Skip to content
vm_tags.py 5.2 KiB
Newer Older
# This file is part of CloudControl.
#
# CloudControl is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# CloudControl 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CloudControl.  If not, see <http://www.gnu.org/licenses/>.


import logging
import itertools
from functools import wraps
Anael Beutot's avatar
Anael Beutot committed
from xml.etree import cElementTree as et
from StringIO import StringIO

import libvirt

from cloudcontrol.node.utils import execute

from cloudcontrol.common.client.tags import ttl, refresh, background
Anael Beutot's avatar
Anael Beutot committed

Anael Beutot's avatar
Anael Beutot committed

logger = logging.getLogger(__name__)


def _vir_tag(func):
    """Catches libvirt related exception.

    Decorator used for tag declarations that interacts with libvirt.

    """
    @wraps(func)
    def decorated(dom):
        if not dom.hypervisor.handler.virt_connected:
            return
        try:
Anael Beutot's avatar
Anael Beutot committed
            return func(dom)
Anael Beutot's avatar
Anael Beutot committed
        except libvirt.libvirtError as exc:
            if 'Domain not found' in str(exc):
                # sometimes, libvirt tells us too late when a domain is removed
                # we just ignore the error and remove the domain
                dom.hypervisor.vm_unregister(dom.name)
Anael Beutot's avatar
Anael Beutot committed
                return
            logger.exception('Unexpected libvirt error')
            dom.hypervisor.handler.virt_connect_restart()

    return decorated


Anael Beutot's avatar
Anael Beutot committed
def uuid(dom):
    """Unique identifier of the domain."""
    return dom.uuid.lower()
def rescue(dom):
    """Is rescue mode enabled or not"""
    rescue_path = dom.hypervisor.handler.main.config.rescue_script
    rcode, output = execute(dom.hypervisor.handler.main, [rescue_path, '-s', dom.name])
    if rcode == 0:
        return output.strip()
    else:
        return 'error'


Anael Beutot's avatar
Anael Beutot committed
def status(dom):
    return dom.state


def hv(dom):
Antoine Millet's avatar
Antoine Millet committed
    # FIXME: what shoud be the value of this tag ?
Anael Beutot's avatar
Anael Beutot committed
    return dom.hypervisor.name


def htype(dom):
    return dom.hypervisor.type


Anael Beutot's avatar
Anael Beutot committed
def arch(dom):
    """VM CPU architecture."""
    try:
        return dict(i686='x86', x86_64='x64')[et.ElementTree().parse(
            StringIO(dom.lv_dom.XMLDesc(0))).find('os/type').get('arch')]
    except Exception:
        logger.exception('Error while get Architecture tag')


def h(dom):
    """Name of the VM."""
    return dom.name
def t(dom):
    """Title of the VM (or name if title is not defined)."""
    if dom.title is None:
        return dom.name
    else:
        return dom.title


Anael Beutot's avatar
Anael Beutot committed
def cpu(dom):
    """Number of CPU of the VM."""
    return dom.lv_dom.info()[3]


Anael Beutot's avatar
Anael Beutot committed
@ttl(10)
@refresh(5)
@_vir_tag
def cpuuse(dom):
    """Represent CPU use in percent average on 5 seconds."""
    state, _, _, vcpu, cpu_time = dom.lv_dom.info()
    if state != 1:  # if VM is not running
        return None
    old_cpu_stats = dom.cpu_stats
    dom.cpu_stats = (dom.hypervisor.handler.main.evloop.now(), cpu_time)
Anael Beutot's avatar
Anael Beutot committed
    # calculate CPU percentage, code is from virt-manager in domain.py:1210
    return '%.2f' % max(0., min(100., ((cpu_time - old_cpu_stats[1]) * 100.) / (
Antoine Millet's avatar
Antoine Millet committed
        (dom.cpu_stats[0] - old_cpu_stats[0]) * 1000. * 1000. * 1000.) / vcpu))
Anael Beutot's avatar
Anael Beutot committed
def mem(dom):
    """Memory currently allocated."""
    if dom.state == 'stopped':
        return dom.lv_dom.info()[1] * 1024
    else:
        return dom.lv_dom.info()[2] * 1024
Anael Beutot's avatar
Anael Beutot committed
def memmax(dom):
    """Maximum memory allocation."""
    return dom.lv_dom.info()[1] * 1024


Anael Beutot's avatar
Anael Beutot committed
def vncport(dom):
    """VNC port for the VM console access."""
    try:
        port = et.ElementTree().parse(
Anael Beutot's avatar
Anael Beutot committed
            StringIO(dom.lv_dom.XMLDesc(0))
Antoine Millet's avatar
Antoine Millet committed
        ).find('devices/graphics[@type="vnc"]').get('port')
Anael Beutot's avatar
Anael Beutot committed
    except Exception:
        logger.exception('VNCPort')
    try:
        if 0 < int(port) < 65536:
            return port
    except (TypeError, ValueError):
        pass
@_vir_tag
def spiceport(dom):
    """Spice port for the VM console access."""
    try:
        port = et.ElementTree().parse(
            StringIO(dom.lv_dom.XMLDesc(0))
        ).find('devices/graphics[@type="spice"]').get('port')
    except Exception:
        logger.exception('SpicePort')
        raise

    try:
        if 0 < int(port) < 65536:
            return port
    except (TypeError, ValueError):
        pass

    return


Anael Beutot's avatar
Anael Beutot committed
@ttl(10)
@refresh(10)
Anael Beutot's avatar
Anael Beutot committed
def disk(dom):
    """Get backend disks."""
Anael Beutot's avatar
Anael Beutot committed
    return u' '.join(map(str, xrange(len(dom.disks)))) or None
Anael Beutot's avatar
Anael Beutot committed
@ttl(10)
@refresh(10)
Anael Beutot's avatar
Anael Beutot committed
def nic(dom):
    """VM network interfaces."""
    return u' '.join(map(str, xrange(len(dom.nics)))) or None
@ttl(10)
@refresh(10)
@_vir_tag
def nic_vlans(dom):
    """VM network interfaces."""
    vlans = set(itertools.chain(*[x.vlans for x in dom.nics]))
    return u' '.join(str(x) for x in sorted(vlans)) or None


@refresh(10)
@_vir_tag
def autostart(dom):
    """Autostart status."""
    return {True: 'yes', False: 'no'}[bool(dom.lv_dom.autostart())]