@@ 76,6 76,15 @@ async fn main() {
move |headers, body| routes::message::message(shared_state, headers, body)
}),
)
+ .route(
+ "/alertmanager/v4",
+ post({
+ let shared_state = Arc::clone(&state);
+ move |headers, body| {
+ routes::alertmanager::alertmanager_v4(shared_state, headers, body)
+ }
+ }),
+ )
.layer(TraceLayer::new_for_http())
.with_state(state);
@@ 0,0 1,77 @@
+/*
+ * Copyright (C) 2025 Jonni Liljamo <jonni@liljamo.com>
+ *
+ * This file is licensed under AGPL-3.0-or-later, see NOTICE and LICENSE for
+ * more information.
+ */
+
+use std::{collections::HashMap, sync::Arc};
+
+use axum::{Json, http::HeaderMap, response::IntoResponse};
+use reqwest::StatusCode;
+use serde::Deserialize;
+
+use crate::{
+ routes::{extract_token, message::MessageForm},
+ state::State,
+};
+
+const ALERTMANAGER_JSON_VERSION_4: &str = "4";
+
+#[derive(Debug, Deserialize)]
+pub struct V4Alert {
+ annotations: HashMap<String, String>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct V4Form {
+ version: String,
+ alerts: Vec<V4Alert>,
+}
+
+impl From<V4Alert> for MessageForm {
+ fn from(value: V4Alert) -> Self {
+ MessageForm {
+ title: value
+ .annotations
+ .get("summary")
+ .cloned()
+ .unwrap_or("Summary N/A".into()),
+ message: value
+ .annotations
+ .get("description")
+ .cloned()
+ .unwrap_or("Description N/A".into()),
+ format_commonmark: false,
+ }
+ }
+}
+
+pub async fn alertmanager_v4(
+ state: Arc<State>,
+ headers: HeaderMap,
+ Json(message): Json<V4Form>,
+) -> impl IntoResponse {
+ let token = extract_token!(headers).trim_start_matches("Bearer ");
+
+ let notifier = match state.find_notifier(token) {
+ Some(n) => n,
+ None => return (StatusCode::UNAUTHORIZED, "unauthorized"),
+ };
+
+ if message.version != ALERTMANAGER_JSON_VERSION_4 {
+ return (
+ StatusCode::BAD_REQUEST,
+ "wrong alertmanager json version, this API is for version 4",
+ );
+ }
+
+ for alert in message.alerts {
+ if let Err(err) = state.send_message(notifier, &alert.into()).await {
+ tracing::error!(?err, "message sending failed");
+ return (StatusCode::INTERNAL_SERVER_ERROR, "failed to send message");
+ };
+ }
+
+ (StatusCode::OK, "")
+}