Exemplo n.º 1
0
class ReactionnerLink(SatelliteLink):
    """
    Class to manage the reactionner information
    """
    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 register_to_my_realm(
            self):  # pragma: no cover, seems not to be used anywhere
        """
        Add this reactionner to the realm

        :return: None
        """
        self.realm.reactionners.append(self)
Exemplo n.º 2
0
class Hostescalation(Item):
    """Hostescalation class is used to implement notification escalation for hosts

    TODO: Why this class does not inherit from alignak.objects.Escalation.
          Maybe we can merge it
    """
    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(),
        'first_notification_time':
            IntegerProp(),
        'last_notification_time':
            IntegerProp(),
    })
Exemplo n.º 3
0
class PollerLink(SatelliteLink):
    """
    Class to manage the link between Arbiter and Poller. With it, arbiter
    can see if a poller is alive, and can send it new configuration
    """
    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),
        'poller_tags':
        ListProp(default=['None'], to_send=True),
    })

    def register_to_my_realm(
            self):  # pragma: no cover, seems not to be used anywhere
        """
        Add this relation to the realm

        :return: None
        """
        self.realm.pollers.append(self)
Exemplo n.º 4
0
class Comment(AlignakObject):
    """Comment class implements comments for monitoring purpose.
    It contains data like author, type etc..
    """

    my_type = 'comment'
    properties = {
        'entry_time':   IntegerProp(),
        'author':       StringProp(default='(Alignak)'),
        'comment':      StringProp(default='Automatic Comment'),
        'comment_type': IntegerProp(),
        'entry_type':   IntegerProp(),
        'source':       IntegerProp(),
        'expires':      BoolProp(),
        'ref':  StringProp(default=''),
    }

    def __init__(self, params, parsing=True):
        """Adds a comment to a particular service.

        :param ref: reference object (host / service)
        :type ref: alignak.object.schedulingitem.SchedulingItem
        :param author: Author of this comment
        :type author: str
        :param comment: text comment itself
        :type comment: str
        :param comment_type: comment type ::

                            * 1 <=> HOST_COMMENT
                            * 2 <=> SERVICE_COMMENT

        :type comment_type: int
        :param entry_type: type of entry linked to this comment ::

                          * 1 <=> USER_COMMENT
                          * 2 <=>DOWNTIME_COMMENT
                          * 3 <=>FLAPPING_COMMENT
                          * 4 <=>ACKNOWLEDGEMENT_COMMENT

        :type entry_type: int
        :param source: source of this comment ::

                      * 0 <=> COMMENTSOURCE_INTERNAL
                      * 1 <=> COMMENTSOURCE_EXTERNAL

        :type source: int
        :param expires: comment expires or not
        :type expires: bool
        :return: None
        """
        super(Comment, self).__init__(params, parsing)
        if not hasattr(self, 'entry_time'):
            self.entry_time = int(time.time())
        self.fill_default()

    def __str__(self):
        return "Comment id=%s %s" % (self.uuid, self.comment)
Exemplo n.º 5
0
class SchedulerLink(SatelliteLink):
    """
    Class to manage the scheduler information
    """
    _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']),
    })

    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 run_external_commands(self, commands):
        """
        Run external commands

        :param commands:
        :type commands:
        :return: False, None
        :rtype: bool | None
        TODO: need recode this fonction because return types are too many
        """
        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
Exemplo n.º 6
0
class SchedulerLink(SatelliteLink):
    """
    Class to manage the scheduler information
    """

    # Ok we lie a little here because we are a mere link in fact
    my_type = 'scheduler'

    properties = SatelliteLink.properties.copy()
    properties.update({
        'type':
        StringProp(default=u'scheduler',
                   fill_brok=['full_status'],
                   to_send=True),
        'scheduler_name':
        StringProp(default='', fill_brok=['full_status']),
        'port':
        IntegerProp(default=7768, fill_brok=['full_status'], to_send=True),
        'weight':
        IntegerProp(default=1, fill_brok=['full_status']),
        'skip_initial_broks':
        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),
    })

    running_properties = SatelliteLink.running_properties.copy()
    running_properties.update({
        # 'conf':
        #     StringProp(default=None),
        # 'cfg':
        #     DictProp(default={}),
        'need_conf': StringProp(default=True),
        'external_commands': StringProp(default=[]),
    })

    def get_override_configuration(self):
        """
        Some parameters can give as 'overridden parameters' like use_timezone
        so they will be mixed (in the scheduler) with the standard conf sent by the arbiter

        :return: dictionary of properties
        :rtype: dict
        """
        res = {}
        properties = self.__class__.properties
        for prop, entry in list(properties.items()):
            if entry.override:
                res[prop] = getattr(self, prop)
        return res
Exemplo n.º 7
0
class Businessimpactmodulation(Item):
    """Businessimpactmodulation class is simply a modulation of the business impact value
    (of a Host/Service) during a modulation period.
    """
    my_type = 'businessimpactmodulation'

    properties = Item.properties.copy()
    properties.update({'business_impact_modulation_name': StringProp(),
                       'business_impact':                 IntegerProp(),
                       'modulation_period':               StringProp(default=''),
                       })

    def __init__(self, params=None, parsing=True):
        super(Businessimpactmodulation, self).__init__(params, parsing=parsing)

        # Ok just put None as modulation_period, means 24x7
        if not hasattr(self, 'modulation_period'):
            self.modulation_period = '24x7'

    def get_name(self):
        """Accessor to business_impact_modulation_name attribute

        :return: business impact modulation name
        :rtype: str
        """
        if hasattr(self, 'business_impact_modulation_name'):
            return self.business_impact_modulation_name
        return 'Unnamed'
Exemplo n.º 8
0
class BrokerLink(SatelliteLink):
    """
    Class to manage the broker information
    """
    my_type = 'broker'
    properties = SatelliteLink.properties.copy()
    properties.update({
        'type':
        StringProp(default=u'broker', fill_brok=['full_status'], to_send=True),
        'broker_name':
        StringProp(default='', fill_brok=['full_status']),
        'port':
        IntegerProp(default=7772, fill_brok=['full_status'], to_send=True),
        'initialized':
        BoolProp(default=False, fill_brok=['full_status'], to_send=True),
    })

    def prepare_for_conf(self):
        """Initialize the pushed configuration dictionary
        with the inner properties that are to be propagated to the satellite link.

        :return: None
        """
        super(BrokerLink, self).prepare_for_conf()

        self.cfg.update({
            'satellites': {
                'receivers': {},
                'pollers': {},
                'reactionners': {}
            }
        })
