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
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__
doc = inspect.getdoc(attr)
if doc:
cmd['description'] = inspect.cleandoc(doc)
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):
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
125
126
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):
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)
Antoine Millet
committed
@pure
@listed
def destroy(self, query):
self.stop(query, force=True)
Antoine Millet
committed
@pure
@listed
Antoine Millet
committed
self._vm_action(query, 'suspend_vm')
@pure
@listed
def resume(self, query):
self._vm_action(query, 'resume_vm')
def account_setpassword(self, login, password, method='ssha'):
'''
Define a new password for specified user.
'''
self._server.conf.set_password(login, password, method)
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
@pure
@listed
def account_create(self, login, password, role):
'''
Create a new account with specified login.
'''
self._server.conf.create_account(login, password, role)
@pure
@listed
def account_addtag(self, login, tag):
'''
Add a tag to the account with specified login.
'''
self._server.conf.add_tag(login, tag)
@pure
@listed
def account_removetag(self, login, tag):
'''
Remove a tag of the account with specified login.
'''
self._server.conf.remove_tag(login, tag)
@pure
@listed
def account_delete(self, login):
'''
Delete the account with specified login.
'''
self._server.conf.remove_account(login)
@pure
def proxy_client(self, login, command, *args, **kwargs):
client = self._server.get_connection(login)
return client.connection.call(command, *args, **kwargs)
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