From 48cba259e3f850c6f3225ca164e80c1b8d7a1a8d Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Thu, 2 Dec 2021 10:58:33 -0500 Subject: [PATCH 01/14] Handle encoding of non-ASCII characters in email subjects --- circuit_maintenance_parser/data.py | 11 +- tests/unit/data/gtt/gtt7.eml | 430 ++++++++++++++++++ .../data/gtt/gtt7_html_parser_result.json | 15 + tests/unit/data/gtt/gtt7_result.json | 21 + tests/unit/test_e2e.py | 5 + tests/unit/test_parsers.py | 5 + 6 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 tests/unit/data/gtt/gtt7.eml create mode 100644 tests/unit/data/gtt/gtt7_html_parser_result.json create mode 100644 tests/unit/data/gtt/gtt7_result.json diff --git a/circuit_maintenance_parser/data.py b/circuit_maintenance_parser/data.py index 5d5fd137..485248f1 100644 --- a/circuit_maintenance_parser/data.py +++ b/circuit_maintenance_parser/data.py @@ -75,7 +75,16 @@ def init_from_emailmessage(cls: Type["NotificationData"], email_message) -> Opti cls.walk_email(email_message, data_parts) # Adding extra headers that are interesting to be parsed - data_parts.add(DataPart(EMAIL_HEADER_SUBJECT, email_message["Subject"].encode())) + data_parts.add( + DataPart( + EMAIL_HEADER_SUBJECT, + # decode_header() handles conversion from RFC2047 ASCII representation of non-ASCII content to + # a list of (string, charset) tuples. + # make_header() merges these back into a single Header object containing this text + # str() gets the simple Unicode representation of the Header. + str(email.header.make_header(email.header.decode_header(email_message["Subject"]))).encode(), + ) + ) data_parts.add(DataPart(EMAIL_HEADER_DATE, email_message["Date"].encode())) # Ensure the data parts are processed in a consistent order return cls(data_parts=sorted(data_parts, key=lambda part: part.type)) diff --git a/tests/unit/data/gtt/gtt7.eml b/tests/unit/data/gtt/gtt7.eml new file mode 100644 index 00000000..cddd7f09 --- /dev/null +++ b/tests/unit/data/gtt/gtt7.eml @@ -0,0 +1,430 @@ +Delivered-To: nautobot.email@example.com +Received: by 2002:a05:7000:1f21:0:0:0:0 with SMTP id hs33csp8787082mab; + Tue, 23 Nov 2021 06:50:05 -0800 (PST) +X-Received: by 2002:a05:620a:1a10:: with SMTP id bk16mr5510732qkb.258.1637679004754; + Tue, 23 Nov 2021 06:50:04 -0800 (PST) +ARC-Seal: i=3; a=rsa-sha256; t=1637679004; cv=pass; + d=google.com; s=arc-20160816; + b=vUe79MzQJmlVkvvGnvcgbAgme/2Jwt1B2Zo3js/kAu7QCToy4cjQqUHyT7J2srn5dO + /kyktHkm4zI6WH5rSd7rWgSkabkVJs0Uwb0BewZ6pTCqITcz7spPhRyQ/mWR7kaALAXy + MKJSvJ+486N/6N/Wos867jffOxERI5C7fLxtGdJSaXDwYvA2ecJ3SUaRheuF7i1GzrgL + CO9EvbCOaSftPlkUolS98E7wWoIxkNJYZRs7FoMUZNeJJ9LxUQJwOvoBV8LnTB0Obklm + YfuSQ5BteOgMj7JSqJJSb23uPRgc3G/RQ0Pp5+vSHjCkaBGNOEMuFK6c6xvyxKkZfmB4 + 7tuQ== +ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=list-unsubscribe:list-archive:list-help:list-post:list-id + :mailing-list:precedence:content-transfer-encoding:mime-version + :message-id:reply-to:from:date:subject:to:sender:dkim-signature; + bh=C0Jesyuuv4BU+nssMchN2LsveiLMpbfsTndp3ny2HT4=; + b=jh+TxTU+BvFo6G0sAv03NdxeaMNwVBUGuIX/ZMudpc1hie8NpY225QcazVPg3CMfno + GXTF8srtUvofKWf1VHkAii0AvqIpJUDIY62zr/raOX2r2vMzAGDP270PREpazPgscNZj + iBLuebnSvy3NoyxS+X+plJ70vrDY0lKzeDkrb6DeEC/LiRXJXSZksazG8q+xngW+FCQK + YpJenJlRIGgBfNaH4JNe0L4uRFWpfJZhtKI2cIXSilGla3T8WfcK3k3UaaIUovGK9ZAZ + Jjg/6ko3Cd02WLd0wnQdE/j1M6Ecy3o75hEvHhiKr7Lnc0NjEGDzPkEtN9PtpQgyHg59 + vXSQ== +ARC-Authentication-Results: i=3; mx.google.com; + dkim=pass header.i=@example.com header.s=example header.b=Va3JHXMB; + arc=pass (i=2 spf=pass spfdomain=exainfra.net); + spf=pass (google.com: domain of maint-notices+bncbaabbgp76ogamgqetzq64dq@example.com designates 209.85.220.101 as permitted sender) smtp.mailfrom=maint-notices+bncBAABBGP76OGAMGQETZQ64DQ@example.com +Return-Path: +Received: from mail-sor-f101.google.com (mail-sor-f101.google.com. [209.85.220.101]) + by mx.google.com with SMTPS id t65sor2273382qkh.48.2021.11.23.06.50.04 + for + (Google Transport Security); + Tue, 23 Nov 2021 06:50:04 -0800 (PST) +Received-SPF: pass (google.com: domain of maint-notices+bncbaabbgp76ogamgqetzq64dq@example.com designates 209.85.220.101 as permitted sender) client-ip=209.85.220.101; +Authentication-Results: mx.google.com; + dkim=pass header.i=@example.com header.s=example header.b=Va3JHXMB; + arc=pass (i=2 spf=pass spfdomain=exainfra.net); + spf=pass (google.com: domain of maint-notices+bncbaabbgp76ogamgqetzq64dq@example.com designates 209.85.220.101 as permitted sender) smtp.mailfrom=maint-notices+bncBAABBGP76OGAMGQETZQ64DQ@example.com +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; + h=x-gm-message-state:dkim-signature:sender:to:subject:date:from + :reply-to:message-id:mime-version:content-transfer-encoding + :x-original-sender:x-original-authentication-results:precedence + :mailing-list:list-id:list-post:list-help:list-archive + :list-unsubscribe; + bh=C0Jesyuuv4BU+nssMchN2LsveiLMpbfsTndp3ny2HT4=; + b=jllEAnf+YmTc4vg0ITD6WzAynLyTDtcn1n4IXcLucVwBzG9O2JNmgdZ5r7qH14dyZY + ox2cYTbG8vmTvG5EMOLDZpwItR45dCnr4fGY6Q3E5t3+UNGMzgxhlXgYz6weQejPeL3Z + O3vtKJL7VZaVz0lAIj6XWLH9NjI/1UjHheZLFp4jjkPArhYvtGAMadvaLj6OvMID2U/s + RqPsYv0Jp9o9wCUeV0TGadOTHj1OKtj8idxwFNZ/Qp1qeDbQsCGFhmN2V2Vvvr0s5KCA + +MRCT5YhSgzLj83QDbccmHuot6WCzN9bVqGp0qnPKDyRsmGGTRW3JtsNSD5wM2IMbqfJ + 5X2g== +X-Gm-Message-State: AOAM531KBPx07Y6btFUQSetapqmUGATdLolWR5FI5p5SzB17j7XNBOD2 + mpcrzHfz28uZn3CaYk6COBL83Kn5GHMv73Aq3ZzZtOHTDtCPkF/k +X-Google-Smtp-Source: ABdhPJyKtSr2+JBNZ/K7AU0fv8rsre882Kbrvmgui9UZnUisErOQMUCLsJEigXZHEY+lBCF40OczIu95mTF2 +X-Received: by 2002:ab0:3349:: with SMTP id h9mr9749289uap.111.1637679004217; + Tue, 23 Nov 2021 06:50:04 -0800 (PST) +Return-Path: +Received: from netskope.com ([8.36.116.139]) + by smtp-relay.gmail.com with ESMTPS id y6sm3667722vkc.4.2021.11.23.06.50.03 + for + (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); + Tue, 23 Nov 2021 06:50:04 -0800 (PST) +X-Relaying-Domain: example.com +Received: by mail-wm1-f72.google.com with SMTP id 187-20020a1c02c4000000b003335872db8dsf8071724wmc.2 + for ; Tue, 23 Nov 2021 06:50:02 -0800 (PST) +ARC-Seal: i=2; a=rsa-sha256; t=1637679001; cv=pass; + d=google.com; s=arc-20160816; + b=FAEyypmFn1ucJuPYezfoObVktEmUzIWF9RbdsLFVWT+koSL/cW7fjahj1f71Gh2HFm + 9MnPddkynP8m4fY6p9J096ZmLk7UcYNngvzHgJcJxSfuAN0daPplTdKnTL+Xlh7CPkF+ + gzq+VFmcRO2ZMc664SCt1DJASI5D1tb+gbXj/O+AFU1KpKKNRI/H1G5H35BU32LO6ewZ + +FJdjTmL5SpAN47Yhl/Cxe1AbVcrCj2kEj8zbcrcICWNiTxH3sC7Xaz9As/NYR5B7ggD + PFVMIqPoKkDtOwvZFZXQXuhNlcs9p9k5e9MLRX/dwsJBOgsE7oP2ypDxRtAd/MGtmwSW + Vj9w== +ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=list-unsubscribe:list-archive:list-help:list-post:list-id + :mailing-list:precedence:content-transfer-encoding:mime-version + :message-id:reply-to:from:date:subject:to:sender:dkim-signature; + bh=C0Jesyuuv4BU+nssMchN2LsveiLMpbfsTndp3ny2HT4=; + b=Y4qeLp1Ne97E8V8qD2lystu+9ocF4zJd8WU4yOsCGqH520Ut1Vq8F6gcq5q+Bhciuz + tQ2ms2rspHLKTYKzMjcm3OcAWzIdo2R/0c5WMD0r3K2ws3S+UVY4EAnetonWZownRMFs + zmHDRJNn6/uOmiEgOq7rCyiUFfoBMovEcJqcNuan8rKOV91KpnEN6gcYTYvhr2X0edH2 + AlpnJbwHgu3fha1q8t5RGwuFE/AGlRgX0/n6BXpyg2k2ijXc8W0MqWrSf+4YBUreesFm + gxnydAhzUE+oRhPyWme+YsgnUv6zpFz1/1QSrZ1REwD7tHLe3SwwY2BvOh5y6PIhJb/V + eUjg== +ARC-Authentication-Results: i=2; mx.google.com; + spf=pass (google.com: domain of cmd.bounceback@exainfra.net designates 154.14.213.215 as permitted sender) smtp.mailfrom=cmd.bounceback@exainfra.net +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=example.com; s=example; + h=sender:to:subject:date:from:reply-to:message-id:mime-version + :content-transfer-encoding:x-original-sender + :x-original-authentication-results:precedence:mailing-list:list-id + :list-post:list-help:list-archive:list-unsubscribe; + bh=C0Jesyuuv4BU+nssMchN2LsveiLMpbfsTndp3ny2HT4=; + b=Va3JHXMBfNDPJisXXDXiEuiwMYHEa4Efrlc5pXIdolSBuNQUiq6/7ClhYCc2Mr88Yx + V0cqHX+MK/IeATDfPoWii7irgv7RCGW5iq7l/vZ+nJSlmhk8aGz3pvDEoSFShFndo60h + bzR2sOV2vUHahllv4m7Tgwir2Mzv+c+MmiNa4= +Sender: maint-notices@example.com +X-Received: by 2002:a5d:68d2:: with SMTP id p18mr8189115wrw.21.1637679001692; + Tue, 23 Nov 2021 06:50:01 -0800 (PST) +X-Received: by 2002:a5d:68d2:: with SMTP id p18mr8189096wrw.21.1637679001549; + Tue, 23 Nov 2021 06:50:01 -0800 (PST) +X-BeenThere: maint-notices@example.com +Received: by 2002:a05:600c:ad6:: with SMTP id c22ls889756wmr.1.canary-gmail; + Tue, 23 Nov 2021 06:50:00 -0800 (PST) +X-Received: by 2002:a05:600c:a08:: with SMTP id z8mr3945922wmp.52.1637679000526; + Tue, 23 Nov 2021 06:50:00 -0800 (PST) +ARC-Seal: i=1; a=rsa-sha256; t=1637679000; cv=none; + d=google.com; s=arc-20160816; + b=iZPVXO7zKyxAnRrjL+FBY7L1RayjqS1Qx4su4wA/yKZmODuu+GvUHbckcEoHYeX46z + WYXYG7web/1sbxK/G3MKDxt7lfLg4tBdXX5dtCHFwq6nPDbPrZ9b71AZJPSjNJVSAinz + BkV9FJYdPESBBG6scAVBJ2MD7Rn850q7XAmdXdkLUyvvWSiimqVaNDOLOPRMPOm5OYDL + 4RJ1JArnMR0uFR1zkO6Uk293RJZ6SKZTQCub7LVJCmHD7m/57M83IeJMIHgdCevt4qD9 + PO6V2rybxuYj/HrMtkc+CHgtVU12s2h5YhuuD5A23RrsZJRzoMHcwZq/UwI1cU6cgY50 + GvYw== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=content-transfer-encoding:mime-version:message-id:reply-to:from + :date:subject:to; + bh=q4mPDFTARsCcneEpOnF/XKc0L6eRffzoP2m6dEvPRaE=; + b=WmP2TfL5/HMjeAlnWxy5uCaEhIVlI9Lsp10OkUZ5M9EfBUkjbBY0yBYwlbDmRUMpAs + VYyOkjovQg1E1DuOI3LO6x0O60NdP/myf7Uo3z42gwnikh7xRUjxpqWtTjcxkPlGEUuE + HbikknX8P2JY0fOWAkjSsDF4UiyTQLii8gvH+4YcnkGIHMZYNxntnxSKh7XP8RaoVd5T + 66noi25/QZnorAIpYffCNgT7zOOyFtboxBU1wwe3eXvpO/VAGtjUZRQbRX1abU+4iRAZ + FfPiwr8Bkqt1F74QJAVRcx8EGsH6laarVEr3hhpu+vv8xwSqdiXfCugFmwganrkpvMjL + 4lUg== +ARC-Authentication-Results: i=1; mx.google.com; + spf=pass (google.com: domain of cmd.bounceback@exainfra.net designates 154.14.213.215 as permitted sender) smtp.mailfrom=cmd.bounceback@exainfra.net +Received: from mexch01.crosstera.com (mexch01.crosstera.com. [154.14.213.215]) + by mx.google.com with ESMTPS id v129si1976559wme.213.2021.11.23.06.49.59 + (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); + Tue, 23 Nov 2021 06:50:00 -0800 (PST) +Received-SPF: pass (google.com: domain of cmd.bounceback@exainfra.net designates 154.14.213.215 as permitted sender) client-ip=154.14.213.215; +Received: from uklon1-cmd2.gt-t.net (89.149.165.100) by + IEDUB-EXCEDGE01.crosstera.com (10.151.34.215) with Microsoft SMTP Server id + 15.2.659.4; Tue, 23 Nov 2021 14:49:59 +0000 +Received: by uklon1-cmd2.gt-t.net (Postfix, from userid 1001) + id D931C2800122A; Tue, 23 Nov 2021 14:49:58 +0000 (UTC) +To: , , + , + +Subject: =?UTF-8?Q?=5Bmaint=2Dnotices=5D_EXA_Emergency_Work_Notification_TT_6543?= + =?UTF-8?Q?0619_=E2=80=93_New?= +Date: Tue, 23 Nov 2021 14:49:58 +0000 +From: +Reply-To: +Message-ID: +X-Mailer: PHPMailer 6.1.7 (https://github.com/PHPMailer/PHPMailer) +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="b1_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E" +Content-Transfer-Encoding: 8bit +X-Original-Sender: infraco.cm@exainfra.net +X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: + domain of cmd.bounceback@exainfra.net designates 154.14.213.215 as permitted + sender) smtp.mailfrom=cmd.bounceback@exainfra.net +Precedence: list +Mailing-list: list maint-notices@example.com; contact maint-notices+owners@example.com +List-ID: +X-Google-Group-Id: 536184160288 +List-Post: , +List-Help: , + +List-Archive: +List-Unsubscribe: , + +x-netskope-inspected: true + +--b1_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E +Content-Type: multipart/alternative; + boundary="b2_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E" + +--b2_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + +Planned Work Notification: 65430585 - New + +As part of our commitment to continually improve the quality of service we = +provide to our clients, we will be performing a planned work in Washington,= + DC between 2021-12-02 05:00:00 - 2021-12-02 10:00:00 GMT.=E2=80=AFPlease s= +ee details of the work and impact on your service below. + +Detail: + +Start 2021-12-02 05:00:00 GMT +End 2021-12-02 10:00:00 GMT +Location Washington, DC + +Planned work Reason: +Network optimization on our partner network. + +Services Affected SLID/CCSD Customer PON Service Type Expected Impact to yo= +ur Service Site Address +HI/Wavelength/00696448 1098765-12345678 PO # EXA00012345 Wavelength 300 min= + 23456 Example Ct,1st Floor Equinix DC2,Ashburn, VA 20147, USA +Comments (Color explanation) : + +Service interruption Service will experience interruption lasting maximum t= +he duration value in the service row +Resiliency Loss Primary or backup circuit will be impacted only. Service wi= +ll remain operational throughout the maintenance + +If you have any questions regarding the planned work, please login to MyPor= +tal or contact our Change Management Team using the email below. + +Kind Regards, +EXA Network Operations +InfraCo.CM@exainfra.net + +Did you know that it is now easier than ever to log your tickets=E2=80=AFon= + our=E2=80=AFMyPortal=E2=80=AF? You will be able to answer a few troublesho= +oting questions and receive a ticket ID immediately.=E2=80=AFMyPortal=E2=80= +=AFalso helps you check on status of existing tickets and access your escal= +ation list. If you do not have an=E2=80=AFMyPortal=E2=80=AFlogin, you can c= +ontact your company=E2=80=99s account administrator or submit a request on= +=E2=80=AFour=E2=80=AFwebsite. + +--=20 +You received this message because you are subscribed to the Google Groups "= +Riot Direct Notices" group. +To unsubscribe from this group and stop receiving emails from it, send an e= +mail to maint-notices+unsubscribe@example.com. +To view this discussion on the web visit https://groups.google.com/a/exampl= +e.com/d/msgid/maint-notices/EXA_MSG_ID-62c2d771-800d-4be1-b458-f2b3f9de31ea-= +EXA_MSG_ID%40exainfra.net. + +--b2_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + =20 + + +
+ + + + + +
Planned Work= + Notification: 65430585 - New
+

