LCOV - code coverage report
Current view: top level - pengine - rules_alerts.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 128 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 6 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             : #include <crm/crm.h>
      12             : #include <crm/common/xml.h>
      13             : #include <crm/pengine/rules.h>
      14             : #include <crm/common/alerts_internal.h>
      15             : #include <crm/common/xml_internal.h>
      16             : #include <crm/pengine/rules_internal.h>
      17             : 
      18             : /*!
      19             :  * \internal
      20             :  * \brief Unpack an alert's or alert recipient's meta attributes
      21             :  *
      22             :  * \param[in,out] basenode     Alert or recipient XML
      23             :  * \param[in,out] entry        Where to store unpacked values
      24             :  * \param[in,out] max_timeout  Max timeout of all alerts and recipients thus far
      25             :  *
      26             :  * \return Standard Pacemaker return code
      27             :  */
      28             : static int
      29           0 : get_meta_attrs_from_cib(xmlNode *basenode, pcmk__alert_t *entry,
      30             :                         guint *max_timeout)
      31             : {
      32           0 :     GHashTable *config_hash = pcmk__strkey_table(free, free);
      33           0 :     crm_time_t *now = crm_time_new(NULL);
      34           0 :     const char *value = NULL;
      35           0 :     int rc = pcmk_rc_ok;
      36             : 
      37           0 :     pe_unpack_nvpairs(basenode, basenode, PCMK_XE_META_ATTRIBUTES, NULL,
      38             :                       config_hash, NULL, FALSE, now, NULL);
      39           0 :     crm_time_free(now);
      40             : 
      41           0 :     value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED);
      42           0 :     if ((value != NULL) && !crm_is_true(value)) {
      43             :         // No need to continue unpacking
      44           0 :         rc = pcmk_rc_disabled;
      45           0 :         goto done;
      46             :     }
      47             : 
      48           0 :     value = g_hash_table_lookup(config_hash, PCMK_META_TIMEOUT);
      49           0 :     if (value) {
      50           0 :         long long timeout_ms = crm_get_msec(value);
      51             : 
      52           0 :         entry->timeout = (int) QB_MIN(timeout_ms, INT_MAX);
      53           0 :         if (entry->timeout <= 0) {
      54           0 :             if (entry->timeout == 0) {
      55           0 :                 crm_trace("Alert %s uses default timeout of %dmsec",
      56             :                           entry->id, PCMK__ALERT_DEFAULT_TIMEOUT_MS);
      57             :             } else {
      58           0 :                 pcmk__config_warn("Alert %s has invalid timeout value '%s', "
      59             :                                   "using default (%d ms)",
      60             :                                   entry->id, value,
      61             :                                   PCMK__ALERT_DEFAULT_TIMEOUT_MS);
      62             :             }
      63           0 :             entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
      64             :         } else {
      65           0 :             crm_trace("Alert %s uses timeout of %dmsec",
      66             :                       entry->id, entry->timeout);
      67             :         }
      68           0 :         if (entry->timeout > *max_timeout) {
      69           0 :             *max_timeout = entry->timeout;
      70             :         }
      71             :     }
      72           0 :     value = g_hash_table_lookup(config_hash, PCMK_META_TIMESTAMP_FORMAT);
      73           0 :     if (value) {
      74             :         /* hard to do any checks here as merely anything can
      75             :          * can be a valid time-format-string
      76             :          */
      77           0 :         entry->tstamp_format = strdup(value);
      78           0 :         crm_trace("Alert %s uses timestamp format '%s'",
      79             :                   entry->id, entry->tstamp_format);
      80             :     }
      81             : 
      82           0 : done:
      83           0 :     g_hash_table_destroy(config_hash);
      84           0 :     return rc;
      85             : }
      86             : 
      87             : static void
      88           0 : get_envvars_from_cib(xmlNode *basenode, pcmk__alert_t *entry)
      89             : {
      90             :     xmlNode *child;
      91             : 
      92           0 :     if ((basenode == NULL) || (entry == NULL)) {
      93           0 :         return;
      94             :     }
      95             : 
      96           0 :     child = pcmk__xe_first_child(basenode, PCMK_XE_INSTANCE_ATTRIBUTES, NULL,
      97             :                                  NULL);
      98           0 :     if (child == NULL) {
      99           0 :         return;
     100             :     }
     101             : 
     102           0 :     if (entry->envvars == NULL) {
     103           0 :         entry->envvars = pcmk__strkey_table(free, free);
     104             :     }
     105             : 
     106           0 :     for (child = pcmk__xe_first_child(child, PCMK_XE_NVPAIR, NULL, NULL);
     107           0 :          child != NULL; child = pcmk__xe_next_same(child)) {
     108             : 
     109           0 :         const char *name = crm_element_value(child, PCMK_XA_NAME);
     110           0 :         const char *value = crm_element_value(child, PCMK_XA_VALUE);
     111             : 
     112           0 :         if (value == NULL) {
     113           0 :             value = "";
     114             :         }
     115           0 :         pcmk__insert_dup(entry->envvars, name, value);
     116           0 :         crm_trace("Alert %s: added environment variable %s='%s'",
     117             :                   entry->id, name, value);
     118             :     }
     119             : }
     120             : 
     121             : static void
     122           0 : unpack_alert_filter(xmlNode *basenode, pcmk__alert_t *entry)
     123             : {
     124           0 :     xmlNode *select = pcmk__xe_first_child(basenode, PCMK_XE_SELECT, NULL,
     125             :                                            NULL);
     126           0 :     xmlNode *event_type = NULL;
     127           0 :     uint32_t flags = pcmk__alert_none;
     128             : 
     129           0 :     for (event_type = pcmk__xe_first_child(select, NULL, NULL, NULL);
     130           0 :          event_type != NULL; event_type = pcmk__xe_next(event_type)) {
     131             : 
     132           0 :         if (pcmk__xe_is(event_type, PCMK_XE_SELECT_FENCING)) {
     133           0 :             flags |= pcmk__alert_fencing;
     134             : 
     135           0 :         } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_NODES)) {
     136           0 :             flags |= pcmk__alert_node;
     137             : 
     138           0 :         } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_RESOURCES)) {
     139           0 :             flags |= pcmk__alert_resource;
     140             : 
     141           0 :         } else if (pcmk__xe_is(event_type, PCMK_XE_SELECT_ATTRIBUTES)) {
     142             :             xmlNode *attr;
     143             :             const char *attr_name;
     144           0 :             int nattrs = 0;
     145             : 
     146           0 :             flags |= pcmk__alert_attribute;
     147           0 :             for (attr = pcmk__xe_first_child(event_type, PCMK_XE_ATTRIBUTE,
     148             :                                              NULL, NULL);
     149           0 :                  attr != NULL; attr = pcmk__xe_next_same(attr)) {
     150             : 
     151           0 :                 attr_name = crm_element_value(attr, PCMK_XA_NAME);
     152           0 :                 if (attr_name) {
     153           0 :                     if (nattrs == 0) {
     154           0 :                         g_strfreev(entry->select_attribute_name);
     155           0 :                         entry->select_attribute_name = NULL;
     156             :                     }
     157           0 :                     ++nattrs;
     158           0 :                     entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
     159           0 :                                                                  (nattrs + 1) * sizeof(char*));
     160           0 :                     entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
     161           0 :                     entry->select_attribute_name[nattrs] = NULL;
     162             :                 }
     163             :             }
     164             :         }
     165             :     }
     166             : 
     167           0 :     if (flags != pcmk__alert_none) {
     168           0 :         entry->flags = flags;
     169           0 :         crm_debug("Alert %s receives events: attributes:%s%s%s%s",
     170             :                   entry->id,
     171             :                   (pcmk_is_set(flags, pcmk__alert_attribute)?
     172             :                    (entry->select_attribute_name? "some" : "all") : "none"),
     173             :                   (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
     174             :                   (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
     175             :                   (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
     176             :     }
     177           0 : }
     178             : 
     179             : /*!
     180             :  * \internal
     181             :  * \brief Unpack an alert or an alert recipient
     182             :  *
     183             :  * \param[in,out] alert        Alert or recipient XML
     184             :  * \param[in,out] entry        Where to store unpacked values
     185             :  * \param[in,out] max_timeout  Max timeout of all alerts and recipients thus far
     186             :  *
     187             :  * \return Standard Pacemaker return code
     188             :  */
     189             : static int
     190           0 : unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
     191             : {
     192           0 :     int rc = pcmk_rc_ok;
     193             : 
     194           0 :     get_envvars_from_cib(alert, entry);
     195           0 :     rc = get_meta_attrs_from_cib(alert, entry, max_timeout);
     196           0 :     if (rc == pcmk_rc_ok) {
     197           0 :         unpack_alert_filter(alert, entry);
     198             :     }
     199           0 :     return rc;
     200             : }
     201             : 
     202             : /*!
     203             :  * \internal
     204             :  * \brief Unpack a CIB alerts section
     205             :  *
     206             :  * \param[in] alerts  XML of alerts section
     207             :  *
     208             :  * \return  List of unpacked alert entries
     209             :  *
     210             :  * \note Unlike most unpack functions, this is not used by the scheduler itself,
     211             :  *       but is supplied for use by daemons that need to send alerts.
     212             :  */
     213             : GList *
     214           0 : pe_unpack_alerts(const xmlNode *alerts)
     215             : {
     216             :     xmlNode *alert;
     217             :     pcmk__alert_t *entry;
     218           0 :     guint max_timeout = 0;
     219           0 :     GList *alert_list = NULL;
     220             : 
     221           0 :     if (alerts == NULL) {
     222           0 :         return alert_list;
     223             :     }
     224             : 
     225           0 :     for (alert = pcmk__xe_first_child(alerts, PCMK_XE_ALERT, NULL, NULL);
     226           0 :          alert != NULL; alert = pcmk__xe_next_same(alert)) {
     227             : 
     228             :         xmlNode *recipient;
     229           0 :         int recipients = 0;
     230           0 :         const char *alert_id = pcmk__xe_id(alert);
     231           0 :         const char *alert_path = crm_element_value(alert, PCMK_XA_PATH);
     232             : 
     233             :         /* The schema should enforce this, but to be safe ... */
     234           0 :         if (alert_id == NULL) {
     235           0 :             pcmk__config_warn("Ignoring invalid alert without " PCMK_XA_ID);
     236           0 :             crm_log_xml_info(alert, "missing-id");
     237           0 :             continue;
     238             :         }
     239           0 :         if (alert_path == NULL) {
     240           0 :             pcmk__config_warn("Ignoring alert %s: No " PCMK_XA_PATH, alert_id);
     241           0 :             continue;
     242             :         }
     243             : 
     244           0 :         entry = pcmk__alert_new(alert_id, alert_path);
     245             : 
     246           0 :         if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
     247             :             // Don't allow recipients to override if entire alert is disabled
     248           0 :             crm_debug("Alert %s is disabled", entry->id);
     249           0 :             pcmk__free_alert(entry);
     250           0 :             continue;
     251             :         }
     252             : 
     253           0 :         if (entry->tstamp_format == NULL) {
     254           0 :             entry->tstamp_format = strdup(PCMK__ALERT_DEFAULT_TSTAMP_FORMAT);
     255             :         }
     256             : 
     257           0 :         crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars",
     258             :                   entry->id, entry->path, entry->timeout, entry->tstamp_format,
     259             :                   (entry->envvars? g_hash_table_size(entry->envvars) : 0));
     260             : 
     261           0 :         for (recipient = pcmk__xe_first_child(alert, PCMK_XE_RECIPIENT, NULL,
     262             :                                               NULL);
     263           0 :              recipient != NULL; recipient = pcmk__xe_next_same(recipient)) {
     264             : 
     265           0 :             pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
     266             : 
     267           0 :             recipients++;
     268           0 :             recipient_entry->recipient = crm_element_value_copy(recipient,
     269             :                                                                 PCMK_XA_VALUE);
     270             : 
     271           0 :             if (unpack_alert(recipient, recipient_entry,
     272             :                              &max_timeout) != pcmk_rc_ok) {
     273           0 :                 crm_debug("Alert %s: recipient %s is disabled",
     274             :                           entry->id, recipient_entry->id);
     275           0 :                 pcmk__free_alert(recipient_entry);
     276           0 :                 continue;
     277             :             }
     278           0 :             alert_list = g_list_prepend(alert_list, recipient_entry);
     279           0 :             crm_debug("Alert %s has recipient %s with value %s and %d envvars",
     280             :                       entry->id, pcmk__xe_id(recipient),
     281             :                       recipient_entry->recipient,
     282             :                       (recipient_entry->envvars?
     283             :                        g_hash_table_size(recipient_entry->envvars) : 0));
     284             :         }
     285             : 
     286           0 :         if (recipients == 0) {
     287           0 :             alert_list = g_list_prepend(alert_list, entry);
     288             :         } else {
     289           0 :             pcmk__free_alert(entry);
     290             :         }
     291             :     }
     292           0 :     return alert_list;
     293             : }
     294             : 
     295             : /*!
     296             :  * \internal
     297             :  * \brief Free an alert list generated by pe_unpack_alerts()
     298             :  *
     299             :  * \param[in,out] alert_list  Alert list to free
     300             :  */
     301             : void
     302           0 : pe_free_alert_list(GList *alert_list)
     303             : {
     304           0 :     if (alert_list) {
     305           0 :         g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
     306             :     }
     307           0 : }

Generated by: LCOV version 1.14