Exemplo n.º 9
0
class PollerLink(SatelliteLink):
    """
    Class to manage the link between Arbiter and Poller. With this, an arbiter
    can communicate with a poller
    """
    my_type = 'poller'
    # To_send: send or not to satellite conf
    properties = SatelliteLink.properties.copy()
    properties.update({
        'type':
        StringProp(default=u'poller', fill_brok=['full_status'], to_send=True),
        'poller_name':
        StringProp(default='', fill_brok=['full_status']),
        'port':
        IntegerProp(default=7771, 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),
        # 'worker_polling_interval':
        #     IntegerProp(default=1, to_send=True),
        'poller_tags':
        ListProp(default=['None'], to_send=True),
    })
Exemplo n.º 10
0
class ArbiterLink(SatelliteLink):
    """
    Class to manage the link to Arbiter daemon.
    With it, a master arbiter can communicate with  a spare Arbiter daemon
    """
    my_type = 'arbiter'
    properties = SatelliteLink.properties.copy()
    properties.update({
        'type':
        StringProp(default=u'arbiter', fill_brok=['full_status'],
                   to_send=True),
        'arbiter_name':
        StringProp(default='', fill_brok=['full_status']),
        'host_name':
        StringProp(default=socket.gethostname(), to_send=True),
        'port':
        IntegerProp(default=7770, to_send=True),
        'last_master_speak':
        FloatProp(default=0.0)
    })

    def is_me(self):  # pragma: no cover, seems not to be used anywhere
        """Check if parameter name if same than name of this object

        TODO: is it useful?

        :return: true if parameter name if same than this name
        :rtype: bool
        """
        logger.info(
            "And arbiter is launched with the hostname:%s "
            "from an arbiter point of view of addr:%s", self.host_name,
            socket.getfqdn())
        return self.host_name == socket.getfqdn(
        ) or self.host_name == socket.gethostname()

    def do_not_run(self):
        """Check if satellite running or not
        If not, try to run

        :return: true if satellite not running
        :rtype: bool
        """
        logger.debug("[%s] do_not_run", self.name)

        try:
            self.con.get('_do_not_run')
            return True
        except HTTPClientConnectionException as exp:  # pragma: no cover, simple protection
            self.add_failed_check_attempt("Connection error when "
                                          "sending do not run: %s" % str(exp))
            self.set_dead()
        except HTTPClientTimeoutException as exp:  # pragma: no cover, simple protection
            self.add_failed_check_attempt("Connection timeout when "
                                          "sending do not run: %s" % str(exp))
        except HTTPClientException as exp:
            self.add_failed_check_attempt("Error when "
                                          "sending do not run: %s" % str(exp))

        return False
Exemplo n.º 11
0
class Reactionner(Satellite):
    """
    This class is an application that launches actions for the schedulers
    Actions can be:
       Notifications
       Event handlers

    When running the Reactionner will :
      Respond to pings from Arbiter
      Listen for new configurations from Arbiter

    The configuration consists of a list of Schedulers for which
    the Reactionner will launch actions for.
    """
    do_checks = False  # I do not do checks
    do_actions = True
    my_type = 'reactionner'

    properties = Satellite.properties.copy()
    properties.update({
        'type':
            StringProp(default='reactionner'),
        'port':
            IntegerProp(default=7769)
    })

    def __init__(self, **kwargs):
        """Reactionner daemon initialisation

        :param kwargs: command line arguments
        """
        super(Reactionner, self).__init__(kwargs.get('daemon_name',
                                                     'Default-reactionner'), **kwargs)
Exemplo n.º 12
0
class Poller(Satellite):
    """Poller class. Referenced as "app" in most Interface

    """
    do_checks = True  # I do checks
    do_actions = False  # but no actions
    my_type = 'poller'

    properties = Satellite.properties.copy()
    properties.update({
        'daemon_type': StringProp(default='poller'),
        '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,
                 port=None,
                 local_log=None,
                 daemon_name=None):
        self.daemon_name = 'poller'
        if daemon_name:
            self.daemon_name = daemon_name

        super(Poller,
              self).__init__(self.daemon_name, config_file, is_daemon,
                             do_replace, debug, debug_file, port, local_log)
Exemplo n.º 13
0
class Reactionner(Satellite):
    """
    This class is an application that launches actions for the schedulers
    Actions can be:
       Notifications
       Event handlers

    When running the Reactionner will :
      Respond to pings from Arbiter
      Listen for new configurations from Arbiter

    The configuration consists of a list of Schedulers for which
    the Reactionner will launch actions for.
    """
    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)
Exemplo n.º 14
0
class ReceiverLink(SatelliteLink):
    """
    Class to manage the receiver information
    """
    _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),
    })

    def register_to_my_realm(self):
        """
        Add this reactionner to the realm

        :return: None
        """
        self.realm.receivers.append(self)

    def push_host_names(self, sched_id, hnames):
        """
        Send host names to receiver

        :param sched_id: id of the scheduler
        :type sched_id: int
        :param hnames: list of host names
        :type hnames: list
        :return: None
        """
        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))
Exemplo n.º 15
0
class Serviceescalation(Item):
    """Serviceescalation class is used to implement notification escalation for services

    TODO: Why this class does not inherit from alignak.objects.Escalation.
          Maybe we can merge it
    """
    _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(),
    })

    def get_name(self):
        """Get escalation name

        :return: name
        :rtype: str
        TODO: Remove this function
        """
        return ''
Exemplo n.º 16
0
class Contact(Item):
    """Host class implements monitoring concepts for contact.
    For example it defines host_notification_period, service_notification_period etc.
    """
    _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),
    })
Exemplo n.º 17
0
class Serviceescalation(Item):
    """Serviceescalation class is used to implement notification escalation for services

    TODO: Why this class does not inherit from alignak.objects.Escalation.
          Maybe we can merge it
    """
    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=['w', 'x', 'c', 'r'], split_on_comma=True),
        'contacts':
        ListProp(default=[], merging='join', split_on_comma=True),
        'contact_groups':
        ListProp(default=[], merging='join', split_on_comma=True),
        'first_notification_time':
        IntegerProp(),
        'last_notification_time':
        IntegerProp(),
    })

    def __init__(self, params=None, parsing=True):
        if params is None:
            params = {}

        for prop in ['escalation_options']:
            if prop in params:
                params[prop] = [p.replace('u', 'x') for p in params[prop]]
        super(Serviceescalation, self).__init__(params, parsing=parsing)