As part of our commitment to continually improve the quality of serv= +ice we provide to our clients, we will be performing a planned work in Wash= +ington, DC between 2021-12-02 05:00:00 - 2021-12-02 10:00:00 GMT.=E2=80=AFP= +lease see details of the work and impact on your service below.

+ + Detail:
+ + + + + + + + + + =20 + + + + +
+Start + +2021-12-02 05:00:00 GMT +
+End + +2021-12-02 10:00:00 GMT +
+Location + +Washington, DC +
+ +

+ Planned work Reason:
+ Network optimization on our partner network. +

+ + + + + + + + + + + + =20 + + + + + + + + + =20 +
Services AffectedSLID/CCSDCustomer PONService TypeExpected Impact to your Service= +Site Address
HI/Wavelength/006964481098765-12345678PO # EXA00012345Wavelength300 = +min23456 Example Ct,1st Floor Equinix DC2,= +Ashburn, VA 20147, USA
+ =20 +
+ Comments (Color explanation) :
+ + + + + + + + + +
+Service interruption + Service will experience interruption lasting maximu= +m the duration value in the service row +
+Resiliency Loss + Primary or backup circuit will be impacted only. Service will rem= +ain operational throughout the maintenance +
+ +

If you have any questions regarding the planned work, please login t= +o MyPor= +tal or contact our Change Management Team using the email below.

+ +
Kind Regards, +
EXA Network Operations +
InfraCo.CM@exainfra.net +

+
+ + Did you know that it is now easier than ever to log your tickets=E2=80=AF= +on our=E2=80=AFMyPortal=E2=80=AF? You will be able to answer a few troubleshoo= +ting questions and receive a ticket ID immediately.=E2=80=AFMyPortal=E2=80= +=AFalso helps you check on status of existing tickets and access your escal= +ation list. + + If you do not have an=E2=80=AFMyPortal=E2=80=AFlogin, you can contact you= +r company=E2=80=99s account administrator or submit a request on=E2=80=AFou= +r=E2=80=AFwebsite. + +
+
+ + + +

