Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Colt Parser #61

Merged
merged 15 commits into from
Sep 7, 2021
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- #59 - Added a new parser `EmailDateParser` that uses the temail `Date` to get the `Stamp` and use in most of the `Providers` via the `CombinedProcessor`. Also, `Maintenance.stamp` attribute is mandatory.
- #60 - Added new provider `Seaborn` using `Html` and a new parser for Email Subject: `EmailSubjectParser`
- #66 - Added new provider `Momentum` using `Html` and `EmailSubjectParser`
- #61 - Added new provider `Colt` using `ICal` and `Csv`

### Fixed

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ By default, there is a `GenericProvider` that support a `SimpleProcessor` using
#### Supported providers based on other parsers

- Cogent
- Colt
- GTT
- Lumen
- Megaport
Expand Down
2 changes: 2 additions & 0 deletions circuit_maintenance_parser/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .provider import (
GenericProvider,
Cogent,
Colt,
EUNetworks,
GTT,
Lumen,
Expand All @@ -25,6 +26,7 @@
SUPPORTED_PROVIDERS = (
GenericProvider,
Cogent,
Colt,
EUNetworks,
GTT,
Lumen,
Expand Down
26 changes: 26 additions & 0 deletions circuit_maintenance_parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,29 @@ def parse_subject(self, subject: str) -> List[Dict]:
def bytes_to_string(string):
"""Convert bytes variable to a string."""
return string.decode("utf-8")


class Csv(Parser):
"""Csv parser."""

_data_types = ["application/csv", "text/csv", "application/octet-stream"]

def parse(self, raw: bytes) -> List[Dict]:
"""Execute parsing."""
result = []

data_base: Dict[str, Union[int, str, Iterable]] = {}
try:
for data in self.parse_csv(raw, data_base):
result.append(data)
chadell marked this conversation as resolved.
Show resolved Hide resolved
logger.debug("Successful parsing for %s", self.__class__.__name__)

return result

except Exception as exc:
raise ParserError from exc

@staticmethod
def parse_csv(raw: bytes, data_base: Dict) -> List[Dict]:
"""Custom CSV parsing."""
raise NotImplementedError
92 changes: 92 additions & 0 deletions circuit_maintenance_parser/parsers/colt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Colt parser."""

import logging
import re
import csv
import io
import base64

from icalendar import Calendar # type: ignore

from circuit_maintenance_parser.parser import Csv
from circuit_maintenance_parser.errors import ParserError
from circuit_maintenance_parser.output import Status, Impact, CircuitImpact
from circuit_maintenance_parser.parser import ICal

logger = logging.getLogger(__name__)

# pylint: disable=too-many-branches


class ICalParserColt1(ICal):
"""Colt Notifications Parser based on ICal notifications."""

def parse(self, raw: bytes):
"""Method that returns a list of Maintenance objects."""
result = []

# iCalendar data sometimes comes encoded with base64
# TODO: add a test case
try:
gcal = Calendar.from_ical(base64.b64decode(raw))
except ValueError:
try:
gcal = Calendar.from_ical(raw)
except ValueError as exc:
raise ParserError from exc

if not gcal:
raise ParserError("Not a valid iCalendar data received")

try:
for component in gcal.walk():
if component.name == "VEVENT":
maintenance_id = ""
account = ""

summary_match = re.search(
r"^.*?[-]\s(?P<maintenance_id>CRQ[\S]+).*?,\s*(?P<account>\d+)$", str(component.get("SUMMARY"))
)
if summary_match:
maintenance_id = summary_match.group("maintenance_id")
account = summary_match.group("account")

data = {
"account": account,
"maintenance_id": maintenance_id,
"status": Status("CONFIRMED"),
"start": round(component.get("DTSTART").dt.timestamp()),
"end": round(component.get("DTEND").dt.timestamp()),
"stamp": round(component.get("DTSTAMP").dt.timestamp()),
"summary": str(component.get("SUMMARY")),
"sequence": int(component.get("SEQUENCE")),
}
result.append(data)

chadell marked this conversation as resolved.
Show resolved Hide resolved
except Exception as exc:
raise ParserError from exc

logger.debug("Successful parsing for %s", self.__class__.__name__)

return result


class CsvParserColt1(Csv):
"""Colt Notifications partial parser for circuit-ID's in CSV notifications."""

@staticmethod
def parse_csv(raw, data_base):
"""Execute parsing."""
data = data_base.copy()
data["circuits"] = []
try:
with io.StringIO(raw.decode("utf-16")) as csv_data:
parsed_csv = csv.DictReader(csv_data, dialect=csv.excel_tab)
for row in parsed_csv:
data["circuits"].append(
CircuitImpact(impact=Impact("OUTAGE"), circuit_id=row["Circuit ID"].strip())
)
return [data]

except Exception as exc:
raise ParserError from exc
10 changes: 10 additions & 0 deletions circuit_maintenance_parser/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from circuit_maintenance_parser.processor import CombinedProcessor, SimpleProcessor, GenericProcessor

from circuit_maintenance_parser.parsers.cogent import HtmlParserCogent1
from circuit_maintenance_parser.parsers.colt import ICalParserColt1, CsvParserColt1
from circuit_maintenance_parser.parsers.gtt import HtmlParserGTT1
from circuit_maintenance_parser.parsers.lumen import HtmlParserLumen1
from circuit_maintenance_parser.parsers.megaport import HtmlParserMegaport1
Expand Down Expand Up @@ -112,6 +113,15 @@ class Cogent(GenericProvider):
_default_organizer = "[email protected]"


class Colt(GenericProvider):
"""Cogent provider custom class."""

_processors: List[GenericProcessor] = [
CombinedProcessor(data_parsers=[ICalParserColt1, CsvParserColt1]),
]
_default_organizer = "[email protected]"


class EUNetworks(GenericProvider):
"""EUNetworks provider custom class."""

Expand Down
44 changes: 44 additions & 0 deletions tests/unit/data/colt/colt1
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
BEGIN:VCALENDAR
PRODID:-//Microsoft Corporation//Outlook 16.0 MIMEDIR//EN
VERSION:2.0
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:UTC
BEGIN:STANDARD
DTSTART:16011028T020000
TZOFFSETFROM:-0000
TZOFFSETTO:-0000
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CLASS:PUBLIC
CREATED:20210730T140308Z
DTEND;TZID=UTC:20210807T050000
DTSTAMP:20210730T140308Z
DTSTART;TZID=UTC:20210806T210000
LAST-MODIFIED:20210730T140308Z
ORGANIZER:[email protected]
LOCATION:Colt Internal Maintenance
PRIORITY:5
SEQUENCE:0
SUMMARY;LANGUAGE=en-us:Update: Colt Service Affecting Maintenance Notification - CRQ1-12345678 [06/8/2021 21:00:00 GMT - 07/8/2021 05:00:00 GMT] for ACME, 12345000
TRANSP:OPAQUE
UID:MS00NDE1Mjc5NDc3NTM4ODE4MTFJbXBhY3RlZA==
X-ALT-DESC;FMTTYPE=text/html:<html xmlns:v='urn:schemas-microsoft-com:vml' xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-mic rosoft-com:office:word' xmlns:m='http://schemas.microsoft.com/office/2004/12/omml' xmlns='http://www.w3.org/TR/REC-html40'><head><meta name=ProgId content=Word.Document><meta name=Generator content='Microsoft Word 15'><meta name=Originator content='Microsoft Word 15'><link rel=File-List href='cid:[email protected]'> </head> <body lang=EN-US link='#0563C1' vlink='#954F72' style='tab-interval:.5in'><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td align="center"><span style="font-size:12pt;font-family:'Calibri',sans-serif;color:#C00000;text-align:center"><strong>This is a system generated calendar invite. Accepting or Declining is meant only for the purpose of a Calendar display. The timing of the invite is set to the user’s local system time and should not to be confused with the text displayed withi
n the invite, which is in GMT. Should you require any assistance, please contact us via the Colt Online Portal <span style="color:#C00000"><a href="http://online.colt.net/" style="border-bottom: 1px solid #000;"><span lang="DE" style="color:#C00000;border-bottom: 1px solid #000;">http://online.colt.net</span></a></span> or alternatively mail us by replying to the notification</span></td></tr></table><p></p><p><strong><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><img border="0" id="_x0000_i1025" src="https://filestore.xmr3.com/763252/111359790/146229/185004/jobsettings/docs/logol_1429145502442.png" /></span></span></strong></p><p></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;"><strong>Planned Outage Notification</strong></span></span></span></p><p></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;">Dear Sir or Madam,</span></span></p><p></p><p><span styl
e="font-size: 10pt;"><span style="font-family: arial, sans-serif;">In order&nbsp;to maintain the highest levels of availability and service to our customers, it is sometimes necessary for Colt&nbsp;and our partners to perform network maintenance.&nbsp;&nbsp;We apologize for any resulting inconvenience and assure you of our efforts to minimise any service disruption. To view this, and all other planned maintenance on your services, or if you require any assistance, please contact us via the Colt Online Portal&nbsp;</span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 11pt;"><span style="font-size: 10pt;"><a href="http://online.colt.net">http://online.colt.net</a>. Alternatively, email us to&nbsp;</span><span style="font-size: 10pt;"><a href="mailto:[email protected]">[email protected]</a>,&nbsp;</span></span></span><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;">quoting the following reference number&nbsp;<strong>CRQ1
-12345678</strong>. Please retain this unique reference for the maintenance.</span></span></p><p></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;"><strong><u>Planned Works Details:</u></strong></span></span></span></p><p></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><strong>Planned Work (PW)Ref.:</strong>&nbsp;&nbsp; CRQ1-12345678</span></span><br /><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><strong>Start Date &amp; Time:</strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span></span>06/8/2021 21:00:00<span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;">(GMT)*</span></span><br /><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><strong>End Date &amp; Time:</strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span></span>07/8/2021 05:00:00<span style="font-size: 10pt;"><span
style="font-family: arial, sans-serif;">&nbsp;(GMT)*</span></span><br /><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><strong>Outage Duration:</strong>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; No Impact</span></span></p><p></p><p><strong><em><span style="background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"><span style="font-family: arial, sans-serif;"><span style="font-size: 9pt;">*Time Zone:</span></span></span></em></strong><br /><em><span style="background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"><span style="font-family: arial, sans-serif;"><span style="font-size: 9pt;">Central European Time (CET)&nbsp;&nbsp;= GMT + 1 hour</span></span></span></em><br /><e
m><span style="background-image: initial; background-position: initial; background-size: initial; background-repeat: initial; background-attachment: initial; background-origin: initial; background-clip: initial;"><span style="font-family: arial, sans-serif;"><span style="font-size: 9pt;"><em>Central European Summer Time (CEST) = GMT + 2&nbsp;hours</em></span></span></span></em></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><strong>Justification of the work:</strong>&nbsp;Kindly note the device on which your service is commissioned, will be upgraded at a later stage. Thus please take note that this maintenance for your service, in the attached CSV file, stands as cancelled. There are currently no new dates available. Once the new timings have been finalised, Colt will raise a new change ticket, and inform you about the work. We would like to apologise for any inconvenience this may have resulted in</span></span></p><p></p><p><span style="font-size
: 10pt;"><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;"><strong>Service:&nbsp;&nbsp;<span style="color: rgb(0, 51, 153);">***Please refer to the attached CSV file for your service(s) affected by this maintenance****</span></strong></span></span></span></p><p></p><p></p><p></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><strong>PLEASE NOTE:</strong>&nbsp;&nbsp;To enable you to plan appropriately the list of impacted services includes those that have been completed, as well as those pending completion.&nbsp;&nbsp;If the pending installation is completed prior to the scheduled date for the planned maintenance these services will be impacted.</span></span></p><p></p><p><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;">Please assist Colt by informing us about any changes to your contact details&nbsp;</span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;">via the
Colt Online Portal&nbsp;</span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 11pt;"><a href="http://online.colt.net"><span style="font-size: 10pt;">http://online.colt.net</span></a></span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;">&nbsp;or by replying to&nbsp;</span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 11pt;"><span style="font-size: 10pt;"><a href="mailto:[email protected]">[email protected]</a>&nbsp;</span></span></span><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;">so that we can ensure that future notifications reach the correct parties.</span></span><br /><br /><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;">Should you experience any issue with your service post the maintenance end time, please contact Colt Technical support via the Colt Online Portal&nbsp;</span></span><span style="font-family: arial,
sans-serif;"><span style="font-size: 11pt;"><a href="http://online.colt.net"><span style="font-size: 10pt;">http://online.colt.net</span></a></span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;">. Alternatively, visit&nbsp;<a href="http://www.colt.net/support">http://www.colt.net/support</a>&nbsp;to contact us by phone, quoting your service ID</span><span style="font-size: 11pt;">.</span><br /><br /><span style="font-size: 10pt;">For more information about a service, please consult&nbsp;</span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 10pt;">the Colt Online Portal&nbsp;</span></span><span style="font-family: arial, sans-serif;"><span style="font-size: 11pt;"><a href="http://online.colt.net"><span style="font-size: 10pt;">http://online.colt.net</span></a></span></span></p><p></p><p><br /><strong><span style="color: rgb(106, 106, 106);"><span style="font-family: arial, sans-serif;"><span style="font-size: 11pt;">
Colt Change management</span></span></span></strong><br /><strong><span style="color: rgb(106, 106, 106);"><span style="font-family: arial, sans-serif;"><span style="font-size: 11pt;"><strong>Colt Technology Services - Operations</strong></span></span></span></strong><br /><span style="font-size: 10pt;"><span style="font-family: arial, sans-serif;"><img border="0" id="_x0000_i1025" src="https://filestore.xmr3.com/763252/111359790/146229/185004/jobsettings/docs/logol_1429145502442.png" />&nbsp;</span></span><br /><span style="font-family: arial, sans-serif;"><span style="font-size: 9pt;">For support log into Colt Online:&nbsp;<span style="color: rgb(31, 73, 125);"><a href="https://online.colt.net">https://online.colt.net</a></span></span></span><br /><span style="font-family: arial, sans-serif;"><span style="font-size: 9pt;">For other contact options:&nbsp;<span style="color: rgb(31, 73, 125);"><a href="https://www.colt.net/support">https://www.colt.net/support</a></span></span></spa
n></p></body></html>
BEGIN:VALARM
TRIGGER:-PT15M
ACTION:DISPLAY
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR
12 changes: 12 additions & 0 deletions tests/unit/data/colt/colt1_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"account": "12345000",
"end": 1628312400,
"maintenance_id": "CRQ1-12345678",
"sequence": 0,
"stamp": 1627653788,
"start": 1628283600,
"status": "CONFIRMED",
"summary": "Update: Colt Service Affecting Maintenance Notification - CRQ1-12345678 [06/8/2021 21:00:00 GMT - 07/8/2021 05:00:00 GMT] for ACME, 12345000"
}
]
Binary file added tests/unit/data/colt/colt2.csv
Binary file not shown.
10 changes: 10 additions & 0 deletions tests/unit/data/colt/colt2_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[
{
"circuits": [
{
"impact": "OUTAGE",
"circuit_id": "C-1234567"
}
]
}
]
Loading