Correlation Endpoints

An Endpoint is an individually identifiable entity that can have an up or down state. For example, a physical or logical Juniper port, bgp peering session, etc.

Base Class

dashboard.correlation.endpoints.ENDPOINTS = {}

This dictionary contains all endpoints currently being tracked by the system. The keys are computed by calling endpoint_name_from_trap().

class dashboard.correlation.endpoints.endpoint.Endpoint(trap=None, cached_params=None)
CACHED_EVENT_HISTORY_TIME = 300.0
property alarm
property all_services
abstractmethod carries(other)

check if this endpoint carries (directly) the other endpoint :param other: :return: True if this endpoint carries other

static collect_services(endpoints)
static contacts_from_trap(trap)
dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

find_subordinate_alarms()

find all other alarms containing an endpoint that is carried (next level) by this one, or is correlated (at the same level) :return: all such alarms

find_superior_alarm()

find any other alarm containing an endpoint that is either correlated (same level) or a next-level carrier :return: the first eligible alarm found containing such an endpoint

classmethod from_cache(cached_params)
Parameters:

cached_params

Returns:

classmethod from_trap(trap)
Parameters:

trap – a normal trap dict

Returns:

abstractmethod generate_placeholder_event(down)
handle_state_update(update_info)

called when a state checker update for this endpoint is received :param update_info: dict received from the state checker :return:

handle_trap(trap)
handle_updated_state_change(event)

Handle a discovered state change. Should only be called from state_check_handler.

Parameters:

event – event with the new state

Returns:

static has_overlapping_services(a, b)
initialize_event_history(trap)
initialize_event_history_from_cache(event_uuids)
abstractmethod is_correlated(other)

check if this endpoint is of the same type as the other endpoint, and is part of the same circuit :param other: :return:

property is_down
property is_initializing
is_subordinate_endpoint(other)
is_superior_endpoint(other)
property is_up
locations_from_trap(trap)

Extracts & returns a list(iterable) of location dicts from the trap.

Note: Could be static, but is overridden in fiberlink.py, since the inventory provider returns the same format for all routes except that one.

‘locations’ is expected to look like this:

"locations": [
    {
        "a": {
            "abbreviation": "par",
            "equipment": "mx1.par.fr.geant.net",
            "name": "Paris"
        },
        "b": {
            "abbreviation": "par",
            "equipment": "mx1.par.fr.geant.net",
            "name": "Paris"
        }
    }
]

(cf. LOCATIONS_LIST_SCHEMA)

Parameters:

trap – a classified trap dict

Returns:

iterable yielding all locations from this trap, each is a dict with keys ‘site’ and ‘equipment’

abstractmethod make_event(trap)

create an EndpointEvent containing the data we need from this trap to process flapping, etc.

child classes must construct a concrete subclass instance of EndpointEvent instance and return it

Parameters:

trap – a normal trap dict

Returns:

concrete EndpointEvent subclass instance

static match_trap_type(trap)
static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint

property non_operational_services
property operational_services
static projects_from_trap(trap)
release_all()

leaves this object in a corrupt state :return:

save_if_dirty(session)
services_from_trap(trap)

return all services & related services

Parameters:

trap – trap dict

Returns:

iterable of dicts conforming to

SERVICE_LIST_SCHEMA
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "definitions": {
    "service": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "circuit_type": {
          "type": "string"
        },
        "service_type": {
          "type": "string"
        },
        "status": {
          "type": "string"
        },
        "project": {
          "type": "string"
        },
        "sid": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "service_type",
        "status"
      ]
    }
  },
  "type": "array",
  "items": {
    "$ref": "#/definitions/service"
  }
}
set_alarm(a, session)

setter helper, more efficient when using for lots of endpoints (e.g. when devouring or loading cache) :param a: :param session: :return:

static sort_services(services)

sorts the list of services into ‘operational’ and ‘non-operational’

the input collection must contain dicts with the structure:

