Newer
Older
#!/usr/bin/env python
#coding=utf8
import inspect
import logging
from sjrpc.utils import RpcHandler, pure
from tql import TqlQuery
from conf import CCConf
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def listed(func):
func.__listed__ = True
return func
class CCHandler(RpcHandler):
'''
Base class for handlers of CloudControl server.
:cvar role_name: the name of the role binded to the handler
:type role_name: str or None is not applicable
'''
role_name = None
def __init__(self, server):
self._server = server
def __getitem__(self, name):
logging.debug('Called method %s.%s' % (self.__class__.__name__, name))
return super(CCHandler, self).__getitem__(name)
@pure
def list_commands(self):
cmd_list = []
for attr in dir(self):
attr = getattr(self, attr, None)
if getattr(attr, '__listed__', False):
cmd = {}
cmd['name'] = attr.__name__
cmd['description'] = inspect.cleandoc(inspect.getdoc(attr))
cmd_list.append(cmd)
return cmd_list
class OnlineCCHandler(CCHandler):
def on_disconnect(self, connection):
self._server.unregister(connection)
class HypervisorHandler(OnlineCCHandler):
'''
Handler binded to 'node' role.
'''
role_name = 'hypervisor'
class ClientHandler(OnlineCCHandler):
'''
Handler binded to 'cli' role.
'''
role_name = 'client'
def _list(self, query):
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
for condition in query.iterconditions():
tag_name = condition.name
if tag_name in ('a', 'hv', 'h', 'id'):
# Append all accounts:
for login in self._server.conf.list_accounts():
tags = self._server.resolve_tags(login, query.tags)
objects.append(tags)
if tag_name in ('vm', 'h', 'id'):
hvs = [o for o in objects if o['role'] == 'hypervisor'
and o['status'] == 'online']
if not hvs:
for hy in self._server.iter_connected_role('hypervisor'):
tags = self._server.resolve_tags(hy.login, query.tags)
hvs.append(tags)
# Query the selected hypervisors:
logging.debug('Querying %d hypervisors: '
'%s' % (len(hvs), hvs))
async_calls = {}
tags = tuple(query.tags)
for hy_tags in hvs:
hy = self._server.get_connection(hy_tags['a'])
cid = hy.connection.async_call('list_vm', tags=tags)
async_calls[cid] = hy_tags
logging.debug('Waiting for the response of hypervisors...')
calls = frozenset(async_calls)
responses = self._server.manager.wait(calls, timeout=5)
logging.debug('Responses received from hypervisors.')
for resp in responses:
if resp['error'] is None:
hy = async_calls[resp['id']]
for vm_tags in resp['return']:
vm_tags['role'] = 'vm'
vm_tags['id'] = '%s.%s' % (hy['a'], vm_tags['vm'])
vm_tags.update(hy['__static_user'])
objects.append(vm_tags)
# Filter the tag
objects = [o for o in objects if condition.check(o.get(tag_name))]
# Before to return, filter with the asked tags for each objects:
tags = query.tags
tags.add('id')
tags.add('role')
final_objects = {}
for obj in objects:
for key in obj.keys():
if key not in tags:
del obj[key]
final_objects[obj['id']] = obj
return final_objects.values()
@pure
@listed
def list(self, query):
'''
List all objects registered on this instance.
'''
logging.debug('Executed list function with query %s' % query)
return self._list(query)
Antoine Millet
committed
def _vm_action(self, query, method, *args, **kwargs):
vms = self._list(query)
hypervisors = list(self._server.iter_connected_role('hypervisor'))
Antoine Millet
committed
for hv in hypervisors:
vm_to_start = []
for vm in vms:
if vm['role'] != 'vm':
pass
elif vm['id'].split('.')[0] == hv.login:
vm_to_start.append(vm['vm'])
Antoine Millet
committed
if vm_to_start:
hv.connection.call(method, vm_to_start, *args, **kwargs)
@pure
@listed
def start(self, query):
self._vm_action(query, 'start_vm')
@pure
@listed
def stop(self, query, force=False):
self._vm_action(query, 'stop_vm', force)
@pure
@listed
def suspend(self, query):
self._vm_action(query, 'suspend_vm')
@pure
@listed
def resume(self, query):
self._vm_action(query, 'resume_vm')
class AuthenticationError(Exception):
pass
class WelcomeHandler(CCHandler):
'''
Default handler used on client connections of the server.
:cvar ROLES: role name/handler mapping
'''
ROLES = {
'client': ClientHandler,
'hypervisor': HypervisorHandler,
}
@listed
def authentify(self, connection, login, password):
'''
Authenticate the client.
'''
try:
role = self._server.conf.authentify(login, password)
except CCConf.UnknownAccount:
raise AuthenticationError('Authentication failure (Unknown login)')
if role is None:
logging.info('New authentication from %s: failure' % login)
raise AuthenticationError('Authentication failure')
else:
# If authentication is a success, ask tags to the server:
self._server.register(login, role, connection)
connection.set_handler(WelcomeHandler.ROLES.get(role)(self._server))
logging.info('New authentication from %s: success' % login)
return role