root/daemons/execd/execd_alerts.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. add_inflight_alert
  2. remove_inflight_alert
  3. max_inflight_timeout
  4. alert_complete
  5. process_lrmd_alert_exec
  6. drain_check
  7. lrmd_drain_alerts

   1 /*
   2  * Copyright 2016-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU General Public License version 2
   7  * or later (GPLv2+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #include <glib.h>
  13 
  14 #include <crm/crm.h>
  15 #include <crm/services.h>
  16 #include <crm/common/ipc.h>
  17 #include <crm/common/ipc_internal.h>
  18 #include <crm/common/alerts_internal.h>
  19 #include <crm/msg_xml.h>
  20 
  21 #include "pacemaker-execd.h"
  22 
  23 /* Track in-flight alerts so we can wait for them at shutdown */
  24 static GHashTable *inflight_alerts; /* key = call_id, value = timeout */
  25 static gboolean draining_alerts = FALSE;
  26 
  27 static inline void
  28 add_inflight_alert(int call_id, int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
  29 {
  30     if (inflight_alerts == NULL) {
  31         inflight_alerts = g_hash_table_new(g_direct_hash, g_direct_equal);
  32     }
  33     g_hash_table_insert(inflight_alerts, GINT_TO_POINTER(call_id),
  34                         GINT_TO_POINTER(timeout));
  35 }
  36 
  37 static inline void
  38 remove_inflight_alert(int call_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40     if (inflight_alerts != NULL) {
  41         g_hash_table_remove(inflight_alerts, GINT_TO_POINTER(call_id));
  42     }
  43 }
  44 
  45 static int
  46 max_inflight_timeout(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  47 {
  48     GHashTableIter iter;
  49     gpointer timeout;
  50     int max_timeout = 0;
  51 
  52     if (inflight_alerts) {
  53         g_hash_table_iter_init(&iter, inflight_alerts);
  54         while (g_hash_table_iter_next(&iter, NULL, &timeout)) {
  55             if (GPOINTER_TO_INT(timeout) > max_timeout) {
  56                 max_timeout = GPOINTER_TO_INT(timeout);
  57             }
  58         }
  59     }
  60     return max_timeout;
  61 }
  62 
  63 struct alert_cb_s {
  64     char *client_id;
  65     int call_id;
  66 };
  67 
  68 static void
  69 alert_complete(svc_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71     struct alert_cb_s *cb_data = (struct alert_cb_s *) (action->cb_data);
  72 
  73     remove_inflight_alert(cb_data->call_id);
  74     crm_debug("Alert pid %d for %s completed with rc=%d",
  75               action->pid, cb_data->client_id, action->rc);
  76 
  77     free(cb_data->client_id);
  78     free(action->cb_data);
  79     action->cb_data = NULL;
  80 }
  81 
  82 int
  83 process_lrmd_alert_exec(pcmk__client_t *client, uint32_t id, xmlNode *request)
     /* [previous][next][first][last][top][bottom][index][help] */
  84 {
  85     static int alert_sequence_no = 0;
  86 
  87     xmlNode *alert_xml = get_xpath_object("//" F_LRMD_ALERT, request, LOG_ERR);
  88     const char *alert_id = crm_element_value(alert_xml, F_LRMD_ALERT_ID);
  89     const char *alert_path = crm_element_value(alert_xml, F_LRMD_ALERT_PATH);
  90     svc_action_t *action = NULL;
  91     int alert_timeout = 0;
  92     int rc = pcmk_ok;
  93     GHashTable *params = NULL;
  94     struct alert_cb_s *cb_data = NULL;
  95 
  96     if ((alert_id == NULL) || (alert_path == NULL) ||
  97         (client == NULL) || (client->id == NULL)) { /* hint static analyzer */
  98         return -EINVAL;
  99     }
 100     if (draining_alerts) {
 101         return pcmk_ok;
 102     }
 103 
 104     crm_element_value_int(alert_xml, F_LRMD_TIMEOUT, &alert_timeout);
 105 
 106     crm_info("Executing alert %s for %s", alert_id, client->id);
 107 
 108     params = xml2list(alert_xml);
 109     pcmk__add_alert_key_int(params, PCMK__alert_key_node_sequence,
 110                             ++alert_sequence_no);
 111 
 112     cb_data = calloc(1, sizeof(struct alert_cb_s));
 113     CRM_CHECK(cb_data != NULL,
 114               rc = -ENOMEM; goto err);
 115 
 116     /* coverity[deref_ptr] False Positive */
 117     cb_data->client_id = strdup(client->id);
 118     CRM_CHECK(cb_data->client_id != NULL,
 119               rc = -ENOMEM; goto err);
 120 
 121     crm_element_value_int(request, F_LRMD_CALLID, &(cb_data->call_id));
 122 
 123     action = services_alert_create(alert_id, alert_path, alert_timeout, params,
 124                                    alert_sequence_no, cb_data);
 125     rc = services_action_user(action, CRM_DAEMON_USER);
 126     if (rc < 0) {
 127         goto err;
 128     }
 129 
 130     add_inflight_alert(cb_data->call_id, alert_timeout);
 131     if (services_alert_async(action, alert_complete) == FALSE) {
 132         services_action_free(action);
 133     }
 134     return pcmk_ok;
 135 
 136 err:
 137     if (cb_data) {
 138         if (cb_data->client_id) {
 139             free(cb_data->client_id);
 140         }
 141         free(cb_data);
 142     }
 143     if (action) {
 144         services_action_free(action);
 145     }
 146     return rc;
 147 }
 148 
 149 static bool
 150 drain_check(guint remaining_timeout_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152     if (inflight_alerts != NULL) {
 153         guint count = g_hash_table_size(inflight_alerts);
 154 
 155         if (count > 0) {
 156             crm_trace("%d alerts pending (%.3fs timeout remaining)",
 157                       count, remaining_timeout_ms / 1000.0);
 158             return TRUE;
 159         }
 160     }
 161     return FALSE;
 162 }
 163 
 164 void
 165 lrmd_drain_alerts(GMainLoop *mloop)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167     if (inflight_alerts != NULL) {
 168         guint timer_ms = max_inflight_timeout() + 5000;
 169 
 170         crm_trace("Draining in-flight alerts (timeout %.3fs)",
 171                   timer_ms / 1000.0);
 172         draining_alerts = TRUE;
 173         pcmk_drain_main_loop(mloop, timer_ms, drain_check);
 174         g_hash_table_destroy(inflight_alerts);
 175         inflight_alerts = NULL;
 176     }
 177 }

/* [previous][next][first][last][top][bottom][index][help] */