Esempio n. 1
0
def email_failed_logins_alarm(now=None, failed_threshold=None, **dead_for):
    """
    raise alert about failed `Citrix` logon events and send it via email

    :arg int failed_threshold: the number of failed logons that will trigger the
        alert

        By default, this will be retrieved from the dynamic preference
        `Failed logon events count alert threshold
        <../../../admin/dynamic_preferences/globalpreferencemodel/?q=logon_alert_threshold>`__

    See the :func:`email_dead_borgs_alert` for details about the other arguments.

    This alert used the subscription at `Citrix logon alert
    <../../../admin/ssl_cert_tracker/subscription/?q=Citrix+logon+alert>`__.
    """
    if failed_threshold is None:
        failed_threshold = get_preference(
            'citrusborglogon__logon_alert_threshold')

    if not dead_for:
        time_delta = get_preference('citrusborglogon__logon_alert_after')
    else:
        time_delta = base_utils.MomentOfTime.time_delta(**dead_for)

    now = base_utils.MomentOfTime.now(now)
    data = raise_failed_logins_alarm(now=now,
                                     time_delta=time_delta,
                                     failed_threshold=failed_threshold)

    if not data:
        return (
            'there were less than {} failed logon events between'
            ' {:%a %b %d, %Y %H:%M %Z} and {:%a %b %d, %Y %H:%M %Z}'.format(
                failed_threshold, timezone.localtime(value=now),
                timezone.localtime(now - time_delta)))

    try:
        return base_utils.borgs_are_hailing(
            data=data,
            subscription=base_utils.get_subscription('Citrix logon alert'),
            logger=LOGGER,
            time_delta=time_delta,
            failed_threshold=failed_threshold)
    except Exception as error:
        raise error
Esempio n. 2
0
def get_session():
    """
    prepare and return a :class:`<requests.Session>` instance with all the
    trimmings

    #TODO: not useful until the orionsdk package is update =d to version 0.0.8
    or higher
    """
    session = requests.Session()

    session.timeout = (get_preference('orionserverconn__orion_conn_timeout'),
                       get_preference('orionserverconn__orion_read_timeout'))
    session.verify = get_preference('orionserverconn__orion_verify_ssl_cert')

    retry = Retry(
        total=get_preference('orionserverconn__orion_retry'),
        read=get_preference('orionserverconn__orion_retry'),
        connect=get_preference('orionserverconn__orion_retry'),
        backoff_factor=get_preference('orionserverconn__orion_backoff_factor'),
        status_forcelist=(500, 502, 504))

    adapter = HTTPAdapter(max_retries=retry)

    session.mount('http://', adapter)
    session.mount('https:/', adapter)

    return session
def invoke_report_events_by_bot(report_interval=None, report_level=None):
    """
    invoke tasks for mailing the events by bot reports

    :arg `object` report_interval:

        the time interval for which the report is calculated

        it is either a :class:`datetime.timedelta` instance or a
        :class:`dict` suitable for constructing a :class:`datetime.timedelta`
        instance. it defaults to ``None`` and  when it is ``None``,
        the value is picked from
        :class:`citrus_borg.dynamic_preferences_registry.ExchangeReportInterval`

    :arg str report_level: similar to a log level, defaults to ``None``

        when ``None``, the value is picked from
        :class:`citrus_borg.dynamic_preferences_registry"""\
        """.ExchangeDefaultErrorLevel`


    :returns: the bots for which the report tasks have been invoked
    :rtype: str

    """
    if report_interval is None:
        report_interval = get_preference('exchange__report_interval')

    if report_level is None:
        report_level = get_preference('exchange__report_level')

    bots = list(
        base_utils.get_base_queryset('mail_collector.mailhost',
                                     enabled=True).values_list('host_name',
                                                               flat=True))

    group(
        report_events_by_bot.s(bot, report_interval, report_level)
        for bot in bots)()

    group(report_failed_events_by_bot.s(bot, report_interval)
          for bot in bots)()

    LOG.info('launched report tasks for exchange events by bot for bots: %s',
             ', '.join(bots))
