Skip to content
kvm.py 5.95 KiB
Newer Older
Benziane Chakib's avatar
Benziane Chakib committed
'''
All KVM technology specefic functions are implemented inside this module
Two entites belong to this module: a Kvm hypervisor or a Kvm virtual machine
'''


from libvirtwrapper import *
from exceptions import *
import subprocess
Benziane Chakib's avatar
Benziane Chakib committed


class KvmHypervisor(LibvirtHypervisor):
    '''
    Base class of a Kvm Hypervisor
    This class have a attribute hv_type for tagging purposes
    '''
    _instance = None

    def __init__(self):
        super(KvmHypervisor, self).__init__('kvm')
        self.hv_type = 'KVM/QEMU'
    
    
    def __new__(cls, *args, **kwargs):
        '''
        .. note::
            We use singleton design pattern to force only a single instance
            of ourlibvirt hypervisor handle, it's essential since we connect
            with libvirt only on localhost so we must assure one single 
            connection to the hypervisor
        '''
        if cls._instance is None:
            cls._instance = super(KvmHypervisor, cls).__new__(cls, *args,
                                                                **kwargs)
        return cls._instance

   
    def start_vm(self, name, start_options=DEFAULT_VM_START):
        '''
        Starts the vm identified by name
        
        :param name: The name of the virtual machine
        :type nane: :class:`str`

        :param start_options: Options flags while starting vm
        :type start_options: TODO reference to constants

        '''
        for vm in self._vm_list:
            if vm.get_name() == name:
                vm.start()
                return
        raise VMError('Virtual Machine %s not found: '% name)

    def stop_vm(self, name, force=False):
Benziane Chakib's avatar
Benziane Chakib committed
        '''
        Poweroff the specifed vm with the specified options

        :param name: the name of the vm
Benziane Chakib's avatar
Benziane Chakib committed
        :type name: :class:`str`
        '''
        for vm in self._vm_list:
            if vm.get_name() == name:
                vm.force_poweroff() if force else vm.shutdown()
Benziane Chakib's avatar
Benziane Chakib committed
                return
        raise VMError('Virtual Machine %s not found: ' % name)   

    def suspend_vm(self, name):
        '''
        Suspends the specifed vm

        :param name: the name of the vm
        :type name: :class:`str`
        '''
        for vm in self._vm_list:
            if vm.get_name() == name:
                vm.suspend()
                return
        raise VMError('Virtual machine %s not found: ' % name)

    def resume_vm(self, name):
        '''
        Resumes the specifed vm

        :param name: the name of the vm
        :type name: :class:`str`
        '''
        for vm in self._vm_list:
            if vm.get_name() == name:
                vm.resume()
                return
        raise VMError('Virtual machine %s not found: ' % name)
Thibault VINCENT's avatar
Thibault VINCENT committed
    def local_execute(self, command):
        '''
        Excecutes the command given in command on the local host
        Returns a tuple with (stdout, stderr) from the process that has
        been executed

        ..warning:: This is a dangerous function as it gives the command given
        in paramter to a shell prompt, anything can then be executed locally
        ..warning:: If the command given is a long processing one, this may be
            a deadlock to the node be carefull !

        :param command: the command to execute with it's arguments
        :type command: :class:`str`
        '''
        #FIXME: stop using shell=true and parse arguments with shlex.split()
        p = subprocess.Popen(command, shell=True,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)
        result = p.communicate()
        return result
    def export_vm(self, name, target, port):
        '''
        Migrates the given vm (name) to (target) hypervisor which is already
        waiting for the migration

        :param name: the name of the vm
        :type name: :class:`str`
        :param target: the destination hypervisor
        :type target: :class:`str`
        :param port: the port on the destination to use for the transfer
        :type port: :class:`str`
        '''
        # We will be using subprocess to pipe the volume using dd  in a netcat 
        # connection to the destination
        # We send a hash of the volume before so that the target can checksum
        # and validate integrity.
        # This algorithm is just a proof of concept of the cold migration
        # process it is likely that it does not anticipates some problems

        buff = 1024 * 1024 * 10   #10 Mo
        path = [vm.get_disk_path() for vm in self._vm_list 
                                    if vm.get_name() == name].pop()
        dd_cmd = ['dd', 'if=%s' % path]
        
        dd_process = subprocess.Popen(dd_cmd, bufsize=-1,
                                    stdout=subprocess.PIPE)
        nc_process = subprocess.Popen(['nc', target, port],
                                    bufsize=-1,
                                    stdin=subprocess.PIPE,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
        #We send dd output to nc
        dd_out = dd_process.stdout
        nc_in = nc_process.stdin
        m = hashlib.md5()
        print 'going to pipe loop'
        try:
            read = dd_out.read(buff)
        except Exception as err:
            raise IOError('error while reading dd process output %s' % err)
        try:
            while len(read) != 0:
                print len(read)
                m.update(read)
                nc_in.write(read)
                nc_in.flush()
                read = dd_out.read(buff)
        except Exception as err:
            raise IOError('Error occured while writing to nc process %s' % err)
        nc_in.close()
        print m.hexdigest()

Benziane Chakib's avatar
Benziane Chakib committed
    def get_network_conf(self):
        raise NotImplementedError

    def get_storage_conf(self):
        raise NotImplementedError

    def get_storage_stats(self):
        raise NotImplementedError