Exemplo n.º 18
0
class ReceiverLink(SatelliteLink):
    """
    Class to manage the receiver information
    """
    my_type = 'receiver'
    properties = SatelliteLink.properties.copy()
    properties.update({
        'type':
        StringProp(default='receiver', fill_brok=['full_status'],
                   to_send=True),
        'receiver_name':
        StringProp(default='', fill_brok=['full_status'], to_send=True),
        'port':
        IntegerProp(default=7772, fill_brok=['full_status'], to_send=True),
    })
Exemplo n.º 19
0
class Resultmodulation(Item):
    """Resultmodulation class is simply a modulation of a check result exit code
    during a modulation_period.

    """
    _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),
    })

    def get_name(self):
        """Accessor to resultmodulation_name attribute

        :return: result modulation name
        :rtype: str
        """
        return self.resultmodulation_name

    def module_return(self, return_code):
        """Module the exit code if necessary ::

        * modulation_period is legit
        * exit_code_modulation
        * return_code in exit_codes_match

        :param return_code: actual code returned by the check
        :type return_code: int
        :return: return_code modulated if necessary (exit_code_modulation)
        :rtype: int
        """
        # 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
Exemplo n.º 20
0
class BrokerLink(SatelliteLink):
    """
    Class to manage the broker information
    """
    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 register_to_my_realm(
            self):  # pragma: no cover, seems not to be used anywhere
        """
        Add this broker to the realm

        :return: None
        """
        self.realm.brokers.append(self)
Exemplo n.º 21
0
class Businessimpactmodulation(Item):
    """Businessimpactmodulation class is simply a modulation of the business impact value
    (of a Host/Service) during a modulation period.
    """
    _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=''),
    })

    def get_name(self):
        """Accessor to business_impact_modulation_name attribute

        :return: business impact modulation name
        :rtype: str
        """
        return self.business_impact_modulation_name
Exemplo n.º 22
0
class ReceiverLink(SatelliteLink):
    """
    Class to manage the receiver information
    """
    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),
        'accept_passive_unknown_check_results': BoolProp(default=False,
                                                         fill_brok=['full_status'], to_send=True),
    })

    def register_to_my_realm(self):  # pragma: no cover, seems not to be used anywhere
        """
        Add this reactionner to the realm

        :return: None
        """
        self.realm.receivers.append(self)
Exemplo n.º 23
0
class Poller(Satellite):
    """Poller class. Referenced as "app" in most Interface

    """
    do_checks = True  # I do checks
    do_actions = False  # but no actions
    my_type = 'poller'

    properties = Satellite.properties.copy()
    properties.update({
        'type': StringProp(default='poller'),
        'port': IntegerProp(default=7771)
    })

    def __init__(self, **kwargs):
        """Poller daemon initialisation

        :param kwargs: command line arguments
        """
        super(Poller,
              self).__init__(kwargs.get('daemon_name', 'Default-poller'),
                             **kwargs)
