Source code for lago.providers.libvirt.utils

#
# Copyright 2014-2017 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
#
# Refer to the README and COPYING files for full details of the license
#

from __future__ import absolute_import
"""
Utilities to help deal with the libvirt python bindings
"""
import libvirt
import xmltodict
import lxml.etree
import logging
import pkg_resources
from jinja2 import Environment, PackageLoader, TemplateNotFound
from lago.config import config

LOGGER = logging.getLogger(__name__)

#: Mapping of domain statuses values to human readable strings
DOMAIN_STATES = {
    libvirt.VIR_DOMAIN_NOSTATE: 'no state',
    libvirt.VIR_DOMAIN_RUNNING: 'running',
    libvirt.VIR_DOMAIN_BLOCKED: 'blocked',  # the domain is blocked on resource
    libvirt.VIR_DOMAIN_PAUSED: 'paused',
    libvirt.VIR_DOMAIN_SHUTDOWN: 'begin shut down',
    libvirt.VIR_DOMAIN_SHUTOFF: 'shut off',
    libvirt.VIR_DOMAIN_CRASHED: 'crashed',
    libvirt.VIR_DOMAIN_PMSUSPENDED:
        'suspended',  # the domain is suspended by guest power management
}

DOMAIN_RUNNING_STATES = {
    libvirt.VIR_DOMAIN_RUNNING,
}

#: Singleton with the cached opened libvirt connections
LIBVIRT_CONNECTIONS = {}


[docs]class Domain(object): """ Class to namespace libvirt domain related helpers """
[docs] @staticmethod def resolve_state(state_number): """ Get a nice description from a domain state number Args: state_number(list of int): State number as returned by :func:`libvirt.virDomain.state` Returns: str: small human readable description of the domain state, unknown if the state is not in the known list """ return DOMAIN_STATES.get(state_number[0], 'unknown')
[docs]def libvirt_callback(userdata, err): pass
[docs]def auth_callback(credentials, user_data): for credential in credentials: if credential[0] == libvirt.VIR_CRED_AUTHNAME: credential[4] = config.get('libvirt_username') elif credential[0] == libvirt.VIR_CRED_PASSPHRASE: credential[4] = config.get('libvirt_password') return 0
[docs]def get_libvirt_connection(name): if name not in LIBVIRT_CONNECTIONS: auth = [ [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE], auth_callback, None ] libvirt_url = config.get('libvirt_url', 'qemu:///system') libvirt.registerErrorHandler(f=libvirt_callback, ctx=None) LIBVIRT_CONNECTIONS[name] = libvirt.openAuth(libvirt_url, auth) return LIBVIRT_CONNECTIONS[name]
[docs]def get_template(basename): """ Load a file as a string from the templates directory Args: basename(str): filename Returns: str: string representation of the file """ return pkg_resources.resource_string( __name__, '/'.join(['templates', basename]) )
[docs]def get_domain_template(distro, libvirt_ver, **kwargs): """ Get a rendered Jinja2 domain template Args: distro(str): domain distro libvirt_ver(int): libvirt version kwargs(dict): args for template render Returns: str: rendered template """ env = Environment( loader=PackageLoader('lago', 'providers/libvirt/templates'), trim_blocks=True, lstrip_blocks=True, ) template_name = 'dom_template-{0}.xml.j2'.format(distro) try: template = env.get_template(template_name) except TemplateNotFound: LOGGER.debug('could not find template %s using default', template_name) template = env.get_template('dom_template-base.xml.j2') return template.render(libvirt_ver=libvirt_ver, **kwargs)
[docs]def dict_to_xml(spec, full_document=False): """ Convert dict to XML Args: spec(dict): dict to convert full_document(bool): whether to add XML headers Returns: lxml.etree.Element: XML tree """ middle = xmltodict.unparse(spec, full_document=full_document, pretty=True) return lxml.etree.fromstring(middle)