def delete_expired_entries(data_source=None):
    """
    delete rows marked as expired from the :class:`model
    <django.db.models.Model>` defined by the `data_source` argument

    This task assumes that the :class:`model <django.db.models.Model>`
    defined by the data_source argument has a :class:`bool` attribute named
    `is_expired`.

    The task will actually delete entries only if the user preference defined
    in :class:
    `citrus_borg.dynamic_preferences_registry.LdapDeleteExpiredProbeLogEntries`
    is so configured.

    :arg str data_source: the name of a :class:`model
        <django.db.models.Model>` in the `app_label.modelname` format

        By default this argument will point to the
        :class:`ldap_probe.models.LdapProbeLog` model

    :returns: the name of the data source and the number of deleted rows

    :raises:

        :exc:`p_soc-auto.base.utils.UnknownDataTargetError` if the
        `data_source` argument cannot be resolved to a valid
        :class:`django.db.models.Model`

        :exc:`exceptions.AttributeError` if the
        :class:`django.db.models.Model` resolved from the `data_source`
        argument doesn't have an `is_expired` attribute

    """
    LOG.debug('kick delete_expired_entries')
    if not get_preference('ldapprobe__ldap_delete_expired'):
        LOG.info('the application is not configured to delete expired rows')
        return

    if data_source is None:
        data_source = 'ldap_probe.LdapProbeLog'

    try:
        data_source = apps.get_model(data_source)
    except utils.UnknownDataTargetError:
        LOG.exception('Cannot delete entries for non-existent model %s',
                      data_source)
        raise

    if not hasattr(data_source, 'is_expired'):
        raise AttributeError(
            f'There are no expired rows in {data_source._meta.model_name}.'
            ' It does not have an is_expired field')

    count_deleted = data_source.objects.filter(is_expired=True).all().delete()

    LOG.info('Deleted %s expired rows from %s',
             count_deleted, data_source._meta.verbose_name)
Esempio n. 5
0
 def _annotate_orion_url(cls, queryset=None):
     return queryset.annotate(
         orion_anchor=cls.sql_orion_anchor_field).annotate(
             orion_url=Concat(
                 Value(get_preference('orionserverconn__orion_server_url')),
                 F('node__details_url'),
                 output_field=URLField()
             )
         )
def get_ux_alarms(  # pylint: disable=too-many-arguments
        now=None,  group_by=GroupBy.NONE,
        time_delta=get_preference('citrusborgux__ux_alert_interval'),
        ux_alert_threshold=get_preference('citrusborgux__ux_alert_threshold'),
        annotate_url=True, annotate_details_url=True, **details):
    """
    get the user experience alert data
    """
    queryset = raise_ux_alarm(
        now=now, group_by=group_by, time_delta=time_delta,
        ux_alert_threshold=ux_alert_threshold)

    if annotate_url:
        queryset = base_utils.url_annotate(queryset)

    if annotate_details_url:
        queryset = base_utils.details_url_annotate(queryset, **details)

    return queryset
    def __init__(
            self, *args,
            verify=get_preference('orionserverconn__orion_verify_ssl_cert')):
        """
        override the parent constructor to prefer defaults specific to the
        target server
        """
        if not args:
            args = DST_DEFAULTS

        super().__init__(*args, verify=verify)
Esempio n. 8
0
    def perf_warn(self):
        """
        flag for considering if an instance of this class must trigger a
        performance warning

        :returns: `True` if there is a timing from the probe above the warn
                  threshold, and ldap_perf_raise_all is `True`.
        :rtype: bool
        """
        return get_preference('ldapprobe__ldap_perf_raise_all')\
            and self._perf_level(self.node_perf_bucket.avg_warn_threshold)
def raise_ldap_probe_failed_alert(instance_pk=None, subscription=None):
    """
    raise an email alert for a failed instance of the
    :class:`ldap_probe.models.LdapProbeLog` model

    :arg int instance_pk: the primary key of the instance

    :arg str subscription: the value of the :attr:`subscription
        <p_soc_auto_base.models.Subscription.subscription>` attribute
        used to retrieve the
        :class:`p_soc_auto_base.models.Subscription` instance required
        for raising this alert via email

    """
    if subscription is None:
        subscription = get_preference('ldapprobe__ldap_error_subscription')

    return _raise_ldap_alert(
        instance_pk=instance_pk,
        subscription=Subscription.get_subscription(subscription),
        level=get_preference('commonalertargs__error_level'))
Esempio n. 10
0
    def query(cls, orion_query, **params):
        """
        query the `Orion` server

        :arg str query: the query string
        :arg dict params: the query params

        :returns: the data that matches the query
        :rtype: dict

        """

        # need to configure the SESSION object here because the
        # user configurable settings will not work if used at the
        # module level
        SESSION.auth = (get_preference('orionserverconn__orion_user'),
                        get_preference('orionserverconn__orion_password'))
        SESSION.verify = get_preference(
            'orionserverconn__orion_verify_ssl_cert')

        response = SESSION.post(
            '{}/Query'.format(
                get_preference('orionserverconn__orion_rest_url')),
            data=json.dumps(dict(query=orion_query, parameters=params),
                            default=serialize_custom_json),
            timeout=(get_preference('orionserverconn__orion_conn_timeout'),
                     get_preference('orionserverconn__orion_read_timeout')))

        response.raise_for_status()

        return response.json()['results']
