diff --git a/README.md b/README.md index 1a34db0bc0..6edfba384b 100644 --- a/README.md +++ b/README.md @@ -223,14 +223,21 @@ Graylog + + + Icinga2 +
+ Icinga2 +
+ + + Kibana
Kibana
- - LibreNMS
@@ -261,15 +268,15 @@ OpenSearch Serverless
+ + + Parseable
Parseable
- - - Pingdom
@@ -300,15 +307,15 @@ SignalFX
- + + + + OpenObserve
OpenObserve
- - - Site24x7
@@ -339,15 +346,15 @@ ThousandEyes
- + + + + UptimeKuma
UptimeKuma
- - - VictoriaLogs
diff --git a/docs/mint.json b/docs/mint.json index 5028322a64..6fb6f16d9f 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -188,6 +188,7 @@ "providers/documentation/graylog-provider", "providers/documentation/grok-provider", "providers/documentation/http-provider", + "providers/documentation/icinga2-provider", "providers/documentation/ilert-provider", "providers/documentation/incidentio-provider", "providers/documentation/incidentmanager-provider", diff --git a/docs/providers/documentation/icinga2-provider.mdx b/docs/providers/documentation/icinga2-provider.mdx new file mode 100644 index 0000000000..7031c2f0fb --- /dev/null +++ b/docs/providers/documentation/icinga2-provider.mdx @@ -0,0 +1,122 @@ +--- +title: "Icinga2 Provider" +sidebarTitle: "Icinga2" +description: "Icinga2 Provider Allows Reception of Push Alerts from Icinga2 to Keep." +--- +import AutoGeneratedSnippet from '/snippets/providers/icinga2-snippet-autogenerated.mdx'; + + + +import ProviderLogo from '@components/ProviderLogo'; + + + +# Icinga2 Provider + +The Icinga2 provider allows you to receive alerts from Icinga2 monitoring system within Keep. +Icinga2 provider supports 2 methods for recieving alerts; Webhooks & API Polling. + +The recommended and primary method for receiving alerts is via Webhooks. + +## Setup + +### Prerequisites +1. Access to an Icinga2 instance +2. API user with relevant permissions +3. Keep instance with webhook capability + +### Configuration + +The provider requires the following configuration: + +```yaml +authentication: + host_url: "https://icinga2.example.com" # Your Icinga2 instance URL + api_user: "your-api-user" # Icinga2 API username + api_password: "your-api-password" # Icinga2 API password +``` + +### Webhook Configuration +To configure Icinga2 to send alerts to Keep via webhooks: + +1. Navigate to your Icinga2 configuration directory +2. Create or edit the ```eventcommands.conf``` file +3. Add the following event command configuration: + +```plaintext +object EventCommand "keep-notification" { + command = [ "curl" ] + arguments = { + "-X" = "POST" + "-H" = "Content-Type: application/json" + "-H" = "X-API-KEY: ${keep_api_key}" + "--data" = "{ + \"host\": { + \"name\": \"$host.name$\", + \"display_name\": \"$host.display_name$\", + \"check_command\": \"$host.check_command$\", + \"acknowledgement\": \"$host.acknowledgement$\", + \"downtime_depth\": \"$host.downtime_depth$\", + \"flapping\": \"$host.flapping$\" + }, + \"service\": { + \"name\": \"$service.name$\", + \"display_name\": \"$service.display_name$\", + \"check_command\": \"$service.check_command$\", + \"acknowledgement\": \"$service.acknowledgement$\", + \"downtime_depth\": \"$service.downtime_depth$\", + \"flapping\": \"$service.flapping$\" + }, + \"check_result\": { + \"exit_status\": \"$service.state$\", + \"state\": \"$service.state_text$\", + \"output\": \"$service.output$\", + \"execution_start\": \"$service.last_check$\", + \"execution_end\": \"$service.last_check$\", + \"state_type\": \"$service.state_type$\", + \"attempt\": \"$service.check_attempt$\", + \"execution_time\": \"$service.execution_time$\", + \"latency\": \"$service.latency$\" + } + }" + "${keep_webhook_url}" = { + required = true + } + } +} +``` +4. Define variables in your Icinga2 Configuration: + - ```keep_api_key```: Your Keep API key with webhook role + - ```keep_webhook_url```: Your Keep Webhook URL +5. Create a notification rule that uses this event command +6. Restart Icinga2 to apply changes + +### State Mapping + +By Default, Icinga2 states are automatically mapped to Keep alert severities & statuses as follows: + + +#### Status Mapping +| Icinga2 State | Keep Status | +|:--------------|:------------| +| OK | RESOLVED | +| WARNING | FIRING | +| CRITICAL | FIRING | +| UNKNOWN | FIRING | +| UP | RESOLVED | +| DOWN | FIRING | + + + + +#### Severity Mapping +| Icinga2 State | Keep Severity | +|:--------------|:--------------| +| OK | INFO | +| WARNING | WARNING | +| CRITICAL | CRITICAL | +| UNKNOWN | INFO | +| UP | INFO | +| DOWN | CRITICAL | + + \ No newline at end of file diff --git a/docs/providers/overview.mdx b/docs/providers/overview.mdx index 2222321108..39903e2e31 100644 --- a/docs/providers/overview.mdx +++ b/docs/providers/overview.mdx @@ -364,6 +364,14 @@ By leveraging Keep Providers, users are able to deeply integrate Keep with the t } > + + } +> + list[AlertDto]: + """ + Get alerts from Icinga2 via API. + + Returns: + list[AlertDto]: List of alerts in Keep format + """ + self.logger.info("Getting alerts from Icinga2") + + try: + response = requests.get( + url=f"{self.authentication_config.host_url}/v1/services?attrs=name,display_name,state,last_state_change", + auth=( + self.authentication_config.api_user, + self.authentication_config.api_password, + ), + verify=True, + ) + + if response.status_code != 200: + response.raise_for_status() + + services = response.json()["results"] + + return [ + AlertDto( + id=service.get("name"), + name=service.get("display_name"), + status=self.STATUS_MAP.get( + service.get("state"), AlertStatus.FIRING + ), + severity=self.SEVERITY_MAP.get( + service.get("state"), AlertSeverity.INFO + ), + timestamp=service.get("last_state_change"), + source=["icinga2"], + ) + for service in services + ] + + except Exception as e: + self.logger.exception("Failed to get alerts from Icinga2") + raise Exception(f"Failed to get alerts from Icinga2: {str(e)}") + + @staticmethod + def _format_alert( + event: dict, provider_instance: "BaseProvider" = None + ) -> AlertDto | list[AlertDto]: + """ + Format Icinga2 webhook payload into Keep alert format. + + Args: + event (dict): Raw alert data from Icinga2 + provider_instance (BaseProvider, optional): Provider instance + + Returns: + AlertDto: Formatted alert in Keep format + """ + check_result = event.get("check_result", {}) + service = event.get("service", {}) + host = event.get("host", {}) + + status = check_result.get("exit_status", 0) + state = check_result.get("state", "UNKNOWN") + output = check_result.get("output", "No output provided") + + alert = AlertDto( + id=service.get("name") or host.get("name"), + name=service.get("display_name") or host.get("display_name"), + status=Icinga2Provider.STATUS_MAP.get(state, AlertStatus.FIRING), + severity=Icinga2Provider.SEVERITY_MAP.get(state, AlertSeverity.INFO), + timestamp=check_result.get("execution_start"), + lastReceived=check_result.get("execution_end"), + description=output, + source=["icinga2"], + hostname=host.get("name"), + service_name=service.get("name"), + check_command=service.get("check_command") or host.get("check_command"), + state=state, + state_type=check_result.get("state_type"), + attempt=check_result.get("attempt"), + acknowledgement=service.get("acknowledgement") + or host.get("acknowledgement"), + downtime_depth=service.get("downtime_depth") or host.get("downtime_depth"), + flapping=service.get("flapping") or host.get("flapping"), + execution_time=check_result.get("execution_time"), + latency=check_result.get("latency"), + raw_output=output, + exit_status=status, + ) + + return alert + + +if __name__ == "__main__": + import logging + + logging.basicConfig(level=logging.DEBUG, handlers=[logging.StreamHandler()]) + + context_manager = ContextManager( + tenant_id="singletenant", + workflow_id="test", + ) + + import os + + icinga2_api_user = os.getenv("ICINGA2_API_USER") + icinga2_api_password = os.getenv("ICINGA2_API_PASSWORD") + + config = ProviderConfig( + description="Icinga2 Provider", + authentication={ + "host_url": "https://icinga2.example.com", + "api_user": icinga2_api_user, + "api_password": icinga2_api_password, + }, + ) + + provider = Icinga2Provider(context_manager, "icinga2", config)