root/lib/lrmd/lrmd_alerts.c

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

DEFINITIONS

This source file includes following definitions.
  1. alert_key2param
  2. alert_key2param_int
  3. set_ev_kv
  4. alert_envvar2params
  5. is_target_alert
  6. exec_alert_list
  7. lrmd_send_attribute_alert
  8. lrmd_send_node_alert
  9. lrmd_send_fencing_alert
  10. lrmd_send_resource_alert

   1 /*
   2  * Copyright (c) 2015 David Vossel <davidvossel@gmail.com>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  * 
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  *
  18  */
  19 
  20 #include <crm_internal.h>
  21 
  22 #include <glib.h>
  23 #include <unistd.h>
  24 
  25 #include <crm/crm.h>
  26 #include <crm/msg_xml.h>
  27 #include <crm/services.h>
  28 #include <crm/common/mainloop.h>
  29 #include <crm/common/alerts_internal.h>
  30 #include <crm/common/iso8601_internal.h>
  31 #include <crm/lrmd_alerts_internal.h>
  32 
  33 #include <crm/pengine/status.h>
  34 #include <crm/cib.h>
  35 #include <crm/lrmd.h>
  36 
  37 static lrmd_key_value_t *
  38 alert_key2param(lrmd_key_value_t *head, enum crm_alert_keys_e name,
     /* [previous][next][first][last][top][bottom][index][help] */
  39                 const char *value)
  40 {
  41     const char **key;
  42 
  43     if (value == NULL) {
  44         value = "";
  45     }
  46     for (key = crm_alert_keys[name]; *key; key++) {
  47         crm_trace("Setting alert key %s = '%s'", *key, value);
  48         head = lrmd_key_value_add(head, *key, value);
  49     }
  50     return head;
  51 }
  52 
  53 static lrmd_key_value_t *
  54 alert_key2param_int(lrmd_key_value_t *head, enum crm_alert_keys_e name,
     /* [previous][next][first][last][top][bottom][index][help] */
  55                     int value)
  56 {
  57     char *value_s = crm_itoa(value);
  58 
  59     head = alert_key2param(head, name, value_s);
  60     free(value_s);
  61     return head;
  62 }
  63 
  64 static void
  65 set_ev_kv(gpointer key, gpointer value, gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67     lrmd_key_value_t **head = (lrmd_key_value_t **) user_data;
  68 
  69     if (value) {
  70         crm_trace("Setting environment variable %s='%s'",
  71                   (char*)key, (char*)value);
  72         *head = lrmd_key_value_add(*head, key, value);
  73     }
  74 }
  75 
  76 static lrmd_key_value_t *
  77 alert_envvar2params(lrmd_key_value_t *head, crm_alert_entry_t *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
  78 {
  79     if (entry->envvars) {
  80         g_hash_table_foreach(entry->envvars, set_ev_kv, &head);
  81     }
  82     return head;
  83 }
  84 
  85 /*
  86  * We could use g_strv_contains() instead of this function,
  87  * but that has only been available since glib 2.43.2.
  88  */
  89 static gboolean
  90 is_target_alert(char **list, const char *value)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92     int target_list_num = 0;
  93     gboolean rc = FALSE;
  94 
  95     CRM_CHECK(value != NULL, return FALSE);
  96 
  97     if (list == NULL) {
  98         return TRUE;
  99     }
 100 
 101     target_list_num = g_strv_length(list);
 102 
 103     for (int cnt = 0; cnt < target_list_num; cnt++) {
 104         if (strcmp(list[cnt], value) == 0) {
 105             rc = TRUE;
 106             break;
 107         }
 108     }
 109     return rc;
 110 }
 111 
 112 /*!
 113  * \internal
 114  * \brief Execute alert agents for an event
 115  *
 116  * \param[in]     lrmd        LRMD connection to use
 117  * \param[in]     alert_list  Alerts to execute
 118  * \param[in]     kind        Type of event that is being alerted for
 119  * \param[in]     attr_name   If crm_alert_attribute, the attribute name
 120  * \param[in,out] params      Environment variables to pass to agents
 121  *
 122  * \retval pcmk_ok on success
 123  * \retval -1 if some alerts failed
 124  * \retval -2 if all alerts failed
 125  */
 126 static int
 127 exec_alert_list(lrmd_t *lrmd, GList *alert_list, enum crm_alert_flags kind,
     /* [previous][next][first][last][top][bottom][index][help] */
 128                 const char *attr_name, lrmd_key_value_t *params)
 129 {
 130     bool any_success = FALSE, any_failure = FALSE;
 131     const char *kind_s = crm_alert_flag2text(kind);
 132     crm_time_hr_t *now = NULL;
 133 
 134     params = alert_key2param(params, CRM_alert_kind, kind_s);
 135     params = alert_key2param(params, CRM_alert_version, VERSION);
 136 
 137     for (GList *iter = g_list_first(alert_list); iter; iter = g_list_next(iter)) {
 138         crm_alert_entry_t *entry = (crm_alert_entry_t *)(iter->data);
 139         lrmd_key_value_t *copy_params = NULL;
 140         lrmd_key_value_t *head = NULL;
 141         int rc;
 142 
 143         if (is_not_set(entry->flags, kind)) {
 144             crm_trace("Filtering unwanted %s alert to %s via %s",
 145                       kind_s, entry->recipient, entry->id);
 146             continue;
 147         }
 148 
 149         if ((kind == crm_alert_attribute)
 150             && !is_target_alert(entry->select_attribute_name, attr_name)) {
 151 
 152             crm_trace("Filtering unwanted attribute '%s' alert to %s via %s",
 153                       attr_name, entry->recipient, entry->id);
 154             continue;
 155         }
 156 
 157         if (now == NULL) {
 158             now = crm_time_hr_new(NULL);
 159         }
 160         crm_info("Sending %s alert via %s to %s",
 161                  kind_s, entry->id, entry->recipient);
 162 
 163         /* Make a copy of the parameters, because each alert will be unique */
 164         for (head = params; head != NULL; head = head->next) {
 165             copy_params = lrmd_key_value_add(copy_params, head->key, head->value);
 166         }
 167 
 168         copy_params = alert_key2param(copy_params, CRM_alert_recipient,
 169                                       entry->recipient);
 170 
 171         if (now) {
 172             char *timestamp = crm_time_format_hr(entry->tstamp_format, now);
 173 
 174             if (timestamp) {
 175                 copy_params = alert_key2param(copy_params, CRM_alert_timestamp,
 176                                               timestamp);
 177                 free(timestamp);
 178             }
 179         }
 180 
 181         copy_params = alert_envvar2params(copy_params, entry);
 182 
 183         rc = lrmd->cmds->exec_alert(lrmd, entry->id, entry->path,
 184                                     entry->timeout, copy_params);
 185         if (rc < 0) {
 186             crm_err("Could not execute alert %s: %s " CRM_XS " rc=%d",
 187                     entry->id, pcmk_strerror(rc), rc);
 188             any_failure = TRUE;
 189         } else {
 190             any_success = TRUE;
 191         }
 192     }
 193 
 194     if (now) {
 195         free(now);
 196     }
 197 
 198     if (any_failure) {
 199         return (any_success? -1 : -2);
 200     }
 201     return pcmk_ok;
 202 }
 203 
 204 /*!
 205  * \internal
 206  * \brief Send an alert for a node attribute change
 207  *
 208  * \param[in] lrmd        LRMD connection to use
 209  * \param[in] alert_list  List of alert agents to execute
 210  * \param[in] node        Name of node with attribute change
 211  * \param[in] nodeid      Node ID of node with attribute change
 212  * \param[in] attr_name   Name of attribute that changed
 213  * \param[in] attr_value  New value of attribute that changed
 214  *
 215  * \retval pcmk_ok on success
 216  * \retval -1 if some alert agents failed
 217  * \retval -2 if all alert agents failed
 218  */
 219 int
 220 lrmd_send_attribute_alert(lrmd_t *lrmd, GList *alert_list,
     /* [previous][next][first][last][top][bottom][index][help] */
 221                           const char *node, uint32_t nodeid,
 222                           const char *attr_name, const char *attr_value)
 223 {
 224     int rc = pcmk_ok;
 225     lrmd_key_value_t *params = NULL;
 226 
 227     if (lrmd == NULL) {
 228         return -2;
 229     }
 230 
 231     params = alert_key2param(params, CRM_alert_node, node);
 232     params = alert_key2param_int(params, CRM_alert_nodeid, nodeid);
 233     params = alert_key2param(params, CRM_alert_attribute_name, attr_name);
 234     params = alert_key2param(params, CRM_alert_attribute_value, attr_value);
 235 
 236     rc = exec_alert_list(lrmd, alert_list, crm_alert_attribute, attr_name,
 237                          params);
 238     lrmd_key_value_freeall(params);
 239     return rc;
 240 }
 241 
 242 /*!
 243  * \internal
 244  * \brief Send an alert for a node membership event
 245  *
 246  * \param[in] lrmd        LRMD connection to use
 247  * \param[in] alert_list  List of alert agents to execute
 248  * \param[in] node        Name of node with change
 249  * \param[in] nodeid      Node ID of node with change
 250  * \param[in] state       New state of node with change
 251  *
 252  * \retval pcmk_ok on success
 253  * \retval -1 if some alert agents failed
 254  * \retval -2 if all alert agents failed
 255  */
 256 int
 257 lrmd_send_node_alert(lrmd_t *lrmd, GList *alert_list,
     /* [previous][next][first][last][top][bottom][index][help] */
 258                      const char *node, uint32_t nodeid, const char *state)
 259 {
 260     int rc = pcmk_ok;
 261     lrmd_key_value_t *params = NULL;
 262 
 263     if (lrmd == NULL) {
 264         return -2;
 265     }
 266 
 267     params = alert_key2param(params, CRM_alert_node, node);
 268     params = alert_key2param(params, CRM_alert_desc, state);
 269     params = alert_key2param_int(params, CRM_alert_nodeid, nodeid);
 270 
 271     rc = exec_alert_list(lrmd, alert_list, crm_alert_node, NULL, params);
 272     lrmd_key_value_freeall(params);
 273     return rc;
 274 }
 275 
 276 /*!
 277  * \internal
 278  * \brief Send an alert for a fencing event
 279  *
 280  * \param[in] lrmd        LRMD connection to use
 281  * \param[in] alert_list  List of alert agents to execute
 282  * \param[in] target      Name of fence target node
 283  * \param[in] task        Type of fencing event that occurred
 284  * \param[in] desc        Readable description of event
 285  * \param[in] op_rc       Result of fence action
 286  *
 287  * \retval pcmk_ok on success
 288  * \retval -1 if some alert agents failed
 289  * \retval -2 if all alert agents failed
 290  */
 291 int
 292 lrmd_send_fencing_alert(lrmd_t *lrmd, GList *alert_list,
     /* [previous][next][first][last][top][bottom][index][help] */
 293                         const char *target, const char *task, const char *desc,
 294                         int op_rc)
 295 {
 296     int rc = pcmk_ok;
 297     lrmd_key_value_t *params = NULL;
 298 
 299     if (lrmd == NULL) {
 300         return -2;
 301     }
 302 
 303     params = alert_key2param(params, CRM_alert_node, target);
 304     params = alert_key2param(params, CRM_alert_task, task);
 305     params = alert_key2param(params, CRM_alert_desc, desc);
 306     params = alert_key2param_int(params, CRM_alert_rc, op_rc);
 307 
 308     rc = exec_alert_list(lrmd, alert_list, crm_alert_fencing, NULL, params);
 309     lrmd_key_value_freeall(params);
 310     return rc;
 311 }
 312 
 313 /*!
 314  * \internal
 315  * \brief Send an alert for a resource operation
 316  *
 317  * \param[in] lrmd        LRMD connection to use
 318  * \param[in] alert_list  List of alert agents to execute
 319  * \param[in] node        Name of node that executed operation
 320  * \param[in] op          Resource operation
 321  *
 322  * \retval pcmk_ok on success
 323  * \retval -1 if some alert agents failed
 324  * \retval -2 if all alert agents failed
 325  */
 326 int
 327 lrmd_send_resource_alert(lrmd_t *lrmd, GList *alert_list,
     /* [previous][next][first][last][top][bottom][index][help] */
 328                          const char *node, lrmd_event_data_t *op)
 329 {
 330     int rc = pcmk_ok;
 331     int target_rc = pcmk_ok;
 332     lrmd_key_value_t *params = NULL;
 333 
 334     if (lrmd == NULL) {
 335         return -2;
 336     }
 337 
 338     target_rc = rsc_op_expected_rc(op);
 339     if ((op->interval == 0) && (target_rc == op->rc)
 340         && safe_str_eq(op->op_type, RSC_STATUS)) {
 341 
 342         /* Don't send alerts for probes with the expected result. Leave it up to
 343          * the agent whether to alert for 'failed' probes. (Even if we find a
 344          * resource running, it was probably because someone did a clean-up of
 345          * the status section.)
 346          */
 347         return pcmk_ok;
 348     }
 349 
 350     params = alert_key2param(params, CRM_alert_node, node);
 351     params = alert_key2param(params, CRM_alert_rsc, op->rsc_id);
 352     params = alert_key2param(params, CRM_alert_task, op->op_type);
 353     params = alert_key2param_int(params, CRM_alert_interval, op->interval);
 354     params = alert_key2param_int(params, CRM_alert_target_rc, target_rc);
 355     params = alert_key2param_int(params, CRM_alert_status, op->op_status);
 356     params = alert_key2param_int(params, CRM_alert_rc, op->rc);
 357 
 358     if (op->op_status == PCMK_LRM_OP_DONE) {
 359         params = alert_key2param(params, CRM_alert_desc, services_ocf_exitcode_str(op->rc));
 360     } else {
 361         params = alert_key2param(params, CRM_alert_desc, services_lrm_status_str(op->op_status));
 362     }
 363 
 364     rc = exec_alert_list(lrmd, alert_list, crm_alert_resource, NULL, params);
 365     lrmd_key_value_freeall(params);
 366     return rc;
 367 }

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