pacemaker  1.1.18-36d2962a86
Scalable High-Availability cluster resource manager
unpack.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 
21 #include <sys/param.h>
22 #include <crm/crm.h>
23 #include <crm/msg_xml.h>
24 
25 #include <crm/common/xml.h>
26 #include <crm/transition.h>
27 #include <sys/stat.h>
28 
29 CRM_TRACE_INIT_DATA(transitioner);
30 
31 static crm_action_t *
32 unpack_action(synapse_t * parent, xmlNode * xml_action)
33 {
34  crm_action_t *action = NULL;
35  const char *value = crm_element_value(xml_action, XML_ATTR_ID);
36  xmlNode *rsc_xml = NULL;
37 
38  if (value == NULL) {
39  crm_err("Actions must have an id!");
40  crm_log_xml_trace(xml_action, "Action with missing id");
41  return NULL;
42  }
43 
44  action = calloc(1, sizeof(crm_action_t));
45  if (action == NULL) {
46  crm_perror(LOG_CRIT, "Cannot unpack action");
47  crm_log_xml_trace(xml_action, "Lost action");
48  return NULL;
49  }
50 
51  action->id = crm_parse_int(value, NULL);
52  if (action->id > parent->graph->max_action_id) {
53  parent->graph->max_action_id = action->id;
54  }
55 
56  action->type = action_type_rsc;
57  action->xml = copy_xml(xml_action);
58  action->synapse = parent;
59 
60  if (safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_RSC_OP)) {
61  action->type = action_type_rsc;
62 
63  } else if (safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_PSEUDO_EVENT)) {
64  action->type = action_type_pseudo;
65 
66  } else if (safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_CRM_EVENT)) {
67  action->type = action_type_crm;
68  }
69 
70  action->params = xml2list(action->xml);
71 
72  value = g_hash_table_lookup(action->params, "CRM_meta_timeout");
73  if (value != NULL) {
74  action->timeout = crm_parse_int(value, NULL);
75  }
76 
77  /* Take start-delay into account for the timeout of the action timer */
78  value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
79  if (value != NULL) {
80  action->timeout += crm_parse_int(value, NULL);
81  }
82 
83  value = g_hash_table_lookup(action->params, "CRM_meta_interval");
84  if (value != NULL) {
85  action->interval = crm_parse_int(value, NULL);
86  }
87 
88  value = g_hash_table_lookup(action->params, "CRM_meta_can_fail");
89  if (value != NULL) {
90  crm_str_to_boolean(value, &(action->can_fail));
91  }
92 
93  crm_trace("Action %d has timer set to %dms", action->id, action->timeout);
94 
96 
97  rsc_xml = find_xml_node(action->xml, XML_CIB_TAG_RESOURCE, FALSE);
98  if (!rsc_xml) {
99  return action;
100  }
101 
102  value = crm_element_value(rsc_xml, XML_ATTR_ID_LONG);
103  if (value != NULL) {
104  g_hash_table_insert(action->params, strdup(XML_ATTR_ID_LONG), strdup(value));
105  }
106 
107  action->rsc_info = calloc(1, sizeof(lrmd_rsc_info_t));
108  action->rsc_info->id = crm_element_value_copy(rsc_xml, XML_ATTR_ID);
111  action->rsc_info->type = crm_element_value_copy(rsc_xml, XML_ATTR_TYPE);
112 
113  return action;
114 }
115 
116 static synapse_t *
117 unpack_synapse(crm_graph_t * new_graph, xmlNode * xml_synapse)
118 {
119  const char *value = NULL;
120  xmlNode *inputs = NULL;
121  xmlNode *action_set = NULL;
122  synapse_t *new_synapse = NULL;
123 
124  CRM_CHECK(xml_synapse != NULL, return NULL);
125  crm_trace("looking in synapse %s", ID(xml_synapse));
126 
127  new_synapse = calloc(1, sizeof(synapse_t));
128  new_synapse->id = crm_parse_int(ID(xml_synapse), NULL);
129 
130  value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY);
131  if (value != NULL) {
132  new_synapse->priority = crm_parse_int(value, NULL);
133  }
134 
135  CRM_CHECK(new_synapse->id >= 0, free(new_synapse);
136  return NULL);
137 
138  new_graph->num_synapses++;
139 
140  new_synapse->graph = new_graph;
141 
142  crm_trace("look for actions in synapse %s", crm_element_value(xml_synapse, XML_ATTR_ID));
143 
144  for (action_set = __xml_first_child(xml_synapse); action_set != NULL;
145  action_set = __xml_next(action_set)) {
146  if (crm_str_eq((const char *)action_set->name, "action_set", TRUE)) {
147  xmlNode *action = NULL;
148 
149  for (action = __xml_first_child(action_set); action != NULL;
150  action = __xml_next(action)) {
151  crm_action_t *new_action = unpack_action(new_synapse, action);
152 
153  if (new_action == NULL) {
154  continue;
155  }
156 
157  new_graph->num_actions++;
158 
159  crm_trace("Adding action %d to synapse %d", new_action->id, new_synapse->id);
160 
161  new_synapse->actions = g_list_append(new_synapse->actions, new_action);
162  }
163  }
164  }
165 
166  crm_trace("look for inputs in synapse %s", ID(xml_synapse));
167 
168  for (inputs = __xml_first_child(xml_synapse); inputs != NULL; inputs = __xml_next(inputs)) {
169  if (crm_str_eq((const char *)inputs->name, "inputs", TRUE)) {
170  xmlNode *trigger = NULL;
171 
172  for (trigger = __xml_first_child(inputs); trigger != NULL;
173  trigger = __xml_next(trigger)) {
174  xmlNode *input = NULL;
175 
176  for (input = __xml_first_child(trigger); input != NULL; input = __xml_next(input)) {
177  crm_action_t *new_input = unpack_action(new_synapse, input);
178 
179  if (new_input == NULL) {
180  continue;
181  }
182 
183  crm_trace("Adding input %d to synapse %d", new_input->id, new_synapse->id);
184 
185  new_synapse->inputs = g_list_append(new_synapse->inputs, new_input);
186  }
187  }
188  }
189  }
190 
191  return new_synapse;
192 }
193 
194 static void destroy_action(crm_action_t * action);
195 
196 crm_graph_t *
197 unpack_graph(xmlNode * xml_graph, const char *reference)
198 {
199 /*
200  <transition_graph>
201  <synapse>
202  <action_set>
203  <rsc_op id="2"
204  ...
205  <inputs>
206  <rsc_op id="2"
207  ...
208 */
209  crm_graph_t *new_graph = NULL;
210  const char *t_id = NULL;
211  const char *time = NULL;
212  xmlNode *synapse = NULL;
213 
214  new_graph = calloc(1, sizeof(crm_graph_t));
215 
216  new_graph->id = -1;
217  new_graph->abort_priority = 0;
218  new_graph->network_delay = -1;
219  new_graph->transition_timeout = -1;
220  new_graph->stonith_timeout = -1;
221  new_graph->completion_action = tg_done;
222  new_graph->max_action_id = 0;
223 
224  if (reference) {
225  new_graph->source = strdup(reference);
226  } else {
227  new_graph->source = strdup("unknown");
228  }
229 
230  if (xml_graph != NULL) {
231  t_id = crm_element_value(xml_graph, "transition_id");
232  CRM_CHECK(t_id != NULL, free(new_graph);
233  return NULL);
234  new_graph->id = crm_parse_int(t_id, "-1");
235 
236  time = crm_element_value(xml_graph, "cluster-delay");
237  CRM_CHECK(time != NULL, free(new_graph);
238  return NULL);
239  new_graph->network_delay = crm_get_msec(time);
240 
241  time = crm_element_value(xml_graph, "stonith-timeout");
242  if (time == NULL) {
243  new_graph->stonith_timeout = new_graph->network_delay;
244  } else {
245  new_graph->stonith_timeout = crm_get_msec(time);
246  }
247 
248  t_id = crm_element_value(xml_graph, "batch-limit");
249  new_graph->batch_limit = crm_parse_int(t_id, "0");
250 
251  t_id = crm_element_value(xml_graph, "migration-limit");
252  new_graph->migration_limit = crm_parse_int(t_id, "-1");
253  }
254 
255  for (synapse = __xml_first_child(xml_graph); synapse != NULL; synapse = __xml_next(synapse)) {
256  if (crm_str_eq((const char *)synapse->name, "synapse", TRUE)) {
257  synapse_t *new_synapse = unpack_synapse(new_graph, synapse);
258 
259  if (new_synapse != NULL) {
260  new_graph->synapses = g_list_append(new_graph->synapses, new_synapse);
261  }
262  }
263  }
264 
265  crm_debug("Unpacked transition %d: %d actions in %d synapses",
266  new_graph->id, new_graph->num_actions, new_graph->num_synapses);
267 
268  return new_graph;
269 }
270 
271 static void
272 destroy_action(crm_action_t * action)
273 {
274  if (action->timer && action->timer->source_id != 0) {
275  crm_warn("Cancelling timer for action %d (src=%d)", action->id, action->timer->source_id);
276  g_source_remove(action->timer->source_id);
277  }
278  if (action->params) {
279  g_hash_table_destroy(action->params);
280  }
281  free_xml(action->xml);
282  free(action->timer);
283  free(action->task);
284  lrmd_free_rsc_info(action->rsc_info);
285  free(action);
286 }
287 
288 static void
289 destroy_synapse(synapse_t * synapse)
290 {
291  while (g_list_length(synapse->actions) > 0) {
292  crm_action_t *action = g_list_nth_data(synapse->actions, 0);
293 
294  synapse->actions = g_list_remove(synapse->actions, action);
295  destroy_action(action);
296  }
297 
298  while (g_list_length(synapse->inputs) > 0) {
299  crm_action_t *action = g_list_nth_data(synapse->inputs, 0);
300 
301  synapse->inputs = g_list_remove(synapse->inputs, action);
302  destroy_action(action);
303  }
304  free(synapse);
305 }
306 
307 void
309 {
310  if (graph == NULL) {
311  return;
312  }
313  while (g_list_length(graph->synapses) > 0) {
314  synapse_t *synapse = g_list_nth_data(graph->synapses, 0);
315 
316  graph->synapses = g_list_remove(graph->synapses, synapse);
317  destroy_synapse(synapse);
318  }
319 
320  free(graph->source);
321  free(graph);
322 }
323 
325 convert_graph_action(xmlNode * resource, crm_action_t * action, int status, int rc)
326 {
327  xmlNode *xop = NULL;
328  lrmd_event_data_t *op = NULL;
329  GHashTableIter iter;
330  const char *name = NULL;
331  const char *value = NULL;
332  xmlNode *action_resource = NULL;
333 
334  CRM_CHECK(action != NULL, return NULL);
335  CRM_CHECK(action->type == action_type_rsc, return NULL);
336 
337  action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
338  CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "Bad");
339  return NULL);
340 
341  op = calloc(1, sizeof(lrmd_event_data_t));
342 
343  op->rsc_id = strdup(ID(action_resource));
344  op->interval = action->interval;
345  op->op_type = strdup(action->task);
346 
347  op->rc = rc;
348  op->op_status = status;
349  op->t_run = time(NULL);
350  op->t_rcchange = op->t_run;
351 
352  op->params = g_hash_table_new_full(crm_str_hash, g_str_equal,
354 
355  g_hash_table_iter_init(&iter, action->params);
356  while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
357  if (safe_str_eq(name, XML_ATTR_ID_LONG)) {
358  continue;
359  }
360 
361  g_hash_table_insert(op->params, strdup(name), strdup(value));
362  }
363 
364  for (xop = __xml_first_child(resource); xop != NULL; xop = __xml_next(xop)) {
365  int tmp = 0;
366 
368  crm_debug("Got call_id=%d for %s", tmp, ID(resource));
369  if (tmp > op->call_id) {
370  op->call_id = tmp;
371  }
372  }
373 
374  op->call_id++;
375  return op;
376 }
#define XML_ATTR_ID_LONG
Definition: msg_xml.h:104
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:164
GListPtr actions
Definition: transition.h:43
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition: xml.c:2235
A dumping ground.
GHashTable * xml2list(xmlNode *parent)
Definition: xml.c:4931
action_type_e type
Definition: transition.h:54
enum transition_action completion_action
Definition: transition.h:105
lrmd_rsc_info_t * rsc_info
Definition: transition.h:70
const char * rsc_id
Definition: lrmd.h:209
xmlNode * xml
Definition: transition.h:66
char * class
Definition: lrmd.h:263
#define XML_ATTR_TYPE
Definition: msg_xml.h:105
long long crm_get_msec(const char *input)
Definition: utils.c:598
gboolean can_fail
Definition: transition.h:64
char * id
Definition: lrmd.h:261
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:313
int crm_parse_int(const char *text, const char *default_text)
Definition: strings.c:125
char * crm_element_value_copy(xmlNode *data, const char *name)
Definition: xml.c:3869
unsigned int t_rcchange
Definition: lrmd.h:235
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:315
int num_synapses
Definition: transition.h:108
enum ocf_exitcode rc
Definition: lrmd.h:227
GHashTable * params
Definition: transition.h:53
crm_action_timer_t * timer
Definition: transition.h:56
int transition_timeout
Definition: transition.h:113
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:314
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:264
crm_graph_t * graph
Definition: transition.h:46
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2712
int priority
Definition: transition.h:36
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:284
char * task
Definition: transition.h:68
void * params
Definition: lrmd.h:246
#define crm_warn(fmt, args...)
Definition: logging.h:249
#define crm_debug(fmt, args...)
Definition: logging.h:253
#define XML_ATTR_ID
Definition: msg_xml.h:102
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:195
#define crm_trace(fmt, args...)
Definition: logging.h:254
#define XML_AGENT_ATTR_PROVIDER
Definition: msg_xml.h:254
Wrappers for and extensions to libxml2.
#define crm_log_xml_warn(xml, text)
Definition: logging.h:258
int crm_element_value_int(xmlNode *data, const char *name, int *dest)
Definition: xml.c:3844
const char * crm_element_value(xmlNode *data, const char *name)
Definition: xml.c:5165
GListPtr synapses
Definition: transition.h:121
crm_graph_t * unpack_graph(xmlNode *xml_graph, const char *reference)
Definition: unpack.c:197
void free_xml(xmlNode *child)
Definition: xml.c:2706
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:213
int stonith_timeout
Definition: transition.h:112
const char * op_type
Definition: lrmd.h:211
int batch_limit
Definition: transition.h:110
unsigned int t_run
Definition: lrmd.h:233
GListPtr inputs
Definition: transition.h:44
char * source
Definition: transition.h:100
int network_delay
Definition: transition.h:111
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:176
char * type
Definition: lrmd.h:262
int num_actions
Definition: transition.h:107
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:226
int migration_limit
Definition: transition.h:123
#define crm_err(fmt, args...)
Definition: logging.h:248
int abort_priority
Definition: transition.h:101
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:296
#define crm_str_hash
Definition: util.h:73
int source_id
Definition: transition.h:84
char * provider
Definition: lrmd.h:264
int max_action_id
Definition: transition.h:125
xmlNode * first_named_child(xmlNode *parent, const char *name)
Definition: xml.c:5053
#define crm_log_xml_trace(xml, text)
Definition: logging.h:262
void lrmd_free_rsc_info(lrmd_rsc_info_t *rsc_info)
Definition: lrmd_client.c:1487
CRM_TRACE_INIT_DATA(pe_status)
#define ID(x)
Definition: msg_xml.h:446
#define safe_str_eq(a, b)
Definition: util.h:72
void destroy_graph(crm_graph_t *graph)
Definition: unpack.c:308
void g_hash_destroy_str(gpointer data)
Definition: strings.c:74
synapse_t * synapse
Definition: transition.h:57
lrmd_event_data_t * convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc)
Definition: unpack.c:325
#define XML_AGENT_ATTR_CLASS
Definition: msg_xml.h:253