Esempio n. 11
0
def login_states_by_site_host_hour(
        now=None,
        time_delta=get_preference(
            'citrusborgevents__ignore_events_older_than'),
        site=None,
        host_name=None):
    """
    :returns: a :class:`django.db.models.query.QuerySet` based on the
        :class:`citru_borg.models.WinlogbeatHost` `annotated
        <https://docs.djangoproject.com/en/2.2/ref/models/querysets/#annotate>`__
        with all the `aggregations
        <https://docs.djangoproject.com/en/2.2/topics/db/aggregation/#aggregation>`__
        extracted from the :class:`citrus_borg.models.WinlogEvent` model
        calculated on a per hour basis for the interval defined by the
        `now` and `time_delta` arguments

    :arg datetime.datetime now: the initial moment

        By default the initial moment is the value returned by
        :meth:`django.utils.timezone.now`

    :arg datetime.timedelta time_delta: the time interval to consider

        By default, this will be retrieved from the dynamic preference
        `Ignore events created older than
        <../../../admin/dynamic_preferences/globalpreferencemodel/?q=ignore_events_older_than>`__

    :arg str site: if present, filter the data that will be returned by `site`,
        otherwise return data for all known sites



    :arg str host_name: if present, filter the data that will be returned by
        'host_name`, otherwise return data for all known hosts

        Be careful when using the `site` and `host_name` arguments together.
        It is possible to come up with a combination of values for which
        no data can be returned (one filters by a host that lives at a site
        that was filtered out already). This function considers such a
        combination valid and will happily return an empty
        :class:`django.db.models.query.QuerySet` when invoked with such a
        combination

    :raises: :exc:`Exception` when failing

    """
    try:
        queryset = _by_site_host_hour(now, time_delta, site, host_name)
    except Exception as error:
        raise error

    return queryset.order_by('site__site', 'host_name', '-hour')
def raise_site_not_configured_for_bot():
    """
    email alerts if there are exchange bots with mis-configured site info
    """
    data = models.MailHost.objects.filter(
        Q(site__isnull=True) | Q(site__site__iexact='site.not.exist')).\
        exclude(host_name__iexact='host.not.exist')

    if data.exists():
        data = base_utils.url_annotate(data)

    if not data and not get_preference('exchange__empty_alerts'):
        LOG.info('all exchange bots are properly configured')
        return

    if Email.send_email(
            data=data,
            subscription=Subscription.get_subscription('Exchange bot no site'),
            level=get_preference('exchange__server_error')):
        LOG.info('emailed alert for mis-configured Exchange bots')

    LOG.warning('cannot email alert for mis-configured Exchange bots')
Esempio n. 13
0
    def orion_node_url(self):
        """
        absolute `SolarWinds Orion <https://www.solarwinds.com/solutions/orion>`__
        `URL` for the network node serving this :class:`SslCertificate` instance
        """
        orion_node = OrionNode.objects.filter(orion_id=self.orion_id)
        if orion_node.exists():
            orion_node = orion_node.values('node_caption', 'details_url')[0]
            return '<a href="%s%s">%s on Orion</>' % (
                get_preference('orionserverconn__orion_server_url'),
                orion_node.get('details_url'), orion_node.get('node_caption'))

        return 'acquired outside the Orion infrastructure'
