Skip to content
__init__.py 3.91 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 ccnode.tags import Tag, tag_inspector
from ccnode.hypervisor import lib as _libvirt
from ccnode.hypervisor.lib import DOMAIN_STATES as STATE
Anael Beutot's avatar
Anael Beutot committed
from ccnode.hypervisor.domains import vm_tags


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
Anael Beutot's avatar
Anael Beutot committed
        self.tags['status'].value = value

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