Commit 79e8f0a2 authored by Antoine Catton's avatar Antoine Catton Committed by Łukasz Nowak

Merge Antoine Catton work on promises.

Squashed commit of the following:

commit 29caaa556d1d641f6b2241db84d2d8b588689a82
Merge: 32d5fef 13d6e1d3
Author: Antoine Catton <acatton@tiolive.com>
Date:   Mon Sep 19 11:49:27 2011 +0200

    Merge branch 'master' into promises

    Conflicts:
    	slapos/recipe/kvm/__init__.py

commit 32d5fef49f22e3a47ca0b0728e502d177979b214
Author: Antoine Catton <acatton@tiolive.com>
Date:   Wed Aug 24 16:45:31 2011 +0200

    Minor: Use pkg_resources the right way

    http://peak.telecommunity.com/DevCenter/PkgResources

commit e2fae493ab6a96fa10cbe6531ee1a1ba9c16bb4c
Author: Antoine Catton <acatton@tiolive.com>
Date:   Wed Aug 24 16:00:02 2011 +0200

    Minor: some typo fix to get the recipe working

commit 3764ab93da5031f9b5ea59072090d2b961a791cf
Author: Antoine Catton <acatton@tiolive.com>
Date:   Wed Aug 24 15:53:17 2011 +0200

    Minor: typo fix

commit 259026f718e0e37c5c151fb40dbf85866f6ab87f
Author: Antoine Catton <acatton@tiolive.com>
Date:   Wed Aug 24 15:33:04 2011 +0200

    Cleanup: use createPromiseWrapper instead of easy_install.script

    - Install the socket_connection_attempt script into bin/ directory
    - Create promises running this script specifying the right command line
      arguments

commit a870a4d77a3b72d79354e557ee0b8571da9a7459
Author: Antoine Catton <acatton@tiolive.com>
Date:   Wed Aug 24 13:44:50 2011 +0200

    Minor: remove appending promise path to path_list

commit 260df1be27ac382061809aa8851130cd26f74be0
Author: Łukasz Nowak <luke@nexedi.com>
Date:   Thu Jul 28 14:40:29 2011 +0200

    Do not expose python's shabang.

commit 7db31e9b6759183a54390480a77032009bf2e9ae
Author: Antoine Catton <acatton@tiolive.com>
Date:   Thu Jul 28 14:13:03 2011 +0200

    Replaced the usage python script as template by the easy_install
    capability usage.

commit 3f62cda3a2a9e64cc92cd4c01585b422bb30ff0e
Author: Antoine Catton <acatton@tiolive.com>
Date:   Tue Jul 26 15:34:13 2011 +0200

    Adding promises to kvm software release.

    Not tested yet

    Minor: removed magic number 5900

commit 2e36426bd11e4833ec3be6a8e2b664e343760417
Author: Antoine Catton <acatton@tiolive.com>
Date:   Tue Jul 26 13:38:14 2011 +0200

    Trailing spaces on KVM recipe

commit 02ed180bd0002cbfe387875ec917e4d6e214e40e
Author: Antoine Catton <acatton@tiolive.com>
Date:   Mon Jul 25 16:57:43 2011 +0200

    Method createPromise in slapos.librecipe

    This method create a promise script which should return 0 whether the
    promise was kept.