Esempio n. 14
0
def expire_events():
    """
    task that marks :class:`citrus_borg.models.WinlogEvent` instances as
    expired; it will also delete `expired` instances if so configured

    This task is configured by:

    * `Mark Events As Expired If Older Than
      <../../../admin/dynamic_preferences/globalpreferencemodel/?q=expire_events_older_than>`__

       This preference is defined by
       :class:`citrus_borg.dynamic_preferences_registry.ExpireEvents`

    * `Delete Expired Events
      <../../../admin/dynamic_preferences/globalpreferencemodel/?q=delete_expired_events>`__

       The preference is defined by
       :class:`citrus_borg.dynamic_preferences_registry.DeleteExpireEvents`

    :returns: a status string about how many events were handles by the task,
        the types of operations performed, and the threshold used for marking
        events as expired (see `Mark Events As Expired If Older Than
        <../../../admin/dynamic_preferences/globalpreferencemodel/?q=expire_events_older_than>`__)
    :rtype: str

    """
    expired = WinlogEvent.objects.filter(
        created_on__lt=timezone.now() -
        get_preference('citrusborgevents__expire_events_older_than')).update(
            is_expired=True)

    if get_preference('citrusborgevents__delete_expired_events'):
        WinlogEvent.objects.filter(is_expired=True).all().delete()
        return 'deleted %s events accumulated over the last %s' % (
            expired,
            get_preference('citrusborgevents__expire_events_older_than'))

    return 'expired %s events accumulated over the last %s' % (
        expired, get_preference('citrusborgevents__expire_events_older_than'))
Esempio n. 15
0
def save_citrix_login_event(borg):
    """
    Save data received from a citrix bot.
    :param borg: Message received from bot.
    :raises: Any exception raised during
    """
    def reraise(msg):
        LOG.exception('%s %s.', msg, borg)
        # This function should only be called from inside an except block
        # If an Exception is not being handled it will cause a RuntimeError
        raise  # pylint: disable=misplaced-bare-raise

    event_host = WinlogbeatHost.get_or_create_from_borg(borg)
    event_broker = KnownBrokeringDevice.get_or_create_from_borg(borg)
    try:
        event_source = AllowedEventSource.objects.get(
            source_name=borg.event_source)
    except AllowedEventSource.DoesNotExist:
        reraise('Cannot match event source for event')

    try:
        windows_log = WindowsLog.objects.get(log_name=borg.windows_log)
    except WindowsLog.DoesNotExist:
        reraise('Cannot match windows log info for event')

    user = get_or_create_user(get_preference('citrusborgcommon__service_user'))

    winlogevent = WinlogEvent(
        source_host=event_host,
        record_number=borg.record_number,
        event_source=event_source,
        windows_log=windows_log,
        event_state=borg.borg_message.state,
        xml_broker=event_broker,
        event_test_result=borg.borg_message.test_result,
        storefront_connection_duration
        =borg.borg_message.storefront_connection_duration,
        receiver_startup_duration=borg.borg_message.receiver_startup_duration,
        connection_achieved_duration
        =borg.borg_message.connection_achieved_duration,
        logon_achieved_duration=borg.borg_message.logon_achieved_duration,
        logoff_achieved_duration=borg.borg_message.logoff_achieved_duration,
        failure_reason=borg.borg_message.failure_reason,
        failure_details=borg.borg_message.failure_details,
        raw_message=borg.borg_message.raw_message,
        event_id=borg.event_id,
        timestamp=borg.timestamp,
        created_by=user, updated_by=user)
    winlogevent.save()

    LOG.info('saved event: %s', winlogevent.uuid)
Esempio n. 16
0
def email_failed_login_sites_report(now=None, send_no_news=False,
                                    **reporting_period):
    """
    spawn an instance of the :func:`email_failed_login_site_report` task for the
    `site` and `borg_name` combination.

    If `site` and/or `borg_name` are `None`, spawn an instance of the
    :func:`email_failed_login_site_report` task for each `enabled` `site` and
    `borg_name` known to the system

    :arg str site: if `None`, spawn tasks for all sites

    :arg str borg_name: the short host name of the bot host

        If `None`, spawn a task for each `borg_name` on the `site`.

        Note that it is possible to pick `site` and `borg_name` combinations
        that will result in no data being generated.

        In most cases this `task` is used to spawn an instance of the
        :func:`email_login_ux_summary` task for each `enabled` bot on each
        `enabled` site known to the system.

    :arg now: see :func:`email_dead_borgs_alert`

    :arg bool send_no_news: see :func:`email_dead_borgs_alert`

    :arg dict reporting_period: see the `dead_for` argument of the
        :func:`email_dead_borgs_alert` task

        If this argument is  not present, the reporting interval is picked from
        dynamic preference `Logon events reporting period
        <../../../admin/dynamic_preferences/globalpreferencemodel/"""\
            """?q=logon_report_period>`__

    """
    if not reporting_period:
        time_delta = get_preference('citrusborglogon__logon_report_period')
    else:
        time_delta = base_utils.MomentOfTime.time_delta(**reporting_period)

    borg_names = WinlogbeatHost.active\
        .order_by('host_name').values_list('host_name', flat=True)

    group(email_failed_login_site_report.s(now, time_delta,
                                           send_no_news, borg_name) for
          borg_name in borg_names)()

    LOG.info('bootstrapped failed login reports for %s', borg_names)