+ +--
+You received this message because you are subscribed to the Google Groups &= +quot;Riot Direct Notices" group.
+To unsubscribe from this group and stop receiving emails from it, send an e= +mail to maint-notices+= +unsubscribe@example.com.
+To view this discussion on the web visit https://groups.google.com/a/example.com/d/msgid/maint-notices/EXA_MSG_ID-6= +2c2d771-800d-4be1-b458-f2b3f9de31ea-EXA_MSG_ID%40exainfra.net.
+ +--b2_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E-- + +--b1_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E +Content-Type: text/calendar; name="planned_work_primary_window.ics" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="planned_work_primary_window.ics" +Content-Description: planned_work_primary_window.ics + +QkVHSU46VkNBTEVOREFSDQpWRVJTSU9OOjIuMA0KUFJPRElEOkVYQQ0KTUVUSE9EOlJFUVVFU1QN +CkJFR0lOOlZFVkVOVA0KVUlEOjYwNTQwNjE5LTIwMjExMjAyVDA1MDAwMFotMjAyMTEyMDJUMTAw +MDAwWi0wDQpEVFNUQVJUOjIwMjExMjAyVDA1MDAwMFoNClNFUVVFTkNFOjANClRSQU5TUDpPUEFR +VUUNCkRURU5EOjIwMjExMjAyVDEwMDAwMFoNClNVTU1BUlk6RVhBIFRUIyg2MDU0MDYxOSlcLCBQ +bGFubmVkIFdvcmsNCkNMQVNTOlBVQkxJQw0KT1JHQU5JWkVSOkluZnJhQ28uQ01AZXhhaW5mcmEu +bmV0DQpEVFNUQU1QOjIwMjExMTIzVDE0NDk1OFoNCkVORDpWRVZFTlQNCkVORDpWQ0FMRU5EQVI= + +--b1_NhhArHvVcTgy70DuEH3RYcn0mg5DORMTnhJfuXf2E-- diff --git a/tests/unit/data/gtt/gtt7_html_parser_result.json b/tests/unit/data/gtt/gtt7_html_parser_result.json new file mode 100644 index 00000000..a434881a --- /dev/null +++ b/tests/unit/data/gtt/gtt7_html_parser_result.json @@ -0,0 +1,15 @@ +[ + { + "account": "PO # EXA00012345", + "circuits": [ + { + "circuit_id": "1098765-12345678", + "impact": "OUTAGE" + } + ], + "end": 1638439200, + "maintenance_id": "65430585", + "start": 1638421200, + "status": "CONFIRMED" + } +] diff --git a/tests/unit/data/gtt/gtt7_result.json b/tests/unit/data/gtt/gtt7_result.json new file mode 100644 index 00000000..1e4894e8 --- /dev/null +++ b/tests/unit/data/gtt/gtt7_result.json @@ -0,0 +1,21 @@ +[ + { + "account": "PO # EXA00012345", + "circuits": [ + { + "circuit_id": "1098765-12345678", + "impact": "OUTAGE" + } + ], + "end": 1638439200, + "maintenance_id": "65430585", + "organizer": "InfraCo.CM@exainfra.net", + "provider": "gtt", + "sequence": 1, + "stamp": 1637678998, + "start": 1638421200, + "status": "CONFIRMED", + "summary": "", + "uid": "0" + } +] diff --git a/tests/unit/test_e2e.py b/tests/unit/test_e2e.py index bc74586c..da2e55a9 100644 --- a/tests/unit/test_e2e.py +++ b/tests/unit/test_e2e.py @@ -187,6 +187,11 @@ Path(dir_path, "data", "date", "email_date_1_result.json"), ], ), + ( + GTT, + [("email", Path(dir_path, "data", "gtt", "gtt7.eml")),], + [Path(dir_path, "data", "gtt", "gtt7_result.json"),], + ), # HGC ( HGC, diff --git a/tests/unit/test_parsers.py b/tests/unit/test_parsers.py index 442dcc16..aab49c87 100644 --- a/tests/unit/test_parsers.py +++ b/tests/unit/test_parsers.py @@ -149,6 +149,11 @@ Path(dir_path, "data", "gtt", "gtt6.html"), Path(dir_path, "data", "gtt", "gtt6_result.json"), ), + ( + HtmlParserGTT1, + Path(dir_path, "data", "gtt", "gtt7.eml"), + Path(dir_path, "data", "gtt", "gtt7_html_parser_result.json"), + ), # HGC ( HtmlParserHGC1, From bf69a70ef08268c4023bbc2e5ac45d8f6a3437d4 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Thu, 2 Dec 2021 13:01:48 -0500 Subject: [PATCH 02/14] Add changelog for #124 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88748a5d..9cce230c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## v2.0.8 - 2021-MM-DD + +### Fixed + +- #124 - Handle encoded non-ASCII characters in email subjects. + ## v2.0.7 - 2021-12-01 ### Fixed From d8d0ffddfd0c7e83ca87fe63f9dd79be82cbf912 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Fri, 3 Dec 2021 14:38:30 -0500 Subject: [PATCH 03/14] Fix #115: Make 'status' optional, accept iCal notifications with no 'sequence' either --- circuit_maintenance_parser/output.py | 11 +++++++---- circuit_maintenance_parser/parser.py | 8 ++++++-- tests/unit/data/ical/ical6 | 20 ++++++++++++++++++++ tests/unit/data/ical/ical6_result.json | 20 ++++++++++++++++++++ tests/unit/test_output.py | 4 ++-- tests/unit/test_parsers.py | 1 + 6 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 tests/unit/data/ical/ical6 create mode 100644 tests/unit/data/ical/ical6_result.json diff --git a/circuit_maintenance_parser/output.py b/circuit_maintenance_parser/output.py index 9370e5ea..1af4faf9 100644 --- a/circuit_maintenance_parser/output.py +++ b/circuit_maintenance_parser/output.py @@ -37,8 +37,9 @@ class Status(str, Enum): - "CONFIRMED": Indicates maintenance event is definite. - "CANCELLED": Indicates maintenance event was cancelled. - "IN-PROCESS": Indicates maintenance event is in process (e.g. open). - - "COMPLETED":Indicates maintenance event completed (e.g. closed). + - "COMPLETED": Indicates maintenance event completed (e.g. closed). - "RE-SCHEDULED": Indicates maintenance event was re-scheduled. + - "NO-CHANGE": Indicates status is unchanged from a previous notification (dummy value) """ TENTATIVE = "TENTATIVE" @@ -48,6 +49,8 @@ class Status(str, Enum): COMPLETED = "COMPLETED" RE_SCHEDULED = "RE-SCHEDULED" + NO_CHANGE = "NO-CHANGE" + class CircuitImpact(BaseModel, extra=Extra.forbid): """CircuitImpact class. @@ -96,13 +99,13 @@ class Maintenance(BaseModel, extra=Extra.forbid): account: identifies an account associated with the service that is the subject of the maintenance notification maintenance_id: contains text that uniquely identifies the maintenance that is the subject of the notification circuits: list of circuits affected by the maintenance notification and their specific impact - status: defines the overall status or confirmation for the maintenance start: timestamp that defines the start date of the maintenance in GMT end: timestamp that defines the end date of the maintenance in GMT stamp: timestamp that defines the update date of the maintenance in GMT organizer: defines the contact information included in the original notification Optional attributes: + status: defines the overall status or confirmation for the maintenance summary: description of the maintenace notification uid: specific unique identifier for each notification sequence: sequence number - initially zero - to serialize updates in case they are received or processed out of @@ -123,20 +126,20 @@ class Maintenance(BaseModel, extra=Extra.forbid): ... summary="This is a maintenance notification", ... uid="1111", ... ) - Maintenance(provider='A random NSP', account='12345000', maintenance_id='VNOC-1-99999999999', circuits=[CircuitImpact(circuit_id='123', impact=), CircuitImpact(circuit_id='456', impact=)], status=, start=1533704400, end=1533712380, stamp=1533595768, organizer='myemail@example.com', uid='1111', sequence=1, summary='This is a maintenance notification') + Maintenance(provider='A random NSP', account='12345000', maintenance_id='VNOC-1-99999999999', circuits=[CircuitImpact(circuit_id='123', impact=), CircuitImpact(circuit_id='456', impact=)], start=1533704400, end=1533712380, stamp=1533595768, organizer='myemail@example.com', status=, uid='1111', sequence=1, summary='This is a maintenance notification') """ provider: StrictStr account: StrictStr maintenance_id: StrictStr circuits: List[CircuitImpact] - status: Status start: StrictInt end: StrictInt stamp: StrictInt organizer: StrictStr # Non mandatory attributes + status: Status = Status.NO_CHANGE uid: StrictStr = "0" sequence: StrictInt = 1 summary: StrictStr = "" diff --git a/circuit_maintenance_parser/parser.py b/circuit_maintenance_parser/parser.py index f844b728..8711b271 100644 --- a/circuit_maintenance_parser/parser.py +++ b/circuit_maintenance_parser/parser.py @@ -110,14 +110,18 @@ def parse_ical(gcal: Calendar) -> List[Dict]: "provider": str(component.get("X-MAINTNOTE-PROVIDER")), "account": str(component.get("X-MAINTNOTE-ACCOUNT")), "maintenance_id": str(component.get("X-MAINTNOTE-MAINTENANCE-ID")), - "status": Status(component.get("X-MAINTNOTE-STATUS")), + # status may be omitted, per the BCOP + "status": Status(component.get("X-MAINTNOTE-STATUS", "NO-CHANGE")), "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")), "organizer": str(component.get("ORGANIZER")), "uid": str(component.get("UID")), - "sequence": int(component.get("SEQUENCE")), + # per the BCOP sequence is mandatory, but we have real examples where it's omitted, + # usually in combination with an omitted status. In that case let's treat the sequence as -1, + # i.e. older than all known updates. + "sequence": int(component.get("SEQUENCE", -1)), } data = {key: value for key, value in data.items() if value != "None"} diff --git a/tests/unit/data/ical/ical6 b/tests/unit/data/ical/ical6 new file mode 100644 index 00000000..5ca604dc --- /dev/null +++ b/tests/unit/data/ical/ical6 @@ -0,0 +1,20 @@ +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:Data::ICal 0.22 +BEGIN:VEVENT +DESCRIPTION:NTT (AS2914) Regular Maintenance Notification: completed [GIN-C + HG0123456]\nPlease refer to the email notification for more details regard + ing maintenance or outage reason and impact. +DTEND:20211115T205700Z +DTSTAMP:20211115T205904Z +DTSTART:20211115T180000Z +SUMMARY:NTT (AS2914) Regular Maintenance Notification: completed [GIN-CHG01 + 23456] +UID:GIN-CHG0040894 +X-MAINTNOTE-ACCOUNT:47004321 +X-MAINTNOTE-IMPACT:OUTAGE +X-MAINTNOTE-MAINTENANCE-ID:GIN-CHG0123456 +X-MAINTNOTE-OBJECT-ID;X-MAINTNOTE-OBJECT-IMPACT=OUTAGE:246810 +X-MAINTNOTE-PROVIDER:NTT (AS2914) +END:VEVENT +END:VCALENDAR diff --git a/tests/unit/data/ical/ical6_result.json b/tests/unit/data/ical/ical6_result.json new file mode 100644 index 00000000..614f1bbe --- /dev/null +++ b/tests/unit/data/ical/ical6_result.json @@ -0,0 +1,20 @@ +[ + { + "account": "47004321", + "circuits": [ + { + "circuit_id": "246810", + "impact": "OUTAGE" + } + ], + "end": 1637009820, + "maintenance_id": "GIN-CHG0123456", + "provider": "NTT (AS2914)", + "sequence": -1, + "stamp": 1637009944, + "start": 1636999200, + "status": "NO-CHANGE", + "summary": "NTT (AS2914) Regular Maintenance Notification: completed [GIN-CHG0123456]", + "uid": "GIN-CHG0040894" + } +] diff --git a/tests/unit/test_output.py b/tests/unit/test_output.py index b4189887..b972f638 100644 --- a/tests/unit/test_output.py +++ b/tests/unit/test_output.py @@ -35,11 +35,11 @@ ("provider", None, ValidationError), ("provider", 1, ValidationError), ("provider", "good", None), - ("status", None, ValidationError), + # Non mandatory attributes + ("status", None, None), ("status", 1, ValidationError), ("status", "good", ValidationError), ("status", "IN-PROCESS", None), - # Non mandatory attributes ("sequence", None, None), ("sequence", "1", ValidationError), ("sequence", 1, None), diff --git a/tests/unit/test_parsers.py b/tests/unit/test_parsers.py index aab49c87..e99ed856 100644 --- a/tests/unit/test_parsers.py +++ b/tests/unit/test_parsers.py @@ -43,6 +43,7 @@ (ICal, Path(dir_path, "data", "ical", "ical3"), Path(dir_path, "data", "ical", "ical3_result.json"),), (ICal, Path(dir_path, "data", "ical", "ical4"), Path(dir_path, "data", "ical", "ical4_result.json"),), (ICal, Path(dir_path, "data", "ical", "ical5"), Path(dir_path, "data", "ical", "ical5_result.json"),), + (ICal, Path(dir_path, "data", "ical", "ical6"), Path(dir_path, "data", "ical", "ical6_result.json"),), # AquaComms ( HtmlParserAquaComms1, From 99aa2ec25c7f546ce6a4eeb060a3069e93def74b Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Fri, 3 Dec 2021 15:17:39 -0500 Subject: [PATCH 04/14] Add exclude filter for Telia --- circuit_maintenance_parser/provider.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/circuit_maintenance_parser/provider.py b/circuit_maintenance_parser/provider.py index 1189dd69..c3816518 100644 --- a/circuit_maintenance_parser/provider.py +++ b/circuit_maintenance_parser/provider.py @@ -301,6 +301,8 @@ class Sparkle(GenericProvider): class Telia(GenericProvider): """Telia provider custom class.""" + _exclude_filter = {EMAIL_HEADER_SUBJECT: ["Disturbance Information"]} + _default_organizer = "carrier-csc@teliacompany.com" From 6f01221ab57f1719493333890ae96f91224b9d63 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Mon, 6 Dec 2021 08:25:58 -0500 Subject: [PATCH 05/14] Add changelog for #126 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cce230c..2f5abbd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - #124 - Handle encoded non-ASCII characters in email subjects. +- #126 - Ignore a class of non-maintenance-notification emails from Telia. ## v2.0.7 - 2021-12-01 From 6d58d74ea4fb2a443f205bb458655d107c297f93 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Mon, 6 Dec 2021 08:40:33 -0500 Subject: [PATCH 06/14] Add CHANGELOG and update README --- CHANGELOG.md | 1 + README.md | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f5abbd3..b52c352e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixed +- #115 - Add default `status` and `sequence` values for iCal notifications missing these fields - #124 - Handle encoded non-ASCII characters in email subjects. - #126 - Ignore a class of non-maintenance-notification emails from Telia. diff --git a/README.md b/README.md index 917dee8f..d72beeb6 100644 --- a/README.md +++ b/README.md @@ -25,14 +25,24 @@ You can leverage this library in your automation framework to process circuit ma - **account**: identifies an account associated with the service that is the subject of the maintenance notification. - **maintenance_id**: contains text that uniquely identifies the maintenance that is the subject of the notification. - **circuits**: list of circuits affected by the maintenance notification and their specific impact. -- **status**: defines the overall status or confirmation for the maintenance. - **start**: timestamp that defines the start date of the maintenance in GMT. - **end**: timestamp that defines the end date of the maintenance in GMT. - **stamp**: timestamp that defines the update date of the maintenance in GMT. - **organizer**: defines the contact information included in the original notification. +and may additionally contain the following attributes: + +- **status**: defines the overall status or confirmation for the maintenance.¹ +- **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.² +- **summary**: human-readable details about this maintenance notification. +- **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. + > Please, refer to the [BCOP](https://github.com/jda/maintnote-std/blob/master/standard.md) to more details about these attributes. +¹ 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. + +² 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`. + ## Workflow 1. We instantiate a `Provider`, directly or via the `init_provider` method, that depending on the selected type will return the corresponding instance. From cac60ac5db9ee6bd4b756ca977acaa8387617483 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Tue, 7 Dec 2021 11:26:34 -0500 Subject: [PATCH 07/14] Add example of Equinix email without clearly stated status in subject line --- circuit_maintenance_parser/parsers/equinix.py | 11 +- tests/unit/data/equinix/equinix4.eml | 457 ++++++++++++++++++ tests/unit/data/equinix/equinix4_result.json | 13 + .../equinix/equinix4_result_combined.json | 21 + tests/unit/test_e2e.py | 5 + tests/unit/test_parsers.py | 5 + 6 files changed, 510 insertions(+), 2 deletions(-) create mode 100644 tests/unit/data/equinix/equinix4.eml create mode 100644 tests/unit/data/equinix/equinix4_result.json create mode 100644 tests/unit/data/equinix/equinix4_result_combined.json diff --git a/circuit_maintenance_parser/parsers/equinix.py b/circuit_maintenance_parser/parsers/equinix.py index cd0189e9..0455c16a 100644 --- a/circuit_maintenance_parser/parsers/equinix.py +++ b/circuit_maintenance_parser/parsers/equinix.py @@ -112,8 +112,15 @@ def parse_subject(self, subject: str) -> List[Dict]: if maintenance_id: data["maintenance_id"] = maintenance_id[1] data["summary"] = subject.strip().replace("\n", "") - if "COMPLETED" in subject: + if "completed" in subject.lower(): data["status"] = Status.COMPLETED - if "SCHEDULED" in subject or "REMINDER" in subject: + elif "rescheduled" in subject.lower(): + data["status"] = Status.RE_SCHEDULED + elif "scheduled" in subject.lower() or "reminder" in subject.lower(): data["status"] = Status.CONFIRMED + else: + # Some Equinix notifications don't clearly state a status in their subject. + # From inspection of examples, it looks like "Confirmed" would be the most appropriate in this case. + data["status"] = Status.CONFIRMED + return [data] diff --git a/tests/unit/data/equinix/equinix4.eml b/tests/unit/data/equinix/equinix4.eml new file mode 100644 index 00000000..117964fc --- /dev/null +++ b/tests/unit/data/equinix/equinix4.eml @@ -0,0 +1,457 @@ +Delivered-To: nautobot.email@example.com +Received: by 2002:a05:7000:1f21:0:0:0:0 with SMTP id hs33csp4865244mab; + Mon, 6 Dec 2021 07:03:42 -0800 (PST) +X-Received: by 2002:a05:6512:1093:: with SMTP id j19mr36120315lfg.340.1638803022202; + Mon, 06 Dec 2021 07:03:42 -0800 (PST) +ARC-Seal: i=3; a=rsa-sha256; t=1638803022; cv=pass; + d=google.com; s=arc-20160816; + b=wFeh1i2FgY4zIP6j6JX7ur5ZxGySWbBOmnEAqWt0efhNZHYO7dYGGvhd+ew5J3hyei + rYIeHM7bJYqloB8pv3fbFOpOyOoSdpOeuFPZuTdOpn8s/YQKFpkD/cXdM6+EL6ae0MPR + Qg4lggMLqctIFDxGJKkUiFKF11IGdZcGhL/HZKUqAyD4QaxNbhJymBi3cIeSWv9YxMri + mGcZNsMuLpD6DCsn7J8NmL8DIt+VIPhqJNnSqZRtNCiLI4EmOO8e6S5sDItfGMp8qerx + /4GLV4ERMmeiSteVAEUoDSvXyCdbqODitCSRpwwY4Duf24EQPoWR9ZNE9R4rjuwSv+Ft + lAZQ== +ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=list-unsubscribe:list-archive:list-help:list-post:list-id + :mailing-list:precedence:organization:mime-version:subject + :message-id:to:reply-to:from:date:sender:dkim-signature; + bh=R0VYk2ZSiBDs7fEF522bB6CVP+jkmxIwlo7fEz5wuM4=; + b=Ndvx3ze2TJi6Z7rrImATCyNxDPIBXLrGNBZFJfxOY1TjGJsO1P/c8v6yvEkJyveDBS + HeFYmsVCII+50ma0RwRrE6igvgp81wQsAfD09TXnadgzBbsal/u/TKBXpakvfmBOXieU + vhf/dneaion+l9cnWbrAZxgCeErZk4YcvcA/XOAXUQvmz+q3rEClsXy4qxpRRIDY9bIj + XiEcQ8cIyVmLjJkfMg/+8FxjlJz+oEVdCMciM/TbiI+IXDmWCW2nNT7kxmTZq5DrSLS/ + SrCqESUPMngmI+TDZLbqQk0hA/hAqv0tBP/LKtS3blFKnByaE2XqDDnc74/xqOGs0tcN + LQ0g== +ARC-Authentication-Results: i=3; mx.google.com; + dkim=pass header.i=@example.com header.s=example header.b=jlMpGX2M; + arc=pass (i=2 spf=pass spfdomain=equinix.com dmarc=pass fromdomain=equinix.com); + spf=pass (google.com: domain of maint-notices+bncbdbld5ph4eibbtomxcgqmgqeyrh3nsy@example.com designates 209.85.220.69 as permitted sender) smtp.mailfrom=maint-notices+bncBDBLD5PH4EIBBTOMXCGQMGQEYRH3NSY@example.com; + dmarc=fail (p=NONE sp=NONE dis=NONE arc=pass) header.from=equinix.com +Return-Path: +Received: from mail-sor-f69.google.com (mail-sor-f69.google.com. [209.85.220.69]) + by mx.google.com with SMTPS id 124sor4230631vkb.28.2021.12.06.07.03.41 + for + (Google Transport Security); + Mon, 06 Dec 2021 07:03:42 -0800 (PST) +Received-SPF: pass (google.com: domain of maint-notices+bncbdbld5ph4eibbtomxcgqmgqeyrh3nsy@example.com designates 209.85.220.69 as permitted sender) client-ip=209.85.220.69; +Authentication-Results: mx.google.com; + dkim=pass header.i=@example.com header.s=example header.b=jlMpGX2M; + arc=pass (i=2 spf=pass spfdomain=equinix.com dmarc=pass fromdomain=equinix.com); + spf=pass (google.com: domain of maint-notices+bncbdbld5ph4eibbtomxcgqmgqeyrh3nsy@example.com designates 209.85.220.69 as permitted sender) smtp.mailfrom=maint-notices+bncBDBLD5PH4EIBBTOMXCGQMGQEYRH3NSY@example.com; + dmarc=fail (p=NONE sp=NONE dis=NONE arc=pass) header.from=equinix.com +ARC-Seal: i=2; a=rsa-sha256; t=1638803021; cv=pass; + d=google.com; s=arc-20160816; + b=mTB+fBQ+mIfJnTasYRtWnDI7MwI+p8gC+KuU6BNv5TUAm3M9nr6Aq5cccMfTWkzvTP + nXMMEH5AAwpNEXHQP7XzGvQLv7cxOIY5g7B1v1KLpdtrU8dZkoNMUqs3BmpEdBOhujX8 + sOQ9lMBjF8efEJ48x9Ot0B2te1Nzj0+eNS/dymp138OuSdbINbVTxiuqcwlZ97JXOCL8 + zbNpaKgtjmBvsPkCh6otz4BiZmQDOXgV/dEWqJEFzVGc0le8LfWZBCwnZYhVzEyyTPtW + AI5NLZDdqUOjTxLMbY6y4kM1Kyg5EL4hAvSGR01JPdOiH5to3A8DQ2MhnpfQmADTuK7T + bsnA== +ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=list-unsubscribe:list-archive:list-help:list-post:list-id + :mailing-list:precedence:organization:mime-version:subject + :message-id:to:reply-to:from:date:sender:dkim-signature; + bh=R0VYk2ZSiBDs7fEF522bB6CVP+jkmxIwlo7fEz5wuM4=; + b=FVNVdWQeZml1pbbmGemW1a1Cq75xibwRVddCm3xjJO1xlxghswE2i3R8LGGVbTrMl5 + +6D8tVuVs/g1Auezvs6Gj7ZCGTPa2DTmSvcMGxczjVgY8qaYvB2TEJUNdCyrtrv6i1bL + 6mJO0TZbBUbaIAo2Thr4kMOA62UI4s8fufSoKIcFdKXD6Si+1d8Ug2yeztB9IYcbQTcR + iUF3kWSGl4F7VT1tKa0+qK9IEJ+TOyXZFNivxD8bylX/aqvZ/haEaqFZJAw5wBWA+HI0 + 2/7voD6JAa4IJSk3dNaX87Pdhs1WcxlOKAalgsCNVuSeN96kc5FdN0PGV+kFxfl42uy4 + BUow== +ARC-Authentication-Results: i=2; mx.google.com; + spf=pass (google.com: domain of no-reply@equinix.com designates 64.191.227.129 as permitted sender) smtp.mailfrom=no-reply@equinix.com; + dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=equinix.com +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=example.com; s=example; + h=sender:date:from:reply-to:to:message-id:subject:mime-version + :organization:x-original-sender:x-original-authentication-results + :precedence:mailing-list:list-id:list-post:list-help:list-archive + :list-unsubscribe; + bh=R0VYk2ZSiBDs7fEF522bB6CVP+jkmxIwlo7fEz5wuM4=; + b=jlMpGX2M3S6PHG8oE6631CVzWVoLPWcnDiCH83EQ67YXX9rVvz/SuZjPIhjApqYYu5 + J7w8XkeAXAQWJAKbr9IE4AUJ7nA8kLZU/ZP7lAxPTQsM7MFRXdvqw5+xg6R0sk5Pr1uq + 1g3JmWdiVAZKEipEq7H5N1a8K7kNOu27R14yQ= +X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; + d=1e100.net; s=20210112; + h=sender:x-gm-message-state:date:from:reply-to:to:message-id:subject + :mime-version:organization:x-original-sender + :x-original-authentication-results:precedence:mailing-list:list-id + :x-spam-checked-in-group:list-post:list-help:list-archive + :list-unsubscribe; + bh=R0VYk2ZSiBDs7fEF522bB6CVP+jkmxIwlo7fEz5wuM4=; + b=N8yb6kiuCXL7WSYeD60M6aEx67Y7+KXKIlZawUJAzZ71rQaqfnferFxPvZAop+p4/H + Uhj0PghDskYHNkR0vbUOUty842JNIbYOI2S+FrHs/cfdLqHNwNwiv8N5OWdczAUqMDOc + aD0iGBk1A/YucqKtrGqpoNDmiUMDb8bcVqEvx1Tmhs4cIl1fzPTZkvJQZXed4dXQFNUg + B7w2DPNH7+gpm2xETc2XU78kvoopKl4Uqtg3va9ntDl47p7QQ/RH65GOKonIfy6w5sZ7 + UZZVHPP+L/QUA7y1NDHBSVlQWFNiLYCo9tviITATZJWR6NzUpNhHELwMzcErRlhwjxHA + gsNg== +Sender: maint-notices@example.com +X-Gm-Message-State: AOAM533VjlUj/LnFyQw6o0/xeOuSqlLm74Eu6fwRVVfPgXTuX5AJXBcT + cAvJNZpcyEL49FDqjsEE1/LPLlro +X-Google-Smtp-Source: ABdhPJy6PqBs7zFjsCpnVPD/K3IQt2HloRSlQiCjXVwxBKRb7W8g+KhWJ4iR4IeVft1P+Iihq/Xk8Q== +X-Received: by 2002:ac5:cfca:: with SMTP id m10mr41966216vkf.29.1638803021272; + Mon, 06 Dec 2021 07:03:41 -0800 (PST) +X-BeenThere: maint-notices@example.com +Received: by 2002:a05:6102:41a6:: with SMTP id cd38ls5065354vsb.5.gmail; Mon, + 06 Dec 2021 07:03:40 -0800 (PST) +X-Received: by 2002:a05:6102:38ce:: with SMTP id k14mr35991447vst.70.1638803019627; + Mon, 06 Dec 2021 07:03:39 -0800 (PST) +ARC-Seal: i=1; a=rsa-sha256; t=1638803019; cv=none; + d=google.com; s=arc-20160816; + b=s3eQTgOQyndq/+00IH3QWxfI3Sb794jyPwy9/dMYijX8Kp1EcV7v5lTcym69+eKGbU + ZhiI4fVygo80ZL2Sx9GMeO4aT8gWQgzZBSVsumL+zhCdTrXhSQSd05XRX6Ywnlh/S7x8 + 3qxD97RjdTHySFLVoPSg5sd7T51MqRE4Uo4gUcuypm9uMlwyeeC+Zxguk5/1/+03+VXO + bkzvp/wOVAy7OK/H3G7SGUXqQ7L2CchMSHVS/mDrEC7dbPSIzPtMErC1ZG6V6KNHZDoC + O5KSfTGdGPjsYYxb30dTL0fqdfvLqWB7IO2fNA2Hbz5JSIPgGRncY7W8BP3PnfPqQpQB + zryg== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=organization:mime-version:subject:message-id:to:reply-to:from:date; + bh=KXImSC2nRLcb870x1UBCENwiwa6LLafq6KrnTRpMeMA=; + b=z4xTPHCi+j6NfccgK7zZUYlAytL9/xoM2BFIMfBxIvleq6rxXKZ4moL0K0Bm/iizZD + ozEFUQNVsO9Xf0KoA6al8wvHH0v0UnFgcjtK77+cWFR3uabcp3jcny2F66YO3d/3INwH + BLXoi92zLlitD+y7UF3rGhjdArYUGgQPxiL/K5I9k1hvnkG7zvdNNdONiVwHJz1Msj7H + drP+Z/SRjhrnSqZbPHEc3dZSC18uUW0U6tc+lV/qzn+rcplbH9/LJ35U21TLTnKibM88 + PKoIN+w96weW4/fLbXnQmFDFpuLYIDlPicnd+kvrdXhMoLv/SBtz+h9Qf4zxQ1FqwZHD + zz0Q== +ARC-Authentication-Results: i=1; mx.google.com; + spf=pass (google.com: domain of no-reply@equinix.com designates 64.191.227.129 as permitted sender) smtp.mailfrom=no-reply@equinix.com; + dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=equinix.com +Received: from ch3esa01.corp.equinix.com (nat1-ch-mis.equinix.com. [64.191.227.129]) + by mx.google.com with ESMTPS id n9si10427993vse.680.2021.12.06.07.03.24 + (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); + Mon, 06 Dec 2021 07:03:39 -0800 (PST) +Received-SPF: pass (google.com: domain of no-reply@equinix.com designates 64.191.227.129 as permitted sender) client-ip=64.191.227.129; +Received: from unknown (HELO vmclxremas08.corp.equinix.com) ([10.192.140.2]) + by ch3esa01.corp.equinix.com with ESMTP; 06 Dec 2021 07:03:22 -0800 +Date: Mon, 6 Dec 2021 15:03:22 +0000 (UTC) +From: Equinix Network Maintenance NO-REPLY +Reply-To: Equinix Network Maintenance NO-REPLY +To: "EquinixNetworkMaintenance.SE" +Message-ID: <382392005.90948.1638803002267@vmclxremas08.corp.equinix.com> +Subject: [maint-notices] 3rd Party SK Maintenance-SK Metro Area Network + Maintenance -17-DEC-2021 [5-210987654321] +MIME-Version: 1.0 +Content-Type: multipart/alternative; + boundary="----=_Part_90947_625377126.1638803002267" +X-Priority: 1 +Organization: Equinix, Inc +X-Original-Sender: no-reply@equinix.com +X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: + domain of no-reply@equinix.com designates 64.191.227.129 as permitted sender) + smtp.mailfrom=no-reply@equinix.com; dmarc=pass (p=NONE sp=NONE + dis=NONE) header.from=equinix.com +Precedence: list +Mailing-list: list maint-notices@example.com; contact maint-notices+owners@example.com +List-ID: +X-Spam-Checked-In-Group: maint-notices@example.com +X-Google-Group-Id: 536184160288 +List-Post: , +List-Help: , + +List-Archive: +List-Unsubscribe: , + + +------=_Part_90947_625377126.1638803002267 +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + + Dear Equinix Customer, + +DATE: 17-DEC-2021 + +SPAN: 17-DEC-2021 - 17-DEC-2021 + +LOCAL: FRIDAY, 17 DEC 00:01 - FRIDAY, 17 DEC 06:00 +UTC: THURSDAY, 16 DEC 23:01 - FRIDAY, 17 DEC 05:00 + +IBX(s): SK2,SK3 + + DESCRIPTION:Please be advised that our provider will perform maintenance w= +orks that will cause a loss of redundancy for your services. + +PRODUCTS: EQUINIX FABRIC, INTERNET EXCHANGE, METRO CONNECT + +IMPACT: Loss of redundancy to your service + + +Internet Exchange Account # Product Servi= +ce Serial # 309876 Internet Exchange 20987564= + =09 +=20 + +We apologize for any inconvenience you may experience during this activity.= + Your cooperation and understanding are greatly appreciated. + +The Equinix SMC is available to provide up-to-date status information or ad= +ditional details, should you have any questions regarding the maintenance. = + Please reference 5-210987654321.=20 + +v=C3=A4nliga h=C3=A4lsningar/Sincerely, +Equinix SMC + + =20 +Contacts: +To place orders, schedule site access, report trouble or manage your user l= +ist online, please visit: http://www.equinix.com/contact-us/customer-suppor= +t/=20 +Please do not reply to this email address. If you have any questions or con= +cerns regarding this notification, please email Service Desk and include th= +e ticket [5-210987654321] in the subject line. If the matter is urgent, you= + may contact the Equinix Service Desk SE by phone at +46 8 446 866 08 for = +an up-to-date status. + +To unsubscribe from notifications, please log in to the Equinix Customer Po= +rtal and change your preferences. + +How are we doing? Tell Equinix - We're Listening. E Q U= + I N I X (Sweden) Ltd | Kvastv=C3=A4gen 25-29, 128 62 Sk=C3=B6ndal, St= +ockholm, Sweden | www.equinix.com =C2=A9 2021 Equinix, Inc. Al= +l rights reserved.| Legal | Privacy + +--=20 +You received this message because you are subscribed to the Google Groups "= +Maintenance Notices" group. +To unsubscribe from this group and stop receiving emails from it, send an e= +mail to maint-notices+unsubscribe@example.com. +To view this discussion on the web visit https://groups.google.com/a/exampl= +e.com/d/msgid/maint-notices/382392005.90948.1638803002267%40vmclxremas08.cor= +p.equinix.com. + +------=_Part_90947_625377126.1638803002267 +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: quoted-printable + + + + + + + + + + + + + +
+ + + + +
+ +
3D"Meet +
+
+ + + + + + +
  + +
