pacemaker  2.0.3-4b1f869f0f
Scalable High-Availability cluster resource manager
pcmk_trans_unpack.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2019 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>
18 #include <pacemaker-internal.h>
19 
20 CRM_TRACE_INIT_DATA(transitioner);
21 
22 static crm_action_t *
23 unpack_action(synapse_t * parent, xmlNode * xml_action)
24 {
25  crm_action_t *action = NULL;
26  const char *value = crm_element_value(xml_action, XML_ATTR_ID);
27 
28  if (value == NULL) {
29  crm_err("Actions must have an id!");
30  crm_log_xml_trace(xml_action, "Action with missing id");
31  return NULL;
32  }
33 
34  action = calloc(1, sizeof(crm_action_t));
35  if (action == NULL) {
36  crm_perror(LOG_CRIT, "Cannot unpack action");
37  crm_log_xml_trace(xml_action, "Lost action");
38  return NULL;
39  }
40 
41  action->id = crm_parse_int(value, NULL);
42  action->type = action_type_rsc;
43  action->xml = copy_xml(xml_action);
44  action->synapse = parent;
45 
46  if (safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_RSC_OP)) {
47  action->type = action_type_rsc;
48 
49  } else if (safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_PSEUDO_EVENT)) {
50  action->type = action_type_pseudo;
51 
52  } else if (safe_str_eq(crm_element_name(action->xml), XML_GRAPH_TAG_CRM_EVENT)) {
53  action->type = action_type_crm;
54  }
55 
56  action->params = xml2list(action->xml);
57 
58  value = g_hash_table_lookup(action->params, "CRM_meta_timeout");
59  if (value != NULL) {
60  action->timeout = crm_parse_int(value, NULL);
61  }
62 
63  /* Take start-delay into account for the timeout of the action timer */
64  value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
65  if (value != NULL) {
66  action->timeout += crm_parse_int(value, NULL);
67  }
68 
69  value = g_hash_table_lookup(action->params, "CRM_meta_interval");
70  if (value != NULL) {
71  action->interval_ms = crm_parse_ms(value);
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 = __xml_first_child(xml_synapse); action_set != NULL;
111  action_set = __xml_next(action_set)) {
112  if (crm_str_eq((const char *)action_set->name, "action_set", TRUE)) {
113  xmlNode *action = NULL;
114 
115  for (action = __xml_first_child(action_set); action != NULL;
116  action = __xml_next(action)) {
117  crm_action_t *new_action = unpack_action(new_synapse, action);
118 
119  if (new_action == NULL) {
120  continue;
121  }
122 
123  new_graph->num_actions++;
124 
125  crm_trace("Adding action %d to synapse %d", new_action->id, new_synapse->id);
126 
127  new_synapse->actions = g_list_append(new_synapse->actions, new_action);
128  }
129  }
130  }
131 
132  crm_trace("look for inputs in synapse %s", ID(xml_synapse));
133 
134  for (inputs = __xml_first_child(xml_synapse); inputs != NULL; inputs = __xml_next(inputs)) {
135  if (crm_str_eq((const char *)inputs->name, "inputs", TRUE)) {
136  xmlNode *trigger = NULL;
137 
138  for (trigger = __xml_first_child(inputs); trigger != NULL;
139  trigger = __xml_next(trigger)) {
140  xmlNode *input = NULL;
141 
142  for (input = __xml_first_child(trigger); input != NULL; input = __xml_next(input)) {
143  crm_action_t *new_input = unpack_action(new_synapse, input);
144 
145  if (new_input == NULL) {
146  continue;
147  }
148 
149  crm_trace("Adding input %d to synapse %d", new_input->id, new_synapse->id);
150 
151  new_synapse->inputs = g_list_append(new_synapse->inputs, new_input);
152  }
153  }
154  }
155  }
156 
157  return new_synapse;
158 }
159 
160 static void destroy_action(crm_action_t * action);
161 
162 crm_graph_t *
163 unpack_graph(xmlNode * xml_graph, const char *reference)
164 {
165 /*
166  <transition_graph>
167  <synapse>
168  <action_set>
169  <rsc_op id="2"
170  ...
171  <inputs>
172  <rsc_op id="2"
173  ...
174 */
175  crm_graph_t *new_graph = NULL;
176  const char *t_id = NULL;
177  const char *time = NULL;
178  xmlNode *synapse = NULL;
179 
180  new_graph = calloc(1, sizeof(crm_graph_t));
181 
182  new_graph->id = -1;
183  new_graph->abort_priority = 0;
184  new_graph->network_delay = 0;
185  new_graph->stonith_timeout = 0;
186  new_graph->completion_action = tg_done;
187 
188  if (reference) {
189  new_graph->source = strdup(reference);
190  } else {
191  new_graph->source = strdup("unknown");
192  }
193 
194  if (xml_graph != NULL) {
195  t_id = crm_element_value(xml_graph, "transition_id");
196  CRM_CHECK(t_id != NULL, free(new_graph);
197  return NULL);
198  new_graph->id = crm_parse_int(t_id, "-1");
199 
200  time = crm_element_value(xml_graph, "cluster-delay");
201  CRM_CHECK(time != NULL, free(new_graph);
202  return NULL);
203  new_graph->network_delay = crm_parse_interval_spec(time);
204 
205  time = crm_element_value(xml_graph, "stonith-timeout");
206  if (time == NULL) {
207  new_graph->stonith_timeout = new_graph->network_delay;
208  } else {
209  new_graph->stonith_timeout = crm_parse_interval_spec(time);
210  }
211 
212  t_id = crm_element_value(xml_graph, "batch-limit");
213  new_graph->batch_limit = crm_parse_int(t_id, "0");
214 
215  t_id = crm_element_value(xml_graph, "migration-limit");
216  new_graph->migration_limit = crm_parse_int(t_id, "-1");
217  }
218 
219  for (synapse = __xml_first_child(xml_graph); synapse != NULL; synapse = __xml_next(synapse)) {
220  if (crm_str_eq((const char *)synapse->name, "synapse", TRUE)) {
221  synapse_t *new_synapse = unpack_synapse(new_graph, synapse);
222 
223  if (new_synapse != NULL) {
224  new_graph->synapses = g_list_append(new_graph->synapses, new_synapse);
225  }
226  }
227  }
228 
229  crm_debug("Unpacked transition %d: %d actions in %d synapses",
230  new_graph->id, new_graph->num_actions, new_graph->num_synapses);
231 
232  return new_graph;
233 }
234 
235 static void
236 destroy_action(crm_action_t * action)
237 {
238  if (action->timer && action->timer->source_id != 0) {
239  crm_warn("Cancelling timer for action %d (src=%d)", action->id, action->timer->source_id);
240  g_source_remove(action->timer->source_id);
241  }
242  if (action->params) {
243  g_hash_table_destroy(action->params);
244  }
245  free_xml(action->xml);
246  free(action->timer);
247  free(action);
248 }
249 
250 static void
251 destroy_synapse(synapse_t * synapse)
252 {
253  while (g_list_length(synapse->actions) > 0) {
254  crm_action_t *action = g_list_nth_data(synapse->actions, 0);
255 
256  synapse->actions = g_list_remove(synapse->actions, action);
257  destroy_action(action);
258  }
259 
260  while (g_list_length(synapse->inputs) > 0) {
261  crm_action_t *action = g_list_nth_data(synapse->inputs, 0);
262 
263  synapse->inputs = g_list_remove(synapse->inputs, action);
264  destroy_action(action);
265  }
266  free(synapse);
267 }
268 
269 void
271 {
272  if (graph == NULL) {
273  return;
274  }
275  while (g_list_length(graph->synapses) > 0) {
276  synapse_t *synapse = g_list_nth_data(graph->synapses, 0);
277 
278  graph->synapses = g_list_remove(graph->synapses, synapse);
279  destroy_synapse(synapse);
280  }
281 
282  free(graph->source);
283  free(graph);
284 }
285 
287 convert_graph_action(xmlNode * resource, crm_action_t * action, int status, int rc)
288 {
289  xmlNode *xop = NULL;
290  lrmd_event_data_t *op = NULL;
291  GHashTableIter iter;
292  const char *name = NULL;
293  const char *value = NULL;
294  xmlNode *action_resource = NULL;
295 
296  CRM_CHECK(action != NULL, return NULL);
297  CRM_CHECK(action->type == action_type_rsc, return NULL);
298 
299  action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
300  CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "Bad");
301  return NULL);
302 
303  op = calloc(1, sizeof(lrmd_event_data_t));
304 
305  op->rsc_id = strdup(ID(action_resource));
306  op->interval_ms = action->interval_ms;
307  op->op_type = strdup(crm_element_value(action->xml, XML_LRM_ATTR_TASK));
308 
309  op->rc = rc;
310  op->op_status = status;
311  op->t_run = time(NULL);
312  op->t_rcchange = op->t_run;
313 
314  op->params = g_hash_table_new_full(crm_str_hash, g_str_equal, free, free);
315 
316  g_hash_table_iter_init(&iter, action->params);
317  while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
318  g_hash_table_insert(op->params, strdup(name), strdup(value));
319  }
320 
321  for (xop = __xml_first_child(resource); xop != NULL; xop = __xml_next(xop)) {
322  int tmp = 0;
323 
325  crm_debug("Got call_id=%d for %s", tmp, ID(resource));
326  if (tmp > op->call_id) {
327  op->call_id = tmp;
328  }
329  }
330 
331  op->call_id++;
332  return op;
333 }
crm_graph_s::source
char * source
Definition: pcmki_transition.h:81
crm_action_s::synapse
synapse_t * synapse
Definition: pcmki_transition.h:52
crm_str_eq
gboolean crm_str_eq(const char *a, const char *b, gboolean use_case)
Definition: strings.c:224
pacemaker-internal.h
msg_xml.h
crm_graph_s::batch_limit
int batch_limit
Definition: pcmki_transition.h:91
crm_action_s
Definition: pcmki_transition.h:44
XML_GRAPH_TAG_CRM_EVENT
#define XML_GRAPH_TAG_CRM_EVENT
Definition: msg_xml.h:291
crm_element_value_int
int crm_element_value_int(const xmlNode *data, const char *name, int *dest)
Retrieve the integer value of an XML attribute.
Definition: nvpair.c:555
crm_str_to_boolean
int crm_str_to_boolean(const char *s, int *ret)
Definition: strings.c:187
CRM_TRACE_INIT_DATA
CRM_TRACE_INIT_DATA(transitioner)
crm_action_s::id
int id
Definition: pcmki_transition.h:45
lrmd_event_data_s::rc
enum ocf_exitcode rc
Definition: lrmd.h:221
crm_graph_s::id
int id
Definition: pcmki_transition.h:80
CRM_CHECK
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:157
copy_xml
xmlNode * copy_xml(xmlNode *src_node)
Definition: xml.c:2136
crm_parse_ms
guint crm_parse_ms(const char *text)
Definition: strings.c:147
synapse_s
Definition: pcmki_transition.h:31
synapse_s::id
int id
Definition: pcmki_transition.h:32
crm_err
#define crm_err(fmt, args...)
Definition: logging.h:241
crm_str_hash
#define crm_str_hash
Definition: util.h:62
crm_trace
#define crm_trace(fmt, args...)
Definition: logging.h:247
safe_str_eq
#define safe_str_eq(a, b)
Definition: util.h:61
crm_warn
#define crm_warn(fmt, args...)
Definition: logging.h:242
free_xml
void free_xml(xmlNode *child)
Definition: xml.c:2130
crm_graph_s::synapses
GListPtr synapses
Definition: pcmki_transition.h:101
XML_CIB_ATTR_PRIORITY
#define XML_CIB_ATTR_PRIORITY
Definition: msg_xml.h:235
crm_graph_s::num_synapses
int num_synapses
Definition: pcmki_transition.h:89
tg_done
@ tg_done
Definition: pcmki_transition.h:73
lrmd_event_data_s::call_id
int call_id
Definition: lrmd.h:210
xml.h
Wrappers for and extensions to libxml2.
action_type_pseudo
@ action_type_pseudo
Definition: pcmki_transition.h:23
lrmd_event_data_s::t_run
unsigned int t_run
Definition: lrmd.h:227
crm_action_s::xml
xmlNode * xml
Definition: pcmki_transition.h:61
crm_graph_s::num_actions
int num_actions
Definition: pcmki_transition.h:88
crm_action_s::type
action_type_e type
Definition: pcmki_transition.h:49
XML_ATTR_ID
#define XML_ATTR_ID
Definition: msg_xml.h:96
ID
#define ID(x)
Definition: msg_xml.h:415
XML_CIB_TAG_RESOURCE
#define XML_CIB_TAG_RESOURCE
Definition: msg_xml.h:174
first_named_child
xmlNode * first_named_child(const xmlNode *parent, const char *name)
Definition: xml.c:4384
synapse_s::priority
int priority
Definition: pcmki_transition.h:33
crm_action_s::timeout
int timeout
Definition: pcmki_transition.h:46
crm_graph_s::network_delay
guint network_delay
Definition: pcmki_transition.h:92
lrmd_event_data_s::rsc_id
const char * rsc_id
Definition: lrmd.h:203
convert_graph_action
lrmd_event_data_t * convert_graph_action(xmlNode *resource, crm_action_t *action, int status, int rc)
Definition: pcmk_trans_unpack.c:287
crm_graph_s::completion_action
enum transition_action completion_action
Definition: pcmki_transition.h:86
lrmd_event_data_s::t_rcchange
unsigned int t_rcchange
Definition: lrmd.h:229
XML_LRM_ATTR_TASK
#define XML_LRM_ATTR_TASK
Definition: msg_xml.h:260
lrmd_event_data_s
Definition: lrmd.h:198
te_timer_s::source_id
int source_id
Definition: pcmki_transition.h:66
unpack_graph
crm_graph_t * unpack_graph(xmlNode *xml_graph, const char *reference)
Definition: pcmk_trans_unpack.c:163
lrmd_event_data_s::op_type
const char * op_type
Definition: lrmd.h:205
crm_debug
#define crm_debug(fmt, args...)
Definition: logging.h:246
crm_graph_s::abort_priority
int abort_priority
Definition: pcmki_transition.h:82
lrmd_event_data_s::op_status
int op_status
Definition: lrmd.h:223
crm_log_xml_trace
#define crm_log_xml_trace(xml, text)
Definition: logging.h:255
crm_element_value
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition: nvpair.c:519
crm_log_xml_warn
#define crm_log_xml_warn(xml, text)
Definition: logging.h:251
lrmd_event_data_s::params
void * params
Definition: lrmd.h:240
crm_action_s::timer
crm_action_timer_t * timer
Definition: pcmki_transition.h:51
crm_action_s::params
GHashTable * params
Definition: pcmki_transition.h:48
crm_parse_int
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
Definition: strings.c:114
crm_perror
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:219
crm_graph_s::migration_limit
int migration_limit
Definition: pcmki_transition.h:103
crm_parse_interval_spec
guint crm_parse_interval_spec(const char *input)
Definition: utils.c:542
crm_action_s::interval_ms
guint interval_ms
Definition: pcmki_transition.h:47
XML_GRAPH_TAG_RSC_OP
#define XML_GRAPH_TAG_RSC_OP
Definition: msg_xml.h:289
lrmd_event_data_s::interval_ms
guint interval_ms
Definition: lrmd.h:214
synapse_s::inputs
GListPtr inputs
Definition: pcmki_transition.h:41
crm_action_s::can_fail
gboolean can_fail
Definition: pcmki_transition.h:59
action_type_rsc
@ action_type_rsc
Definition: pcmki_transition.h:24
destroy_graph
void destroy_graph(crm_graph_t *graph)
Definition: pcmk_trans_unpack.c:270
XML_GRAPH_TAG_PSEUDO_EVENT
#define XML_GRAPH_TAG_PSEUDO_EVENT
Definition: msg_xml.h:290
XML_LRM_ATTR_CALLID
#define XML_LRM_ATTR_CALLID
Definition: msg_xml.h:272
crm_internal.h
crm.h
A dumping ground.
xml2list
GHashTable * xml2list(xmlNode *parent)
Retrieve XML attributes as a hash table.
Definition: nvpair.c:894
synapse_s::actions
GListPtr actions
Definition: pcmki_transition.h:40
crm_graph_s::stonith_timeout
guint stonith_timeout
Definition: pcmki_transition.h:93
action_type_crm
@ action_type_crm
Definition: pcmki_transition.h:25
crm_graph_s
Definition: pcmki_transition.h:79