Esempio n. 17
0
def report_failed_events_by_bot(bot, report_interval):
    """
    send out report for failed events for a bot over a given duration measured
    back from the moment of the call  via email

    :arg str bot: the host (short) name of the bot to report on

    :arg `object` report_interval: the time interval for which the report is
        calculated. it is either a :class:`datetime.timedelta` instance or a
        :class:`dict` suitable for constructing a :classL`datetime.timedelta`
        instance, for instance {'hours': 1, 'seconds': 1}

    :returns: the result of the email send operation
    :rtype: str

    :raises:

        :exc:`Exception` if an exception was thrown while sending the alert

    """
    subscription = base_utils.get_subscription(
        'Exchange Failed Send Receive By Bot')

    data = queries.dead_bodies(
        data_source='mail_collector.mailbotmessage',
        filter_exp='event__event_registered_on__gte',
        not_seen_after=base_utils.MomentOfTime.past(
            time_delta=report_interval),
        event__source_host__host_name=bot,
        event__event_status__iexact='fail').\
        order_by('-mail_message_identifier', 'event__event_type_sort')

    try:
        ret = base_utils.borgs_are_hailing(
            data=data, subscription=subscription, logger=LOGGER,
            time_delta=report_interval,
            level=get_preference('exchange__server_error'), bot=bot)
    except Exception as error:
        raise error

    if ret:
        return (
            'emailed exchange failed send receive events report for bot %s'
            % bot)

    return (
        'could not email exchange failed send receive events report for bot %s'
        % bot)
Esempio n. 18
0
    def orion_node_url(self):
        """
        :returns: an instance property with the `URL` of the
            `Django Admin change` form for the
            :class:`orion_integration.models.OrionNode` instance representing
            the host

        """
        orion_node = OrionNode.objects.filter(orion_id=self.orion_id)
        if orion_node.exists():
            orion_node = orion_node.values('node_caption', 'details_url')[0]
            return '<a href="%s%s">%s on Orion</>' % (
                get_preference('orionserverconn__orion_server_url'),
                orion_node.get('details_url'), orion_node.get('node_caption'))

        return 'acquired outside the Orion infrastructure'
Esempio n. 19
0
def get_dead_brokers(now=None, time_delta=None):
    """
    get the `Citrix` session hosts that have not serviced any requests during
    the interval defined by the arguments

    This function is very similar to :func:`get_dead_bots`.
    The only differences are:

    * The data is pulled from the
      :class:`citrus_borg.models.KnownnBrokeringDevice`

    * The default value for the `time_delta` argument is picked from the
      dynamic preference `Session host not seen alert threshold
      <../../../admin/dynamic_preferences/globalpreferencemodel/?q=dead_session_host_after>`__
    """
    if now is None:
        now = timezone.now()

    if time_delta is None:
        time_delta = get_preference('citrusborgnode__dead_session_host_after')

    if not isinstance(now, datetime.datetime):
        raise TypeError('%s type invalid for %s' % (type(now), now))

    if not isinstance(time_delta, datetime.timedelta):
        raise TypeError('%s type invalid for %s' %
                        (type(time_delta), time_delta))

    live_brokers = list(
        WinlogEvent.objects.filter(
            created_on__gt=now - time_delta,
            event_state__iexact='successful').distinct().values_list(
                'xml_broker__broker_name', flat=True))

    all_brokers = list(
        KnownBrokeringDevice.objects.filter(enabled=True).values_list(
            'broker_name', flat=True))

    dead_brokers = set(all_brokers).symmetric_difference(set(live_brokers))

    dead_brokers = KnownBrokeringDevice.objects.\
        filter(broker_name__in=list(dead_brokers))
    if dead_brokers.exists():
        dead_brokers = dead_brokers.order_by('last_seen')

    return dead_brokers
Esempio n. 20
0
    def get_queryset(self):
        """
        override :meth:`django.db.models.Manager.get_queryset`

        See `Modifying a manager's initial QuerySet
        <https://docs.djangoproject.com/en/2.2/topics/db/managers/#modifying-a-manager-s-initial-queryset>`__
        in the `Django` docs.

        :returns: a :class:`django.db.models.query.QuerySet` with the
            :class:`OrionNode` instances that are `Windows domain
            controllers`

        """
        return super().get_queryset().\
            filter(program_application_type__icontains=get_preference(
                'orionfilters__domaincontroller')).\
            exclude(enabled=False)
