From 3903e1aa82fbae46dad558d189809942c04fb027 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Wed, 21 Mar 2012 23:33:36 -0700 Subject: [PATCH 1/3] Class'ify' libvirt util --- conf/distros/rhel-6.yaml | 2 + conf/distros/ubuntu-oneiric.yaml | 2 + devstack/components/nova.py | 33 ++---- devstack/libvirt.py | 197 +++++++++++++++---------------- devstack/opts.py | 1 - devstack/progs/actions.py | 10 +- 6 files changed, 119 insertions(+), 126 deletions(-) diff --git a/conf/distros/rhel-6.yaml b/conf/distros/rhel-6.yaml index aea77d02..98ce93bb 100644 --- a/conf/distros/rhel-6.yaml +++ b/conf/distros/rhel-6.yaml @@ -17,6 +17,8 @@ commands: libvirt: restart: service libvirtd restart status: service libvirtd status + # This is just used to check that libvirt will work with a given protocol + verify: virsh -c %VIRT_PROTOCOL% uri mysql: create_db: mysql --user=%USER% --password=%PASSWORD% -e "CREATE DATABASE %DB%;" drop_db: mysql --user=%USER% --password=%PASSWORD% -e "DROP DATABASE IF EXISTS diff --git a/conf/distros/ubuntu-oneiric.yaml b/conf/distros/ubuntu-oneiric.yaml index 19f4e902..4918723b 100644 --- a/conf/distros/ubuntu-oneiric.yaml +++ b/conf/distros/ubuntu-oneiric.yaml @@ -23,6 +23,8 @@ commands: libvirt: restart: service libvirt-bin restart status: service libvirt-bin status + # This is just used to check that libvirt will work with a given protocol + verify: virsh -c %VIRT_PROTOCOL% uri mysql: # NOTE: we aren't stopping any sql injection... create_db: mysql --user=%USER% --password=%PASSWORD% -e "CREATE DATABASE %DB%;" diff --git a/devstack/components/nova.py b/devstack/components/nova.py index de6c6fc2..58d572e8 100644 --- a/devstack/components/nova.py +++ b/devstack/components/nova.py @@ -19,7 +19,7 @@ from urlparse import urlunparse from devstack import component as comp from devstack import date from devstack import exceptions -from devstack import libvirt as virsh +from devstack import libvirt as lv from devstack import log as logging from devstack import shell as sh from devstack import utils @@ -145,7 +145,6 @@ DEF_VOL_TEMPL = DEF_VOL_PREFIX + '%08x' # Default virt types DEF_VIRT_DRIVER = 'libvirt' -DEF_VIRT_TYPE = 'qemu' # Virt drivers map -> to there connection name VIRT_DRIVER_CON_MAP = { @@ -198,21 +197,12 @@ def canon_virt_driver(virt_driver): return virt_driver -def canon_libvirt_type(virt_type): - if not virt_type: - return DEF_VIRT_TYPE - virt_type = virt_type.lower().strip() - if not (virt_type in virsh.LIBVIRT_PROTOCOL_MAP): - return DEF_VIRT_TYPE - else: - return virt_type - - class NovaUninstaller(comp.PythonUninstallComponent): def __init__(self, *args, **kargs): comp.PythonUninstallComponent.__init__(self, *args, **kargs) self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) + self.virsh = lv.Virsh(self.cfg, self.distro) def known_subsystems(self): return SUBSYSTEMS @@ -238,8 +228,8 @@ class NovaUninstaller(comp.PythonUninstallComponent): virt_driver = canon_virt_driver(self.cfg.get('nova', 'virt_driver')) if virt_driver == 'libvirt': inst_prefix = self.cfg.getdefaulted('nova', 'instance_name_prefix', DEF_INSTANCE_PREFIX) - libvirt_type = canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) - virsh.clear_libvirt_domains(self.distro, libvirt_type, inst_prefix) + libvirt_type = lv.canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) + self.virsh.clear_domains(libvirt_type, inst_prefix) class NovaInstaller(comp.PythonInstallComponent): @@ -376,6 +366,7 @@ class NovaRuntime(comp.PythonRuntime): self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) self.wait_time = max(self.cfg.getint('default', 'service_wait_seconds'), 1) + self.virsh = lv.Virsh(self.cfg, self.distro) def _setup_network_init(self): tgt_fn = sh.joinpths(self.bin_dir, NET_INIT_CONF) @@ -420,13 +411,13 @@ class NovaRuntime(comp.PythonRuntime): if virt_driver == 'libvirt': # FIXME: The configuration for the virtualization-type # should come from the persona. - virt_type = canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) - LOG.info("Checking that your selected libvirt virtualization type [%s] is working and running." % (virt_type)) - if not virsh.virt_ok(virt_type, self.distro): - msg = ("Libvirt type %s does not seem to be active or configured correctly, " - "perhaps you should be using %s instead." % (virt_type, DEF_VIRT_TYPE)) + virt_type = lv.canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) + LOG.info("Checking that your selected libvirt virtualization type %r is working and running." % (virt_type)) + if not self.virsh.check_virt(virt_type): + msg = ("Libvirt type %r does not seem to be active or configured correctly, " + "perhaps you should be using %r instead." % (virt_type, lv.DEF_VIRT_TYPE)) raise exceptions.StartException(msg) - virsh.restart(self.distro) + self.virsh.restart_service() def _get_param_map(self, app_name): params = comp.PythonRuntime._get_param_map(self, app_name) @@ -584,7 +575,7 @@ class NovaConfConfigurator(object): # Configure anything libvirt related? virt_driver = canon_virt_driver(self._getstr('virt_driver')) if virt_driver == 'libvirt': - libvirt_type = canon_libvirt_type(self._getstr('libvirt_type')) + libvirt_type = lv.canon_libvirt_type(self._getstr('libvirt_type')) self._configure_libvirt(libvirt_type, nova_conf) # How instances will be presented diff --git a/devstack/libvirt.py b/devstack/libvirt.py index c35a4c27..4753363b 100644 --- a/devstack/libvirt.py +++ b/devstack/libvirt.py @@ -14,6 +14,8 @@ # License for the specific language governing permissions and limitations # under the License. +import contextlib + from devstack import exceptions as excp from devstack import log as logging from devstack import shell as sh @@ -29,121 +31,118 @@ LIBVIRT_PROTOCOL_MAP = { 'uml': 'uml:///system', 'lxc': 'lxc:///', } -VIRT_LIB = 'libvirt' - -# This is just used to check that libvirt will work with -# a given protocol, may not be ideal but does seem to crap -# out if it won't work, so thats good... -VIRSH_SANITY_CMD = ['virsh', '-c', '%VIRT_PROTOCOL%', 'uri'] # Status is either dead or alive! _DEAD = 'DEAD' _ALIVE = 'ALIVE' -# Alive wait time, just a sleep we put into so that the service can start up -# FIXME: take from config... -WAIT_ALIVE_TIME = 5 +# Type that should always work +DEF_VIRT_TYPE = 'qemu' + + +def canon_libvirt_type(virt_type): + if not virt_type: + return DEF_VIRT_TYPE + virt_type = virt_type.lower().strip() + if not (virt_type in LIBVIRT_PROTOCOL_MAP): + return DEF_VIRT_TYPE + else: + return virt_type def _get_virt_lib(): # Late import so that we don't always need this library to be active # ie if u aren't using libvirt in the first place... - return utils.import_module(VIRT_LIB) + return utils.import_module('libvirt') -def _status(distro): - cmds = [{'cmd': distro.get_command('libvirt', 'status'), - 'run_as_root': True, - }] - result = utils.execute_template(*cmds, - check_exit_code=False, - params={}) - if not result or not result[0]: - return _DEAD - (sysout, stderr) = result[0] - combined = str(sysout) + str(stderr) - combined = combined.lower() - if combined.find("running") != -1 or combined.find('start') != -1: - return _ALIVE - else: - return _DEAD +class Virsh(object): + def __init__(self, config, distro): + self.cfg = config + self.distro = distro + self.wait_time = max(self.cfg.getint('default', 'service_wait_seconds'), 1) -def _destroy_domain(libvirt, conn, dom_name): - try: - dom = conn.lookupByName(dom_name) - LOG.debug("Destroying domain (%s) (id=%s) running %s" % (dom_name, dom.ID(), dom.OSType())) - dom.destroy() - dom.undefine() - except libvirt.libvirtError, e: - LOG.warn("Could not clear out libvirt domain (%s) due to [%s]" % (dom_name, e.message)) + def _service_status(self): + cmd = self.distro.get_command('libvirt', 'status') + (stdout, stderr) = sh.execute(*cmd, run_as_root=True, check_exit_code=False) + combined = (stdout + stderr).lower() + if combined.find("running") != -1 or combined.find('start') != -1: + return _ALIVE + else: + return _DEAD - -def restart(distro): - if _status(distro) != _ALIVE: - cmds = [{ - 'cmd': distro.get_command('libvirt', 'restart'), - 'run_as_root': True, - }] - utils.execute_template(*cmds, params={}) - LOG.info("Restarting the libvirt service, please wait %s seconds until its started." % (WAIT_ALIVE_TIME)) - sh.sleep(WAIT_ALIVE_TIME) - - -def virt_ok(virt_type, distro): - virt_protocol = LIBVIRT_PROTOCOL_MAP.get(virt_type) - if not virt_protocol: - return False - try: - restart(distro) - except excp.ProcessExecutionError, e: - LOG.warn("Could not restart libvirt due to [%s]" % (e)) - return False - try: - cmds = list() - cmds.append({ - 'cmd': VIRSH_SANITY_CMD, - 'run_as_root': True, - }) - mp = dict() - mp['VIRT_PROTOCOL'] = virt_protocol - utils.execute_template(*cmds, params=mp) - return True - except excp.ProcessExecutionError, e: - LOG.warn("Could check if libvirt was ok for protocol [%s] due to [%s]" % (virt_protocol, e.message)) - return False - - -def clear_libvirt_domains(distro, virt_type, inst_prefix): - libvirt = _get_virt_lib() - if not libvirt: - LOG.warn("Could not clear out libvirt domains, libvirt not available for python.") - return - virt_protocol = LIBVIRT_PROTOCOL_MAP.get(virt_type) - if not virt_protocol: - LOG.warn("Could not clear out libvirt domains, no known protocol for virt type %s" % (virt_type)) - return - with sh.Rooted(True): - LOG.info("Attempting to clear out leftover libvirt domains using protocol %s" % (virt_protocol)) + def _destroy_domain(self, conn, dom_name): + libvirt = _get_virt_lib() try: - restart(distro) + dom = conn.lookupByName(dom_name) + LOG.debug("Destroying domain (%r) (id=%s) running %r" % (dom_name, dom.ID(), dom.OSType())) + dom.destroy() + dom.undefine() + except libvirt.libvirtError as e: + LOG.warn("Could not clear out libvirt domain %r due to: %s" % (dom_name, e)) + + def restart_service(self): + if self._service_status() != _ALIVE: + cmd = self.distro.get_command('libvirt', 'restart') + sh.execute(*cmd, run_as_root=True) + LOG.info("Restarting the libvirt service, please wait %s seconds until its started." % (self.wait_time)) + sh.sleep(self.wait_time) + + def check_virt(self, virt_type): + virt_protocol = LIBVIRT_PROTOCOL_MAP.get(virt_type) + if not virt_protocol: + return False + try: + self.restart_service() except excp.ProcessExecutionError, e: - LOG.warn("Could not restart libvirt due to [%s]" % (e)) - return + LOG.warn("Could not restart libvirt due to: %s" % (e)) + return False try: - conn = libvirt.open(virt_protocol) - except libvirt.libvirtError, e: - LOG.warn("Could not connect to libvirt using protocol [%s] due to [%s]" % (virt_protocol, e.message)) + cmds = list() + cmds.append({ + 'cmd': self.distro.get_command('libvirt', 'verify'), + 'run_as_root': True, + }) + mp = dict() + mp['VIRT_PROTOCOL'] = virt_protocol + utils.execute_template(*cmds, params=mp) + return True + except excp.ProcessExecutionError as e: + LOG.warn("Could check if libvirt was ok for protocol %r due to: %s" % (virt_protocol, e)) + return False + + def clear_domains(self, virt_type, inst_prefix): + libvirt = _get_virt_lib() + if not libvirt: + LOG.warn("Could not clear out libvirt domains, libvirt not available for python.") return - try: - defined_domains = conn.listDefinedDomains() - kill_domains = list() - for domain in defined_domains: - if domain.startswith(inst_prefix): - kill_domains.append(domain) - if kill_domains: - LOG.info("Found %s old domains to destroy (%s)" % (len(kill_domains), ", ".join(sorted(kill_domains)))) - for domain in sorted(kill_domains): - _destroy_domain(libvirt, conn, domain) - except libvirt.libvirtError, e: - LOG.warn("Could not clear out libvirt domains due to [%s]" % (e.message)) + virt_protocol = LIBVIRT_PROTOCOL_MAP.get(virt_type) + if not virt_protocol: + LOG.warn("Could not clear out libvirt domains, no known protocol for virt type %r" % (virt_type)) + return + with sh.Rooted(True): + LOG.info("Attempting to clear out leftover libvirt domains using protocol %r" % (virt_protocol)) + try: + self.restart_service() + except excp.ProcessExecutionError as e: + LOG.warn("Could not restart libvirt due to: %s" % (e)) + return + try: + conn = libvirt.open(virt_protocol) + except libvirt.libvirtError as e: + LOG.warn("Could not connect to libvirt using protocol %r due to: %s" % (virt_protocol, e)) + return + with contextlib.closing(conn) as ch: + try: + defined_domains = ch.listDefinedDomains() + kill_domains = list() + for domain in defined_domains: + if domain.startswith(inst_prefix): + kill_domains.append(domain) + if kill_domains: + LOG.info("Found %s old domains to destroy (%s)" % (len(kill_domains), ", ".join(sorted(kill_domains)))) + for domain in sorted(kill_domains): + self._destroy_domain(ch, domain) + except libvirt.libvirtError, e: + LOG.warn("Could not clear out libvirt domains due to %s" % (e)) diff --git a/devstack/opts.py b/devstack/opts.py index cee72b24..e271ce88 100644 --- a/devstack/opts.py +++ b/devstack/opts.py @@ -19,7 +19,6 @@ from optparse import OptionParser, OptionGroup from devstack.progs import actions from devstack import log as logging -from devstack import settings from devstack import version HELP_WIDTH = 80 diff --git a/devstack/progs/actions.py b/devstack/progs/actions.py index 5ba79e84..758adf49 100644 --- a/devstack/progs/actions.py +++ b/devstack/progs/actions.py @@ -29,6 +29,7 @@ class ActionRunner(object): __meta__ = abc.ABCMeta PREREQ = None + NAME = None def __init__(self, distro, @@ -69,13 +70,13 @@ class ActionRunner(object): """Create component objects for each component in the persona. """ components = persona.wanted_components - desired_subsystems = persona.wanted_subsystems or dict() - component_opts = persona.component_options or dict() - instances = dict() + desired_subsystems = persona.wanted_subsystems or {} + component_opts = persona.component_options or {} + instances = {} for c in components: (cls, my_info) = self.distro.extract_component(c, self.NAME) LOG.debug("Constructing class %s" % (cls)) - cls_kvs = dict() + cls_kvs = {} cls_kvs['runner'] = self cls_kvs['component_dir'] = sh.joinpths(root_dir, c) cls_kvs['subsystem_info'] = my_info.get('subsystems', {}) @@ -312,7 +313,6 @@ class UninstallRunner(ActionRunner): ) - _NAMES_TO_RUNNER = { 'install': InstallRunner, 'uninstall': UninstallRunner, From d2eeea4d32d8f882cdcade5684feb77163d95211 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Thu, 22 Mar 2012 10:42:21 -0700 Subject: [PATCH 2/3] Dougs recommended fixups. Thx Doug. --- devstack/components/nova.py | 9 ++++++--- devstack/libvirt.py | 30 ++++++++++-------------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/devstack/components/nova.py b/devstack/components/nova.py index 58d572e8..e8b687e1 100644 --- a/devstack/components/nova.py +++ b/devstack/components/nova.py @@ -413,11 +413,14 @@ class NovaRuntime(comp.PythonRuntime): # should come from the persona. virt_type = lv.canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) LOG.info("Checking that your selected libvirt virtualization type %r is working and running." % (virt_type)) - if not self.virsh.check_virt(virt_type): + try: + self.virsh.check_virt(virt_type) + self.virsh.restart_service() + except exceptions.ProcessExecutionError as e: msg = ("Libvirt type %r does not seem to be active or configured correctly, " - "perhaps you should be using %r instead." % (virt_type, lv.DEF_VIRT_TYPE)) + "perhaps you should be using %r instead: %s" % + (virt_type, lv.DEF_VIRT_TYPE, e)) raise exceptions.StartException(msg) - self.virsh.restart_service() def _get_param_map(self, app_name): params = comp.PythonRuntime._get_param_map(self, app_name) diff --git a/devstack/libvirt.py b/devstack/libvirt.py index 4753363b..2f7361e1 100644 --- a/devstack/libvirt.py +++ b/devstack/libvirt.py @@ -91,26 +91,16 @@ class Virsh(object): def check_virt(self, virt_type): virt_protocol = LIBVIRT_PROTOCOL_MAP.get(virt_type) - if not virt_protocol: - return False - try: - self.restart_service() - except excp.ProcessExecutionError, e: - LOG.warn("Could not restart libvirt due to: %s" % (e)) - return False - try: - cmds = list() - cmds.append({ - 'cmd': self.distro.get_command('libvirt', 'verify'), - 'run_as_root': True, - }) - mp = dict() - mp['VIRT_PROTOCOL'] = virt_protocol - utils.execute_template(*cmds, params=mp) - return True - except excp.ProcessExecutionError as e: - LOG.warn("Could check if libvirt was ok for protocol %r due to: %s" % (virt_protocol, e)) - return False + self.restart_service() + cmds = list() + cmds.append({ + 'cmd': self.distro.get_command('libvirt', 'verify'), + 'run_as_root': True, + }) + mp = dict() + mp['VIRT_PROTOCOL'] = virt_protocol + mp['VIRT_TYPE'] = virt_type + utils.execute_template(*cmds, params=mp) def clear_domains(self, virt_type, inst_prefix): libvirt = _get_virt_lib() From d77b5984d8b2ec9c280014c0831c52aa479625c1 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Thu, 22 Mar 2012 10:48:57 -0700 Subject: [PATCH 3/3] Add in a misc var env section --- devstack/env_rc.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/devstack/env_rc.py b/devstack/env_rc.py index 03d9d3c3..18e98399 100644 --- a/devstack/env_rc.py +++ b/devstack/env_rc.py @@ -133,6 +133,7 @@ class RcWriter(object): lines.extend(self._generate_os_env()) lines.extend(self._generate_euca_env()) lines.extend(self._generate_extern_inc()) + lines.extend(self._generate_misc_env()) lines.extend(self._generate_aliases()) return lines @@ -145,6 +146,7 @@ class RcWriter(object): possible_vars.update(self._get_os_envs()) possible_vars.update(self._get_euca_envs()) possible_vars.update(self._get_nova_envs()) + possible_vars.update(self._get_misc_envs()) new_vars = dict() updated_vars = dict() for (key, value) in possible_vars.items(): @@ -187,6 +189,19 @@ class RcWriter(object): to_set['OS_AUTH_URL'] = key_params['SERVICE_ENDPOINT'] return to_set + def _get_misc_envs(self): + key_params = keystone.get_shared_params(self.cfg, self.pw_gen) + to_set = dict() + to_set.update(key_params) + return to_set + + def _generate_misc_env(self): + lines = list() + lines.append('# Misc stuff') + lines.extend(self._make_dict_export(self._get_misc_envs())) + lines.append("") + return lines + def _generate_os_env(self): lines = list() lines.append('# Openstack stuff')