From 0690e652645631fae08a5e775f282e2e2f26b369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20=C5=9Eahin?= Date: Mon, 18 Jul 2016 18:21:03 +0300 Subject: [PATCH] new plugins commands added: load,reload and remove with parameters dynamically. Ahenk is loading plugins automatically which is installed while running ahenk --- opt/ahenk/ahenkd.py | 58 +++++++--- opt/ahenk/base/command/commander.py | 20 +++- opt/ahenk/base/plugin/plugin_manager.py | 147 ++++++++++++++++-------- 3 files changed, 160 insertions(+), 65 deletions(-) diff --git a/opt/ahenk/ahenkd.py b/opt/ahenk/ahenkd.py index 90d6ef1..b338104 100755 --- a/opt/ahenk/ahenkd.py +++ b/opt/ahenk/ahenkd.py @@ -3,14 +3,17 @@ # Author: İsmail BAŞARAN # Author: Volkan Şahin +import json import os import queue import signal import sys import threading import time -import json +from multiprocessing import Process + from base.Scope import Scope +from base.agreement.agreement import Agreement from base.command.commander import Commander from base.config.ConfigManager import ConfigManager from base.database.AhenkDbService import AhenkDbService @@ -19,17 +22,14 @@ from base.event.EventManager import EventManager from base.execution.ExecutionManager import ExecutionManager from base.logger.AhenkLogger import Logger from base.messaging.MessageResponseQueue import MessageResponseQueue -from base.messaging.Messenger import Messenger from base.messaging.Messaging import Messaging +from base.messaging.Messenger import Messenger from base.plugin.plugin_manager_factory import PluginManagerFactory -from base.plugin.Plugin import Plugin from base.registration.Registration import Registration from base.scheduler.scheduler_factory import SchedulerFactory from base.system.system import System from base.task.TaskManager import TaskManager -from base.agreement.agreement import Agreement from base.util.util import Util -from multiprocessing import Process ahenkdaemon = None @@ -81,8 +81,9 @@ class AhenkDeamon(BaseDaemon): def init_plugin_manager(self): pluginManager = PluginManagerFactory.get_instance() - pluginManager.loadPlugins() Scope.getInstance().setPluginManager(pluginManager) + # order changed, problem? + pluginManager.load_plugins() return pluginManager def init_task_manager(self): @@ -136,11 +137,6 @@ class AhenkDeamon(BaseDaemon): plugin_manager = scope.getPluginManager() plugin_manager.process_mode('shutdown') - def init_mode(self): - scope = Scope().getInstance() - plugin_manager = scope.getPluginManager() - plugin_manager.process_mode('init') - def registration_failed(self): self.logger.error('[AhenkDeamon] Registration failed. All registration attemps were failed. Ahenk is stopping...') print('Registration failed. Ahenk is stopping..') @@ -206,9 +202,6 @@ class AhenkDeamon(BaseDaemon): self.check_registration() self.logger.info('[AhenkDeamon] Ahenk was registered') - self.init_mode() - self.logger.info('[AhenkDeamon] Plugins were initialized') - self.messenger = self.init_messenger() self.logger.info('[AhenkDeamon] Messager was set') @@ -312,6 +305,9 @@ class AhenkDeamon(BaseDaemon): if agreement_choice is True: db_service.delete('session', 'username=\'{}\''.format(username)) + + self.logger.info('[AhenkDeamon] Display is {0}, desktop env is {1} for {2}'.format(display, desktop, username)) + db_service.update('session', scope.getDbService().get_cols('session'), [username, display, desktop, Util.timestamp()]) get_policy_message = message_manager.policy_request_msg(username) @@ -335,6 +331,38 @@ class AhenkDeamon(BaseDaemon): message = str(json.dumps(json_data['message'])) messenger.send_direct_message(message) + elif 'load' == str(json_data['event']): + plugin_name = str(json_data['plugins']) + + if plugin_name == 'all': + self.logger.info('[AhenkDeamon] All plugins are loading to ahenk'.format(plugin_name)) + plugin_manager.load_plugins() + else: + for p_name in plugin_name.split(','): + self.logger.info('[AhenkDeamon] {} plugin is loading to ahenk'.format(p_name)) + plugin_manager.load_single_plugin(p_name) + + elif 'reload' == str(json_data['event']): + plugin_name = str(json_data['plugins']) + self.logger.info('[AhenkDeamon] {} plugin/s is/are reloading to ahenk'.format(plugin_name)) + + if plugin_name == 'all': + plugin_manager.reload_plugins() + else: + for p_name in plugin_name.split(','): + plugin_manager.reload_single_plugin(p_name) + + elif 'remove' == str(json_data['event']): + plugin_name = str(json_data['plugins']) + + if plugin_name == 'all': + self.logger.info('[AhenkDeamon] All plugins are removing from ahenk'.format(plugin_name)) + plugin_manager.remove_plugins() + else: + for p_name in plugin_name.split(','): + self.logger.info('[AhenkDeamon] {} plugin is removing from ahenk'.format(p_name)) + plugin_manager.remove_single_plugin(p_name) + elif 'stop' == str(json_data['event']): self.shutdown_mode() self.logger.info('[AhenkDeamon] Shutdown mode activated.') @@ -394,7 +422,7 @@ if __name__ == '__main__': except(KeyboardInterrupt, SystemExit): if System.Ahenk.is_running() is True: print('Ahenk stopping...') - result = Commander().set_event(['stop']) + result = Commander().set_event([None, 'stop']) if result is True: if System.Ahenk.is_running() is True: os.kill(int(System.Ahenk.get_pid_number()), signal.SIGALRM) diff --git a/opt/ahenk/base/command/commander.py b/opt/ahenk/base/command/commander.py index 991fad4..e932250 100644 --- a/opt/ahenk/base/command/commander.py +++ b/opt/ahenk/base/command/commander.py @@ -5,7 +5,6 @@ import os import queue as Queue import threading -from base.Scope import Scope from base.command.fifo import Fifo from base.model.enum.ContentType import ContentType from base.model.enum.MessageCode import MessageCode @@ -19,9 +18,14 @@ class Commander(object): pass def set_event(self, *args): + + if args is None or len(args) < 1: + print('ERR') + params = args[0] data = {} + if System.Ahenk.is_running() is True: if len(params) > 1 and params[1] == 'clean': @@ -42,9 +46,21 @@ class Commander(object): data['event'] = params[1] data['username'] = params[2] - elif params[0] == 'stop': + elif len(params) == 2 and params[1] == 'stop': data['event'] = 'stop' + elif len(params) == 4 and params[1] == 'load' and params[2] == '-p': + data['event'] = 'load' + data['plugins'] = params[3] + + elif len(params) == 4 and params[1] == 'reload' and params[2] == '-p': + data['event'] = 'reload' + data['plugins'] = params[3] + + elif len(params) == 4 and params[1] == 'remove' and params[2] == '-p': + data['event'] = 'remove' + data['plugins'] = params[3] + elif len(params) > 5 and params[1] == 'send': data['event'] = params[1] response = {} diff --git a/opt/ahenk/base/plugin/plugin_manager.py b/opt/ahenk/base/plugin/plugin_manager.py index 1019b5f..1ddc0e7 100644 --- a/opt/ahenk/base/plugin/plugin_manager.py +++ b/opt/ahenk/base/plugin/plugin_manager.py @@ -4,6 +4,7 @@ # Author: Volkan Şahin import imp import os +from multiprocessing import Process from base.Scope import Scope from base.model.PluginBean import PluginBean @@ -15,59 +16,65 @@ from base.model.modes.safe_mode import SafeMode from base.model.modes.shutdown_mode import ShutdownMode from base.plugin.Plugin import Plugin from base.plugin.PluginQueue import PluginQueue +from base.plugin.plugin_install_listener import PluginInstallListener +from base.system.system import System # TODO create base abstract class class PluginManager(object): """docstring for PluginManager""" - # implement logger def __init__(self): super(PluginManager, self).__init__() self.scope = Scope.getInstance() self.configManager = self.scope.getConfigurationManager() self.db_service = self.scope.getDbService() + self.message_manager = self.scope.getMessageManager() + self.logger = self.scope.getLogger() self.plugins = [] self.pluginQueueDict = dict() - self.logger = self.scope.getLogger() - self.message_manager = self.scope.getMessageManager() + + self.listener = self.install_listener() self.delayed_profiles = {} self.delayed_tasks = {} # TODO version? - def loadPlugins(self): - """ - This method loads plugins - """ + def load_plugins(self): self.logger.info('[PluginManager] Loading plugins...') self.plugins = [] self.logger.debug('[PluginManager] Lookup for possible plugins...') - try: possible_plugins = os.listdir(self.configManager.get("PLUGIN", "pluginFolderPath")) self.logger.debug('[PluginManager] Possible plugins: {} '.format(str(possible_plugins))) for plugin_name in possible_plugins: - location = os.path.join(self.configManager.get("PLUGIN", "pluginFolderPath"), plugin_name) - if not os.path.isdir(location) or not self.configManager.get("PLUGIN", "mainModuleName") + ".py" in os.listdir(location): - self.logger.debug('It is not a plugin location ! There is no main module - {}'.format(str(location))) - continue try: - self.loadSinglePlugin(plugin_name) + self.load_single_plugin(plugin_name) except Exception as e: - self.logger.error('[PluginManager] Exception occurred when loading plugin ! Plugin name : {} .Error Message: {}'.format(str(plugin_name), str(e))) + self.logger.error('[PluginManager] Exception occurred while loading plugin ! Plugin name : {}. Error Message: {}'.format(str(plugin_name), str(e))) self.logger.info('[PluginManager] Loaded plugins successfully.') except Exception as e: self.logger.warning('[PluginManager] Plugin folder path not found. Error Message: {}'.format(str(e))) - def loadSinglePlugin(self, plugin_name): + def load_single_plugin(self, plugin_name): # TODO check already loaded plugin - self.pluginQueueDict[plugin_name] = PluginQueue() - plugin = Plugin(plugin_name, self.pluginQueueDict[plugin_name]) - plugin.setDaemon(True) - plugin.start() - self.plugins.append(plugin) + location = os.path.join(self.configManager.get("PLUGIN", "pluginFolderPath"), plugin_name) + if not os.path.isdir(location) or not self.configManager.get("PLUGIN", "mainModuleName") + ".py" in os.listdir(location): + self.logger.debug('[PluginManager] It is not a plugin location ! There is no main module - {}'.format(str(location))) + else: + if self.is_plugin_loaded(plugin_name): + self.logger.debug('[PluginManager] {0} plugin was already loaded. Reloading {0} plugin'.format(plugin_name)) + self.reload_single_plugin(plugin_name) + else: + self.pluginQueueDict[plugin_name] = PluginQueue() + plugin = Plugin(plugin_name, self.pluginQueueDict[plugin_name]) + plugin.setDaemon(True) + plugin.start() + self.plugins.append(plugin) + self.logger.debug('[PluginManager] New plugin was loaded. Plugin Name: {}'.format(plugin_name)) - self.logger.debug('[PluginManager] New plugin was loaded. Plugin Name: {}'.format(plugin_name)) + # active init mode + mode = InitMode() + self.pluginQueueDict[plugin_name].put(mode, 1) if len(self.delayed_profiles) > 0: self.pluginQueueDict[plugin_name].put(self.delayed_profiles[plugin_name], 1) @@ -76,7 +83,58 @@ class PluginManager(object): self.pluginQueueDict[plugin_name].put(self.delayed_tasks[plugin_name], 1) self.logger.debug('[PluginManager] Delayed task was found for this plugin. It will be run.') - def findCommand(self, pluginName, commandId): + def reload_plugins(self): + try: + self.logger.info('[PluginManager] Reloading plugins...') + kill_signal = PluginKillSignal() + for p_queue in self.pluginQueueDict: + p_queue.put(kill_signal) + self.plugins = [] + self.load_plugins() + self.logger.info('[PluginManager] Plugin reloaded successfully.') + except Exception as e: + self.logger.error('[PluginManager] Exception occurred when reloading plugins ' + str(e)) + + def reload_single_plugin(self, plugin_name): + try: + self.logger.info('[PluginManager] {} plugin is reloading'.format(plugin_name)) + self.logger.debug('[PluginManager] {} plugin is killing (in reloading action)'.format(plugin_name)) + self.remove_single_plugin(plugin_name) + self.logger.debug('[PluginManager] {} plugin is loading (in reloading action)'.format(plugin_name)) + self.load_single_plugin(plugin_name) + except Exception as e: + self.logger.error('[PluginManager] A problem occurred while reloading {0} plugin. Error Message: {1}'.format(plugin_name, str(e))) + + def remove_plugins(self): + try: + self.logger.debug('[PluginManager] Removing all plugins...') + for p_queue in self.pluginQueueDict: + p_queue.put(PluginKillSignal()) + # todo check is running + self.plugins = [] + self.pluginQueueDict = dict() + self.logger.debug('[PluginManager] All plugins were removed successfully.') + except Exception as e: + self.logger.debug('[PluginManager] A problem occurred while removing plugins. Error Message :{0}.'.format(str(e))) + + def remove_single_plugin(self, plugin_name): + try: + self.logger.debug('[PluginManager] Trying to remove {} plugin...'.format(plugin_name)) + if self.is_plugin_loaded(plugin_name): + self.logger.debug('[PluginManager] {} plugin is killing...'.format(plugin_name)) + self.pluginQueueDict[plugin_name].put(PluginKillSignal(), 1) + del self.pluginQueueDict[plugin_name] + + for plugin in self.plugins: + if plugin.name == plugin_name: + self.plugins.remove(plugin) + self.logger.debug('[PluginManager] {} plugin was removed.'.format(plugin_name)) + else: + self.logger.warning('[PluginManager] {} plugin not found.'.format(plugin_name)) + except Exception as e: + self.logger.error('[PluginManager] A problem occurred while removing {0} plugin. Error Message :{1}.'.format(plugin_name, str(e))) + + def find_command(self, pluginName, commandId): location = os.path.join(self.configManager.get("PLUGIN", "pluginFolderPath"), pluginName) if os.path.isdir(location) and commandId + ".py" in os.listdir(location): info = imp.find_module(commandId, [location]) @@ -85,7 +143,7 @@ class PluginManager(object): self.logger.warning('Command id -' + commandId + ' - not found') return None - def processTask(self, task): + def process_task(self, task): ## scope = Scope().getInstance() @@ -105,19 +163,7 @@ class PluginManager(object): except Exception as e: self.logger.error('[PluginManager] Exception occurred while processing task. Error Message: {}'.format(str(e))) - def reloadPlugins(self): - try: - self.logger.info('[PluginManager] Reloading plugins... ') - kill_sgnl = PluginKillSignal() - for p_queue in self.pluginQueueDict: - p_queue.put(kill_sgnl) - self.plugins = [] - self.loadPlugins() - self.logger.info('[PluginManager] Plugin reloaded successfully.') - except Exception as e: - self.logger.error('[PluginManager] Exception occurred when reloading plugins ' + str(e)) - - def findPolicyModule(self, plugin_name): + def find_policy_module(self, plugin_name): location = os.path.join(self.configManager.get("PLUGIN", "pluginFolderPath"), plugin_name) if os.path.isdir(location) and "policy.py" in os.listdir(location): info = imp.find_module("policy", [location]) @@ -126,13 +172,7 @@ class PluginManager(object): self.logger.warning('[PluginManager] policy.py not found Plugin Name : ' + str(plugin_name)) return None - def is_profile_overridable(self, profiles, plugin_name): - for profile in profiles: - if profile.plugin.name == plugin_name and profile.overridable.lower() == 'true': - return True - return False - - def processPolicy(self, policy): + def process_policy(self, policy): self.logger.info('[PluginManager] Processing policies...') username = policy.username @@ -143,7 +183,7 @@ class PluginManager(object): self.logger.info('[PluginManager] Working on Ahenk profiles...') for agent_profile in ahenk_profiles: - if agent_profile.overridable.lower() != 'true' and self.is_profile_overridable(policy.user_profiles, agent_profile.plugin.name) is True: + if agent_profile.overridable.lower() != 'true': temp_list = [] self.logger.debug('[PluginManager] User profile of {0} plugin will not executed because of profile override rules.'.format(agent_profile.plugin.name)) for usr_profile in user_profiles: @@ -183,7 +223,7 @@ class PluginManager(object): except Exception as e: self.logger.error('[PluginManager] Exception occurred while processing profile. Error Message: {}'.format(str(e))) - def checkPluginExists(self, plugin_name, version=None): + def check_plugin_exists(self, plugin_name, version=None): criteria = ' name=\'' + plugin_name + '\'' if version is not None: @@ -211,6 +251,7 @@ class PluginManager(object): self.logger.error('[PluginManager] Unknown mode type: {}'.format(mode_type)) if mode is not None: + self.logger.info('[PluginManager] {} mode is running'.format(mode_type)) for plugin_name in self.pluginQueueDict: try: self.pluginQueueDict[plugin_name].put(mode, 1) @@ -228,10 +269,20 @@ class PluginManager(object): self.logger.warning('[PluginManager] safe.py not found Plugin Name : ' + str(plugin_name)) return None - def reloadSinglePlugin(self, pluginName): - # Not implemented yet + def install_listener(self): + listener = PluginInstallListener() + thread = Process(target=listener.listen, args=(System.Ahenk.plugins_path(),)) + thread.start() + return thread - pass + def is_plugin_loaded(self, plugin_name): + try: + if self.pluginQueueDict[plugin_name] is not None: + return True + else: + return False + except Exception as e: + return False def checkCommandExist(self, pluginName, commandId): # Not implemented yet