Esempio n. 21
0
    def get_queryset(self):
        """
        override :meth:`django.db.models.Manager.get_queryset`

        See `Modifying a manager's initial QuerySet
        <https://docs.djangoproject.com/en/2.2/topics/db/managers/#modifying-a-manager-s-initial-queryset>`__
        in the `Django` docs.

        :returns: a :class:`django.db.models.query.QuerySet` with the
            :class:`OrionNode` instances that map to `Orion` nodes tagged as
            `Cerner-CST` nodes


        """
        return super().get_queryset().filter(
            program_application__exact=get_preference(
                'orionfilters__cerner_cst'))
def report_failed_events_by_site(site, report_interval):
    """
    send out report with failed events for a site via email

    :arg str site: the host (short) name of the bot to report on

    :arg `object` report_interval: the time interval for which the report is
        calculated. it is either a :class:`datetime.timedelta` instance or a
        :class:`dict` suitable for constructing a :class:`datetime.timedelta`
        instance


    :returns: the result of the email send operation
    :rtype: str

    :raises:

        :exc:`Exception` if an exception was thrown while sending the alert

    """
    subscription = Subscription.get_subscription(
        'Exchange Failed Send Receive By Site')

    data = queries.dead_bodies(
        data_source='mail_collector.mailbotmessage',
        filter_exp='event__event_registered_on__gte',
        not_seen_after=base_utils.MomentOfTime.past(
            time_delta=report_interval),
        event__source_host__site__site=site,
        event__event_status__iexact='fail').\
        order_by('-mail_message_identifier', 'event__event_type_sort')

    if Email.send_email(data=data,
                        subscription=subscription,
                        time_delta=report_interval,
                        level=get_preference('exchange__server_error'),
                        site=site):
        LOG.info(
            'emailed exchange failed send receive events report for site'
            ' %s', site)
        return

    LOG.warning(
        'could not email exchange failed send receive events report for'
        ' site %s', site)
Esempio n. 23
0
def get_logins_by_event_state_borg_hour(now=None, time_delta=None):
    """
    get the number of failed events and successful events during the interval
    defined by the arguments for each monitoring site aggregated by hour

    :arg datetime.datetime now: the initial moment
        By default the initial moment is the value returned by
        :meth:`django.utils.timezone.now`

    :arg datetime.timedelta time_delta: the time interval to consider
        By default, this will be retrieved from the dynamic preference
        `Dead if not seen for more than
        <../../../admin/dynamic_preferences/globalpreferencemodel/?q=dead_after>`__

    :returns: a :class:`django.db.models.query.QuerySet` based on the
        :class:`citrus_borg.models.WinlogbeatHost` model


    """
    if now is None:
        now = timezone.now()

    if time_delta is None:
        time_delta = get_preference('citrusborgcommon__dead_after')

    if not isinstance(now, datetime.datetime):
        raise TypeError('%s type invalid for %s' % (type(now), now))

    if not isinstance(time_delta, datetime.timedelta):
        raise TypeError('%s type invalid for %s' %
                        (type(time_delta), time_delta))

    return WinlogbeatHost.objects.\
        filter(winlogevent__created_on__gt=now - time_delta).\
        annotate(hour=TruncHour('winlogevent__created_on')).values('hour').\
        annotate(
            failed_events=Count(
                'winlogevent__event_state',
                filter=Q(winlogevent__event_state__iexact='failed'))).\
        annotate(
            successful_events=Count(
                'winlogevent__event_state',
                filter=Q(winlogevent__event_state__iexact='successful'))).\
        order_by('-hour', 'site__site')
Esempio n. 24
0
def get_dead_sites(now=None, time_delta=None):
    """
    ge the remote sites from where no `ControlUp` events have been delivered
    during the interval defined by the arguments

    This function is very similar to :func:`get_dead_bots`.
    The only differences are:

    * The data is pulled from the
      :class:`citrus_borg.models.BorgSite`

    * The default value for the `time_delta` argument is picked from the
      dynamic preference `Site not seen alert threshold
      <../../../admin/dynamic_preferences/globalpreferencemodel/?q=dead_site_after>`__

    """
    if now is None:
        now = timezone.now()

    if time_delta is None:
        time_delta = get_preference('citrusborgnode__dead_site_after')

    if not isinstance(now, datetime.datetime):
        raise TypeError('%s type invalid for %s' % (type(now), now))

    if not isinstance(time_delta, datetime.timedelta):
        raise TypeError('%s type invalid for %s' %
                        (type(time_delta), time_delta))

    live_sites = list(
        WinlogEvent.objects.filter(created_on__gt=now -
                                   time_delta).distinct().values_list(
                                       'source_host__site__site', flat=True))

    all_sites = list(
        BorgSite.objects.filter(enabled=True).values_list('site', flat=True))

    dead_sites = set(all_sites).symmetric_difference(set(live_sites))

    dead_sites = BorgSite.objects.filter(site__in=list(dead_sites)).distinct()
    if dead_sites.exists():
        dead_sites = dead_sites.order_by('winlogbeathost__last_seen')

    return dead_sites
