Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
"providers/documentation/clickhouse-provider",
"providers/documentation/cloudwatch-provider",
"providers/documentation/console-provider",
"providers/documentation/coroot-provider",
"providers/documentation/coralogix-provider",
"providers/documentation/dash0-provider",
"providers/documentation/databend-provider",
Expand Down
92 changes: 92 additions & 0 deletions docs/providers/documentation/coroot-provider.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
title: "Coroot"
sidebarTitle: "Coroot Provider"
description: "Coroot provider allows you to pull alerts from Coroot into Keep."
---
import AutoGeneratedSnippet from '/snippets/providers/coroot-snippet-autogenerated.mdx';

## Overview

[Coroot](https://coroot.com) is an open-source observability platform for Kubernetes applications. It provides comprehensive monitoring of applications, infrastructure, and dependencies with zero-instrumentation and automatic root cause analysis.

Coroot collects metrics from Prometheus, logs from Loki or ClickHouse, and distributed traces from OpenTelemetry or Jaeger to provide a complete picture of your system's health.

## Connecting Coroot to Keep

To connect Coroot to Keep, you'll need to configure the Coroot provider with your Coroot instance URL and optionally an API key.

### Prerequisites

- A running Coroot instance (self-hosted or cloud)
- Coroot URL (e.g., `https://coroot.example.com`)
- API Key (if authentication is enabled on your Coroot instance)

### Configuration Parameters

| Parameter | Required | Description | Example |
|-----------|----------|-------------|---------|
| URL | Yes | Your Coroot instance URL | `https://coroot.example.com` |
| API Key | No | Coroot API key for authentication | `coroot_api_xxx` |
| Project ID | No | Coroot project ID (if using projects) | `default` |
| Verify SSL | No | Verify SSL certificates (default: true) | `true` or `false` |

### Obtaining Your Coroot API Key

1. Log in to your Coroot instance
2. Navigate to **Settings** → **API Keys** (or User Profile)
3. Generate a new API key
4. Copy the key for use in Keep

### Setting Up the Provider in Keep

1. Go to the Keep platform and navigate to **Providers**
2. Search for "Coroot" and click **Connect**
3. Enter your Coroot URL
4. If your Coroot instance requires authentication, enter your API key
5. Optionally specify a Project ID if you're using Coroot's multi-project feature
6. Click **Connect** to validate the connection

<AutoGeneratedSnippet />

## Fingerprinting

Alerts from Coroot are fingerprinted based on:
- Alert name/alertname
- Service name (if available)
- Project ID (if configured)

This ensures that recurring alerts are properly deduplicated and correlated within Keep.

## Alert Severity Mapping

Coroot severities are mapped to Keep alert severities as follows:

| Coroot Severity | Keep Severity |
|-----------------|---------------|
| critical | CRITICAL |
| error / high | HIGH |
| warning / warn / medium | WARNING |
| info | INFO |
| low | LOW |

## Alert Status Mapping

Coroot alert statuses are mapped to Keep alert statuses:

| Coroot Status | Keep Status |
|---------------|-------------|
| firing / open | FIRING |
| resolved / closed | RESOLVED |

## Notes

- The Coroot provider supports both webhook-based and polling-based alert ingestion
- For webhook integration, configure your Coroot instance to send alerts to Keep's webhook endpoint
- The provider handles various alert formats from different Coroot versions

## Useful Links

- [Coroot Documentation](https://docs.coroot.com)
- [Coroot GitHub Repository](https://github.com/coroot/coroot)
- [Coroot Installation Guide](https://docs.coroot.com/installation)
- [Coroot Alerting Configuration](https://docs.coroot.com/alerting)
33 changes: 33 additions & 0 deletions docs/snippets/providers/coroot-snippet-autogenerated.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{/* This snippet is automatically generated using scripts/docs_render_provider_snippets.py
Do not edit it manually, as it will be overwritten */}


## In workflows

This provider can be used in workflows.


As "step" to query data, example:
```yaml
steps:
- name: Get alerts from Coroot
provider: coroot
config: "{{ provider.my_coroot_provider }}"
```






## Authentication Parameters

The `api_key` is optional. If your Coroot instance has authentication enabled, you need to provide it.


## Provider Configuration

- `url` (required): Coroot server URL, e.g., `https://coroot.example.com`
- `api_key` (optional): Coroot API key if authentication is enabled
- `project_id` (optional): Coroot project ID (leave empty for default project)
- `verify` (optional): Verify SSL certificates (default: `true`, set to `false` to allow self-signed certificates)
4 changes: 4 additions & 0 deletions keep/providers/coroot_provider/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""
Coroot provider package.
"""
from keep.providers.coroot_provider.coroot_provider import CorootProvider # noqa: F401
225 changes: 225 additions & 0 deletions keep/providers/coroot_provider/coroot_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
"""
CorootProvider is a class that provides a way to read data from Coroot.
"""

import dataclasses
import datetime
from typing import Optional

import pydantic
import requests

from keep.api.models.alert import AlertDto, AlertSeverity, AlertStatus
from keep.contextmanager.contextmanager import ContextManager
from keep.providers.base.base_provider import BaseProvider, ProviderHealthMixin
from keep.providers.models.provider_config import ProviderConfig, ProviderScope


@pydantic.dataclasses.dataclass
class CorootProviderAuthConfig:
url: pydantic.AnyHttpUrl = dataclasses.field(
metadata={
"required": True,
"description": "Coroot server URL",
"hint": "https://coroot.example.com",
"validation": "any_http_url",
}
)
api_key: str = dataclasses.field(
metadata={
"description": "Coroot API key (if authentication is enabled)",
"sensitive": True,
},
default="",
)
project_id: str = dataclasses.field(
metadata={
"description": "Coroot project ID",
"hint": "Leave empty for default project",
},
default="",
)
verify: bool = dataclasses.field(
metadata={
"description": "Verify SSL certificates",
"hint": "Set to false to allow self-signed certificates",
"sensitive": False,
},
default=True,
)


class CorootProvider(BaseProvider, ProviderHealthMixin):
"""Get alerts from Coroot into Keep."""

PROVIDER_DISPLAY_NAME = "Coroot"
PROVIDER_TAGS = ["alert"]
PROVIDER_CATEGORY = ["Monitoring"]

PROVIDER_SCOPES = [
ProviderScope(
name="connectivity",
description="Connectivity Test",
mandatory=True,
)
]

SEVERITIES_MAP = {
"critical": AlertSeverity.CRITICAL,
"error": AlertSeverity.HIGH,
"high": AlertSeverity.HIGH,
"warning": AlertSeverity.WARNING,
"warn": AlertSeverity.WARNING,
"medium": AlertSeverity.WARNING,
"info": AlertSeverity.INFO,
"low": AlertSeverity.LOW,
}

STATUS_MAP = {
"firing": AlertStatus.FIRING,
"resolved": AlertStatus.RESOLVED,
"open": AlertStatus.FIRING,
"closed": AlertStatus.RESOLVED,
}

def __init__(
self, context_manager: ContextManager, provider_id: str, config: ProviderConfig
):
super().__init__(context_manager, provider_id, config)

def validate_config(self):
"""
Validates required configuration for Coroot's provider.
"""
self.authentication_config = CorootProviderAuthConfig(
**self.config.authentication
)

def validate_scopes(self) -> dict[str, bool | str]:
validated_scopes = {"connectivity": True}
try:
self._get_alerts()
except Exception as e:
validated_scopes["connectivity"] = str(e)
return validated_scopes

def _get_auth_headers(self) -> dict:
"""Get authentication headers if API key is provided."""
headers = {"Content-Type": "application/json"}
if self.authentication_config.api_key:
headers["Authorization"] = f"Bearer {self.authentication_config.api_key}"
return headers

def _get_project_param(self) -> dict:
"""Get project query parameter if project_id is provided."""
params = {}
if self.authentication_config.project_id:
params["project"] = self.authentication_config.project_id
return params

def _get_alerts(self) -> list[AlertDto]:
"""Fetch alerts from Coroot API."""
url = f"{self.authentication_config.url}/api/alerts"
headers = self._get_auth_headers()
params = self._get_project_param()

response = requests.get(
url,
headers=headers,
params=params,
verify=self.authentication_config.verify,
timeout=30,
)
response.raise_for_status()

alerts_data = response.json()
alert_dtos = self._format_alerts(alerts_data)
return alert_dtos

@staticmethod
def _format_alerts(
data: dict | list, provider_instance: Optional["CorootProvider"] = None
) -> list[AlertDto]:
"""Format Coroot alerts into Keep AlertDto format."""
alert_dtos = []

# Handle both dict and list responses
if isinstance(data, dict):
alerts = data.get("alerts", data.get("items", []))
elif isinstance(data, list):
alerts = data
else:
return alert_dtos

for alert in alerts:
if not isinstance(alert, dict):
continue

# Extract alert fields
alert_id = alert.get("id") or alert.get("alert_id") or alert.get("name")
name = alert.get("name") or alert.get("alertname") or alert_id
description = alert.get("description") or alert.get("summary") or alert.get("message", name)

# Extract labels/annotations
labels = alert.get("labels", {})
if isinstance(labels, dict):
labels = {k.lower(): v for k, v in labels.items()}

# Map severity
severity_str = (
alert.get("severity")
or labels.get("severity", "info")
).lower()
severity = CorootProvider.SEVERITIES_MAP.get(severity_str, AlertSeverity.INFO)

# Map status
status_str = (
alert.get("status")
or alert.get("state")
or labels.get("status", "firing")
).lower()
status = CorootProvider.STATUS_MAP.get(status_str, AlertStatus.FIRING)

# Extract service name
service = (
labels.get("service")
or labels.get("application")
or labels.get("app")
or alert.get("service")
or alert.get("application")
)

# Extract timestamp
timestamp_str = alert.get("timestamp") or alert.get("created_at") or alert.get("starts_at")
try:
if timestamp_str:
timestamp = datetime.datetime.fromisoformat(timestamp_str.replace("Z", "+00:00"))
else:
timestamp = datetime.datetime.now(datetime.timezone.utc)
except (ValueError, TypeError):
timestamp = datetime.datetime.now(datetime.timezone.utc)

# Build AlertDto
alert_dto = AlertDto(
id=str(alert_id) if alert_id else None,
name=name,
description=description,
status=status,
severity=severity,
service=service,
timestamp=timestamp,
source=["coroot"],
labels=labels,
annotations=alert.get("annotations", {}),
raw_payload=alert,
)
alert_dtos.append(alert_dto)

return alert_dtos

def dispose(self):
"""
Dispose of the provider.
"""
pass

Loading
Loading