This source file includes following definitions.
- update_synapse_ready
- update_synapse_confirmed
- pcmk__update_graph
- pcmk__set_graph_functions
- should_fire_synapse
- initiate_action
- fire_synapse
- pseudo_action_dummy
- pcmk__execute_graph
- unpack_action
- unpack_synapse
- pcmk__unpack_graph
- free_graph_action
- free_graph_synapse
- pcmk__free_graph
- pcmk__event_from_graph_action
1
2
3
4
5
6
7
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 <crm/common/xml_internal.h>
19 #include <crm/lrmd_internal.h>
20 #include <pacemaker-internal.h>
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 static void
45 update_synapse_ready(pcmk__graph_synapse_t *synapse, int action_id)
46 {
47 if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
48 return;
49 }
50 pcmk__set_synapse_flags(synapse, pcmk__synapse_ready);
51 for (GList *lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
52 pcmk__graph_action_t *prereq = (pcmk__graph_action_t *) lpc->data;
53
54 if (prereq->id == action_id) {
55 crm_trace("Confirming input %d of synapse %d",
56 action_id, synapse->id);
57 pcmk__set_graph_action_flags(prereq, pcmk__graph_action_confirmed);
58
59 } else if (!(pcmk_is_set(prereq->flags, pcmk__graph_action_confirmed))) {
60 pcmk__clear_synapse_flags(synapse, pcmk__synapse_ready);
61 crm_trace("Synapse %d still not ready after action %d",
62 synapse->id, action_id);
63 }
64 }
65 if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
66 crm_trace("Synapse %d is now ready to execute", synapse->id);
67 }
68 }
69
70
71
72
73
74
75
76
77 static void
78 update_synapse_confirmed(pcmk__graph_synapse_t *synapse, int action_id)
79 {
80 bool all_confirmed = true;
81
82 for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
83 pcmk__graph_action_t *action = (pcmk__graph_action_t *) lpc->data;
84
85 if (action->id == action_id) {
86 crm_trace("Confirmed action %d of synapse %d",
87 action_id, synapse->id);
88 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
89
90 } else if (all_confirmed && !(pcmk_is_set(action->flags, pcmk__graph_action_confirmed))) {
91 all_confirmed = false;
92 crm_trace("Synapse %d still not confirmed after action %d",
93 synapse->id, action_id);
94 }
95 }
96
97 if (all_confirmed && !(pcmk_is_set(synapse->flags, pcmk__synapse_confirmed))) {
98 crm_trace("Confirmed synapse %d", synapse->id);
99 pcmk__set_synapse_flags(synapse, pcmk__synapse_confirmed);
100 }
101 }
102
103
104
105
106
107
108
109
110 void
111 pcmk__update_graph(pcmk__graph_t *graph, pcmk__graph_action_t *action)
112 {
113 for (GList *lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
114 pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
115
116 if (pcmk_any_flags_set(synapse->flags, pcmk__synapse_confirmed|pcmk__synapse_failed)) {
117 continue;
118
119 } else if (pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
120 update_synapse_confirmed(synapse, action->id);
121
122 } else if (!(pcmk_is_set(action->flags, pcmk__graph_action_failed)) || (synapse->priority == INFINITY)) {
123 update_synapse_ready(synapse, action->id);
124 }
125 }
126 }
127
128
129
130
131
132
133
134
135
136
137 static pcmk__graph_functions_t *graph_fns = NULL;
138
139
140
141
142
143
144
145 void
146 pcmk__set_graph_functions(pcmk__graph_functions_t *fns)
147 {
148 crm_debug("Setting custom functions for executing transition graphs");
149 graph_fns = fns;
150
151 CRM_ASSERT(graph_fns != NULL);
152 CRM_ASSERT(graph_fns->rsc != NULL);
153 CRM_ASSERT(graph_fns->cluster != NULL);
154 CRM_ASSERT(graph_fns->pseudo != NULL);
155 CRM_ASSERT(graph_fns->fence != NULL);
156 }
157
158
159
160
161
162
163
164
165
166
167 static bool
168 should_fire_synapse(pcmk__graph_t *graph, pcmk__graph_synapse_t *synapse)
169 {
170 GList *lpc = NULL;
171
172 pcmk__set_synapse_flags(synapse, pcmk__synapse_ready);
173 for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
174 pcmk__graph_action_t *prereq = (pcmk__graph_action_t *) lpc->data;
175
176 if (!(pcmk_is_set(prereq->flags, pcmk__graph_action_confirmed))) {
177 crm_trace("Input %d for synapse %d not yet confirmed",
178 prereq->id, synapse->id);
179 pcmk__clear_synapse_flags(synapse, pcmk__synapse_ready);
180 break;
181
182 } else if (pcmk_is_set(prereq->flags, pcmk__graph_action_failed) && !(pcmk_is_set(prereq->flags, pcmk__graph_action_can_fail))) {
183 crm_trace("Input %d for synapse %d confirmed but failed",
184 prereq->id, synapse->id);
185 pcmk__clear_synapse_flags(synapse, pcmk__synapse_ready);
186 break;
187 }
188 }
189 if (pcmk_is_set(synapse->flags, pcmk__synapse_ready)) {
190 crm_trace("Synapse %d is ready to execute", synapse->id);
191 } else {
192 return false;
193 }
194
195 for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
196 pcmk__graph_action_t *a = (pcmk__graph_action_t *) lpc->data;
197
198 if (a->type == pcmk__pseudo_graph_action) {
199
200
201 } else if (synapse->priority < graph->abort_priority) {
202 crm_trace("Skipping synapse %d: priority %d is less than "
203 "abort priority %d",
204 synapse->id, synapse->priority, graph->abort_priority);
205 graph->skipped++;
206 return false;
207
208 } else if (graph_fns->allowed && !(graph_fns->allowed(graph, a))) {
209 crm_trace("Deferring synapse %d: not allowed", synapse->id);
210 return false;
211 }
212 }
213
214 return true;
215 }
216
217
218
219
220
221
222
223
224
225
226 static int
227 initiate_action(pcmk__graph_t *graph, pcmk__graph_action_t *action)
228 {
229 const char *id = ID(action->xml);
230
231 CRM_CHECK(id != NULL, return EINVAL);
232 CRM_CHECK(!pcmk_is_set(action->flags, pcmk__graph_action_executed),
233 return pcmk_rc_already);
234
235 pcmk__set_graph_action_flags(action, pcmk__graph_action_executed);
236 switch (action->type) {
237 case pcmk__pseudo_graph_action:
238 crm_trace("Executing pseudo-action %d (%s)", action->id, id);
239 return graph_fns->pseudo(graph, action);
240
241 case pcmk__rsc_graph_action:
242 crm_trace("Executing resource action %d (%s)", action->id, id);
243 return graph_fns->rsc(graph, action);
244
245 case pcmk__cluster_graph_action:
246 if (pcmk__str_eq(crm_element_value(action->xml, XML_LRM_ATTR_TASK),
247 CRM_OP_FENCE, pcmk__str_casei)) {
248 crm_trace("Executing fencing action %d (%s)",
249 action->id, id);
250 return graph_fns->fence(graph, action);
251 }
252 crm_trace("Executing cluster action %d (%s)", action->id, id);
253 return graph_fns->cluster(graph, action);
254
255 default:
256 crm_err("Unsupported graph action type <%s id='%s'> (bug?)",
257 crm_element_name(action->xml), id);
258 return EINVAL;
259 }
260 }
261
262
263
264
265
266
267
268
269
270
271 static int
272 fire_synapse(pcmk__graph_t *graph, pcmk__graph_synapse_t *synapse)
273 {
274 pcmk__set_synapse_flags(synapse, pcmk__synapse_executed);
275 for (GList *lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
276 pcmk__graph_action_t *action = (pcmk__graph_action_t *) lpc->data;
277 int rc = initiate_action(graph, action);
278
279 if (rc != pcmk_rc_ok) {
280 crm_err("Failed initiating <%s id=%d> in synapse %d: %s",
281 crm_element_name(action->xml), action->id, synapse->id,
282 pcmk_rc_str(rc));
283 pcmk__set_synapse_flags(synapse, pcmk__synapse_confirmed);
284 pcmk__set_graph_action_flags(action,
285 pcmk__graph_action_confirmed
286 |pcmk__graph_action_failed);
287 return pcmk_rc_error;
288 }
289 }
290 return pcmk_rc_ok;
291 }
292
293
294
295
296
297
298
299
300
301
302
303
304 static int
305 pseudo_action_dummy(pcmk__graph_t * graph, pcmk__graph_action_t *action)
306 {
307 static int fail = -1;
308
309 if (fail < 0) {
310 long long fail_ll;
311
312 if ((pcmk__scan_ll(getenv("PE_fail"), &fail_ll, 0LL) == pcmk_rc_ok)
313 && (fail_ll > 0LL) && (fail_ll <= INT_MAX)) {
314 fail = (int) fail_ll;
315 } else {
316 fail = 0;
317 }
318 }
319
320 if (action->id == fail) {
321 crm_err("Dummy event handler: pretending action %d failed", action->id);
322 pcmk__set_graph_action_flags(action, pcmk__graph_action_failed);
323 graph->abort_priority = INFINITY;
324 } else {
325 crm_trace("Dummy event handler: action %d initiated", action->id);
326 }
327 pcmk__set_graph_action_flags(action, pcmk__graph_action_confirmed);
328 pcmk__update_graph(graph, action);
329 return pcmk_rc_ok;
330 }
331
332 static pcmk__graph_functions_t default_fns = {
333 pseudo_action_dummy,
334 pseudo_action_dummy,
335 pseudo_action_dummy,
336 pseudo_action_dummy
337 };
338
339
340
341
342
343
344
345
346
347 enum pcmk__graph_status
348 pcmk__execute_graph(pcmk__graph_t *graph)
349 {
350 GList *lpc = NULL;
351 int log_level = LOG_DEBUG;
352 enum pcmk__graph_status pass_result = pcmk__graph_active;
353 const char *status = "In progress";
354
355 if (graph_fns == NULL) {
356 graph_fns = &default_fns;
357 }
358 if (graph == NULL) {
359 return pcmk__graph_complete;
360 }
361
362 graph->fired = 0;
363 graph->pending = 0;
364 graph->skipped = 0;
365 graph->completed = 0;
366 graph->incomplete = 0;
367
368
369 for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
370 pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
371
372 if (pcmk_is_set(synapse->flags, pcmk__synapse_confirmed)) {
373 graph->completed++;
374
375 } else if (!(pcmk_is_set(synapse->flags, pcmk__synapse_failed)) && pcmk_is_set(synapse->flags, pcmk__synapse_executed)) {
376 graph->pending++;
377 }
378 }
379 crm_trace("Executing graph %d (%d synapses already completed, %d pending)",
380 graph->id, graph->completed, graph->pending);
381
382
383 for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
384 pcmk__graph_synapse_t *synapse = (pcmk__graph_synapse_t *) lpc->data;
385
386 if ((graph->batch_limit > 0)
387 && (graph->pending >= graph->batch_limit)) {
388
389 crm_debug("Throttling graph execution: batch limit (%d) reached",
390 graph->batch_limit);
391 break;
392
393 } else if (pcmk_is_set(synapse->flags, pcmk__synapse_failed)) {
394 graph->skipped++;
395 continue;
396
397 } else if (pcmk_any_flags_set(synapse->flags, pcmk__synapse_confirmed|pcmk__synapse_executed)) {
398 continue;
399
400 } else if (should_fire_synapse(graph, synapse)) {
401 graph->fired++;
402 if (fire_synapse(graph, synapse) != pcmk_rc_ok) {
403 crm_err("Synapse %d failed to fire", synapse->id);
404 log_level = LOG_ERR;
405 graph->abort_priority = INFINITY;
406 graph->incomplete++;
407 graph->fired--;
408 }
409
410 if (!(pcmk_is_set(synapse->flags, pcmk__synapse_confirmed))) {
411 graph->pending++;
412 }
413
414 } else {
415 crm_trace("Synapse %d cannot fire", synapse->id);
416 graph->incomplete++;
417 }
418 }
419
420 if ((graph->pending == 0) && (graph->fired == 0)) {
421 graph->complete = true;
422
423 if ((graph->incomplete != 0) && (graph->abort_priority <= 0)) {
424 log_level = LOG_WARNING;
425 pass_result = pcmk__graph_terminated;
426 status = "Terminated";
427
428 } else if (graph->skipped != 0) {
429 log_level = LOG_NOTICE;
430 pass_result = pcmk__graph_complete;
431 status = "Stopped";
432
433 } else {
434 log_level = LOG_NOTICE;
435 pass_result = pcmk__graph_complete;
436 status = "Complete";
437 }
438
439 } else if (graph->fired == 0) {
440 pass_result = pcmk__graph_pending;
441 }
442
443 do_crm_log(log_level,
444 "Transition %d (Complete=%d, Pending=%d,"
445 " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s",
446 graph->id, graph->completed, graph->pending, graph->fired,
447 graph->skipped, graph->incomplete, graph->source, status);
448
449 return pass_result;
450 }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466 static pcmk__graph_action_t *
467 unpack_action(pcmk__graph_synapse_t *parent, xmlNode *xml_action)
468 {
469 enum pcmk__graph_action_type action_type;
470 pcmk__graph_action_t *action = NULL;
471 const char *element = TYPE(xml_action);
472 const char *value = ID(xml_action);
473
474 if (value == NULL) {
475 crm_err("Ignoring transition graph action without id (bug?)");
476 crm_log_xml_trace(xml_action, "invalid");
477 return NULL;
478 }
479
480 if (pcmk__str_eq(element, XML_GRAPH_TAG_RSC_OP, pcmk__str_casei)) {
481 action_type = pcmk__rsc_graph_action;
482
483 } else if (pcmk__str_eq(element, XML_GRAPH_TAG_PSEUDO_EVENT,
484 pcmk__str_casei)) {
485 action_type = pcmk__pseudo_graph_action;
486
487 } else if (pcmk__str_eq(element, XML_GRAPH_TAG_CRM_EVENT,
488 pcmk__str_casei)) {
489 action_type = pcmk__cluster_graph_action;
490
491 } else {
492 crm_err("Ignoring transition graph action of unknown type '%s' (bug?)",
493 element);
494 crm_log_xml_trace(xml_action, "invalid");
495 return NULL;
496 }
497
498 action = calloc(1, sizeof(pcmk__graph_action_t));
499 if (action == NULL) {
500 crm_perror(LOG_CRIT, "Cannot unpack transition graph action");
501 crm_log_xml_trace(xml_action, "lost");
502 return NULL;
503 }
504
505 pcmk__scan_min_int(value, &(action->id), -1);
506 action->type = pcmk__rsc_graph_action;
507 action->xml = copy_xml(xml_action);
508 action->synapse = parent;
509 action->type = action_type;
510 action->params = xml2list(action->xml);
511
512 value = g_hash_table_lookup(action->params, "CRM_meta_timeout");
513 pcmk__scan_min_int(value, &(action->timeout), 0);
514
515
516 value = g_hash_table_lookup(action->params, "CRM_meta_start_delay");
517 {
518 int start_delay;
519
520 pcmk__scan_min_int(value, &start_delay, 0);
521 action->timeout += start_delay;
522 }
523
524 if (pcmk__guint_from_hash(action->params,
525 CRM_META "_" XML_LRM_ATTR_INTERVAL, 0,
526 &(action->interval_ms)) != pcmk_rc_ok) {
527 action->interval_ms = 0;
528 }
529
530 value = g_hash_table_lookup(action->params, "CRM_meta_can_fail");
531 if (value != NULL) {
532
533 gboolean can_fail = FALSE;
534 crm_str_to_boolean(value, &can_fail);
535 if (can_fail) {
536 pcmk__set_graph_action_flags(action, pcmk__graph_action_can_fail);
537 } else {
538 pcmk__clear_graph_action_flags(action, pcmk__graph_action_can_fail);
539 }
540
541 #ifndef PCMK__COMPAT_2_0
542 if (pcmk_is_set(action->flags, pcmk__graph_action_can_fail)) {
543 crm_warn("Support for the can_fail meta-attribute is deprecated"
544 " and will be removed in a future release");
545 }
546 #endif
547 }
548
549 crm_trace("Action %d has timer set to %dms", action->id, action->timeout);
550
551 return action;
552 }
553
554
555
556
557
558
559
560
561
562
563 static pcmk__graph_synapse_t *
564 unpack_synapse(pcmk__graph_t *new_graph, xmlNode *xml_synapse)
565 {
566 const char *value = NULL;
567 xmlNode *action_set = NULL;
568 pcmk__graph_synapse_t *new_synapse = NULL;
569
570 crm_trace("Unpacking synapse %s", ID(xml_synapse));
571
572 new_synapse = calloc(1, sizeof(pcmk__graph_synapse_t));
573 if (new_synapse == NULL) {
574 return NULL;
575 }
576
577 pcmk__scan_min_int(ID(xml_synapse), &(new_synapse->id), 0);
578
579 value = crm_element_value(xml_synapse, XML_CIB_ATTR_PRIORITY);
580 pcmk__scan_min_int(value, &(new_synapse->priority), 0);
581
582 CRM_CHECK(new_synapse->id >= 0, free(new_synapse);
583 return NULL);
584
585 new_graph->num_synapses++;
586
587 crm_trace("Unpacking synapse %s action sets",
588 crm_element_value(xml_synapse, XML_ATTR_ID));
589
590 for (action_set = first_named_child(xml_synapse, "action_set");
591 action_set != NULL; action_set = crm_next_same_xml(action_set)) {
592
593 for (xmlNode *action = pcmk__xml_first_child(action_set);
594 action != NULL; action = pcmk__xml_next(action)) {
595
596 pcmk__graph_action_t *new_action = unpack_action(new_synapse,
597 action);
598
599 if (new_action == NULL) {
600 continue;
601 }
602
603 crm_trace("Adding action %d to synapse %d",
604 new_action->id, new_synapse->id);
605 new_graph->num_actions++;
606 new_synapse->actions = g_list_append(new_synapse->actions,
607 new_action);
608 }
609 }
610
611 crm_trace("Unpacking synapse %s inputs", ID(xml_synapse));
612
613 for (xmlNode *inputs = first_named_child(xml_synapse, "inputs");
614 inputs != NULL; inputs = crm_next_same_xml(inputs)) {
615
616 for (xmlNode *trigger = first_named_child(inputs, "trigger");
617 trigger != NULL; trigger = crm_next_same_xml(trigger)) {
618
619 for (xmlNode *input = pcmk__xml_first_child(trigger);
620 input != NULL; input = pcmk__xml_next(input)) {
621
622 pcmk__graph_action_t *new_input = unpack_action(new_synapse,
623 input);
624
625 if (new_input == NULL) {
626 continue;
627 }
628
629 crm_trace("Adding input %d to synapse %d",
630 new_input->id, new_synapse->id);
631
632 new_synapse->inputs = g_list_append(new_synapse->inputs,
633 new_input);
634 }
635 }
636 }
637
638 return new_synapse;
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666 pcmk__graph_t *
667 pcmk__unpack_graph(xmlNode *xml_graph, const char *reference)
668 {
669 pcmk__graph_t *new_graph = NULL;
670 const char *t_id = NULL;
671 const char *time = NULL;
672
673 new_graph = calloc(1, sizeof(pcmk__graph_t));
674 if (new_graph == NULL) {
675 return NULL;
676 }
677
678 new_graph->source = strdup((reference == NULL)? "unknown" : reference);
679 if (new_graph->source == NULL) {
680 free(new_graph);
681 return NULL;
682 }
683
684 new_graph->id = -1;
685 new_graph->abort_priority = 0;
686 new_graph->network_delay = 0;
687 new_graph->stonith_timeout = 0;
688 new_graph->completion_action = pcmk__graph_done;
689
690
691 if (xml_graph != NULL) {
692 t_id = crm_element_value(xml_graph, "transition_id");
693 CRM_CHECK(t_id != NULL, free(new_graph);
694 return NULL);
695 pcmk__scan_min_int(t_id, &(new_graph->id), -1);
696
697 time = crm_element_value(xml_graph, "cluster-delay");
698 CRM_CHECK(time != NULL, free(new_graph);
699 return NULL);
700 new_graph->network_delay = crm_parse_interval_spec(time);
701
702 time = crm_element_value(xml_graph, "stonith-timeout");
703 if (time == NULL) {
704 new_graph->stonith_timeout = new_graph->network_delay;
705 } else {
706 new_graph->stonith_timeout = crm_parse_interval_spec(time);
707 }
708
709
710 t_id = crm_element_value(xml_graph, "batch-limit");
711 if ((t_id == NULL)
712 || (pcmk__scan_min_int(t_id, &(new_graph->batch_limit),
713 -1) != pcmk_rc_ok)) {
714 new_graph->batch_limit = 0;
715 }
716
717 t_id = crm_element_value(xml_graph, "migration-limit");
718 pcmk__scan_min_int(t_id, &(new_graph->migration_limit), -1);
719 }
720
721
722 for (xmlNode *synapse_xml = first_named_child(xml_graph, "synapse");
723 synapse_xml != NULL; synapse_xml = crm_next_same_xml(synapse_xml)) {
724
725 pcmk__graph_synapse_t *new_synapse = unpack_synapse(new_graph,
726 synapse_xml);
727
728 if (new_synapse != NULL) {
729 new_graph->synapses = g_list_append(new_graph->synapses,
730 new_synapse);
731 }
732 }
733
734 crm_debug("Unpacked transition %d from %s: %d actions in %d synapses",
735 new_graph->id, new_graph->source, new_graph->num_actions,
736 new_graph->num_synapses);
737
738 return new_graph;
739 }
740
741
742
743
744
745
746
747
748
749
750
751
752 static void
753 free_graph_action(gpointer user_data)
754 {
755 pcmk__graph_action_t *action = user_data;
756
757 if (action->timer != 0) {
758 crm_warn("Cancelling timer for graph action %d", action->id);
759 g_source_remove(action->timer);
760 }
761 if (action->params != NULL) {
762 g_hash_table_destroy(action->params);
763 }
764 free_xml(action->xml);
765 free(action);
766 }
767
768
769
770
771
772
773
774 static void
775 free_graph_synapse(gpointer user_data)
776 {
777 pcmk__graph_synapse_t *synapse = user_data;
778
779 g_list_free_full(synapse->actions, free_graph_action);
780 g_list_free_full(synapse->inputs, free_graph_action);
781 free(synapse);
782 }
783
784
785
786
787
788
789
790 void
791 pcmk__free_graph(pcmk__graph_t *graph)
792 {
793 if (graph != NULL) {
794 g_list_free_full(graph->synapses, free_graph_synapse);
795 free(graph->source);
796 free(graph);
797 }
798 }
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817 lrmd_event_data_t *
818 pcmk__event_from_graph_action(const xmlNode *resource,
819 const pcmk__graph_action_t *action,
820 int status, int rc, const char *exit_reason)
821 {
822 lrmd_event_data_t *op = NULL;
823 GHashTableIter iter;
824 const char *name = NULL;
825 const char *value = NULL;
826 xmlNode *action_resource = NULL;
827
828 CRM_CHECK(action != NULL, return NULL);
829 CRM_CHECK(action->type == pcmk__rsc_graph_action, return NULL);
830
831 action_resource = first_named_child(action->xml, XML_CIB_TAG_RESOURCE);
832 CRM_CHECK(action_resource != NULL, crm_log_xml_warn(action->xml, "invalid");
833 return NULL);
834
835 op = lrmd_new_event(ID(action_resource),
836 crm_element_value(action->xml, XML_LRM_ATTR_TASK),
837 action->interval_ms);
838 lrmd__set_result(op, rc, status, exit_reason);
839 op->t_run = time(NULL);
840 op->t_rcchange = op->t_run;
841 op->params = pcmk__strkey_table(free, free);
842
843 g_hash_table_iter_init(&iter, action->params);
844 while (g_hash_table_iter_next(&iter, (void **)&name, (void **)&value)) {
845 g_hash_table_insert(op->params, strdup(name), strdup(value));
846 }
847
848 for (xmlNode *xop = pcmk__xml_first_child(resource); xop != NULL;
849 xop = pcmk__xml_next(xop)) {
850 int tmp = 0;
851
852 crm_element_value_int(xop, XML_LRM_ATTR_CALLID, &tmp);
853 crm_debug("Got call_id=%d for %s", tmp, ID(resource));
854 if (tmp > op->call_id) {
855 op->call_id = tmp;
856 }
857 }
858
859 op->call_id++;
860 return op;
861 }