Exemplo n.º 24
0
class Alignak(BaseSatellite):
    # pylint: disable=too-many-instance-attributes
    """Scheduler class. Referenced as "app" in most Interface

    """

    properties = BaseSatellite.properties.copy()
    properties.update({
        'type': StringProp(default='scheduler'),
        'port': IntegerProp(default=7768)
    })

    def __init__(self, **kwargs):
        """Scheduler daemon initialisation

        :param kwargs: command line arguments
        """
        super(Alignak,
              self).__init__(kwargs.get('daemon_name', 'Default-scheduler'),
                             **kwargs)

        self.http_interface = SchedulerInterface(self)
        self.sched = Scheduler(self)

        # stats part
        # --- copied from scheduler.py
        self.nb_pulled_checks = 0
        self.nb_pulled_actions = 0
        # self.nb_checks_send = 0

        self.nb_pushed_checks = 0
        self.nb_pushed_actions = 0

        self.nb_pulled_broks = 0
        # ---

        # And possible links for satellites
        self.brokers = {}
        self.pollers = {}
        self.reactionners = {}
        self.receivers = {}

        # This because it is the Satellite that has thes properties and I am a Satellite
        # todo: change this?
        # Broks are stored in each broker link, not locally
        # self.broks = []
        self.broks_lock = threading.RLock()

        # Modules are only loaded one time
        self.have_modules = False

        self.first_scheduling = False

    def get_broks(self, broker_name):
        """Send broks to a specific broker

        :param broker_name: broker name to send broks
        :type broker_name: str
        :greturn: dict of brok for this broker
        :rtype: dict[alignak.brok.Brok]
        """
        logger.debug("Broker %s requests my broks list", broker_name)
        res = []
        if not broker_name:
            return res

        for broker_link in list(self.brokers.values()):
            if broker_name == broker_link.name:
                for brok in sorted(broker_link.broks,
                                   key=lambda x: x.creation_time):
                    # Only provide broks that did not yet sent to our external modules
                    if getattr(brok, 'sent_to_externals', False):
                        res.append(brok)
                        brok.got = True
                broker_link.broks = [
                    b for b in broker_link.broks
                    if not getattr(b, 'got', False)
                ]
                logger.debug("Providing %d broks to %s", len(res), broker_name)
                break
        else:
            logger.warning("Got a brok request from an unknown broker: %s",
                           broker_name)

        return res

    def compensate_system_time_change(self, difference):  # pragma: no cover,
        # pylint: disable=too-many-branches
        # not with unit tests
        """Compensate a system time change of difference for all hosts/services/checks/notifs

        :param difference: difference in seconds
        :type difference: int
        :return: None
        """
        super(Alignak, self).compensate_system_time_change(difference)

        # We only need to change some value
        self.program_start = max(0, self.program_start + difference)

        if not hasattr(self.sched, "conf"):
            # Race condition where time change before getting conf
            return

        # Then we compensate all host/services
        for host in self.sched.hosts:
            host.compensate_system_time_change(difference)
        for serv in self.sched.services:
            serv.compensate_system_time_change(difference)

        # Now all checks and actions
        for chk in list(self.sched.checks.values()):
            # Already launch checks should not be touch
            if chk.status == u'scheduled' and chk.t_to_go is not None:
                t_to_go = chk.t_to_go
                ref = self.sched.find_item_by_id(chk.ref)
                new_t = max(0, t_to_go + difference)
                timeperiod = self.sched.timeperiods[ref.check_period]
                if timeperiod is not None:
                    # But it's no so simple, we must match the timeperiod
                    new_t = timeperiod.get_next_valid_time_from_t(new_t)
                # But maybe no there is no more new value! Not good :(
                # Say as error, with error output
                if new_t is None:
                    chk.state = u'waitconsume'
                    chk.exit_status = 2
                    chk.output = '(Error: there is no available check time after time change!)'
                    chk.check_time = time.time()
                    chk.execution_time = 0
                else:
                    chk.t_to_go = new_t
                    ref.next_chk = new_t

        # Now all checks and actions
        for act in list(self.sched.actions.values()):
            # Already launch checks should not be touch
            if act.status == u'scheduled':
                t_to_go = act.t_to_go

                #  Event handler do not have ref
                ref_id = getattr(act, 'ref', None)
                new_t = max(0, t_to_go + difference)

                # Notification should be check with notification_period
                if act.is_a == u'notification':
                    ref = self.sched.find_item_by_id(ref_id)
                    if ref.notification_period:
                        # But it's no so simple, we must match the timeperiod
                        notification_period = self.sched.timeperiods[
                            ref.notification_period]
                        new_t = notification_period.get_next_valid_time_from_t(
                            new_t)
                    # And got a creation_time variable too
                    act.creation_time += difference

                # But maybe no there is no more new value! Not good :(
                # Say as error, with error output
                if new_t is None:
                    act.state = 'waitconsume'
                    act.exit_status = 2
                    act.output = '(Error: there is no available check time after time change!)'
                    act.check_time = time.time()
                    act.execution_time = 0
                else:
                    act.t_to_go = new_t

    def do_before_loop(self):
        """Stop the scheduling process"""
        if self.sched:
            self.sched.stop_scheduling()

    def do_loop_turn(self):
        """Scheduler loop turn

        Simply run the Alignak scheduler loop

        This is called when a configuration got received by the scheduler daemon. As of it,
        check if the first scheduling has been done... and manage this.

        :return: None
        """
        if not self.first_scheduling:
            # Ok, now all is initialized, we can make the initial broks
            logger.info("First scheduling launched")
            _t0 = time.time()
            # Program start brok
            self.sched.initial_program_status()
            # First scheduling
            self.sched.schedule()
            statsmgr.timer('first_scheduling', time.time() - _t0)
            logger.info("First scheduling done")

            # Connect to our passive satellites if needed
            for satellite in [
                    s for s in list(self.pollers.values()) if s.passive
            ]:
                if not self.daemon_connection_init(satellite):
                    logger.error("Passive satellite connection failed: %s",
                                 satellite)

            for satellite in [
                    s for s in list(self.reactionners.values()) if s.passive
            ]:
                if not self.daemon_connection_init(satellite):
                    logger.error("Passive satellite connection failed: %s",
                                 satellite)

            # Ticks are for recurrent function call like consume, del zombies etc
            self.sched.ticks = 0
            self.first_scheduling = True

        # Each loop turn, execute the daemon specific treatment...
        # only if the daemon has a configuration to manage
        if self.sched.pushed_conf:
            # If scheduling is not yet enabled, enable scheduling
            if not self.sched.must_schedule:
                self.sched.start_scheduling()
                self.sched.before_run()
            self.sched.run()
        else:
            logger.warning("#%d - No monitoring configuration to scheduler...",
                           self.loop_count)

    def get_managed_configurations(self):
        """Get the configurations managed by this scheduler

        The configuration managed by a scheduler is the self configuration got
        by the scheduler during the dispatching.

        :return: a dict of scheduler links with instance_id as key and
        hash, push_flavor and configuration identifier as values
        :rtype: dict
        """
        # for scheduler_link in list(self.schedulers.values()):
        #     res[scheduler_link.instance_id] = {
        #         'hash': scheduler_link.hash,
        #         'push_flavor': scheduler_link.push_flavor,
        #         'managed_conf_id': scheduler_link.managed_conf_id
        #     }

        res = {}
        if self.sched.pushed_conf and self.cur_conf and 'instance_id' in self.cur_conf:
            res[self.cur_conf['instance_id']] = {
                'hash': self.cur_conf['hash'],
                'push_flavor': self.cur_conf['push_flavor'],
                'managed_conf_id': self.cur_conf['managed_conf_id']
            }
        logger.debug("Get managed configuration: %s", res)
        return res

    def setup_new_conf(self):
        # pylint: disable=too-many-statements, too-many-branches, too-many-locals
        """Setup new conf received for scheduler

        :return: None
        """
        # Execute the base class treatment...
        super(Alignak, self).setup_new_conf()

        # ...then our own specific treatment!
        with self.conf_lock:
            # self_conf is our own configuration from the alignak environment
            # self_conf = self.cur_conf['self_conf']
            logger.debug("Got config: %s", self.cur_conf)
            if 'conf_part' not in self.cur_conf:
                self.cur_conf['conf_part'] = None
            conf_part = self.cur_conf['conf_part']

            # Ok now we can save the retention data
            if self.sched.pushed_conf is not None:
                self.sched.update_retention()

            # Get the monitored objects configuration
            t00 = time.time()
            received_conf_part = None
            try:
                received_conf_part = unserialize(conf_part)
                assert received_conf_part is not None
            except AssertionError as exp:
                # This to indicate that no configuration is managed by this scheduler...
                logger.warning(
                    "No managed configuration received from arbiter")
            except AlignakClassLookupException as exp:  # pragma: no cover
                # This to indicate that the new configuration is not managed...
                self.new_conf = {
                    "_status":
                    "Cannot un-serialize configuration received from arbiter",
                    "_error": str(exp)
                }
                logger.error(self.new_conf)
                logger.error("Back trace of the error:\n%s",
                             traceback.format_exc())
                return
            except Exception as exp:  # pylint: disable=broad-except
                # This to indicate that the new configuration is not managed...
                self.new_conf = {
                    "_status":
                    "Cannot un-serialize configuration received from arbiter",
                    "_error": str(exp)
                }
                logger.error(self.new_conf)
                self.exit_on_exception(exp, str(self.new_conf))

            # if not received_conf_part:
            #     return

            logger.info(
                "Monitored configuration %s received at %d. Un-serialized in %d secs",
                received_conf_part, t00,
                time.time() - t00)
            logger.info("Scheduler received configuration : %s",
                        received_conf_part)

            # Now we create our pollers, reactionners and brokers
            for link_type in ['pollers', 'reactionners', 'brokers']:
                if link_type not in self.cur_conf['satellites']:
                    logger.error("Missing %s in the configuration!", link_type)
                    continue

                my_satellites = getattr(self, link_type, {})
                received_satellites = self.cur_conf['satellites'][link_type]
                for link_uuid in received_satellites:
                    rs_conf = received_satellites[link_uuid]
                    logger.debug("- received %s - %s: %s",
                                 rs_conf['instance_id'], rs_conf['type'],
                                 rs_conf['name'])

                    # Must look if we already had a configuration and save our broks
                    already_got = rs_conf['instance_id'] in my_satellites
                    broks = []
                    actions = {}
                    wait_homerun = {}
                    external_commands = {}
                    running_id = 0
                    if already_got:
                        logger.warning("I already got: %s",
                                       rs_conf['instance_id'])
                        # Save some information
                        running_id = my_satellites[link_uuid].running_id
                        (broks, actions,
                         wait_homerun, external_commands) = \
                            my_satellites[link_uuid].get_and_clear_context()
                        # Delete the former link
                        del my_satellites[link_uuid]

                    # My new satellite link...
                    new_link = SatelliteLink.get_a_satellite_link(
                        link_type[:-1], rs_conf)
                    my_satellites[new_link.uuid] = new_link
                    logger.info("I got a new %s satellite: %s", link_type[:-1],
                                new_link)

                    new_link.running_id = running_id
                    new_link.external_commands = external_commands
                    new_link.broks = broks
                    new_link.wait_homerun = wait_homerun
                    new_link.actions = actions

                    # Replacing the satellite address and port by those defined in satellite_map
                    if new_link.name in self.cur_conf['override_conf'].get(
                            'satellite_map', {}):
                        override_conf = self.cur_conf['override_conf']
                        overriding = override_conf.get('satellite_map')[
                            new_link.name]
                        logger.warning(
                            "Do not override the configuration for: %s, with: %s. "
                            "Please check whether this is necessary!",
                            new_link.name, overriding)

            # First mix conf and override_conf to have our definitive conf
            for prop in getattr(self.cur_conf, 'override_conf', []):
                logger.debug("Overriden: %s / %s ", prop,
                             getattr(received_conf_part, prop, None))
                logger.debug("Overriding: %s / %s ", prop,
                             self.cur_conf['override_conf'])
                setattr(received_conf_part, prop,
                        self.cur_conf['override_conf'].get(prop, None))

            # Scheduler modules
            if not self.have_modules:
                try:
                    logger.debug("Modules configuration: %s",
                                 self.cur_conf['modules'])
                    self.modules = unserialize(self.cur_conf['modules'],
                                               no_load=True)
                except AlignakClassLookupException as exp:  # pragma: no cover, simple protection
                    logger.error(
                        'Cannot un-serialize modules configuration '
                        'received from arbiter: %s', exp)
                if self.modules:
                    logger.debug("I received some modules configuration: %s",
                                 self.modules)
                    self.have_modules = True

                    self.do_load_modules(self.modules)
                    # and start external modules too
                    self.modules_manager.start_external_instances()
                else:
                    logger.info("I do not have modules")

            if received_conf_part:
                logger.info("Loading configuration...")

                # Propagate the global parameters to the configuration items
                received_conf_part.explode_global_conf()

                # We give the configuration to our scheduler
                self.sched.reset()
                self.sched.load_conf(self.cur_conf['instance_id'],
                                     self.cur_conf['instance_name'],
                                     received_conf_part)

                # Once loaded, the scheduler has an inner pushed_conf object
                logger.info("Loaded: %s", self.sched.pushed_conf)

                # Update the scheduler ticks according to the daemon configuration
                self.sched.update_recurrent_works_tick(self)

                # We must update our pushed configuration macros with correct values
                # from the configuration parameters
                # self.sched.pushed_conf.fill_resource_macros_names_macros()

                # Creating the Macroresolver Class & unique instance
                m_solver = MacroResolver()
                m_solver.init(received_conf_part)

                # Now create the external commands manager
                # We are an applyer: our role is not to dispatch commands, but to apply them
                ecm = ExternalCommandManager(
                    received_conf_part, 'applyer', self.sched,
                    received_conf_part.accept_passive_unknown_check_results,
                    received_conf_part.log_external_commands)

                # Scheduler needs to know about this external command manager to use it if necessary
                self.sched.external_commands_manager = ecm

                # Ok now we can load the retention data
                self.sched.retention_load()

                # Log hosts/services initial states
                self.sched.log_initial_states()

            # Create brok new conf
            brok = Brok({'type': 'new_conf', 'data': {}})
            self.sched.add_brok(brok)

            # Initialize connection with all our satellites
            logger.info("Initializing connection with my satellites:")
            my_satellites = self.get_links_of_type(s_type='')
            for satellite in list(my_satellites.values()):
                logger.info("- : %s/%s", satellite.type, satellite.name)
                if not self.daemon_connection_init(satellite):
                    logger.error("Satellite connection failed: %s", satellite)

            if received_conf_part:
                # Enable the scheduling process
                logger.info("Loaded: %s", self.sched.pushed_conf)
                self.sched.start_scheduling()

        # Now I have a configuration!
        self.have_conf = True

    def clean_previous_run(self):
        """Clean variables from previous configuration

        :return: None
        """
        # Execute the base class treatment...
        super(Alignak, self).clean_previous_run()

        # Clean all lists
        self.pollers.clear()
        self.reactionners.clear()
        self.brokers.clear()

    def get_daemon_stats(self, details=False):
        """Increase the stats provided by the Daemon base class

        :return: stats dictionary
        :rtype: dict
        """
        # Call the base Daemon one
        res = super(Alignak, self).get_daemon_stats(details=details)

        res.update({
            'name': self.name,
            'type': self.type,
            'monitored_objects': {}
        })

        counters = res['counters']

        # Satellites counters
        counters['brokers'] = len(self.brokers)
        counters['pollers'] = len(self.pollers)
        counters['reactionners'] = len(self.reactionners)
        counters['receivers'] = len(self.receivers)

        if not self.sched:
            return res

        # # Hosts/services problems counters
        # m_solver = MacroResolver()
        # counters['hosts_problems'] = m_solver._get_total_host_problems()
        # counters['hosts_unhandled_problems'] = m_solver._get_total_host_problems_unhandled()
        # counters['services_problems'] = m_solver._get_total_service_problems()
        # counters['services_unhandled_problems'] = m_solver._get_total_service_problems_unhandled()

        # Get statistics from the scheduler
        scheduler_stats = self.sched.get_scheduler_stats(details=details)
        res['counters'].update(scheduler_stats['counters'])
        scheduler_stats.pop('counters')
        res.update(scheduler_stats)

        return res

    def get_monitoring_problems(self):
        """Get the current scheduler livesynthesis

        :return: live synthesis and problems dictionary
        :rtype: dict
        """
        res = {}
        if not self.sched:
            return res

        # Get statistics from the scheduler
        scheduler_stats = self.sched.get_scheduler_stats(details=True)
        if 'livesynthesis' in scheduler_stats:
            res['livesynthesis'] = scheduler_stats['livesynthesis']
        if 'problems' in scheduler_stats:
            res['problems'] = scheduler_stats['problems']

        return res

    def main(self):
        """Main function for Scheduler, launch after the init::

        * Init daemon
        * Load module manager
        * Launch main loop
        * Catch any Exception that occurs

        :return: None
        """
        try:
            # Start the daemon mode
            if not self.do_daemon_init_and_start():
                self.exit_on_error(message="Daemon initialization error",
                                   exit_code=3)

            #  We wait for initial conf
            self.wait_for_initial_conf()
            if self.new_conf:
                # Setup the received configuration
                self.setup_new_conf()

                # Now the main loop
                self.do_main_loop()
                logger.info("Exited from the main loop.")

                # On main loop exit, call the scheduler after run process
                self.sched.after_run()

            self.request_stop()
        except Exception:  # pragma: no cover, this should never happen indeed ;)
            self.exit_on_exception(traceback.format_exc())
            raise
