Skip to content
__init__.py 3.92 KiB
Newer Older
Anael Beutot's avatar
Anael Beutot committed
import logging
import weakref
from StringIO import StringIO
from xml.etree import cElementTree as et
Anael Beutot's avatar
Anael Beutot committed
from collections import namedtuple
Anael Beutot's avatar
Anael Beutot committed

from cloudcontrol.node.tags import Tag, tag_inspector
from cloudcontrol.node.hypervisor import lib as _libvirt
from cloudcontrol.node.hypervisor.lib import DOMAIN_STATES as STATE
from cloudcontrol.node.hypervisor.domains import vm_tags
Anael Beutot's avatar
Anael Beutot committed


logger = logging.getLogger(__name__)
Anael Beutot's avatar
Anael Beutot committed
NetworkInterface = namedtuple('NetworkInterface', ('source', 'mac', 'model'))


class VirtualMachine(object):
    """Represent a VM instance."""
Anael Beutot's avatar
Anael Beutot committed
    def __init__(self, dom, hypervisor):
        """
        :param dom: libvirt domain instance
Anael Beutot's avatar
Anael Beutot committed
        :param hypervisor: hypervisor where the VM is
        self.hypervisor = weakref.proxy(hypervisor)

        #: UUID string of domain
        self.uuid = dom.UUIDString()
        self.name = dom.name()
        #: state of VM: started, stoped, paused
Anael Beutot's avatar
Anael Beutot committed
        self._state = STATE[dom.info()[0]]
        #: tags for this VM
        # FIXME use a tag db instance
Anael Beutot's avatar
Anael Beutot committed
        self.tags = dict((t.name, t) for t in tag_inspector(vm_tags, self))
        # define dynamic tags
        i = 0
        for v in self.iter_disks():
            for t in (
Anael Beutot's avatar
Anael Beutot committed
                Tag('disk%s_size' % i, v.capacity, 10),
                Tag('disk%s_path' % i, v.path, 10),
                Tag('disk%s_pool' % i, v.storage, 10),  # FIXME: change
                Tag('disk%s_vol' % i, v.name, 10),
            ):
                self.tags[t.name] = t
Anael Beutot's avatar
Anael Beutot committed

Anael Beutot's avatar
Anael Beutot committed
        i = 0
        for nic in self.iter_nics():
            for t in (
Anael Beutot's avatar
Anael Beutot committed
                Tag('nic%s_mac' % i, nic.mac, 10),
                Tag('nic%s_source' % i, nic.source, 10),
                Tag('nic%s_model' %i, nic.model, 10),
Anael Beutot's avatar
Anael Beutot committed
            ):
                self.tags[t.name] = t
Anael Beutot's avatar
Anael Beutot committed
        logger.debug('Virtual Machine tags: %s', self.tags)
Anael Beutot's avatar
Anael Beutot committed
    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, value):
        self._state = value
        self.tags['status'].update_value()
Anael Beutot's avatar
Anael Beutot committed

Anael Beutot's avatar
Anael Beutot committed
    @property
    def lv_dom(self):
        """Libvirt domain instance."""
        return self.hypervisor.vir_con.lookupByUUIDString(self.uuid)
    def start(self):
        self.lv_dom.create()

    def stop(self):
        self.lv_dom.shutdown()
    def suspend(self):
        self.lv_dom.suspend()
    def resume(self):
        self.lv_dom.resume()
    def destroy(self):
        self.lv_dom.destroy()
    def undefine(self):
        self.lv_dom.undefine()

    @property
    def disks(self):
        return list(self.iter_disks())

    def iter_disks(self):
        for d in et.ElementTree().parse(
            StringIO(self.lv_dom.XMLDesc(0))
        ).findall('devices/disk'):
            if d.get('device') != 'disk':
                continue

            type_ = d.get('type')

            if type_ not in ('file', 'block'):
                continue

            path = d.find('source').get(dict(file='file', block='dev')[type_])
            volume = self.hypervisor.storage.get_volume(path)
            if volume is None:
                continue

            yield volume
Anael Beutot's avatar
Anael Beutot committed

    @property
    def nics(self):
        return list(self.iter_nics())

    def iter_nics(self):
        for nic in et.ElementTree().parse(
            StringIO(self.lv_dom.XMLDesc(0))
        ).findall('devices/interface'):
            if nic.get('type') == 'bridge':
                try:
                    mac = nic.find('mac').get('address')
                except AttributeError:
                    mac = None
                try:
                    model = nic.find('model').get('type')
                except AttributeError:
                    model = None
                try:
                    source = nic.find('source').get('bridge')
                except AttributeError:
                    source = None
                yield NetworkInterface(
                    mac=mac,
                    source=source,
                    model=model,
                )