class Serviceescalation(Item): id = 1 # zero is always special in database, so we do not take risk here my_type = 'serviceescalation' properties = Item.properties.copy() properties.update({ 'host_name': StringProp(), 'hostgroup_name': StringProp(), 'service_description': StringProp(), 'first_notification': IntegerProp(), 'last_notification': IntegerProp(), 'notification_interval': IntegerProp(default=30), # like Nagios value 'escalation_period': StringProp(default=''), 'escalation_options': ListProp(default=['d', 'u', 'r', 'w', 'c'], split_on_coma=True), 'contacts': StringProp(), 'contact_groups': StringProp(), 'first_notification_time': IntegerProp(), 'last_notification_time': IntegerProp(), }) # For debugging purpose only (nice name) def get_name(self): return ''
class PollerLink(SatelliteLink): """This class is the link between Arbiter and Poller. With it, arbiter can see if a poller is alive, and can send it new configuration """ id = 0 my_type = 'poller' # To_send: send or not to satellite conf properties = SatelliteLink.properties.copy() properties.update({ 'poller_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default=7771, fill_brok=['full_status']), 'passive': BoolProp(default='0', fill_brok=['full_status'], to_send=True), 'min_workers': IntegerProp(default='0', fill_brok=['full_status'], to_send=True), 'max_workers': IntegerProp(default='30', fill_brok=['full_status'], to_send=True), 'processes_by_worker': IntegerProp(default='256', fill_brok=['full_status'], to_send=True), 'poller_tags': ListProp(default='None', to_send=True), }) def get_name(self): return self.poller_name def register_to_my_realm(self): self.realm.pollers.append(self)
class ReactionnerLink(SatelliteLink): """Please Add a Docstring to describe the class here""" id = 0 my_type = 'reactionner' properties = SatelliteLink.properties.copy() properties.update({ 'reactionner_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default=7769, fill_brok=['full_status']), 'min_workers': IntegerProp(default=1, fill_brok=['full_status'], to_send=True), 'max_workers': IntegerProp(default=30, fill_brok=['full_status'], to_send=True), 'processes_by_worker': IntegerProp(default=256, fill_brok=['full_status'], to_send=True), 'reactionner_tags': ListProp(default=['None'], to_send=True), }) def get_name(self): return self.reactionner_name def register_to_my_realm(self): self.realm.reactionners.append(self)
class ReactionnerLink(SatelliteLink): id = 0 my_type = 'reactionner' properties = SatelliteLink.properties.copy() properties.update({ 'reactionner_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default='7769', fill_brok=['full_status']), 'passive': BoolProp(default='0', fill_brok=['full_status'], to_send=True), 'min_workers': IntegerProp(default='1', fill_brok=['full_status'], to_send=True), 'max_workers': IntegerProp(default='30', fill_brok=['full_status'], to_send=True), 'processes_by_worker': IntegerProp(default='256', fill_brok=['full_status'], to_send=True), 'reactionner_tags': ListProp(default='None', to_send=True), }) def get_name(self): return self.reactionner_name def register_to_my_realm(self): self.realm.reactionners.append(self)
class Contactgroup(Itemgroup): id = 1 my_type = 'contactgroup' properties = Itemgroup.properties.copy() properties.update({ 'id': IntegerProp(default=0, fill_brok=['full_status']), 'contactgroup_name': StringProp(fill_brok=['full_status']), 'alias': StringProp(fill_brok=['full_status']), }) macros = { 'CONTACTGROUPALIAS': 'alias', 'CONTACTGROUPMEMBERS': 'get_members' } def get_contacts(self): return getattr(self, 'members', '') def get_name(self): return getattr(self, 'contactgroup_name', 'UNNAMED-CONTACTGROUP') def get_contactgroup_members(self): if self.has('contactgroup_members'): return self.contactgroup_members.split(',') else: return [] # We fillfull properties with template ones if need # Because hostgroup we call may not have it's members # we call get_hosts_by_explosion on it def get_contacts_by_explosion(self, contactgroups): # First we tag the hg so it will not be explode # if a son of it already call it self.already_explode = True # Now the recursive part # rec_tag is set to False every CG we explode # so if True here, it must be a loop in HG # calls... not GOOD! if self.rec_tag: logger.error("[contactgroup::%s] got a loop in contactgroup definition", self.get_name()) if self.has('members'): return self.members else: return '' # Ok, not a loop, we tag it and continue self.rec_tag = True cg_mbrs = self.get_contactgroup_members() for cg_mbr in cg_mbrs: cg = contactgroups.find_by_name(cg_mbr.strip()) if cg is not None: value = cg.get_contacts_by_explosion(contactgroups) if value is not None: self.add_string_member(value) if self.has('members'): return self.members else: return ''
class SchedulerLink(SatelliteLink): """Please Add a Docstring to describe the class here""" id = 0 # Ok we lie a little here because we are a mere link in fact my_type = 'scheduler' properties = SatelliteLink.properties.copy() properties.update({ 'scheduler_name': StringProp(fill_brok=['full_status']), 'port': IntegerProp(default=7768, fill_brok=['full_status']), 'weight': IntegerProp(default=1, fill_brok=['full_status']), 'skip_initial_broks': BoolProp(default=False, fill_brok=['full_status']), 'accept_passive_unknown_check_results': BoolProp(default=False, fill_brok=['full_status']), 'harakiri_threshold': StringProp(default=None, fill_brok=['full_status'], to_send=True), }) running_properties = SatelliteLink.running_properties.copy() running_properties.update({ 'conf': StringProp(default=None), 'need_conf': StringProp(default=True), 'external_commands': StringProp(default=[]), 'push_flavor': IntegerProp(default=0), }) def get_name(self): return self.scheduler_name def run_external_commands(self, commands): if self.con is None: self.create_connection() if not self.alive: return None logger.debug("[SchedulerLink] Sending %d commands", len(commands)) try: self.con.post('run_external_commands', {'cmds': commands}) except HTTPExceptions, exp: self.con = None logger.debug(exp) return False
class Realm(Itemgroup): id = 1 # zero is always a little bit special... like in database my_type = 'realm' properties = Itemgroup.properties.copy() properties.update({ 'id': IntegerProp(default=0, fill_brok=['full_status']), 'realm_name': StringProp(fill_brok=['full_status']), 'realm_members': StringProp(default=''), # No status_broker_name because it put hosts, not host_name 'higher_realms': StringProp(default=''), 'default': BoolProp(default='0'), 'broker_complete_links': BoolProp(default='0'), #'alias': {'required': True, 'fill_brok': ['full_status']}, #'notes': {'required': False, 'default':'', 'fill_brok': ['full_status']}, #'notes_url': {'required': False, 'default':'', 'fill_brok': ['full_status']}, #'action_url': {'required': False, 'default':'', 'fill_brok': ['full_status']}, }) running_properties = Item.running_properties.copy() running_properties.update({ 'serialized_confs': StringProp(default={}), }) macros = { 'REALMNAME': 'realm_name', 'REALMMEMBERS': 'members', } def get_name(self): return self.realm_name def get_realms(self): return self.realm_members def add_string_member(self, member): self.realm_members += ',' + member def get_realm_members(self): if self.has('realm_members'): return [r.strip() for r in self.realm_members.split(',')] else: return [] # Use to make python properties # TODO: change itemgroup function pythonize? def pythonize(self): cls = self.__class__ for prop, tab in cls.properties.items(): try: old_val = getattr(self, prop) new_val = tab.pythonize(old_val) #print "Changing ", old_val, "by", new_val setattr(self, prop, new_val) except AttributeError, exp: pass # Will be catch at the is_correct moment
class SchedulerLink(SatelliteLink): """Please Add a Docstring to describe the class here""" id = 0 # Ok we lie a little here because we are a mere link in fact my_type = 'scheduler' properties = SatelliteLink.properties.copy() properties.update({ 'scheduler_name': StringProp(fill_brok=['full_status']), 'port': IntegerProp(default='7768', fill_brok=['full_status']), 'weight': IntegerProp(default='1', fill_brok=['full_status']), 'skip_initial_broks': BoolProp(default='0', fill_brok=['full_status']), }) running_properties = SatelliteLink.running_properties.copy() running_properties.update({ 'conf': StringProp(default=None), 'need_conf': StringProp(default=True), 'external_commands': StringProp(default=[]), 'push_flavor': IntegerProp(default=0), }) def get_name(self): return self.scheduler_name def run_external_commands(self, commands): if self.con is None: self.create_connection() if not self.alive: return None logger.debug("[SchedulerLink] Sending %d commands" % len(commands)) try: self.con.run_external_commands(commands) except Pyro.errors.URIError, exp: self.con = None return False except Pyro.errors.ProtocolError, exp: self.con = None return False
class ArbiterLink(SatelliteLink): id = 0 my_type = 'arbiter' properties = SatelliteLink.properties.copy() properties.update({ 'arbiter_name': StringProp(), 'host_name': StringProp(default=socket.gethostname()), 'port': IntegerProp(default=7770), }) def get_name(self): return self.arbiter_name def get_config(self): return self.con.get('get_config') # Check is required when prop are set: # contacts OR contactgroups is need def is_correct(self): state = True cls = self.__class__ for prop, entry in cls.properties.items(): if not hasattr(self, prop) and entry.required: # This should raise an error afterwards? # Log the issue logger.warning("%s arbiterlink is missing %s property", self.get_name(), prop) self.debug("%s arbiterlink is missing %s property" % (self.get_name(), prop)) state = False # Bad boy... return state # Look for ourself as an arbiter. If we search for a specific arbiter name, go forit # If not look be our fqdn name, or if not, our hostname def is_me(self, lookup_name): logger.info("And arbiter is launched with the hostname:%s from an arbiter point of view of addr:%s", self.host_name, socket.getfqdn()) if lookup_name: return lookup_name == self.get_name() else: return self.host_name == socket.getfqdn() or self.host_name == socket.gethostname() def give_satellite_cfg(self): return {'port': self.port, 'address': self.address, 'name': self.arbiter_name, 'use_ssl':self.use_ssl, 'hard_ssl_name_check':self.hard_ssl_name_check} def do_not_run(self): if self.con is None: self.create_connection() try: self.con.get('do_not_run') return True except HTTPExceptions, exp: self.con = None return False
class Contact(Item): id = 1 # zero is always special in database, so we do not take risk here my_type = 'contact' properties = Item.properties.copy() properties.update({ 'contact_name': StringProp(fill_brok=['full_status']), 'alias': StringProp(default='none', fill_brok=['full_status']), 'contactgroups': ListProp(default=[], fill_brok=['full_status']), 'host_notifications_enabled': BoolProp(default=True, fill_brok=['full_status']), 'service_notifications_enabled': BoolProp(default=True, fill_brok=['full_status']), 'host_notification_period': StringProp(fill_brok=['full_status']), 'service_notification_period': StringProp(fill_brok=['full_status']), 'host_notification_options': ListProp(default=[''], fill_brok=['full_status'], split_on_coma=True), 'service_notification_options': ListProp(default=[''], fill_brok=['full_status'], split_on_coma=True), # To be consistent with notificationway object attributes 'host_notification_commands': ListProp(fill_brok=['full_status']), 'service_notification_commands': ListProp(fill_brok=['full_status']), 'min_business_impact': IntegerProp(default=0, fill_brok=['full_status']), 'email': StringProp(default='none', fill_brok=['full_status']), 'pager': StringProp(default='none', fill_brok=['full_status']), 'address1': StringProp(default='none', fill_brok=['full_status']), 'address2': StringProp(default='none', fill_brok=['full_status']), 'address3': StringProp(default='none', fill_brok=['full_status']), 'address4': StringProp(default='none', fill_brok=['full_status']), 'address5': StringProp(default='none', fill_brok=['full_status']), 'address6': StringProp(default='none', fill_brok=['full_status']), 'can_submit_commands': BoolProp(default=False, fill_brok=['full_status']), 'is_admin': BoolProp(default=False, fill_brok=['full_status']), 'expert': BoolProp(default=False, fill_brok=['full_status']), 'retain_status_information': BoolProp(default=True, fill_brok=['full_status']), 'notificationways': ListProp(default=[], fill_brok=['full_status']), 'password': StringProp(default='NOPASSWORDSET', fill_brok=['full_status']), }) running_properties = Item.running_properties.copy() running_properties.update({ 'modified_attributes': IntegerProp(default=0L, fill_brok=['full_status'], retention=True), 'downtimes': StringProp(default=[], fill_brok=['full_status'], retention=True), })
class Hostescalation(Item): id = 1 # zero is always special in database, so we do not take risk here my_type = 'hostescalation' properties = Item.properties.copy() properties.update({ 'host_name': StringProp(), 'hostgroup_name': StringProp(), 'first_notification': IntegerProp(), 'last_notification': IntegerProp(), 'notification_interval': IntegerProp(default='30'), # like Nagios value 'escalation_period': StringProp(default=''), 'escalation_options': ListProp(default='d,u,r,w,c'), 'contacts': StringProp(), 'contact_groups': StringProp(), }) # For debugging purpose only (nice name) def get_name(self): return ''
class BrokerLink(SatelliteLink): """TODO: Add some comment about this class for the doc""" id = 0 my_type = 'broker' properties = SatelliteLink.properties.copy() properties.update({ 'broker_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default=7772, fill_brok=['full_status']), 'broks_batch': IntegerProp(default=0, fill_brok=['full_status'], to_send=True), 'harakiri_threshold': StringProp(default=None, fill_brok=['full_status'], to_send=True), }) def get_name(self): return self.broker_name def register_to_my_realm(self): self.realm.brokers.append(self)
class Businessimpactmodulation(Item): id = 1 # zero is always special in database, so we do not take risk here my_type = 'businessimpactmodulation' properties = Item.properties.copy() properties.update({'business_impact_modulation_name': StringProp(), 'business_impact': IntegerProp(), 'modulation_period': StringProp(default=''), }) # For debugging purpose only (nice name) def get_name(self): return self.business_impact_modulation_name
class SchedulerLink(SatelliteLink): id = 0 #Ok we lie a little here because we are a mere link in fact my_type = 'scheduler' properties = SatelliteLink.properties.copy() properties.update({ 'scheduler_name': StringProp(fill_brok=['full_status']), 'port': IntegerProp(default='7768', fill_brok=['full_status']), 'weight': IntegerProp(default='1', fill_brok=['full_status']), }) running_properties = SatelliteLink.running_properties.copy() running_properties.update({ 'conf': StringProp(default=None), 'need_conf': StringProp(default=True), }) def get_name(self): return self.scheduler_name def run_external_command(self, command): if self.con is None: self.create_connexion() if not self.alive: return None print "Send command", command try: self.con.run_external_command(command) except Pyro.errors.URIError , exp: self.con = None return False except Pyro.errors.ProtocolError , exp: self.con = None return False
class Poller(Satellite): do_checks = True # I do checks do_actions = False # but no actions properties = Satellite.properties.copy() properties.update({ 'pidfile': PathProp(default='pollerd.pid'), 'port': IntegerProp(default='7771'), 'local_log': PathProp(default='pollerd.log'), }) def __init__(self, config_file, is_daemon, do_replace, debug, debug_file): super(Poller, self).__init__('poller', config_file, is_daemon, do_replace, debug, debug_file)
class Hostescalation(Item): id = 1 #0 is always special in database, so we do not take risk here my_type = 'hostescalation' properties = { 'host_name': StringProp(), 'hostgroup_name': StringProp(), 'first_notification': IntegerProp(), 'last_notification': IntegerProp(), 'notification_interval': IntegerProp(), 'escalation_period': StringProp(default=''), 'escalation_options': ListProp(default='d,u,r,w,c'), 'contacts': StringProp(), 'contact_groups': StringProp(), } running_properties = {} macros = {} #For debugging purpose only (nice name) def get_name(self): return ''
class PollerLink(SatelliteLink): id = 0 my_type = 'poller' #To_send : send or not to satellite conf properties = SatelliteLink.properties.copy() properties.update({ 'poller_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default=7771, fill_brok=['full_status']), 'passive' : BoolProp(default='0', fill_brok=['full_status'], to_send=True), 'min_workers': IntegerProp(default='1', fill_brok=['full_status'], to_send=True), 'max_workers': IntegerProp(default='30', fill_brok=['full_status'], to_send=True), 'processes_by_worker': IntegerProp(default='256', fill_brok=['full_status'], to_send=True), 'poller_tags': ListProp(default='None', to_send=True), }) def get_name(self): return self.poller_name def register_to_my_realm(self): self.realm.pollers.append(self) if self.poller_tags != []: print "I %s manage tags : %s " % (self.get_name(), self.poller_tags)
class ArbiterLink(SatelliteLink): id = 0 my_type = 'arbiter' properties = SatelliteLink.properties.copy() properties.update({ 'arbiter_name': StringProp(), 'host_name': StringProp(default=socket.gethostname()), 'port': IntegerProp(default='7770'), }) def get_name(self): return self.arbiter_name #Check is required prop are set: #contacts OR contactgroups is need def is_correct(self): state = True #guilty or not? :) cls = self.__class__ for prop, entry in cls.properties.items(): if not hasattr(self, prop) and entry.required: print self.get_name(), " : I do not have", prop state = False #Bad boy... return state def is_me(self): print "Hostname:%s, gethostname:%s" % (self.host_name, socket.gethostname()) return self.host_name == socket.gethostname() def give_satellite_cfg(self): return { 'port': self.port, 'address': self.address, 'name': self.arbiter_name } def do_not_run(self): if self.con is None: self.create_connexion() try: self.con.do_not_run() return True except Pyro.errors.URIError, exp: self.con = None return False except Pyro.errors.ProtocolError, exp: self.con = None return False
class ReceiverLink(SatelliteLink): """Please Add a Docstring to describe the class here""" id = 0 my_type = 'receiver' properties = SatelliteLink.properties.copy() properties.update({ 'receiver_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default=7772, fill_brok=['full_status']), 'manage_sub_realms': BoolProp(default=True, fill_brok=['full_status']), 'manage_arbiters': BoolProp(default=False, fill_brok=['full_status'], to_send=True), 'direct_routing': BoolProp(default=False, fill_brok=['full_status'], to_send=True), 'accept_passive_unknown_check_results': BoolProp(default=False, fill_brok=['full_status'], to_send=True), 'harakiri_threshold': StringProp(default=None, fill_brok=['full_status'], to_send=True), }) def get_name(self): return self.receiver_name def register_to_my_realm(self): self.realm.receivers.append(self) def push_host_names(self, sched_id, hnames): try: if self.con is None: self.create_connection() logger.info(" (%s)", self.uri) # If the connection failed to initialize, bail out if self.con is None: self.add_failed_check_attempt() return # r = self.con.push_host_names(sched_id, hnames) self.con.get('ping') self.con.post('push_host_names', { 'sched_id': sched_id, 'hnames': hnames }, wait='long') except HTTPExceptions, exp: self.add_failed_check_attempt(reason=str(exp))
class Reactionner(Satellite): do_checks = False # I do not do checks do_actions = True my_type = 'reactionner' properties = Satellite.properties.copy() properties.update({ 'pidfile': PathProp(default='reactionnerd.pid'), 'port': IntegerProp(default=7769), 'local_log': PathProp(default='reactionnerd.log'), }) def __init__(self, config_file, is_daemon, do_replace, debug, debug_file, profile=''): super(Reactionner, self).__init__('reactionner', config_file, is_daemon, do_replace, debug, debug_file)
class BrokerLink(SatelliteLink): id = 0 my_type = 'broker' properties = SatelliteLink.properties.copy() properties.update({ 'broker_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default='7772', fill_brok=['full_status']), }) def get_name(self): return self.broker_name def register_to_my_realm(self): self.realm.brokers.append(self)
class ArbiterLink(SatelliteLink): id = 0 my_type = 'arbiter' properties = SatelliteLink.properties.copy() properties.update({ 'arbiter_name': StringProp(), 'host_name': StringProp(default=socket.gethostname()), 'port': IntegerProp(default=7770), }) def get_name(self): return self.arbiter_name def get_config(self): return self.con.get('get_config') # Look for ourself as an arbiter. If we search for a specific arbiter name, go forit # If not look be our fqdn name, or if not, our hostname def is_me(self, lookup_name): logger.info( "And arbiter is launched with the hostname:%s " "from an arbiter point of view of addr:%s", self.host_name, socket.getfqdn()) if lookup_name: return lookup_name == self.get_name() else: return self.host_name == socket.getfqdn( ) or self.host_name == socket.gethostname() def give_satellite_cfg(self): return { 'port': self.port, 'address': self.address, 'name': self.arbiter_name, 'use_ssl': self.use_ssl, 'hard_ssl_name_check': self.hard_ssl_name_check } def do_not_run(self): if self.con is None: self.create_connection() try: self.con.get('do_not_run') return True except HTTPExceptions, exp: self.con = None return False
class Reactionner(Satellite): do_checks = False # I do not do checks do_actions = True # just actions like notifications properties = Satellite.properties.copy() properties.update({ 'pidfile': PathProp(default='/usr/local/shinken/var/reactionnerd.pid'), 'port': IntegerProp(default='7769'), 'local_log': PathProp(default='/usr/local/shinken/var/reactionnerd.log'), }) def __init__(self, config_file, is_daemon, do_replace, debug, debug_file): super(Reactionner, self).__init__('reactionner', config_file, is_daemon, do_replace, debug, debug_file)
class Resultmodulation(Item): id = 1 # zero is always special in database, so we do not take risk here my_type = 'resultmodulation' properties = Item.properties.copy() properties.update({ 'resultmodulation_name': StringProp(), 'exit_codes_match': IntListProp(default=[]), 'exit_code_modulation': IntegerProp(default=None), 'modulation_period': StringProp(default=None), }) # For debugging purpose only (nice name) def get_name(self): return self.resultmodulation_name # Make the return code modulation if need def module_return(self, return_code): # Only if in modulation_period of modulation_period == None if self.modulation_period is None or self.modulation_period.is_time_valid(time.time()): # Try to change the exit code only if a new one is defined if self.exit_code_modulation is not None: # First with the exit_code_match if return_code in self.exit_codes_match: return_code = self.exit_code_modulation return return_code # We override the pythonize because we have special cases that we do not want # to be do at running def pythonize(self): # First apply Item pythonize super(Resultmodulation, self).pythonize() # Then very special cases # Intify the exit_codes_match, and make list self.exit_codes_match = [int(ec) for ec in getattr(self, 'exit_codes_match', [])] if hasattr(self, 'exit_code_modulation'): self.exit_code_modulation = int(self.exit_code_modulation) else: self.exit_code_modulation = None
class ReceiverLink(SatelliteLink): id = 0 my_type = 'receiver' properties = SatelliteLink.properties.copy() properties.update({ 'receiver_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default='7772', fill_brok=['full_status']), 'manage_sub_realms': BoolProp(default='1', fill_brok=['full_status']), 'manage_arbiters': BoolProp(default='0', fill_brok=['full_status'], to_send=True), }) def get_name(self): return self.receiver_name def register_to_my_realm(self): self.realm.receivers.append(self)
class PollerLink(SatelliteLink): """This class is the link between Arbiter and Poller. With it, arbiter can see if a poller is alive, and can send it new configuration """ id = 0 my_type = 'poller' # To_send: send or not to satellite conf properties = SatelliteLink.properties.copy() properties.update({ 'poller_name': StringProp(fill_brok=['full_status'], to_send=True), 'port': IntegerProp(default=7771, fill_brok=['full_status']), 'min_workers': IntegerProp(default=0, fill_brok=['full_status'], to_send=True), 'max_workers': IntegerProp(default=30, fill_brok=['full_status'], to_send=True), 'processes_by_worker': IntegerProp(default=256, fill_brok=['full_status'], to_send=True), 'max_q_size': IntegerProp(default=0, fill_brok=['full_status'], to_send=True), 'q_factor': IntegerProp(default=0, fill_brok=['full_status'], to_send=True), 'results_batch': IntegerProp(default=0, fill_brok=['full_status'], to_send=True), 'poller_tags': ListProp(default=['None'], to_send=True), 'harakiri_threshold': StringProp(default=None, fill_brok=['full_status'], to_send=True), }) def get_name(self): return getattr(self, 'poller_name', 'UNNAMED-POLLER') def register_to_my_realm(self): self.realm.pollers.append(self)
class EventHandler(Action): # AutoSlots create the __slots__ with properties and # running_properties names __metaclass__ = AutoSlots my_type = 'eventhandler' properties = { 'is_a': StringProp(default='eventhandler'), 'type': StringProp(default=''), '_in_timeout': StringProp(default=False), 'status': StringProp(default=''), 'exit_status': StringProp(default=3), 'output': StringProp(default=''), 'long_output': StringProp(default=''), 't_to_go': StringProp(default=0), 'check_time': StringProp(default=0), 'execution_time': FloatProp(default=0), 'u_time': FloatProp(default=0.0), 's_time': FloatProp(default=0.0), 'env': StringProp(default={}), 'perf_data': StringProp(default=''), 'sched_id': IntegerProp(default=0), 'timeout': IntegerProp(default=10), 'check_time': IntegerProp(default=0), 'command': StringProp(default=''), 'module_type': StringProp(default='fork'), 'worker': StringProp(default='none'), 'reactionner_tag': StringProp(default='None'), } # id = 0 #Is common to Actions def __init__(self, command, id=None, ref=None, timeout=10, env={}, \ module_type='fork', reactionner_tag='None'): self.is_a = 'eventhandler' self.type = '' self.status = 'scheduled' if id is None: # id != None is for copy call only self.id = Action.id Action.id += 1 self.ref = ref self._in_timeout = False self.timeout = timeout self.exit_status = 3 self.command = command self.output = '' self.long_output = '' self.t_to_go = time.time() self.check_time = 0 self.execution_time = 0 self.u_time = 0 self.s_time = 0 self.perf_data = '' self.env = {} self.module_type = module_type self.worker = 'none' self.reactionner_tag = reactionner_tag # return a copy of the check but just what is important for execution # So we remove the ref and all def copy_shell(self): # We create a dummy check with nothing in it, just defaults values return self.copy_shell__(EventHandler('', id=self.id)) def get_return_from(self, e): self.exit_status = e.exit_status self.output = e.output self.long_output = getattr(e, 'long_output', '') self.check_time = e.check_time self.execution_time = getattr(e, 'execution_time', 0.0) self.perf_data = getattr(e, 'perf_data', '') # <TMI!!> def get_outputs(self, out, max_plugins_output_length): elts = out.split('\n') # For perf data elts_line1 = elts[0].split('|') # First line before | is output self.output = elts_line1[0] # After | is perfdata if len(elts_line1) > 1: self.perf_data = elts_line1[1] # The others lines are long_output if len(elts) > 1: self.long_output = '\n'.join(elts[1:]) # </TMI!!> def is_launchable(self, t): return t >= self.t_to_go def __str__(self): return "Check %d status:%s command:%s" % (self.id, self.status, self.command) def get_id(self): return self.id # Call by pickle to dataify the comment # because we DO NOT WANT REF in this pickleisation! def __getstate__(self): cls = self.__class__ # id is not in *_properties res = {'id': self.id} for prop in cls.properties: if hasattr(self, prop): res[prop] = getattr(self, prop) return res # Inverted function of getstate def __setstate__(self, state): cls = self.__class__ self.id = state['id'] for prop in cls.properties: if prop in state: setattr(self, prop, state[prop]) if not hasattr(self, 'worker'): self.worker = 'none' if not getattr(self, 'module_type', None): self.module_type = 'fork' # s_time and u_time are added between 1.2 and 1.4 if not hasattr(self, 'u_time'): self.u_time = 0 self.s_time = 0
class Receiver(BaseSatellite): properties = BaseSatellite.properties.copy() properties.update({ 'pidfile': PathProp(default='/usr/local/shinken/var/receiverd.pid'), 'port': IntegerProp(default='7773'), 'local_log': PathProp(default='/usr/local/shinken/var/receiverd.log'), }) def __init__(self, config_file, is_daemon, do_replace, debug, debug_file): super(Receiver, self).__init__('receiver', config_file, is_daemon, do_replace, debug, debug_file) # Our arbiters self.arbiters = {} # Our pollers and reactionners self.pollers = {} self.reactionners = {} # Modules are load one time self.have_modules = False # Can have a queue of external_commands give by modules # will be taken by arbiter to process self.external_commands = [] # All broks to manage self.broks = [] # broks to manage # broks raised this turn and that need to be put in self.broks self.broks_internal_raised = [] # Schedulers have some queues. We can simplify call by adding # elements into the proper queue just by looking at their type # Brok -> self.broks # TODO : better tag ID? # External commands -> self.external_commands def add(self, elt): cls_type = elt.__class__.my_type if cls_type == 'brok': # For brok, we TAG brok with our instance_id elt.data['instance_id'] = 0 self.broks_internal_raised.append(elt) return elif cls_type == 'externalcommand': print "Adding in queue an external command", ExternalCommand.__dict__ self.external_commands.append(elt) # # Get teh good tabs for links by the kind. If unknown, return None # def get_links_from_type(self, type): # t = {'scheduler' : self.schedulers, 'arbiter' : self.arbiters, \ # 'poller' : self.pollers, 'reactionner' : self.reactionners} # if type in t : # return t[type] # return None # Call by arbiter to get our external commands def get_external_commands(self): res = self.external_commands self.external_commands = [] return res # Get a brok. Our role is to put it in the modules # THEY MUST DO NOT CHANGE data of b !!! # REF: doc/receiver-modules.png (4-5) def manage_brok(self, b): to_del = [] # Call all modules if they catch the call for mod in self.modules_manager.get_internal_instances(): try: mod.manage_brok(b) except Exception, exp: print exp.__dict__ logger.log( "[%s] Warning : The mod %s raise an exception: %s, I kill it" % (self.name, mod.get_name(), str(exp))) logger.log("[%s] Exception type : %s" % (self.name, type(exp))) logger.log("Back trace of this kill: %s" % (traceback.format_exc())) to_del.append(mod) # Now remove mod that raise an exception self.modules_manager.clear_instances(to_del)
class Downtime: id = 1 # Just to list the properties we will send as pickle # so to others daemons, so all but NOT REF properties = { 'activate_me': StringProp(default=[]), 'entry_time': IntegerProp(default=0, fill_brok=['full_status']), 'fixed': BoolProp(default=True, fill_brok=['full_status']), 'start_time': IntegerProp(default=0, fill_brok=['full_status']), 'duration': IntegerProp(default=0, fill_brok=['full_status']), 'trigger_id': IntegerProp(default=0), 'end_time': IntegerProp(default=0, fill_brok=['full_status']), 'real_end_time': IntegerProp(default=0), 'author': StringProp(default='', fill_brok=['full_status']), 'comment': StringProp(default=''), 'is_in_effect': BoolProp(default=False), 'has_been_triggered': BoolProp(default=False), 'can_be_deleted': BoolProp(default=False), # TODO: find a very good way to handle the downtime "ref". # ref must effectively not be in properties because it points # onto a real object. # 'ref': None } def __init__(self, ref, start_time, end_time, fixed, trigger_id, duration, author, comment): now = datetime.datetime.now() self.id = int(time.mktime(now.timetuple()) * 1e6 + now.microsecond) self.__class__.id = self.id + 1 self.ref = ref # pointer to srv or host we are apply self.activate_me = [] # The other downtimes i need to activate self.entry_time = int(time.time()) self.fixed = fixed self.start_time = start_time self.duration = duration self.trigger_id = trigger_id if self.trigger_id != 0: # triggered plus fixed makes no sense self.fixed = False self.end_time = end_time if fixed: self.duration = end_time - start_time # This is important for flexible downtimes. Here start_time and # end_time mean: in this time interval it is possible to trigger # the beginning of the downtime which lasts for duration. # Later, when a non-ok event happens, real_end_time will be # recalculated from now+duration # end_time will be displayed in the web interface, but real_end_time # is used internally self.real_end_time = end_time self.author = author self.comment = comment self.is_in_effect = False # fixed: start_time has been reached, # flexible: non-ok checkresult self.has_been_triggered = False # another downtime has triggered me self.can_be_deleted = False self.add_automatic_comment() def __str__(self): if self.is_in_effect is True: active = "active" else: active = "inactive" if self.fixed is True: type = "fixed" else: type = "flexible" return "%s %s Downtime id=%d %s - %s" % ( active, type, self.id, time.ctime(self.start_time), time.ctime(self.end_time)) def trigger_me(self, other_downtime): self.activate_me.append(other_downtime) def in_scheduled_downtime(self): return self.is_in_effect # The referenced host/service object enters now a (or another) scheduled # downtime. Write a log message only if it was not already in a downtime def enter(self): res = [] self.is_in_effect = True if self.fixed is False: now = time.time() self.real_end_time = now + self.duration if self.ref.scheduled_downtime_depth == 0: self.ref.raise_enter_downtime_log_entry() self.ref.create_notifications('DOWNTIMESTART') self.ref.scheduled_downtime_depth += 1 self.ref.in_scheduled_downtime = True for dt in self.activate_me: res.extend(dt.enter()) return res # The end of the downtime was reached. def exit(self): res = [] if self.is_in_effect is True: # This was a fixed or a flexible+triggered downtime self.is_in_effect = False self.ref.scheduled_downtime_depth -= 1 if self.ref.scheduled_downtime_depth <= 0: self.ref.raise_exit_downtime_log_entry() self.ref.create_notifications('DOWNTIMEEND') self.ref.in_scheduled_downtime = False else: # This was probably a flexible downtime which was not triggered # In this case it silently disappears pass self.del_automatic_comment() self.can_be_deleted = True # when a downtime ends and the service was critical # a notification is sent with the next critical check # So we should set a flag here which signals consume_result # to send a notification self.ref.in_scheduled_downtime_during_last_check = True return res # A scheduled downtime was prematurely canceled def cancel(self): res = [] self.is_in_effect = False self.ref.scheduled_downtime_depth -= 1 if self.ref.scheduled_downtime_depth == 0: self.ref.raise_cancel_downtime_log_entry() self.ref.in_scheduled_downtime = False self.del_automatic_comment() self.can_be_deleted = True self.ref.in_scheduled_downtime_during_last_check = True # Nagios does not notify on canceled downtimes, but we does self.ref.create_notifications('DOWNTIMECANCELLED') # Also cancel other downtimes triggered by me for dt in self.activate_me: res.extend(dt.cancel()) return res # Scheduling a downtime creates a comment automatically def add_automatic_comment(self): if self.fixed is True: text = ( "This %s has been scheduled for fixed downtime from %s to %s. " "Notifications for the %s will not be sent out during that time period." % ( self.ref.my_type, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.start_time)), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.end_time)), self.ref.my_type) ) else: hours, remainder = divmod(self.duration, 3600) minutes, seconds = divmod(remainder, 60) text = ("This %s has been scheduled for flexible downtime starting between %s and %s " "and lasting for a period of %d hours and %d minutes. " "Notifications for the %s will not be sent out during that time period." % ( self.ref.my_type, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.start_time)), time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.end_time)), hours, minutes, self.ref.my_type) ) if self.ref.my_type == 'host': comment_type = 1 else: comment_type = 2 c = Comment(self.ref, False, "(Nagios Process)", text, comment_type, 2, 0, False, 0) self.comment_id = c.id self.extra_comment = c self.ref.add_comment(c) def del_automatic_comment(self): # Extra comment can be None if we load it from a old version of Shinken # TODO: remove it in a future version when every one got upgrade if self.extra_comment is not None: self.extra_comment.can_be_deleted = True # self.ref.del_comment(self.comment_id) # Fill data with info of item by looking at brok_type # in props of properties or running_properties def fill_data_brok_from(self, data, brok_type): cls = self.__class__ # Now config properties for prop, entry in cls.properties.items(): if hasattr(prop, 'fill_brok'): if brok_type in entry['fill_brok']: data[prop] = getattr(self, prop) # Get a brok with initial status def get_initial_status_brok(self): data = {'id': self.id} self.fill_data_brok_from(data, 'full_status') b = Brok('downtime_raise', data) return b # Call by pickle for dataify the downtime # because we DO NOT WANT REF in this pickleisation! def __getstate__(self): cls = self.__class__ # id is not in *_properties res = {'id': self.id} for prop in cls.properties: if hasattr(self, prop): res[prop] = getattr(self, prop) return res # Inverted function of getstate def __setstate__(self, state): cls = self.__class__ self.id = state['id'] for prop in cls.properties: if prop in state: setattr(self, prop, state[prop]) if self.id >= cls.id: cls.id = self.id + 1
class CommandCall(DummyCommandCall): """This class is use when a service, contact or host define a command with args. """ # AutoSlots create the __slots__ with properties and # running_properties names __metaclass__ = AutoSlots #__slots__ = ('id', 'call', 'command', 'valid', 'args', 'poller_tag', # 'reactionner_tag', 'module_type', '__dict__') id = 0 my_type = 'CommandCall' properties = { 'call': StringProp(), 'command': StringProp(), 'poller_tag': StringProp(default='None'), 'reactionner_tag': StringProp(default='None'), 'module_type': StringProp(default='fork'), 'valid': BoolProp(default=False), 'args': StringProp(default=[]), 'timeout': IntegerProp(default='-1'), 'late_relink_done':BoolProp(default=False), } def __init__(self, commands, call, poller_tag='None', reactionner_tag='None'): self.id = self.__class__.id self.__class__.id += 1 self.call = call self.timeout = -1 # Now split by ! and get command and args self.get_command_and_args() self.command = commands.find_by_name(self.command.strip()) self.late_relink_done = False # To do not relink again and again the same commandcall if self.command is not None: self.valid = True else: self.valid = False if self.valid: # If the host/service do not give an override poller_tag, take # the one of the command self.poller_tag = poller_tag # from host/service self.reactionner_tag = reactionner_tag self.module_type = self.command.module_type self.timeout = int(self.command.timeout) if self.valid and poller_tag is 'None': # from command if not set self.poller_tag = self.command.poller_tag # Same for reactionner tag if self.valid and reactionner_tag is 'None': # from command if not set self.reactionner_tag = self.command.reactionner_tag def get_command_and_args(self): """We want to get the command and the args with ! splitting. but don't forget to protect against the \! to do not split them """ # First protect p_call = self.call.replace('\!', '___PROTECT_EXCLAMATION___') tab = p_call.split('!') self.command = tab[0] # Reverse the protection self.args = [s.replace('___PROTECT_EXCLAMATION___', '!') for s in tab[1:]] # If we didn't already lately relink us, do it def late_linkify_with_command(self, commands): if self.late_relink_done: return self.late_relink_done = True c = commands.find_by_name(self.command) self.command = c def is_valid(self): return self.valid def __str__(self): return str(self.__dict__) def get_name(self): return self.call def __getstate__(self): """Call by pickle to dataify the comment because we DO NOT WANT REF in this pickleisation! """ cls = self.__class__ # id is not in *_properties res = {'id': self.id} for prop in cls.properties: if hasattr(self, prop): res[prop] = getattr(self, prop) # The command is a bit special, we just put it's name # or a '' if need if self.command and not isinstance(self.command, basestring): res['command'] = self.command.get_name() # Maybe it's a repickle of a unpickle thing... (like with deepcopy). If so # only take the value elif self.command and isinstance(self.command, basestring): res['command'] = self.command else: res['command'] = '' return res def __setstate__(self, state): """Inverted function of getstate""" cls = self.__class__ # We move during 1.0 to a dict state # but retention file from 0.8 was tuple if isinstance(state, tuple): self.__setstate_pre_1_0__(state) return self.id = state['id'] for prop in cls.properties: if prop in state: setattr(self, prop, state[prop]) def __setstate_pre_1_0__(self, state): """In 1.0 we move to a dict save. Before, it was a tuple save, like ({'id': 11}, {'poller_tag': 'None', 'reactionner_tag': 'None', 'command_line': u'/usr/local/nagios/bin/rss-multiuser', 'module_type': 'fork', 'command_name': u'notify-by-rss'}) """ for d in state: for k, v in d.items(): setattr(self, k, v)