root/lrmd/lrmd_alert_api.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. alert_drain_timeout_callback
  7. lrmd_drain_alerts

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

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