Exemplo n.º 25
0
class Downtime:
    """ Schedules downtime for a specified service. If the "fixed" argument is set
    to one (1), downtime will start and end at the times specified by the
    "start" and "end" arguments.
    Otherwise, downtime will begin between the "start" and "end" times and last
    for "duration" seconds. The "start" and "end" arguments are specified
    in time_t format (seconds since the UNIX epoch). The specified service
    downtime can be triggered by another downtime entry if the "trigger_id"
    is set to the ID of another scheduled downtime entry.
    Set the "trigger_id" argument to zero (0) if the downtime for the
    specified service should not be triggered by another downtime entry.

    """
    _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:
            d_type = "fixed"
        else:
            d_type = "flexible"
        return "%s %s Downtime id=%d %s - %s" % (
            active, d_type, self._id, time.ctime(self.start_time), time.ctime(self.end_time))

    @property
    def id(self):  # pylint: disable=C0103
        """Getter for id, raise deprecation warning

        :return: self._id
        """
        warnings.warn("Access to deprecated attribute id %s Item class" % self.__class__,
                      DeprecationWarning, stacklevel=2)
        return self._id

    @id.setter
    def id(self, value):  # pylint: disable=C0103
        """Setter for id, raise deprecation warning

        :param value: value to set
        :return: None
        """
        warnings.warn("Access to deprecated attribute id of %s class" % self.__class__,
                      DeprecationWarning, stacklevel=2)
        self._id = value

    def trigger_me(self, other_downtime):
        """Wrapper to activate_me.append function
        Used to add another downtime to activate

        :param other_downtime: other downtime to activate/cancel
        :type other_downtime:
        :return: None
        """
        self.activate_me.append(other_downtime)

    def in_scheduled_downtime(self):
        """Getter for is_in_effect attribute

        :return: True if downtime is in effect, False otherwise
        :rtype: bool
        """
        return self.is_in_effect

    def enter(self):
        """Set ref in scheduled downtime and raise downtime log entry (start)

        :return: [], always
        :rtype: list
        TODO: res is useless
        """
        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 downtime in self.activate_me:
            res.extend(downtime.enter())
        return res

    def exit(self):
        """Remove ref in scheduled downtime and raise downtime log entry (exit)

        :return: [], always | None
        :rtype: list
        TODO: res is useless
        """
        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

    def cancel(self):
        """Remove ref in scheduled downtime and raise downtime log entry (cancel)

        :return: [], always
        :rtype: list
        TODO: res is useless
        """
        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
        # res.extend(self.ref.create_notifications('DOWNTIMECANCELLED'))
        # Also cancel other downtimes triggered by me
        for downtime in self.activate_me:
            res.extend(downtime.cancel())
        return res

    def add_automatic_comment(self):
        """Add comment on ref for downtime

        :return: None
        """
        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
        comm = Comment(self.ref, False, "(Alignak)", text, comment_type, 2, 0, False, 0)
        self.comment_id = comm._id
        self.extra_comment = comm
        self.ref.add_comment(comm)

    def del_automatic_comment(self):
        """Remove automatic comment on ref previously created

        :return: None
        """
        # Extra comment can be None if we load it from a old version of Alignak
        # 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)

    def fill_data_brok_from(self, data, brok_type):
        """Fill data with info of item by looking at brok_type
        in props of properties or running_properties

        :param data: data to fill
        :type data:
        :param brok_type: type of brok
        :type brok_type: str
        :return: None
        TODO: Duplicate from Notification.fill_data_brok_from
        """
        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)

    def get_initial_status_brok(self):
        """Get a initial status brok

        :return: brok with wanted data
        :rtype: alignak.brok.Brok
        TODO: Duplicate from Notification.fill_data_brok_from
        """
        data = {'_id': self._id}

        self.fill_data_brok_from(data, 'full_status')
        brok = Brok('downtime_raise', data)
        return brok

    def __getstate__(self):
        """Call by pickle for dataify the comment
        because we DO NOT WANT REF in this pickleisation!

        :return: dict containing notification data
        :rtype: dict
        TODO: REMOVE THIS
        """
        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

    def __setstate__(self, state):
        """Inverted function of getstate

        :param state: state to restore
        :type state: dict
        :return: None
        TODO: REMOVE THIS
        """
        cls = self.__class__

        # Maybe it's not a dict but a list like in the old 0.4 format
        # so we should call the 0.4 function for it
        if isinstance(state, list):
            self.__setstate_deprecated__(state)
            return

        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

    def __setstate_deprecated__(self, state):
        """In 1.0 we move to a dict save.

        :param state: it's the state
        :type state: dict
        :return: None
        TODO: REMOVE THIS"""
        cls = self.__class__
        # Check if the len of this state is like the previous,
        # if not, we will do errors!
        # -1 because of the '_id' prop
        if len(cls.properties) != (len(state) - 1):
            logger.info("Passing downtime")
            return

        self._id = state.pop()
        for prop in cls.properties:
            val = state.pop()
            setattr(self, prop, val)
        if self._id >= cls._id:
            cls._id = self._id + 1