+

+Dear Equinix Customer,
+
+DATE: 17-DEC-2021
+
+SPAN: 17-DEC-2021 - 17-DEC-2021
+
+LOCAL: FRIDAY, 17 DEC 00:01 - FRIDAY, 17 DEC 06:00
+UTC: THURSDAY, 16 DEC 23:01 - FRIDAY, 17 DEC 05:00
+
+IBX(s): SK2,SK3
+
+ +DESCRIPTION:Please be advised that our provider will perform mainten= +ance works that will cause a loss of redundancy for your services.
+
+PRODUCTS: EQUINIX FABRIC, INTERNET EXCHANGE, METRO CONNECT
+
+IMPACT: Loss of redundancy to your service
+
+
+ Internet Exchange +=09 + +

+ + + + + + + + + + +
Account #ProductService Serial #
309876Internet Exchange20987564
+
+ +

We apologize for any inconvenience you may experience during t= +his activity. Your cooperation and understanding are greatly appreciated.<= +br />
The Equinix SMC is available to provide up-to-date status info= +rmation or additional details, should you have any questions regarding the = +maintenance. Please reference 5-210987654321.
+
+v=C3=A4nliga h=C3=A4lsningar/Sincerely,
Equinix SMC

<= +/span>

Contacts:

To place orders, schedule site access, report trouble or= + manage your user list online, please visit: http://www.equinix.com/contact-us/custom= +er-support/

