-
Thibault VINCENT authoredThibault VINCENT authored
ccnodehandlers.py 10.24 KiB
# Gerer le cas ou le mdp n'est pa valable
#TODO: catch livbirt disconnection errors and handle it
from __init__ import __version__
from interface import Host
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_WRAP_MAP = {
'h' : 'get_name',
'hv' : 'get_name',
'hvtype' : 'get_hv_type',
'hvver' : 'get_hv_version',
'arch' : 'get_arch_type',
'cpu' : 'get_cpu',
'cpufreq' : 'get_cpu_frequency',
'cpuuse' : 'get_cpu_percent',
'status' : 'get_status',
'mem' : 'get_mem',
'memused' : 'get_mem_used',
'memfree' : 'get_mem_free',
}
HV_TAG_HELPER_LIST = [
'disk',
'sto',
]
# Vm
VM_TAG_WRAP_MAP = {
'h' : 'get_name',
'vm' : 'get_name',
'hv' : 'get_hv_name',
'cpu' : 'get_cpu',
'vmstatus' : 'get_status',
'mem' : 'get_mem',
'memused' : 'get_mem_used',
'memfree' : 'get_mem_free',
}
VM_TAG_HELPER_LIST = [
'disk',
]
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, hypervisor):
super(RpcHandler, self).__init__()
self._connection = connection
#do not detect hypervisor if connection is disable in configuration
if not hypervisor:
logging.debug('Hypervisor detection disabled, running as regular'
' node')
self.hv_handle = Host()
else:
#we set our hypervisor handle
#FIXME: must be aware of hypervisor type
logging.debug('Initializing a connection on the hypervisor')
self.hv_handle = KvmHypervisor()
logging.debug('Initialized connection to a KVM hypervisor')
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`
'''
return getattr(self.hv_handle, HV_TAG_WRAP_MAP[method])()
def _call_hv_helper(self, method):
return getattr(self, "_helper_hv_" + method)()
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`
'''
return getattr(vm, VM_TAG_WRAP_MAP[method])()
def _call_vm_helper(self, method):
return getattr(self, "_helper_vm_" + method)()
def _helper_hv_sto(self):
result = {}
hv = self.hv_handle
# fetch pool list
pools = hv.get_storage_pools()
result['sto'] = " ".join(pools)
# get pool info
for pool in pools:
# pool size
result['sto%s_size' % pool] = hv.get_storage_capacity(pool)
# pool used space
result['sto%s_used' % pool] = hv.get_storage_used(pool)
# pool free space
result['sto%s_free' % pool] = hv.get_storage_free(pool)
return result
def _helper_hv_disk(self):
return {}
def _helper_vm_disk(self):
result = {}
hv = self.hv_handle
# fetch disk list
disks = hv.get_vm_disks()
result['disk'] = " ".join([d['name'] for d in disks])
# add disk info
for n, disk in enumerate(disks):
# disk path to real storage
result['disk%i_path' % n] = disk['path']
# disk size
result['disk%i_size' % n] = disk['size']
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 = {}
if tags is None:
tags = HV_TAG_WRAP_MAP.keys()
# static tags
result['version'] = str(__version__)
# direct wrapping
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 mehod in hypervisor to handle %s' % tag)
# tag aggregations from wrapping helpers
for helper in HV_TAG_HELPER_LIST:
result.update(self._call_hv_helper(helper))
return result
@pure
def list_vm(self, vm_names=None, tags=None):
'''
Return a list of vm tags
If vm_names is None or [] returns all vms
If tags is None or [] returns only vm name tag
: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 = [] if tags is None else tags
logging.debug('list_vm: processing tags %s' % tags)
# ensure that vm name is always returned bu default
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):
'''
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 force: soft shutown or force poweroff
:type force: either True or False
'''
if vm_names is None:
#fetch all vm names in hypervisor
vm_names = gen_vm_names(self.hv_handle)
logging.debug('stop_vm: stopping vms %s' % vm_names)
for vm in vm_names:
try:
self.hv_handle.stop_vm(vm, force)
except VMError as err:
logging.warning('Error while stopping %s: %s' % (vm, err))
else:
logging.info('stop_vm: vm %s stopping' % vm)
@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)
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):
'''
Executes the given command on the local hypervisor
:param command: the command to execute as it would be typed on a shell
prompt
:type command: :class:`str`
'''
result = self.hv_handle.local_execute(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]