pacemaker  1.1.18-7fdfbbe
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 (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>
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)
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,
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",
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  }
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)
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)
125 {
126  xmlNode *select = first_named_child(basenode, XML_CIB_TAG_ALERT_SELECT);
127  xmlNode *event_type = NULL;
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)
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 
204 GListPtr
205 pe_unpack_alerts(xmlNode *alerts)
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);
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) {
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,
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 
288 void
290 {
291  if (alert_list) {
292  g_list_free_full(alert_list, (GDestroyNotify) crm_free_alert_entry);
293  }
294 }
A dumping ground.
#define CRM_ALERT_DEFAULT_TSTAMP_FORMAT
void pe_free_alert_list(GListPtr alert_list)
Definition: rules_alerts.c:289
struct crm_time_s crm_time_t
Definition: iso8601.h:37
#define CRM_ALERT_DEFAULT_TIMEOUT_MS
GHashTable * envvars
char * recipient
#define XML_CIB_TAG_ALERT_RESOURCES
Definition: msg_xml.h:174
long long crm_get_msec(const char *input)
Definition: utils.c:598
#define XML_NVPAIR_ATTR_NAME
Definition: msg_xml.h:366
#define XML_CIB_TAG_ALERT_ATTRIBUTES
Definition: msg_xml.h:171
#define XML_CIB_TAG_NVPAIR
Definition: msg_xml.h:181
#define XML_ALERT_ATTR_REC_VALUE
Definition: msg_xml.h:380
crm_alert_entry_t * crm_dup_alert_entry(crm_alert_entry_t *entry)
Definition: alerts.c:119
uint32_t flags
GListPtr pe_unpack_alerts(xmlNode *alerts)
Definition: rules_alerts.c:205
char * tstamp_format
#define XML_TAG_ATTR_SETS
Definition: msg_xml.h:184
#define crm_warn(fmt, args...)
Definition: logging.h:249
char * id
#define crm_debug(fmt, args...)
Definition: logging.h:253
#define XML_CIB_TAG_ALERT_NODES
Definition: msg_xml.h:173
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define XML_TAG_META_SETS
Definition: msg_xml.h:185
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5165
xmlNode * crm_next_same_xml(xmlNode *sibling)
Get next instance of same XML tag.
Definition: xml.c:5078
#define XML_ALERT_ATTR_TIMEOUT
Definition: msg_xml.h:378
#define XML_ALERT_ATTR_TSTAMP_FORMAT
Definition: msg_xml.h:379
#define XML_CIB_TAG_ALERT
Definition: msg_xml.h:168
crm_time_t * crm_time_new(const char *string)
Definition: iso8601.c:99
crm_alert_entry_t * crm_alert_entry_new(const char *id, const char *path)
Create a new alert entry structure.
Definition: alerts.c:70
char ** select_attribute_name
#define XML_CIB_TAG_ALERT_FENCING
Definition: msg_xml.h:172
int timeout
#define XML_NVPAIR_ATTR_VALUE
Definition: msg_xml.h:367
#define uint32_t
Definition: stdint.in.h:158
char * path
void unpack_instance_attributes(xmlNode *top, xmlNode *xml_obj, const char *set_name, GHashTable *node_hash, GHashTable *hash, const char *always_first, gboolean overwrite, crm_time_t *now)
Definition: rules.c:919
xmlNode * first_named_child(xmlNode *parent, const char *name)
Definition: xml.c:5053
#define XML_CIB_TAG_ALERT_SELECT
Definition: msg_xml.h:170
#define XML_ALERT_ATTR_PATH
Definition: msg_xml.h:377
#define XML_CIB_TAG_ALERT_ATTR
Definition: msg_xml.h:175
#define ID(x)
Definition: msg_xml.h:446
#define XML_CIB_TAG_ALERT_RECIPIENT
Definition: msg_xml.h:169
void crm_free_alert_entry(crm_alert_entry_t *entry)
Definition: alerts.c:83
GList * GListPtr
Definition: crm.h:218
uint64_t flags
Definition: remote.c:156
void crm_time_free(crm_time_t *dt)
Definition: iso8601.c:116