From 7bf5fc8d8b649707caf02359abe37678341cfe78 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Tue, 2 May 2023 13:42:50 +0200 Subject: [PATCH 1/6] Parser for Apple peering notifications --- circuit_maintenance_parser/__init__.py | 2 + circuit_maintenance_parser/parsers/apple.py | 58 +++++++++++++++++++ circuit_maintenance_parser/provider.py | 9 +++ tests/unit/data/apple/apple1.eml | 49 ++++++++++++++++ tests/unit/data/apple/apple1_result.json | 17 ++++++ .../data/apple/apple1_text_parser_result.json | 16 +++++ .../apple/apple2_subject_parser_result.json | 5 ++ tests/unit/test_e2e.py | 11 ++++ tests/unit/test_parsers.py | 12 ++++ 9 files changed, 179 insertions(+) create mode 100644 circuit_maintenance_parser/parsers/apple.py create mode 100644 tests/unit/data/apple/apple1.eml create mode 100644 tests/unit/data/apple/apple1_result.json create mode 100644 tests/unit/data/apple/apple1_text_parser_result.json create mode 100644 tests/unit/data/apple/apple2_subject_parser_result.json diff --git a/circuit_maintenance_parser/__init__.py b/circuit_maintenance_parser/__init__.py index 27e993cb..391c72e1 100644 --- a/circuit_maintenance_parser/__init__.py +++ b/circuit_maintenance_parser/__init__.py @@ -6,6 +6,7 @@ from .errors import NonexistentProviderError, ProviderError from .provider import ( GenericProvider, + Apple, AquaComms, AWS, BSO, @@ -31,6 +32,7 @@ SUPPORTED_PROVIDERS = ( GenericProvider, + Apple, AquaComms, AWS, BSO, diff --git a/circuit_maintenance_parser/parsers/apple.py b/circuit_maintenance_parser/parsers/apple.py new file mode 100644 index 00000000..cbef368b --- /dev/null +++ b/circuit_maintenance_parser/parsers/apple.py @@ -0,0 +1,58 @@ +import email +import re + +from typing import Dict, List + +from circuit_maintenance_parser.output import Impact, Status +from circuit_maintenance_parser.parser import EmailSubjectParser, Text, CircuitImpact + +class SubjectParserApple(EmailSubjectParser): + def parser_hook(self, raw: bytes): + message = email.message_from_string(self.bytes_to_string(raw)) + return self.parse_subject(message['subject']) + + def parse_subject(self, subject: str) -> List[Dict]: + return [{'summary': subject}] + + +class TextParserApple(Text): + def parse_text(self, text: str) -> List[Dict]: + data = { + 'circuits': self._circuits(text), + 'maintenance_id': self._maintenance_id(text), + 'start': self._start_time(text), + 'end': self._end_time(text), + 'status': Status.CONFIRMED, # Have yet to see anything but confirmation. + 'organizer': 'peering-noc@group.apple.com', + 'provider': 'apple', + } + return [data] + + def _circuits(self, text): + pattern = r'Peer AS: (\d*)' + m = re.search(pattern, text) + return [CircuitImpact( + circuit_id=f'AS{m.group(1)}', + impact=Impact.NO_IMPACT)] + + def _maintenance_id(self, text): + # Apple ticket numbers always starts with "CHG". + pattern = r'CHG(\d*)' + m = re.search(pattern, text) + return m.group(0) + + def _get_time(self, pattern, text): + # Apple sends timestamps as RFC2822, misused + # email module to convert to datetime. + m = re.search(pattern, text) + rfc2822 = m.group(1) + time_tuple = email.utils.parsedate_tz(rfc2822) + return email.utils.mktime_tz(time_tuple) + + def _start_time(self, text): + pattern = 'Start Time: ([a-zA-Z0-9 :]*)' + return self._get_time(pattern, text) + + def _end_time(self, text): + pattern = 'End Time: ([a-zA-Z0-9 :]*)' + return self._get_time(pattern, text) diff --git a/circuit_maintenance_parser/provider.py b/circuit_maintenance_parser/provider.py index 738431ad..7e43a4e1 100644 --- a/circuit_maintenance_parser/provider.py +++ b/circuit_maintenance_parser/provider.py @@ -17,6 +17,7 @@ from circuit_maintenance_parser.processor import CombinedProcessor, SimpleProcessor, GenericProcessor from circuit_maintenance_parser.constants import EMAIL_HEADER_SUBJECT +from circuit_maintenance_parser.parsers.apple import SubjectParserApple, TextParserApple from circuit_maintenance_parser.parsers.aquacomms import HtmlParserAquaComms1, SubjectParserAquaComms1 from circuit_maintenance_parser.parsers.aws import SubjectParserAWS1, TextParserAWS1 from circuit_maintenance_parser.parsers.bso import HtmlParserBSO1 @@ -164,6 +165,14 @@ def get_provider_type(cls) -> str: # PROVIDERS # #################### +class Apple(GenericProvider): + """Apple provider custom class.""" + + _processors: List[GenericProcessor] = [ + CombinedProcessor(data_parsers=[TextParserApple, SubjectParserApple]), + ] + _default_organizer = "peering-noc@group.apple.com" + class AquaComms(GenericProvider): """AquaComms provider custom class.""" diff --git a/tests/unit/data/apple/apple1.eml b/tests/unit/data/apple/apple1.eml new file mode 100644 index 00000000..1665c168 --- /dev/null +++ b/tests/unit/data/apple/apple1.eml @@ -0,0 +1,49 @@ +Date-warning: Date header was inserted by rn-mailsvcp-relay-lapp01.rno.apple.com +Date: Mon, 01 May 2023 10:38:11 -0700 (PDT) +Message-id: <0RTZ00SF5QBN8K50@rn-mailsvcp-relay-lapp01.rno.apple.com> +Received: from prz3-cstools-hyp001.corp.apple.com + (prz3-cstools-hyp001.corp.apple.com [10.35.7.133]) + by csmail.corp.apple.com (Postfix) with ESMTP id 1E23115EDE4; Mon, + 1 May 2023 17:38:11 +0000 (UTC) +Content-type: multipart/mixed; boundary="===============1255676001481217459==" +MIME-version: 1.0 +From: noreply@apple.com +Subject: Apple (AS714) Net Maintenance Notice for AS12345 in Chicago +To: recipients not specified: ; + +--===============1255676001481217459== +Content-Type: text/plain; charset="us-ascii" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit + +Apple (AS714) Network Maintenance Notification +Reference Internal Ticket: CHG000123456 +Message sent to: noc@example.org + +Details: +Start Time: 2 May 2023 14:00 UTC +End Time: 16 May 2023 23:59 UTC + +Peering Details: +Apple AS: 714 +Peer AS: 12345 + + +Apple IP: ['10.0.0.1', '2000:0000:0000:0000:0000:0000:0000:0001'] +Peer IP: ['10.0.0.2', '2000:0000:0000:0000:0000:0000:0000:0002'] + +There is no change required on your end as we will gracefully drain the traffic prior to maintenance. + +When the maintenance is completed, Apple will automatically re-route traffic back. +For reference, our current max prefix setting recommendation is: IPv4 = 10000 and IPv6 = 1000. +Questions about this event can be sent to peering-noc@group.apple.com. + +Thank you for peering with Apple! + +Regards, + +Apple Peering NOC (AS714) +peering-noc@group.apple.com +as714.peeringdb.com + +--===============1255676001481217459==-- diff --git a/tests/unit/data/apple/apple1_result.json b/tests/unit/data/apple/apple1_result.json new file mode 100644 index 00000000..c582983e --- /dev/null +++ b/tests/unit/data/apple/apple1_result.json @@ -0,0 +1,17 @@ +[ + { + "circuits": [ + { + "circuit_id": "AS12345", + "impact": "OUTAGE" + } + ], + "end": 1684281540, + "maintenance_id": "CHG000123456", + "start": 1683036000, + "status": "CONFIRMED", + "summary": "Apple (AS714) Net Maintenance Notice for AS12345 in Chicago", + "organizer": "peering-noc@group.apple.com", + "provider": "apple" + } +] \ No newline at end of file diff --git a/tests/unit/data/apple/apple1_text_parser_result.json b/tests/unit/data/apple/apple1_text_parser_result.json new file mode 100644 index 00000000..5a8d6003 --- /dev/null +++ b/tests/unit/data/apple/apple1_text_parser_result.json @@ -0,0 +1,16 @@ +[ + { + "circuits": [ + { + "circuit_id": "AS12345", + "impact": "NO-IMPACT" + } + ], + "end": 1684281540, + "maintenance_id": "CHG000123456", + "start": 1683036000, + "status": "CONFIRMED", + "organizer": "peering-noc@group.apple.com", + "provider": "apple" + } +] \ No newline at end of file diff --git a/tests/unit/data/apple/apple2_subject_parser_result.json b/tests/unit/data/apple/apple2_subject_parser_result.json new file mode 100644 index 00000000..6351f55c --- /dev/null +++ b/tests/unit/data/apple/apple2_subject_parser_result.json @@ -0,0 +1,5 @@ +[ + { + "summary": "Apple (AS714) Net Maintenance Notice for AS12345 in Chicago" + } +] \ No newline at end of file diff --git a/tests/unit/test_e2e.py b/tests/unit/test_e2e.py index ab8eb39e..eb36fc35 100644 --- a/tests/unit/test_e2e.py +++ b/tests/unit/test_e2e.py @@ -13,6 +13,7 @@ from circuit_maintenance_parser.provider import ( Equinix, GenericProvider, + Apple, AquaComms, Arelion, AWS, @@ -54,6 +55,16 @@ GENERIC_ICAL_RESULT_PATH, ], ), + # Apple + ( + Apple, + [ + ("email", Path(dir_path, "data", "apple", "apple1.eml")), + ], + [ + Path(dir_path, "data", "apple", "apple1_result.json"), + ], + ), # AquaComms ( AquaComms, diff --git a/tests/unit/test_parsers.py b/tests/unit/test_parsers.py index b2a2a900..07db6795 100644 --- a/tests/unit/test_parsers.py +++ b/tests/unit/test_parsers.py @@ -7,6 +7,7 @@ from circuit_maintenance_parser.errors import ParserError from circuit_maintenance_parser.parser import ICal, EmailDateParser +from circuit_maintenance_parser.parsers.apple import SubjectParserApple, TextParserApple from circuit_maintenance_parser.parsers.aquacomms import HtmlParserAquaComms1, SubjectParserAquaComms1 from circuit_maintenance_parser.parsers.aws import SubjectParserAWS1, TextParserAWS1 from circuit_maintenance_parser.parsers.bso import HtmlParserBSO1 @@ -68,6 +69,17 @@ Path(dir_path, "data", "ical", "ical6"), Path(dir_path, "data", "ical", "ical6_result.json"), ), + # Apple + ( + TextParserApple, + Path(dir_path, "data", "apple", "apple1.eml"), + Path(dir_path, "data", "apple", "apple1_text_parser_result.json"), + ), + ( + SubjectParserApple, + Path(dir_path, "data", "apple", "apple1.eml"), + Path(dir_path, "data", "apple", "apple2_subject_parser_result.json"), + ), # AquaComms ( HtmlParserAquaComms1, From ce38adf51c02ca533b184ca697d682ceaa726d16 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Tue, 2 May 2023 13:42:50 +0200 Subject: [PATCH 2/6] Parser for Apple peering notifications --- circuit_maintenance_parser/parsers/apple.py | 8 +++----- tests/unit/data/apple/apple1.eml | 13 ++----------- tests/unit/data/apple/apple1_result.json | 4 +++- .../unit/data/apple/apple1_text_parser_result.json | 6 ++++-- 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/circuit_maintenance_parser/parsers/apple.py b/circuit_maintenance_parser/parsers/apple.py index cbef368b..ab93bbca 100644 --- a/circuit_maintenance_parser/parsers/apple.py +++ b/circuit_maintenance_parser/parsers/apple.py @@ -7,10 +7,6 @@ from circuit_maintenance_parser.parser import EmailSubjectParser, Text, CircuitImpact class SubjectParserApple(EmailSubjectParser): - def parser_hook(self, raw: bytes): - message = email.message_from_string(self.bytes_to_string(raw)) - return self.parse_subject(message['subject']) - def parse_subject(self, subject: str) -> List[Dict]: return [{'summary': subject}] @@ -21,10 +17,12 @@ def parse_text(self, text: str) -> List[Dict]: 'circuits': self._circuits(text), 'maintenance_id': self._maintenance_id(text), 'start': self._start_time(text), + 'stamp': self._start_time(text), 'end': self._end_time(text), 'status': Status.CONFIRMED, # Have yet to see anything but confirmation. 'organizer': 'peering-noc@group.apple.com', 'provider': 'apple', + 'account': 'Customer info unavailable' } return [data] @@ -33,7 +31,7 @@ def _circuits(self, text): m = re.search(pattern, text) return [CircuitImpact( circuit_id=f'AS{m.group(1)}', - impact=Impact.NO_IMPACT)] + impact=Impact.OUTAGE)] def _maintenance_id(self, text): # Apple ticket numbers always starts with "CHG". diff --git a/tests/unit/data/apple/apple1.eml b/tests/unit/data/apple/apple1.eml index 1665c168..9c402b5e 100644 --- a/tests/unit/data/apple/apple1.eml +++ b/tests/unit/data/apple/apple1.eml @@ -1,15 +1,7 @@ -Date-warning: Date header was inserted by rn-mailsvcp-relay-lapp01.rno.apple.com -Date: Mon, 01 May 2023 10:38:11 -0700 (PDT) -Message-id: <0RTZ00SF5QBN8K50@rn-mailsvcp-relay-lapp01.rno.apple.com> -Received: from prz3-cstools-hyp001.corp.apple.com - (prz3-cstools-hyp001.corp.apple.com [10.35.7.133]) - by csmail.corp.apple.com (Postfix) with ESMTP id 1E23115EDE4; Mon, - 1 May 2023 17:38:11 +0000 (UTC) -Content-type: multipart/mixed; boundary="===============1255676001481217459==" MIME-version: 1.0 -From: noreply@apple.com +Date: Thu, 26 Aug 2021 18:22:09 +0100 Subject: Apple (AS714) Net Maintenance Notice for AS12345 in Chicago -To: recipients not specified: ; +Content-type: multipart/mixed; boundary="===============1255676001481217459==" --===============1255676001481217459== Content-Type: text/plain; charset="us-ascii" @@ -29,7 +21,6 @@ Apple AS: 714 Peer AS: 12345 -Apple IP: ['10.0.0.1', '2000:0000:0000:0000:0000:0000:0000:0001'] Peer IP: ['10.0.0.2', '2000:0000:0000:0000:0000:0000:0000:0002'] There is no change required on your end as we will gracefully drain the traffic prior to maintenance. diff --git a/tests/unit/data/apple/apple1_result.json b/tests/unit/data/apple/apple1_result.json index c582983e..1c79d613 100644 --- a/tests/unit/data/apple/apple1_result.json +++ b/tests/unit/data/apple/apple1_result.json @@ -9,9 +9,11 @@ "end": 1684281540, "maintenance_id": "CHG000123456", "start": 1683036000, + "stamp": 1683036000, "status": "CONFIRMED", "summary": "Apple (AS714) Net Maintenance Notice for AS12345 in Chicago", "organizer": "peering-noc@group.apple.com", - "provider": "apple" + "provider": "apple", + "account": "Customer info unavailable" } ] \ No newline at end of file diff --git a/tests/unit/data/apple/apple1_text_parser_result.json b/tests/unit/data/apple/apple1_text_parser_result.json index 5a8d6003..da9ed36e 100644 --- a/tests/unit/data/apple/apple1_text_parser_result.json +++ b/tests/unit/data/apple/apple1_text_parser_result.json @@ -3,14 +3,16 @@ "circuits": [ { "circuit_id": "AS12345", - "impact": "NO-IMPACT" + "impact": "OUTAGE" } ], "end": 1684281540, "maintenance_id": "CHG000123456", "start": 1683036000, + "stamp": 1683036000, "status": "CONFIRMED", "organizer": "peering-noc@group.apple.com", - "provider": "apple" + "provider": "apple", + "account": "Customer info unavailable" } ] \ No newline at end of file From d4cadf890ae23fef2f3a9efd86437c06babae9e0 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Mon, 22 May 2023 10:57:24 +0200 Subject: [PATCH 3/6] Ensure that Blake parses --- README.md | 1 + circuit_maintenance_parser/parsers/apple.py | 49 ++++++++++++--------- circuit_maintenance_parser/provider.py | 1 + 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 96011919..780d1452 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ By default, there is a `GenericProvider` that support a `SimpleProcessor` using #### Supported providers based on other parsers +- Apple - AWS - AquaComms - BSO diff --git a/circuit_maintenance_parser/parsers/apple.py b/circuit_maintenance_parser/parsers/apple.py index ab93bbca..546e719f 100644 --- a/circuit_maintenance_parser/parsers/apple.py +++ b/circuit_maintenance_parser/parsers/apple.py @@ -1,56 +1,61 @@ import email import re +from datetime import datetime, timezone from typing import Dict, List from circuit_maintenance_parser.output import Impact, Status from circuit_maintenance_parser.parser import EmailSubjectParser, Text, CircuitImpact + class SubjectParserApple(EmailSubjectParser): def parse_subject(self, subject: str) -> List[Dict]: - return [{'summary': subject}] + return [{"summary": subject}] class TextParserApple(Text): def parse_text(self, text: str) -> List[Dict]: data = { - 'circuits': self._circuits(text), - 'maintenance_id': self._maintenance_id(text), - 'start': self._start_time(text), - 'stamp': self._start_time(text), - 'end': self._end_time(text), - 'status': Status.CONFIRMED, # Have yet to see anything but confirmation. - 'organizer': 'peering-noc@group.apple.com', - 'provider': 'apple', - 'account': 'Customer info unavailable' + "circuits": self._circuits(text), + "maintenance_id": self._maintenance_id(text), + "start": self._start_time(text), + "stamp": self._start_time(text), + "end": self._end_time(text), + "status": Status.CONFIRMED, # Have yet to see anything but confirmation. + "organizer": "peering-noc@group.apple.com", + "provider": "apple", + "account": "Customer info unavailable", } return [data] def _circuits(self, text): - pattern = r'Peer AS: (\d*)' + pattern = r"Peer AS: (\d*)" m = re.search(pattern, text) - return [CircuitImpact( - circuit_id=f'AS{m.group(1)}', - impact=Impact.OUTAGE)] + return [CircuitImpact(circuit_id=f"AS{m.group(1)}", impact=Impact.OUTAGE)] def _maintenance_id(self, text): # Apple ticket numbers always starts with "CHG". - pattern = r'CHG(\d*)' + pattern = r"CHG(\d*)" m = re.search(pattern, text) return m.group(0) def _get_time(self, pattern, text): - # Apple sends timestamps as RFC2822, misused - # email module to convert to datetime. + # Apple sends timestamps as RFC2822 for the US + # but a custom format for EU datacenters. m = re.search(pattern, text) - rfc2822 = m.group(1) - time_tuple = email.utils.parsedate_tz(rfc2822) - return email.utils.mktime_tz(time_tuple) + try: + # Try EU timestamp + return int(datetime.strptime(m.group(1), "%Y-%m-%d(%a) %H:%M %Z").replace(tzinfo=timezone.utc).timestamp()) + except: + # Try RFC2822 - US timestamp + rfc2822 = m.group(1) + time_tuple = email.utils.parsedate_tz(rfc2822) + return email.utils.mktime_tz(time_tuple) def _start_time(self, text): - pattern = 'Start Time: ([a-zA-Z0-9 :]*)' + pattern = "Start Time: ([a-zA-Z0-9 :()-]*)" return self._get_time(pattern, text) def _end_time(self, text): - pattern = 'End Time: ([a-zA-Z0-9 :]*)' + pattern = "End Time: ([a-zA-Z0-9 :()-]*)" return self._get_time(pattern, text) diff --git a/circuit_maintenance_parser/provider.py b/circuit_maintenance_parser/provider.py index 7e43a4e1..c2e05a45 100644 --- a/circuit_maintenance_parser/provider.py +++ b/circuit_maintenance_parser/provider.py @@ -165,6 +165,7 @@ def get_provider_type(cls) -> str: # PROVIDERS # #################### + class Apple(GenericProvider): """Apple provider custom class.""" From a51e9bebfee474e1b883efba04730c37779c9795 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Wed, 24 May 2023 11:18:26 +0200 Subject: [PATCH 4/6] Apple: Flake8 and DocStrings --- circuit_maintenance_parser/parsers/apple.py | 25 ++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/circuit_maintenance_parser/parsers/apple.py b/circuit_maintenance_parser/parsers/apple.py index 546e719f..d6626cd8 100644 --- a/circuit_maintenance_parser/parsers/apple.py +++ b/circuit_maintenance_parser/parsers/apple.py @@ -9,12 +9,35 @@ class SubjectParserApple(EmailSubjectParser): + """Subject parser for Apple notification.""" + def parse_subject(self, subject: str) -> List[Dict]: + """Use the subject of the email as summary + + Args: + subject (str): Message subjects + + Returns: + List[Dict]: List of attributes for Maintenance object + """ return [{"summary": subject}] class TextParserApple(Text): + """Parse the plaintext content of an Apple notification + + Args: + Text (str): Plaintext message + """ def parse_text(self, text: str) -> List[Dict]: + """Extract attributes from an Apple notification email. + + Args: + text (str): plaintext message + + Returns: + List[Dict]: List of attributes for Maintenance object + """ data = { "circuits": self._circuits(text), "maintenance_id": self._maintenance_id(text), @@ -46,7 +69,7 @@ def _get_time(self, pattern, text): try: # Try EU timestamp return int(datetime.strptime(m.group(1), "%Y-%m-%d(%a) %H:%M %Z").replace(tzinfo=timezone.utc).timestamp()) - except: + except Exception: # Try RFC2822 - US timestamp rfc2822 = m.group(1) time_tuple = email.utils.parsedate_tz(rfc2822) From 4b383e75f65a74a9f0483809f50301954b681a06 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Thu, 25 May 2023 11:44:45 +0200 Subject: [PATCH 5/6] Apple: Fix blake error. --- circuit_maintenance_parser/parsers/apple.py | 1 + 1 file changed, 1 insertion(+) diff --git a/circuit_maintenance_parser/parsers/apple.py b/circuit_maintenance_parser/parsers/apple.py index d6626cd8..0c3a19cc 100644 --- a/circuit_maintenance_parser/parsers/apple.py +++ b/circuit_maintenance_parser/parsers/apple.py @@ -29,6 +29,7 @@ class TextParserApple(Text): Args: Text (str): Plaintext message """ + def parse_text(self, text: str) -> List[Dict]: """Extract attributes from an Apple notification email. From 093855ea7e47ffd2253f1ed58668a2ee61e63eb5 Mon Sep 17 00:00:00 2001 From: Simon Lyngshede Date: Thu, 8 Jun 2023 10:17:43 +0200 Subject: [PATCH 6/6] Apple: PyDocStyle fixes. --- circuit_maintenance_parser/parsers/apple.py | 29 ++++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/circuit_maintenance_parser/parsers/apple.py b/circuit_maintenance_parser/parsers/apple.py index 0c3a19cc..2990fae8 100644 --- a/circuit_maintenance_parser/parsers/apple.py +++ b/circuit_maintenance_parser/parsers/apple.py @@ -1,3 +1,4 @@ +"""Apple peering parser.""" import email import re @@ -12,7 +13,7 @@ class SubjectParserApple(EmailSubjectParser): """Subject parser for Apple notification.""" def parse_subject(self, subject: str) -> List[Dict]: - """Use the subject of the email as summary + """Use the subject of the email as summary. Args: subject (str): Message subjects @@ -24,7 +25,7 @@ def parse_subject(self, subject: str) -> List[Dict]: class TextParserApple(Text): - """Parse the plaintext content of an Apple notification + """Parse the plaintext content of an Apple notification. Args: Text (str): Plaintext message @@ -52,27 +53,29 @@ def parse_text(self, text: str) -> List[Dict]: } return [data] - def _circuits(self, text): + def _circuits(self, text): # pylint: disable=no-self-use pattern = r"Peer AS: (\d*)" - m = re.search(pattern, text) - return [CircuitImpact(circuit_id=f"AS{m.group(1)}", impact=Impact.OUTAGE)] + match = re.search(pattern, text) + return [CircuitImpact(circuit_id=f"AS{match.group(1)}", impact=Impact.OUTAGE)] - def _maintenance_id(self, text): + def _maintenance_id(self, text): # pylint: disable=no-self-use # Apple ticket numbers always starts with "CHG". pattern = r"CHG(\d*)" - m = re.search(pattern, text) - return m.group(0) + match = re.search(pattern, text) + return match.group(0) - def _get_time(self, pattern, text): + def _get_time(self, pattern, text): # pylint: disable=no-self-use # Apple sends timestamps as RFC2822 for the US # but a custom format for EU datacenters. - m = re.search(pattern, text) + match = re.search(pattern, text) try: # Try EU timestamp - return int(datetime.strptime(m.group(1), "%Y-%m-%d(%a) %H:%M %Z").replace(tzinfo=timezone.utc).timestamp()) - except Exception: + return int( + datetime.strptime(match.group(1), "%Y-%m-%d(%a) %H:%M %Z").replace(tzinfo=timezone.utc).timestamp() + ) + except ValueError: # Try RFC2822 - US timestamp - rfc2822 = m.group(1) + rfc2822 = match.group(1) time_tuple = email.utils.parsedate_tz(rfc2822) return email.utils.mktime_tz(time_tuple)