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):
# Contains all the objects to be filted:
objects = []
# The query object:
query = TqlQuery(query)
# Get the hypervisors that match the query:
hypervisors = list(self._server.iterrole('hypervisor'))
if query.has_condition('hv'):
hypervisors = query.filter(hypervisors, tag_name='hv',
key=lambda o,n: o.get_tags([n]).get(n))
logging.debug('Querying %d hypervisors: %s' % (len(hypervisors),
hypervisors))
# Try to get vm for each matched hypervisor:
async_calls = {}
tags = tuple(query.tags)
async_calls[hy.connection.async_call('list_vm', tags=tags)] = hy
logging.debug('Waiting for the response of hypervisors...')
responses = self._server.manager.wait(frozenset(async_calls), timeout=5)
logging.debug('Responses received.')
# Make the hypervisor object -> tags mapping:
hv_tags = {}
for hy in hypervisors:
tags = hy.get_tags(tags=tuple(query.tags))
hv_tags[hy] = tags
objects.append(tags)
for resp in responses:
if resp['error'] is None:
hy = async_calls[resp['id']]
for vm in resp['return']:
vm_tags = hv_tags[hy].copy()
vm_tags.update(vm)
vm_tags['role'] = 'vm'
objects.append(vm_tags)
# Filter the objects with the query, and return it:
return query.filter(objects)
@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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def _vm_action(self, query, method, *args, **kwargs):
query += '&vm'
vms = self._list(query)
hypervisors = list(self._server.iterrole('hypervisor'))
for hv in hypervisors:
vm_to_start = [vm['vm'] for vm in vms if vm['hv'] == hv.login]
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