Please do not reply to this email address. If y= +ou have any questions or concerns regarding this notification, please email= + Service Desk and include th= +e ticket [5-210987654321] in the subject line. If the matter is urgent, you= + may contact the Equinix Service Desk SE by phone at +46 8 446 866 08 for = +an up-to-date status.


+
To unsubscribe from notifications, please log in to the E= +quinix Customer Portal and change your preferences.

+
+
+
+
+

 

+
+
+ + + +
3D"Equinix" + + + +
How are we doi= +ng? Tell Equinix - We're Listening. + +  +
+
 
+
+ + + + + +
+ + + + + +
+ + + + + + +
= +E Q U I N I X (Sweden) Ltd   |   Kvastv=C3=A4gen 25-29, 128 62 Sk=C3=B6ndal, Stockholm, Sw= +eden +   |   www.equinix.com
+
© 2021 Eq= +uinix, Inc. All rights reserved.| Legal | Priva= +cy +
+ + + + + + +

+ +--
+You received this message because you are subscribed to the Google Groups &= +quot;Maintenance Notices" group.
+To unsubscribe from this group and stop receiving emails from it, send an e= +mail to maint-notices+= +unsubscribe@example.com.
+To view this discussion on the web visit https://gr= +oups.google.com/a/example.com/d/msgid/maint-notices/382392005.90948.16388030= +02267%40vmclxremas08.corp.equinix.com.
+ +------=_Part_90947_625377126.1638803002267-- diff --git a/tests/unit/data/equinix/equinix4_result.json b/tests/unit/data/equinix/equinix4_result.json new file mode 100644 index 00000000..f0534470 --- /dev/null +++ b/tests/unit/data/equinix/equinix4_result.json @@ -0,0 +1,13 @@ +[ + { + "account": "309876", + "circuits": [ + { + "circuit_id": "20987564", + "impact": "REDUCED-REDUNDANCY" + } + ], + "end": 1639717200, + "start": 1639695660 + } +] diff --git a/tests/unit/data/equinix/equinix4_result_combined.json b/tests/unit/data/equinix/equinix4_result_combined.json new file mode 100644 index 00000000..a39fa9af --- /dev/null +++ b/tests/unit/data/equinix/equinix4_result_combined.json @@ -0,0 +1,21 @@ +[ + { + "account": "309876", + "circuits": [ + { + "circuit_id": "20987564", + "impact": "REDUCED-REDUNDANCY" + } + ], + "end": 1639717200, + "maintenance_id": "5-210987654321", + "organizer": "servicedesk@equinix.com", + "provider": "equinix", + "sequence": 1, + "stamp": 1638803002, + "start": 1639695660, + "status": "CONFIRMED", + "summary": "[maint-notices] 3rd Party SK Maintenance-SK Metro Area Network Maintenance -17-DEC-2021 [5-210987654321]", + "uid": "0" + } +] diff --git a/tests/unit/test_e2e.py b/tests/unit/test_e2e.py index da2e55a9..1c8e98ba 100644 --- a/tests/unit/test_e2e.py +++ b/tests/unit/test_e2e.py @@ -112,6 +112,11 @@ [("email", Path(dir_path, "data", "equinix", "equinix3.eml"))], [Path(dir_path, "data", "equinix", "equinix3_result_combined.json")], ), + ( + Equinix, + [("email", Path(dir_path, "data", "equinix", "equinix4.eml"))], + [Path(dir_path, "data", "equinix", "equinix4_result_combined.json")], + ), # EUNetworks (EUNetworks, [("ical", GENERIC_ICAL_DATA_PATH),], [GENERIC_ICAL_RESULT_PATH,],), # EXA / GTT diff --git a/tests/unit/test_parsers.py b/tests/unit/test_parsers.py index e99ed856..7620e80d 100644 --- a/tests/unit/test_parsers.py +++ b/tests/unit/test_parsers.py @@ -119,6 +119,11 @@ Path(dir_path, "data", "equinix", "equinix3.eml"), Path(dir_path, "data", "equinix", "equinix3_result.json"), ), + ( + HtmlParserEquinix, + Path(dir_path, "data", "equinix", "equinix4.eml"), + Path(dir_path, "data", "equinix", "equinix4_result.json"), + ), # GTT ( HtmlParserGTT1, From 35dcb301e07c4a67470185e7b868d7dd36325055 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Tue, 7 Dec 2021 11:46:56 -0500 Subject: [PATCH 08/14] Add 'Cancelled' status for Lumen --- circuit_maintenance_parser/parsers/lumen.py | 2 +- tests/unit/data/lumen/lumen7.html | 181 ++++++++++++++++++++ tests/unit/data/lumen/lumen7_result.json | 17 ++ tests/unit/test_parsers.py | 5 + 4 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 tests/unit/data/lumen/lumen7.html create mode 100644 tests/unit/data/lumen/lumen7_result.json diff --git a/circuit_maintenance_parser/parsers/lumen.py b/circuit_maintenance_parser/parsers/lumen.py index bf87f973..eb0ca468 100644 --- a/circuit_maintenance_parser/parsers/lumen.py +++ b/circuit_maintenance_parser/parsers/lumen.py @@ -93,7 +93,7 @@ def parse_tables(self, tables: ResultSet, data: Dict): data["status"] = Status("COMPLETED") elif status_string == "Postponed": data["status"] = Status("RE-SCHEDULED") - elif status_string == "Not Completed": + elif status_string in ["Not Completed", "Cancelled"]: data["status"] = Status("CANCELLED") elif status_string == "Alternate Night": data["status"] = Status("RE-SCHEDULED") diff --git a/tests/unit/data/lumen/lumen7.html b/tests/unit/data/lumen/lumen7.html new file mode 100644 index 00000000..76567d8f --- /dev/null +++ b/tests/unit/data/lumen/lumen7.html @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+     3D"Lumen" +
+
+ +Scheduled Maintenance #: 23456789 +

