Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(victoriametrics): support either full URL or host and port #2432

Merged
merged 4 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
30 changes: 18 additions & 12 deletions docs/providers/documentation/victoriametrics-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ description: "The VictoriametricsProvider allows you to fetch alerts in Victoria

## Authentication Parameters

The Victoriametrics provider requires the following authentication parameters:
The Victoriametrics provider requires either of the following authentication parameters:

- `VMAlertHost`: The hostname or IP address where VMAlert is running. Example: `localhost`, `192.168.1.100`, or `vmalert.mydomain.com`.
- `VMAlertPort`: The port number on which VMAlert is listening. Example: 8880 (if VMAlert is set to listen on port 8880).

or

- `VMAlertURL`: The full URL to the VMAlert instance. For example: `http://vmalert.mydomain.com:8880`.

## Connecting with the Provider

1. Ensure you have a running instance of VMAlert accessible by the host and port specified.
Expand All @@ -21,6 +25,7 @@ The Victoriametrics provider requires the following authentication parameters:
The Victoriametrics provider allows you to query from Victoriametrics through `query` and `query_range` types. The following are the parameters available for querying:

1. `query` type:

- `query`: The query to execute on Victoriametrics. Example: `sum(rate(http_requests_total{job="api-server"}[5m]))`.
- `start`: The time to query the data for. Example: `2024-01-01T00:00:00Z`

Expand All @@ -33,24 +38,25 @@ The Victoriametrics provider allows you to query from Victoriametrics through `q
## Push alerts to keep using webhooks

You can push alerts to keep without connecting to Victoriametrics This provider takes advantage of configurable webhooks available with Prometheus Alertmanager. Use the following template to configure AlertManager:

```yml
route:
receiver: "keep"
group_by: ['alertname']
group_wait: 15s
group_interval: 15s
group_by: ["alertname"]
group_wait: 15s
group_interval: 15s
repeat_interval: 1m
continue: true

receivers:
- name: "keep"
webhook_configs:
- url: '{keep_webhook_api_url}'
send_resolved: true
http_config:
basic_auth:
username: api_key
password: {api_key}
- name: "keep"
webhook_configs:
- url: "{keep_webhook_api_url}"
send_resolved: true
http_config:
basic_auth:
username: api_key
password: { api_key }
```

## Useful Links
Expand Down
59 changes: 38 additions & 21 deletions keep/providers/victoriametrics_provider/victoriametrics_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,30 @@ class VictoriametricsProviderAuthConfig:
vmalert authentication configuration.
"""

VMAlertHost: str = dataclasses.field(
VMAlertHost: str | None = dataclasses.field(
metadata={
"required": True,
"required": False,
"description": "The hostname or IP address where VMAlert is running. This can be a local or remote server address.",
"hint": "Example: 'localhost', '192.168.1.100', or 'vmalert.mydomain.com'",
},
default=None,
)

VMAlertPort: int = dataclasses.field(
metadata={
"required": True,
"required": False,
"description": "The port number on which VMAlert is listening. This should match the port configured in your VMAlert setup.",
"hint": "Example: 8880 (if VMAlert is set to listen on port 8880)",
"hint": "Example: 8880 (if VMAlert is set to listen on port 8880), defaults to 8880",
},
default=8880,
)

VMAlertURL: str | None = dataclasses.field(
metadata={
"required": False,
"description": "The full URL to the VMAlert instance. For example: http://vmalert.mydomain.com:8880",
},
default=None,
)


Expand Down Expand Up @@ -91,9 +101,7 @@ class VictoriametricsProvider(BaseProvider):
}

def validate_scopes(self) -> dict[str, bool | str]:
response = requests.get(
f"{self.vmalert_host}:{self.authentication_config.VMAlertPort}"
)
response = requests.get(self.vmalert_host)
if response.status_code == 200:
connected_to_client = True
self.logger.info("Connected to client successfully")
Expand Down Expand Up @@ -128,36 +136,47 @@ def validate_config(self):
self.authentication_config = VictoriametricsProviderAuthConfig(
**self.config.authentication
)
if (
self.authentication_config.VMAlertURL is None
and self.authentication_config.VMAlertHost is None
):
raise Exception("VMAlertURL or VMAlertHost is required")

@property
def vmalert_host(self):
# if not the first time, return the cached host
if self._host:
return self._host.rstrip("/")

host = None

if self.authentication_config.VMAlertURL is not None:
host = self.authentication_config.VMAlertURL
else:
host = f"{self.authentication_config.VMAlertHost}:{self.authentication_config.VMAlertPort}"

# if the user explicitly supplied a host with http/https, use it
if self.authentication_config.VMAlertHost.startswith(
"http://"
) or self.authentication_config.VMAlertHost.startswith("https://"):
self._host = self.authentication_config.VMAlertHost
return self.authentication_config.VMAlertHost.rstrip("/")
if host.startswith("http://") or host.startswith("https://"):
self._host = host
return host.rstrip("/")

# otherwise, try to use https:
try:
url = f"https://{host}"
requests.get(
f"https://{self.authentication_config.VMAlertHost}:{self.authentication_config.VMAlertPort}",
url,
verify=False,
)
self.logger.debug("Using https")
self._host = f"https://{self.authentication_config.VMAlertHost}"
self._host = f"https://{host}"
return self._host.rstrip("/")
except requests.exceptions.SSLError:
self.logger.debug("Using http")
self._host = f"http://{self.authentication_config.VMAlertHost}"
self._host = f"http://{host}"
return self._host.rstrip("/")
# should happen only if the user supplied invalid host, so just let validate_config fail
except Exception:
return self.authentication_config.VMAlertHost.rstrip("/")
return host.rstrip("/")

@staticmethod
def _format_alert(
Expand Down Expand Up @@ -185,9 +204,7 @@ def _format_alert(
return alerts

def _get_alerts(self) -> list[AlertDto]:
response = requests.get(
f"{self.vmalert_host}:{self.authentication_config.VMAlertPort}/api/v1/alerts"
)
response = requests.get(f"{self.vmalert_host}/api/v1/alerts")
if response.status_code == 200:
alerts = []
response = response.json()
Expand Down Expand Up @@ -217,7 +234,7 @@ def _get_alerts(self) -> list[AlertDto]:
def _query(self, query="", start="", end="", step="", queryType="", **kwargs: dict):
if queryType == "query":
response = requests.get(
f"{self.vmalert_host}:{self.authentication_config.VMAlertPort}/api/v1/query",
f"{self.vmalert_host}/api/v1/query",
params={"query": query, "time": start},
)
if response.status_code == 200:
Expand All @@ -230,7 +247,7 @@ def _query(self, query="", start="", end="", step="", queryType="", **kwargs: di

elif queryType == "query_range":
response = requests.get(
f"{self.vmalert_host}:{self.authentication_config.VMAlertPort}/api/v1/query_range",
f"{self.vmalert_host}/api/v1/query_range",
params={"query": query, "start": start, "end": end, "step": step},
)
if response.status_code == 200:
Expand Down
Loading