Esempio n. 25
0
def email_dead_servers_report(now=None, send_no_news=False, **dead_for):
    """
    generate and email reports about `Citrix` application servers that have not
    service any requests during the time interval defined by arguments `now` and
    `dead_for` via email

    This task is almost identical to :func:`email_dead_borgs_alert` with the
    exception of the default value for the :class:`datetime.timedelta` object
    created when `dead_for` is not present.
    This value is picked from dynamic preference `Reporting period for dead nodes
    <../../../admin/dynamic_preferences/globalpreferencemodel/?q=node_forgotten_after>`__

    This task used the subscription at `Missing Citrix farm hosts
    <../../../admin/ssl_cert_tracker/subscription/?q=Missing+Citrix+farm+hosts>`__
    to render the emails being sent.
    """
    now = base_utils.MomentOfTime.now(now)

    if not dead_for:
        time_delta = get_preference('citrusborgnode__node_forgotten_after')
    else:
        time_delta = base_utils.MomentOfTime.time_delta(**dead_for)

    data = get_dead_brokers(now=now, time_delta=time_delta)
    if not data and send_no_news:
        return (
            'all known Cerner session servers were active between'
            ' {:%a %b %d, %Y %H:%M %Z} and {:%a %b %d, %Y %H:%M %Z}'.format(
                timezone.localtime(value=now),
                timezone.localtime(now - time_delta)))

    try:
        return base_utils.borgs_are_hailing(
            data=data,
            subscription=base_utils.get_subscription(
                'Missing Citrix farm hosts'),
            logger=LOGGER,
            time_delta=time_delta)
    except Exception as error:
        raise error
Esempio n. 26
0
def email_dead_sites_report(now=None, send_no_news=False, **dead_for):
    """
    generate and email reports about remote sites where`Citrix` monitoring bots
    have not been seen within the time interval defined by arguments `now` and
    `dead_for` via email

    This task is almost identical to :func:`email_dead_borgs_alert` with the
    exception of the default value for the :class:`datetime.timedelta` object
    created when `dead_for` is not present.
    This value is picked from dynamic preference `Reporting period for dead nodes
    <../../../admin/dynamic_preferences/globalpreferencemodel/?q=node_forgotten_after>`__

    This task used the subscription at `Dead Citrix client sites
    <../../../admin/ssl_cert_tracker/subscription/?q=Dead+Citrix+client+sites>`__
    to render the emails being sent.
    """
    now = base_utils.MomentOfTime.now(now)

    if not dead_for:
        time_delta = get_preference('citrusborgnode__node_forgotten_after')
    else:
        time_delta = base_utils.MomentOfTime.time_delta(**dead_for)

    data = get_dead_sites(now=now, time_delta=time_delta)
    if not data and send_no_news:
        return (
            'at least one monitoring bot on each site was active between'
            ' {:%a %b %d, %Y %H:%M %Z} and {:%a %b %d, %Y %H:%M %Z}'.format(
                timezone.localtime(value=now),
                timezone.localtime(now - time_delta)))

    try:
        return base_utils.borgs_are_hailing(
            data=data,
            subscription=base_utils.get_subscription(
                'Dead Citrix client sites'),
            logger=LOGGER,
            time_delta=time_delta)
    except Exception as error:
        raise error
Esempio n. 27
0
def invoke_raise_citrix_slow_alert(sender, instance, *args, **kwargs):
    """
    evaluate whether the :class:`citrus_borg.models.WinlogEvent` instance
    is reporting slower than expected timings and invoke the `Celery task` that
    is responsible for dispatching the alert
    """
    alertable_timings = [
        instance.storefront_connection_duration,
        instance.logon_achieved_duration, instance.receiver_startup_duration,
        instance.connection_achieved_duration,
        instance.receiver_startup_duration
    ]

    # TODO alternately just check if the test passed, if it did there should be
    #      timings if not is it worth alerting?
    # remove None values
    alertable_timings = [d for d in alertable_timings if d]

    threshold = get_preference('citrusborgux__ux_alert_threshold')
    if any(timing > threshold for timing in alertable_timings):
        LOG.info('Slowdown on %s', instance.source_host.host_name)
        raise_citrix_slow_alert.delay(instance.id, threshold.total_seconds())
