Skip to content

Add Hawaiki Provider, Parser and tests - #428

Merged
jvanderaa merged 5 commits into
networktocode:developfrom
mkekez-SIE:hawaiki_parser
Aug 7, 2026
Merged

Add Hawaiki Provider, Parser and tests#428
jvanderaa merged 5 commits into
networktocode:developfrom
mkekez-SIE:hawaiki_parser

Conversation

@mkekez-SIE

Copy link
Copy Markdown
Contributor

Hawaiki have recently updated their maintenance emailing processes where they no longer include all correspondences into their newest email response. At this point, we can now provide a HTML parser which can hopefully parse these emails. Right now we are fully depending on OpenAI parser for their emails and there are a lot of emails/updates which Hawaiki send which should classify as 'No Maintenances Found'.

I have written the provider, parser and tests and have also provided an include filter for Hawaiki to hopefully ignore the updates they are sending that do not actually have parseable maintenance details.

Note: Hawaiki send a contingency window in each maintenance they send, but to me it seems they use it very rarely. I have not parsed this information in my change, but prefer that we see how clients interact with Hawaiki with this parser, and if they see this contingency window needs to be parsed, we can make further improvements there.

Comment thread circuit_maintenance_parser/__init__.py Outdated
Comment on lines +69 to +70
HGC,
Hawaiki,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this before HGC to keep alphabetical.

data: Dict = {
"circuits": [],
"status": Status.CONFIRMED,
"account": "Unknown",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"account": "Unknown",
"account": "Customer info unavailable",

Matching what is in apple.py:52 and bso.py:52

match = re.match(r"Service ID:\s*(.+)", line)
if match:
circuit_id = match.group(1).strip()
data["circuits"].append(CircuitImpact(circuit_id=circuit_id, impact=Impact.NO_IMPACT))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All circuits get Impact.NO_IMPACT unconditionally here, regardless of what the notification says. The email format already carries a Service impact: line that the parser walks past — so a genuinely service-affecting Hawaiki maintenance gets recorded as harmless. Downstream consumers (e.g. Nautobot circuit-maintenance) key off impact to decide whether to act, so this is worse than the current OpenAI-parser fallback for those emails.

The wrinkle is ordering: Service ID: appears above Service impact: in the body, so the single-pass loop can't know the impact at the moment it appends the circuit. Simplest fix is to resolve impact up front, since all circuits in a Hawaiki notification share one impact line; same approach equinix.py:82 takes ("all circuits in the notification share the same impact").

I'd also default to OUTAGE rather than NO_IMPACT for unrecognized phrasing. OUTAGE is the library's own default in CircuitImpact, and it's the safe direction to be wrong in an over-cautious maintenance window costs someone an unnecessary look, an under-cautious one costs them an unexpected outage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh thats my bad! Will get that resolved.

@jvanderaa

Copy link
Copy Markdown
Contributor

Here may help:

IMPACT_LINE_RE = re.compile(r"^Service impact:\s*(.+)$", re.IGNORECASE | re.MULTILINE)


    @staticmethod
    def _parse_impact(text: str) -> Impact:
        """Map the notification's single 'Service impact' line to an Impact."""
        match = IMPACT_LINE_RE.search(text)
        if not match:
            logger.warning("No Hawaiki 'Service impact' line found, defaulting to OUTAGE.")
            return Impact.OUTAGE
        impact_text = match.group(1).strip().lower()
        if "no service impact" in impact_text:
            return Impact.NO_IMPACT
        if "redundancy" in impact_text or "re-routed" in impact_text:
            return Impact.REDUCED_REDUNDANCY
        logger.warning("Unrecognized Hawaiki service impact %r, defaulting to OUTAGE.", impact_text)
        return Impact.OUTAGE

and in parse_text, replacing line 55:

        # All circuits in a Hawaiki notification share one "Service impact" line, and it appears
        # after the "Service ID" lines, so resolve it up front.
        impact = self._parse_impact(text)

        ...
            match = re.match(r"Service ID:\s*(.+)", line)
            if match:
                data["circuits"].append(CircuitImpact(circuit_id=match.group(1).strip(), impact=impact))
                continue

@mkekez-SIE

Copy link
Copy Markdown
Contributor Author

@jvanderaa I think all threads should be resolved now! Please let me know if I am missing something.

@jvanderaa jvanderaa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

@jvanderaa
jvanderaa merged commit 0e606c5 into networktocode:develop Aug 7, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants