Skip to content
ccnodehandlers.py 8.39 KiB
Newer Older
Benziane Chakib's avatar
Benziane Chakib committed
# Gerer le cas ou le mdp n'est pa valable
#TODO: catch livbirt disconnection errors and handle it 


from kvm import *
from sjrpc.utils import RpcHandler
from sjrpc.utils import pure
from sjrpc.core import RpcError
from exceptions import VMError
import logging

############
## Constants
############

# Logging errors

TAG_METHOD_ERROR = 'No method found in hypervisor to handle tag %s'
TAG_NOT_FOUND_ERROR = 'Tag %s requested but unknown in node handler'

# Tags to method mappings

# Hypervisor

HV_TAG_MAP = {
    'hostname' : 'get_name',
    'htype' : 'get_hv_type',
    'hver' : 'get_hv_version',
    'arch' : 'get_arch_type',
    'cpus' : 'get_nb_cpu',
    'cpu_freq' : 'get_cpu_frequency',
    'status' : 'get_status',
    'cpu' : 'get_cpu_percent',
    'mem_used' : 'get_used_mem',
    'mem_avail' : 'get_free_mem',
    'mem_total': 'get_total_mem'
}

# Vm

VM_TAG_MAP = {
    'vm' : 'get_name',
    'vcpus' : 'get_vcpu',
    'status' : 'get_status',
    'cpu' : 'get_cpu_percent',
    'vmem_used' : 'get_used_mem',
    'vmem_avail' : 'get_free_mem',
    'vmem_total' : 'get_total_mem'
}


class NodeHandler(RpcHandler):
    '''
    This is the main node handler that exports the hypervisor
    capabilities to any connected server. In other terms this is
    the node interface to the server.
    '''

    def __init__(self, connection):
        super(RpcHandler, self).__init__()
        self._connection = connection
        #we set our hypervisor handle
        #FIXME: must be aware of hypervisor type
        logging.debug('Initializing a handle over the hypervisor')
        self.hv_handle = KvmHypervisor()

    
    def _call_hv_method(self, method):
        '''
        Calls the given method in the :class:`Hypervisor` instance
        Returns the result of the method called

        :param method: the method to be called
        :type method: :class:`str`
        '''
        result = getattr(self.hv_handle, HV_TAG_MAP[method])()
        return result

    def _call_vm_method(self, vm, method):
        '''
        Calls the given method in vm instance
        Returns the result of the method called

        :param vm: The vm object in which call the method
        :vm type: :class:`VM`
        :param method: the method to be called
        :type method: :class:`str`
        '''
        result = getattr(vm, VM_TAG_MAP[method])()
        return result

    @pure
    def get_tags(self, tags=None):
        '''
        Return tags bound to hypervisor specified in tags parameter otherwise
        returns all

        :param tags: list of tags or None
        :type tags: :class:`list` 
        '''
        result = {}
        logging.debug('get_tags: Fetching tags -> %s' % tags)
        if tags is None:
            tags = HV_TAG_MAP.keys()
        logging.debug('get_tags: processing tags %s' % tags)
        for tag in tags:
            try:
                result[tag] = self._call_hv_method(tag)
            except AttributeError:
                logging.warning(TAG_METHOD_ERROR % tag)
            except KeyError:
                logging.warning(TAG_NOT_FOUND_ERROR % tag)
            except NotImplementedError:
                logging.debug('get_tags: no method in hypervisor to handle %s' % tag)
        logging.debug('get_tags: returning -> %s' % result)
        return result

    @pure
    def list_vm(self, vm_names=None, tags=None):
        '''
        Return a list of vm tags

        :param vm_names: vm names
        :type vm_names: :class:`list` of strings
        :param tags: tags to be returned
        :type tags: :class:`list` of strings
        '''
        vms_info = []
        vm_info = {}
        tags = VM_TAG_MAP.keys() if tags is None else tags 
        logging.debug('list_vm: processing tags %s' % tags)
        # ensure that vm name is always returned
        if not tags.__contains__('vm'):
            tags.insert(0, 'vm')
        logging.debug('list_vm: fetching tag list %s' % tags)
        for vm in self.hv_handle.get_vms():
            for tag in tags:
                try:
                    vm_info[tag] = self._call_vm_method(vm, tag)
                except AttributeError:
                    logging.warning(TAG_METHOD_ERROR % tag)
                except KeyError:
                    logging.warning(TAG_NOT_FOUND_ERROR % tag)
                except NotImplementedError:
                    logging.debug('list_vm: method in vm to handle %s' % tag)
            vms_info.append(vm_info)
            vm_info = {}
        if vm_names:
            logging.debug('list_vm: filtering tag results for vms %s' % vm_names)
            filterd_vms = [vm for vm in vms_info if vm['vm'] in vm_names]
            logging.debug('list_vm: returning -> %s' % filterd_vms)
            return filterd_vms
        else:
            logging.debug('list_vm: returning -> %s' % vms_info)
            return vms_info

    @pure
    def stop_vm(self, vm_names=None, force=False):
