circuit-maintenance-parser
is a Python library that parses circuit maintenance notifications from Network Service Providers (NSPs), converting heterogeneous formats to a well-defined structured format.
Every network depends on external circuits provided by NSPs who interconnect them to the Internet, to office branches or to external service providers such as Public Clouds.
Obviously, these services occasionally require operation windows to upgrade or to fix related issues, and usually they happen in the form of circuit maintenance periods. NSPs generally notify customers of these upcoming events so that customers can take actions to minimize the impact on the regular usage of the related circuits.
The challenge faced by many customers is that mostly every NSP defines its own maintenance notification format, even though in the end the relevant information is mostly the same across NSPs. This library is built to parse notification formats from several providers and to return always the same object struct that will make it easier to process them afterwards.
The format of this output is following the BCOP defined during a NANOG meeting that aimed to promote the usage of the iCalendar format. Indeed, if the NSP is using the proposed iCalendar format, the parser is straight-forward and there is no need to define custom logic, but this library enables supporting other providers that are not using this proposed practice, getting the same outcome.
You can leverage on this library in your automation framework to process circuit maintenance notifications, and use the standarised output to handle your received circuit maintenance notifications in a simple way.
- We instantiate a
Provider
, directly or via theinit_provider
method, that depending on the selected type will return the corresponding instance. - Each
Provider
have already defined multipleProcessors
that will be used to get theMaintenances
when theProvider.get_maintenances(data)
method is called. - Each
Processor
class can have a pre defined logic to combine the data extracted from the notifications and create the finalMaintenance
object, and receives aList
of multipleParsers
that will be toparse
each type of data. - Each
Parser
class supports one or more data types and implements theParser.parse()
method used to retrieve aDict
with the relevant key/values. - When calling the
Provider.get_maintenances(data)
, thedata
argument is an instance ofNotificationData
(which is just a collection of multipleDataParts
, each one with atype
and acontent
) that will be used by the correspondingParser
when theProcessor
will try to match them.
By default, there is a GenericProvider
that support a SimpleProcessor
using the standard ICal
Parser
, being the easiest path to start using the library in case the provider uses the reference iCalendar standard.
- EuNetworks
- NTT
- PacketFabric
- Telia
- Telstra
- AquaComms
- Cogent
- Colt
- GTT
- HGC
- Lumen
- Megaport
- Momentum
- Seaborn
- Sparkle
- Telstra
- Turkcell
- Verizon
- Zayo
Note: Because these providers do not support the BCOP standard natively, maybe there are some gaps on the implemented parser that will be refined with new test cases. We encourage you to report related issues!
The library is available as a Python package in pypi and can be installed with pip:
pip install circuit-maintenance-parser
Please, refer to the BCOP to understand the meaning of the output attributes.
from circuit_maintenance_parser import init_provider, NotificationData
raw_data = b"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Maint Note//https://github.com/maint-notification//
BEGIN:VEVENT
SUMMARY:Maint Note Example
DTSTART;VALUE=DATE-TIME:20151010T080000Z
DTEND;VALUE=DATE-TIME:20151010T100000Z
DTSTAMP;VALUE=DATE-TIME:20151010T001000Z
UID:42
SEQUENCE:1
X-MAINTNOTE-PROVIDER:example.com
X-MAINTNOTE-ACCOUNT:137.035999173
X-MAINTNOTE-MAINTENANCE-ID:WorkOrder-31415
X-MAINTNOTE-IMPACT:OUTAGE
X-MAINTNOTE-OBJECT-ID;X-MAINTNOTE-OBJECT-IMPACT=NO-IMPACT:acme-widgets-as-a-service
X-MAINTNOTE-OBJECT-ID;X-MAINTNOTE-OBJECT-IMPACT=OUTAGE:acme-widgets-as-a-service-2
X-MAINTNOTE-STATUS:TENTATIVE
ORGANIZER;CN="Example NOC":mailto:noone@example.com
END:VEVENT
END:VCALENDAR
"""
ntt_provider = init_provider("ntt")
data_to_process = NotificationData.init_from_raw("ical", raw_data)
maintenances = ntt_provider.get_maintenances(data_to_process)
print(maintenances[0].to_json())
{
"account": "137.035999173",
"circuits": [
{
"circuit_id": "acme-widgets-as-a-service",
"impact": "NO-IMPACT"
},
{
"circuit_id": "acme-widgets-as-a-service-2",
"impact": "OUTAGE"
}
],
"end": 1444471200,
"maintenance_id": "WorkOrder-31415",
"organizer": "mailto:noone@example.com",
"provider": "example.com",
"sequence": 1,
"stamp": 1444435800,
"start": 1444464000,
"status": "TENTATIVE",
"summary": "Maint Note Example",
"uid": "42"
}
$ circuit-maintenance-parser --data-file tests/unit/data/ical/ical1 --data-type ical
Circuit Maintenance Notification #0
{
"account": "137.035999173",
"circuits": [
{
"circuit_id": "acme-widgets-as-a-service",
"impact": "NO-IMPACT"
}
],
"end": 1444471200,
"maintenance_id": "WorkOrder-31415",
"organizer": "mailto:noone@example.com",
"provider": "example.com",
"sequence": 1,
"stamp": 1444435800,
"start": 1444464000,
"status": "TENTATIVE",
"summary": "Maint Note Example",
"uid": "42"
}
$ circuit-maintenance-parser --data-file tests/unit/data/zayo/zayo1.html --data-type html --provider-type zayo
Circuit Maintenance Notification #0
{
"account": "clientX",
"circuits": [
{
"circuit_id": "/OGYX/000000/ /ZYO /",
"impact": "OUTAGE"
}
],
"end": 1601035200,
"maintenance_id": "TTN-00000000",
"organizer": "mr@zayo.com",
"provider": "zayo",
"sequence": 1,
"stamp": 1599436800,
"start": 1601017200,
"status": "CONFIRMED",
"summary": "Zayo will implement planned maintenance to troubleshoot and restore degraded span",
"uid": "0"
}
circuit-maintenance-parser --data-file "/tmp/___ZAYO TTN-00000000 Planned MAINTENANCE NOTIFICATION___.eml" --data-type email --provider-type zayo
Circuit Maintenance Notification #0
{
"account": "Linode",
"circuits": [
{
"circuit_id": "/OGYX/000000/ /ZYO /",
"impact": "OUTAGE"
}
],
"end": 1601035200,
"maintenance_id": "TTN-00000000",
"organizer": "mr@zayo.com",
"provider": "zayo",
"sequence": 1,
"stamp": 1599436800,
"start": 1601017200,
"status": "CONFIRMED",
"summary": "Zayo will implement planned maintenance to troubleshoot and restore degraded span",
"uid": "0"
}
Pull requests are welcomed and automatically built and tested against multiple versions of Python through Travis CI.
The project is following Network to Code software development guidelines and is leveraging:
- Black, Pylint, Mypy, Bandit and pydocstyle for Python linting and formatting.
- Unit and integration tests to ensure the library is working properly.
- Install
poetry
- Install dependencies and library locally:
poetry install
- Run CI tests locally:
invoke tests --local
- Define the
Parsers
(inheriting from some of the genericParsers
or a new one) that will extract the data from the notification, that could contain itself multipleDataParts
. Thedata_type
of theParser
and theDataPart
have to match. The customParsers
will be placed in theparsers
folder. - Update the
unit/test_parsers.py
with the new parsers, providing some data to test and validate the extracted data. - Define a new
Provider
inheriting from theGenericProvider
, defining theProcessors
and the respectiveParsers
to be used. Maybe you can reuse some of the genericProcessors
or maybe you will need to create a custom one. If this is the case, place it in theprocessors
folder. - Update the
unit/test_e2e.py
with the new provider, providing some data to test and validate the finalMaintenances
created. - Expose the new
Provider
class updating the mapSUPPORTED_PROVIDERS
incircuit_maintenance_parser/__init__.py
to officially expose theProvider
.
For any questions or comments, please check the FAQ first and feel free to swing by the Network to Code slack channel (channel #networktocode). Sign up here