Class'ify' libvirt util

This commit is contained in:
Joshua Harlow 2012-03-21 23:33:36 -07:00
parent fc81122b7a
commit 3903e1aa82
6 changed files with 119 additions and 126 deletions

View File

@ -17,6 +17,8 @@ commands:
libvirt: libvirt:
restart: service libvirtd restart restart: service libvirtd restart
status: service libvirtd status 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: mysql:
create_db: mysql --user=%USER% --password=%PASSWORD% -e "CREATE DATABASE %DB%;" create_db: mysql --user=%USER% --password=%PASSWORD% -e "CREATE DATABASE %DB%;"
drop_db: mysql --user=%USER% --password=%PASSWORD% -e "DROP DATABASE IF EXISTS drop_db: mysql --user=%USER% --password=%PASSWORD% -e "DROP DATABASE IF EXISTS

View File

@ -23,6 +23,8 @@ commands:
libvirt: libvirt:
restart: service libvirt-bin restart restart: service libvirt-bin restart
status: service libvirt-bin status 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: mysql:
# NOTE: we aren't stopping any sql injection... # NOTE: we aren't stopping any sql injection...
create_db: mysql --user=%USER% --password=%PASSWORD% -e "CREATE DATABASE %DB%;" create_db: mysql --user=%USER% --password=%PASSWORD% -e "CREATE DATABASE %DB%;"

View File

@ -19,7 +19,7 @@ from urlparse import urlunparse
from devstack import component as comp from devstack import component as comp
from devstack import date from devstack import date
from devstack import exceptions 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 log as logging
from devstack import shell as sh from devstack import shell as sh
from devstack import utils from devstack import utils
@ -145,7 +145,6 @@ DEF_VOL_TEMPL = DEF_VOL_PREFIX + '%08x'
# Default virt types # Default virt types
DEF_VIRT_DRIVER = 'libvirt' DEF_VIRT_DRIVER = 'libvirt'
DEF_VIRT_TYPE = 'qemu'
# Virt drivers map -> to there connection name # Virt drivers map -> to there connection name
VIRT_DRIVER_CON_MAP = { VIRT_DRIVER_CON_MAP = {
@ -198,21 +197,12 @@ def canon_virt_driver(virt_driver):
return 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): class NovaUninstaller(comp.PythonUninstallComponent):
def __init__(self, *args, **kargs): def __init__(self, *args, **kargs):
comp.PythonUninstallComponent.__init__(self, *args, **kargs) comp.PythonUninstallComponent.__init__(self, *args, **kargs)
self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR)
self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR)
self.virsh = lv.Virsh(self.cfg, self.distro)
def known_subsystems(self): def known_subsystems(self):
return SUBSYSTEMS return SUBSYSTEMS
@ -238,8 +228,8 @@ class NovaUninstaller(comp.PythonUninstallComponent):
virt_driver = canon_virt_driver(self.cfg.get('nova', 'virt_driver')) virt_driver = canon_virt_driver(self.cfg.get('nova', 'virt_driver'))
if virt_driver == 'libvirt': if virt_driver == 'libvirt':
inst_prefix = self.cfg.getdefaulted('nova', 'instance_name_prefix', DEF_INSTANCE_PREFIX) inst_prefix = self.cfg.getdefaulted('nova', 'instance_name_prefix', DEF_INSTANCE_PREFIX)
libvirt_type = canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) libvirt_type = lv.canon_libvirt_type(self.cfg.get('nova', 'libvirt_type'))
virsh.clear_libvirt_domains(self.distro, libvirt_type, inst_prefix) self.virsh.clear_domains(libvirt_type, inst_prefix)
class NovaInstaller(comp.PythonInstallComponent): class NovaInstaller(comp.PythonInstallComponent):
@ -376,6 +366,7 @@ class NovaRuntime(comp.PythonRuntime):
self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR) self.cfg_dir = sh.joinpths(self.app_dir, CONFIG_DIR)
self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR) self.bin_dir = sh.joinpths(self.app_dir, BIN_DIR)
self.wait_time = max(self.cfg.getint('default', 'service_wait_seconds'), 1) 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): def _setup_network_init(self):
tgt_fn = sh.joinpths(self.bin_dir, NET_INIT_CONF) tgt_fn = sh.joinpths(self.bin_dir, NET_INIT_CONF)
@ -420,13 +411,13 @@ class NovaRuntime(comp.PythonRuntime):
if virt_driver == 'libvirt': if virt_driver == 'libvirt':
# FIXME: The configuration for the virtualization-type # FIXME: The configuration for the virtualization-type
# should come from the persona. # should come from the persona.
virt_type = canon_libvirt_type(self.cfg.get('nova', 'libvirt_type')) virt_type = lv.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)) LOG.info("Checking that your selected libvirt virtualization type %r is working and running." % (virt_type))
if not virsh.virt_ok(virt_type, self.distro): if not self.virsh.check_virt(virt_type):
msg = ("Libvirt type %s does not seem to be active or configured correctly, " msg = ("Libvirt type %r does not seem to be active or configured correctly, "
"perhaps you should be using %s instead." % (virt_type, DEF_VIRT_TYPE)) "perhaps you should be using %r instead." % (virt_type, lv.DEF_VIRT_TYPE))
raise exceptions.StartException(msg) raise exceptions.StartException(msg)
virsh.restart(self.distro) self.virsh.restart_service()
def _get_param_map(self, app_name): def _get_param_map(self, app_name):
params = comp.PythonRuntime._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? # Configure anything libvirt related?
virt_driver = canon_virt_driver(self._getstr('virt_driver')) virt_driver = canon_virt_driver(self._getstr('virt_driver'))
if virt_driver == 'libvirt': 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) self._configure_libvirt(libvirt_type, nova_conf)
# How instances will be presented # How instances will be presented

