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:
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

View File

@ -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%;"

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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,