LCOV - code coverage report
Current view: top level - lrmd - lrmd_alerts.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 152 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 2015-2024 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 Lesser General Public License
       7             :  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
       8             :  */
       9             : 
      10             : #include <crm_internal.h>
      11             : 
      12             : #include <glib.h>
      13             : #include <unistd.h>
      14             : 
      15             : #include <crm/crm.h>
      16             : #include <crm/common/xml.h>
      17             : #include <crm/services.h>
      18             : #include <crm/common/mainloop.h>
      19             : #include <crm/common/alerts_internal.h>
      20             : #include <crm/lrmd_internal.h>
      21             : 
      22             : #include <crm/pengine/status.h>
      23             : #include <crm/cib.h>
      24             : #include <crm/lrmd.h>
      25             : 
      26             : static lrmd_key_value_t *
      27           0 : alert_key2param(lrmd_key_value_t *head, enum pcmk__alert_keys_e name,
      28             :                 const char *value)
      29             : {
      30             :     const char **key;
      31             : 
      32           0 :     if (value == NULL) {
      33           0 :         value = "";
      34             :     }
      35           0 :     for (key = pcmk__alert_keys[name]; *key; key++) {
      36           0 :         crm_trace("Setting alert key %s = '%s'", *key, value);
      37           0 :         head = lrmd_key_value_add(head, *key, value);
      38             :     }
      39           0 :     return head;
      40             : }
      41             : 
      42             : static lrmd_key_value_t *
      43           0 : alert_key2param_int(lrmd_key_value_t *head, enum pcmk__alert_keys_e name,
      44             :                     int value)
      45             : {
      46           0 :     char *value_s = pcmk__itoa(value);
      47             : 
      48           0 :     head = alert_key2param(head, name, value_s);
      49           0 :     free(value_s);
      50           0 :     return head;
      51             : }
      52             : 
      53             : static lrmd_key_value_t *
      54           0 : alert_key2param_ms(lrmd_key_value_t *head, enum pcmk__alert_keys_e name,
      55             :                    guint value)
      56             : {
      57           0 :     char *value_s = crm_strdup_printf("%u", value);
      58             : 
      59           0 :     head = alert_key2param(head, name, value_s);
      60           0 :     free(value_s);
      61           0 :     return head;
      62             : }
      63             : 
      64             : static void
      65           0 : set_ev_kv(gpointer key, gpointer value, gpointer user_data)
      66             : {
      67           0 :     lrmd_key_value_t **head = (lrmd_key_value_t **) user_data;
      68             : 
      69           0 :     if (value) {
      70           0 :         crm_trace("Setting environment variable %s='%s'",
      71             :                   (char*)key, (char*)value);
      72           0 :         *head = lrmd_key_value_add(*head, key, value);
      73             :     }
      74           0 : }
      75             : 
      76             : static lrmd_key_value_t *
      77           0 : alert_envvar2params(lrmd_key_value_t *head, const pcmk__alert_t *entry)
      78             : {
      79           0 :     if (entry->envvars) {
      80           0 :         g_hash_table_foreach(entry->envvars, set_ev_kv, &head);
      81             :     }
      82           0 :     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           0 : is_target_alert(char **list, const char *value)
      91             : {
      92           0 :     int target_list_num = 0;
      93           0 :     gboolean rc = FALSE;
      94             : 
      95           0 :     CRM_CHECK(value != NULL, return FALSE);
      96             : 
      97           0 :     if (list == NULL) {
      98           0 :         return TRUE;
      99             :     }
     100             : 
     101           0 :     target_list_num = g_strv_length(list);
     102             : 
     103           0 :     for (int cnt = 0; cnt < target_list_num; cnt++) {
     104           0 :         if (strcmp(list[cnt], value) == 0) {
     105           0 :             rc = TRUE;
     106           0 :             break;
     107             :         }
     108             :     }
     109           0 :     return rc;
     110             : }
     111             : 
     112             : /*!
     113             :  * \internal
     114             :  * \brief Execute alert agents for an event
     115             :  *
     116             :  * \param[in,out] lrmd        Executor 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 pcmk__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           0 : exec_alert_list(lrmd_t *lrmd, const GList *alert_list,
     128             :                 enum pcmk__alert_flags kind, const char *attr_name,
     129             :                 lrmd_key_value_t *params)
     130             : {
     131           0 :     bool any_success = FALSE, any_failure = FALSE;
     132           0 :     const char *kind_s = pcmk__alert_flag2text(kind);
     133           0 :     pcmk__time_hr_t *now = NULL;
     134             :     char timestamp_epoch[20];
     135             :     char timestamp_usec[7];
     136           0 :     time_t epoch = 0;
     137             : 
     138           0 :     params = alert_key2param(params, PCMK__alert_key_kind, kind_s);
     139           0 :     params = alert_key2param(params, PCMK__alert_key_version,
     140             :                              PACEMAKER_VERSION);
     141             : 
     142           0 :     for (const GList *iter = alert_list;
     143           0 :          iter != NULL; iter = g_list_next(iter)) {
     144           0 :         const pcmk__alert_t *entry = (pcmk__alert_t *) (iter->data);
     145           0 :         lrmd_key_value_t *copy_params = NULL;
     146           0 :         lrmd_key_value_t *head = NULL;
     147             :         int rc;
     148             : 
     149           0 :         if (!pcmk_is_set(entry->flags, kind)) {
     150           0 :             crm_trace("Filtering unwanted %s alert to %s via %s",
     151             :                       kind_s, entry->recipient, entry->id);
     152           0 :             continue;
     153             :         }
     154             : 
     155           0 :         if ((kind == pcmk__alert_attribute)
     156           0 :             && !is_target_alert(entry->select_attribute_name, attr_name)) {
     157             : 
     158           0 :             crm_trace("Filtering unwanted attribute '%s' alert to %s via %s",
     159             :                       attr_name, entry->recipient, entry->id);
     160           0 :             continue;
     161             :         }
     162             : 
     163           0 :         if (now == NULL) {
     164           0 :             now = pcmk__time_hr_now(&epoch);
     165             :         }
     166           0 :         crm_info("Sending %s alert via %s to %s",
     167             :                  kind_s, entry->id, entry->recipient);
     168             : 
     169             :         /* Make a copy of the parameters, because each alert will be unique */
     170           0 :         for (head = params; head != NULL; head = head->next) {
     171           0 :             copy_params = lrmd_key_value_add(copy_params, head->key, head->value);
     172             :         }
     173             : 
     174           0 :         copy_params = alert_key2param(copy_params, PCMK__alert_key_recipient,
     175           0 :                                       entry->recipient);
     176             : 
     177           0 :         if (now) {
     178           0 :             char *timestamp = pcmk__time_format_hr(entry->tstamp_format, now);
     179             : 
     180           0 :             if (timestamp) {
     181           0 :                 copy_params = alert_key2param(copy_params,
     182             :                                               PCMK__alert_key_timestamp,
     183             :                                               timestamp);
     184           0 :                 free(timestamp);
     185             :             }
     186             : 
     187           0 :             snprintf(timestamp_epoch, sizeof(timestamp_epoch), "%lld",
     188             :                      (long long) epoch);
     189           0 :             copy_params = alert_key2param(copy_params,
     190             :                                           PCMK__alert_key_timestamp_epoch,
     191             :                                           timestamp_epoch);
     192           0 :             snprintf(timestamp_usec, sizeof(timestamp_usec), "%06d", now->useconds);
     193           0 :             copy_params = alert_key2param(copy_params,
     194             :                                           PCMK__alert_key_timestamp_usec,
     195             :                                           timestamp_usec);
     196             :         }
     197             : 
     198           0 :         copy_params = alert_envvar2params(copy_params, entry);
     199             : 
     200           0 :         rc = lrmd->cmds->exec_alert(lrmd, entry->id, entry->path,
     201           0 :                                     entry->timeout, copy_params);
     202           0 :         if (rc < 0) {
     203           0 :             crm_err("Could not execute alert %s: %s " CRM_XS " rc=%d",
     204             :                     entry->id, pcmk_strerror(rc), rc);
     205           0 :             any_failure = TRUE;
     206             :         } else {
     207           0 :             any_success = TRUE;
     208             :         }
     209             :     }
     210             : 
     211           0 :     if (now) {
     212           0 :         free(now);
     213             :     }
     214             : 
     215           0 :     if (any_failure) {
     216           0 :         return (any_success? -1 : -2);
     217             :     }
     218           0 :     return pcmk_ok;
     219             : }
     220             : 
     221             : /*!
     222             :  * \internal
     223             :  * \brief Send an alert for a node attribute change
     224             :  *
     225             :  * \param[in,out] lrmd        Executor connection to use
     226             :  * \param[in]     alert_list  List of alert agents to execute
     227             :  * \param[in]     node        Name of node with attribute change
     228             :  * \param[in]     nodeid      Node ID of node with attribute change
     229             :  * \param[in]     attr_name   Name of attribute that changed
     230             :  * \param[in]     attr_value  New value of attribute that changed
     231             :  *
     232             :  * \retval pcmk_ok on success
     233             :  * \retval -1 if some alert agents failed
     234             :  * \retval -2 if all alert agents failed
     235             :  */
     236             : int
     237           0 : lrmd_send_attribute_alert(lrmd_t *lrmd, const GList *alert_list,
     238             :                           const char *node, uint32_t nodeid,
     239             :                           const char *attr_name, const char *attr_value)
     240             : {
     241           0 :     int rc = pcmk_ok;
     242           0 :     lrmd_key_value_t *params = NULL;
     243             : 
     244           0 :     if (lrmd == NULL) {
     245           0 :         return -2;
     246             :     }
     247             : 
     248           0 :     params = alert_key2param(params, PCMK__alert_key_node, node);
     249           0 :     params = alert_key2param_int(params, PCMK__alert_key_nodeid, nodeid);
     250           0 :     params = alert_key2param(params, PCMK__alert_key_attribute_name, attr_name);
     251           0 :     params = alert_key2param(params, PCMK__alert_key_attribute_value,
     252             :                              attr_value);
     253             : 
     254           0 :     rc = exec_alert_list(lrmd, alert_list, pcmk__alert_attribute, attr_name,
     255             :                          params);
     256           0 :     lrmd_key_value_freeall(params);
     257           0 :     return rc;
     258             : }
     259             : 
     260             : /*!
     261             :  * \internal
     262             :  * \brief Send an alert for a node membership event
     263             :  *
     264             :  * \param[in,out] lrmd        Executor connection to use
     265             :  * \param[in]     alert_list  List of alert agents to execute
     266             :  * \param[in]     node        Name of node with change
     267             :  * \param[in]     nodeid      Node ID of node with change
     268             :  * \param[in]     state       New state of node with change
     269             :  *
     270             :  * \retval pcmk_ok on success
     271             :  * \retval -1 if some alert agents failed
     272             :  * \retval -2 if all alert agents failed
     273             :  */
     274             : int
     275           0 : lrmd_send_node_alert(lrmd_t *lrmd, const GList *alert_list,
     276             :                      const char *node, uint32_t nodeid, const char *state)
     277             : {
     278           0 :     int rc = pcmk_ok;
     279           0 :     lrmd_key_value_t *params = NULL;
     280             : 
     281           0 :     if (lrmd == NULL) {
     282           0 :         return -2;
     283             :     }
     284             : 
     285           0 :     params = alert_key2param(params, PCMK__alert_key_node, node);
     286           0 :     params = alert_key2param(params, PCMK__alert_key_desc, state);
     287           0 :     params = alert_key2param_int(params, PCMK__alert_key_nodeid, nodeid);
     288             : 
     289           0 :     rc = exec_alert_list(lrmd, alert_list, pcmk__alert_node, NULL, params);
     290           0 :     lrmd_key_value_freeall(params);
     291           0 :     return rc;
     292             : }
     293             : 
     294             : /*!
     295             :  * \internal
     296             :  * \brief Send an alert for a fencing event
     297             :  *
     298             :  * \param[in,out] lrmd        Executor connection to use
     299             :  * \param[in]     alert_list  List of alert agents to execute
     300             :  * \param[in]     target      Name of fence target node
     301             :  * \param[in]     task        Type of fencing event that occurred
     302             :  * \param[in]     desc        Readable description of event
     303             :  * \param[in]     op_rc       Result of fence action
     304             :  *
     305             :  * \retval pcmk_ok on success
     306             :  * \retval -1 if some alert agents failed
     307             :  * \retval -2 if all alert agents failed
     308             :  */
     309             : int
     310           0 : lrmd_send_fencing_alert(lrmd_t *lrmd, const GList *alert_list,
     311             :                         const char *target, const char *task, const char *desc,
     312             :                         int op_rc)
     313             : {
     314           0 :     int rc = pcmk_ok;
     315           0 :     lrmd_key_value_t *params = NULL;
     316             : 
     317           0 :     if (lrmd == NULL) {
     318           0 :         return -2;
     319             :     }
     320             : 
     321           0 :     params = alert_key2param(params, PCMK__alert_key_node, target);
     322           0 :     params = alert_key2param(params, PCMK__alert_key_task, task);
     323           0 :     params = alert_key2param(params, PCMK__alert_key_desc, desc);
     324           0 :     params = alert_key2param_int(params, PCMK__alert_key_rc, op_rc);
     325             : 
     326           0 :     rc = exec_alert_list(lrmd, alert_list, pcmk__alert_fencing, NULL, params);
     327           0 :     lrmd_key_value_freeall(params);
     328           0 :     return rc;
     329             : }
     330             : 
     331             : /*!
     332             :  * \internal
     333             :  * \brief Send an alert for a resource operation
     334             :  *
     335             :  * \param[in,out] lrmd        Executor connection to use
     336             :  * \param[in]     alert_list  List of alert agents to execute
     337             :  * \param[in]     node        Name of node that executed operation
     338             :  * \param[in]     op          Resource operation
     339             :  *
     340             :  * \retval pcmk_ok on success
     341             :  * \retval -1 if some alert agents failed
     342             :  * \retval -2 if all alert agents failed
     343             :  */
     344             : int
     345           0 : lrmd_send_resource_alert(lrmd_t *lrmd, const GList *alert_list,
     346             :                          const char *node, const lrmd_event_data_t *op)
     347             : {
     348           0 :     int rc = pcmk_ok;
     349           0 :     int target_rc = pcmk_ok;
     350           0 :     lrmd_key_value_t *params = NULL;
     351             : 
     352           0 :     if (lrmd == NULL) {
     353           0 :         return -2;
     354             :     }
     355             : 
     356           0 :     target_rc = rsc_op_expected_rc(op);
     357           0 :     if ((op->interval_ms == 0) && (target_rc == op->rc)
     358           0 :         && pcmk__str_eq(op->op_type, PCMK_ACTION_MONITOR, pcmk__str_casei)) {
     359             : 
     360             :         /* Don't send alerts for probes with the expected result. Leave it up to
     361             :          * the agent whether to alert for 'failed' probes. (Even if we find a
     362             :          * resource running, it was probably because someone did a clean-up of
     363             :          * the status section.)
     364             :          */
     365           0 :         return pcmk_ok;
     366             :     }
     367             : 
     368           0 :     params = alert_key2param(params, PCMK__alert_key_node, node);
     369           0 :     params = alert_key2param(params, PCMK__alert_key_rsc, op->rsc_id);
     370           0 :     params = alert_key2param(params, PCMK__alert_key_task, op->op_type);
     371           0 :     params = alert_key2param_ms(params, PCMK__alert_key_interval,
     372           0 :                                 op->interval_ms);
     373           0 :     params = alert_key2param_int(params, PCMK__alert_key_target_rc, target_rc);
     374           0 :     params = alert_key2param_int(params, PCMK__alert_key_status, op->op_status);
     375           0 :     params = alert_key2param_int(params, PCMK__alert_key_rc, op->rc);
     376             : 
     377             :     /* Reoccurring operations do not set exec_time, so on timeout, set it
     378             :      * to the operation timeout since that's closer to the actual value.
     379             :      */
     380           0 :     if ((op->op_status == PCMK_EXEC_TIMEOUT) && (op->exec_time == 0)) {
     381           0 :         params = alert_key2param_int(params, PCMK__alert_key_exec_time,
     382           0 :                                      op->timeout);
     383             :     } else {
     384           0 :         params = alert_key2param_int(params, PCMK__alert_key_exec_time,
     385           0 :                                      op->exec_time);
     386             :     }
     387             : 
     388           0 :     if (op->op_status == PCMK_EXEC_DONE) {
     389           0 :         params = alert_key2param(params, PCMK__alert_key_desc,
     390           0 :                                  services_ocf_exitcode_str(op->rc));
     391             :     } else {
     392           0 :         params = alert_key2param(params, PCMK__alert_key_desc,
     393           0 :                                  pcmk_exec_status_str(op->op_status));
     394             :     }
     395             : 
     396           0 :     rc = exec_alert_list(lrmd, alert_list, pcmk__alert_resource, NULL, params);
     397           0 :     lrmd_key_value_freeall(params);
     398           0 :     return rc;
     399             : }

Generated by: LCOV version 1.14