diff --git a/docs/deployment/configuration.mdx b/docs/deployment/configuration.mdx index f4c1a1714..abcbb00fc 100644 --- a/docs/deployment/configuration.mdx +++ b/docs/deployment/configuration.mdx @@ -69,7 +69,7 @@ Resource provisioning settings control how Keep sets up initial resources. This Authentication configuration determines how Keep verifies user identities and manages access control. These settings are essential for securing your Keep instance and integrating with various authentication providers. -For specifc authentication type configuration, please see [authentication docs](/deployment/authentication/overview). +For specific authentication type configuration, please see [authentication docs](/deployment/authentication/overview). | Env var | Purpose | Required | Default Value | Valid options | diff --git a/docs/deployment/ecs.mdx b/docs/deployment/ecs.mdx index 097092e1a..61289afcd 100644 --- a/docs/deployment/ecs.mdx +++ b/docs/deployment/ecs.mdx @@ -102,7 +102,7 @@ sidebarTitle: "AWS ECS" - Configuration Type: Configure at task definition creation - Volume type: EFS - Storage configurations: - - File system ID: Select an exisiting EFS filesystem or create a new one + - File system ID: Select an existing EFS filesystem or create a new one - Root Directory: / ![Volume Configuration](/images/ecs-task-def-backend5.png) - Container mount points: diff --git a/docs/deployment/kubernetes/installation.mdx b/docs/deployment/kubernetes/installation.mdx index 5b3010ffd..9680df532 100644 --- a/docs/deployment/kubernetes/installation.mdx +++ b/docs/deployment/kubernetes/installation.mdx @@ -46,8 +46,11 @@ To read about more installation options, see [ingress-nginx installation docs](h ```bash # simplest way to install +# we set snippet-annotations to true to allow rewrites +# see https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#allow-snippet-annotations helm upgrade --install ingress-nginx ingress-nginx \ --repo https://kubernetes.github.io/ingress-nginx \ + --set controller.config.allow-snippet-annotations=true \ --namespace ingress-nginx --create-namespace ``` diff --git a/docs/deployment/kubernetes/overview.mdx b/docs/deployment/kubernetes/overview.mdx index b40d9c771..a3d889f07 100644 --- a/docs/deployment/kubernetes/overview.mdx +++ b/docs/deployment/kubernetes/overview.mdx @@ -14,5 +14,6 @@ We maintain an opinionated, batteries-included Helm chart, but you can customize ## Next steps - Install Keep on [Kubernetes](/deployment/kubernetes/installation). - Keep's [Helm Chart](https://github.com/keephq/helm-charts). +- Keep with [Kubernetes Secret Manager](/deployment/secret-manager#kubernetes-secret-manager) - Deep dive to Keep's kubernetes [Architecture](/deployment/kubernetes/architecture). - Install Keep on [OpenShift](/deployment/kubernetes/openshift). diff --git a/docs/deployment/secret-manager.mdx b/docs/deployment/secret-manager.mdx index e6db52f51..00b18cb3b 100644 --- a/docs/deployment/secret-manager.mdx +++ b/docs/deployment/secret-manager.mdx @@ -59,11 +59,16 @@ Usage: ## Kubernetes Secret Manager -The `KubernetesSecretManager` interfaces with Kubernetes' native secrets system. It manages secrets within a specified Kubernetes namespace and is designed to operate within a Kubernetes cluster. +### Overview -Configuration: +The `KubernetesSecretManager` interfaces with Kubernetes' native secrets system. + +It manages secrets within a specified Kubernetes namespace and is designed to operate within a Kubernetes cluster. + +### Configuration -Set `K8S_NAMESPACE` environment variable to specify the Kubernetes namespace. Defaults to default if not set. Assumes Kubernetes configurations (like service account tokens) are properly set up when running within a cluster. +- `SECRET_MANAGER_TYPE=k8s` +- `K8S_NAMESPACE=keep` - environment variable to specify the Kubernetes namespace. Defaults to `.metadata.namespace` if not set. Assumes Kubernetes configurations (like service account tokens) are properly set up when running within a cluster. Usage: @@ -71,6 +76,80 @@ Usage: - Provides functionalities to create, retrieve, and delete Kubernetes secrets. - Handles base64 encoding and decoding as required by Kubernetes. +### Environment Variables From Secrets +The Kubernetes Secret Manager integration allows Keep to fetch environment variables from Kubernetes Secrets. + +For sensitive environment variables, such as `DATABASE_CONNECTION_STRING`, it is recommended to store as a secret: + +#### Creating Database Connection Secret +```bash +# Create the base64 encoded string without newline +CONNECTION_STRING_B64=$(echo -n "mysql+pymysql://user:password@host:3306/dbname" | base64) + +# Create the Kubernetes secret +kubectl create secret generic keep-db-secret \ + --namespace=keep \ + --from-literal=connection_string=$(echo -n "mysql+pymysql://user:password@host:3306/dbname" | base64) + +# Or using a YAML file: +cat < You can start using Keep by logging in to the [platform](https://platform.keephq.dev). diff --git a/docs/overview/keyconcepts.mdx b/docs/overview/keyconcepts.mdx index 07c2193fe..77cd21758 100644 --- a/docs/overview/keyconcepts.mdx +++ b/docs/overview/keyconcepts.mdx @@ -23,7 +23,7 @@ A Provider can either push alerts into Keep, or Keep can pull alerts from the Pr #### Push alerts to Keep (Manual) You can configure your alert source to push alerts into Keep. -For example, consider Promethues. If you want to push alerts from Promethues to Keep, you'll need to configure Promethues Alertmanager to send the alerts to +For example, consider Prometheus. If you want to push alerts from Prometheus to Keep, you'll need to configure Prometheus Alertmanager to send the alerts to 'https://api.keephq.dev/alerts/event/prometheus' using API key authentication. Each Provider implements Push mechanism and is documented under the specific Provider page. #### Push alerts to Keep (Automatic) diff --git a/docs/providers/adding-a-new-provider.mdx b/docs/providers/adding-a-new-provider.mdx index d81520cda..e2541e95b 100644 --- a/docs/providers/adding-a-new-provider.mdx +++ b/docs/providers/adding-a-new-provider.mdx @@ -2,7 +2,7 @@ title: "Adding a new Provider" sidebarTitle: "Adding a New Provider" --- -Under contstruction +Under construction ### Basics @@ -192,7 +192,7 @@ class BaseProvider(metaclass=abc.ABCMeta): ) # else, if we are in an event context, use the event fingerprint elif self.context_manager.event_context: - # TODO: map all casses event_context is dict and update them to the DTO + # TODO: map all cases event_context is dict and update them to the DTO # and remove this if statement if isinstance(self.context_manager.event_context, dict): fingerprint = self.context_manager.event_context.get("fingerprint") @@ -446,7 +446,7 @@ class BaseProvider(metaclass=abc.ABCMeta): @staticmethod def parse_event_raw_body(raw_body: bytes) -> bytes: """ - Parse the raw body of an event and create an ingestable dict from it. + Parse the raw body of an event and create an ingestible dict from it. For instance, in parseable, the "event" is just a string > b'Alert: Server side error triggered on teststream1\nMessage: server reporting status as 500\nFailing Condition: status column equal to abcd, 2 times' @@ -459,7 +459,7 @@ class BaseProvider(metaclass=abc.ABCMeta): raw_body (bytes): The raw body of the incoming event (/event endpoint in alerts.py) Returns: - dict: Ingestable event + dict: Ingestible event """ return raw_body diff --git a/docs/providers/documentation/auth0-provider.mdx b/docs/providers/documentation/auth0-provider.mdx index 8eb53bc4e..0ea5aa8b0 100644 --- a/docs/providers/documentation/auth0-provider.mdx +++ b/docs/providers/documentation/auth0-provider.mdx @@ -51,6 +51,6 @@ workflow: audience: "https://api.example.com" grant_type: "client_credentials" -##Usefull Links +## Useful Links -[Auth0 API Documentation](https://auth0.com/docs/api) -[Auth0 as an authentication method for keep](https://docs.keephq.dev/deployment/authentication/auth0-auth) \ No newline at end of file diff --git a/docs/workflows/state.mdx b/docs/workflows/state.mdx index c06e46f34..3ef54c15d 100644 --- a/docs/workflows/state.mdx +++ b/docs/workflows/state.mdx @@ -8,7 +8,7 @@ Keep State Manager is currently used for: 2. Track alerts over time 3. Previous runs context -State is currently being saved as a JSON file under `./state/keepstate.json`, a path that can be overriden by setting the `KEEP_STATE_FILE` environment variable. +State is currently being saved as a JSON file under `./state/keepstate.json`, a path that can be overridden by setting the `KEEP_STATE_FILE` environment variable. ## Example One of the usages for Keep's state mechanism is throttling, see [One Until Resolved](/workflows/throttles/one-until-resolved) Keep handles it for you behind the scenes so you can use it without doing any further modifications. @@ -44,4 +44,4 @@ An example for a simple state file: Keep's roadmap around state (great first issues): - Saving state in a database. - Hosting state in buckets (AWS, GCP and Azure -> read/write). -- Enriching state with more context so throttling mechanism would be flexer. +- Enriching state with more context so throttling mechanism would be flexible. diff --git a/docs/workflows/syntax/basic-syntax.mdx b/docs/workflows/syntax/basic-syntax.mdx index 143dff685..b7ea0f28c 100644 --- a/docs/workflows/syntax/basic-syntax.mdx +++ b/docs/workflows/syntax/basic-syntax.mdx @@ -4,7 +4,7 @@ description: "At Keep, we view alerts as workflows, which consist of a series of --- ## Full Example ```yaml title=examples/raw_sql_query_datetime.yml -# Notify if a result queried from the DB is above a certain thershold. +# Notify if a result queried from the DB is above a certain threshold. workflow: id: raw-sql-query description: Monitor that time difference is no more than 1 hour @@ -52,7 +52,7 @@ workflow: - Metadata (id, description. owners and tags will be added soon) - `steps` - list of steps - `actions` - list of actions -- `on-failure` - a conditionless action used in case of an alert failure +- `on-failure` - an action with no condition used in case of an alert failure ### Provider ```yaml @@ -126,5 +126,5 @@ on-failure: config: " {{ providers.slack-demo }} " ``` -On-failure is actually a condtionless `Action` used to notify in case the alert failed with an exception. +On-failure is actually an `Action` with no condition used to notify in case the alert failed with an exception. The provider is passed a `message` (string) to it's `notify` function. diff --git a/docs/workflows/syntax/context-syntax.mdx b/docs/workflows/syntax/context-syntax.mdx index 4cf854780..62cff7253 100644 --- a/docs/workflows/syntax/context-syntax.mdx +++ b/docs/workflows/syntax/context-syntax.mdx @@ -1,6 +1,6 @@ --- title: "Working with context" -sidebarTitle: "Content Syntax" +sidebarTitle: "Context Syntax" description: "Keep uses [Mustache](https://mustache.github.io/) syntax to inject context at runtime, supporting functions, dictionaries, lists, and nested access." --- @@ -12,7 +12,7 @@ Here are some examples: - `keep.first({{ steps.this.results }})` - First result (equivalent to the previous example) - `{{ steps.step-id.results[0][0] }}` - First item of the first result -If you have suggestions/improvments/bugs for Keep's syntax, please [open feature request](https://github.com/keephq/keep/issues/new?assignees=&labels=&template=feature_request.md&title=) and get eternal glory. +If you have suggestions/improvements/bugs for Keep's syntax, please [open feature request](https://github.com/keephq/keep/issues/new?assignees=&labels=&template=feature_request.md&title=) and get eternal glory. ### Special context diff --git a/docs/workflows/syntax/foreach-syntax.mdx b/docs/workflows/syntax/foreach-syntax.mdx index 310f7ceb0..0d8433dca 100644 --- a/docs/workflows/syntax/foreach-syntax.mdx +++ b/docs/workflows/syntax/foreach-syntax.mdx @@ -1,7 +1,7 @@ --- title: "Foreach" sidebarTitle: "Foreach Syntax" -description: "Foreach syntax add the flexability of running action per result instead of only once on all results." +description: "Foreach syntax add the flexibility of running action per result instead of only once on all results." --- ## Usage diff --git a/docs/workflows/throttles/one-until-resolved.mdx b/docs/workflows/throttles/one-until-resolved.mdx index 6f36874bd..491c0b7bc 100644 --- a/docs/workflows/throttles/one-until-resolved.mdx +++ b/docs/workflows/throttles/one-until-resolved.mdx @@ -8,7 +8,7 @@ For example: 1. Alert executed and action were triggered as a result -> the alert status is now "Firing". 2. Alert executed again and action should be triggered -> the action will be throttled. 3. Alert executed and no action is required -> the alert status is now "Resolved". -4. Alert exectued and action were triggered -> the action is triggered +4. Alert executed and action were triggered -> the action is triggered ## How to use diff --git a/examples/workflows/cron-digest-alerts.yml b/examples/workflows/cron-digest-alerts.yml index 10baa9ecc..a4bcd786b 100644 --- a/examples/workflows/cron-digest-alerts.yml +++ b/examples/workflows/cron-digest-alerts.yml @@ -2,6 +2,7 @@ workflow: id: alerts-daily-digest description: run alerts digest twice a day (on 11:00 and 14:00) triggers: + - type: manual - type: interval cron: 0 11,14 * * * steps: @@ -10,18 +11,16 @@ workflow: provider: type: keep with: - filters: - # filter out alerts that are closed - - key: status - value: open + version: 2 + filter: "status == 'firing'" timerange: - from: "{{ state.workflows.alerts-daily-digest.last_run_time }}" + from: "{{ last_workflow_run_time }}" to: now actions: - name: send-digest foreach: "{{ steps.get-alerts.results }}" provider: - type: slack - config: "{{ providers.slack }}" + type: console + config: "{{ providers.console }}" with: - message: "Open alert: {{ foreach.value.name }}" + message: "Open alerts: {{ foreach.value.name }}" diff --git a/keep-ui/app/incidents/[id]/incident-activity.tsx b/keep-ui/app/incidents/[id]/incident-activity.tsx index f693d994d..2ab50d2d9 100644 --- a/keep-ui/app/incidents/[id]/incident-activity.tsx +++ b/keep-ui/app/incidents/[id]/incident-activity.tsx @@ -15,7 +15,7 @@ import { import { AuditEvent, useAlerts } from "@/utils/hooks/useAlerts"; import Loading from "@/app/loading"; import { useCallback, useState, useEffect } from "react"; -import { getApiURL } from "@/utils/apiUrl"; +import { useApiUrl } from "@/utils/hooks/useConfig"; import { useSession } from "next-auth/react"; import { KeyedMutator } from "swr"; import { toast } from "react-toastify"; @@ -68,7 +68,7 @@ export function IncidentActivityChronoItemComment({ mutator: KeyedMutator; }) { const [comment, setComment] = useState(""); - const apiUrl = getApiURL(); + const apiUrl = useApiUrl(); const { data: session } = useSession(); const onSubmit = useCallback(async () => { diff --git a/keep/api/models/db/migrations/versions/2024-10-22-10-38_8438f041ee0e.py b/keep/api/models/db/migrations/versions/2024-10-22-10-38_8438f041ee0e.py index eae0abfc5..dac33f5aa 100644 --- a/keep/api/models/db/migrations/versions/2024-10-22-10-38_8438f041ee0e.py +++ b/keep/api/models/db/migrations/versions/2024-10-22-10-38_8438f041ee0e.py @@ -1,9 +1,7 @@ """add pulling_enabled - Revision ID: 8438f041ee0e Revises: 83c1020be97d Create Date: 2024-10-22 10:38:29.857284 - """ import sqlalchemy as sa @@ -16,13 +14,48 @@ depends_on = None +def is_sqlite(): + """Check if we're running on SQLite""" + bind = op.get_bind() + return bind.engine.name == "sqlite" + + def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### - with op.batch_alter_table("provider", schema=None) as batch_op: - batch_op.add_column( - sa.Column("pulling_enabled", sa.Boolean(), nullable=False, default=True) + if is_sqlite(): + # SQLite specific implementation + with op.batch_alter_table("provider", schema=None) as batch_op: + # First add the column as nullable with a default value + batch_op.add_column( + sa.Column( + "pulling_enabled", + sa.Boolean(), + server_default=sa.true(), + nullable=True, + ) + ) + + # Then make it not nullable if needed + with op.batch_alter_table("provider", schema=None) as batch_op: + batch_op.alter_column("pulling_enabled", nullable=False) + else: + # PostgreSQL and other databases implementation + # 1. Add the column as nullable + op.add_column( + "provider", sa.Column("pulling_enabled", sa.Boolean(), nullable=True) + ) + # 2. Set default value for existing rows + op.execute( + "UPDATE provider SET pulling_enabled = true WHERE pulling_enabled IS NULL" + ) + # 3. Make it non-nullable with default + op.alter_column( + "provider", + "pulling_enabled", + existing_type=sa.Boolean(), + nullable=False, + server_default=sa.true(), ) - # ### end Alembic commands ### def downgrade() -> None: diff --git a/keep/api/routes/alerts.py b/keep/api/routes/alerts.py index c14c092f9..8a35b8f9d 100644 --- a/keep/api/routes/alerts.py +++ b/keep/api/routes/alerts.py @@ -4,7 +4,7 @@ import json import logging import os -from typing import Optional, List +from typing import List, Optional import celpy from arq import ArqRedis @@ -25,7 +25,12 @@ from keep.api.consts import KEEP_ARQ_QUEUE_BASIC from keep.api.core.config import config from keep.api.core.db import get_alert_audit as get_alert_audit_db -from keep.api.core.db import get_alerts_by_fingerprint, get_enrichment, get_last_alerts, get_alerts_metrics_by_provider +from keep.api.core.db import ( + get_alerts_by_fingerprint, + get_alerts_metrics_by_provider, + get_enrichment, + get_last_alerts, +) from keep.api.core.dependencies import extract_generic_body, get_pusher_client from keep.api.core.elastic import ElasticClient from keep.api.models.alert import ( @@ -37,15 +42,15 @@ from keep.api.models.alert_audit import AlertAuditDto from keep.api.models.db.alert import AlertActionType from keep.api.models.search_alert import SearchAlertsRequest +from keep.api.models.time_stamp import TimeStampFilter from keep.api.tasks.process_event_task import process_event from keep.api.utils.email_utils import EmailTemplates, send_email from keep.api.utils.enrichment_helpers import convert_db_alerts_to_dto_alerts +from keep.api.utils.time_stamp_helpers import get_time_stamp_filter from keep.identitymanager.authenticatedentity import AuthenticatedEntity from keep.identitymanager.identitymanagerfactory import IdentityManagerFactory from keep.providers.providers_factory import ProvidersFactory from keep.searchengine.searchengine import SearchEngine -from keep.api.utils.time_stamp_helpers import get_time_stamp_filter -from keep.api.models.time_stamp import TimeStampFilter router = APIRouter() logger = logging.getLogger(__name__) @@ -447,19 +452,23 @@ def enrich_alert( authenticated_entity: AuthenticatedEntity = Depends( IdentityManagerFactory.get_auth_verifier(["write:alert"]) ), + dispose_on_new_alert: Optional[bool] = Query( + False, description="Dispose on new alert" + ), ) -> dict[str, str]: - return _enrich_alert(enrich_data, authenticated_entity=authenticated_entity) + return _enrich_alert( + enrich_data, + authenticated_entity=authenticated_entity, + dispose_on_new_alert=dispose_on_new_alert, + ) def _enrich_alert( enrich_data: EnrichAlertRequestBody, - pusher_client: Pusher = Depends(get_pusher_client), authenticated_entity: AuthenticatedEntity = Depends( IdentityManagerFactory.get_auth_verifier(["write:alert"]) ), - dispose_on_new_alert: Optional[bool] = Query( - False, description="Dispose on new alert" - ), + dispose_on_new_alert: Optional[bool] = False, ) -> dict[str, str]: tenant_id = authenticated_entity.tenant_id logger.info( @@ -469,7 +478,6 @@ def _enrich_alert( "tenant_id": tenant_id, }, ) - try: enrichement_bl = EnrichmentsBl(tenant_id) # Shahar: TODO, change to the specific action type, good enough for now @@ -530,6 +538,7 @@ def _enrich_alert( logger.exception("Failed to push alert to elasticsearch") pass # use pusher to push the enriched alert to the client + pusher_client = get_pusher_client() if pusher_client: logger.info("Telling client to poll alerts") try: @@ -770,17 +779,15 @@ def get_alert_quality( ): logger.info( "Fetching alert quality metrics per provider", - extra={ - "tenant_id": authenticated_entity.tenant_id, - "fields": fields - }, - + extra={"tenant_id": authenticated_entity.tenant_id, "fields": fields}, ) start_date = time_stamp.lower_timestamp if time_stamp else None end_date = time_stamp.upper_timestamp if time_stamp else None db_alerts_quality = get_alerts_metrics_by_provider( - tenant_id=authenticated_entity.tenant_id, start_date=start_date, end_date=end_date, - fields=fields + tenant_id=authenticated_entity.tenant_id, + start_date=start_date, + end_date=end_date, + fields=fields, ) - + return db_alerts_quality diff --git a/keep/contextmanager/contextmanager.py b/keep/contextmanager/contextmanager.py index b044962c4..59ca134bc 100644 --- a/keep/contextmanager/contextmanager.py +++ b/keep/contextmanager/contextmanager.py @@ -35,6 +35,7 @@ def __init__(self, tenant_id, workflow_id=None, workflow_execution_id=None): self.click_context = {} # last workflow context self.last_workflow_execution_results = {} + self.last_workflow_run_time = None if self.workflow_id: try: last_workflow_execution = get_last_workflow_execution_by_workflow_id( @@ -44,6 +45,7 @@ def __init__(self, tenant_id, workflow_id=None, workflow_execution_id=None): self.last_workflow_execution_results = ( last_workflow_execution.results ) + self.last_workflow_run_time = last_workflow_execution.started except Exception: self.logger.exception("Failed to get last workflow execution") pass @@ -130,6 +132,7 @@ def get_full_context(self, exclude_providers=False, exclude_env=False): "foreach": self.foreach_context, "event": self.event_context, "last_workflow_results": self.last_workflow_execution_results, + "last_workflow_run_time": self.last_workflow_run_time, "alert": self.event_context, # this is an alias so workflows will be able to use alert.source "incident": self.incident_context, # this is an alias so workflows will be able to use alert.source "consts": self.consts_context, diff --git a/keep/providers/keep_provider/keep_provider.py b/keep/providers/keep_provider/keep_provider.py index c06f251f0..6a7137b59 100644 --- a/keep/providers/keep_provider/keep_provider.py +++ b/keep/providers/keep_provider/keep_provider.py @@ -3,6 +3,7 @@ """ import logging +from datetime import datetime, timezone from keep.api.core.db import get_alerts_with_filters from keep.api.models.alert import AlertDto @@ -28,6 +29,31 @@ def dispose(self): """ pass + def _calculate_time_delta(self, timerange=None, default_time_range=1): + """Calculate time delta in days from timerange dict.""" + if not timerange or "from" not in timerange: + return default_time_range # default value + + from_time_str = timerange["from"] + to_time_str = timerange.get("to", "now") + + # Parse from_time and ensure it's timezone-aware + from_time = datetime.fromisoformat(from_time_str.replace("Z", "+00:00")) + if from_time.tzinfo is None: + from_time = from_time.replace(tzinfo=timezone.utc) + + # Handle 'to' time + if to_time_str == "now": + to_time = datetime.now(timezone.utc) + else: + to_time = datetime.fromisoformat(to_time_str.replace("Z", "+00:00")) + if to_time.tzinfo is None: + to_time = to_time.replace(tzinfo=timezone.utc) + + # Calculate difference in days + delta = (to_time - from_time).total_seconds() / (24 * 3600) # convert to days + return delta + def _query(self, filters=None, version=1, distinct=True, time_delta=1, **kwargs): """ Query Keep for alerts. @@ -40,6 +66,11 @@ def _query(self, filters=None, version=1, distinct=True, time_delta=1, **kwargs) "time_delta": time_delta, }, ) + # if timerange is provided, calculate time delta + if kwargs.get("timerange"): + time_delta = self._calculate_time_delta( + timerange=kwargs.get("timerange"), default_time_range=time_delta + ) if version == 1: # filters are mandatory for version 1 if not filters: diff --git a/keep/providers/zabbix_provider/zabbix_provider.py b/keep/providers/zabbix_provider/zabbix_provider.py index b7bca0ad3..9ca8d7b14 100644 --- a/keep/providers/zabbix_provider/zabbix_provider.py +++ b/keep/providers/zabbix_provider/zabbix_provider.py @@ -594,6 +594,8 @@ def _format_alert( event_id = event.get("id") trigger_id = event.get("triggerId") zabbix_url = event.pop("ZABBIX.URL", None) + hostname = event.get("HOST.NAME") + ip_address = event.get("HOST.IP") if zabbix_url == "{$ZABBIX.URL}": # This means user did not configure $ZABBIX.URL in Zabbix probably @@ -638,6 +640,9 @@ def _format_alert( url=url, lastReceived=last_received, tags=tags, + hostname=hostname, + service=hostname, + ip_address=ip_address, ) diff --git a/pyproject.toml b/pyproject.toml index 5546b50e7..6d44fbede 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "keep" -version = "0.27.1" +version = "0.27.6" description = "Alerting. for developers, by developers." authors = ["Keep Alerting LTD"] readme = "README.md"