{‘status’: str (e.g. ‘operational’, ‘name’: str}

Parameters:

services – list of dicts

Returns:

dict with keys ‘operational’, ‘non-operational’, values are lists of service names

sync_db_events(session, alarm_changed=False)
check/fix/update flap records in the db
  • split event history into buckets

  • get id from first bucket event (or create a new row)

  • if id of subsequent events differs or is None, this means that some new traps/events have arrived, or maybe traps arrived out-of-order and have moved between buckets

Juniper

class dashboard.correlation.endpoints.link.LinkEndpoint(trap=None, cached_params=None)

Bases: Endpoint

carries(other)

check if this endpoint carries (directly) the other endpoint :param other: :return: True if this endpoint carries other

dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

generate_placeholder_event(down)
is_correlated(other)

check if this endpoint is of the same type as the other endpoint, and is part of the same circuit :param other: :return:

make_event(trap)

create a LinkEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a LinkEndpointEvent

static match_trap_type(trap)

check if this trap is link interface up/down trap :param trap: a trap dict :return: true iff the trap is a link up/down trap

static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint

class dashboard.correlation.endpoints.bgp_peering.BGPPeeringEndpoint(trap=None, cached_params=None)

Bases: Endpoint

carries(other)

BGP peering endpoints don’t carry other endpoints :param other: :return: always returns False

dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

find_subordinate_alarms()

find all other alarms containing an endpoint that is carried (next level) by this one, or is correlated (at the same level) :return: all such alarms

generate_placeholder_event(down)
is_correlated(other)

check the other endpoint is:

  • peered with the same address as this one

  • shares some services

  • is a related iBGP endpoint

… always False unless other is a BGPPeeringEndpoint :param other: :return: True/False based on the above checks

make_event(trap)

create a BGPEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a BGPEndpointEvent

static match_trap_type(trap)

check if this trap is a BGP Peering trap (i.e. a bgp trap but not an ix or vpnrr peering interface) :param trap: a trap dict :return: true iff the trap is a BGP Peering trap

static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint

services_from_trap(trap)
must return an Iterable of dicts like:

{‘status’: str (e.g. ‘operational’, ‘name’: str}

Parameters:

trap – trap dict

Returns:

iterable of dicts

class dashboard.correlation.endpoints.bgp_ix.BGPIXEndpoint(trap=None, cached_params=None)

Bases: Endpoint

carries(other)

BGP IX peering endpoints don’t carry other endpoints :param other: :return: always returns False

dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

find_subordinate_alarms()

find all other alarms containing an endpoint that is carried (next level) by this one, or is correlated (at the same level) :return: all such alarms

generate_placeholder_event(down)
is_correlated(other)

Check the other endpoint peer is in this endpoint’s router or peer group.

Parameters:

other

Returns:

True iff the other endpoint is also BGP IX and has a peer in the same router/peer group

make_event(trap)

create a BGPEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a BGPEndpointEvent

static match_trap_type(trap)

check if this trap is from a BGP IX public peering interface :param trap: a trap dict :return: true iff the trap is a BGP Peering trap

static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint

class dashboard.correlation.endpoints.vpn_rr.VPNRREndpoint(trap=None, cached_params=None)

Bases: Endpoint

carries(other)

BGP VPN RR peering endpoints don’t carry other endpoints.

Parameters:

other

Returns:

always returns False

dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

find_subordinate_alarms()

find all other alarms containing an endpoint that is carried (next level) by this one, or is correlated (at the same level) :return: all such alarms

generate_placeholder_event(down)
is_correlated(other)

Check the other endpoint peer is peered with the same address.

Parameters:

other

Returns:

True iff the other endpoint is also BGP VPN RR with the same remote peer address

make_event(trap)

create a BGPEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a BGPEndpointEvent

static match_trap_type(trap)

check if this trap is a VPN RR Peering trap :param trap: a trap dict :return: true iff the trap is a BGP Peering trap

static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint

Coriant

class dashboard.correlation.endpoints.coriant.CoriantEndpoint(trap=None, cached_params=None)

Bases: Endpoint

carries(other)

decide if this endpoint is a carrier of the other endpoint note: only link endpoints are eligible :param other: :return:

dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

generate_placeholder_event(down)
is_correlated(other)

check if the other Coriant Endpoint path shares an endpoint with this Endpoint

this method should always be idempotent

Parameters:

other

Returns:

make_event(trap)

create a CoriantEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a CoriantEndpointEvent

static match_trap_type(trap)

check if this trap is link interface up/down trap :param trap: a trap dict :return: true iff the trap is a link up/down trap

static name_from_transcend_alarm(alarm)

generate a name from an alarm retrieved from tanscend (tnms) that should match the name_from_trap :param alarm: a transcend alarm dict :return: an endpoint name

static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint

MTC

class dashboard.correlation.endpoints.mtc.MTCEndpoint(trap=None, cached_params=None)

Bases: Endpoint

LOCAL = 'LOCAL_OPTICAL_SNC'
REMOTE = 'REMOTE_OPTICAL_SNC'
carries(other)

check if this endpoint carries (directly) the other endpoint … only LinkEndpoints are supported :param other: :return: True if this endpoint carries other

dumpd()

create a json-serializable dict that can be used to re-create this object :return: a json-serializable dict

generate_placeholder_event(down)
is_correlated(other)

check if the other endpoint is an MTCEndpoint and shares services Coriant endpoints can also correlate if they share services :param other: :return: True if there are overlapping services

is_local()
is_remote()
make_event(trap)

create an MTCEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a MTCEndpointEvent

static match_trap_type(trap)

check if this trap is link interface up/down trap :param trap: a trap dict :return: true iff the trap is a link up/down trap

static name_from_transcend_alarm(alarm)

generate a name from an alarm retrieved from tanscend (tnms) that should match the name_from_trap :param alarm: a transcend alarm dict :return: an endpoint name

static name_from_trap(trap)

returns a key that defines whether a trap applies to a particular endpoint

every subclass needs to re-implement this static method

Parameters:

trap – trap dict

Returns:

string used to uniquely identify a particular endpoint