+Summary: +


+Dear customer, we hereby inform you about this corrective activity performe= +d by our Third Party. We apologize for the inconvenience that this may caus= +e. +
+
It is require replace a equipment, in order to guarantee the stability = +and continuity of the services. +
+
We appreciate your understanding in allowing us to improve every day th= +e provision of telecommunications services that we provide. +
+

+Updates: +

+2021-12-01 15:50:45 GMT - Please be advised that this maintenance has been = +cancelled.
+
+ +Customer Impact: +

+

23456789-1<= +/span>
StartEnd
2= +021-11-05 06:00 GMT (Greenwich Mean Time)2021-11-05 12:00 GMT (Gre= +enwich Mean Time)
2021-11-05 00:00 CST (Central Standard T= +ime)2021-11-05 06:00 CST (Central Standard Time)
= +

Maintenance Location(s): Ciu= +dad de M=C3=A9xico Mexico

Customer NameCircuit IDAlt Circuit IDBandwidthA LocationZ LocationImpact TypeMaxim= +um DurationOrder NumberStatusSOME CUSTOMER INC,= + INC.2006789012N/A10GIGSOME CUSTOMER IN= +C, INC MIAMI FL USASOME CUSTOMER INC, INC CIUDAD DE MEXICO MEXICO<= +/td>Outage2 hours  Cancelled<= +/table>
+

+ +Notes History: +

+2021-12-01 15:50:45 GMT - Please be advised that this maintenance has been = +cancelled.
2021-11-05 12:58:30 GMT - This maintenance has been = +postponed due to vendor issue. Once a new date is determined, upda= +ted notifications will be sent reflecting the date change.
2021-10-28 2= +2:42:06 GMT - This maintenance is scheduled.
+

+Click here for immediate information on scheduled maintenances via the = +Lumen Customer Portal. + +

+Click here to manage your notification subscriptions via the Lumen Cust= +omer Potral. + +

+Click here to open a case for assistance on this scheduled maintenance = +via the Lumen Customer Portal. +

+Network Change Management Team +
+Lumen +
+ +Click here=20 + +for Latin America contact numbers +
+ +Change.Management.LATAM@Lumen.com + +

+Lumen and its logos are registered trademarks of Lumen in the United States= + and other countries. +
+Your privacy is important to us. +
+Please review the Lumen Online Privacy Policy by clicking on: +
+ +http://www.level3.com/en/network-security/ + +

+The information in this communication is confidential and may not be disclo= +sed to=20 +third parties or shared further without the express permission of Lumen. + +

