Newer
Older
# Gerer le cas ou le mdp n'est pa valable
#TODO: catch livbirt disconnection errors and handle it
Thibault VINCENT
committed
from __init__ import __version__
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',
'uname' : 'get_uname',
'uptime' : 'get_uptime',
'load' : 'get_loadavg',
'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_TAG_WRAP_MAP = {
'h' : 'get_name',
'vm' : 'get_name',
'hv' : 'get_hv_name',
'cpu' : 'get_cpu',
'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
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`
'''
logging.debug('called _call_hv_method(%s)' % method)
return getattr(self.hv_handle, HV_TAG_WRAP_MAP[method])()
def _call_hv_helper(self, method):
logging.debug('called _call_hv_helper(%s)' % method)
return getattr(self, "_helper_hv_" + method)()
def _call_vm_method(self, vm_name, tag):
'''
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`
'''
logging.debug('called _call_vm_method(%s,%s)' % (vm_name, tag))
vm_obj = self.hv_handle.get_vm(vm_name)
return getattr(vm_obj, VM_TAG_WRAP_MAP[tag])()
def _call_vm_helper(self, vm_name, helper):
logging.debug('called _call_vm_helper(%s,%s)' % (vm_name, helper))
vm_obj = self.hv_handle.get_vm(vm_name)
return getattr(self, "_helper_vm_" + helper)(vm_obj)
logging.debug('called _helper_hv_sto()')
result = {}
hv = self.hv_handle
# fetch pool list
pools = hv.get_storage_pools()
result['sto'] = " ".join(pools)
# get pool info
for pool in pools:
# storage type
result['sto%s_type' % pool] = hv.get_storage_type(pool)
# path to the pool base
result['sto%s_path' % pool] = hv.get_storage_path(pool)
result['sto%s_size' % pool] = str(hv.get_storage_capacity(pool))
result['sto%s_used' % pool] = str(hv.get_storage_used(pool))
result['sto%s_free' % pool] = str(hv.get_storage_free(pool))
# pool volume list
result['sto%s_vol' % pool] = hv.get_storage_volumes(pool)
logging.debug('called _helper_hv_disk()')
result = {}
disks = self.hv_handle.get_disks()
result['disk'] = " ".join(disks.keys())
for disk, size in disks.iteritems():
result['disk%s_size' % disk] = str(size)
return result
def _helper_vm_disk(self, vm):
logging.debug('called _helper_vm_disk(%s)' % vm.get_name())
disks = vm.get_disks()
logging.debug('_helper_vm_disk: disk list "%s"' % disks)
if len(disks):
result['disk'] = " ".join(str(id) for id in range(0, len(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] = str(disk['size'])
# disk pool
result['disk%i_pool' % n] = disk['pool']
# disk volume
result['disk%i_vol' % n] = disk['vol']
logging.debug('_helper_vm_disk returns "%s"' % 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 not None:
tags = set(tags)
tags |= set(('h', 'hv'))
hv_tags = HV_TAG_WRAP_MAP.keys() if tags is None else tags
Thibault VINCENT
committed
# static tags
result['version'] = str(__version__)
result[tag] = str(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)
# tag aggregations from wrapping helpers
for helper in HV_TAG_HELPER_LIST:
htags = self._call_hv_helper(helper)
for tag, val in htags.iteritems():
if tags is None or tag in tags:
result.update({tag:val})
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 = {}
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
#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:
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))
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
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):
'''
:param command: the command to execute as it would be typed on a shell
prompt
:type command: :class:`str`
'''