File

mod_pubsub_alertmanager/mod_pubsub_alertmanager.lua @ 5418:f2c7bb3af600

mod_http_oauth2: Add role selector to consent page List includes all roles available to the user, if more than one. Defaults to either the first role in the scope string or the users primary role. Earlier draft listed all roles, but having options that can't be selected is bad UX and the entire list of all roles on the server could be long, and perhaps even sensitive. Allows e.g. picking a role with fewer permissions than what might otherwise have been selected. UX wise, doing this with more checkboxes or possibly radio buttons would have been confusion and/or looked messier. Fixes the previous situation where unselecting a role would default to the primary role, which could be more permissions than requested.
author Kim Alvefur <zash@zash.se>
date Fri, 05 May 2023 01:23:13 +0200
parent 4627:adda872fa9e1
child 5485:67190744b1eb
line wrap: on
line source

local st = require "util.stanza";
local json = require "util.json";
local filters = { --[[ TODO what's useful? ]] };
local render = require "util.interpolation".new("%b{}", tostring, filters);
local uuid_generate = require "util.uuid".generate;

-- TODO alertmanager supports inclusion of HTTP auth and OAuth, worth looking
-- into for using instead of request IP

module:depends("http");

local pubsub_service = module:depends("pubsub").service;

local error_mapping = {
	["forbidden"] = 403;
	["item-not-found"] = 404;
	["internal-server-error"] = 500;
	["conflict"] = 409;
};

local function publish_payload(node, actor, item_id, payload)
	local post_item = st.stanza("item", { xmlns = "http://jabber.org/protocol/pubsub", id = item_id, })
		:add_child(payload);
	local ok, err = pubsub_service:publish(node, actor, item_id, post_item);
	module:log("debug", ":publish(%q, true, %q, %s) -> %q", node, item_id, payload:top_tag(), err or "");
	if not ok then
		return error_mapping[err] or 500;
	end
	return 202;
end

local node_template = module:get_option_string("alertmanager_node_template", "{path?alerts}");

function handle_POST(event, path)
	local request = event.request;

	local payload = json.decode(event.request.body);
	if type(payload) ~= "table" then return 400; end
	if payload.version ~= "4" then return 501; end

	for _, alert in ipairs(payload.alerts) do
		local item = st.stanza("alerts", {xmlns = "urn:uuid:e3bec775-c607-4e9b-9a3f-94de1316d861:v4", status=alert.status});
		for k, v in pairs(alert.annotations) do
			item:text_tag("annotation", v, { name=k });
		end
		for k, v in pairs(alert.labels) do
			item:text_tag("label", v, { name=k });
		end
		item:tag("starts", { at = alert.startsAt}):up();
		if alert.endsAt and alert.status == "resolved" then
			item:tag("ends", { at = alert.endsAt }):up();
		end
		if alert.generatorURL then
			item:tag("link", { href=alert.generatorURL }):up();
		end

		local node = render(node_template, {alert = alert, path = path, payload = payload, request = request});
		local ret = publish_payload(node, request.ip, uuid_generate(), item);
		if ret ~= 202 then
			return ret
		end
	end
	return 202;
end

local template = module:get_option_string("alertmanager_body_template", [[
*ALARM!*
Status: {status}
Starts at: {startsAt}{endsAt&
Ends at: {endsAt}}
Labels: {labels%
  {idx}: {item}}
Annotations: {annotations%
  {idx}: {item}}
]]);

module:hook("pubsub-summary/urn:uuid:e3bec775-c607-4e9b-9a3f-94de1316d861:v4", function(event)
	local payload = event.payload;

	local data = {
		status = payload.attr.status,
		firing = "firing" == payload.attr.status,
		resolved = "resolved" == payload.attr.status,
		annotations = {},
		labels = {},
		endsAt = payload:find("ends/@at"),
		startsAt = payload:find("starts/@at"),
	};
	for label in payload:childtags("label") do
		data.labels[tostring(label.attr.name)] = label:get_text();
	end
	for annotation in payload:childtags("annotation") do
		data.annotations[tostring(annotation.attr.name)] = annotation:get_text();
	end

	return render(template, data);
end);

module:provides("http", {
	route = {
		["POST /*"] = handle_POST;
		["POST"] = handle_POST;
	};
});