diff --git a/tests/unit/data/lumen/lumen7_result.json b/tests/unit/data/lumen/lumen7_result.json new file mode 100644 index 00000000..a5d6c4d7 --- /dev/null +++ b/tests/unit/data/lumen/lumen7_result.json @@ -0,0 +1,17 @@ +[ + { + "account": "SOME CUSTOMER INC, INC.", + "circuits": [ + { + "circuit_id": "2006789012", + "impact": "OUTAGE" + } + ], + "end": 1636113600, + "maintenance_id": "23456789", + "stamp": 1638373845, + "start": 1636092000, + "status": "CANCELLED", + "summary": "Dear customer, we hereby inform you about this corrective activity performed by our Third Party. We apologize for the inconvenience that this may cause." + } +] diff --git a/tests/unit/test_parsers.py b/tests/unit/test_parsers.py index 7620e80d..f461dd75 100644 --- a/tests/unit/test_parsers.py +++ b/tests/unit/test_parsers.py @@ -202,6 +202,11 @@ Path(dir_path, "data", "lumen", "lumen6.html"), Path(dir_path, "data", "lumen", "lumen6_result.json"), ), + ( + HtmlParserLumen1, + Path(dir_path, "data", "lumen", "lumen7.html"), + Path(dir_path, "data", "lumen", "lumen7_result.json"), + ), # Megaport ( HtmlParserMegaport1, From a38ee775202fe782aa8a885a04a5531509ffd4f0 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Tue, 7 Dec 2021 11:51:02 -0500 Subject: [PATCH 09/14] Partial reversion of #125 - restore Status as a mandatory field on Maintenance object --- circuit_maintenance_parser/output.py | 2 +- tests/unit/test_output.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/circuit_maintenance_parser/output.py b/circuit_maintenance_parser/output.py index 1af4faf9..00232ed8 100644 --- a/circuit_maintenance_parser/output.py +++ b/circuit_maintenance_parser/output.py @@ -137,9 +137,9 @@ class Maintenance(BaseModel, extra=Extra.forbid): end: StrictInt stamp: StrictInt organizer: StrictStr + status: Status # Non mandatory attributes - status: Status = Status.NO_CHANGE uid: StrictStr = "0" sequence: StrictInt = 1 summary: StrictStr = "" diff --git a/tests/unit/test_output.py b/tests/unit/test_output.py index b972f638..b4189887 100644 --- a/tests/unit/test_output.py +++ b/tests/unit/test_output.py @@ -35,11 +35,11 @@ ("provider", None, ValidationError), ("provider", 1, ValidationError), ("provider", "good", None), - # Non mandatory attributes - ("status", None, None), + ("status", None, ValidationError), ("status", 1, ValidationError), ("status", "good", ValidationError), ("status", "IN-PROCESS", None), + # Non mandatory attributes ("sequence", None, None), ("sequence", "1", ValidationError), ("sequence", 1, None), From 6dbcc532a5bacf518a90c075cee9dcb2b9b3a6f8 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Tue, 7 Dec 2021 11:57:17 -0500 Subject: [PATCH 10/14] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b52c352e..885037fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - #115 - Add default `status` and `sequence` values for iCal notifications missing these fields - #124 - Handle encoded non-ASCII characters in email subjects. - #126 - Ignore a class of non-maintenance-notification emails from Telia. +- #127 - Improve handling of Equinix and Lumen notifications. ## v2.0.7 - 2021-12-01 From 9a996170624ad93cc78e859dd434dc946c036f9f Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Wed, 8 Dec 2021 08:20:40 -0500 Subject: [PATCH 11/14] Update README --- README.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d72beeb6..5c9c2816 100644 --- a/README.md +++ b/README.md @@ -19,29 +19,26 @@ during a NANOG meeting that aimed to promote the usage of the iCalendar format. 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 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: +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: - **provider**: identifies the provider of the service that is the subject of the maintenance notification. - **account**: identifies an account associated with the service that is the subject of the maintenance notification. -- **maintenance_id**: contains text that uniquely identifies the maintenance that is the subject of the notification. +- **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. - **circuits**: list of circuits affected by the maintenance notification and their specific impact. -- **start**: timestamp that defines the start date of the maintenance in GMT. -- **end**: timestamp that defines the end date of the maintenance in GMT. -- **stamp**: timestamp that defines the update date of the maintenance in GMT. +- **start**: timestamp that defines the starting date/time of the maintenance in GMT. +- **end**: timestamp that defines the ending date/time of the maintenance in GMT. +- **stamp**: timestamp that defines the update date/time of the maintenance in GMT. - **organizer**: defines the contact information included in the original notification. - -and may additionally contain the following attributes: - - **status**: defines the overall status or confirmation for the maintenance.¹ -- **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.² -- **summary**: human-readable details about this maintenance notification. -- **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. +- **summary**: human-readable details about this maintenance notification. May be an empty string. +- **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.² +- **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. -> Please, refer to the [BCOP](https://github.com/jda/maintnote-std/blob/master/standard.md) to more details about these attributes. +> 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. -¹ 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. +¹ 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. -² 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`. +² 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`. ## Workflow From ac144939e4ed72a007ed77aa110e532e39f5dadb Mon Sep 17 00:00:00 2001 From: pke11y Date: Thu, 9 Dec 2021 15:05:51 +0000 Subject: [PATCH 12/14] Add Verizon Reschedule Status (#128) * Add rescheduled status for Verizon * Remove space from summary * Update CHANGELOG Co-authored-by: Glenn Matthews --- CHANGELOG.md | 1 + circuit_maintenance_parser/parsers/verizon.py | 4 +++- tests/unit/data/verizon/verizon4.html | 1 + tests/unit/data/verizon/verizon4_result.json | 20 +++++++++++++++++++ tests/unit/test_parsers.py | 5 +++++ 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/unit/data/verizon/verizon4.html create mode 100644 tests/unit/data/verizon/verizon4_result.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 885037fc..b0bce148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - #124 - Handle encoded non-ASCII characters in email subjects. - #126 - Ignore a class of non-maintenance-notification emails from Telia. - #127 - Improve handling of Equinix and Lumen notifications. +- #128 - Add capability to set `RE-SCHEDULED` status for Verizon rescheduled notifications. ## v2.0.7 - 2021-12-01 diff --git a/circuit_maintenance_parser/parsers/verizon.py b/circuit_maintenance_parser/parsers/verizon.py index 5a8fcb74..27cf741c 100644 --- a/circuit_maintenance_parser/parsers/verizon.py +++ b/circuit_maintenance_parser/parsers/verizon.py @@ -42,12 +42,14 @@ def parse_tables(self, tables: ResultSet, data: Dict): # pylint: disable=too-ma if not cells_text: continue if cells_text[0].startswith("Description of Maintenance"): - data["summary"] = cells_text[1] + data["summary"] = cells_text[1].replace(" ", "") elif cells_text[0].startswith("Verizon MASTARS Request number:"): data["maintenance_id"] = cells_text[1] elif cells_text[0].startswith("Attention:"): if "maintenance was not completed" in cells_text[0]: data["status"] = Status("CANCELLED") + elif "request has been rescheduled" in cells_text[0]: + data["status"] = Status("RE-SCHEDULED") elif cells_text[0].startswith("Maintenance Date/Time (GMT):"): maintenance_time = cells_text[1].split("-") start = parser.parse(maintenance_time[0].strip()) diff --git a/tests/unit/data/verizon/verizon4.html b/tests/unit/data/verizon/verizon4.html new file mode 100644 index 00000000..5c730380 --- /dev/null +++ b/tests/unit/data/verizon/verizon4.html @@ -0,0 +1 @@ +
[ EXTERNAL ]

ENGLISH

logo

Verizon Maintenance Notification

Dear Verizon Customer,

I’d like to take this opportunity to thank you for being a Verizon Customer, and to update you on maintenance work that will be carried out on the Verizon network. Verizon will be performing maintenance activities, utilizing proven methods, in a manner to ensure the best performance for your connection. The maintenance window is from Dec 7 2021 04:00 GMT - Dec 7 2021 10:00 GMT , however your expected circuit downtime within this window to be 10 Minute(s). Below you will find more detailed information as it relates to the impact to your environment.

If you have questions regarding this maintenance event, please contact Verizon’s Global Event Management Center at email GEMC@VERIZON.COM.

For those customers with a defined Account Team or Technical Service Manager, please refer all circuit-based questions to your Verizon Account Representative.  

NOTE: If your circuit remains down after the maintenance window has passed, please follow your defined Verizon Repair Center process for investigation.

We appreciate your cooperation and understanding in this matter. Verizon’s goal is to provide you with exceptional service every day, in every interaction. Thank you once again for your business, and your partnership.

Regards,

Global Event Management Center

GEMC.Leadership@verizon.com

Attention: This request has been rescheduled from Dec 07 2021 19:00 GMT to Dec 07 2021 04:00 GMT

Contact ID:            773101

Maintenance Date/Time (Local):

Dec 7 2021 04:00 GMT - Dec 7 2021 10:00 GMT

Maintenance Date/Time (GMT):

Dec 7 2021 04:00 GMT - Dec 7 2021 10:00 GMT

Maintenance Location:

SYDNEY, AUSTRALIA

Description of Maintenance:

DEMAND MAINTENANCE: A Third Party vendor will be performing scheduled network maintenance.

Planned Circuit Downtime:

10 Minute(s)

Verizon MASTARS Request number:

987654321-1

Verizon MASTARS Event id:

987654321-1

Circuits Affected:

Company NameCircuit IDZ EndBilling IDDNS Short NameServiceType

ACMEC12345678N/ASG000000acme-corp-123456PIP

ACMEE23456789SYDNEY/td>SG0000000acme-corp-123456UNI