View File

@ -14,6 +14,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import contextlib
from devstack import exceptions as excp from devstack import exceptions as excp
from devstack import log as logging from devstack import log as logging
from devstack import shell as sh from devstack import shell as sh
@ -29,121 +31,118 @@ LIBVIRT_PROTOCOL_MAP = {
'uml': 'uml:///system', 'uml': 'uml:///system',
'lxc': 'lxc:///', '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! # Status is either dead or alive!
_DEAD = 'DEAD' _DEAD = 'DEAD'
_ALIVE = 'ALIVE' _ALIVE = 'ALIVE'
# Alive wait time, just a sleep we put into so that the service can start up # Type that should always work
# FIXME: take from config... DEF_VIRT_TYPE = 'qemu'
WAIT_ALIVE_TIME = 5
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(): def _get_virt_lib():
# Late import so that we don't always need this library to be active # 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... # 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): class Virsh(object):
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
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): def _service_status(self):
try: cmd = self.distro.get_command('libvirt', 'status')
dom = conn.lookupByName(dom_name) (stdout, stderr) = sh.execute(*cmd, run_as_root=True, check_exit_code=False)
LOG.debug("Destroying domain (%s) (id=%s) running %s" % (dom_name, dom.ID(), dom.OSType())) combined = (stdout + stderr).lower()
dom.destroy() if combined.find("running") != -1 or combined.find('start') != -1:
dom.undefine() return _ALIVE
except libvirt.libvirtError, e: else:
LOG.warn("Could not clear out libvirt domain (%s) due to [%s]" % (dom_name, e.message)) return _DEAD
def _destroy_domain(self, conn, dom_name):
def restart(distro): libvirt = _get_virt_lib()
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))
try: 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: except excp.ProcessExecutionError, e:
LOG.warn("Could not restart libvirt due to [%s]" % (e)) LOG.warn("Could not restart libvirt due to: %s" % (e))
return return False
try: try:
conn = libvirt.open(virt_protocol) cmds = list()
except libvirt.libvirtError, e: cmds.append({
LOG.warn("Could not connect to libvirt using protocol [%s] due to [%s]" % (virt_protocol, e.message)) '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 return
try: virt_protocol = LIBVIRT_PROTOCOL_MAP.get(virt_type)
defined_domains = conn.listDefinedDomains() if not virt_protocol:
kill_domains = list() LOG.warn("Could not clear out libvirt domains, no known protocol for virt type %r" % (virt_type))
for domain in defined_domains: return
if domain.startswith(inst_prefix): with sh.Rooted(True):
kill_domains.append(domain) LOG.info("Attempting to clear out leftover libvirt domains using protocol %r" % (virt_protocol))
if kill_domains: try:
LOG.info("Found %s old domains to destroy (%s)" % (len(kill_domains), ", ".join(sorted(kill_domains)))) self.restart_service()
for domain in sorted(kill_domains): except excp.ProcessExecutionError as e:
_destroy_domain(libvirt, conn, domain) LOG.warn("Could not restart libvirt due to: %s" % (e))
except libvirt.libvirtError, e: return
LOG.warn("Could not clear out libvirt domains due to [%s]" % (e.message)) 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))

View File

@ -19,7 +19,6 @@ from optparse import OptionParser, OptionGroup
from devstack.progs import actions from devstack.progs import actions
from devstack import log as logging from devstack import log as logging
from devstack import settings
from devstack import version from devstack import version
HELP_WIDTH = 80 HELP_WIDTH = 80

View File

@ -29,6 +29,7 @@ class ActionRunner(object):
__meta__ = abc.ABCMeta __meta__ = abc.ABCMeta
PREREQ = None PREREQ = None
NAME = None
def __init__(self, def __init__(self,
distro, distro,
@ -69,13 +70,13 @@ class ActionRunner(object):
"""Create component objects for each component in the persona. """Create component objects for each component in the persona.
""" """
components = persona.wanted_components components = persona.wanted_components
desired_subsystems = persona.wanted_subsystems or dict() desired_subsystems = persona.wanted_subsystems or {}
component_opts = persona.component_options or dict() component_opts = persona.component_options or {}
instances = dict() instances = {}
for c in components: for c in components:
(cls, my_info) = self.distro.extract_component(c, self.NAME) (cls, my_info) = self.distro.extract_component(c, self.NAME)
LOG.debug("Constructing class %s" % (cls)) LOG.debug("Constructing class %s" % (cls))
cls_kvs = dict() cls_kvs = {}
cls_kvs['runner'] = self cls_kvs['runner'] = self
cls_kvs['component_dir'] = sh.joinpths(root_dir, c) cls_kvs['component_dir'] = sh.joinpths(root_dir, c)
cls_kvs['subsystem_info'] = my_info.get('subsystems', {}) cls_kvs['subsystem_info'] = my_info.get('subsystems', {})
@ -312,7 +313,6 @@ class UninstallRunner(ActionRunner):
) )
_NAMES_TO_RUNNER = { _NAMES_TO_RUNNER = {
'install': InstallRunner, 'install': InstallRunner,
'uninstall': UninstallRunner, 'uninstall': UninstallRunner,