pacemaker  2.0.5-ba59be712
Scalable High-Availability cluster resource manager
pcmk_trans_unpack.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2020 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  action->id = crm_parse_int(value, NULL);
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  if (value != NULL) {
59  action->timeout = crm_parse_int(value, NULL);
60  }
61 
62  /* Take start-delay into account for the timeout of the action timer */
63  value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
64  if (value != NULL) {
65  action->timeout += crm_parse_int(value, NULL);
66  }
67 
68  if (pcmk__guint_from_hash(action->params,
70  &(action->interval_ms)) != pcmk_rc_ok) {
71  action->interval_ms = 0;
72  }
73 
74  value = g_hash_table_lookup(action->params, "CRM_meta_can_fail");
75  if (value != NULL) {
76  crm_str_to_boolean(value, &(action->can_fail));
77  }
78 
79  crm_trace("Action %d has timer set to %dms", action->id, action->timeout);
80 
81  return action;
82 }
83 
84 static synapse_t *
85 unpack_synapse(crm_graph_t * new_graph, xmlNode * xml_synapse)
86 {
87  const char *value = NULL;
88  xmlNode *inputs = NULL;
89  xmlNode *action_set = NULL;
90  synapse_t *new_synapse = NULL;
91 
92  CRM_CHECK(xml_synapse != NULL, return NULL);
93  crm_trace("looking in synapse %s", ID(xml_synapse));
94 
95  new_synapse = calloc(1, sizeof(synapse_t));
96  new_synapse->id = crm_parse_int(ID(xml_synapse), NULL);
97 
98  value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY);
99  if (value != NULL) {
100  new_synapse->priority = crm_parse_int(value, NULL);
101  }
102 
103  CRM_CHECK(new_synapse->id >= 0, free(new_synapse);
104  return NULL);
105 
106  new_graph->num_synapses++;
107 
108  crm_trace("look for actions in synapse %s", crm_element_value(xml_synapse, XML_ATTR_ID));
109 
110  for (action_set = pcmk__xml_first_child(xml_synapse); action_set != NULL;
111  action_set = pcmk__xml_next(action_set)) {
112 
113  if (pcmk__str_eq((const char *)action_set->name, "action_set",
114  pcmk__str_none)) {
115  xmlNode *action = NULL;
116 
117  for (action = pcmk__xml_first_child(action_set); action != NULL;
118  action = pcmk__xml_next(action)) {
119  crm_action_t *new_action = unpack_action(new_synapse, action);
120 
121  if (new_action == NULL) {
122  continue;
123  }
124 
125  new_graph->num_actions++;
126 
127  crm_trace("Adding action %d to synapse %d", new_action->id, new_synapse->id);
128 
129  new_synapse->actions = g_list_append(new_synapse->actions, new_action);
130  }
131  }
132  }
133 
134  crm_trace("look for inputs in synapse %s", ID(xml_synapse));
135 
136  for (inputs = pcmk__xml_first_child(xml_synapse); inputs != NULL;
137  inputs = pcmk__xml_next(inputs)) {
138 
139  if (pcmk__str_eq((const char *)inputs->name, "inputs", pcmk__str_none)) {
140  xmlNode *trigger = NULL;
141 
142  for (trigger = pcmk__xml_first_child(inputs); trigger != NULL;
143  trigger = pcmk__xml_next(trigger)) {
144  xmlNode *input = NULL;
145 
146  for (input = pcmk__xml_first_child(trigger); input != NULL;
147  input = pcmk__xml_next(input)) {
148  crm_action_t *new_input = unpack_action(new_synapse, input);
149 
150  if (new_input == NULL) {
151  continue;
152  }
153 
154  crm_trace("Adding input %d to synapse %d", new_input->id, new_synapse->id);
155 
156  new_synapse->inputs = g_list_append(new_synapse->inputs, new_input);
157  }
158  }
159  }
160  }
161 
162  return new_synapse;
163 }
164 
165 static void destroy_action(crm_action_t * action);
166 
167 crm_graph_t *
168 unpack_graph(xmlNode * xml_graph, const char *reference)
169 {
170 /*
171  <transition_graph>
172  <synapse>
173  <action_set>
174  <rsc_op id="2"
175  ...
176  <inputs>
177  <rsc_op id="2"
178  ...
179 */
180  crm_graph_t *new_graph = NULL;
181  const char *t_id = NULL;
182  const char *time = NULL;
183  xmlNode *synapse = NULL;
184 
185  new_graph = calloc(1, sizeof(crm_graph_t));
186 
187  new_graph->id = -1;
188  new_graph->abort_priority = 0;
189  new_graph->network_delay = 0;
190  new_graph->stonith_timeout = 0;
191  new_graph->completion_action = tg_done;
192 
193  if (reference) {
194  new_graph->source = strdup(reference);
195  } else {
196  new_graph->source = strdup("unknown");
197  }
198 
199  if (xml_graph != NULL) {
200  t_id = crm_element_value(xml_graph, "transition_id");
201  CRM_CHECK(t_id != NULL, free(new_graph);
202  return NULL);
203  new_graph->id = crm_parse_int(t_id, "-1");
204 
205  time = crm_element_value(xml_graph, "cluster-delay");
206  CRM_CHECK(time != NULL, free(new_graph);
207  return NULL);
208  new_graph->network_delay = crm_parse_interval_spec(time);
209 
210  time = crm_element_value(xml_graph, "stonith-timeout");
211  if (time == NULL) {
212  new_graph->stonith_timeout = new_graph->network_delay;
213  } else {
214  new_graph->stonith_timeout = crm_parse_interval_spec(time);
215  }
216 
217  t_id = crm_element_value(xml_graph, "batch-limit");
218  new_graph->batch_limit = crm_parse_int(t_id, "0");
219 
220  t_id = crm_element_value(xml_graph, "migration-limit");
221  new_graph->migration_limit = crm_parse_int(t_id, "-1");
222  }
223 
224  for (synapse = pcmk__xml_first_child(xml_graph); synapse != NULL;
225  synapse = pcmk__xml_next(synapse)) {
226 
227  if (pcmk__str_eq((const char *)synapse->name, "synapse", pcmk__str_none)) {
228  synapse_t *new_synapse = unpack_synapse(new_graph, synapse);
229 
230  if (new_synapse != NULL) {
231  new_graph->synapses = g_list_append(new_graph->synapses, new_synapse);
232  }
233  }
234  }
235 
236  crm_debug("Unpacked transition %d: %d actions in %d synapses",
237  new_graph->id, new_graph->num_actions, new_graph->num_synapses);
238 
239  return new_graph;
240 }
241 
242 static void
243 destroy_action(crm_action_t * action)
244 {
245  if (action->timer && action->timer->source_id != 0) {
246  crm_warn("Cancelling timer for action %d (src=%d)", action->id, action->timer->source_id);
247  g_source_remove(action->timer->source_id);
248  }
249  if (action->params) {
250  g_hash_table_destroy(action->params);
251  }
252  free_xml(action->xml);
253  free(action->timer);
254  free(action);
255 }
256 
257 static void
258 destroy_synapse(synapse_t * synapse)
259 {
260  while (synapse->actions != NULL) {
261  crm_action_t *action = g_list_nth_data(synapse->actions, 0);
262 
263  synapse->actions = g_list_remove(synapse->actions, action);
264  destroy_action(action);
265  }
266 
267  while (synapse->inputs != NULL) {
268  crm_action_t *action = g_list_nth_data(synapse->inputs, 0);
269 
270  synapse->inputs = g_list_remove(synapse->inputs, action);
271  destroy_action(action);
272  }
273  free(synapse);
274 }
275 
276 void
278 {
279  if (graph == NULL) {
280  return;
281  }
282  while (graph->synapses != NULL) {
283  synapse_t *synapse = g_list_nth_data(graph->synapses, 0);
284 
285  graph->synapses = g_list_remove(graph->synapses, synapse);
286  destroy_synapse(synapse);
287  }
288 
289  free(graph->source);
290  free(graph);
291 }
292 
294 convert_graph_action(xmlNode * resource, crm_action_t * action, int status, int rc)
295 {
296  xmlNode *xop = NULL;
297  lrmd_event_data_t *op = NULL;
298  GHashTableIter iter;
299  const char *name = NULL;
300  const char *value = NULL;
301  xmlNode *action_resource = NULL;
302 
303  CRM_CHECK(action != NULL, return NULL);
304  CRM_CHECK(action->type == action_type_rsc, return NULL);
305 
306  action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
307  CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "Bad");
308  return NULL);
309 
310  op = lrmd_new_event(ID(action_resource),
312  action->interval_ms);
313  op->rc = rc;
314  op->op_status = status;
315  op->t_run = time(NULL);
316  op->t_rcchange = op->t_run;
317 
318  op->params = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
319 
320  g_hash_table_iter_init(&iter, action->params);
321  while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
322  g_hash_table_insert(op->params, strdup(name), strdup(value));
323  }
324 
325  for (xop = pcmk__xml_first_child(resource); xop != NULL;
326  xop = pcmk__xml_next(xop)) {
327  int tmp = 0;
328 
330  crm_debug("Got call_id=%d for %s", tmp, ID(resource));
331  if (tmp > op->call_id) {
332  op->call_id = tmp;
333  }
334  }
335 
336  op->call_id++;
337  return op;
338 }
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:215
GListPtr actions
A dumping ground.
enum transition_action completion_action
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:2777
#define XML_LRM_ATTR_INTERVAL
Definition: msg_xml.h:261
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:296
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:134
unsigned int t_rcchange
Definition: lrmd.h:229
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:298
guint crm_parse_interval_spec(const char *input)
Parse milliseconds from a Pacemaker interval specification.
Definition: utils.c:307
enum ocf_exitcode rc
Definition: lrmd.h:221
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:559
const char * action
Definition: pcmk_fence.c:30
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:297
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:242
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:796
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:267
void * params
Definition: lrmd.h:240
#define crm_warn(fmt, args...)
Definition: logging.h:348
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition: strings.c:290
int rc
Definition: pcmk_fence.c:35
#define crm_debug(fmt, args...)
Definition: logging.h:352
#define XML_ATTR_ID
Definition: msg_xml.h:96
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:523
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:181
lrmd_event_data_t * convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc)
#define crm_trace(fmt, args...)
Definition: logging.h:353
crm_graph_t * unpack_graph(xmlNode *xml_graph, const char *reference)
Wrappers for and extensions to libxml2.
#define crm_log_xml_warn(xml, text)
Definition: logging.h:357
GListPtr synapses
void free_xml(xmlNode *child)
Definition: xml.c:790
unsigned int t_run
Definition: lrmd.h:227
GListPtr inputs
guint stonith_timeout
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:403
lrmd_event_data_t * lrmd_new_event(const char *rsc_id, const char *task, guint interval_ms)
Definition: lrmd_client.c:194
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:298
#define CRM_META
Definition: crm.h:71
#define crm_err(fmt, args...)
Definition: logging.h:347
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:279
#define crm_str_hash
Definition: util.h:62
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:911
#define crm_log_xml_trace(xml, text)
Definition: logging.h:361
void destroy_graph(crm_graph_t *graph)
#define ID(x)
Definition: msg_xml.h:425
char * name
Definition: pcmk_fence.c:31