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',
'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_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
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)
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:
Thibault VINCENT
committed
# static tags
result['version'] = str(__version__)
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 = {}
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))
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
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`
'''