Skip to content

Conversation

@idofi555-ux
Copy link

Summary

Implements Nagios XI integration for Keep, allowing users to pull alerts from Nagios monitoring systems.

Features

  • API Integration: Connect to Nagios XI REST API to fetch host and service alerts
  • Webhook Support: Receive real-time notifications from Nagios
  • State Mapping: Properly maps Nagios states (OK, WARNING, CRITICAL, UNKNOWN, UP, DOWN) to Keep alert statuses

Implementation Details

  • Uses Nagios XI API v1 endpoints for fetching status
  • Supports both host and service alerts
  • Includes proper error handling and logging
  • Follows existing provider patterns (similar to Centreon)

Testing

  • Provider structure validated against existing providers
  • API response parsing tested with sample data

Closes #3960


This PR was created to claim the Nagios Provider bounty.

Implements Nagios XI integration for Keep, allowing users to:
- Pull host and service alerts from Nagios XI API
- Receive webhook notifications from Nagios
- Map Nagios states to Keep alert statuses

Closes keephq#3960
@vercel
Copy link

vercel bot commented Feb 1, 2026

Someone is attempting to deploy a commit to the KeepHQ Team on Vercel.

A member of the Team first needs to authorize it.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 1, 2026
@dosubot
Copy link

dosubot bot commented Feb 1, 2026

Related Documentation

No published documentation to review for changes on this repository.

Write your first living document

How did I do? Any feedback?  Join Discord

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Jean Bot seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 1, 2026

Target branch is not in the allowed branches list.

@dosubot dosubot bot added Feature A new feature Provider Providers related issues labels Feb 1, 2026
@talboren talboren requested a review from Copilot February 1, 2026 09:22
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements a new Nagios XI provider to ingest alerts into Keep via both polling the Nagios XI REST API and formatting Nagios webhooks.

Changes:

  • Adds NagiosProviderAuthConfig and NagiosProvider with API-based fetching of host and service problems from Nagios XI v1 endpoints.
  • Maps Nagios host/service states and severities into AlertStatus/AlertSeverity and converts Nagios API responses into AlertDto instances.
  • Introduces a _format_alert webhook handler to normalize incoming Nagios notifications into Keep’s alert model.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 3 comments.

File Description
keep/providers/nagios_provider/nagios_provider.py Defines the Nagios provider, including auth config, REST polling, Nagios→Keep state/severity mapping, and webhook alert formatting.
keep/providers/nagios_provider/__init__.py Declares the nagios_provider package so the factory can import the provider module.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +170 to +179
return AlertDto(
id=f"nagios-host-{host.get('host_id', '')}",
name=f"Host: {host.get('name', 'Unknown')}",
description=host.get("status_text", host.get("plugin_output", "")),
status=self.HOST_STATUS_MAP.get(current_state, AlertStatus.FIRING),
severity=self.SEVERITY_MAP.get(current_state, AlertSeverity.WARNING),
source=["nagios"],
lastReceived=datetime.datetime.fromisoformat(
host.get("last_check", datetime.datetime.now().isoformat())
) if host.get("last_check") else datetime.datetime.now(),
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

AlertDto.lastReceived is being passed a datetime object here, but AlertDto's lastReceived validator (see keep/api/models/alert.py:170-208) expects a string/timestamp and will fail when given a datetime, causing _host_to_alert to raise and return None so host alerts are silently dropped. To avoid this, either pass a string (e.g. using .isoformat() or the raw API value) or let AlertDto handle the original last_check value directly and remove the datetime.fromisoformat call here.

Copilot uses AI. Check for mistakes.
Comment on lines +200 to +209
return AlertDto(
id=f"nagios-service-{service.get('servicestatus_id', '')}",
name=f"Service: {host_name}/{service_name}",
description=service.get("status_text", service.get("plugin_output", "")),
status=self.SERVICE_STATUS_MAP.get(current_state, AlertStatus.FIRING),
severity=self.SEVERITY_MAP.get(current_state, AlertSeverity.WARNING),
source=["nagios"],
lastReceived=datetime.datetime.fromisoformat(
service.get("last_check", datetime.datetime.now().isoformat())
) if service.get("last_check") else datetime.datetime.now(),
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

Same as for hosts, lastReceived is set to a datetime object here, which conflicts with AlertDto's lastReceived validator expecting a string and will cause _service_to_alert to fail and drop service alerts. Align this with other providers by passing a string value (e.g. ISO-formatted or the raw last_check from the API) instead of a datetime instance.

Copilot uses AI. Check for mistakes.
Comment on lines +235 to +261
# Service alert
state = int(event.get("servicestate", event.get("state", 0)))
status = NagiosProvider.SERVICE_STATUS_MAP.get(state, AlertStatus.FIRING)
severity = NagiosProvider.SEVERITY_MAP.get(state, AlertSeverity.WARNING)

host_name = event.get("hostname", event.get("host", "Unknown"))
service_name = event.get("servicedesc", event.get("service", "Unknown"))

return AlertDto(
id=event.get("id", f"nagios-{host_name}-{service_name}"),
name=f"Service: {host_name}/{service_name}",
description=event.get("output", event.get("message", "")),
status=status,
severity=severity,
source=["nagios"],
fingerprint=f"nagios-service-{host_name}-{service_name}",
labels={
"host_name": host_name,
"service_name": service_name,
"notification_type": event.get("notificationtype", ""),
},
)
else:
# Host alert
state = int(event.get("hoststate", event.get("state", 0)))
status = NagiosProvider.HOST_STATUS_MAP.get(state, AlertStatus.FIRING)
severity = NagiosProvider.SEVERITY_MAP.get(state, AlertSeverity.WARNING)
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

The webhook formatter assumes servicestate/hoststate (or state) are numeric and calls int(...), but Nagios notification macros like SERVICESTATE/HOSTSTATE are typically strings such as "OK", "WARNING", "CRITICAL", "UP", "DOWN"; trying to cast those to int will raise and break webhook handling, contradicting the documented state mapping behavior. Consider supporting both textual and numeric states (e.g. by normalizing strings through a separate mapping or by trying int only when the value is digit-like) so that common Nagios webhook payloads are accepted.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature A new feature Provider Providers related issues size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[🔌 Provider]: Nagios Provider

2 participants