Skip to content
Snippets Groups Projects
libvirtwrapper.py 17.4 KiB
Newer Older
Thibault VINCENT's avatar
Thibault VINCENT committed
# -*- coding: utf-8 -*-
Benziane Chakib's avatar
Benziane Chakib committed

import libvirt
import xml.dom.minidom
Thibault VINCENT's avatar
Thibault VINCENT committed
from logging import error, warning, info, debug
from time import sleep
from common import Hypervisor, VM, Storage, StoragePool, StorageVolume
Thibault VINCENT's avatar
Thibault VINCENT committed
from utils import RWLock
Thibault VINCENT's avatar
Thibault VINCENT committed
from exceptions import HypervisorError, VMError, StoragePoolError
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):
        super(LibvirtHypervisor, self).__init__()
Thibault VINCENT's avatar
Thibault VINCENT committed
                warning("LibvirtHypervisor: initialized as KVM")
                self._lvcon_handle = libvirt.open(KVM_LIBVIRT_SESSION)
            elif hv_type == 'xen':
Thibault VINCENT's avatar
Thibault VINCENT committed
                warning("LibvirtHypervisor: initialized as Xen")
Thibault VINCENT's avatar
Thibault VINCENT committed
                self._lvcon_handle = libvirt.open(XEN_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 = {}
Thibault VINCENT's avatar
Thibault VINCENT committed
        self._vm_cache_lock = RWLock()
    
    def scheduler_run(self):
        self._cache_vm_rebuild()
Thibault VINCENT's avatar
Thibault VINCENT committed
    def _cache_vm_rebuild(self):
Thibault VINCENT's avatar
Thibault VINCENT committed
        running = {}
        defined = {}
        
        for dom_id in self._lvcon_handle.listDomainsID():
Thibault VINCENT's avatar
Thibault VINCENT committed
            try:
                vm = LibvirtVm(self, self._lvcon_handle.lookupByID(dom_id))
                running[vm.get_name()] = vm
            except Exception as err:
Thibault VINCENT's avatar
Thibault VINCENT committed
                debug("_cache_vm_rebuild: listDomainsID: `%s` -> `%s`",
                                                                repr(err), err)
Thibault VINCENT's avatar
Thibault VINCENT committed
        
        for dom_name in self._lvcon_handle.listDefinedDomains():
Thibault VINCENT's avatar
Thibault VINCENT committed
            try:
                vm = LibvirtVm(self,
                                self._lvcon_handle.lookupByName(dom_name))
                defined[vm.get_name()] = vm
            except Exception as err:
Thibault VINCENT's avatar
Thibault VINCENT committed
                debug("_cache_vm_rebuild: listDefinedDomains: `%s` -> `%s`",
                                                                repr(err), err)
Thibault VINCENT's avatar
Thibault VINCENT committed
        with self._vm_cache_lock.write:
            self._vm_cache_running = running
            self._vm_cache_defined = defined
            self._vm_cache = self._vm_cache_running
            self._vm_cache.update(self._vm_cache_defined)
        return self._hv_type
    
    def get_hv_version(self):
        version = None
        try:
            data = self._lvcon_handle.getVersion()
            if data:
Thibault VINCENT's avatar
Thibault VINCENT committed
                version = data  
        except:
            pass
        return version
    
    def get_libvirt_version(self):
        '''
        '''
        version = None
        try:
            data = self._lvcon_handle.getLibVersion()
            if data:
                version = data
        except:
            pass
        return version
        return int(self.get_cpu() / self.get_cpu_threads())
        return self._lvcon_handle.getInfo()[7]
    
    def get_cpu_frequency(self):
        return self._lvcon_handle.getInfo()[3]
    
    def storage(self):
    def vm_define(self, data):
        '''
        '''
        vm = self._lvcon_handle.defineXML(data)
        self._cache_vm_rebuild()
        if hasattr(vm, 'name'):
            return vm.name()
        else:
            raise HypervisorError('VM not defined properly')
    
Thibault VINCENT's avatar
Thibault VINCENT committed
        with self._vm_cache_lock.read:
            return self._vm_cache.keys()
Thibault VINCENT's avatar
Thibault VINCENT committed
        with self._vm_cache_lock.read:
            for vm_name, vm in self._vm_cache_running.iteritems():
                if vm.is_active():
                    running.append(vm_name)
Thibault VINCENT's avatar
Thibault VINCENT committed
        with self._vm_cache_lock.read:
            return self._vm_cache_defined.keys()
Thibault VINCENT's avatar
Thibault VINCENT committed
        with self._vm_cache_lock.read:
            for vm_name, vm in self._vm_cache_running.iteritems():
                if vm.is_paused():
                    paused.append(vm_name)
        return paused
    
    def vm_get(self, name):
Thibault VINCENT's avatar
Thibault VINCENT committed
        with self._vm_cache_lock.read:
            if name in self.vm_list():
                return self._vm_cache[name]
            else:
                raise Exception()
class LibvirtStorage(Storage):
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)
        if not self._pool_cache:
            self._pool_cache_rebuild()
        return self._pool_cache.keys()
        if name in self.pool_list():
            return self._pool_cache[name]
        else:
            raise Exception()
        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):
            data = self._lvpool_handle.name()
            if data:
                name = data
Thibault VINCENT's avatar
Thibault VINCENT committed
        except libvirt.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)
        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))
            data = self._lvvol_handle.name()
            if data:
                name = data
Thibault VINCENT's avatar
Thibault VINCENT committed
        except libvirt.libvirtError:
    def get_space_capacity(self):
        capacity = None
        try:
            capacity = self._lvvol_handle.info()[1]
Thibault VINCENT's avatar
Thibault VINCENT committed
        except libvirt.libvirtError:
    def get_space_allocation(self):
Benziane Chakib's avatar
Benziane Chakib committed
        try:
            allocated = self._lvvol_handle.info()[2]
Thibault VINCENT's avatar
Thibault VINCENT committed
        except libvirt.libvirtError:
            path = self._lvvol_handle.path()
Thibault VINCENT's avatar
Thibault VINCENT committed
        except libvirt.libvirtError:
            self._lvvol_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()
        result = find_process_id(self.get_uuid())
        if result:
            self._pid = int(result.pop())
        else:
            self._pid = None
    def undefine(self):
        '''
        '''
        if self._domain.undefine():
            raise VMError('deletion of VM `%s` failed' % self.get_name())
        self._hv_handle._cache_vm_rebuild()
    
            self._domain.create()
        except libvirt.libvirtError:
            raise VMError('`%s` is already running' % self.get_name())
        try:
            self._domain.destroy()
        except libvirt.libvirtError:
            raise VMError('`%s` is not running' % self.get_name())
        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:
            paused = self._domain.info()[0] in self.STATUS_PAUSED
        except libvirt.libvirtError:
    def get_config(self):
        '''
        '''
        return self._domain.XMLDesc(0)
    
        return self._domain.UUIDString()
            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:
Thibault VINCENT's avatar
Thibault VINCENT committed
            pass
        return self._domain.info()[3]
        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
        return self._domain.info()[1] * KILOBYTE_DIV
        return self._domain.info()[2] * KILOBYTE_DIV
    
    def get_mem_free(self):
        return (self.get_mem() - self.get_mem_used()) * KILOBYTE_DIV
            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 = xdisk.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)]