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)
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
{ "$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)
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)
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)
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)
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
DTNx & (Infinera) Fiberlink
- class dashboard.correlation.endpoints.infinera.InfineraEndpoint(trap=None, cached_params=None)
Bases:
Endpoint- FLOOD_SLACK_TIME = 180
- LOCAL = 'LOCAL_SNC'
- REMOTE = 'REMOTE_SNC'
- carries(other)
check if this endpoint carries (directly) the other endpoint … only InfineraEndpoint’s and 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)
check if the other endpoint has the same dna correlation id :param other: :return: True if node_id & correlation_id are the same
- is_local()
- is_remote()
- make_event(trap)
create an InfineraEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a InfineraEndpointEvent
- 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.fiberlink.FiberlinkEndpoint(trap=None, cached_params=None)
Bases:
Endpoint- carries(other)
check if this endpoint carries (directly) the other endpoint … only InfineraEndpoints and Coriant Endpoints 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)
check if this endpoint is of the same type as the other endpoint, and is part of the same circuit :param other: :return:
- locations_from_trap(trap)
This is the only endpoint that overrides this method.
TODO: consolidate the formats in theh inventory provider (and use only the base class method)
‘ends’ is expected to look like this:
"ends": { "a": { "equipment": "LUG-OLA1", "pop": "LUG-OLA", "pop_abbreviation": "lug" }, "b": { "equipment": "MIL01-DTNX4-1", "pop": "Milan 1 Lancetti", "pop_abbreviation": "mil1" } }
- Parameters:
trap – a classified trap dict
- Returns:
iterable yielding all locations from this trap
- make_event(trap)
create an InfineraEndpointEvent containing the data we need from this trap to process flapping, etc. :param trap: a normal trap dict :return: a InfineraEndpointEvent
- static match_trap_type(trap)
check if this trap is a fiberlink up/down trap :param trap: a trap dict :return: true iff the trap is a fiberlink 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
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)
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)
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