Exemplo n.º 26
0
class Contactgroup(Itemgroup):
    """Class to manage a group of contacts
    A Contactgroup is used to manage a group of contacts
    """
    _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):
        """
        Get list of contacts of this group

        :return: list of contacts
        :rtype: list[alignak.objects.contact.Contact]
        """
        if getattr(self, 'members', None) is not None:
            return [m.strip() for m in self.members]
        else:
            return []

    def get_name(self):
        """
        Get name of group

        :return: Name of contactgroup
        :rtype: str
        """
        return getattr(self, 'contactgroup_name', 'UNNAMED-CONTACTGROUP')

    def get_contactgroup_members(self):
        """
        Get contactgroup members

        :return: list of hosts
        :rtype: list
        """
        # TODO: imho a Contactgroup instance should always have defined
        # its contactgroup_members attribute, even if it's empty / the empty list.
        if hasattr(self, 'contactgroup_members'):
            # more over: it should already be in the list form,
            # not anymore in the "bare" string from as readed
            # from configuration (files or db or whaterver)
            return [m.strip() for m in self.contactgroup_members.split(',')]
        else:
            return []

    def get_contacts_by_explosion(self, contactgroups):
        """
        Get hosts of this group

        :param contactgroups: Contactgroups object, use to look for a specific one
        :type contactgroups: alignak.objects.contactgroup.Contactgroups
        :return: list of contact of this group
        :rtype: list[alignak.objects.contact.Contact]
        """
        # 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 hasattr(self, '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:
            contactgroup = contactgroups.find_by_name(cg_mbr.strip())
            if contactgroup is not None:
                value = contactgroup.get_contacts_by_explosion(contactgroups)
                if value is not None:
                    self.add_string_member(value)
        if hasattr(self, 'members'):
            return self.members
        else:
            return ''
