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         const char *tagname = crm_element_name(event_type);
 127 
 128         if (tagname == NULL) {
 129             continue;
 130 
 131         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_FENCING)) {
 132             flags |= pcmk__alert_fencing;
 133 
 134         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_NODES)) {
 135             flags |= pcmk__alert_node;
 136 
 137         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_RESOURCES)) {
 138             flags |= pcmk__alert_resource;
 139 
 140         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_ATTRIBUTES)) {
 141             xmlNode *attr;
 142             const char *attr_name;
 143             int nattrs = 0;
 144 
 145             flags |= pcmk__alert_attribute;
 146             for (attr = first_named_child(event_type, XML_CIB_TAG_ALERT_ATTR);
 147                  attr != NULL;
 148                  attr = crm_next_same_xml(attr)) {
 149 
 150                 attr_name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
 151                 if (attr_name) {
 152                     if (nattrs == 0) {
 153                         g_strfreev(entry->select_attribute_name);
 154                         entry->select_attribute_name = NULL;
 155                     }
 156                     ++nattrs;
 157                     entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
 158                                                                  (nattrs + 1) * sizeof(char*));
 159                     entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
 160                     entry->select_attribute_name[nattrs] = NULL;
 161                 }
 162             }
 163         }
 164     }
 165 
 166     if (flags != pcmk__alert_none) {
 167         entry->flags = flags;
 168         crm_debug("Alert %s receives events: attributes:%s%s%s%s",
 169                   entry->id,
 170                   (pcmk_is_set(flags, pcmk__alert_attribute)?
 171                    (entry->select_attribute_name? "some" : "all") : "none"),
 172                   (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
 173                   (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
 174                   (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
 175     }
 176 }
 177 
 178 /*!
 179  * \internal
 180  * \brief Unpack an alert or an alert recipient
 181  *
 182  * \param[in,out] alert        Alert or recipient XML
 183  * \param[in,out] entry        Where to store unpacked values
 184  * \param[in,out] max_timeout  Max timeout of all alerts and recipients thus far
 185  *
 186  * \return Standard Pacemaker return code
 187  */
 188 static int
 189 unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191     int rc = pcmk_rc_ok;
 192 
 193     get_envvars_from_cib(alert, entry);
 194     rc = get_meta_attrs_from_cib(alert, entry, max_timeout);
 195     if (rc == pcmk_rc_ok) {
 196         unpack_alert_filter(alert, entry);
 197     }
 198     return rc;
 199 }
 200 
 201 /*!
 202  * \internal
 203  * \brief Unpack a CIB alerts section
 204  *
 205  * \param[in] alerts  XML of alerts section
 206  *
 207  * \return  List of unpacked alert entries
 208  *
 209  * \note Unlike most unpack functions, this is not used by the scheduler itself,
 210  *       but is supplied for use by daemons that need to send alerts.
 211  */
 212 GList *
 213 pe_unpack_alerts(const xmlNode *alerts)
     /* [previous][next][first][last][top][bottom][index][help] */
 214 {
 215     xmlNode *alert;
 216     pcmk__alert_t *entry;
 217     guint max_timeout = 0;
 218     GList *alert_list = NULL;
 219 
 220     if (alerts == NULL) {
 221         return alert_list;
 222     }
 223 
 224     for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT);
 225          alert != NULL; alert = crm_next_same_xml(alert)) {
 226 
 227         xmlNode *recipient;
 228         int recipients = 0;
 229         const char *alert_id = ID(alert);
 230         const char *alert_path = crm_element_value(alert, XML_ALERT_ATTR_PATH);
 231 
 232         /* The schema should enforce this, but to be safe ... */
 233         if ((alert_id == NULL) || (alert_path == NULL)) {
 234             crm_warn("Ignoring invalid alert without id and path");
 235             continue;
 236         }
 237 
 238         entry = pcmk__alert_new(alert_id, alert_path);
 239 
 240         if (unpack_alert(alert, entry, &max_timeout) != pcmk_rc_ok) {
 241             // Don't allow recipients to override if entire alert is disabled
 242             crm_debug("Alert %s is disabled", entry->id);
 243             pcmk__free_alert(entry);
 244             continue;
 245         }
 246 
 247         if (entry->tstamp_format == NULL) {
 248             entry->tstamp_format = strdup(PCMK__ALERT_DEFAULT_TSTAMP_FORMAT);
 249         }
 250 
 251         crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars",
 252                   entry->id, entry->path, entry->timeout, entry->tstamp_format,
 253                   (entry->envvars? g_hash_table_size(entry->envvars) : 0));
 254 
 255         for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT);
 256              recipient != NULL; recipient = crm_next_same_xml(recipient)) {
 257 
 258             pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
 259 
 260             recipients++;
 261             recipient_entry->recipient = strdup(crm_element_value(recipient,
 262                                                 XML_ALERT_ATTR_REC_VALUE));
 263 
 264             if (unpack_alert(recipient, recipient_entry,
 265                              &max_timeout) != pcmk_rc_ok) {
 266                 crm_debug("Alert %s: recipient %s is disabled",
 267                           entry->id, recipient_entry->id);
 268                 pcmk__free_alert(recipient_entry);
 269                 continue;
 270             }
 271             alert_list = g_list_prepend(alert_list, recipient_entry);
 272             crm_debug("Alert %s has recipient %s with value %s and %d envvars",
 273                       entry->id, ID(recipient), recipient_entry->recipient,
 274                       (recipient_entry->envvars?
 275                        g_hash_table_size(recipient_entry->envvars) : 0));
 276         }
 277 
 278         if (recipients == 0) {
 279             alert_list = g_list_prepend(alert_list, entry);
 280         } else {
 281             pcmk__free_alert(entry);
 282         }
 283     }
 284     return alert_list;
 285 }
 286 
 287 /*!
 288  * \internal
 289  * \brief Free an alert list generated by pe_unpack_alerts()
 290  *
 291  * \param[in,out] alert_list  Alert list to free
 292  */
 293 void
 294 pe_free_alert_list(GList *alert_list)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296     if (alert_list) {
 297         g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
 298     }
 299 }

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