From d16611bbdd2a9ad24364edef21ca1d479d465fc7 Mon Sep 17 00:00:00 2001
From: Pietro Tota <115724836+pietro-tota@users.noreply.github.com>
Date: Wed, 6 Sep 2023 17:44:53 +0200
Subject: [PATCH] feat(openapi spec): modified specs to complain to grafana
webhook (#6)
* feat(openapi spec): modified specs to complain to grafana webhook
* fix: add sonar cloud action project key
* fix: pom typo
---
.github/workflows/code_review.yml | 2 +-
api-spec/openapi.yaml | 126 +++++++++++-----
pom.xml | 2 +-
.../qi/alertmanagement/AlertParsingTests.java | 142 ++++++++++++++++++
4 files changed, 233 insertions(+), 39 deletions(-)
create mode 100644 src/test/java/it/pagopa/qi/alertmanagement/AlertParsingTests.java
diff --git a/.github/workflows/code_review.yml b/.github/workflows/code_review.yml
index 3ea4730..8887f2b 100644
--- a/.github/workflows/code_review.yml
+++ b/.github/workflows/code_review.yml
@@ -18,7 +18,7 @@ on:
workflow_dispatch:
env:
- PROJECT_KEY: # TODO
+ PROJECT_KEY: pagopa_pagopa-qi-alerts-management-function
permissions:
id-token: write
diff --git a/api-spec/openapi.yaml b/api-spec/openapi.yaml
index a971dce..be8cf85 100644
--- a/api-spec/openapi.yaml
+++ b/api-spec/openapi.yaml
@@ -9,7 +9,7 @@ tags:
- name: QI
description: Api's for alert ingestion
externalDocs:
- url: TODO
+ url: https://pagopa.atlassian.net/wiki/spaces/PPAOP/pages/758874245/DR+Gestione+Alert
description: Technical specifications
paths:
@@ -83,51 +83,103 @@ components:
example: 200
QiAlertIngestionRequest:
type: object
- description: Alert ingestion request
+ description: Alert ingestion request. This maps grafana webhook specifications https://grafana.com/docs/grafana/latest/alerting/alerting-rules/manage-contact-points/webhook-notifier
properties:
+ receiver:
+ type: string
+ description: Name of the webhook
+ status:
+ type: string
+ description: Current status of the alert, firing or resolved
+ orgId:
+ type: number
+ description: ID of the organization related to the payload
alerts:
type: array
+ description: Alerts that are triggering
items:
$ref: '#/components/schemas/AlertInfo'
- minItems: 1
- required:
- - alerts
- AlertInfo:
+ groupLabels:
+ $ref: '#/components/schemas/KeyValueMapStringValue'
+ commonLabels:
+ $ref: '#/components/schemas/KeyValueMapStringValue'
+ commonAnnotations:
+ $ref: '#/components/schemas/KeyValueMapStringValue'
+ externalURL:
+ type: string
+ format: uri
+ description: External URL to the Grafana instance sending this webhook
+ version:
+ type: string
+ description: Version of the payload
+ groupKey:
+ type: string
+ description: Key that is used for grouping
+ truncatedAlerts:
+ type: number
+ description: Number of alerts that were truncated
+ title:
+ type: string
+ description: Will be deprecated soon
+ state:
+ type: string
+ description: Will be deprecated soon
+ message:
+ type: string
+ description: Will be deprecated soon
+ AlertInfo:
type: object
description: Alert information
- properties:
- code:
- type: string
- description: Unique code that identifies the alert typology
- enum:
- - TDP
- - TGP
- - TSRT
- - TVP
- - TPNP
- - TNSPO
- - TPSPO
- - NFER
- - NBI
- owner:
- type: string
- description: Identifier of subject that caused the alert trigger
- threshold:
- type: integer
- description: Alert metric threshold
- value:
- type: integer
- description: Detected metric threshold that trigger alert
- triggerDate:
+ properties:
+ status:
+ type: string
+ description: Current status of the alert, firing or resolved
+ labels:
+ $ref: '#/components/schemas/KeyValueMapStringValue'
+ annotations:
+ $ref: '#/components/schemas/KeyValueMapStringValue'
+ startsAt:
type: string
format: date-time
- description: Timestamp when alert is triggered
- required:
- - code
- - owner
- - threshold
- - value
- - triggerDate
+ description: Start time of the alert
+ endsAt:
+ type: string
+ format: date-time
+ description: End time of the alert, default value when not resolved is 0001-01-01T00:00:00Z
+ values:
+ $ref: '#/components/schemas/KeyValueMapNumericValue'
+ generatorURL:
+ type: string
+ format: uri
+ description: URL of the alert rule in the Grafana UI
+ fingerprint:
+ type: string
+ description: The labels fingerprint, alarms with the same labels will have the same fingerprint
+ silenceURL:
+ type: string
+ format: uri
+ description: URL to silence the alert rule in the Grafana UI
+ dashboardURL:
+ type: string
+ format: uri
+ description: Will be deprecated soon
+ panelURL:
+ type: string
+ format: uri
+ description: Will be deprecated soon
+ imageURL:
+ type: string
+ format: uri
+ description: Will be deprecated soon
+ KeyValueMapStringValue:
+ type: object
+ additionalProperties:
+ type: string
+ KeyValueMapNumericValue:
+ type: object
+ additionalProperties:
+ type: number
+ format: double
requestBodies:
QiAlertIngestionRequest:
required: true
diff --git a/pom.xml b/pom.xml
index d4d08a9..34a9944 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
it.pagopa
- pagopa-qi-alerte-management-function
+ pagopa-qi-alerts-management-function
0.0.1
jar
diff --git a/src/test/java/it/pagopa/qi/alertmanagement/AlertParsingTests.java b/src/test/java/it/pagopa/qi/alertmanagement/AlertParsingTests.java
new file mode 100644
index 0000000..ead5cff
--- /dev/null
+++ b/src/test/java/it/pagopa/qi/alertmanagement/AlertParsingTests.java
@@ -0,0 +1,142 @@
+package it.pagopa.qi.alertmanagement;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import it.pagopa.generated.qi.alerts.v1.dto.AlertInfoDto;
+import it.pagopa.generated.qi.alerts.v1.dto.QiAlertIngestionRequestDto;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.net.URI;
+import java.time.OffsetDateTime;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class AlertParsingTests {
+
+ private final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
+
+ /**
+ * Webhook alert example taken from grafana documentation at: ...
+ */
+ private final String webhokAlertExample = "{\n" +
+ " \"receiver\": \"My Super Webhook\",\n" +
+ " \"status\": \"firing\",\n" +
+ " \"orgId\": 1,\n" +
+ " \"alerts\": [\n" +
+ " {\n" +
+ " \"status\": \"firing\",\n" +
+ " \"labels\": {\n" +
+ " \"alertname\": \"High memory usage\",\n" +
+ " \"team\": \"blue\",\n" +
+ " \"zone\": \"us-1\"\n" +
+ " },\n" +
+ " \"annotations\": {\n" +
+ " \"description\": \"The system has high memory usage\",\n" +
+ " \"runbook_url\": \"https://myrunbook.com/runbook/1234\",\n" +
+ " \"summary\": \"This alert was triggered for zone us-1\"\n" +
+ " },\n" +
+ " \"startsAt\": \"2021-10-12T09:51:03.157076+02:00\",\n" +
+ " \"endsAt\": \"0001-01-01T00:00:00Z\",\n" +
+ " \"generatorURL\": \"https://play.grafana.org/alerting/1afz29v7z/edit\",\n" +
+ " \"fingerprint\": \"c6eadffa33fcdf37\",\n" +
+ " \"silenceURL\": \"https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT2%2Cteam%3Dblue%2Czone%3Dus-1\",\n" +
+ " \"dashboardURL\": \"\",\n" +
+ " \"panelURL\": \"\",\n" +
+ " \"values\": {\n" +
+ " \"B\": 44.23943737541908,\n" +
+ " \"C\": 1\n" +
+ " }\n" +
+ " },\n" +
+ " {\n" +
+ " \"status\": \"firing\",\n" +
+ " \"labels\": {\n" +
+ " \"alertname\": \"High CPU usage\",\n" +
+ " \"team\": \"blue\",\n" +
+ " \"zone\": \"eu-1\"\n" +
+ " },\n" +
+ " \"annotations\": {\n" +
+ " \"description\": \"The system has high CPU usage\",\n" +
+ " \"runbook_url\": \"https://myrunbook.com/runbook/1234\",\n" +
+ " \"summary\": \"This alert was triggered for zone eu-1\"\n" +
+ " },\n" +
+ " \"startsAt\": \"2021-10-12T09:56:03.157076+02:00\",\n" +
+ " \"endsAt\": \"0001-01-01T00:00:00Z\",\n" +
+ " \"generatorURL\": \"https://play.grafana.org/alerting/d1rdpdv7k/edit\",\n" +
+ " \"fingerprint\": \"bc97ff14869b13e3\",\n" +
+ " \"silenceURL\": \"https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT1%2Cteam%3Dblue%2Czone%3Deu-1\",\n" +
+ " \"dashboardURL\": \"\",\n" +
+ " \"panelURL\": \"\",\n" +
+ " \"values\": {\n" +
+ " \"B\": 44.23943737541908,\n" +
+ " \"C\": 1\n" +
+ " }\n" +
+ " }\n" +
+ " ],\n" +
+ " \"groupLabels\": {},\n" +
+ " \"commonLabels\": {\n" +
+ " \"team\": \"blue\"\n" +
+ " },\n" +
+ " \"commonAnnotations\": {},\n" +
+ " \"externalURL\": \"https://play.grafana.org/\",\n" +
+ " \"version\": \"1\",\n" +
+ " \"groupKey\": \"{}:{}\",\n" +
+ " \"truncatedAlerts\": 0,\n" +
+ " \"title\": \"[FIRING:2] (blue)\",\n" +
+ " \"state\": \"alerting\",\n" +
+ " \"message\": \"**Firing**\\n\\nLabels:\\n - alertname = T2\\n - team = blue\\n - zone = us-1\\nAnnotations:\\n - description = This is the alert rule checking the second system\\n - runbook_url = https://myrunbook.com\\n - summary = This is my summary\\nSource: https://play.grafana.org/alerting/1afz29v7z/edit\\nSilence: https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT2%2Cteam%3Dblue%2Czone%3Dus-1\\n\\nLabels:\\n - alertname = T1\\n - team = blue\\n - zone = eu-1\\nAnnotations:\\nSource: https://play.grafana.org/alerting/d1rdpdv7k/edit\\nSilence: https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT1%2Cteam%3Dblue%2Czone%3Deu-1\\n\"\n" +
+ "}\n";
+
+ @Test
+ void shouldParseAlertSuccessfully() throws JsonProcessingException {
+ //test
+ QiAlertIngestionRequestDto parsedRequest = objectMapper.readValue(webhokAlertExample, QiAlertIngestionRequestDto.class);
+ QiAlertIngestionRequestDto expectedRequest = new QiAlertIngestionRequestDto()
+ .receiver("My Super Webhook")
+ .status("firing")
+ .orgId(BigDecimal.ONE)
+ .alerts(List.of(
+ new AlertInfoDto()
+ .status("firing")
+ .labels(Map.of("alertname", "High memory usage", "team", "blue", "zone", "us-1"))
+ .annotations(Map.of("description", "The system has high memory usage", "runbook_url", "https://myrunbook.com/runbook/1234", "summary", "This alert was triggered for zone us-1"))
+ .startsAt(OffsetDateTime.parse("2021-10-12T07:51:03.157076Z"))
+ .endsAt(OffsetDateTime.parse("0001-01-01T00:00Z"))
+ .values(Map.of("B", 44.23943737541908, "C", 1.0))
+ .generatorURL(URI.create("https://play.grafana.org/alerting/1afz29v7z/edit"))
+ .fingerprint("c6eadffa33fcdf37")
+ .silenceURL(URI.create("https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT2%2Cteam%3Dblue%2Czone%3Dus-1"))
+ .dashboardURL(URI.create(""))
+ .panelURL(URI.create(""))
+ .imageURL(null),
+ new AlertInfoDto()
+ .status("firing")
+ .labels(Map.of("alertname", "High CPU usage", "team", "blue", "zone", "eu-1"))
+ .annotations(Map.of("description", "The system has high CPU usage", "runbook_url", "https://myrunbook.com/runbook/1234", "summary", "This alert was triggered for zone eu-1"))
+ .startsAt(OffsetDateTime.parse("2021-10-12T07:56:03.157076Z"))
+ .endsAt(OffsetDateTime.parse("0001-01-01T00:00Z"))
+ .values(Map.of("B", 44.23943737541908, "C", 1.0))
+ .generatorURL(URI.create("https://play.grafana.org/alerting/d1rdpdv7k/edit"))
+ .fingerprint("bc97ff14869b13e3")
+ .silenceURL(URI.create("https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT1%2Cteam%3Dblue%2Czone%3Deu-1"))
+ .dashboardURL(URI.create(""))
+ .panelURL(URI.create(""))
+ .imageURL(null)
+ ))
+ .groupLabels(Map.of())
+ .commonLabels(Map.of("team", "blue"))
+ .commonAnnotations(Map.of())
+ .externalURL(URI.create("https://play.grafana.org/"))
+ .version("1")
+ .groupKey("{}:{}")
+ .truncatedAlerts(BigDecimal.ZERO)
+ .title("[FIRING:2] (blue)")
+ .state("alerting")
+ .message("**Firing**\n\nLabels:\n - alertname = T2\n - team = blue\n - zone = us-1\nAnnotations:\n - description = This is the alert rule checking the second system\n - runbook_url = https://myrunbook.com\n - summary = This is my summary\nSource: https://play.grafana.org/alerting/1afz29v7z/edit\nSilence: https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT2%2Cteam%3Dblue%2Czone%3Dus-1\n\nLabels:\n - alertname = T1\n - team = blue\n - zone = eu-1\nAnnotations:\nSource: https://play.grafana.org/alerting/d1rdpdv7k/edit\nSilence: https://play.grafana.org/alerting/silence/new?alertmanager=grafana&matchers=alertname%3DT1%2Cteam%3Dblue%2Czone%3Deu-1\n");
+ assertEquals(expectedRequest, parsedRequest);
+
+ }
+}