Exemplo n.º 27
0
class Acknowledge(AlignakObject):  # pylint: disable=R0903
    """
    Allows you to acknowledge the current problem for the specified service.
    By acknowledging the current problem, future notifications (for the same
    service state) are disabled.

    If the acknowledge is "sticky", the acknowledgement will remain until
    the service returns to an OK state. Otherwise the acknowledgement will automatically
    be removed when the service state changes.

    If the acknowledge is "notify", a notification will be sent out to contacts
    indicating that the current service problem has been acknowledged and when the
    acknowledge is cleared.
    """

    my_type = 'acknowledge'
    properties = {
        'sticky':
            BoolProp(default=True),
        'notify':
            BoolProp(default=False),
        'end_time':
            IntegerProp(default=0),
        'author':
            StringProp(default=u'Alignak'),
        'comment':
            StringProp(default=u''),
        'comment_id':
            StringProp(default=u'')
    }

    def __init__(self, params=None, parsing=False):
        super(Acknowledge, self).__init__(params, parsing=parsing)

        self.fill_default()

    def serialize(self):
        """This function serialize into a simple dict object.
        It is used when transferring data to other daemons over the network (http)

        Here we directly return all attributes

        :return: json representation of a Acknowledge
        :rtype: dict
        """
        return {'uuid': self.uuid, 'ref': self.ref, 'sticky': self.sticky, 'notify': self.notify,
                'end_time': self.end_time, 'author': self.author, 'comment': self.comment}

    def get_raise_brok(self, host_name, service_name=''):
        """Get a start acknowledge brok

        :param comment_type: 1 = host, 2 = service
        :param host_name:
        :param service_name:
        :return: brok with wanted data
        :rtype: alignak.brok.Brok
        """
        data = self.serialize()
        data['host'] = host_name
        if service_name != '':
            data['service'] = service_name

        return Brok({'type': 'acknowledge_raise', 'data': data})

    def get_expire_brok(self, host_name, service_name=''):
        """Get an expire acknowledge brok

        :type item: item
        :return: brok with wanted data
        :rtype: alignak.brok.Brok
        """
        data = self.serialize()
        data['host'] = host_name
        if service_name != '':
            data['service'] = service_name

        return Brok({'type': 'acknowledge_expire', 'data': data})
