# 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 . import logging from functools import wraps from xml.etree import cElementTree as et from StringIO import StringIO import libvirt from cloudcontrol.common.client.tags import ttl, refresh 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: return func(dom) 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) return logger.exception('Unexpected libvirt error') dom.hypervisor.handler.virt_connect_restart() return decorated def uuid(dom): """Unique identifier of the domain.""" return dom.uuid def status(dom): return dom.state def hv(dom): #FIXME: what shoud be the value of this tag ? return dom.hypervisor.name def htype(dom): return dom.hypervisor.type @_vir_tag 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 @_vir_tag def cpu(dom): """Number of CPU of the VM.""" return dom.lv_dom.info()[3] @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) # 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.) / ( (dom.cpu_stats[0] - old_cpu_stats[0]) * 1000. * 1000. * 1000.))) @_vir_tag def mem(dom): """Memory currently allocated.""" return dom.lv_dom.info()[2] * 1024 @_vir_tag def memmax(dom): """Maximum memory allocation.""" return dom.lv_dom.info()[1] * 1024 @_vir_tag def vncport(dom): """VNC port for the VM console access.""" try: port = et.ElementTree().parse( StringIO(dom.lv_dom.XMLDesc(0)) ).find('devices/graphics').get('port') except Exception: logger.exception('VNCPort') raise if 0 < int(port) < 65536: return port return @ttl(10) @refresh(10) @_vir_tag def disk(dom): """Get backend disks.""" return u' '.join(map(str, xrange(len(dom.disks)))) or None @ttl(10) @refresh(10) @_vir_tag def nic(dom): """VM network interfaces.""" return u' '.join(map(str, xrange(len(dom.nics)))) or None @refresh(10) @_vir_tag def autostart(dom): """Autostart status.""" return {True: 'yes', False: 'no'}[bool(dom.lv_dom.autostart())]