diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:53:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:53:20 +0000 |
commit | e5a812082ae033afb1eed82c0f2df3d0f6bdc93f (patch) | |
tree | a6716c9275b4b413f6c9194798b34b91affb3cc7 /daemons/execd/execd_alerts.c | |
parent | Initial commit. (diff) | |
download | pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.tar.xz pacemaker-e5a812082ae033afb1eed82c0f2df3d0f6bdc93f.zip |
Adding upstream version 2.1.6.upstream/2.1.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'daemons/execd/execd_alerts.c')
-rw-r--r-- | daemons/execd/execd_alerts.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/daemons/execd/execd_alerts.c b/daemons/execd/execd_alerts.c new file mode 100644 index 0000000..5944d93 --- /dev/null +++ b/daemons/execd/execd_alerts.c @@ -0,0 +1,205 @@ +/* + * Copyright 2016-2022 the Pacemaker project contributors + * + * The version control history for this file may have further details. + * + * This source code is licensed under the GNU General Public License version 2 + * or later (GPLv2+) WITHOUT ANY WARRANTY. + */ + +#include <crm_internal.h> + +#include <glib.h> + +#include <crm/crm.h> +#include <crm/services.h> +#include <crm/services_internal.h> +#include <crm/common/ipc.h> +#include <crm/common/ipc_internal.h> +#include <crm/common/alerts_internal.h> +#include <crm/msg_xml.h> + +#include "pacemaker-execd.h" + +/* Track in-flight alerts so we can wait for them at shutdown */ +static GHashTable *inflight_alerts; /* key = call_id, value = timeout */ +static gboolean draining_alerts = FALSE; + +static inline void +add_inflight_alert(int call_id, int timeout) +{ + if (inflight_alerts == NULL) { + inflight_alerts = pcmk__intkey_table(NULL); + } + pcmk__intkey_table_insert(inflight_alerts, call_id, + GINT_TO_POINTER(timeout)); +} + +static inline void +remove_inflight_alert(int call_id) +{ + if (inflight_alerts != NULL) { + pcmk__intkey_table_remove(inflight_alerts, call_id); + } +} + +static int +max_inflight_timeout(void) +{ + GHashTableIter iter; + gpointer timeout; + int max_timeout = 0; + + if (inflight_alerts) { + g_hash_table_iter_init(&iter, inflight_alerts); + while (g_hash_table_iter_next(&iter, NULL, &timeout)) { + if (GPOINTER_TO_INT(timeout) > max_timeout) { + max_timeout = GPOINTER_TO_INT(timeout); + } + } + } + return max_timeout; +} + +struct alert_cb_s { + char *client_id; + int call_id; +}; + +static void +alert_complete(svc_action_t *action) +{ + struct alert_cb_s *cb_data = (struct alert_cb_s *) (action->cb_data); + + CRM_CHECK(cb_data != NULL, return); + + remove_inflight_alert(cb_data->call_id); + + if (action->status != PCMK_EXEC_DONE) { + const char *reason = services__exit_reason(action); + + crm_notice("Could not send alert: %s%s%s%s " CRM_XS " client=%s", + pcmk_exec_status_str(action->status), + (reason == NULL)? "" : " (", + (reason == NULL)? "" : reason, + (reason == NULL)? "" : ")", + cb_data->client_id); + + } else if (action->rc != 0) { + crm_notice("Alert [%d] completed but exited with status %d " + CRM_XS " client=%s", + action->pid, action->rc, cb_data->client_id); + + } else { + crm_debug("Alert [%d] completed " CRM_XS " client=%s", + action->pid, cb_data->client_id); + } + + free(cb_data->client_id); + free(action->cb_data); + action->cb_data = NULL; +} + +int +process_lrmd_alert_exec(pcmk__client_t *client, uint32_t id, xmlNode *request) +{ + static int alert_sequence_no = 0; + + xmlNode *alert_xml = get_xpath_object("//" F_LRMD_ALERT, request, LOG_ERR); + const char *alert_id = crm_element_value(alert_xml, F_LRMD_ALERT_ID); + const char *alert_path = crm_element_value(alert_xml, F_LRMD_ALERT_PATH); + svc_action_t *action = NULL; + int alert_timeout = 0; + int rc = pcmk_ok; + GHashTable *params = NULL; + struct alert_cb_s *cb_data = NULL; + + if ((alert_id == NULL) || (alert_path == NULL) || + (client == NULL) || (client->id == NULL)) { /* hint static analyzer */ + return -EINVAL; + } + if (draining_alerts) { + return pcmk_ok; + } + + crm_element_value_int(alert_xml, F_LRMD_TIMEOUT, &alert_timeout); + + crm_info("Executing alert %s for %s", alert_id, client->id); + + params = xml2list(alert_xml); + pcmk__add_alert_key_int(params, PCMK__alert_key_node_sequence, + ++alert_sequence_no); + + cb_data = calloc(1, sizeof(struct alert_cb_s)); + if (cb_data == NULL) { + rc = -errno; + goto err; + } + + /* coverity[deref_ptr] False Positive */ + cb_data->client_id = strdup(client->id); + if (cb_data->client_id == NULL) { + rc = -errno; + goto err; + } + + crm_element_value_int(request, F_LRMD_CALLID, &(cb_data->call_id)); + + action = services_alert_create(alert_id, alert_path, alert_timeout, params, + alert_sequence_no, cb_data); + if (action->rc != PCMK_OCF_UNKNOWN) { + rc = -E2BIG; + goto err; + } + + rc = services_action_user(action, CRM_DAEMON_USER); + if (rc < 0) { + goto err; + } + + add_inflight_alert(cb_data->call_id, alert_timeout); + if (services_alert_async(action, alert_complete) == FALSE) { + services_action_free(action); + } + return pcmk_ok; + +err: + if (cb_data) { + if (cb_data->client_id) { + free(cb_data->client_id); + } + free(cb_data); + } + services_action_free(action); + return rc; +} + +static bool +drain_check(guint remaining_timeout_ms) +{ + if (inflight_alerts != NULL) { + guint count = g_hash_table_size(inflight_alerts); + + if (count > 0) { + crm_trace("%d alerts pending (%.3fs timeout remaining)", + count, remaining_timeout_ms / 1000.0); + return TRUE; + } + } + return FALSE; +} + +void +lrmd_drain_alerts(GMainLoop *mloop) +{ + if (inflight_alerts != NULL) { + guint timer_ms = max_inflight_timeout() + 5000; + + crm_trace("Draining in-flight alerts (timeout %.3fs)", + timer_ms / 1000.0); + draining_alerts = TRUE; + pcmk_drain_main_loop(mloop, timer_ms, drain_check); + g_hash_table_destroy(inflight_alerts); + inflight_alerts = NULL; + } +} |