Exemplo n.º 28
0
class Receiver(Satellite):
    """Receiver class. Referenced as "app" in most Interface

    """
    my_type = 'receiver'

    properties = Satellite.properties.copy()
    properties.update({
        'pidfile': PathProp(default='receiverd.pid'),
        'port': IntegerProp(default=7773),
        'local_log': PathProp(default='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 = []
        # and the unprocessed one, a buffer
        self.unprocessed_external_commands = []

        self.host_assoc = {}
        self.direct_routing = False
        self.accept_passive_unknown_check_results = False

        self.http_interface = ReceiverInterface(self)

        # Now create the external commander. It's just here to dispatch
        # the commands to schedulers
        ecm = ExternalCommandManager(None, 'receiver')
        ecm.load_receiver(self)
        self.external_command = ecm

    def add(self, elt):
        """Add an object to the receiver one
        Handles brok and externalcommand

        :param elt: object to add
        :type elt: object
        :return: None
        """
        cls_type = elt.__class__.my_type
        if cls_type == 'brok':
            # For brok, we TAG brok with our instance_id
            elt.instance_id = 0
            self.broks[elt._id] = elt
            return
        elif cls_type == 'externalcommand':
            logger.debug("Enqueuing an external command: %s",
                         str(ExternalCommand.__dict__))
            self.unprocessed_external_commands.append(elt)

    def push_host_names(self, sched_id, hnames):
        """Link hostnames to scheduler id.
        Called by alignak.satellite.IForArbiter.push_host_names

        :param sched_id: scheduler id to link to
        :type sched_id: int
        :param hnames: host names list
        :type hnames: list
        :return: None
        """
        for h_name in hnames:
            self.host_assoc[h_name] = sched_id

    def get_sched_from_hname(self, hname):
        """Get scheduler linked to the given host_name

        :param hname: host_name we want the scheduler from
        :type hname: str
        :return: scheduler with id corresponding to the mapping table
        :rtype: dict
        """
        item = self.host_assoc.get(hname, None)
        sched = self.schedulers.get(item, None)
        return sched

    def manage_brok(self, brok):
        """Send brok to modules. Modules have to implement their own manage_brok function.
        They usually do if they inherits from basemodule
        REF: doc/receiver-modules.png (4-5)

        :param brok: brok to manage
        :type brok: alignak.brok.Brok
        :return: None
        """
        to_del = []
        # Call all modules if they catch the call
        for mod in self.modules_manager.get_internal_instances():
            try:
                mod.manage_brok(brok)
            except Exception, exp:
                logger.warning("The mod %s raise an exception: %s, I kill it",
                               mod.get_name(), str(exp))
                logger.warning("Exception type: %s", type(exp))
                logger.warning("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)
Exemplo n.º 29
0
class Check(Action):  # pylint: disable=R0902
    """Check class implements monitoring concepts of checks :(status, state, output)
    Check instance are used to store monitoring plugins data (exit status, output)
    and used by schedule to raise alert, reschedule check etc.

    """
    # AutoSlots create the __slots__ with properties and
    # running_properties names

    # FIXME : re-enable AutoSlots if possible
    # __metaclass__ = AutoSlots

    my_type = 'check'

    properties = Action.properties.copy()
    properties.update({
        'is_a':
        StringProp(default=u'check'),
        'state':
        IntegerProp(default=0),
        'depend_on':
        ListProp(default=[]),
        'depend_on_me':
        ListProp(default=[], split_on_comma=False),
        'passive_check':
        BoolProp(default=False),
        'freshness_expiry_check':
        BoolProp(default=False),
        'poller_tag':
        StringProp(default=u'None'),
        'dependency_check':
        BoolProp(default=False),
    })

    def __init__(self, params=None, parsing=False):
        super(Check, self).__init__(params, parsing=parsing)

        if self.command.startswith('_'):
            self.internal = True

    def __str__(self):  # pragma: no cover
        return "Check %s %s, item: %s, status: %s, command:'%s'" % \
               (self.uuid, "active" if not self.passive_check else "passive",
                self.ref, self.status, self.command)

    def get_return_from(self, check):
        """Update check data from action (notification for instance)

        :param check: action to get data from
        :type check: alignak.action.Action
        :return: None
        """
        for prop in [
                'exit_status', 'output', 'long_output', 'check_time',
                'execution_time', 'perf_data', 'u_time', 's_time'
        ]:
            setattr(self, prop, getattr(check, prop))

    def set_type_active(self):
        """Set this check as an active one (indeed, not passive)

        :return: None
        """
        self.passive_check = False

    def set_type_passive(self):
        """Set this check as a passive one

        :return: None
        """
        self.passive_check = True

    def is_dependent(self):
        """Getter for dependency_check attribute

        :return: True if this check was created for a dependent one, False otherwise
        :rtype: bool
        """
        return self.dependency_check

    def serialize(self):
        """This function serializes into a simple dict object.

        The only usage is to send to poller, and it does not need to have the
        depend_on and depend_on_me properties.

        :return: json representation of a Check
        :rtype: dict
        """
        res = super(Check, self).serialize()
        if 'depend_on' in res:
            del res['depend_on']
        if 'depend_on_me' in res:
            del res['depend_on_me']
        return res
Exemplo n.º 30
0
class SatelliteLink(Item):
    """SatelliteLink is a common Class for links between
    Arbiter and other satellites. Used by the Dispatcher object.

    """
    # _id = 0 each Class will have it's own id

    properties = Item.properties.copy()
    properties.update({
        'address':         StringProp(default='localhost', fill_brok=['full_status']),
        'timeout':         IntegerProp(default=3, fill_brok=['full_status']),
        'data_timeout':    IntegerProp(default=120, fill_brok=['full_status']),
        'check_interval':  IntegerProp(default=60, fill_brok=['full_status']),
        'max_check_attempts': IntegerProp(default=3, fill_brok=['full_status']),
        'spare':              BoolProp(default=False, 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),
        'modules':            ListProp(default=[''], to_send=True, split_on_coma=True),
        'polling_interval':   IntegerProp(default=1, fill_brok=['full_status'], to_send=True),
        'use_timezone':       StringProp(default='NOTSET', to_send=True),
        'realm':              StringProp(default='', fill_brok=['full_status'],
                                         brok_transformation=get_obj_name_two_args_and_void),
        'satellitemap':       DictProp(default={}, elts_prop=AddrProp, to_send=True, override=True),
        'use_ssl':             BoolProp(default=False, fill_brok=['full_status']),
        'hard_ssl_name_check': BoolProp(default=True, fill_brok=['full_status']),
        'passive':             BoolProp(default=False, fill_brok=['full_status'], to_send=True),
    })

    running_properties = Item.running_properties.copy()
    running_properties.update({
        'con':                  StringProp(default=None),
        'alive':                BoolProp(default=True, fill_brok=['full_status']),
        'broks':                StringProp(default=[]),

        # the number of failed attempt
        'attempt':              StringProp(default=0, fill_brok=['full_status']),

        # can be network ask or not (dead or check in timeout or error)
        'reachable':            BoolProp(default=False, fill_brok=['full_status']),
        'last_check':           IntegerProp(default=0, fill_brok=['full_status']),
        'managed_confs':        StringProp(default={}),
    })

    def __init__(self, *args, **kwargs):
        super(SatelliteLink, self).__init__(*args, **kwargs)

        self.arb_satmap = {'address': '0.0.0.0', 'port': 0}
        if hasattr(self, 'address'):
            self.arb_satmap['address'] = self.address
        if hasattr(self, 'port'):
            try:
                self.arb_satmap['port'] = int(self.port)
            except Exception:
                pass

    def get_name(self):
        """Get the name of the link based on its type
        if *mytype*_name is an attribute then returns self.*mytype*_name.
        otherwise returns "Unnamed *mytype*"
        Example : self.poller_name or "Unnamed poller"

        :return: String corresponding to the link name
        :rtype: str
        """
        return getattr(self,
                       "{0}_name".format(self.get_my_type()),
                       "Unnamed {0}".format(self.get_my_type()))

    def set_arbiter_satellitemap(self, satellitemap):
        """
            arb_satmap is the satellitemap in current context:
                - A SatelliteLink is owned by an Arbiter
                - satellitemap attribute of SatelliteLink is the map
                  defined IN THE satellite configuration
                  but for creating connections, we need the have the satellitemap of the Arbiter

        :return: None
        """
        self.arb_satmap = {'address': self.address, 'port': self.port, 'use_ssl': self.use_ssl,
                           'hard_ssl_name_check': self.hard_ssl_name_check}
        self.arb_satmap.update(satellitemap)

    def create_connection(self):
        """Initialize HTTP connection with a satellite (con attribute) and
        set uri attribute

        :return: None
        """
        self.con = HTTPClient(address=self.arb_satmap['address'], port=self.arb_satmap['port'],
                              timeout=self.timeout, data_timeout=self.data_timeout,
                              use_ssl=self.use_ssl,
                              strong_ssl=self.hard_ssl_name_check
                              )
        self.uri = self.con.uri

    def put_conf(self, conf):
        """Send the conf (serialized) to the satellite
        HTTP request to the satellite (POST / put_conf)

        :param conf: The conf to send (data depend on the satellite)
        :type conf:
        :return: None
        """
        if self.con is None:
            self.create_connection()

        # Maybe the connection was not ok, bail out
        if not self.con:
            return False

        try:
            self.con.get('ping')
            self.con.post('put_conf', {'conf': conf}, wait='long')
            print "PUT CONF SUCESS", self.get_name()
            return True
        except HTTPEXCEPTIONS, exp:
            self.con = None
            logger.error("Failed sending configuration for %s: %s", self.get_name(), str(exp))
            return False