def main(self): self.set_proctitle(self.name) # Daemon like init self.debug_output = [] self.modules_dir = modulesctx.get_modulesdir() self.modules_manager = ModulesManager('webui', self.find_modules_path(), []) self.modules_manager.set_modules(self.modules) # We can now output some previously silenced debug output self.do_load_modules() for inst in self.modules_manager.instances: f = getattr(inst, 'load', None) if f and callable(f): f(self) for s in self.debug_output: print s del self.debug_output # Check if the Bottle view dir really exist if not os.path.exists(bottle.TEMPLATE_PATH[0]): logger.error("[WebUI] The view path do not exist at %s" % bottle.TEMPLATE_PATH) sys.exit(2) # Check directories # We check if the photo directory exists. If not, try to create it for d in [self.photo_dir, self.share_dir, self.config_dir]: logger.debug("[WebUI] Checking dir: %s", d) if not os.path.exists(d): try: os.mkdir(d) logger.info("[WebUI] Created dir: %s", d) except Exception, exp: logger.error("[WebUI] Dir creation failed: %s", exp)
def get_module(self, mod_name): if self.modules_dir and self.modules_dir not in sys.path: sys.path.append(self.modules_dir) if self.modules_dir: mod_dir = os.path.join(self.modules_dir, mod_name) else: mod_dir = None # to keep it back-compatible with previous Shinken module way, # we first try with "import `mod_name`.module" and if we succeed # then that's the one to actually use: mod = ModulesManager.try_best_load('.module', mod_name) if mod: return mod # otherwise simply try new and old style: return ModulesManager.try_load(mod_name, mod_dir)
def init_livestatus(self, modconf=None, dbmodconf=None, needcache=False): self.livelogs = 'tmp/livelogs.db' + self.testid if modconf is None: modconf = Module({'module_name': 'LiveStatus', 'module_type': 'livestatus', 'port': str(50000 + os.getpid()), 'pnp_path': 'tmp/pnp4nagios_test' + self.testid, 'host': '127.0.0.1', 'socket': 'live', 'name': 'test', #? }) if dbmodconf is None: dbmodconf = Module({'module_name': 'LogStore', 'module_type': 'logstore_sqlite', 'use_aggressive_sql': "0", 'database_file': self.livelogs, 'archive_path': os.path.join(os.path.dirname(self.livelogs), 'archives'), }) modconf.modules = [dbmodconf] self.livestatus_broker = LiveStatus_broker(modconf) self.livestatus_broker.create_queues() #--- livestatus_broker.main self.livestatus_broker.log = logger # this seems to damage the logger so that the scheduler can't use it #self.livestatus_broker.log.load_obj(self.livestatus_broker) self.livestatus_broker.debug_output = [] self.livestatus_broker.modules_manager = ModulesManager('livestatus', modules_dir, []) self.livestatus_broker.modules_manager.set_modules(self.livestatus_broker.modules) # We can now output some previouly silented debug ouput self.livestatus_broker.do_load_modules() for inst in self.livestatus_broker.modules_manager.instances: if inst.properties["type"].startswith('logstore'): f = getattr(inst, 'load', None) if f and callable(f): f(self.livestatus_broker) # !!! NOT self here !!!! break for s in self.livestatus_broker.debug_output: print "errors during load", s del self.livestatus_broker.debug_output self.livestatus_broker.rg = LiveStatusRegenerator() self.livestatus_broker.datamgr = datamgr datamgr.load(self.livestatus_broker.rg) self.livestatus_broker.query_cache = LiveStatusQueryCache() if not needcache: self.livestatus_broker.query_cache.disable() self.livestatus_broker.rg.register_cache(self.livestatus_broker.query_cache) #--- livestatus_broker.main self.livestatus_broker.init() self.livestatus_broker.db = self.livestatus_broker.modules_manager.instances[0] self.livestatus_broker.livestatus = LiveStatus(self.livestatus_broker.datamgr, self.livestatus_broker.query_cache, self.livestatus_broker.db, self.livestatus_broker.pnp_path, self.livestatus_broker.from_q) #--- livestatus_broker.do_main self.livestatus_broker.db.open() if hasattr(self.livestatus_broker.db, 'prepare_log_db_table'): self.livestatus_broker.db.prepare_log_db_table()
def __init__(self, name, config_file, is_daemon, do_replace, debug, debug_file): self.check_shm() self.name = name self.config_file = config_file self.is_daemon = is_daemon self.do_replace = do_replace self.debug = debug self.debug_file = debug_file self.interrupted = False # Track time now = time.time() self.program_start = now self.t_each_loop = now # used to track system time change self.sleep_time = 0.0 #used to track the time we wait self.pyro_daemon = None # Log init self.log = logger self.log.load_obj(self) self.new_conf = None # used by controller to push conf self.cur_conf = None # Flag to know if we need to dump memory or not self.need_dump_memory = False #Keep a trace of the local_log file desc if need self.local_log_fd = None self.modules_manager = ModulesManager(name, self.find_modules_path(), []) os.umask(UMASK) self.set_exit_handler()
def __init__(self, name, config_file, is_daemon, do_replace, debug, debug_file): self.check_shm() self.name = name self.config_file = config_file self.is_daemon = is_daemon self.do_replace = do_replace self.debug = debug self.debug_file = debug_file self.interrupted = False # Track time now = time.time() self.program_start = now self.t_each_loop = now # used to track system time change self.sleep_time = 0.0 #used to track the time we wait self.pyro_daemon = None # Log init self.log = logger self.log.load_obj(self) self.new_conf = None # used by controller to push conf self.cur_conf = None # Flag to know if we need to dump memory or not self.need_dump_memory = False #Keep a trace of the local_log file desc if need self.local_log_fd = None # Put in queue some debug output we will raise # when we will be in daemon self.debug_output = [] self.modules_manager = ModulesManager(name, self.find_modules_path(), []) os.umask(UMASK) self.set_exit_handler()
class Daemon(object): properties = { # workdir is relative to $(dirname "$0"/..) # where "$0" is the path of the file being executed, # in python normally known as: # # os.path.join( os.getcwd(), sys.argv[0] ) # # as returned once the daemon is started. 'workdir': PathProp(default='var'), 'host': StringProp(default='0.0.0.0'), 'user': StringProp(default=get_cur_user()), 'group': StringProp(default=get_cur_group()), 'use_ssl': BoolProp(default='0'), 'certs_dir': StringProp(default='etc/certs'), 'ca_cert': StringProp(default='etc/certs/ca.pem'), 'server_cert': StringProp(default='etc/certs/server.pem'), 'use_local_log': BoolProp(default='1'), 'hard_ssl_name_check': BoolProp(default='0'), 'idontcareaboutsecurity': BoolProp(default='0'), 'spare': BoolProp(default='0') } def __init__(self, name, config_file, is_daemon, do_replace, debug, debug_file): self.check_shm() self.name = name self.config_file = config_file self.is_daemon = is_daemon self.do_replace = do_replace self.debug = debug self.debug_file = debug_file self.interrupted = False # Track time now = time.time() self.program_start = now self.t_each_loop = now # used to track system time change self.sleep_time = 0.0 #used to track the time we wait self.pyro_daemon = None # Log init self.log = logger self.log.load_obj(self) self.new_conf = None # used by controller to push conf self.cur_conf = None # Flag to know if we need to dump memory or not self.need_dump_memory = False #Keep a trace of the local_log file desc if need self.local_log_fd = None # Put in queue some debug output we will raise # when we will be in daemon self.debug_output = [] self.modules_manager = ModulesManager(name, self.find_modules_path(), []) os.umask(UMASK) self.set_exit_handler() # At least, lose the local log file if need def do_stop(self): if self.modules_manager: # We save what we can but NOT for the scheduler # because the current sched object is a dummy one # and the old one aleady do it! if not hasattr(self, 'sched'): self.hook_point('save_retention') # And we quit logger.log('Stopping all modules') self.modules_manager.stop_all() if self.pyro_daemon: pyro.shutdown(self.pyro_daemon)#.shutdown(True) logger.quit() def request_stop(self): self.unlink() ## unlink first self.do_stop() print("Exiting") sys.exit(0) def do_loop_turn(self): raise NotImplementedError() # Main loop for nearly all daemon # the scheduler is not managed by it :'( def do_mainloop(self): while True: self.do_loop_turn() # If ask us to dump memory, do it if self.need_dump_memory: self.dump_memory() self.need_dump_memory = False # Maybe we ask us to die, if so, do it :) if self.interrupted: break self.request_stop() def do_load_modules(self): self.modules_manager.load_and_init() self.log.log("I correctly loaded the modules : [%s]" % (','.join([inst.get_name() for inst in self.modules_manager.instances]))) def add(self, elt): """ Dummy method for adding broker to this daemon """ pass def dump_memory(self): logger.log("I dump my memory, it can ask some seconds to do") try: from guppy import hpy hp = hpy() logger.log(hp.heap()) except ImportError: logger.log('I do not have the module guppy for memory dump, please install it') def load_config_file(self): self.parse_config_file() if self.config_file is not None: # Some paths can be relatives. We must have a full path by taking # the config file by reference self.relative_paths_to_full(os.path.dirname(self.config_file)) pass def change_to_workdir(self): try: os.chdir(self.workdir) except Exception, e: raise InvalidWorkDir(e) print("Successfully changed to workdir: %s" % (self.workdir))
class Webui_broker(BaseModule, Daemon): def __init__(self, modconf): BaseModule.__init__(self, modconf) self.plugins = [] self.modconf = modconf # Web server configuration self.host = getattr(modconf, 'host', '0.0.0.0') self.port = int(getattr(modconf, 'port', '7767')) logger.info("[WebUI] server: %s:%d", self.host, self.port) self.endpoint = getattr(modconf, 'endpoint', None) if self.endpoint: if self.endpoint.endswith('/'): self.endpoint = self.endpoint[:-1] logger.info("[WebUI] configured endpoint: %s", self.endpoint) logger.warning("[WebUI] endpoint feature is not implemented! WebUI is served from root URL: http://%s:%d/", self.host, self.port) self.endpoint = None self.auth_secret = resolve_auth_secret(modconf) # TODO : common preferences self.play_sound = to_bool(getattr(modconf, 'play_sound', '0')) # TODO : common preferences self.login_text = getattr(modconf, 'login_text', None) # TODO : common preferences self.company_logo = getattr(modconf, 'company_logo', 'default_company') if self.company_logo == '': # Set a dummy value if webui.cfg value is empty to force using the default logo ... self.company_logo = 'abcdef' # TODO : common preferences self.gravatar = to_bool(getattr(modconf, 'gravatar', '0')) # TODO : common preferences self.allow_html_output = to_bool(getattr(modconf, 'allow_html_output', '0')) # TODO : common preferences #self.max_output_length = int(getattr(modconf, 'max_output_length', '100')) # TODO : common preferences self.refresh_period = int(getattr(modconf, 'refresh_period', '60')) # Use element tag as image or use text self.tag_as_image = to_bool(getattr(modconf, 'tag_as_image', '0')) # Manage user's ACL self.manage_acl = to_bool(getattr(modconf, 'manage_acl', '1')) self.allow_anonymous = to_bool(getattr(modconf, 'allow_anonymous', '0')) # Advanced options self.http_backend = getattr(modconf, 'http_backend', 'auto') self.remote_user_enable = getattr(modconf, 'remote_user_enable', '0') self.remote_user_variable = getattr(modconf, 'remote_user_variable', 'X_REMOTE_USER') self.serveropts = {} umask = getattr(modconf, 'umask', None) if umask is not None: self.serveropts['umask'] = int(umask) bindAddress = getattr(modconf, 'bindAddress', None) if bindAddress: self.serveropts['bindAddress'] = str(bindAddress) # Apache htpasswd file for authentication self.htpasswd_file = getattr(modconf, 'htpasswd_file', None) if self.htpasswd_file: if not os.path.exists(self.htpasswd_file): logger.warning("[WebUI] htpasswd file '%s' does not exist.", self.htpasswd_file) self.htpasswd_file = None # Load the config dir and make it an absolute path self.config_dir = getattr(modconf, 'config_dir', 'share') self.config_dir = os.path.abspath(self.config_dir) logger.info("[WebUI] Config dir: %s", self.config_dir) # Load the share dir and make it an absolute path self.share_dir = getattr(modconf, 'share_dir', 'share') self.share_dir = os.path.abspath(self.share_dir) logger.info("[WebUI] Share dir: %s", self.share_dir) # Load the photo dir and make it an absolute path self.photo_dir = getattr(modconf, 'photos_dir', 'photos') self.photo_dir = os.path.abspath(self.photo_dir) logger.info("[WebUI] Photo dir: %s", self.photo_dir) self.user_picture = '' # @mohierf: still useful ? No value in webui.cfg, so always False ... # self.embeded_graph = to_bool(getattr(modconf, 'embeded_graph', '0')) # Look for an additional pages dir self.additional_plugins_dir = getattr(modconf, 'additional_plugins_dir', '') if self.additional_plugins_dir: self.additional_plugins_dir = os.path.abspath(self.additional_plugins_dir) logger.info("[WebUI] Additional plugins dir: %s", self.additional_plugins_dir) # Web UI timezone self.timezone = getattr(modconf, 'timezone', 'Europe/Paris') if self.timezone: logger.info("[WebUI] Setting our timezone to %s", self.timezone) os.environ['TZ'] = self.timezone time.tzset() logger.info("[WebUI] parameter timezone: %s", self.timezone) # Visual alerting thresholds # Used in the dashboard view to select background color for percentages self.hosts_states_warning = int(getattr(modconf, 'hosts_states_warning', '95')) self.hosts_states_critical = int(getattr(modconf, 'hosts_states_critical', '90')) self.services_states_warning = int(getattr(modconf, 'services_states_warning', '95')) self.services_states_critical = int(getattr(modconf, 'services_states_critical', '90')) # Web UI information self.app_version = getattr(modconf, 'about_version', WEBUI_VERSION) self.app_copyright = getattr(modconf, 'about_copyright', WEBUI_COPYRIGHT) self.app_release = getattr(modconf, 'about_release', WEBUI_RELEASENOTES) # We will save all widgets self.widgets = {} # We need our regenerator now (before main) so if we are in a scheduler, # rg will be able to skip some broks self.rg = Regenerator() # My bottle object ... self.bottle = bottle bottle.BaseTemplate.defaults['app'] = self # Called by Broker so we can do init stuff def init(self): logger.info("[WebUI] Initializing ...") self.rg.load_external_queue(self.from_q) # This is called only when we are in a scheduler # and just before we are started. So we can gain time, and # just load all scheduler objects without fear :) (we # will be in another process, so we will be able to hack objects # if need) def hook_pre_scheduler_mod_start(self, sched): print "pre_scheduler_mod_start::", sched.__dict__ self.rg.load_from_scheduler(sched) # In a scheduler we will have a filter of what we really want as a brok def want_brok(self, b): return self.rg.want_brok(b) def main(self): self.set_proctitle(self.name) # Daemon like init self.debug_output = [] self.modules_dir = modulesctx.get_modulesdir() self.modules_manager = ModulesManager('webui', self.find_modules_path(), []) self.modules_manager.set_modules(self.modules) # We can now output some previously silenced debug output self.do_load_modules() for inst in self.modules_manager.instances: f = getattr(inst, 'load', None) if f and callable(f): f(self) for s in self.debug_output: print s del self.debug_output # Check if the Bottle view dir really exist if not os.path.exists(bottle.TEMPLATE_PATH[0]): logger.error("[WebUI] The view path do not exist at %s" % bottle.TEMPLATE_PATH) sys.exit(2) # Check directories # We check if the photo directory exists. If not, try to create it for d in [self.photo_dir, self.share_dir, self.config_dir]: logger.debug("[WebUI] Checking dir: %s", d) if not os.path.exists(d): try: os.mkdir(d) logger.info("[WebUI] Created dir: %s", d) except Exception, exp: logger.error("[WebUI] Dir creation failed: %s", exp) # :TODO:maethor:150724: Complete with other function names self.auth_module = AuthMetaModule(AuthMetaModule.find_modules(self.modules_manager.get_internal_instances()), self) self.prefs_module = PrefsMetaModule(PrefsMetaModule.find_modules(self.modules_manager.get_internal_instances()), self) self.logs_module = LogsMetaModule(LogsMetaModule.find_modules(self.modules_manager.get_internal_instances()), self) self.graphs_module = GraphsMetaModule(GraphsMetaModule.find_modules(self.modules_manager.get_internal_instances()), self) self.helpdesk_module = HelpdeskMetaModule(HelpdeskMetaModule.find_modules(self.modules_manager.get_internal_instances()), self) # Data manager self.datamgr = WebUIDataManager(self.rg) self.helper = helper self.request = bottle.request self.response = bottle.response # :TODO:maethor:150717: Doesn't work #username = self.request.get_cookie("user", secret=self.auth_secret) #if username: #self.user = User.from_contact(self.datamgr.get_contact(username), self.gravatar) #else: #self.user = None try: self.do_main() except Exception, exp: msg = Message(id=0, type='ICrash', data={'name': self.get_name(), 'exception': exp, 'trace': traceback.format_exc()}) self.from_q.put(msg) # wait 2 sec so we know that the broker got our message, and die time.sleep(2) raise
def main(self, stand_alone=False): """ Module main function """ self.stand_alone = stand_alone if self.stand_alone: setproctitle(self.name) else: self.set_proctitle(self.name) # Modules management self.debug_output = [] self.modules_dir = modulesctx.get_modulesdir() self.modules_manager = ModulesManager('webui', self.find_modules_path(), []) self.modules_manager.set_modules(self.modules) logger.info("[WebUI] modules %s", self.modules) # We can now output some previously silenced debug output self.do_load_modules() for inst in self.modules_manager.instances: f = getattr(inst, 'load', None) if f and callable(f): f(self) for s in self.debug_output: print s del self.debug_output logger.info("[WebUI] loaded modules %s", self.modules) # Check if the Bottle view dir really exist if not os.path.exists(bottle.TEMPLATE_PATH[0]): logger.error("[WebUI] The view path do not exist at %s", bottle.TEMPLATE_PATH) sys.exit(2) # Load internal sub modules self.auth_module = AuthMetaModule( AuthMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.prefs_module = PrefsMetaModule( PrefsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.logs_module = LogsMetaModule( LogsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.graphs_module = GraphsMetaModule( GraphsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.helpdesk_module = HelpdeskMetaModule( HelpdeskMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) # Data manager self.datamgr = WebUIDataManager(self.rg, self.frontend, self.alignak_backend_objects) self.helper = helper # Check directories # We check if the photo directory exists. If not, try to create it for dir in [self.share_dir, self.photo_dir, self.config_dir]: logger.debug("[WebUI] Checking dir: %s", dir) if not os.path.exists(dir): try: # os.mkdir(dir) os.makedirs(dir, mode=0o777) logger.info("[WebUI] Created directory: %s", dir) except Exception as e: logger.error( "[WebUI] Directory creation failed: %s, error: %s", dir, str(e)) else: logger.debug("[WebUI] Still existing directory: %s", dir) # Bottle objects self.request = bottle.request self.response = bottle.response try: # I register my exit function self.set_exit_handler() # First load the additional plugins so they will have the lead on URI routes if self.additional_plugins_dir: self.load_plugins(self.additional_plugins_dir) # Modules can also override some views if need for inst in self.modules_manager.instances: f = getattr(inst, 'get_webui_plugins_path', None) if f and callable(f): mod_plugins_path = os.path.abspath(f(self)) self.load_plugins(mod_plugins_path) # Then look at the plugins into core and load all we can there core_plugin_dir = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'plugins') self.load_plugins(core_plugin_dir) # Declare the whole app static files AFTER the plugin ones self.declare_common_static() # Mount Web UI application # if self.endpoint: # root_app.mount(self.endpoint, webui_app) # logger.info("[WebUI] root routes: %s", root_app.routes) # for route in webui_app.routes: # logger.info("[WebUI] route: %s", route) for route in webui_app.routes: logger.info("[WebUI] route: %s", route) # We will protect the operations on # the non read+write with a lock and # 2 int self.global_lock = threading.RLock() self.nb_readers = 0 self.nb_writers = 0 self.data_thread = None self.ls_thread = None # For alignak backend ... if self.frontend: # Launch the livestate thread ... self.ls_thread = threading.Thread(None, self.manage_ls_thread, 'lsthread') self.ls_thread.start() else: # Launch the data thread ... self.data_thread = threading.Thread(None, self.manage_brok_thread, 'datathread') self.data_thread.start() # TODO: look for alive and killing logger.info("[WebUI] starting Web UI server on %s:%d ...", self.host, self.port) bottle.TEMPLATES.clear() webui_app.run(host=self.host, port=self.port, server=self.http_backend, **self.serveropts) except Exception as e: if self.stand_alone: logger.error("[WebUI] do_main exception: %s", str(e)) logger.error("[WebUI] traceback: %s", traceback.format_exc()) exit(1) else: msg = Message(id=0, type='ICrash', data={ 'name': self.get_name(), 'exception': e, 'trace': traceback.format_exc() }) self.from_q.put(msg) # wait 2 sec so we know that the broker got our message, and die time.sleep(2) raise
class Webui_broker(BaseModule, Daemon): def __init__(self, modconf): BaseModule.__init__(self, modconf) self.plugins = [] self.modconf = modconf # Web server configuration self.host = getattr(modconf, 'host', '0.0.0.0') self.port = int(getattr(modconf, 'port', '7767')) logger.info("[WebUI] server: %s:%d", self.host, self.port) self.endpoint = getattr(modconf, 'endpoint', None) if self.endpoint: if self.endpoint.endswith('/'): self.endpoint = self.endpoint[:-1] logger.info("[WebUI] configured endpoint: %s", self.endpoint) logger.warning( "[WebUI] endpoint feature is not implemented! WebUI is served from root URL: http://%s:%d/", self.host, self.port) self.endpoint = None # Build session cookie self.session_cookie = getattr(modconf, 'cookie_name', 'user') self.auth_secret = resolve_auth_secret(modconf) logger.info("[WebUI] cookie: %s", self.session_cookie) # TODO : common preferences self.play_sound = to_bool(getattr(modconf, 'play_sound', '0')) # TODO : common preferences self.login_text = getattr(modconf, 'login_text', None) # TODO : common preferences self.company_logo = getattr(modconf, 'company_logo', 'default_company') if self.company_logo == '': # Set a dummy value if webui.cfg value is empty to force using the default logo ... self.company_logo = 'abcdef' # TODO : common preferences self.gravatar = to_bool(getattr(modconf, 'gravatar', '0')) # TODO : common preferences self.allow_html_output = to_bool( getattr(modconf, 'allow_html_output', '0')) # TODO : common preferences #self.max_output_length = int(getattr(modconf, 'max_output_length', '100')) # TODO : common preferences self.refresh_period = int(getattr(modconf, 'refresh_period', '60')) self.refresh = False if self.refresh_period == 0 else True # Use element tag as image or use text self.tag_as_image = to_bool(getattr(modconf, 'tag_as_image', '0')) # Manage user's ACL self.manage_acl = to_bool(getattr(modconf, 'manage_acl', '1')) self.allow_anonymous = to_bool(getattr(modconf, 'allow_anonymous', '0')) # Allow to customize default downtime duration self.default_downtime_hours = int( getattr(modconf, 'default_downtime_hours', '48')) self.shinken_downtime_fixed = int( getattr(modconf, 'shinken_downtime_fixed', '1')) self.shinken_downtime_trigger = int( getattr(modconf, 'shinken_downtime_trigger', '0')) self.shinken_downtime_duration = int( getattr(modconf, 'shinken_downtime_duration', '0')) # Allow to customize default acknowledge parameters self.default_ack_sticky = int( getattr(modconf, 'default_ack_sticky', '2')) self.default_ack_notify = int( getattr(modconf, 'default_ack_notify', '1')) self.default_ack_persistent = int( getattr(modconf, 'default_ack_persistent', '1')) # Advanced options self.http_backend = getattr(modconf, 'http_backend', 'auto') self.remote_user_enable = getattr(modconf, 'remote_user_enable', '0') self.remote_user_variable = getattr(modconf, 'remote_user_variable', 'X_REMOTE_USER') self.serveropts = {} umask = getattr(modconf, 'umask', None) if umask is not None: self.serveropts['umask'] = int(umask) bindAddress = getattr(modconf, 'bindAddress', None) if bindAddress: self.serveropts['bindAddress'] = str(bindAddress) # Apache htpasswd file for authentication self.htpasswd_file = getattr(modconf, 'htpasswd_file', None) if self.htpasswd_file: if not os.path.exists(self.htpasswd_file): logger.warning("[WebUI] htpasswd file '%s' does not exist.", self.htpasswd_file) self.htpasswd_file = None # Alignak backend for authentication self.frontend = None self.alignak_backend_objects = False self.alignak_backend_endpoint = getattr(modconf, 'alignak_backend_endpoint', None) if frontend_available and self.alignak_backend_endpoint: self.frontend = FrontEnd() if self.frontend: self.frontend.configure(self.alignak_backend_endpoint) logger.info("[WebUI] alignak backend: %s", self.frontend.url_endpoint_root) self.alignak_backend_objects = to_bool( getattr(modconf, 'alignak_backend_objects', '0')) # Load the config dir and make it an absolute path self.config_dir = getattr(modconf, 'config_dir', 'share') self.config_dir = os.path.abspath(self.config_dir) logger.info("[WebUI] Config dir: %s", self.config_dir) # Load the share dir and make it an absolute path self.share_dir = getattr(modconf, 'share_dir', 'share') self.share_dir = os.path.abspath(self.share_dir) logger.info("[WebUI] Share dir: %s", self.share_dir) # Load the photo dir and make it an absolute path self.photo_dir = getattr(modconf, 'photos_dir', 'photos') self.photo_dir = os.path.abspath(self.photo_dir) logger.info("[WebUI] Photo dir: %s", self.photo_dir) # User information self.user_session = None self.user_info = None # @mohierf: still useful ? No value in webui.cfg, so always False ... # self.embeded_graph = to_bool(getattr(modconf, 'embeded_graph', '0')) # Look for an additional pages dir self.additional_plugins_dir = getattr(modconf, 'additional_plugins_dir', '') if self.additional_plugins_dir: self.additional_plugins_dir = os.path.abspath( self.additional_plugins_dir) logger.info("[WebUI] Additional plugins dir: %s", self.additional_plugins_dir) # Web UI timezone self.timezone = getattr(modconf, 'timezone', 'Europe/Paris') if self.timezone: logger.info("[WebUI] Setting our timezone to %s", self.timezone) os.environ['TZ'] = self.timezone time.tzset() logger.info("[WebUI] parameter timezone: %s", self.timezone) # Visual alerting thresholds # Used in the dashboard view to select background color for percentages self.hosts_states_warning = int( getattr(modconf, 'hosts_states_warning', '95')) self.hosts_states_critical = int( getattr(modconf, 'hosts_states_critical', '90')) self.services_states_warning = int( getattr(modconf, 'services_states_warning', '95')) self.services_states_critical = int( getattr(modconf, 'services_states_critical', '90')) # Web UI information self.app_version = getattr(modconf, 'about_version', WEBUI_VERSION) self.app_copyright = getattr(modconf, 'about_copyright', WEBUI_COPYRIGHT) # We will save all widgets self.widgets = {} # We need our regenerator now (before main) so if we are in a scheduler, # rg will be able to skip some broks self.rg = None if not self.alignak_backend_objects: self.rg = Regenerator() # My bottle object ... self.bottle = bottle bottle.BaseTemplate.defaults['app'] = self # Called by Broker so we can do init stuff def init(self): logger.info("[WebUI] Initializing ...") if not self.alignak_backend_objects: self.rg.load_external_queue(self.from_q) # This is called only when we are in a scheduler # and just before we are started. So we can gain time, and # just load all scheduler objects without fear :) (we # will be in another process, so we will be able to hack objects # if need) def hook_pre_scheduler_mod_start(self, sched): print "pre_scheduler_mod_start::", sched.__dict__ self.rg.load_from_scheduler(sched) # In a scheduler we will have a filter of what we really want as a brok def want_brok(self, b): return self.rg.want_brok(b) def main(self, stand_alone=False): """ Module main function """ self.stand_alone = stand_alone if self.stand_alone: setproctitle(self.name) else: self.set_proctitle(self.name) # Modules management self.debug_output = [] self.modules_dir = modulesctx.get_modulesdir() self.modules_manager = ModulesManager('webui', self.find_modules_path(), []) self.modules_manager.set_modules(self.modules) logger.info("[WebUI] modules %s", self.modules) # We can now output some previously silenced debug output self.do_load_modules() for inst in self.modules_manager.instances: f = getattr(inst, 'load', None) if f and callable(f): f(self) for s in self.debug_output: print s del self.debug_output logger.info("[WebUI] loaded modules %s", self.modules) # Check if the Bottle view dir really exist if not os.path.exists(bottle.TEMPLATE_PATH[0]): logger.error("[WebUI] The view path do not exist at %s", bottle.TEMPLATE_PATH) sys.exit(2) # Load internal sub modules self.auth_module = AuthMetaModule( AuthMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.prefs_module = PrefsMetaModule( PrefsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.logs_module = LogsMetaModule( LogsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.graphs_module = GraphsMetaModule( GraphsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.helpdesk_module = HelpdeskMetaModule( HelpdeskMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) # Data manager self.datamgr = WebUIDataManager(self.rg, self.frontend, self.alignak_backend_objects) self.helper = helper # Check directories # We check if the photo directory exists. If not, try to create it for dir in [self.share_dir, self.photo_dir, self.config_dir]: logger.debug("[WebUI] Checking dir: %s", dir) if not os.path.exists(dir): try: # os.mkdir(dir) os.makedirs(dir, mode=0o777) logger.info("[WebUI] Created directory: %s", dir) except Exception as e: logger.error( "[WebUI] Directory creation failed: %s, error: %s", dir, str(e)) else: logger.debug("[WebUI] Still existing directory: %s", dir) # Bottle objects self.request = bottle.request self.response = bottle.response try: # I register my exit function self.set_exit_handler() # First load the additional plugins so they will have the lead on URI routes if self.additional_plugins_dir: self.load_plugins(self.additional_plugins_dir) # Modules can also override some views if need for inst in self.modules_manager.instances: f = getattr(inst, 'get_webui_plugins_path', None) if f and callable(f): mod_plugins_path = os.path.abspath(f(self)) self.load_plugins(mod_plugins_path) # Then look at the plugins into core and load all we can there core_plugin_dir = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'plugins') self.load_plugins(core_plugin_dir) # Declare the whole app static files AFTER the plugin ones self.declare_common_static() # Mount Web UI application # if self.endpoint: # root_app.mount(self.endpoint, webui_app) # logger.info("[WebUI] root routes: %s", root_app.routes) # for route in webui_app.routes: # logger.info("[WebUI] route: %s", route) for route in webui_app.routes: logger.info("[WebUI] route: %s", route) # We will protect the operations on # the non read+write with a lock and # 2 int self.global_lock = threading.RLock() self.nb_readers = 0 self.nb_writers = 0 self.data_thread = None self.ls_thread = None # For alignak backend ... if self.frontend: # Launch the livestate thread ... self.ls_thread = threading.Thread(None, self.manage_ls_thread, 'lsthread') self.ls_thread.start() else: # Launch the data thread ... self.data_thread = threading.Thread(None, self.manage_brok_thread, 'datathread') self.data_thread.start() # TODO: look for alive and killing logger.info("[WebUI] starting Web UI server on %s:%d ...", self.host, self.port) bottle.TEMPLATES.clear() webui_app.run(host=self.host, port=self.port, server=self.http_backend, **self.serveropts) except Exception as e: if self.stand_alone: logger.error("[WebUI] do_main exception: %s", str(e)) logger.error("[WebUI] traceback: %s", traceback.format_exc()) exit(1) else: msg = Message(id=0, type='ICrash', data={ 'name': self.get_name(), 'exception': e, 'trace': traceback.format_exc() }) self.from_q.put(msg) # wait 2 sec so we know that the broker got our message, and die time.sleep(2) raise # External commands # ----------------------------------------------------- def push_external_command(self, e): """ A plugin sends us an external command. Notify this command to the monitoring framework ... """ logger.debug("[WebUI] Got an external command: %s", e.__dict__) if self.stand_alone: logger.warning( "[WebUI] --------------------------------------------------") logger.warning("[WebUI] TODO: notify external command: %s", e.__dict__) logger.warning( "[WebUI] --------------------------------------------------") else: try: self.from_q.put(e) except Exception, exp: logger.error("[WebUI] External command push, exception: %s", str(exp))
def test_modulemanager(self): mod = Module({'module_name': 'DummyExternal', 'module_type': 'dummy_broker_external'}) self.modulemanager = ModulesManager('broker', modules_dir, []) self.modulemanager.set_modules([mod]) self.modulemanager.load_and_init() # And start external ones, like our LiveStatus self.modulemanager.start_external_instances() print "I correctly loaded the modules: %s " % ([inst.get_name() for inst in self.modulemanager.instances]) print "*** First kill ****" # Now I will try to kill the livestatus module ls = self.modulemanager.instances[0] ls._BaseModule__kill() time.sleep(1) print "Check alive?" print "Is alive?", ls.process.is_alive() # Should be dead self.assertFalse(ls.process.is_alive()) self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() # In fact it's too early, so it won't do it # Here the inst should still be dead print "Is alive?", ls.process.is_alive() self.assertFalse(ls.process.is_alive()) # So we lie ls.last_init_try = -5 self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() # In fact it's too early, so it won't do it # Here the inst should be alive again print "Is alive?", ls.process.is_alive() self.assertTrue(ls.process.is_alive()) # should be nothing more in to_restart of # the module manager self.assertEqual([], self.modulemanager.to_restart) # Now we look for time restart so we kill it again ls._BaseModule__kill() time.sleep(1) self.assertFalse(ls.process.is_alive()) # Should be too early self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() print "Is alive or not", ls.process.is_alive() self.assertFalse(ls.process.is_alive()) # We lie for the test again ls.last_init_try = -5 self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() # Here the inst should be alive again print "Is alive?", ls.process.is_alive() self.assertTrue(ls.process.is_alive()) # And we clear all now print "Ask to die" self.modulemanager.stop_all() print "Died"
class Webui_broker(BaseModule, Daemon): def __init__(self, modconf): BaseModule.__init__(self, modconf) self.plugins = [] self.modconf = modconf # Web server configuration self.host = getattr(modconf, 'host', '0.0.0.0') self.port = int(getattr(modconf, 'port', '7767')) self.auth_secret = getattr(modconf, 'auth_secret', 'secret').encode('utf8', 'replace') # TODO : common preferences self.play_sound = to_bool(getattr(modconf, 'play_sound', '0')) # TODO : common preferences self.login_text = getattr(modconf, 'login_text', None) # TODO : common preferences self.company_logo = getattr(modconf, 'company_logo', 'default_company') if self.company_logo == '': # Set a dummy value if webui.cfg value is empty to force using the default logo ... self.company_logo = 'abcdef' # TODO : common preferences self.gravatar = to_bool(getattr(modconf, 'gravatar', '0')) # TODO : common preferences self.allow_html_output = to_bool( getattr(modconf, 'allow_html_output', '0')) # TODO : common preferences #self.max_output_length = int(getattr(modconf, 'max_output_length', '100')) # TODO : common preferences self.refresh_period = int(getattr(modconf, 'refresh_period', '60')) # Use element tag as image or use text self.tag_as_image = to_bool(getattr(modconf, 'tag_as_image', '0')) # Manage user's ACL self.manage_acl = to_bool(getattr(modconf, 'manage_acl', '1')) self.allow_anonymous = to_bool(getattr(modconf, 'allow_anonymous', '0')) # Advanced options self.http_backend = getattr(modconf, 'http_backend', 'auto') self.remote_user_enable = getattr(modconf, 'remote_user_enable', '0') self.remote_user_variable = getattr(modconf, 'remote_user_variable', 'X_REMOTE_USER') self.serveropts = {} umask = getattr(modconf, 'umask', None) if umask is not None: self.serveropts['umask'] = int(umask) bindAddress = getattr(modconf, 'bindAddress', None) if bindAddress: self.serveropts['bindAddress'] = str(bindAddress) # Apache htpasswd file for authentication self.htpasswd_file = getattr(modconf, 'htpasswd_file', '/etc/shinken/htpasswd.users') logger.info("[WebUI] htpasswd file: %s", self.htpasswd_file) if self.htpasswd_file: if not os.path.exists(self.htpasswd_file): logger.warning("[WebUI] htpasswd file '%s' does not exist.", self.htpasswd_file) self.htpasswd_file = None # Load the config dir and make it an absolute path self.config_dir = getattr(modconf, 'config_dir', 'share') self.config_dir = os.path.abspath(self.config_dir) logger.info("[WebUI] Config dir: %s", self.config_dir) # Load the share dir and make it an absolute path self.share_dir = getattr(modconf, 'share_dir', 'share') self.share_dir = os.path.abspath(self.share_dir) logger.info("[WebUI] Share dir: %s", self.share_dir) # Load the photo dir and make it an absolute path self.photo_dir = getattr(modconf, 'photos_dir', 'photos') self.photo_dir = os.path.abspath(self.photo_dir) logger.info("[WebUI] Photo dir: %s", self.photo_dir) self.user_picture = '' # @mohierf: still useful ? No value in webui.cfg, so always False ... # self.embeded_graph = to_bool(getattr(modconf, 'embeded_graph', '0')) # Look for an additional pages dir self.additional_plugins_dir = getattr(modconf, 'additional_plugins_dir', '') if self.additional_plugins_dir: self.additional_plugins_dir = os.path.abspath( self.additional_plugins_dir) logger.info("[WebUI] Additional plugins dir: %s", self.additional_plugins_dir) # Web UI timezone self.timezone = getattr(modconf, 'timezone', 'Europe/Paris') if self.timezone: logger.info("[WebUI] Setting our timezone to %s", self.timezone) os.environ['TZ'] = self.timezone time.tzset() logger.info("[WebUI] parameter timezone: %s", self.timezone) # Visual alerting thresholds # Used in the dashboard view to select background color for percentages self.hosts_states_warning = int( getattr(modconf, 'hosts_states_warning', '95')) self.hosts_states_critical = int( getattr(modconf, 'hosts_states_critical', '90')) self.services_states_warning = int( getattr(modconf, 'services_states_warning', '95')) self.services_states_critical = int( getattr(modconf, 'services_states_critical', '90')) # Web UI information self.app_version = getattr(modconf, 'about_version', WEBUI_VERSION) self.app_copyright = getattr(modconf, 'about_copyright', WEBUI_COPYRIGHT) self.app_release = getattr(modconf, 'about_release', WEBUI_RELEASENOTES) # We will save all widgets self.widgets = {} # We need our regenerator now (before main) so if we are in a scheduler, # rg will be able to skip some broks self.rg = Regenerator() # My bottle object ... self.bottle = bottle bottle.BaseTemplate.defaults['app'] = self # Called by Broker so we can do init stuff def init(self): logger.info("[WebUI] Initializing ...") self.rg.load_external_queue(self.from_q) # This is called only when we are in a scheduler # and just before we are started. So we can gain time, and # just load all scheduler objects without fear :) (we # will be in another process, so we will be able to hack objects # if need) def hook_pre_scheduler_mod_start(self, sched): print "pre_scheduler_mod_start::", sched.__dict__ self.rg.load_from_scheduler(sched) # In a scheduler we will have a filter of what we really want as a brok def want_brok(self, b): return self.rg.want_brok(b) def main(self): self.set_proctitle(self.name) # Daemon like init self.debug_output = [] self.modules_dir = modulesctx.get_modulesdir() self.modules_manager = ModulesManager('webui', self.find_modules_path(), []) self.modules_manager.set_modules(self.modules) # We can now output some previously silenced debug output self.do_load_modules() for inst in self.modules_manager.instances: f = getattr(inst, 'load', None) if f and callable(f): f(self) for s in self.debug_output: print s del self.debug_output # Check if the Bottle view dir really exist if not os.path.exists(bottle.TEMPLATE_PATH[0]): logger.error("[WebUI] The view path do not exist at %s" % bottle.TEMPLATE_PATH) sys.exit(2) # Check directories # We check if the photo directory exists. If not, try to create it for d in [self.photo_dir, self.share_dir, self.config_dir]: logger.debug("[WebUI] Checking dir: %s", d) if not os.path.exists(d): try: os.mkdir(d) logger.info("[WebUI] Created dir: %s", d) except Exception, exp: logger.error("[WebUI] Dir creation failed: %s", exp) # :TODO:maethor:150724: Complete with other function names self.auth_module = AuthMetaModule( AuthMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.prefs_module = PrefsMetaModule( PrefsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.logs_module = LogsMetaModule( LogsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.graphs_module = GraphsMetaModule( GraphsMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) self.helpdesk_module = HelpdeskMetaModule( HelpdeskMetaModule.find_modules( self.modules_manager.get_internal_instances()), self) # Data manager self.datamgr = WebUIDataManager(self.rg) self.helper = helper self.request = request self.response = response self.template_call = template # :TODO:maethor:150717: Doesn't work #username = self.request.get_cookie("user", secret=self.auth_secret) #if username: #self.user = User.from_contact(self.datamgr.get_contact(username), self.gravatar) #else: #self.user = None try: self.do_main() except Exception, exp: msg = Message(id=0, type='ICrash', data={ 'name': self.get_name(), 'exception': exp, 'trace': traceback.format_exc() }) self.from_q.put(msg) # wait 2 sec so we know that the broker got our message, and die time.sleep(2) raise
def test_modulemanager(self): mod = Module({ 'module_name': 'DummyExternal', 'module_type': 'dummy_broker_external' }) self.modulemanager = ModulesManager('broker', "var/lib/shinken/modules", []) self.modulemanager.set_modules([mod]) self.modulemanager.load_and_init() # And start external ones, like our LiveStatus self.modulemanager.start_external_instances() print "I correctly loaded the modules: %s " % ( [inst.get_name() for inst in self.modulemanager.instances]) print "*** First kill ****" # Now I will try to kill the livestatus module ls = self.modulemanager.instances[0] ls._BaseModule__kill() time.sleep(1) print "Check alive?" print "Is alive?", ls.process.is_alive() # Should be dead self.assertFalse(ls.process.is_alive()) self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() # In fact it's too early, so it won't do it # Here the inst should still be dead print "Is alive?", ls.process.is_alive() self.assertFalse(ls.process.is_alive()) # So we lie ls.last_init_try = -5 self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() # In fact it's too early, so it won't do it # Here the inst should be alive again print "Is alive?", ls.process.is_alive() self.assertTrue(ls.process.is_alive()) # should be nothing more in to_restart of # the module manager self.assertEqual([], self.modulemanager.to_restart) # Now we look for time restart so we kill it again ls._BaseModule__kill() time.sleep(1) self.assertFalse(ls.process.is_alive()) # Should be too early self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() print "Is alive or not", ls.process.is_alive() self.assertFalse(ls.process.is_alive()) # We lie for the test again ls.last_init_try = -5 self.modulemanager.check_alive_instances() self.modulemanager.try_to_restart_deads() # Here the inst should be alive again print "Is alive?", ls.process.is_alive() self.assertTrue(ls.process.is_alive()) # And we clear all now print "Ask to die" self.modulemanager.stop_all() print "Died"
class Daemon(object): properties = { 'workdir': PathProp(default='/usr/local/shinken/var'), 'host': StringProp(default='0.0.0.0'), 'user': StringProp(default='shinken'), 'group': StringProp(default='shinken'), 'use_ssl': BoolProp(default='0'), 'certs_dir': StringProp(default='etc/certs'), 'ca_cert': StringProp(default='etc/certs/ca.pem'), 'server_cert': StringProp(default='etc/certs/server.pem'), 'use_local_log': BoolProp(default='0'), 'hard_ssl_name_check': BoolProp(default='0'), 'idontcareaboutsecurity': BoolProp(default='0'), 'spare': BoolProp(default='0') } def __init__(self, name, config_file, is_daemon, do_replace, debug, debug_file): self.check_shm() self.name = name self.config_file = config_file self.is_daemon = is_daemon self.do_replace = do_replace self.debug = debug self.debug_file = debug_file self.interrupted = False # Track time now = time.time() self.program_start = now self.t_each_loop = now # used to track system time change self.sleep_time = 0.0 #used to track the time we wait self.pyro_daemon = None # Log init self.log = logger self.log.load_obj(self) self.new_conf = None # used by controller to push conf self.cur_conf = None # Flag to know if we need to dump memory or not self.need_dump_memory = False #Keep a trace of the local_log file desc if need self.local_log_fd = None self.modules_manager = ModulesManager(name, self.find_modules_path(), []) os.umask(UMASK) self.set_exit_handler() # At least, lose the local log file if need def do_stop(self): if self.modules_manager: # We save what we can but NOT for the scheduler # because the current sched object is a dummy one # and the old one aleady do it! if not hasattr(self, 'sched'): self.hook_point('save_retention') # And we quit logger.log('Stopping all modules') self.modules_manager.stop_all() if self.pyro_daemon: pyro.shutdown(self.pyro_daemon) #.shutdown(True) logger.quit() def request_stop(self): self.unlink() ## unlink first self.do_stop() print("Exiting") sys.exit(0) def do_loop_turn(self): raise NotImplementedError() # Main loop for nearly all daemon # the scheduler is not managed by it :'( def do_mainloop(self): while True: self.do_loop_turn() # If ask us to dump memory, do it if self.need_dump_memory: self.dump_memory() self.need_dump_memory = False # Maybe we ask us to die, if so, do it :) if self.interrupted: break self.request_stop() def do_load_modules(self): self.modules_manager.load_and_init() self.log.log("I correctly loaded the modules : [%s]" % (','.join( [inst.get_name() for inst in self.modules_manager.instances]))) def add(self, elt): """ Dummy method for adding broker to this daemon """ pass def dump_memory(self): logger.log("I dump my memory, it can ask some seconds to do") try: from guppy import hpy hp = hpy() logger.log(hp.heap()) except ImportError: logger.log( 'I do not have the module guppy for memory dump, please install it' ) def load_config_file(self): self.parse_config_file() if self.config_file is not None: # Some paths can be relatives. We must have a full path by taking # the config file by reference self.relative_paths_to_full(os.path.dirname(self.config_file)) # Then start to log all in the local file if asked so self.register_local_log() def change_to_workdir(self): try: os.chdir(self.workdir) except Exception, e: raise InvalidWorkDir(e) print("Successfully changed to workdir: %s" % (self.workdir))