# This file is part of CloudControl. # # CloudControl is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # CloudControl is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with CloudControl. If not, see <http://www.gnu.org/licenses/>. import os import logging import logging.config from functools import wraps from cloudcontrol.common.client.loop import RPCStartHandler, MainLoop from cloudcontrol.common.client.tags import Tag from cloudcontrol.node import __version__ from cloudcontrol.node.config import NodeConfigParser, configure_logging from cloudcontrol.node.jobs import JobManager from cloudcontrol.node.exc import ForbiddenHandler logger = logging.getLogger(__name__) def _rights_check(handler_name): """Method instance decorator for checking permissions before executing an RPC handler. """ def decorator(func): @wraps(func) def decorated(*args, **kwargs): if handler_name in func.im_self.main.config.forbidden_handlers: logger.error('Remote tried to call forbidden handler "%s"', handler_name) raise ForbiddenHandler('Forbidden handler "%s"' % handler_name) return func(*args, **kwargs) return decorated return decorator class NodeRPCStartHandler(RPCStartHandler): def handle_authentication_response(self, response=None): # set handler according to which role was returned by the cc-server if response == self.loop.role and response is not None: # we don't need to reload the plugins # but we need to register the objects and tags self.loop.tag_db.rpc_register() elif response == u'host': # close previous plugins if needed if self.loop.role is not None: self.loop.close_plugins() logger.debug('Role host affected') from cloudcontrol.node.host import Handler as HostHandler self.loop.main_plugin = HostHandler(loop=self.loop) self.loop.role = 'host' # (re)-register the tags of the main loop self.loop.tag_db.rpc_register() self.loop.register_plugin(self.loop.main_plugin) elif response == u'hv': # close previous plugins if needed if self.loop.role is not None: self.loop.close_plugins() logger.debug('Role hypervisor affected') # set libvirt environement variables os.environ['LIBVIRT_DEBUG'] = '4' # os.environ['LIBVIRT_LOG_FILTERS'] = '' os.environ['LIBVIRT_LOG_OUTPUT'] = '4:stderr' # we don't import those modules at the top because some dependancies # may not be installed from cloudcontrol.node.hypervisor import Handler as HypervisorHandler self.loop.main_plugin = HypervisorHandler( hypervisor_name=self.loop.config.server_user, loop=self.loop, ) self.loop.role = 'hv' # (re)-register the tags of the main loop self.loop.tag_db.rpc_register() self.loop.register_plugin(self.loop.main_plugin) else: logger.error('Failed authentication, role returned: %s', response) self._goto(self.handle_error) return self._goto(self.handle_done) class NodeLoop(MainLoop): CONFIG_CLASS = NodeConfigParser CONNECT_CLASS = NodeRPCStartHandler DEFAULT_TAGS = (Tag(u'version', __version__),) def __init__(self, config_path): MainLoop.__init__(self, config_path) self.job_manager = JobManager(self) def reset_handler(self, name, handl): # we decorate each handler for permissions to be checked before each # invocation MainLoop.reset_handler(self, name, _rights_check(name)(handl)) def configure_logging(self): configure_logging(self.config.logging_level, self.config.logging_output) def stop(self, watcher=None, revents=None): MainLoop.stop(self, watcher, revents) # stop running jobs self.job_manager.stop()