Benziane Chakib's avatar
Benziane Chakib committed
        '''
        Stop the specified list of vm names
        This method do a soft shutdown on the Virtual Machine
        If vm_names is None all vms in hypervisor will be stopped

        :param vm_names: the list of vm names to stop
        :vm_names type: :class:`list` of strings
        :param stop_mode: soft shutown or force poweroff
        :type stop_mode: either `FORCE_VM_POWEROFF` or `SOFT_VM_POWEROFF`
            default is SOFT_VM_POWEROFF
        '''
        if vm_names is None:
            #fetch all vm names in hypervisor
Benziane Chakib's avatar
Benziane Chakib committed
            vm_names = [vm.get_name() for vm in self.hv_handle._vm_list]
        logging.debug('stop_vm: stopping vms %s' % vm_names)
        for vm in vm_names:
            try:
                self.hv_handle.stop_vm(vm, stop_mode)
            except VMError as err:
                logging.warning('Error while stopping %s: %s' % (vm, err))
            else:
                logging.info('stop_vm: vm %s stopping' % vm)
Benziane Chakib's avatar
Benziane Chakib committed

    @pure
    def start_vm(self, vm_names=None):
        '''
        Starts the specified list of vms
        If vm_names is None all vms in the hypervisor will be started
        
        :param vm_names: the list of vms to start
        :type vm_names: :class:`list` of strings
        '''
        if vm_names is None:
            vm_names = gen_vm_names(self.hv_handle)
Benziane Chakib's avatar
Benziane Chakib committed
        logging.debug('start_vm: starting vms %s' % vm_names)
        for vm in vm_names:
            try:
                self.hv_handle.start_vm(vm)
            except VMError as err:
                logging.warning('Error while starting %s: %s' % (vm ,err))
            else:
                logging.info('start_vm: vm %s starting' % vm)

    @pure
    def suspend_vm(self, vm_names=None):
        '''
        Suspends the specifed list of vms
        If vm_names is None all vms in hypervisor will be suspended

        :param vm_names: the list of vms to suspend
        :type vm_names: :class:`list` of strings
        '''
        if vm_names is None:
            vm_names = gen_vm_names(self.hv_handle)
        logging.debug('suspend_vm: suspending vms %s' % vm_names)
        for vm in vm_names:
            try:
                self.hv_handle.suspend_vm(vm)
            except VMError as err:
                logging.info('Error while suspending %s: %s' % (vm, err))
            else:
                logging.info('suspend_vm: vm %s suspended' % vm)
                
    @pure
    def resume_vm(self, vm_names=None):
        '''
        Resumes the specified list of vms
        If vm_names is None all vms in hypervisor will be resumed

        :param vm_names: the list of vms to resume
        :type vm_names: :class:`str`
        '''
        if vm_names is None:
            vm_names = gen_vm_names(self.hv_handle)
        logging.debug('resume_vm: resuming vms %s' % vm_names)
        for vm in vm_names:
            try:
                self.hv_handle.resume_vm(vm)
            except VMError as err:
                logging.info('Error while resuming %s: %s' % (vm, err))
            else:
                logging.info('resume_vm: vm %s resumed' % vm)
            
    @pure
    def execute_command(self, command):
        '''
        Excecutes the given command on the local hypervisor

        :param command: the command to excecute as it would be typed on a shell
            prompt
        :type command: :class:`str`
        '''
        result = self.hv_handle.local_excecute(command)
        return result


### Helper Functions

def gen_vm_names(hypervisor):
    '''
    generates a list of vm names defined in hypervisor
    '''
    return [vm.get_name() for vm in hypervisor._vm_list]