pacemaker  2.1.6-802a72226b
Scalable High-Availability cluster resource manager
rules_alerts.c
Go to the documentation of this file.
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>
17 
28 static int
29 get_meta_attrs_from_cib(xmlNode *basenode, pcmk__alert_t *entry,
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",
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  }
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)
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)
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)) {
133 
134  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_NODES)) {
136 
137  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_RESOURCES)) {
139 
140  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_ATTRIBUTES)) {
141  xmlNode *attr;
142  const char *attr_name;
143  int nattrs = 0;
144 
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,
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 
188 static int
189 unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
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 
212 GList *
213 pe_unpack_alerts(const xmlNode *alerts)
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) {
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,
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 
293 void
294 pe_free_alert_list(GList *alert_list)
295 {
296  if (alert_list) {
297  g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
298  }
299 }
A dumping ground.
const char * name
Definition: cib.c:24
struct crm_time_s crm_time_t
Definition: iso8601.h:32
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2521
char ** select_attribute_name
#define XML_CIB_TAG_ALERT_RESOURCES
Definition: msg_xml.h:214
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:364
char * tstamp_format
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:403
#define XML_CIB_TAG_ALERT_ATTRIBUTES
Definition: msg_xml.h:211
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:219
#define XML_ALERT_ATTR_REC_VALUE
Definition: msg_xml.h:420
#define PCMK_META_ENABLED
Definition: msg_xml.h:62
void pcmk__free_alert(pcmk__alert_t *entry)
Definition: alerts.c:108
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:222
#define crm_warn(fmt, args...)
Definition: logging.h:378
#define crm_debug(fmt, args...)
Definition: logging.h:382
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:496
pcmk__alert_t * pcmk__dup_alert(const pcmk__alert_t *entry)
Definition: alerts.c:133
#define XML_CIB_TAG_ALERT_NODES
Definition: msg_xml.h:213
#define crm_trace(fmt, args...)
Definition: logging.h:383
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:121
#define XML_TAG_META_SETS
Definition: msg_xml.h:223
void pe_unpack_nvpairs(xmlNode *top, const xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now, crm_time_t *next_change)
Extract nvpair blocks contained by an XML element into a hash table.
Definition: rules.c:532
GHashTable * envvars
#define XML_ALERT_ATTR_TIMEOUT
Definition: msg_xml.h:418
#define XML_ALERT_ATTR_TSTAMP_FORMAT
Definition: msg_xml.h:419
GList * pe_unpack_alerts(const xmlNode *alerts)
Definition: rules_alerts.c:213
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:611
#define XML_CIB_TAG_ALERT
Definition: msg_xml.h:208
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:109
#define XML_CIB_TAG_ALERT_FENCING
Definition: msg_xml.h:212
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:404
void pe_free_alert_list(GList *alert_list)
Definition: rules_alerts.c:294
pcmk__alert_t * pcmk__alert_new(const char *id, const char *path)
Create a new alert entry structure.
Definition: alerts.c:95
gboolean crm_is_true(const char *s)
Definition: strings.c:416
#define XML_CIB_TAG_ALERT_SELECT
Definition: msg_xml.h:210
#define PCMK__ALERT_DEFAULT_TSTAMP_FORMAT
#define XML_ALERT_ATTR_PATH
Definition: msg_xml.h:417
#define XML_CIB_TAG_ALERT_ATTR
Definition: msg_xml.h:215
#define ID(x)
Definition: msg_xml.h:480
#define XML_CIB_TAG_ALERT_RECIPIENT
Definition: msg_xml.h:209
#define PCMK__ALERT_DEFAULT_TIMEOUT_MS
uint64_t flags
Definition: remote.c:215
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2547
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:150