Esempio n. 28
0
def raise_failed_event_by_mail(event_pk):
    """
    send an alert email for failed events

    :arg int event_pk:

        the primary key of the :class:`mail_collector.models.MailBotLogEvent`
        instance with the failed event

    :returns: the result of the email operation
    :rtype: str

    :raises: :exc:`Exception` if an error is thrown by the email send op

    """
    data = models.MailBotLogEvent.objects.filter(pk=event_pk)
    subscription = base_utils.get_subscription('Exchange Client Error')

    # let's cache some data to avoid evaluating the queryset multiple times
    data_extract = data.values(
        'uuid', 'event_type',
        'source_host__site__site', 'source_host__host_name')[0]

    try:
        ret = base_utils.borgs_are_hailing(
            data=data, subscription=subscription, logger=LOGGER,
            level=get_preference('exchange__server_error'),
            event_type=data_extract.get('event_type'),
            site=data_extract.get('source_host__site__site'),
            bot=data_extract.get('source_host__host_name'))
    except Exception as error:
        raise error

    if ret:
        return 'raised email alert for event %s' % str(
            data_extract.get('uuid'))

    return 'could not raise email alert for event %s' % str(
        data_extract.get('uuid'))
Esempio n. 29
0
def email_dead_borgs_report(now=None, send_no_news=False, **dead_for):
    """
    generate and email reports about `Citrix` monitoring bots that have not
    been seen within the time interval defined by arguments `now` and
    `dead_for` via email

    This task is almost identical to :func:`email_dead_borgs_alert` with the
    exception of the default value for the :class:`datetime.timedelta` object
    created when `dead_for` is not present. This value is picked from dynamic
    preference `Reporting period for dead nodes
    <../../../admin/dynamic_preferences/globalpreferencemodel/"""\
            """?q=node_forgotten_after>`__.

    This task used the subscription at `Dead Citrix monitoring bots
    <../../../admin/p_soc_auto_base/subscription/"""\
    """?q=Dead+Citrix+monitoring+bots>`__ to render the emails being sent.
    """
    now = base_utils.MomentOfTime.now(now)

    if not dead_for:
        time_delta = get_preference('citrusborgnode__node_forgotten_after')
    else:
        time_delta = base_utils.MomentOfTime.time_delta(**dead_for)

    data = get_dead_bots(now=now, time_delta=time_delta)
    if not data and send_no_news:
        return (
            'all monitoring bots were active between'
            ' {:%a %b %d, %Y %H:%M %Z} and {:%a %b %d, %Y %H:%M %Z}'.
            format(timezone.localtime(value=now),
                   timezone.localtime(now - time_delta))
        )

    return Email.send_email(
        data=data,
        subscription=Subscription.get_subscription(
            'Dead Citrix monitoring bots'),
        time_delta=time_delta)
def maintain_ad_orion_nodes():
    """
    synchronize :class:`ldap_probe.models.OrionADNode` with
    :class:`orion_integration.models.OrionDomainControllerNode`

    This is needed because `AD` `Orion` nodes may change outside this
    application
    """
    known_nodes_model = apps.get_model('ldap_probe.orionadnode')
    new_nodes_model = apps.get_model(
        'orion_integration.oriondomaincontrollernode')

    known_node_ids = known_nodes_model.objects.values_list(
        'node_id', flat=True)

    new_nodes = new_nodes_model.objects.exclude(id__in=known_node_ids)

    if not new_nodes.exists():
        LOG.debug('did not find any unknown AD nodes in Orion')
        return

    service_user = get_or_create_user(
        name=get_preference('ldapprobe__service_user'))
    ldap_bind_cred = apps.get_model('ldap_probe.ldapbindcred').default()

    for node in new_nodes:
        new_ad_orion_node = known_nodes_model(
            node=node, ldap_bind_cred=ldap_bind_cred,
            created_by=service_user, updated_by=service_user)
        try:
            new_ad_orion_node.save()
        except Exception as error:
            LOG.exception(error)
            raise error

    LOG.info('created %s AD nodes from Orion', new_nodes.count())