parent 13d6e1d3
......@@ -37,6 +37,9 @@ import hashlib
class Recipe(BaseSlapRecipe):
# To avoid magic numbers
VNC_BASE_PORT = 5900
def _install(self):
"""
Set the connection dictionnary for the computer partition and create a list
......@@ -49,42 +52,58 @@ class Recipe(BaseSlapRecipe):
self.path_list = []
self.requirements, self.ws = self.egg.working_set()
self.cron_d = self.installCrond()
self.cron_d = self.installCrond()
self.ca_conf = self.installCertificateAuthority()
self.key_path, self.certificate_path = self.requestCertificate('noVNC')
# Install the socket_connection_attempt script
catcher = zc.buildout.easy_install.scripts(
[('check_port_listening', __name__ + 'socket_connection_attempt', 'connection_attempt')],
self.ws,
sys.executable,
self.bin_directory,
)
# Save the check_port_listening script path
check_port_listening_script = catcher[0]
# Get the port_listening_promise template path, and save it
self.port_listening_promise_path = pkg_resources.resource_filename(
__name__, 'template/port_listening_promise.in')
self.port_listening_promise_conf = dict(
check_port_listening_script=check_port_listening_script,
)
kvm_conf = self.installKvm(vnc_ip = self.getLocalIPv4Address())
vnc_port = 5900 + kvm_conf['vnc_display']
vnc_port = Recipe.VNC_BASE_PORT + kvm_conf['vnc_display']
noVNC_conf = self.installNoVnc(source_ip = self.getGlobalIPv6Address(),
source_port = 6080,
target_ip = kvm_conf['vnc_ip'],
target_port = vnc_port)
self.linkBinary()
self.computer_partition.setConnectionDict(dict(
url = "https://[%s]:%s/vnc.html?host=[%s]&port=%s&encrypt=1" % (noVNC_conf['source_ip'],
noVNC_conf['source_port'],
noVNC_conf['source_ip'],
noVNC_conf['source_port']
),
),
password = kvm_conf['vnc_passwd']))
return self.path_list
def installKvm(self, vnc_ip):
"""
Create kvm configuration dictionnary and instanciate a wrapper for kvm and
kvm controller
Create kvm configuration dictionnary and instanciate a wrapper for kvm and
kvm controller
Parameters : IP the vnc server is listening on
Returns : Dictionnary kvm_conf
"""
kvm_conf = dict(vnc_ip = vnc_ip)
connection_found = False
for tap_interface, dummy in self.parameter_dict['ip_list']:
# Get an ip associated to a tap interface
......@@ -94,13 +113,13 @@ class Recipe(BaseSlapRecipe):
raise NotImplementedError("Do not support ip without tap interface")
kvm_conf['tap_interface'] = tap_interface
# Disk path
kvm_conf['disk_path'] = os.path.join(self.data_root_directory,
'virtual.qcow2')
kvm_conf['socket_path'] = os.path.join(self.var_directory, 'qmp_socket')
# XXX Weak password
##XXX -Vivien: add an option to generate one password for all instances
##XXX -Vivien: add an option to generate one password for all instances
# and/or to input it yourself
kvm_conf['vnc_passwd'] = binascii.hexlify(os.urandom(4))
......@@ -119,7 +138,7 @@ class Recipe(BaseSlapRecipe):
int(self.options['disk_size']))], shell=True)
if retcode != 0:
raise OSError, "Disk creation failed!"
# Options nbd_ip and nbd_port are provided by slapos master
kvm_conf['nbd_ip'] = self.parameter_dict['nbd_ip']
kvm_conf['nbd_port'] = self.parameter_dict['nbd_port']
......@@ -133,37 +152,45 @@ class Recipe(BaseSlapRecipe):
kvm_conf['ram_size'] = self.options['ram_size']
kvm_conf['vnc_display'] = 1
# Instanciate KVM
kvm_template_location = pkg_resources.resource_filename(
__name__, os.path.join(
'template', 'kvm_run.in'))
kvm_runner_path = self.createRunningWrapper("kvm",
kvm_template_location = pkg_resources.resource_filename(
__name__, 'template/kvm_run.in')
kvm_runner_path = self.createRunningWrapper("kvm",
self.substituteTemplate(kvm_template_location,
kvm_conf))
self.path_list.append(kvm_runner_path)
# Instanciate KVM controller
kvm_controller_template_location = pkg_resources.resource_filename(
__name__, os.path.join(
'template',
'kvm_controller_run.in' ))
kvm_controller_runner_path = self.createRunningWrapper("kvm_controller",
kvm_controller_template_location = pkg_resources.resource_filename(
__name__, 'template/kvm_controller_run.in')
kvm_controller_runner_path = self.createRunningWrapper("kvm_controller",
self.substituteTemplate(kvm_controller_template_location,
kvm_conf))
self.path_list.append(kvm_controller_runner_path)
# Instanciate Slapmonitor
##slapmonitor_runner_path = self.instanciate_wrapper("slapmonitor",
# [database_path, pid_file_path, python_path])
# Instanciate Slapreport
##slapreport_runner_path = self.instanciate_wrapper("slapreport",
# [database_path, python_path])
# Add VNC promise
self.port_listening_promise_conf.update(
hostname=kvm_conf['vnc_ip'],
port=Recipe.VNC_BASE_PORT + kvm_conf['vnc_display'],
)
self.createPromiseWrapper("vnc_promise",
self.substituteTemplate(self.port_listening_promise_path,
self.port_listening_promise_conf,
)
)
return kvm_conf
def installNoVnc(self, source_ip, source_port, target_ip, target_port):
......@@ -204,9 +231,19 @@ class Recipe(BaseSlapRecipe):
[self.certificate_path, self.key_path],
environment]
)[0]
self.path_list.append(websockify_runner_path)
# Add noVNC promise
self.port_listening_promise_conf.update(hostname=noVNC_conf['source_ip'],
port=noVNC_conf['source_port'],
)
self.createPromiseWrapper("novnc_promise",
self.substituteTemplate(self.port_listening_promise_path,
self.port_listening_promise_conf,
)
)
return noVNC_conf
def linkBinary(self):
......@@ -230,7 +267,7 @@ class Recipe(BaseSlapRecipe):
os.symlink(target, link)
self.logger.debug('Created link %r -> %r' % (link, target))
self.path_list.append(link)
def installCertificateAuthority(self, ca_country_code='XX',
ca_email='xx@example.com', ca_state='State', ca_city='City',
ca_company='Company'):
......@@ -289,7 +326,7 @@ class Recipe(BaseSlapRecipe):
ca_crl=os.path.join(config['ca_dir'], 'crl'),
certificate_authority_path=config['ca_dir']
)
def requestCertificate(self, name):
hash = hashlib.sha512(name).hexdigest()
key = os.path.join(self.ca_private, hash + self.ca_key_ext)
......@@ -301,7 +338,7 @@ class Recipe(BaseSlapRecipe):
parser.set('certificate', 'certificate_file', certificate)
parser.write(open(os.path.join(self.ca_request_dir, hash), 'w'))
return key, certificate
def installCrond(self):
timestamps = self.createDataDirectory('cronstamps')
cron_output = os.path.join(self.log_directory, 'cron-output')
......
import socket
import sys
def connection_attempt():
try:
hostname, port = sys.argv[1:3]
except ValueError:
print >> sys.stderr, """Bad command line.
Usage: %s hostname|ip port""" % sys.argv[0]
sys.exit(1)
connection_okay = False
try:
s = socket.create_connection((hostname, port))
connection_okay = True
s.close()
except (socket.error, socket.timeout):
connection_okay = False
if not connection_okay:
print >> sys.stderr, "%(port)s on %(ip)s isn't listening" % {
'port': port, 'ip': hostname
}
sys.exit(127)
#!/usr/bin/env sh
"%(check_port_listening_script)s" "%(hostname)s" "%(port)s"
exit $?
......@@ -60,6 +60,7 @@ class BaseSlapRecipe:
'xml_report')
self.destroy_script_location = os.path.join(self, self.work_directory,
'sbin', 'destroy')
self.promise_directory = os.path.join(self.etc_directory, 'promise')
# default directory structure information
self.default_directory_list = [
......@@ -71,6 +72,7 @@ class BaseSlapRecipe:
self.etc_directory, # CP/etc - configuration container
self.wrapper_directory, # CP/etc/run - for wrappers
self.wrapper_report_directory, # CP/etc/report - for report wrappers
self.promise_directory, # CP/etc/promise - for promise checking scripts
self.var_directory, # CP/var - partition "internal" container for logs,
# and another metadata
self.wrapper_xml_report_directory, # CP/var/xml_report - for xml_report wrappers
......@@ -243,3 +245,14 @@ class BaseSlapRecipe:
def _install(self):
"""Hook which shall be implemented in children class"""
raise NotImplementedError('Shall be implemented by subclass')
def createPromiseWrapper(self, promise_name, file_content):
"""Create a promise wrapper.
This wrapper aim to check if the software release is doing its job.
Return the promise file path.
"""
promise_path = os.path.join(self.promise_directory, promise_name)
self._writeExecutable(promise_path, file_content)
return promise_path
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment