Skip to content
Snippets Groups Projects
libvirtwrapper.py 14 KiB
Newer Older
Benziane Chakib's avatar
Benziane Chakib committed

import libvirt
import xml.dom.minidom
from time import sleep
from common import Hypervisor, VM, Storage, StoragePool, StorageVolume
Benziane Chakib's avatar
Benziane Chakib committed


KVM_LIBVIRT_SESSION = 'qemu:///system'
XEN_LIBVIRT_SESSION = 'xen:///'

MEGABYTE_DIV = 1024 * 1024
GIGABYTE_DIV = 1024 * 1024 * 1024
KILOBYTE_DIV = 1024


class LibvirtHypervisor(Hypervisor):
    
    def __init__(self, hv_type):
        try:
            if hv_type == 'kvm':
                self._lvcon_handle = libvirt.open(KVM_LIBVIRT_SESSION)
            else:
                raise NotImplemented('Unknown hypervisor type')
        except libvirt.libvirtError as error:
            raise HypervisorError('libvirt cannot connect to hypervisor')
        
        self._hv_type = hv_type
        self._sto_handle = LibvirtStorage(self)
        self._vm_cache_running = {}
        self._vm_cache_defined = {}
        self._vm_cache = {}
    
    def _vm_cache_rebuild(self):
        self._vm_cache_running = {}
        self._vm_cache_defined = {}
        self._vm_cache = {}
        
        for dom_id in self._lvcon_handle.listDomainsID():
            vm = LibvirtVm(self, self._lvcon_handle.lookupByID(dom_id))
            self._vm_cache_running[vm.get_name()] = vm
        for dom_name in self._lvcon_handle.listDefinedDomains():
            vm = LibvirtVm(self, self._lvcon_handle.lookupByName(dom_name))
            self._vm_cache_defined[vm.get_name()] = vm
        
        self._vm_cache = self._vm_cache_running
        self._vm_cache.update(self._vm_cache_defined)
    
    def get_hv_type(self):
        return self._hv_type
    
    def get_hv_version(self):
        return self._lvcon_handle.getVersion()
    
    def get_cpu_core(self):
        return int(self.get_cpu() / self.get_cpu_threads())

    def get_cpu_threads(self):
        return self._lvcon_handle.getInfo()[7]
    
    def get_cpu_frequency(self):
        return self._lvcon_handle.getInfo()[3]
    
    def storage(self):
        return self._sto_handle
    
    def vm_list(self):
        if not self._vm_cache:
            self._vm_cache_rebuild()
        return self._vm_cache.keys()
    
    def vm_list_running(self):
        if not self._vm_cache_running:
            self._vm_cache_rebuild()
        running = []
        for vm_name in self._vm_cache_running:
            vm = self.vm_get(vm_name)
            if vm.is_active():
                running.append(vm_name)
        return running

    def vm_list_stopped(self):
        if not self._vm_cache_defined:
            self._vm_cache_rebuild()
        return self._vm_cache_defined.keys()
        
    def vm_list_paused(self):
        if not self._vm_cache_running:
            self._vm_cache_rebuild()
        paused = []
        for vm_name in self._vm_cache_running:
            vm = self.vm_get(vm_name)
            if vm.is_paused():
                paused.append(vm_name)
        return paused
    
    def vm_get(self, name):
        if name in self.vm_list():
            return self._vm_cache[name]
Benziane Chakib's avatar
Benziane Chakib committed
        else:
class LibvirtStorage(Storage):
    
    def __init__(self, hypervisor):
Benziane Chakib's avatar
Benziane Chakib committed
        if isinstance(hypervisor, LibvirtHypervisor):
            self._hv_handle = hypervisor
Benziane Chakib's avatar
Benziane Chakib committed
        else:
            raise TypeError('Expected `%s` given `%s`' % (LibvirtHypervisor,
                                                        hypervisor))
        
        self._pool_cache_running = {}
        self._pool_cache_defined = {}
        self._pool_cache = {}
    
    def _pool_cache_rebuild(self):
        self._pool_cache_running = {}
        self._pool_cache_defined = {}
        self._pool_cache = {}
        
        for name in self._hv_handle._lvcon_handle.listStoragePools():
            pool = LibvirtStoragePool(self,
                    self._hv_handle._lvcon_handle.storagePoolLookupByName(name))
            self._pool_cache_running[pool.get_name()] = pool
        for name in self._hv_handle._lvcon_handle.listDefinedStoragePools():
            pool = LibvirtStoragePool(self,
                    self._hv_handle._lvcon_handle.storagePoolLookupByName(name))
            self._pool_cache_defined[pool.get_name()] = pool
        
        self._pool_cache = self._pool_cache_running
        self._pool_cache.update(self._pool_cache_defined)
    def pool_list(self):
        if not self._pool_cache:
            self._pool_cache_rebuild()
        return self._pool_cache.keys()
    def pool_get(self, name):
        if name in self.pool_list():
            return self._pool_cache[name]
        else:
            raise Exception()
    def capacity(self):
        capacity = 0
        for pool_name in self.pool_list():
            pool = self.pool_get(pool_name)
            capacity += pool.get_space_capacity()
        return capacity
    def find_volumes(self, path=None, name=None):
        volumes = []
        if path is not None or name is not None:
            for pool_name in self.pool_list():
                pool = self.pool_get(pool_name)
                for vol_name in pool.volume_list():
                    vol = pool.volume_get(vol_name)
                    if (path is not None and vol.get_path() == path) \
                            or (name is not None and vol.get_name() == name):
                        volumes.append(vol)
        return volumes


class LibvirtStoragePool(StoragePool):
    def __init__(self, storage, libvirt_pool):
        if isinstance(storage, LibvirtStorage):
            self._sto_handle = storage
Benziane Chakib's avatar
Benziane Chakib committed
        else:
            raise TypeError('Expected `%s` given `%s`' % (LibvirtStorage,
                                                        storage))
        if isinstance(libvirt_pool, libvirt.virStoragePool):
            self._lvpool_handle = libvirt_pool
        else:
            raise TypeError('Expected `%s` given `%s`' % (libvirt.virStoragePool
                                                        , libvirt_pool))
        
        self._vol_cache = {}
    def _vol_cache_rebuild(self):
        self._vol_cache = {}
        if self._lvpool_handle.isActive():
            for name in self._lvpool_handle.listVolumes():
                vol = LibvirtStorageVolume(self,
                        self._lvpool_handle.storageVolLookupByName(name))
                self._vol_cache[vol.get_name()] = vol
    
    def get_name(self):
        name = None
            name = self._lvpool_handle.name()
        except libvirtError:
    def get_space_capacity(self):
Benziane Chakib's avatar
Benziane Chakib committed
        try:
            return self._lvpool_handle.info()[1]
        except libvirt.libvirtError as e:
            raise StoragePoolError("can't get pool information (%s)" % e)
Benziane Chakib's avatar
Benziane Chakib committed
        try:
            return self._lvpool_handle.info()[3]
        except libvirt.libvirtError as e:
            raise StoragePoolError("can't get pool information (%s)" % e)
Benziane Chakib's avatar
Benziane Chakib committed
        try:
            return self._lvpool_handle.info()[2]
        except libvirt.libvirtError as e:
            raise StoragePoolError("can't get pool information (%s)" % e)
    def volume_list(self):
        if not self._vol_cache:
            self._vol_cache_rebuild()
        return self._vol_cache.keys()
    
    def volume_get(self, name):
        if name in self.volume_list():
            return self._vol_cache[name]
        else:
            raise Exception()


class LibvirtStorageVolume(StorageVolume):
    
    def __init__(self, pool, libvirt_vol):
        if isinstance(pool, LibvirtStoragePool):
            self._pool_handle = pool
        else:
            raise TypeError('Expected `%s` given `%s`' % (LibvirtStoragePool,
                                                        pool))
        if isinstance(libvirt_vol, libvirt.virStorageVol):
            self._lvvol_handle = libvirt_vol
        else:
            raise TypeError('Expected `%s` given `%s`' % (libvirt.virStorageVol,
                                                                libvirt_vol))
            name = self._lvvol_handle.name()
        except libvirtError:
            pass
        return name
    def get_space_capacity(self):
        capacity = None
        try:
            capacity = self._lvvol_handle.info()[1]
        except libvirtError:
            pass
        return capacity
    def get_space_allocation(self):
        allocated = None
Benziane Chakib's avatar
Benziane Chakib committed
        try:
            allocated = self._lvvol_handle.info()[2]
        except libvirtError:
            pass
        return allocated 
            path = self._lvvol_handle.path()
        except libvirtError:
            self._lvvvol_handle.wipe(0)
        except libvirt.libvirtError:
    ARCH = {
        'i686' : 'x86',
        'x86_64' : 'x64',
    }
    STATUS = (
        'No state',
        'Running',
        'Blocked on resource',
        'Paused',
        'Shutting down ...',
        'Shutdown',
        'Crashed',
    )
    STATUS_STOPPED = [0, 5, 6]
    STATUS_RUNNING = [1, 2 , 3, 4]
    STATUS_PAUSED = [3]
    def __init__(self, hypervisor, domain):
        super(LibvirtVm, self).__init__()
        if isinstance(domain, libvirt.virDomain):
            self._domain = domain
        else:
            raise TypeError('Need virDomain object given %s' % type(domain))
            
        self._hv_handle = hypervisor
        self._find_pid()
    def _find_pid(self):
        result = find_process_id(self.get_uuid())
        if result:
            self._pid = int(result.pop())
        else:
            self._pid = None
    def hypervisor(self):
        return self._hv_handle
    
    def power_on(self):
            self._domain.create()
        except libvirt.libvirtError:
            raise VMError('`%s` is already running' % self.get_name())
    def power_off(self):
        try:
            self._domain.destroy()
        except libvirt.libvirtError:
            raise VMError('`%s` is not running' % self.get_name())
    def power_shutdown(self):
        try:
            self._domain.shutdown()
        except libvirt.libvirtError:
            raise VMError('`%s` is not running' % self.get_name())
            self._domain.suspend()
        except libvirt.libvirtError:
            raise VMError('`%s` is not running' % self.get_name())
            self._domain.resume()
        except libvirt.libvirtError:
            raise VMError('`%s` is not running' % self.get_name())
    
    def is_active(self):
        active = None
        try:
            active = self._domain.info()[0] in self.STATUS_RUNNING
        except libvirt.libvirtError:
    def is_paused(self):
        paused = None
            paused = self._domain.info()[0] in self.STATUS_PAUSED
        except libvirt.libvirtError:
    def get_uuid(self):
        return self._domain.UUIDString()
    def get_name(self):
        return self._domain.name()
    def get_pid(self):
        return self._pid
            xroot = xml.dom.minidom.parseString(
                        self._domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE))
            xdomain = xroot.getElementsByTagName('domain').pop()
            xos = xdomain.getElementsByTagName('os').pop()
            xtype = xos.getElementsByTagName('type').pop()
            xarch = xtype.getAttribute('arch')
            if xarch in self.ARCH:
                arch = self.ARCH[xarch]
        except:
              pass
        return arch
    def get_cpu_core(self):
        return self._domain.info()[3]
    def get_cpu_usage(self):
        usage = None
        if self._pid is not None:
            try:
                p = psutil.Process(self._pid)
                sleep(0.2)
                usage = p.get_cpu_percent()
            except:
                pass
        return usage
    def get_mem(self):
        return self._domain.info()[1] * KILOBYTE_DIV
    def get_mem_used(self):
        return self._domain.info()[2] * KILOBYTE_DIV
    
    def get_mem_free(self):
        return (self.get_mem() - self.get_mem_used()) * KILOBYTE_DIV
    def get_volumes(self):
        volumes = []
            xroot = xml.dom.minidom.parseString(
                        self._domain.XMLDesc(libvirt.VIR_DOMAIN_XML_INACTIVE))
            xdomain = xroot.getElementsByTagName('domain').pop()
            xdevices = xdomain.getElementsByTagName('devices').pop()
            # iter on "disk" devices
            for xdisk in xdevices.getElementsByTagName('disk'):
                try:
                    # disks we can handle
                    if xdisk.getAttribute('device') == 'disk':
                        # get type
                        d_type = xdisk.getAttribute('type')
                        # get backend path
                        if d_type == 'file':
                            d_path = xdisk.getElementsByTagName('source').pop()\
                                                        .getAttribute('file')
                        elif d_type == 'block':
                            d_path = disk.getElementsByTagName('source').pop()\
                                                            .getAttribute('dev')
                        # search the volume object
                        if d_type in ['file', 'block']:
                            volumes.append(self._hv_handle._sto_handle
                                            .find_volumes(path=d_path).pop())
                except Exception as e:
                    print e
        except:
            pass
        return volumes
def find_process_id(cmd_subchain):
    return [p.pid for p in psutil.get_process_list()
                                        if p.cmdline.__contains__(cmd_subchain)]