root/lib/pengine/rules_alerts.c

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

DEFINITIONS

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

   1 /*
   2  * Copyright (C) 2015-2017 Andrew Beekhof <andrew@beekhof.net>
   3  *
   4  * This source code is licensed under the GNU Lesser General Public License
   5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   6  */
   7 
   8 #include <crm_internal.h>
   9 #include <crm/crm.h>
  10 #include <crm/msg_xml.h>
  11 #include <crm/pengine/rules.h>
  12 #include <crm/common/alerts_internal.h>
  13 #include <crm/pengine/rules_internal.h>
  14 
  15 #ifdef RHEL7_COMPAT
  16 /* @COMPAT An early implementation of alerts was backported to RHEL 7,
  17  * even though it was never in an upstream release.
  18  */
  19 static char *notify_script = NULL;
  20 static char *notify_target = NULL;
  21 
  22 void
  23 pe_enable_legacy_alerts(const char *script, const char *target)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25     static bool need_warning = TRUE;
  26 
  27     free(notify_script);
  28     notify_script = (script && strcmp(script, "/dev/null"))?
  29                     strdup(script) : NULL;
  30 
  31     free(notify_target);
  32     notify_target = target? strdup(target): NULL;
  33 
  34     if (notify_script || notify_target) {
  35         if (need_warning) {
  36             crm_warn("Support for 'notification-agent' and 'notification-target' cluster options"
  37                      " is deprecated and will be removed in a future release"
  38                      " (use alerts feature instead)");
  39             need_warning = FALSE;
  40         }
  41     }
  42 }
  43 #endif
  44 
  45 static void
  46 get_meta_attrs_from_cib(xmlNode *basenode, crm_alert_entry_t *entry,
     /* [previous][next][first][last][top][bottom][index][help] */
  47                         guint *max_timeout)
  48 {
  49     GHashTable *config_hash = crm_str_table_new();
  50     crm_time_t *now = crm_time_new(NULL);
  51     const char *value = NULL;
  52 
  53     unpack_instance_attributes(basenode, basenode, XML_TAG_META_SETS, NULL,
  54                                config_hash, NULL, FALSE, now);
  55     crm_time_free(now);
  56 
  57     value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TIMEOUT);
  58     if (value) {
  59         entry->timeout = crm_get_msec(value);
  60         if (entry->timeout <= 0) {
  61             if (entry->timeout == 0) {
  62                 crm_trace("Alert %s uses default timeout of %dmsec",
  63                           entry->id, CRM_ALERT_DEFAULT_TIMEOUT_MS);
  64             } else {
  65                 crm_warn("Alert %s has invalid timeout value '%s', using default %dmsec",
  66                          entry->id, (char*)value, CRM_ALERT_DEFAULT_TIMEOUT_MS);
  67             }
  68             entry->timeout = CRM_ALERT_DEFAULT_TIMEOUT_MS;
  69         } else {
  70             crm_trace("Alert %s uses timeout of %dmsec",
  71                       entry->id, entry->timeout);
  72         }
  73         if (entry->timeout > *max_timeout) {
  74             *max_timeout = entry->timeout;
  75         }
  76     }
  77     value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TSTAMP_FORMAT);
  78     if (value) {
  79         /* hard to do any checks here as merely anything can
  80          * can be a valid time-format-string
  81          */
  82         entry->tstamp_format = strdup(value);
  83         crm_trace("Alert %s uses timestamp format '%s'",
  84                   entry->id, entry->tstamp_format);
  85     }
  86 
  87     g_hash_table_destroy(config_hash);
  88 }
  89 
  90 static void
  91 get_envvars_from_cib(xmlNode *basenode, crm_alert_entry_t *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
  92 {
  93     xmlNode *child;
  94 
  95     if ((basenode == NULL) || (entry == NULL)) {
  96         return;
  97     }
  98 
  99     child = first_named_child(basenode, XML_TAG_ATTR_SETS);
 100     if (child == NULL) {
 101         return;
 102     }
 103 
 104     if (entry->envvars == NULL) {
 105         entry->envvars = crm_str_table_new();
 106     }
 107 
 108     for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL;
 109          child = crm_next_same_xml(child)) {
 110 
 111         const char *name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
 112         const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE);
 113 
 114         if (value == NULL) {
 115             value = "";
 116         }
 117         g_hash_table_insert(entry->envvars, strdup(name), strdup(value));
 118         crm_trace("Alert %s: added environment variable %s='%s'",
 119                   entry->id, name, value);
 120     }
 121 }
 122 
 123 static void
 124 unpack_alert_filter(xmlNode *basenode, crm_alert_entry_t *entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126     xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT);
 127     xmlNode *event_type = NULL;
 128     uint32_t flags = crm_alert_none;
 129 
 130     for (event_type = __xml_first_child(select); event_type != NULL;
 131          event_type = __xml_next(event_type)) {
 132 
 133         const char *tagname = crm_element_name(event_type);
 134 
 135         if (tagname == NULL) {
 136             continue;
 137 
 138         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_FENCING)) {
 139             flags |= crm_alert_fencing;
 140 
 141         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_NODES)) {
 142             flags |= crm_alert_node;
 143 
 144         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_RESOURCES)) {
 145             flags |= crm_alert_resource;
 146 
 147         } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_ATTRIBUTES)) {
 148             xmlNode *attr;
 149             const char *attr_name;
 150             int nattrs = 0;
 151 
 152             flags |= crm_alert_attribute;
 153             for (attr = first_named_child(event_type, XML_CIB_TAG_ALERT_ATTR);
 154                  attr != NULL;
 155                  attr = crm_next_same_xml(attr)) {
 156 
 157                 attr_name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
 158                 if (attr_name) {
 159                     if (nattrs == 0) {
 160                         g_strfreev(entry->select_attribute_name);
 161                         entry->select_attribute_name = NULL;
 162                     }
 163                     ++nattrs;
 164                     entry->select_attribute_name = realloc_safe(entry->select_attribute_name,
 165                                                                 (nattrs + 1) * sizeof(char*));
 166                     entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
 167                     entry->select_attribute_name[nattrs] = NULL;
 168                 }
 169             }
 170         }
 171     }
 172 
 173     if (flags != crm_alert_none) {
 174         entry->flags = flags;
 175         crm_debug("Alert %s receives events: attributes:%s, fencing:%s, nodes:%s, resources:%s",
 176                   entry->id,
 177                   (flags & crm_alert_attribute)?
 178                     (entry->select_attribute_name? "some" : "all") : "no",
 179                   (flags & crm_alert_fencing)? "yes" : "no",
 180                   (flags & crm_alert_node)? "yes" : "no",
 181                   (flags & crm_alert_resource)? "yes" : "no");
 182     }
 183 }
 184 
 185 static void
 186 unpack_alert(xmlNode *alert, crm_alert_entry_t *entry, guint *max_timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188     get_envvars_from_cib(alert, entry);
 189     get_meta_attrs_from_cib(alert, entry, max_timeout);
 190     unpack_alert_filter(alert, entry);
 191 }
 192 
 193 /*!
 194  * \internal
 195  * \brief Unpack a CIB alerts section
 196  *
 197  * \param[in] alerts  XML of alerts section
 198  *
 199  * \return  List of unpacked alert entries
 200  *
 201  * \note Unlike most unpack functions, this is not used by the pengine itself,
 202  *       but is supplied for use by daemons that need to send alerts.
 203  */
 204 GListPtr
 205 pe_unpack_alerts(xmlNode *alerts)
     /* [previous][next][first][last][top][bottom][index][help] */
 206 {
 207     xmlNode *alert;
 208     crm_alert_entry_t *entry;
 209     guint max_timeout = 0;
 210     GListPtr alert_list = NULL;
 211 
 212     if (alerts) {
 213 #ifdef RHEL7_COMPAT
 214         if (notify_script) {
 215             crm_warn("Ignoring deprecated notification configuration because alerts available");
 216         }
 217 #endif
 218     } else {
 219 #ifdef RHEL7_COMPAT
 220         if (notify_script) {
 221             entry = crm_alert_entry_new("legacy_notification", notify_script);
 222             entry->recipient = strdup(notify_target);
 223             entry->tstamp_format = strdup(CRM_ALERT_DEFAULT_TSTAMP_FORMAT);
 224             alert_list = g_list_prepend(alert_list, entry);
 225             crm_warn("Deprecated notification syntax in use (alerts syntax is preferable)");
 226         }
 227 #endif
 228         return alert_list;
 229     }
 230 
 231     for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT);
 232          alert != NULL; alert = crm_next_same_xml(alert)) {
 233 
 234         xmlNode *recipient;
 235         int recipients = 0;
 236         const char *alert_id = ID(alert);
 237         const char *alert_path = crm_element_value(alert, XML_ALERT_ATTR_PATH);
 238 
 239         /* The schema should enforce this, but to be safe ... */
 240         if ((alert_id == NULL) || (alert_path == NULL)) {
 241             crm_warn("Ignoring invalid alert without id and path");
 242             continue;
 243         }
 244 
 245         entry = crm_alert_entry_new(alert_id, alert_path);
 246 
 247         unpack_alert(alert, entry, &max_timeout);
 248 
 249         if (entry->tstamp_format == NULL) {
 250             entry->tstamp_format = strdup(CRM_ALERT_DEFAULT_TSTAMP_FORMAT);
 251         }
 252 
 253         crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars",
 254                   entry->id, entry->path, entry->timeout, entry->tstamp_format,
 255                   (entry->envvars? g_hash_table_size(entry->envvars) : 0));
 256 
 257         for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT);
 258              recipient != NULL; recipient = crm_next_same_xml(recipient)) {
 259 
 260             crm_alert_entry_t *recipient_entry = crm_dup_alert_entry(entry);
 261 
 262             recipients++;
 263             recipient_entry->recipient = strdup(crm_element_value(recipient,
 264                                                 XML_ALERT_ATTR_REC_VALUE));
 265             unpack_alert(recipient, recipient_entry, &max_timeout);
 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             crm_free_alert_entry(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] alert_list  Alert list to free
 287  */
 288 void
 289 pe_free_alert_list(GListPtr alert_list)
     /* [previous][next][first][last][top][bottom][index][help] */
 290 {
 291     if (alert_list) {
 292         g_list_free_full(alert_list, (GDestroyNotify) crm_free_alert_entry);
 293     }
 294 }

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