\ No newline at end of file diff --git a/tests/unit/data/verizon/verizon4_result.json b/tests/unit/data/verizon/verizon4_result.json new file mode 100644 index 00000000..03b20fb4 --- /dev/null +++ b/tests/unit/data/verizon/verizon4_result.json @@ -0,0 +1,20 @@ +[ + { + "account": "Verizon Customer", + "circuits": [ + { + "circuit_id": "C12345678", + "impact": "OUTAGE" + }, + { + "circuit_id": "E23456789", + "impact": "OUTAGE" + } + ], + "end": 1638871200, + "maintenance_id": "987654321-1", + "start": 1638849600, + "status": "RE-SCHEDULED", + "summary": "DEMAND MAINTENANCE: A Third Party vendor will be performing scheduled network maintenance." + } +] diff --git a/tests/unit/test_parsers.py b/tests/unit/test_parsers.py index f461dd75..a0bc505f 100644 --- a/tests/unit/test_parsers.py +++ b/tests/unit/test_parsers.py @@ -311,6 +311,11 @@ Path(dir_path, "data", "verizon", "verizon3.html"), Path(dir_path, "data", "verizon", "verizon3_result.json"), ), + ( + HtmlParserVerizon1, + Path(dir_path, "data", "verizon", "verizon4.html"), + Path(dir_path, "data", "verizon", "verizon4_result.json"), + ), # Zayo ( SubjectParserZayo1, From 2757016a02b5f7de3c48d6aed558451b77b78406 Mon Sep 17 00:00:00 2001 From: "Network to Code (smith-ntc)" <35795917+smith-ntc@users.noreply.github.com> Date: Thu, 9 Dec 2021 16:45:13 +0100 Subject: [PATCH 13/14] Update dependency mypy to ^0.910 (#114) * Update dependency mypy to ^0.910 * Add mypy dev dependencies Co-authored-by: Renovate Bot Co-authored-by: Glenn Matthews --- poetry.lock | 100 ++++++++++++++++++++++++++++++++++++------------- pyproject.toml | 6 ++- 2 files changed, 79 insertions(+), 27 deletions(-) diff --git a/poetry.lock b/poetry.lock index 56ec32b8..91291be1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -318,7 +318,7 @@ python-versions = "*" [[package]] name = "mypy" -version = "0.812" +version = "0.910" description = "Optional static typing for Python" category = "dev" optional = false @@ -326,11 +326,13 @@ python-versions = ">=3.5" [package.dependencies] mypy-extensions = ">=0.4.3,<0.5.0" -typed-ast = ">=1.4.0,<1.5.0" +toml = "*" +typed-ast = {version = ">=1.4.0,<1.5.0", markers = "python_version < \"3.8\""} typing-extensions = ">=3.7.4" [package.extras] dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<1.5.0)"] [[package]] name = "mypy-extensions" @@ -634,6 +636,30 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "types-python-dateutil" +version = "2.8.3" +description = "Typing stubs for python-dateutil" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "types-pytz" +version = "2021.3.2" +description = "Typing stubs for pytz" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "types-toml" +version = "0.10.1" +description = "Typing stubs for toml" +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "typing-extensions" version = "3.10.0.0" @@ -701,7 +727,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.6.1" -content-hash = "09d4e131deebe2b84efab560fb55e2fb7005237ae735fa6303ff6623619b67fe" +content-hash = "9e56380e158d1a5bebdff0456336d656c7367f2a88e42de4d03cd9f8d1aff79e" [metadata.files] appdirs = [ @@ -793,7 +819,6 @@ importlib-metadata = [ {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, ] iniconfig = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] invoke = [ @@ -839,30 +864,40 @@ lxml = [ {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354"}, + {file = "lxml-4.6.3-cp35-cp35m-manylinux2014_x86_64.whl", hash = "sha256:5c8c163396cc0df3fd151b927e74f6e4acd67160d6c33304e805b84293351d16"}, {file = "lxml-4.6.3-cp35-cp35m-win32.whl", hash = "sha256:f2380a6376dfa090227b663f9678150ef27543483055cc327555fb592c5967e2"}, {file = "lxml-4.6.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c4f05c5a7c49d2fb70223d0d5bcfbe474cf928310ac9fa6a7c6dddc831d0b1d4"}, {file = "lxml-4.6.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d2e35d7bf1c1ac8c538f88d26b396e73dd81440d59c1ef8522e1ea77b345ede4"}, {file = "lxml-4.6.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:289e9ca1a9287f08daaf796d96e06cb2bc2958891d7911ac7cae1c5f9e1e0ee3"}, {file = "lxml-4.6.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bccbfc27563652de7dc9bdc595cb25e90b59c5f8e23e806ed0fd623755b6565d"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d916d31fd85b2f78c76400d625076d9124de3e4bda8b016d25a050cc7d603f24"}, {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:820628b7b3135403540202e60551e741f9b6d3304371712521be939470b454ec"}, + {file = "lxml-4.6.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:c47ff7e0a36d4efac9fd692cfa33fbd0636674c102e9e8d9b26e1b93a94e7617"}, {file = "lxml-4.6.3-cp36-cp36m-win32.whl", hash = "sha256:5a0a14e264069c03e46f926be0d8919f4105c1623d620e7ec0e612a2e9bf1c04"}, {file = "lxml-4.6.3-cp36-cp36m-win_amd64.whl", hash = "sha256:92e821e43ad382332eade6812e298dc9701c75fe289f2a2d39c7960b43d1e92a"}, {file = "lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efd7a09678fd8b53117f6bae4fa3825e0a22b03ef0a932e070c0bdbb3a35e654"}, {file = "lxml-4.6.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:efac139c3f0bf4f0939f9375af4b02c5ad83a622de52d6dfa8e438e8e01d0eb0"}, {file = "lxml-4.6.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:36108c73739985979bf302006527cf8a20515ce444ba916281d1c43938b8bb96"}, {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:122fba10466c7bd4178b07dba427aa516286b846b2cbd6f6169141917283aae2"}, + {file = "lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cdaf11d2bd275bf391b5308f86731e5194a21af45fbaaaf1d9e8147b9160ea92"}, {file = "lxml-4.6.3-cp37-cp37m-win32.whl", hash = "sha256:3439c71103ef0e904ea0a1901611863e51f50b5cd5e8654a151740fde5e1cade"}, {file = "lxml-4.6.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4289728b5e2000a4ad4ab8da6e1db2e093c63c08bdc0414799ee776a3f78da4b"}, {file = "lxml-4.6.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b007cbb845b28db4fb8b6a5cdcbf65bacb16a8bd328b53cbc0698688a68e1caa"}, {file = "lxml-4.6.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:76fa7b1362d19f8fbd3e75fe2fb7c79359b0af8747e6f7141c338f0bee2f871a"}, {file = "lxml-4.6.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:26e761ab5b07adf5f555ee82fb4bfc35bf93750499c6c7614bd64d12aaa67927"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:e1cbd3f19a61e27e011e02f9600837b921ac661f0c40560eefb366e4e4fb275e"}, {file = "lxml-4.6.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:66e575c62792c3f9ca47cb8b6fab9e35bab91360c783d1606f758761810c9791"}, + {file = "lxml-4.6.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:1b38116b6e628118dea5b2186ee6820ab138dbb1e24a13e478490c7db2f326ae"}, {file = "lxml-4.6.3-cp38-cp38-win32.whl", hash = "sha256:89b8b22a5ff72d89d48d0e62abb14340d9e99fd637d046c27b8b257a01ffbe28"}, {file = "lxml-4.6.3-cp38-cp38-win_amd64.whl", hash = "sha256:2a9d50e69aac3ebee695424f7dbd7b8c6d6eb7de2a2eb6b0f6c7db6aa41e02b7"}, {file = "lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ce256aaa50f6cc9a649c51be3cd4ff142d67295bfc4f490c9134d0f9f6d58ef0"}, {file = "lxml-4.6.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7610b8c31688f0b1be0ef882889817939490a36d0ee880ea562a4e1399c447a1"}, {file = "lxml-4.6.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f8380c03e45cf09f8557bdaa41e1fa7c81f3ae22828e1db470ab2a6c96d8bc23"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:3082c518be8e97324390614dacd041bb1358c882d77108ca1957ba47738d9d59"}, {file = "lxml-4.6.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:884ab9b29feaca361f7f88d811b1eea9bfca36cf3da27768d28ad45c3ee6f969"}, + {file = "lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:6f12e1427285008fd32a6025e38e977d44d6382cf28e7201ed10d6c1698d2a9a"}, {file = "lxml-4.6.3-cp39-cp39-win32.whl", hash = "sha256:33bb934a044cf32157c12bfcfbb6649807da20aa92c062ef51903415c704704f"}, {file = "lxml-4.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:542d454665a3e277f76954418124d67516c5f88e51a900365ed54a9806122b83"}, {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"}, @@ -872,28 +907,29 @@ mccabe = [ {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, ] mypy = [ - {file = "mypy-0.812-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49"}, - {file = "mypy-0.812-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c"}, - {file = "mypy-0.812-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521"}, - {file = "mypy-0.812-cp35-cp35m-win_amd64.whl", hash = "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"}, - {file = "mypy-0.812-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a"}, - {file = "mypy-0.812-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c"}, - {file = "mypy-0.812-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6"}, - {file = "mypy-0.812-cp36-cp36m-win_amd64.whl", hash = "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064"}, - {file = "mypy-0.812-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56"}, - {file = "mypy-0.812-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8"}, - {file = "mypy-0.812-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7"}, - {file = "mypy-0.812-cp37-cp37m-win_amd64.whl", hash = "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564"}, - {file = "mypy-0.812-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506"}, - {file = "mypy-0.812-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5"}, - {file = "mypy-0.812-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66"}, - {file = "mypy-0.812-cp38-cp38-win_amd64.whl", hash = "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e"}, - {file = "mypy-0.812-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a"}, - {file = "mypy-0.812-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a"}, - {file = "mypy-0.812-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97"}, - {file = "mypy-0.812-cp39-cp39-win_amd64.whl", hash = "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df"}, - {file = "mypy-0.812-py3-none-any.whl", hash = "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4"}, - {file = "mypy-0.812.tar.gz", hash = "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119"}, + {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, + {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, + {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"}, + {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"}, + {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"}, + {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"}, + {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"}, + {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"}, + {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"}, + {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"}, + {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"}, + {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"}, + {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"}, + {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"}, + {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"}, + {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"}, + {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"}, + {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"}, + {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"}, + {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"}, + {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"}, + {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"}, + {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, @@ -1142,6 +1178,18 @@ typed-ast = [ {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] +types-python-dateutil = [ + {file = "types-python-dateutil-2.8.3.tar.gz", hash = "sha256:d94e7c7ecd9f0e23b3a78087eae12c0d7aa4af9e067a8ea963ad03ed0abd1cb7"}, + {file = "types_python_dateutil-2.8.3-py3-none-any.whl", hash = "sha256:42262d0b8f8ecb06cdc5c458956685eb3b27c74f170adf541d1cc5ee4ff68bdc"}, +] +types-pytz = [ + {file = "types-pytz-2021.3.2.tar.gz", hash = "sha256:c4ee36466faed9af334d15093d05cea416323d2d043158bb582bb94c041abf51"}, + {file = "types_pytz-2021.3.2-py3-none-any.whl", hash = "sha256:ef39e119ce3b8f36741ec5de43ffb821038b0d119f8a31db598fa379b4fd72e3"}, +] +types-toml = [ + {file = "types-toml-0.10.1.tar.gz", hash = "sha256:5c1f8f8d57692397c8f902bf6b4d913a0952235db7db17d2908cc110e70610cb"}, + {file = "types_toml-0.10.1-py3-none-any.whl", hash = "sha256:8cdfd2b7c89bed703158b042dd5cf04255dae77096db66f4a12ca0a93ccb07a5"}, +] typing-extensions = [ {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, diff --git a/pyproject.toml b/pyproject.toml index 08fb6eb3..fd807ae6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,7 +44,11 @@ bandit = "^1.6.2" invoke = "^1.4.1" toml = "0.10.2" flake8 = "^4.0.0" -mypy = "^0.812" +mypy = "^0.910" +# Dependencies for mypy to correctly analyze code using these libraries +types-python-dateutil = "^2.8.3" +types-pytz = "^2021.3.2" +types-toml = "^0.10.1" [tool.poetry.scripts] circuit-maintenance-parser = "circuit_maintenance_parser.cli:main" From 6c93c08abe659afeda94bea7a55b8f39c41f6456 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Thu, 9 Dec 2021 11:02:53 -0500 Subject: [PATCH 14/14] Bump version to 2.0.8 --- CHANGELOG.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0bce148..61cd332c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## v2.0.8 - 2021-MM-DD +## v2.0.8 - 2021-12-09 ### Fixed diff --git a/pyproject.toml b/pyproject.toml index fd807ae6..1a3e0a38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "circuit-maintenance-parser" -version = "2.0.7" +version = "2.0.8" description = "Python library to parse Circuit Maintenance notifications and return a structured data back" authors = ["Network to Code "] license = "Apache-2.0"