root/lib/pengine/rules_alerts.c

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

DEFINITIONS

This source file includes following definitions.
  1. get_meta_attrs_from_cib
  2. get_envvars_from_cib
  3. unpack_alert_filter
  4. unpack_alert
  5. pe_unpack_alerts
  6. pe_free_alert_list

   1 /*
   2  * Copyright 2015-2023 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/msg_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 get_meta_attrs_from_cib(xmlNode *basenode, pcmk__alert_t *entry,
     /* [previous][next][first][last][top][bottom][index][help] */
  30                         guint *max_timeout)
  31 {
  32     GHashTable *config_hash = pcmk__strkey_table(free, free);
  33     crm_time_t *now = crm_time_new(NULL);
  34     const char *value = NULL;
  35     int rc = pcmk_rc_ok;
  36 
  37     pe_unpack_nvpairs(basenode, basenode, XML_TAG_META_SETS, NULL, config_hash,
  38                       NULL, FALSE, now, NULL);
  39     crm_time_free(now);
  40 
  41     value = g_hash_table_lookup(config_hash, PCMK_META_ENABLED);
  42     if ((value != NULL) && !crm_is_true(value)) {
  43         // No need to continue unpacking
  44         rc = pcmk_rc_disabled;
  45         goto done;
  46     }
  47 
  48     value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TIMEOUT);
  49     if (value) {
  50         entry->timeout = crm_get_msec(value);
  51         if (entry->timeout <= 0) {
  52             if (entry->timeout == 0) {
  53                 crm_trace("Alert %s uses default timeout of %dmsec",
  54                           entry->id, PCMK__ALERT_DEFAULT_TIMEOUT_MS);
  55             } else {
  56                 crm_warn("Alert %s has invalid timeout value '%s', using default %dmsec",
  57                          entry->id, (char*)value, PCMK__ALERT_DEFAULT_TIMEOUT_MS);
  58             }
  59             entry->timeout = PCMK__ALERT_DEFAULT_TIMEOUT_MS;
  60         } else {
  61             crm_trace("Alert %s uses timeout of %dmsec",
  62                       entry->id, entry->timeout);
  63         }
  64         if (entry->timeout > *max_timeout) {
  65             *max_timeout = entry->timeout;
  66         }
  67     }
  68     value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TSTAMP_FORMAT);
  69     if (value) {
  70         /* hard to do any checks here as merely anything can
  71          * can be a valid time-format-string
  72          */
  73         entry->tstamp_format = strdup(value);
  74         crm_trace("Alert %s uses timestamp format '%s'",
  75                   entry->id, entry->tstamp_format);
  76     }
  77 
  78 done:
  79     g_hash_table_destroy(config_hash);
  80     return rc;
  81 }
  82 
  83 static void
  84 get_envvars_from_cib(xmlNode *basenode, pcmk__alert_t *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86     xmlNode *child;
  87 
  88     if ((basenode == NULL) || (entry == NULL)) {
  89         return;
  90     }
  91 
  92     child = first_named_child(basenode, XML_TAG_ATTR_SETS);
  93     if (child == NULL) {
  94         return;
  95     }
  96 
  97     if (entry->envvars == NULL) {
  98         entry->envvars = pcmk__strkey_table(free, free);
  99     }
 100 
 101     for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL;
 102          child = crm_next_same_xml(child)) {
 103 
 104         const char *name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
 105         const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE);
 106 
 107         if (value == NULL) {
 108             value = "";
 109         }
 110         g_hash_table_insert(entry->envvars, strdup(name), strdup(value));
 111         crm_trace("Alert %s: added environment variable %s='%s'",
 112                   entry->id, name, value);
 113     }
 114 }
 115 
 116 static void
 117 unpack_alert_filter(xmlNode *basenode, pcmk__alert_t *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119     xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT);
 120     xmlNode *event_type = NULL;
 121     uint32_t flags = pcmk__alert_none;
 122 
 123     for (event_type = pcmk__xe_first_child(select); event_type != NULL;
 124          event_type = pcmk__xe_next(event_type)) {
 125 
 126         if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_FENCING)) {
 127             flags |= pcmk__alert_fencing;
 128 
 129         } else if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_NODES)) {
 130             flags |= pcmk__alert_node;
 131 
 132         } else if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_RESOURCES)) {
 133             flags |= pcmk__alert_resource;
 134 
 135         } else if (pcmk__xe_is(event_type, XML_CIB_TAG_ALERT_ATTRIBUTES)) {
 136             xmlNode *attr;
 137             const char *attr_name;
 138             int nattrs = 0;
 139 
 140             flags |= pcmk__alert_attribute;
 141             for (attr = first_named_child(event_type, XML_CIB_TAG_ALERT_ATTR);
 142                  attr != NULL;
 143                  attr = crm_next_same_xml(attr)) {
 144 
 145                 attr_name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
 146                 if (attr_name) {
 147                     if (nattrs == 0) {
 148                         g_strfreev(entry->select_attribute_name);
 149                         entry->select_attribute_name = NULL;
 150                     }
 151                     ++nattrs;
 152                     entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
 153                                                                  (nattrs + 1) * sizeof(char*));
 154                     entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
 155                     entry->select_attribute_name[nattrs] = NULL;
 156                 }
 157             }
 158         }
 159     }
 160 
 161     if (flags != pcmk__alert_none) {
 162         entry->flags = flags;
 163         crm_debug("Alert %s receives events: attributes:%s%s%s%s",
 164                   entry->id,
 165                   (pcmk_is_set(flags, pcmk__alert_attribute)?
 166                    (entry->select_attribute_name? "some" : "all") : "none"),
 167                   (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
 168                   (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
 169                   (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
 170     }
 171 }
 172 
 173 /*!
 174  * \internal
 175  * \brief Unpack an alert or an alert recipient
 176  *
 177  * \param[in,out] alert        Alert or recipient XML
 178  * \param[in,out] entry        Where to store unpacked values
 179  * \param[in,out] max_timeout  Max timeout of all alerts and recipients thus far
 180  *
 181  * \return Standard Pacemaker return code
 182  */
 183 static int
 184 unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186     int rc = pcmk_rc_ok;
 187 
 188     get_envvars_from_cib(alert, entry);
 189     rc = get_meta_attrs_from_cib(alert, entry, max_timeout);
 190     if (rc == pcmk_rc_ok) {
 191         unpack_alert_filter(alert, entry);
 192     }
 193     return rc;
 194 }
 195 
 196 /*!
 197  * \internal
 198  * \brief Unpack a CIB alerts section
 199  *
 200  * \param[in] alerts  XML of alerts section
 201  *
 202  * \return  List of unpacked alert entries
 203  *
 204  * \note Unlike most unpack functions, this is not used by the scheduler itself,
 205  *       but is supplied for use by daemons that need to send alerts.
 206  */
 207 GList *
 208 pe_unpack_alerts(const xmlNode *alerts)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210     xmlNode *alert;
 211     pcmk__alert_t *entry;
 212     guint max_timeout = 0;
 213     GList *alert_list = NULL;
 214 
 215     if (alerts == NULL) {
 216         return alert_list;
 217     }
 218 
 219     for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT);
 220          alert != NULL; alert = crm_next_same_xml(alert)) {
 221 
 222         xmlNode *recipient;
 223         int recipients = 0;
 224         const char *alert_id = ID(alert);
 225         const char *alert_path = crm_element_value(alert, XML_ALERT_ATTR_PATH);
 226 
 227         /* The schema should enforce this, but to be safe ... */
 228         if ((alert_id == NULL) || (alert_path == NULL)) {
 229             crm_warn("Ignoring invalid alert without id and path");
 230             continue;
 231         }
 232 
 233         entry = pcmk__alert_new(alert_id, alert_path);
 234 
 235         if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
 236             // Don't allow recipients to override if entire alert is disabled
 237             crm_debug("Alert %s is disabled", entry->id);
 238             pcmk__free_alert(entry);
 239             continue;
 240         }
 241 
 242         if (entry->tstamp_format == NULL) {
 243             entry->tstamp_format = strdup(PCMK__ALERT_DEFAULT_TSTAMP_FORMAT);
 244         }
 245 
 246         crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars",
 247                   entry->id, entry->path, entry->timeout, entry->tstamp_format,
 248                   (entry->envvars? g_hash_table_size(entry->envvars) : 0));
 249 
 250         for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT);
 251              recipient != NULL; recipient = crm_next_same_xml(recipient)) {
 252 
 253             pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
 254 
 255             recipients++;
 256             recipient_entry->recipient = strdup(crm_element_value(recipient,
 257                                                 XML_ALERT_ATTR_REC_VALUE));
 258 
 259             if (unpack_alert(recipient, recipient_entry,
 260                              &max_timeout) != pcmk_rc_ok) {
 261                 crm_debug("Alert %s: recipient %s is disabled",
 262                           entry->id, recipient_entry->id);
 263                 pcmk__free_alert(recipient_entry);
 264                 continue;
 265             }
 266             alert_list = g_list_prepend(alert_list, recipient_entry);
 267             crm_debug("Alert %s has recipient %s with value %s and %d envvars",
 268                       entry->id, ID(recipient), recipient_entry->recipient,
 269                       (recipient_entry->envvars?
 270                        g_hash_table_size(recipient_entry->envvars) : 0));
 271         }
 272 
 273         if (recipients == 0) {
 274             alert_list = g_list_prepend(alert_list, entry);
 275         } else {
 276             pcmk__free_alert(entry);
 277         }
 278     }
 279     return alert_list;
 280 }
 281 
 282 /*!
 283  * \internal
 284  * \brief Free an alert list generated by pe_unpack_alerts()
 285  *
 286  * \param[in,out] alert_list  Alert list to free
 287  */
 288 void
 289 pe_free_alert_list(GList *alert_list)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291     if (alert_list) {
 292         g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
 293     }
 294 }

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