pacemaker  2.1.0-7c3f660
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pcmk_trans_unpack.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-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 
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 
15 #include <crm/crm.h>
16 #include <crm/msg_xml.h>
17 #include <crm/common/xml.h>
19 #include <pacemaker-internal.h>
20 
21 static crm_action_t *
22 unpack_action(synapse_t * parent, xmlNode * xml_action)
23 {
24  crm_action_t *action = NULL;
25  const char *value = crm_element_value(xml_action, XML_ATTR_ID);
26 
27  if (value == NULL) {
28  crm_err("Actions must have an id!");
29  crm_log_xml_trace(xml_action, "Action with missing id");
30  return NULL;
31  }
32 
33  action = calloc(1, sizeof(crm_action_t));
34  if (action == NULL) {
35  crm_perror(LOG_CRIT, "Cannot unpack action");
36  crm_log_xml_trace(xml_action, "Lost action");
37  return NULL;
38  }
39 
40  pcmk__scan_min_int(value, &(action->id), -1);
41  action->type = action_type_rsc;
42  action->xml = copy_xml(xml_action);
43  action->synapse = parent;
44 
45  if (pcmk__str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_RSC_OP, pcmk__str_casei)) {
46  action->type = action_type_rsc;
47 
48  } else if (pcmk__str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_PSEUDO_EVENT, pcmk__str_casei)) {
49  action->type = action_type_pseudo;
50 
51  } else if (pcmk__str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_CRM_EVENT, pcmk__str_casei)) {
52  action->type = action_type_crm;
53  }
54 
55  action->params = xml2list(action->xml);
56 
57  value = g_hash_table_lookup(action->params, "CRM_meta_timeout");
58  pcmk__scan_min_int(value, &(action->timeout), 0);
59 
60  /* Take start-delay into account for the timeout of the action timer */
61  value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
62  {
63  int start_delay;
64 
65  pcmk__scan_min_int(value, &start_delay, 0);
66  action->timeout += start_delay;
67  }
68 
69  if (pcmk__guint_from_hash(action->params,
71  &(action->interval_ms)) != pcmk_rc_ok) {
72  action->interval_ms = 0;
73  }
74 
75  value = g_hash_table_lookup(action->params, "CRM_meta_can_fail");
76  if (value != NULL) {
77  crm_str_to_boolean(value, &(action->can_fail));
78 #ifndef PCMK__COMPAT_2_0
79  if (action->can_fail) {
80  crm_warn("Support for the can_fail meta-attribute is deprecated"
81  " and will be removed in a future release");
82  }
83 #endif
84  }
85 
86  crm_trace("Action %d has timer set to %dms", action->id, action->timeout);
87 
88  return action;
89 }
90 
91 static synapse_t *
92 unpack_synapse(crm_graph_t * new_graph, xmlNode * xml_synapse)
93 {
94  const char *value = NULL;
95  xmlNode *inputs = NULL;
96  xmlNode *action_set = NULL;
97  synapse_t *new_synapse = NULL;
98 
99  CRM_CHECK(xml_synapse != NULL, return NULL);
100  crm_trace("looking in synapse %s", ID(xml_synapse));
101 
102  new_synapse = calloc(1, sizeof(synapse_t));
103  pcmk__scan_min_int(ID(xml_synapse), &(new_synapse->id), 0);
104 
105  value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY);
106  pcmk__scan_min_int(value, &(new_synapse->priority), 0);
107 
108  CRM_CHECK(new_synapse->id >= 0, free(new_synapse);
109  return NULL);
110 
111  new_graph->num_synapses++;
112 
113  crm_trace("look for actions in synapse %s", crm_element_value(xml_synapse, XML_ATTR_ID));
114 
115  for (action_set = pcmk__xml_first_child(xml_synapse); action_set != NULL;
116  action_set = pcmk__xml_next(action_set)) {
117 
118  if (pcmk__str_eq((const char *)action_set->name, "action_set",
119  pcmk__str_none)) {
120  xmlNode *action = NULL;
121 
122  for (action = pcmk__xml_first_child(action_set); action != NULL;
123  action = pcmk__xml_next(action)) {
124  crm_action_t *new_action = unpack_action(new_synapse, action);
125 
126  if (new_action == NULL) {
127  continue;
128  }
129 
130  new_graph->num_actions++;
131 
132  crm_trace("Adding action %d to synapse %d", new_action->id, new_synapse->id);
133 
134  new_synapse->actions = g_list_append(new_synapse->actions, new_action);
135  }
136  }
137  }
138 
139  crm_trace("look for inputs in synapse %s", ID(xml_synapse));
140 
141  for (inputs = pcmk__xml_first_child(xml_synapse); inputs != NULL;
142  inputs = pcmk__xml_next(inputs)) {
143 
144  if (pcmk__str_eq((const char *)inputs->name, "inputs", pcmk__str_none)) {
145  xmlNode *trigger = NULL;
146 
147  for (trigger = pcmk__xml_first_child(inputs); trigger != NULL;
148  trigger = pcmk__xml_next(trigger)) {
149  xmlNode *input = NULL;
150 
151  for (input = pcmk__xml_first_child(trigger); input != NULL;
152  input = pcmk__xml_next(input)) {
153  crm_action_t *new_input = unpack_action(new_synapse, input);
154 
155  if (new_input == NULL) {
156  continue;
157  }
158 
159  crm_trace("Adding input %d to synapse %d", new_input->id, new_synapse->id);
160 
161  new_synapse->inputs = g_list_append(new_synapse->inputs, new_input);
162  }
163  }
164  }
165  }
166 
167  return new_synapse;
168 }
169 
170 static void destroy_action(crm_action_t * action);
171 
172 crm_graph_t *
173 unpack_graph(xmlNode * xml_graph, const char *reference)
174 {
175 /*
176  <transition_graph>
177  <synapse>
178  <action_set>
179  <rsc_op id="2"
180  ...
181  <inputs>
182  <rsc_op id="2"
183  ...
184 */
185  crm_graph_t *new_graph = NULL;
186  const char *t_id = NULL;
187  const char *time = NULL;
188  xmlNode *synapse = NULL;
189 
190  new_graph = calloc(1, sizeof(crm_graph_t));
191 
192  new_graph->id = -1;
193  new_graph->abort_priority = 0;
194  new_graph->network_delay = 0;
195  new_graph->stonith_timeout = 0;
196  new_graph->completion_action = tg_done;
197 
198  if (reference) {
199  new_graph->source = strdup(reference);
200  } else {
201  new_graph->source = strdup("unknown");
202  }
203 
204  if (xml_graph != NULL) {
205  t_id = crm_element_value(xml_graph, "transition_id");
206  CRM_CHECK(t_id != NULL, free(new_graph);
207  return NULL);
208  pcmk__scan_min_int(t_id, &(new_graph->id), -1);
209 
210  time = crm_element_value(xml_graph, "cluster-delay");
211  CRM_CHECK(time != NULL, free(new_graph);
212  return NULL);
213  new_graph->network_delay = crm_parse_interval_spec(time);
214 
215  time = crm_element_value(xml_graph, "stonith-timeout");
216  if (time == NULL) {
217  new_graph->stonith_timeout = new_graph->network_delay;
218  } else {
219  new_graph->stonith_timeout = crm_parse_interval_spec(time);
220  }
221 
222  // Use 0 (dynamic limit) as default/invalid, -1 (no limit) as minimum
223  t_id = crm_element_value(xml_graph, "batch-limit");
224  if ((t_id == NULL)
225  || (pcmk__scan_min_int(t_id, &(new_graph->batch_limit),
226  -1) != pcmk_rc_ok)) {
227  new_graph->batch_limit = 0;
228  }
229 
230  t_id = crm_element_value(xml_graph, "migration-limit");
231  pcmk__scan_min_int(t_id, &(new_graph->migration_limit), -1);
232  }
233 
234  for (synapse = pcmk__xml_first_child(xml_graph); synapse != NULL;
235  synapse = pcmk__xml_next(synapse)) {
236 
237  if (pcmk__str_eq((const char *)synapse->name, "synapse", pcmk__str_none)) {
238  synapse_t *new_synapse = unpack_synapse(new_graph, synapse);
239 
240  if (new_synapse != NULL) {
241  new_graph->synapses = g_list_append(new_graph->synapses, new_synapse);
242  }
243  }
244  }
245 
246  crm_debug("Unpacked transition %d: %d actions in %d synapses",
247  new_graph->id, new_graph->num_actions, new_graph->num_synapses);
248 
249  return new_graph;
250 }
251 
252 static void
253 destroy_action(crm_action_t * action)
254 {
255  if (action->timer && action->timer->source_id != 0) {
256  crm_warn("Cancelling timer for action %d (src=%d)", action->id, action->timer->source_id);
257  g_source_remove(action->timer->source_id);
258  }
259  if (action->params) {
260  g_hash_table_destroy(action->params);
261  }
262  free_xml(action->xml);
263  free(action->timer);
264  free(action);
265 }
266 
267 static void
268 destroy_synapse(synapse_t * synapse)
269 {
270  while (synapse->actions != NULL) {
271  crm_action_t *action = g_list_nth_data(synapse->actions, 0);
272 
273  synapse->actions = g_list_remove(synapse->actions, action);
274  destroy_action(action);
275  }
276 
277  while (synapse->inputs != NULL) {
278  crm_action_t *action = g_list_nth_data(synapse->inputs, 0);
279 
280  synapse->inputs = g_list_remove(synapse->inputs, action);
281  destroy_action(action);
282  }
283  free(synapse);
284 }
285 
286 void
288 {
289  if (graph == NULL) {
290  return;
291  }
292  while (graph->synapses != NULL) {
293  synapse_t *synapse = g_list_nth_data(graph->synapses, 0);
294 
295  graph->synapses = g_list_remove(graph->synapses, synapse);
296  destroy_synapse(synapse);
297  }
298 
299  free(graph->source);
300  free(graph);
301 }
302 
304 convert_graph_action(xmlNode * resource, crm_action_t * action, int status, int rc)
305 {
306  xmlNode *xop = NULL;
307  lrmd_event_data_t *op = NULL;
308  GHashTableIter iter;
309  const char *name = NULL;
310  const char *value = NULL;
311  xmlNode *action_resource = NULL;
312 
313  CRM_CHECK(action != NULL, return NULL);
314  CRM_CHECK(action->type == action_type_rsc, return NULL);
315 
316  action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
317  CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "Bad");
318  return NULL);
319 
320  op = lrmd_new_event(ID(action_resource),
322  action->interval_ms);
323  op->rc = rc;
324  op->op_status = status;
325  op->t_run = time(NULL);
326  op->t_rcchange = op->t_run;
327  op->params = pcmk__strkey_table(free, free);
328 
329  g_hash_table_iter_init(&iter, action->params);
330  while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
331  g_hash_table_insert(op->params, strdup(name), strdup(value));
332  }
333 
334  for (xop = pcmk__xml_first_child(resource); xop != NULL;
335  xop = pcmk__xml_next(xop)) {
336  int tmp = 0;
337 
339  crm_debug("Got call_id=%d for %s", tmp, ID(resource));
340  if (tmp > op->call_id) {
341  op->call_id = tmp;
342  }
343  }
344 
345  op->call_id++;
346  return op;
347 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:218
A dumping ground.
action_type_e type
enum transition_action completion_action
int pcmk__scan_min_int(const char *text, int *result, int minimum)
Definition: strings.c:127
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2790
gboolean can_fail
crm_graph_t * unpack_graph(xmlNode *xml_graph, const char *reference)
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:291
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:326
unsigned int t_rcchange
Definition: lrmd.h:229
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:328
enum ocf_exitcode rc
Definition: lrmd.h:221
GHashTable * params
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:566
crm_action_timer_t * timer
const char * action
Definition: pcmk_fence.c:30
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:327
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:272
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:829
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:297
void * params
Definition: lrmd.h:240
#define crm_warn(fmt, args...)
Definition: logging.h:351
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:311
int rc
Definition: pcmk_fence.c:35
#define crm_debug(fmt, args...)
Definition: logging.h:355
#define XML_ATTR_ID
Definition: msg_xml.h:129
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_RESOURCE
Definition: msg_xml.h:214
#define crm_trace(fmt, args...)
Definition: logging.h:356
GList * inputs
GList * actions
Wrappers for and extensions to libxml2.
#define crm_log_xml_warn(xml, text)
Definition: logging.h:360
void free_xml(xmlNode *child)
Definition: xml.c:823
void destroy_graph(crm_graph_t *graph)
unsigned int t_run
Definition: lrmd.h:227
guint stonith_timeout
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:426
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Definition: lrmd_client.c:194
lrmd_event_data_t * convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc)
GHashTable * pcmk__strkey_table(GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func)
Definition: strings.c:610
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:301
#define CRM_META
Definition: crm.h:78
#define crm_err(fmt, args...)
Definition: logging.h:350
char guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:314
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:309
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:912
#define crm_log_xml_trace(xml, text)
Definition: logging.h:364
#define ID(x)
Definition: msg_xml.h:456
char * name
Definition: pcmk_fence.c:31
synapse_t * synapse