Skip to content

Commit e4c3a0d

Browse files
authored
Merge pull request #275 from networktocode/release/2.5.0
Release v2.5.0
2 parents baba76e + 37c396c commit e4c3a0d

13 files changed

+266
-33
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## v.2.5.0 - 2024-03-13
4+
5+
### Added
6+
7+
- [#274](https://github.com/networktocode/circuit-maintenance-parser/pull/274) - Add Global Cloud XChange Parser
8+
39
## v2.4.0 - 2024-02-20
410

511
### Added

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ By default, there is a `GenericProvider` that supports a `SimpleProcessor` using
7575
- Equinix
7676
- EXA (formerly GTT)
7777
- HGC
78+
- Global Cloud Xchange
7879
- Google
7980
- Lumen
8081
- Megaport

circuit_maintenance_parser/__init__.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
"""Circuit-maintenance-parser init."""
2-
from typing import Type, Optional
2+
3+
from typing import Optional, Type
34

45
from .data import NotificationData
5-
from .output import Maintenance
66
from .errors import NonexistentProviderError, ProviderError
7+
from .output import Maintenance
78
from .provider import (
8-
GenericProvider,
9-
AquaComms,
10-
Arelion,
119
AWS,
1210
BSO,
11+
GTT,
12+
HGC,
13+
NTT,
14+
AquaComms,
15+
Arelion,
1316
Cogent,
1417
Colt,
1518
CrownCastle,
1619
Equinix,
1720
EUNetworks,
18-
GTT,
21+
GenericProvider,
22+
GlobalCloudXchange,
1923
Google,
20-
HGC,
2124
Lumen,
2225
Megaport,
2326
Momentum,
2427
Netflix,
25-
NTT,
2628
PacketFabric,
2729
Seaborn,
2830
Sparkle,
@@ -44,6 +46,7 @@
4446
CrownCastle,
4547
Equinix,
4648
EUNetworks,
49+
GlobalCloudXchange,
4750
Google,
4851
GTT,
4952
HGC,
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Circuit Maintenance Parser for Equinix Email Notifications."""
2+
3+
import re
4+
from datetime import datetime
5+
from typing import Any, Dict, List
6+
7+
from bs4.element import ResultSet # type: ignore
8+
9+
from circuit_maintenance_parser.output import Impact
10+
from circuit_maintenance_parser.parser import EmailSubjectParser, Html, Status
11+
12+
13+
class HtmlParserGcx1(Html):
14+
"""Custom Parser for HTML portion of Global Cloud Xchange circuit maintenance notifications."""
15+
16+
def parse_html(self, soup: ResultSet) -> List[Dict]:
17+
"""Parse an Global Cloud Xchange circuit maintenance email.
18+
19+
Args:
20+
soup (ResultSet): beautiful soup object containing the html portion of an email.
21+
22+
Returns:
23+
Dict: The data dict containing circuit maintenance data.
24+
"""
25+
data: Dict[str, Any] = {"circuits": []}
26+
27+
for div in soup.find_all("div"):
28+
for pstring in div.strings:
29+
search = re.search("Dear (.*),", pstring)
30+
if search:
31+
data["account"] = search.group(1)
32+
33+
# Find Circuits
34+
for table in soup.find_all("table"):
35+
for row in table.find_all("tr"):
36+
cols = row.find_all("td")
37+
if len(cols) == 2 and "Service ID" not in cols[0].text:
38+
impact = Impact.OUTAGE
39+
if "at risk" in cols[1].text.lower():
40+
impact = Impact.REDUCED_REDUNDANCY
41+
42+
data["circuits"].append({"circuit_id": cols[0].text, "impact": impact})
43+
44+
return [data]
45+
46+
47+
class SubjectParserGcx1(EmailSubjectParser):
48+
"""Parse the subject of a Global Cloud Xchange circuit maintenance email. The subject contains the maintenance ID and status."""
49+
50+
def parse_subject(self, subject: str) -> List[Dict]:
51+
"""Parse the Global Cloud Xchange Email subject for summary and status.
52+
53+
Args:
54+
subject (str): subject of email
55+
e.g. 'PE2024020844407 | Emergency | Service Advisory Notice | Span Loss Rectification | 12-Feb-2024 09:00 (GMT) - 12-Feb-2024 17:00 (GMT)'.
56+
57+
58+
Returns:
59+
List[Dict]: Returns the data object with summary and status fields.
60+
"""
61+
data = {}
62+
search = re.search(
63+
r"^([A-Z0-9]+) \| (\w+) \| ([\w\s]+) \| ([\w\s]+) \| (\d+-[A-Za-z]{3}-\d{4} \d{2}:\d{2}) \(GMT\) - (\d+-[A-Za-z]{3}-\d{4} \d{2}:\d{2}) \(GMT\)$",
64+
subject,
65+
)
66+
if search:
67+
data["maintenance_id"] = search.group(1)
68+
date_format = date_format = "%d-%b-%Y %H:%M"
69+
data["start"] = self.dt2ts(datetime.strptime(search.group(5), date_format))
70+
data["end"] = self.dt2ts(datetime.strptime(search.group(6), date_format))
71+
data["summary"] = search.group(4)
72+
73+
if "completed" in subject.lower():
74+
data["status"] = Status.COMPLETED
75+
elif "rescheduled" in subject.lower():
76+
data["status"] = Status.RE_SCHEDULED
77+
elif "scheduled" in subject.lower() or "reminder" in subject.lower() or "notice" in subject.lower():
78+
data["status"] = Status.CONFIRMED
79+
elif "cancelled" in subject.lower():
80+
data["status"] = Status.CANCELLED
81+
else:
82+
# Some Global Cloud Xchange notifications don't clearly state a status in their subject.
83+
# From inspection of examples, it looks like "Confirmed" would be the most appropriate in this case.
84+
data["status"] = Status.CONFIRMED
85+
86+
return [data]

circuit_maintenance_parser/provider.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,35 @@
11
"""Definition of Provider class as the entry point to the library."""
2+
23
import logging
34
import os
45
import re
56
import traceback
7+
from typing import Dict, Iterable, List
68

7-
from typing import Iterable, List, Dict
89
import chardet
9-
1010
from pydantic import BaseModel, PrivateAttr
1111

12-
from circuit_maintenance_parser.utils import rgetattr
13-
14-
from circuit_maintenance_parser.output import Maintenance
12+
from circuit_maintenance_parser.constants import EMAIL_HEADER_SUBJECT
1513
from circuit_maintenance_parser.data import NotificationData
16-
from circuit_maintenance_parser.parser import ICal, EmailDateParser
1714
from circuit_maintenance_parser.errors import ProcessorError, ProviderError
18-
from circuit_maintenance_parser.processor import CombinedProcessor, SimpleProcessor, GenericProcessor
19-
from circuit_maintenance_parser.constants import EMAIL_HEADER_SUBJECT
20-
15+
from circuit_maintenance_parser.output import Maintenance
16+
from circuit_maintenance_parser.parser import EmailDateParser, ICal
2117
from circuit_maintenance_parser.parsers.aquacomms import HtmlParserAquaComms1, SubjectParserAquaComms1
2218
from circuit_maintenance_parser.parsers.aws import SubjectParserAWS1, TextParserAWS1
2319
from circuit_maintenance_parser.parsers.bso import HtmlParserBSO1
24-
from circuit_maintenance_parser.parsers.cogent import HtmlParserCogent1, TextParserCogent1, SubjectParserCogent1
20+
from circuit_maintenance_parser.parsers.cogent import HtmlParserCogent1, SubjectParserCogent1, TextParserCogent1
2521
from circuit_maintenance_parser.parsers.colt import CsvParserColt1, SubjectParserColt1, SubjectParserColt2
2622
from circuit_maintenance_parser.parsers.crowncastle import HtmlParserCrownCastle1
2723
from circuit_maintenance_parser.parsers.equinix import HtmlParserEquinix, SubjectParserEquinix
28-
from circuit_maintenance_parser.parsers.gtt import HtmlParserGTT1
24+
from circuit_maintenance_parser.parsers.globalcloudxchange import HtmlParserGcx1, SubjectParserGcx1
2925
from circuit_maintenance_parser.parsers.google import HtmlParserGoogle1
26+
from circuit_maintenance_parser.parsers.gtt import HtmlParserGTT1
3027
from circuit_maintenance_parser.parsers.hgc import HtmlParserHGC1, HtmlParserHGC2, SubjectParserHGC1
3128
from circuit_maintenance_parser.parsers.lumen import HtmlParserLumen1
3229
from circuit_maintenance_parser.parsers.megaport import HtmlParserMegaport1
3330
from circuit_maintenance_parser.parsers.momentum import HtmlParserMomentum1, SubjectParserMomentum1
3431
from circuit_maintenance_parser.parsers.netflix import TextParserNetflix1
32+
from circuit_maintenance_parser.parsers.openai import OpenAIParser
3533
from circuit_maintenance_parser.parsers.seaborn import (
3634
HtmlParserSeaborn1,
3735
HtmlParserSeaborn2,
@@ -43,7 +41,8 @@
4341
from circuit_maintenance_parser.parsers.turkcell import HtmlParserTurkcell1
4442
from circuit_maintenance_parser.parsers.verizon import HtmlParserVerizon1
4543
from circuit_maintenance_parser.parsers.zayo import HtmlParserZayo1, SubjectParserZayo1
46-
from circuit_maintenance_parser.parsers.openai import OpenAIParser
44+
from circuit_maintenance_parser.processor import CombinedProcessor, GenericProcessor, SimpleProcessor
45+
from circuit_maintenance_parser.utils import rgetattr
4746

4847
logger = logging.getLogger(__name__)
4948

@@ -282,6 +281,17 @@ class EUNetworks(GenericProvider):
282281
_default_organizer = "noc@eunetworks.com"
283282

284283

284+
class GlobalCloudXchange(GenericProvider):
285+
"""Global Cloud Xchange provider custom class."""
286+
287+
_processors: List[GenericProcessor] = PrivateAttr(
288+
[
289+
CombinedProcessor(data_parsers=[EmailDateParser, SubjectParserGcx1, HtmlParserGcx1]),
290+
]
291+
)
292+
_default_organizer = PrivateAttr("Gnoc@globalcloudxchange.com")
293+
294+
285295
class Google(GenericProvider):
286296
"""Google provider custom class."""
287297

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "circuit-maintenance-parser"
3-
version = "2.4.0"
3+
version = "2.5.0"
44
description = "Python library to parse Circuit Maintenance notifications and return a structured data back"
55
authors = ["Network to Code <opensource@networktocode.com>"]
66
license = "Apache-2.0"
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
MIME-Version: 1.0
2+
From: Gnoc@globalcloudxchange.com
3+
To: email@examplecompany.com
4+
Reply-To: change@gcxworld.com
5+
Date: 8 Feb 2024 17:09:33 +0000
6+
Subject: PE2024020844407 | Emergency | Service Advisory Notice |
7+
Span Loss Rectification | 12-Feb-2024 09:00 (GMT) - 12-Feb-2024 17:00 (GMT)
8+
Content-Type: text/html; charset="UTF-8"
9+
Content-Transfer-Encoding: quoted-printable
10+
11+
12+
13+
<div style=3D"color:Black; font-size:11pt; font-family:Calibri; width:100px=
14+
;"><html><head></head><body><div style=3D"margin-top:20px; margin-left:5px;=
15+
margin-bottom:15px; font-family:calibri;width: 900px;"> =20
16+
Dear Example Company INC, <br/> <br/>
17+
Our provider will be carrying an emergency activity for span loss im=
18+
provement work on old and new fibers between Cairo --Suez on HAWK Egypt bac=
19+
khaul north route.
20+
<br/>
21+
<br/>Impact: At risk
22+
<br/>
23+
<br/>The following schedule is provided as a guide, which is subject to cha=
24+
nge depending on conditions encountered during the activity: <br/><br/></d=
25+
iv><div style=3D"margin-left:50px; font-family:Calibri;width: 900px;"><tabl=
26+
e cellpadding=3D2 cellspacing=3D2 border=3D solid black 2px><tr bgcolor=3D#=
27+
4b6c9e><td align=3Dcenter><font face=3D"calibri" color=3DWhite><b>Window</b=
28+
></font></td><td align=3Dcenter><font face=3D"calibri" color=3DWhite><b>Pri=
29+
mary Start Date (GMT) </b></font></td><td align=3Dcenter><font face=3D"cali=
30+
bri" color=3DWhite><b>Primary End Date (GMT) </b></font></td><td align=3Dce=
31+
nter><font face=3D"calibri" color=3DWhite><b>Backup Start Date (GMT) </b></=
32+
font></td><td align=3Dcenter><font face=3D"calibri" color=3DWhite><b>Backup=
33+
End Date (GMT) </b></font></td></tr><tr bgcolor=3D#EEEEF4><td align=3Dcent=
34+
er><font face=3D"calibri">1</font></td><td align=3Dcenter><font face=3D"cal=
35+
ibri">12-Feb-2024 09:00</font></td><td align=3Dcenter><font face=3D"calibri=
36+
">12-Feb-2024 17:00</font></td><td align=3Dcenter><font face=3D"calibri">NA=
37+
</font></td><td align=3Dcenter><font face=3D"calibri">NA</font></td></tr></=
38+
table></div><br/><br/><div style=3D"margin-left:50px; font-family:Calibri;w=
39+
idth: 700px;"><table cellpadding=3D2 cellspacing=3D2 border=3D solid black =
40+
2px><tr bgcolor=3D#4b6c9e><td align=3Dcenter><font face=3D"calibri" color=
41+
=3DWhite><b>Service ID</b></font></td><td align=3Dcenter><font face=3D"cali=
42+
bri" color=3DWhite><b>Impact</b></font></td></tr><tr bgcolor=3D#EEEEF4><td =
43+
align=3Dcenter><font face=3D"calibri">RGWLS31171</font></td><td align=3Dcen=
44+
ter><font face=3D"calibri">At Risk</font></td></tr></table></div><div style=
45+
=3D"margin-top:20px; margin-left:5px; margin-bottom:15px;font-family:calibr=
46+
i;width: 700px;"> We hope that you will accept our apology for any inconven=
47+
ience this work may cause you and your customers.<br/><br/>
48+
Please contact the Global Cloud Xchange GNOC on +44(0) 208 282 1599/=
49+
change@gcxworld.com should you require any additional information.<br/><br=
50+
/>
51+
=09
52+
Regards<br/>Pradnya V Kokane<br/>Change Management, Global Network O=
53+
perations Center<br/>D: +91 22 303 86148 <br/>M: +91 7977316326<br/>PVKoka=
54+
ne@gcxworld.com <br/>
55+
<img src=3D"https://nims.gcxworld.com/nims/Presentation/images/NewLo=
56+
go_BlackText.png" width=3D"117" height=3D"35" border=3D"0" alt=3D""><br/>
57+
<a href=3D"https://www.linkedin.com/company/gcxworld">LinkedIn</a> |=
58+
<a href=3D"https://www.facebook.com/globalcloudxchange">Facebook</a> | <a =
59+
href=3D"http://twitter.com/globalcloudx">Twitter</a> | <a href=3D"https://p=
60+
lus.google.com/+Globalcloudxchange">Google+ </a><br/>
61+
</div> </body></html></div>
62+
63+
<p></p>
64+
65+
-- <br />
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[
2+
{
3+
"account": "Example Company INC",
4+
"circuits": [
5+
{
6+
"circuit_id": "RGWLS31171",
7+
"impact": "REDUCED-REDUNDANCY"
8+
}
9+
]
10+
}
11+
]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[
2+
{
3+
"account": "Example Company INC",
4+
"circuits": [
5+
{
6+
"circuit_id": "RGWLS31171",
7+
"impact": "REDUCED-REDUNDANCY"
8+
}
9+
],
10+
"end": 1707757200,
11+
"maintenance_id": "PE2024020844407",
12+
"stamp": 1707412173,
13+
"start": 1707728400,
14+
"status": "CONFIRMED",
15+
"summary": "Span Loss Rectification"
16+
}
17+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PE2024020844407 | Emergency | Service Advisory Notice | Span Loss Rectification | 12-Feb-2024 09:00 (GMT) - 12-Feb-2024 17:00 (GMT)

0 commit comments

Comments
 (0)