# HG changeset patch # User Jonas Schäfer # Date 1622125090 -7200 # Node ID cade5dac10034c7da0842428338a24e23e0b609f # Parent 5b4f43b90766c8c428a55b1983a2fb3e8595076b mod_http_admin_api: Add endpoints for server maintenance diff -r 5b4f43b90766 -r cade5dac1003 mod_http_admin_api/mod_http_admin_api.lua --- a/mod_http_admin_api/mod_http_admin_api.lua Tue May 25 19:01:54 2021 +0200 +++ b/mod_http_admin_api/mod_http_admin_api.lua Thu May 27 16:18:10 2021 +0200 @@ -3,9 +3,11 @@ local json = require "util.json"; local st = require "util.stanza"; local array = require "util.array"; +local statsmanager = require "core.statsmanager"; module:depends("http"); +local announce = module:depends("announce"); local invites = module:depends("invites"); local tokens = module:depends("tokenauth"); local mod_pep = module:depends("pep"); @@ -578,6 +580,83 @@ }); end +local function maybe_export_plain_gauge(mf) + if mf == nil then + return nil + end + return mf.data.value +end + +local function maybe_export_plain_counter(mf) + if mf == nil then + return nil + end + return { + since = mf.data._created, + value = mf.data.value, + } +end + +local function maybe_export_summed_gauge(mf) + if mf == nil then + return nil + end + local sum = 0; + for _, metric in mf:iter_metrics() do + sum = sum + metric.value; + end + return sum; +end + +local function get_server_metrics(event) + event.response.headers["Content-Type"] = json_content_type; + local result = {}; + local families = statsmanager.get_metric_registry():get_metric_families(); + result.memory = maybe_export_plain_gauge(families.process_resident_memory_bytes); + result.cpu = maybe_export_plain_counter(families.process_cpu_seconds); + result.c2s = maybe_export_summed_gauge(families["prosody_mod_c2s/connections"]) + return json.encode(result); +end + +local function post_server_announcement(event) + local request = event.request; + if request.headers.content_type ~= json_content_type + or (not request.body or #request.body == 0) then + return 400; + end + local body = json.decode(event.request.body); + if not body then + return 400; + end + + if type(body.recipients) ~= "table" and body.recipients ~= "online" and body.recipients ~= "all" then + return 400; + end + + if not body.body or #body.body == 0 then + return 400; + end + + local message = st.message():tag("body"):text(body.body):up(); + local host = module.host + message.attr.from = host + if body.recipients == "online" then + announce.send_to_online(message, host); + elseif body.recipients == "all" then + for username in usermanager.users(host) do + message.attr.to = username .. "@" .. host + module:send(st.clone(message)) + end + else + for _, addr in ipairs(body.recipients) do + message.attr.to = addr + module:send(message) + end + end + + return 201; +end + module:provides("http", { route = check_auth { ["GET /invites"] = list_invites; @@ -597,5 +676,8 @@ ["DELETE /groups/*"] = delete_group; ["GET /server/info"] = get_server_info; + + ["GET /server/metrics"] = get_server_metrics; + ["POST /server/announcement"] = post_server_announcement; }; }); diff -r 5b4f43b90766 -r cade5dac1003 mod_http_admin_api/openapi.yaml --- a/mod_http_admin_api/openapi.yaml Tue May 25 19:01:54 2021 +0200 +++ b/mod_http_admin_api/openapi.yaml Thu May 27 16:18:10 2021 +0200 @@ -437,6 +437,35 @@ application/json: schema: $ref: '#/components/schemas/ServerInfo' + /server/metrics: + get: + tags: + - server + summary: Get metrics from the running server + operationId: getServerMetrics + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ServerMetrics' + /server/announcement: + post: + tags: + - server + summary: Post an announcement to some or all users + operationId: postServerAnnouncement + requestBody: + description: Announcement parameters + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/Announcement" + responses: + 201: + description: Announcement has been sent components: schemas: UserList: @@ -735,4 +764,39 @@ description: A friendly name for the service version: type: string - description: A human-readable version string \ No newline at end of file + description: A human-readable version string + ServerMetrics: + type: object + description: A selection of instantaneous metrics of the prosody server + properties: + memory: + type: integer + description: RSS in bytes + cpu: + type: object + description: CPU time counter + required: + - value + - since + properties: + since: + type: float + description: The metric epoch as UNIX timestamp + value: + type: float + description: Seconds of CPU time used since the metric epoch + c2s: + type: integer + description: Number of active c2s sessions + Announcement: + type: object + description: An announcemen to post to users on the server + required: + - body + - recipients + properties: + body: + type: string + description: The message body to send + recipients: + description: List of recipients or one of the strings "online" or "all"