pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rules_alerts.c
Go to the documentation of this file.
1 /*
2  * Copyright 2015-2021 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 
18 static void
19 get_meta_attrs_from_cib(xmlNode *basenode, pcmk__alert_t *entry,
20  guint *max_timeout)
21 {
22  GHashTable *config_hash = pcmk__strkey_table(free, free);
23  crm_time_t *now = crm_time_new(NULL);
24  const char *value = NULL;
25 
26  pe_unpack_nvpairs(basenode, basenode, XML_TAG_META_SETS, NULL, config_hash,
27  NULL, FALSE, now, NULL);
28  crm_time_free(now);
29 
30  value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TIMEOUT);
31  if (value) {
32  entry->timeout = crm_get_msec(value);
33  if (entry->timeout <= 0) {
34  if (entry->timeout == 0) {
35  crm_trace("Alert %s uses default timeout of %dmsec",
37  } else {
38  crm_warn("Alert %s has invalid timeout value '%s', using default %dmsec",
39  entry->id, (char*)value, PCMK__ALERT_DEFAULT_TIMEOUT_MS);
40  }
42  } else {
43  crm_trace("Alert %s uses timeout of %dmsec",
44  entry->id, entry->timeout);
45  }
46  if (entry->timeout > *max_timeout) {
47  *max_timeout = entry->timeout;
48  }
49  }
50  value = g_hash_table_lookup(config_hash, XML_ALERT_ATTR_TSTAMP_FORMAT);
51  if (value) {
52  /* hard to do any checks here as merely anything can
53  * can be a valid time-format-string
54  */
55  entry->tstamp_format = strdup(value);
56  crm_trace("Alert %s uses timestamp format '%s'",
57  entry->id, entry->tstamp_format);
58  }
59 
60  g_hash_table_destroy(config_hash);
61 }
62 
63 static void
64 get_envvars_from_cib(xmlNode *basenode, pcmk__alert_t *entry)
65 {
66  xmlNode *child;
67 
68  if ((basenode == NULL) || (entry == NULL)) {
69  return;
70  }
71 
72  child = first_named_child(basenode, XML_TAG_ATTR_SETS);
73  if (child == NULL) {
74  return;
75  }
76 
77  if (entry->envvars == NULL) {
78  entry->envvars = pcmk__strkey_table(free, free);
79  }
80 
81  for (child = first_named_child(child, XML_CIB_TAG_NVPAIR); child != NULL;
82  child = crm_next_same_xml(child)) {
83 
84  const char *name = crm_element_value(child, XML_NVPAIR_ATTR_NAME);
85  const char *value = crm_element_value(child, XML_NVPAIR_ATTR_VALUE);
86 
87  if (value == NULL) {
88  value = "";
89  }
90  g_hash_table_insert(entry->envvars, strdup(name), strdup(value));
91  crm_trace("Alert %s: added environment variable %s='%s'",
92  entry->id, name, value);
93  }
94 }
95 
96 static void
97 unpack_alert_filter(xmlNode *basenode, pcmk__alert_t *entry)
98 {
99  xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT);
100  xmlNode *event_type = NULL;
101  uint32_t flags = pcmk__alert_none;
102 
103  for (event_type = pcmk__xe_first_child(select); event_type != NULL;
104  event_type = pcmk__xe_next(event_type)) {
105 
106  const char *tagname = crm_element_name(event_type);
107 
108  if (tagname == NULL) {
109  continue;
110 
111  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_FENCING)) {
112  flags |= pcmk__alert_fencing;
113 
114  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_NODES)) {
115  flags |= pcmk__alert_node;
116 
117  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_RESOURCES)) {
118  flags |= pcmk__alert_resource;
119 
120  } else if (!strcmp(tagname, XML_CIB_TAG_ALERT_ATTRIBUTES)) {
121  xmlNode *attr;
122  const char *attr_name;
123  int nattrs = 0;
124 
125  flags |= pcmk__alert_attribute;
126  for (attr = first_named_child(event_type, XML_CIB_TAG_ALERT_ATTR);
127  attr != NULL;
128  attr = crm_next_same_xml(attr)) {
129 
130  attr_name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
131  if (attr_name) {
132  if (nattrs == 0) {
133  g_strfreev(entry->select_attribute_name);
134  entry->select_attribute_name = NULL;
135  }
136  ++nattrs;
137  entry->select_attribute_name = pcmk__realloc(entry->select_attribute_name,
138  (nattrs + 1) * sizeof(char*));
139  entry->select_attribute_name[nattrs - 1] = strdup(attr_name);
140  entry->select_attribute_name[nattrs] = NULL;
141  }
142  }
143  }
144  }
145 
146  if (flags != pcmk__alert_none) {
147  entry->flags = flags;
148  crm_debug("Alert %s receives events: attributes:%s%s%s%s",
149  entry->id,
151  (entry->select_attribute_name? "some" : "all") : "none"),
152  (pcmk_is_set(flags, pcmk__alert_fencing)? " fencing" : ""),
153  (pcmk_is_set(flags, pcmk__alert_node)? " nodes" : ""),
154  (pcmk_is_set(flags, pcmk__alert_resource)? " resources" : ""));
155  }
156 }
157 
158 static void
159 unpack_alert(xmlNode *alert, pcmk__alert_t *entry, guint *max_timeout)
160 {
161  get_envvars_from_cib(alert, entry);
162  get_meta_attrs_from_cib(alert, entry, max_timeout);
163  unpack_alert_filter(alert, entry);
164 }
165 
177 GList *
178 pe_unpack_alerts(xmlNode *alerts)
179 {
180  xmlNode *alert;
181  pcmk__alert_t *entry;
182  guint max_timeout = 0;
183  GList *alert_list = NULL;
184 
185  if (alerts == NULL) {
186  return alert_list;
187  }
188 
189  for (alert = first_named_child(alerts, XML_CIB_TAG_ALERT);
190  alert != NULL; alert = crm_next_same_xml(alert)) {
191 
192  xmlNode *recipient;
193  int recipients = 0;
194  const char *alert_id = ID(alert);
195  const char *alert_path = crm_element_value(alert, XML_ALERT_ATTR_PATH);
196 
197  /* The schema should enforce this, but to be safe ... */
198  if ((alert_id == NULL) || (alert_path == NULL)) {
199  crm_warn("Ignoring invalid alert without id and path");
200  continue;
201  }
202 
203  entry = pcmk__alert_new(alert_id, alert_path);
204 
205  unpack_alert(alert, entry, &max_timeout);
206 
207  if (entry->tstamp_format == NULL) {
209  }
210 
211  crm_debug("Alert %s: path=%s timeout=%dms tstamp-format='%s' %u vars",
212  entry->id, entry->path, entry->timeout, entry->tstamp_format,
213  (entry->envvars? g_hash_table_size(entry->envvars) : 0));
214 
215  for (recipient = first_named_child(alert, XML_CIB_TAG_ALERT_RECIPIENT);
216  recipient != NULL; recipient = crm_next_same_xml(recipient)) {
217 
218  pcmk__alert_t *recipient_entry = pcmk__dup_alert(entry);
219 
220  recipients++;
221  recipient_entry->recipient = strdup(crm_element_value(recipient,
223  unpack_alert(recipient, recipient_entry, &max_timeout);
224  alert_list = g_list_prepend(alert_list, recipient_entry);
225  crm_debug("Alert %s has recipient %s with value %s and %d envvars",
226  entry->id, ID(recipient), recipient_entry->recipient,
227  (recipient_entry->envvars?
228  g_hash_table_size(recipient_entry->envvars) : 0));
229  }
230 
231  if (recipients == 0) {
232  alert_list = g_list_prepend(alert_list, entry);
233  } else {
234  pcmk__free_alert(entry);
235  }
236  }
237  return alert_list;
238 }
239 
246 void
247 pe_free_alert_list(GList *alert_list)
248 {
249  if (alert_list) {
250  g_list_free_full(alert_list, (GDestroyNotify) pcmk__free_alert);
251  }
252 }
A dumping ground.
void pe_unpack_nvpairs(xmlNode *top, 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:628
struct crm_time_s crm_time_t
Definition: iso8601.h:32
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2790
char ** select_attribute_name
void pe_free_alert_list(GList *alert_list)
Definition: rules_alerts.c:247
#define XML_CIB_TAG_ALERT_RESOURCES
Definition: msg_xml.h:195
long long crm_get_msec(const char *input)
Parse a time+units string and return milliseconds equivalent.
Definition: strings.c:363
char * tstamp_format
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:377
#define XML_CIB_TAG_ALERT_ATTRIBUTES
Definition: msg_xml.h:192
pcmk__alert_t * pcmk__dup_alert(pcmk__alert_t *entry)
Definition: alerts.c:133
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:200
#define XML_ALERT_ATTR_REC_VALUE
Definition: msg_xml.h:394
void pcmk__free_alert(pcmk__alert_t *entry)
Definition: alerts.c:108
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:203
#define crm_warn(fmt, args...)
Definition: logging.h:351
#define crm_debug(fmt, args...)
Definition: logging.h:355
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:530
#define XML_CIB_TAG_ALERT_NODES
Definition: msg_xml.h:194
#define crm_trace(fmt, args...)
Definition: logging.h:356
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition: util.h:114
#define XML_TAG_META_SETS
Definition: msg_xml.h:204
GHashTable * envvars
#define XML_ALERT_ATTR_TIMEOUT
Definition: msg_xml.h:392
#define XML_ALERT_ATTR_TSTAMP_FORMAT
Definition: msg_xml.h:393
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:610
#define XML_CIB_TAG_ALERT
Definition: msg_xml.h:189
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:93
#define XML_CIB_TAG_ALERT_FENCING
Definition: msg_xml.h:193
GList * pe_unpack_alerts(xmlNode *alerts)
Definition: rules_alerts.c:178
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:378
pcmk__alert_t * pcmk__alert_new(const char *id, const char *path)
Create a new alert entry structure.
Definition: alerts.c:95
#define XML_CIB_TAG_ALERT_SELECT
Definition: msg_xml.h:191
#define PCMK__ALERT_DEFAULT_TSTAMP_FORMAT
#define XML_ALERT_ATTR_PATH
Definition: msg_xml.h:391
#define XML_CIB_TAG_ALERT_ATTR
Definition: msg_xml.h:196
#define ID(x)
Definition: msg_xml.h:456
char * name
Definition: pcmk_fence.c:31
#define XML_CIB_TAG_ALERT_RECIPIENT
Definition: msg_xml.h:190
#define PCMK__ALERT_DEFAULT_TIMEOUT_MS
uint64_t flags
Definition: remote.c:149
xmlNode * crm_next_same_xml(const xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:2816
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:141