Skip to content

Commit 8ee467f

Browse files
Merge pull request #127 from networktocode/gfm-more-fixes
More fixes
2 parents 964e6f0 + 9a99617 commit 8ee467f

File tree

13 files changed

+729
-20
lines changed

13 files changed

+729
-20
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- #115 - Add default `status` and `sequence` values for iCal notifications missing these fields
88
- #124 - Handle encoded non-ASCII characters in email subjects.
99
- #126 - Ignore a class of non-maintenance-notification emails from Telia.
10+
- #127 - Improve handling of Equinix and Lumen notifications.
1011

1112
## v2.0.7 - 2021-12-01
1213

README.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,26 @@ during a NANOG meeting that aimed to promote the usage of the iCalendar format.
1919
proposed iCalendar format, the parser is straight-forward and there is no need to define custom logic, but this library
2020
enables supporting other providers that are not using this proposed practice, getting the same outcome.
2121

22-
You can leverage this library in your automation framework to process circuit maintenance notifications, and use the standardized [`Maintenance`](https://github.com/networktocode/circuit-maintenance-parser/blob/develop/circuit_maintenance_parser/output.py) to handle your received circuit maintenance notifications in a simple way. Every `maintenance` object contains, at least, the following attributes:
22+
You can leverage this library in your automation framework to process circuit maintenance notifications, and use the standardized [`Maintenance`](https://github.com/networktocode/circuit-maintenance-parser/blob/develop/circuit_maintenance_parser/output.py) model to handle your received circuit maintenance notifications in a simple way. Every `Maintenance` object contains the following attributes:
2323

2424
- **provider**: identifies the provider of the service that is the subject of the maintenance notification.
2525
- **account**: identifies an account associated with the service that is the subject of the maintenance notification.
26-
- **maintenance_id**: contains text that uniquely identifies the maintenance that is the subject of the notification.
26+
- **maintenance_id**: contains text that uniquely identifies (at least within the context of a specific provider) the maintenance that is the subject of the notification.
2727
- **circuits**: list of circuits affected by the maintenance notification and their specific impact.
28-
- **start**: timestamp that defines the start date of the maintenance in GMT.
29-
- **end**: timestamp that defines the end date of the maintenance in GMT.
30-
- **stamp**: timestamp that defines the update date of the maintenance in GMT.
28+
- **start**: timestamp that defines the starting date/time of the maintenance in GMT.
29+
- **end**: timestamp that defines the ending date/time of the maintenance in GMT.
30+
- **stamp**: timestamp that defines the update date/time of the maintenance in GMT.
3131
- **organizer**: defines the contact information included in the original notification.
32-
33-
and may additionally contain the following attributes:
34-
3532
- **status**: defines the overall status or confirmation for the maintenance.¹
36-
- **sequence**: a sequence number for notifications involving this maintenance window. In practice this is generally redundant with the **stamp** field, and will be defaulted to `1` for most non-iCal parsed notifications.²
37-
- **summary**: human-readable details about this maintenance notification.
38-
- **uid**: a unique (?) identifer for a thread of related notifications. In practice this is generally redundant with the **maintenance_id** field, and will be defaulted to `0` for most non-iCal parsed notifications.
33+
- **summary**: human-readable details about this maintenance notification. May be an empty string.
34+
- **sequence**: a sequence number for notifications involving this maintenance window. In practice this is generally redundant with the **stamp** field, and will be defaulted to `1` for most non-iCalendar parsed notifications.²
35+
- **uid**: a unique (?) identifer for a thread of related notifications. In practice this is generally redundant with the **maintenance_id** field, and will be defaulted to `0` for most non-iCalendar parsed notifications.
3936

40-
> Please, refer to the [BCOP](https://github.com/jda/maintnote-std/blob/master/standard.md) to more details about these attributes.
37+
> Please, refer to the [BCOP](https://github.com/jda/maintnote-std/blob/master/standard.md) to more details about the standardized meaning of these attributes.
4138
42-
¹ Per the BCOP, **status** (`X-MAINTNOTE_STATUS`) is an optional field in notifications. However, a `Maintenance` object will always contain a `status` value; in the case where the source notification omits this field, the `status` will be set to `"NO-CHANGE"`, and it's up to the consumer of this library to determine how to appropriately handle this case.
39+
¹ Per the BCOP, **status** (`X-MAINTNOTE_STATUS`) is an optional field in iCalendar notifications. However, a `Maintenance` object will always contain a `status` value; in the case where an iCalendar notification omits this field, the `status` will be set to `"NO-CHANGE"`, and it's up to the consumer of this library to determine how to appropriately handle this case. Parsers of other notification formats are responsible for setting an appropriate value for this field based on the notification contents, and may or may not include `"NO-CHANGE"` as one of the possible reported values.
4340

44-
² Per the BCOP, **sequence** is a mandatory field in notifications. However, some NSPs have been seen to send notifications which, while otherwise consistent with the BCOP, omit the `SEQUENCE` field; in such cases, this library will report a sequence number of `-1`.
41+
² Per the BCOP, **sequence** is a mandatory field in iCalendar notifications. However, some NSPs have been seen to send notifications which, while otherwise consistent with the BCOP, omit the `SEQUENCE` field; in such cases, this library will report a sequence number of `-1`.
4542

4643
## Workflow
4744

circuit_maintenance_parser/output.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,9 @@ class Maintenance(BaseModel, extra=Extra.forbid):
137137
end: StrictInt
138138
stamp: StrictInt
139139
organizer: StrictStr
140+
status: Status
140141

141142
# Non mandatory attributes
142-
status: Status = Status.NO_CHANGE
143143
uid: StrictStr = "0"
144144
sequence: StrictInt = 1
145145
summary: StrictStr = ""

circuit_maintenance_parser/parsers/equinix.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,15 @@ def parse_subject(self, subject: str) -> List[Dict]:
112112
if maintenance_id:
113113
data["maintenance_id"] = maintenance_id[1]
114114
data["summary"] = subject.strip().replace("\n", "")
115-
if "COMPLETED" in subject:
115+
if "completed" in subject.lower():
116116
data["status"] = Status.COMPLETED
117-
if "SCHEDULED" in subject or "REMINDER" in subject:
117+
elif "rescheduled" in subject.lower():
118+
data["status"] = Status.RE_SCHEDULED
119+
elif "scheduled" in subject.lower() or "reminder" in subject.lower():
118120
data["status"] = Status.CONFIRMED
121+
else:
122+
# Some Equinix notifications don't clearly state a status in their subject.
123+
# From inspection of examples, it looks like "Confirmed" would be the most appropriate in this case.
124+
data["status"] = Status.CONFIRMED
125+
119126
return [data]

circuit_maintenance_parser/parsers/lumen.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def parse_tables(self, tables: ResultSet, data: Dict):
9393
data["status"] = Status("COMPLETED")
9494
elif status_string == "Postponed":
9595
data["status"] = Status("RE-SCHEDULED")
96-
elif status_string == "Not Completed":
96+
elif status_string in ["Not Completed", "Cancelled"]:
9797
data["status"] = Status("CANCELLED")
9898
elif status_string == "Alternate Night":
9999
data["status"] = Status("RE-SCHEDULED")

0 commit comments

Comments
 (0)