This source file includes following definitions.
- pe_rsc_action_details
- pe_free_rsc_action_details
- pe_can_fence
- node_copy
- node_list_exclude
- node_hash_from_list
- node_list_dup
- sort_node_uname
- dump_node_scores_worker
- append_dump_text
- dump_node_capacity
- dump_rsc_utilization
- sort_rsc_index
- sort_rsc_priority
- custom_action
- unpack_operation_on_fail
- find_min_interval_mon
- unpack_start_delay
- unpack_interval_origin
- unpack_timeout
- pe_get_configured_timeout
- unpack_versioned_meta
- unpack_operation
- find_rsc_op_entry_helper
- find_rsc_op_entry
- print_node
- print_str_str
- print_resource
- pe_free_action
- find_recurring_actions
- get_complex_task
- find_first_action
- find_actions
- find_actions_exact
- resource_node_score
- resource_location
- sort_op_by_callid
- get_effective_time
- get_target_role
- order_actions
- get_pseudo_op
- destroy_ticket
- ticket_new
- filter_parameters
- append_versioned_params
- rsc_action_digest
- rsc_action_digest_cmp
- fencing_action_digest_cmp
- rsc_printable_id
- clear_bit_recursive
- set_bit_recursive
- find_unfencing_devices
- pe_fence_op
- trigger_unfencing
- add_tag_ref
- pe_action_set_flag_reason
- pe_action_set_reason
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #include <crm_internal.h>
19 #include <crm/crm.h>
20 #include <crm/msg_xml.h>
21 #include <crm/common/xml.h>
22 #include <crm/common/util.h>
23
24 #include <glib.h>
25
26 #include <crm/pengine/rules.h>
27 #include <crm/pengine/internal.h>
28
29 #include <unpack.h>
30
31 pe_working_set_t *pe_dataset = NULL;
32
33 extern xmlNode *get_object_root(const char *object_type, xmlNode * the_root);
34 void print_str_str(gpointer key, gpointer value, gpointer user_data);
35 gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
36 void unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
37 pe_working_set_t * data_set);
38 static xmlNode *find_rsc_op_entry_helper(resource_t * rsc, const char *key,
39 gboolean include_disabled);
40
41 #if ENABLE_VERSIONED_ATTRS
42 pe_rsc_action_details_t *
43 pe_rsc_action_details(pe_action_t *action)
44 {
45 pe_rsc_action_details_t *details;
46
47 CRM_CHECK(action != NULL, return NULL);
48
49 if (action->action_details == NULL) {
50 action->action_details = calloc(1, sizeof(pe_rsc_action_details_t));
51 CRM_CHECK(action->action_details != NULL, return NULL);
52 }
53
54 details = (pe_rsc_action_details_t *) action->action_details;
55 if (details->versioned_parameters == NULL) {
56 details->versioned_parameters = create_xml_node(NULL,
57 XML_TAG_OP_VER_ATTRS);
58 }
59 if (details->versioned_meta == NULL) {
60 details->versioned_meta = create_xml_node(NULL, XML_TAG_OP_VER_META);
61 }
62 return details;
63 }
64
65 static void
66 pe_free_rsc_action_details(pe_action_t *action)
67 {
68 pe_rsc_action_details_t *details;
69
70 if ((action == NULL) || (action->action_details == NULL)) {
71 return;
72 }
73
74 details = (pe_rsc_action_details_t *) action->action_details;
75
76 if (details->versioned_parameters) {
77 free_xml(details->versioned_parameters);
78 }
79 if (details->versioned_meta) {
80 free_xml(details->versioned_meta);
81 }
82
83 action->action_details = NULL;
84 }
85 #endif
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 bool pe_can_fence(pe_working_set_t * data_set, node_t *node)
101 {
102 if(is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
103 return FALSE;
104
105 } else if (is_not_set(data_set->flags, pe_flag_have_stonith_resource)) {
106 return FALSE;
107
108 } else if (is_set(data_set->flags, pe_flag_have_quorum)) {
109 return TRUE;
110
111 } else if (data_set->no_quorum_policy == no_quorum_ignore) {
112 return TRUE;
113
114 } else if(node == NULL) {
115 return FALSE;
116
117 } else if(node->details->online) {
118 crm_notice("We can fence %s without quorum because they're in our membership", node->details->uname);
119 return TRUE;
120 }
121
122 crm_trace("Cannot fence %s", node->details->uname);
123 return FALSE;
124 }
125
126 node_t *
127 node_copy(const node_t *this_node)
128 {
129 node_t *new_node = NULL;
130
131 CRM_CHECK(this_node != NULL, return NULL);
132
133 new_node = calloc(1, sizeof(node_t));
134 CRM_ASSERT(new_node != NULL);
135
136 crm_trace("Copying %p (%s) to %p", this_node, this_node->details->uname, new_node);
137
138 new_node->rsc_discover_mode = this_node->rsc_discover_mode;
139 new_node->weight = this_node->weight;
140 new_node->fixed = this_node->fixed;
141 new_node->details = this_node->details;
142
143 return new_node;
144 }
145
146
147 void
148 node_list_exclude(GHashTable * hash, GListPtr list, gboolean merge_scores)
149 {
150 GHashTable *result = hash;
151 node_t *other_node = NULL;
152 GListPtr gIter = list;
153
154 GHashTableIter iter;
155 node_t *node = NULL;
156
157 g_hash_table_iter_init(&iter, hash);
158 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
159
160 other_node = pe_find_node_id(list, node->details->id);
161 if (other_node == NULL) {
162 node->weight = -INFINITY;
163 } else if (merge_scores) {
164 node->weight = merge_weights(node->weight, other_node->weight);
165 }
166 }
167
168 for (; gIter != NULL; gIter = gIter->next) {
169 node_t *node = (node_t *) gIter->data;
170
171 other_node = pe_hash_table_lookup(result, node->details->id);
172
173 if (other_node == NULL) {
174 node_t *new_node = node_copy(node);
175
176 new_node->weight = -INFINITY;
177 g_hash_table_insert(result, (gpointer) new_node->details->id, new_node);
178 }
179 }
180 }
181
182 GHashTable *
183 node_hash_from_list(GListPtr list)
184 {
185 GListPtr gIter = list;
186 GHashTable *result = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, g_hash_destroy_str);
187
188 for (; gIter != NULL; gIter = gIter->next) {
189 node_t *node = (node_t *) gIter->data;
190 node_t *n = node_copy(node);
191
192 g_hash_table_insert(result, (gpointer) n->details->id, n);
193 }
194
195 return result;
196 }
197
198 GListPtr
199 node_list_dup(GListPtr list1, gboolean reset, gboolean filter)
200 {
201 GListPtr result = NULL;
202 GListPtr gIter = list1;
203
204 for (; gIter != NULL; gIter = gIter->next) {
205 node_t *new_node = NULL;
206 node_t *this_node = (node_t *) gIter->data;
207
208 if (filter && this_node->weight < 0) {
209 continue;
210 }
211
212 new_node = node_copy(this_node);
213 if (reset) {
214 new_node->weight = 0;
215 }
216 if (new_node != NULL) {
217 result = g_list_prepend(result, new_node);
218 }
219 }
220
221 return result;
222 }
223
224 gint
225 sort_node_uname(gconstpointer a, gconstpointer b)
226 {
227 const node_t *node_a = a;
228 const node_t *node_b = b;
229
230 return strcmp(node_a->details->uname, node_b->details->uname);
231 }
232
233 void
234 dump_node_scores_worker(int level, const char *file, const char *function, int line,
235 resource_t * rsc, const char *comment, GHashTable * nodes)
236 {
237 GHashTable *hash = nodes;
238 GHashTableIter iter;
239 node_t *node = NULL;
240
241 if (rsc) {
242 hash = rsc->allowed_nodes;
243 }
244
245 if (rsc && is_set(rsc->flags, pe_rsc_orphan)) {
246
247 return;
248 }
249
250 if (level == 0) {
251 char score[128];
252 int len = sizeof(score);
253
254 GListPtr gIter = NULL;
255 GListPtr list = g_hash_table_get_values(hash);
256
257 list = g_list_sort(list, sort_node_uname);
258
259 gIter = list;
260 for (; gIter != NULL; gIter = gIter->next) {
261 node_t *node = (node_t *) gIter->data;
262
263 score2char_stack(node->weight, score, len);
264
265 if (rsc) {
266 printf("%s: %s allocation score on %s: %s\n",
267 comment, rsc->id, node->details->uname, score);
268 } else {
269 printf("%s: %s = %s\n", comment, node->details->uname, score);
270 }
271 }
272
273 g_list_free(list);
274
275 } else if (hash) {
276 char score[128];
277 int len = sizeof(score);
278 g_hash_table_iter_init(&iter, hash);
279 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
280
281 score2char_stack(node->weight, score, len);
282
283 if (rsc) {
284 do_crm_log_alias(LOG_TRACE, file, function, line,
285 "%s: %s allocation score on %s: %s", comment, rsc->id,
286 node->details->uname, score);
287 } else {
288 do_crm_log_alias(LOG_TRACE, file, function, line + 1, "%s: %s = %s", comment,
289 node->details->uname, score);
290 }
291 }
292 }
293
294 if (rsc && rsc->children) {
295 GListPtr gIter = NULL;
296
297 gIter = rsc->children;
298 for (; gIter != NULL; gIter = gIter->next) {
299 resource_t *child = (resource_t *) gIter->data;
300
301 dump_node_scores_worker(level, file, function, line, child, comment, nodes);
302 }
303 }
304 }
305
306 static void
307 append_dump_text(gpointer key, gpointer value, gpointer user_data)
308 {
309 char **dump_text = user_data;
310 int len = 0;
311 char *new_text = NULL;
312
313 len = strlen(*dump_text) + strlen(" ") + strlen(key) + strlen("=") + strlen(value) + 1;
314 new_text = calloc(1, len);
315 sprintf(new_text, "%s %s=%s", *dump_text, (char *)key, (char *)value);
316
317 free(*dump_text);
318 *dump_text = new_text;
319 }
320
321 void
322 dump_node_capacity(int level, const char *comment, node_t * node)
323 {
324 int len = 0;
325 char *dump_text = NULL;
326
327 len = strlen(comment) + strlen(": ") + strlen(node->details->uname) + strlen(" capacity:") + 1;
328 dump_text = calloc(1, len);
329 sprintf(dump_text, "%s: %s capacity:", comment, node->details->uname);
330
331 g_hash_table_foreach(node->details->utilization, append_dump_text, &dump_text);
332
333 if (level == 0) {
334 fprintf(stdout, "%s\n", dump_text);
335 } else {
336 crm_trace("%s", dump_text);
337 }
338
339 free(dump_text);
340 }
341
342 void
343 dump_rsc_utilization(int level, const char *comment, resource_t * rsc, node_t * node)
344 {
345 int len = 0;
346 char *dump_text = NULL;
347
348 len = strlen(comment) + strlen(": ") + strlen(rsc->id) + strlen(" utilization on ")
349 + strlen(node->details->uname) + strlen(":") + 1;
350 dump_text = calloc(1, len);
351 sprintf(dump_text, "%s: %s utilization on %s:", comment, rsc->id, node->details->uname);
352
353 g_hash_table_foreach(rsc->utilization, append_dump_text, &dump_text);
354
355 if (level == 0) {
356 fprintf(stdout, "%s\n", dump_text);
357 } else {
358 crm_trace("%s", dump_text);
359 }
360
361 free(dump_text);
362 }
363
364 gint
365 sort_rsc_index(gconstpointer a, gconstpointer b)
366 {
367 const resource_t *resource1 = (const resource_t *)a;
368 const resource_t *resource2 = (const resource_t *)b;
369
370 if (a == NULL && b == NULL) {
371 return 0;
372 }
373 if (a == NULL) {
374 return 1;
375 }
376 if (b == NULL) {
377 return -1;
378 }
379
380 if (resource1->sort_index > resource2->sort_index) {
381 return -1;
382 }
383
384 if (resource1->sort_index < resource2->sort_index) {
385 return 1;
386 }
387
388 return 0;
389 }
390
391 gint
392 sort_rsc_priority(gconstpointer a, gconstpointer b)
393 {
394 const resource_t *resource1 = (const resource_t *)a;
395 const resource_t *resource2 = (const resource_t *)b;
396
397 if (a == NULL && b == NULL) {
398 return 0;
399 }
400 if (a == NULL) {
401 return 1;
402 }
403 if (b == NULL) {
404 return -1;
405 }
406
407 if (resource1->priority > resource2->priority) {
408 return -1;
409 }
410
411 if (resource1->priority < resource2->priority) {
412 return 1;
413 }
414
415 return 0;
416 }
417
418 action_t *
419 custom_action(resource_t * rsc, char *key, const char *task,
420 node_t * on_node, gboolean optional, gboolean save_action,
421 pe_working_set_t * data_set)
422 {
423 action_t *action = NULL;
424 GListPtr possible_matches = NULL;
425
426 CRM_CHECK(key != NULL, return NULL);
427 CRM_CHECK(task != NULL, free(key); return NULL);
428
429 if (save_action && rsc != NULL) {
430 possible_matches = find_actions(rsc->actions, key, on_node);
431 } else if(save_action) {
432 #if 0
433 action = g_hash_table_lookup(data_set->singletons, key);
434 #else
435
436 possible_matches = find_actions(data_set->actions, key, on_node);
437 #endif
438 }
439
440 if(data_set->singletons == NULL) {
441 data_set->singletons = g_hash_table_new_full(crm_str_hash, g_str_equal, NULL, NULL);
442 }
443
444 if (possible_matches != NULL) {
445 if (g_list_length(possible_matches) > 1) {
446 pe_warn("Action %s for %s on %s exists %d times",
447 task, rsc ? rsc->id : "<NULL>",
448 on_node ? on_node->details->uname : "<NULL>", g_list_length(possible_matches));
449 }
450
451 action = g_list_nth_data(possible_matches, 0);
452 pe_rsc_trace(rsc, "Found existing action (%d) %s for %s on %s",
453 action->id, task, rsc ? rsc->id : "<NULL>",
454 on_node ? on_node->details->uname : "<NULL>");
455 g_list_free(possible_matches);
456 }
457
458 if (action == NULL) {
459 if (save_action) {
460 pe_rsc_trace(rsc, "Creating%s action %d: %s for %s on %s %d",
461 optional ? "" : " mandatory", data_set->action_id, key,
462 rsc ? rsc->id : "<NULL>", on_node ? on_node->details->uname : "<NULL>", optional);
463 }
464
465 action = calloc(1, sizeof(action_t));
466 if (save_action) {
467 action->id = data_set->action_id++;
468 } else {
469 action->id = 0;
470 }
471 action->rsc = rsc;
472 CRM_ASSERT(task != NULL);
473 action->task = strdup(task);
474 if (on_node) {
475 action->node = node_copy(on_node);
476 }
477 action->uuid = strdup(key);
478
479 pe_set_action_bit(action, pe_action_runnable);
480 if (optional) {
481 pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
482 pe_set_action_bit(action, pe_action_optional);
483 } else {
484 pe_clear_action_bit(action, pe_action_optional);
485 pe_rsc_trace(rsc, "Unset optional on %s", action->uuid);
486 }
487
488
489
490
491
492
493
494
495
496
497
498
499 action->extra = crm_str_table_new();
500 action->meta = crm_str_table_new();
501
502 if (save_action) {
503 data_set->actions = g_list_prepend(data_set->actions, action);
504 if(rsc == NULL) {
505 g_hash_table_insert(data_set->singletons, action->uuid, action);
506 }
507 }
508
509 if (rsc != NULL) {
510 action->op_entry = find_rsc_op_entry_helper(rsc, key, TRUE);
511
512 unpack_operation(action, action->op_entry, rsc->container, data_set);
513
514 if (save_action) {
515 rsc->actions = g_list_prepend(rsc->actions, action);
516 }
517 }
518
519 if (save_action) {
520 pe_rsc_trace(rsc, "Action %d created", action->id);
521 }
522 }
523
524 if (optional == FALSE) {
525 pe_rsc_trace(rsc, "Unset optional on %s", action->uuid);
526 pe_clear_action_bit(action, pe_action_optional);
527 }
528
529 if (rsc != NULL) {
530 enum action_tasks a_task = text2task(action->task);
531 int warn_level = LOG_TRACE;
532
533 if (save_action) {
534 warn_level = LOG_WARNING;
535 }
536
537 if (is_set(action->flags, pe_action_have_node_attrs) == FALSE
538 && action->node != NULL && action->op_entry != NULL) {
539 pe_set_action_bit(action, pe_action_have_node_attrs);
540 unpack_instance_attributes(data_set->input, action->op_entry, XML_TAG_ATTR_SETS,
541 action->node->details->attrs,
542 action->extra, NULL, FALSE, data_set->now);
543 }
544
545 if (is_set(action->flags, pe_action_pseudo)) {
546
547
548 } else if (action->node == NULL) {
549 pe_rsc_trace(rsc, "Unset runnable on %s", action->uuid);
550 pe_clear_action_bit(action, pe_action_runnable);
551
552 } else if (is_not_set(rsc->flags, pe_rsc_managed)
553 && g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL) == NULL) {
554 crm_debug("Action %s (unmanaged)", action->uuid);
555 pe_rsc_trace(rsc, "Set optional on %s", action->uuid);
556 pe_set_action_bit(action, pe_action_optional);
557
558
559 } else if (action->node->details->online == FALSE
560 && (!is_container_remote_node(action->node) || action->node->details->remote_requires_reset)) {
561 pe_clear_action_bit(action, pe_action_runnable);
562 do_crm_log(warn_level, "Action %s on %s is unrunnable (offline)",
563 action->uuid, action->node->details->uname);
564 if (is_set(action->rsc->flags, pe_rsc_managed)
565 && save_action && a_task == stop_rsc
566 && action->node->details->unclean == FALSE) {
567 pe_fence_node(data_set, action->node, "resource actions are unrunnable");
568 }
569
570 } else if (action->node->details->pending) {
571 pe_clear_action_bit(action, pe_action_runnable);
572 do_crm_log(warn_level, "Action %s on %s is unrunnable (pending)",
573 action->uuid, action->node->details->uname);
574
575 } else if (action->needs == rsc_req_nothing) {
576 pe_rsc_trace(rsc, "Action %s does not require anything", action->uuid);
577 pe_action_set_reason(action, NULL, TRUE);
578 pe_set_action_bit(action, pe_action_runnable);
579 #if 0
580
581
582
583
584 } else if (action->needs == rsc_req_stonith) {
585 crm_trace("Action %s requires only stonith", action->uuid);
586 action->runnable = TRUE;
587 #endif
588 } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
589 && data_set->no_quorum_policy == no_quorum_stop) {
590 pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, NULL, "no quorum", pe_action_runnable, TRUE);
591 crm_debug("%s\t%s (cancelled : quorum)", action->node->details->uname, action->uuid);
592
593 } else if (is_set(data_set->flags, pe_flag_have_quorum) == FALSE
594 && data_set->no_quorum_policy == no_quorum_freeze) {
595 pe_rsc_trace(rsc, "Check resource is already active: %s %s %s %s", rsc->id, action->uuid, role2text(rsc->next_role), role2text(rsc->role));
596 if (rsc->fns->active(rsc, TRUE) == FALSE || rsc->next_role > rsc->role) {
597 pe_action_set_flag_reason(__FUNCTION__, __LINE__, action, NULL, "quorum freeze", pe_action_runnable, TRUE);
598 pe_rsc_debug(rsc, "%s\t%s (cancelled : quorum freeze)",
599 action->node->details->uname, action->uuid);
600 }
601
602 } else if(is_not_set(action->flags, pe_action_runnable)) {
603 pe_rsc_trace(rsc, "Action %s is runnable", action->uuid);
604
605 pe_set_action_bit(action, pe_action_runnable);
606 }
607
608 if (save_action) {
609 switch (a_task) {
610 case stop_rsc:
611 set_bit(rsc->flags, pe_rsc_stopping);
612 break;
613 case start_rsc:
614 clear_bit(rsc->flags, pe_rsc_starting);
615 if (is_set(action->flags, pe_action_runnable)) {
616 set_bit(rsc->flags, pe_rsc_starting);
617 }
618 break;
619 default:
620 break;
621 }
622 }
623 }
624
625 free(key);
626 return action;
627 }
628
629 static const char *
630 unpack_operation_on_fail(action_t * action)
631 {
632
633 const char *value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ON_FAIL);
634
635 if (safe_str_eq(action->task, CRMD_ACTION_STOP) && safe_str_eq(value, "standby")) {
636 crm_config_err("on-fail=standby is not allowed for stop actions: %s", action->rsc->id);
637 return NULL;
638 } else if (safe_str_eq(action->task, CRMD_ACTION_DEMOTE) && !value) {
639
640 xmlNode *operation = NULL;
641 const char *name = NULL;
642 const char *role = NULL;
643 const char *on_fail = NULL;
644 const char *interval = NULL;
645 const char *enabled = NULL;
646
647 CRM_CHECK(action->rsc != NULL, return NULL);
648
649 for (operation = __xml_first_child(action->rsc->ops_xml);
650 operation && !value; operation = __xml_next_element(operation)) {
651
652 if (!crm_str_eq((const char *)operation->name, "op", TRUE)) {
653 continue;
654 }
655 name = crm_element_value(operation, "name");
656 role = crm_element_value(operation, "role");
657 on_fail = crm_element_value(operation, XML_OP_ATTR_ON_FAIL);
658 enabled = crm_element_value(operation, "enabled");
659 interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
660 if (!on_fail) {
661 continue;
662 } else if (enabled && !crm_is_true(enabled)) {
663 continue;
664 } else if (safe_str_neq(name, "monitor") || safe_str_neq(role, "Master")) {
665 continue;
666 } else if (crm_get_interval(interval) <= 0) {
667 continue;
668 }
669
670 value = on_fail;
671 }
672 }
673
674 return value;
675 }
676
677 static xmlNode *
678 find_min_interval_mon(resource_t * rsc, gboolean include_disabled)
679 {
680 int number = 0;
681 int min_interval = -1;
682 const char *name = NULL;
683 const char *value = NULL;
684 const char *interval = NULL;
685 xmlNode *op = NULL;
686 xmlNode *operation = NULL;
687
688 for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
689 operation = __xml_next_element(operation)) {
690
691 if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
692 name = crm_element_value(operation, "name");
693 interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
694 value = crm_element_value(operation, "enabled");
695 if (!include_disabled && value && crm_is_true(value) == FALSE) {
696 continue;
697 }
698
699 if (safe_str_neq(name, RSC_STATUS)) {
700 continue;
701 }
702
703 number = crm_get_interval(interval);
704 if (number < 0) {
705 continue;
706 }
707
708 if (min_interval < 0 || number < min_interval) {
709 min_interval = number;
710 op = operation;
711 }
712 }
713 }
714
715 return op;
716 }
717
718 static int
719 unpack_start_delay(const char *value, GHashTable *meta)
720 {
721 int start_delay = 0;
722
723 if (value != NULL) {
724 start_delay = crm_get_msec(value);
725
726 if (start_delay < 0) {
727 start_delay = 0;
728 }
729
730 if (meta) {
731 g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY), crm_itoa(start_delay));
732 }
733 }
734
735 return start_delay;
736 }
737
738 static int
739 unpack_interval_origin(const char *value, GHashTable *meta, xmlNode *xml_obj,
740 unsigned long long interval, crm_time_t *now)
741 {
742 int start_delay = 0;
743
744 if (interval > 0 && value) {
745 crm_time_t *origin = crm_time_new(value);
746
747 if (origin && now) {
748 crm_time_t *delay = NULL;
749 int rc = crm_time_compare(origin, now);
750 long long delay_s = 0;
751 int interval_s = (interval / 1000);
752
753 crm_trace("Origin: %s, interval: %d", value, interval_s);
754
755
756 while(rc > 0) {
757 crm_time_add_seconds(origin, -interval_s);
758 rc = crm_time_compare(origin, now);
759 }
760
761
762 while (rc < 0) {
763 crm_time_add_seconds(origin, interval_s);
764 rc = crm_time_compare(origin, now);
765 }
766
767 delay = crm_time_calculate_duration(origin, now);
768
769 crm_time_log(LOG_TRACE, "origin", origin,
770 crm_time_log_date | crm_time_log_timeofday |
771 crm_time_log_with_timezone);
772 crm_time_log(LOG_TRACE, "now", now,
773 crm_time_log_date | crm_time_log_timeofday |
774 crm_time_log_with_timezone);
775 crm_time_log(LOG_TRACE, "delay", delay, crm_time_log_duration);
776
777 delay_s = crm_time_get_seconds(delay);
778
779 CRM_CHECK(delay_s >= 0, delay_s = 0);
780 start_delay = delay_s * 1000;
781
782 if (xml_obj) {
783 crm_info("Calculated a start delay of %llds for %s", delay_s, ID(xml_obj));
784 }
785
786 if (meta) {
787 g_hash_table_replace(meta, strdup(XML_OP_ATTR_START_DELAY),
788 crm_itoa(start_delay));
789 }
790
791 crm_time_free(origin);
792 crm_time_free(delay);
793 } else if (!origin && xml_obj) {
794 crm_config_err("Operation %s contained an invalid " XML_OP_ATTR_ORIGIN ": %s",
795 ID(xml_obj), value);
796 }
797 }
798
799 return start_delay;
800 }
801
802 static int
803 unpack_timeout(const char *value, action_t *action, xmlNode *xml_obj,
804 unsigned long long interval, GHashTable *config_hash)
805 {
806 int timeout = 0;
807
808 if (value == NULL && xml_obj == NULL && action &&
809 safe_str_eq(action->task, RSC_STATUS) && interval == 0) {
810
811 xmlNode *min_interval_mon = find_min_interval_mon(action->rsc, FALSE);
812
813 if (min_interval_mon) {
814 value = crm_element_value(min_interval_mon, XML_ATTR_TIMEOUT);
815 pe_rsc_trace(action->rsc,
816 "\t%s uses the timeout value '%s' from the minimum interval monitor",
817 action->uuid, value);
818 }
819 }
820
821 if (value == NULL && config_hash) {
822 value = pe_pref(config_hash, "default-action-timeout");
823 if (value) {
824 pe_warn_once(pe_wo_default_timeo,
825 "Support for 'default-action-timeout' cluster property"
826 " is deprecated and will be removed in a future release"
827 " (use 'timeout' in op_defaults instead)");
828
829 }
830 }
831
832 if (value == NULL) {
833 value = CRM_DEFAULT_OP_TIMEOUT_S;
834 }
835
836 timeout = crm_get_msec(value);
837 if (timeout < 0) {
838 timeout = 0;
839 }
840
841 return timeout;
842 }
843
844 int
845 pe_get_configured_timeout(resource_t *rsc, const char *action, pe_working_set_t *data_set)
846 {
847 xmlNode *child = NULL;
848 const char *timeout = NULL;
849 int timeout_ms = 0;
850
851 for (child = first_named_child(rsc->ops_xml, XML_ATTR_OP);
852 child != NULL; child = crm_next_same_xml(child)) {
853 if (safe_str_eq(action, crm_element_value(child, XML_NVPAIR_ATTR_NAME))) {
854 timeout = crm_element_value(child, XML_ATTR_TIMEOUT);
855 break;
856 }
857 }
858
859 if (timeout == NULL && data_set->op_defaults) {
860 GHashTable *action_meta = crm_str_table_new();
861 unpack_instance_attributes(data_set->input, data_set->op_defaults, XML_TAG_META_SETS,
862 NULL, action_meta, NULL, FALSE, data_set->now);
863 timeout = g_hash_table_lookup(action_meta, XML_ATTR_TIMEOUT);
864 }
865
866 if (timeout == NULL && data_set->config_hash) {
867 timeout = pe_pref(data_set->config_hash, "default-action-timeout");
868 }
869
870 if (timeout == NULL) {
871 timeout = CRM_DEFAULT_OP_TIMEOUT_S;
872 }
873
874 timeout_ms = crm_get_msec(timeout);
875 if (timeout_ms < 0) {
876 timeout_ms = 0;
877 }
878
879 return timeout_ms;
880 }
881
882 #if ENABLE_VERSIONED_ATTRS
883 static void
884 unpack_versioned_meta(xmlNode *versioned_meta, xmlNode *xml_obj, unsigned long long interval, crm_time_t *now)
885 {
886 xmlNode *attrs = NULL;
887 xmlNode *attr = NULL;
888
889 for (attrs = __xml_first_child(versioned_meta); attrs != NULL; attrs = __xml_next_element(attrs)) {
890 for (attr = __xml_first_child(attrs); attr != NULL; attr = __xml_next_element(attr)) {
891 const char *name = crm_element_value(attr, XML_NVPAIR_ATTR_NAME);
892 const char *value = crm_element_value(attr, XML_NVPAIR_ATTR_VALUE);
893
894 if (safe_str_eq(name, XML_OP_ATTR_START_DELAY)) {
895 int start_delay = unpack_start_delay(value, NULL);
896
897 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
898 } else if (safe_str_eq(name, XML_OP_ATTR_ORIGIN)) {
899 int start_delay = unpack_interval_origin(value, NULL, xml_obj, interval, now);
900
901 crm_xml_add(attr, XML_NVPAIR_ATTR_NAME, XML_OP_ATTR_START_DELAY);
902 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, start_delay);
903 } else if (safe_str_eq(name, XML_ATTR_TIMEOUT)) {
904 int timeout = unpack_timeout(value, NULL, NULL, 0, NULL);
905
906 crm_xml_add_int(attr, XML_NVPAIR_ATTR_VALUE, timeout);
907 }
908 }
909 }
910 }
911 #endif
912
913 void
914 unpack_operation(action_t * action, xmlNode * xml_obj, resource_t * container,
915 pe_working_set_t * data_set)
916 {
917 unsigned long long interval = 0;
918 int timeout = 0;
919 char *value_ms = NULL;
920 const char *value = NULL;
921 const char *field = NULL;
922 #if ENABLE_VERSIONED_ATTRS
923 pe_rsc_action_details_t *rsc_details = NULL;
924 #endif
925
926 CRM_CHECK(action->rsc != NULL, return);
927
928 unpack_instance_attributes(data_set->input, data_set->op_defaults, XML_TAG_META_SETS, NULL,
929 action->meta, NULL, FALSE, data_set->now);
930
931 if (xml_obj) {
932 xmlAttrPtr xIter = NULL;
933
934 for (xIter = xml_obj->properties; xIter; xIter = xIter->next) {
935 const char *prop_name = (const char *)xIter->name;
936 const char *prop_value = crm_element_value(xml_obj, prop_name);
937
938 g_hash_table_replace(action->meta, strdup(prop_name), strdup(prop_value));
939 }
940 }
941
942 unpack_instance_attributes(data_set->input, xml_obj, XML_TAG_META_SETS,
943 NULL, action->meta, NULL, FALSE, data_set->now);
944
945 unpack_instance_attributes(data_set->input, xml_obj, XML_TAG_ATTR_SETS,
946 NULL, action->meta, NULL, FALSE, data_set->now);
947
948 #if ENABLE_VERSIONED_ATTRS
949 rsc_details = pe_rsc_action_details(action);
950 pe_unpack_versioned_attributes(data_set->input, xml_obj, XML_TAG_ATTR_SETS, NULL,
951 rsc_details->versioned_parameters, data_set->now);
952 pe_unpack_versioned_attributes(data_set->input, xml_obj, XML_TAG_META_SETS, NULL,
953 rsc_details->versioned_meta, data_set->now);
954 #endif
955
956 g_hash_table_remove(action->meta, "id");
957
958 field = XML_LRM_ATTR_INTERVAL;
959 value = g_hash_table_lookup(action->meta, field);
960 if (value != NULL) {
961 interval = crm_get_interval(value);
962 if (interval > 0) {
963 value_ms = crm_itoa(interval);
964 g_hash_table_replace(action->meta, strdup(field), value_ms);
965
966 } else {
967 g_hash_table_remove(action->meta, field);
968 }
969 }
970
971
972 value = g_hash_table_lookup(action->meta, "requires");
973 if (value) {
974 pe_warn_once(pe_wo_requires, "Support for 'requires' operation meta-attribute"
975 " is deprecated and will be removed in a future version"
976 " (use 'requires' resource meta-attribute instead)");
977 }
978
979 if (safe_str_neq(action->task, RSC_START)
980 && safe_str_neq(action->task, RSC_PROMOTE)) {
981 action->needs = rsc_req_nothing;
982 value = "nothing (not start/promote)";
983
984 } else if (safe_str_eq(value, "nothing")) {
985 action->needs = rsc_req_nothing;
986
987 } else if (safe_str_eq(value, "quorum")) {
988 action->needs = rsc_req_quorum;
989
990 } else if (safe_str_eq(value, "unfencing")) {
991 action->needs = rsc_req_stonith;
992 set_bit(action->rsc->flags, pe_rsc_needs_unfencing);
993 if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
994 crm_notice("%s requires unfencing but fencing is disabled", action->rsc->id);
995 }
996
997 } else if (is_set(data_set->flags, pe_flag_stonith_enabled)
998 && safe_str_eq(value, "fencing")) {
999 action->needs = rsc_req_stonith;
1000 if (is_not_set(data_set->flags, pe_flag_stonith_enabled)) {
1001 crm_notice("%s requires fencing but fencing is disabled", action->rsc->id);
1002 }
1003
1004
1005 } else if (is_set(action->rsc->flags, pe_rsc_needs_fencing)) {
1006 action->needs = rsc_req_stonith;
1007 value = "fencing (resource)";
1008
1009 } else if (is_set(action->rsc->flags, pe_rsc_needs_quorum)) {
1010 action->needs = rsc_req_quorum;
1011 value = "quorum (resource)";
1012
1013 } else {
1014 action->needs = rsc_req_nothing;
1015 value = "nothing (resource)";
1016 }
1017
1018 pe_rsc_trace(action->rsc, "\tAction %s requires: %s", action->task, value);
1019
1020 value = unpack_operation_on_fail(action);
1021
1022 if (value == NULL) {
1023
1024 } else if (safe_str_eq(value, "block")) {
1025 action->on_fail = action_fail_block;
1026 g_hash_table_insert(action->meta, strdup(XML_OP_ATTR_ON_FAIL), strdup("block"));
1027
1028 } else if (safe_str_eq(value, "fence")) {
1029 action->on_fail = action_fail_fence;
1030 value = "node fencing";
1031
1032 if (is_set(data_set->flags, pe_flag_stonith_enabled) == FALSE) {
1033 crm_config_err("Specifying on_fail=fence and" " stonith-enabled=false makes no sense");
1034 action->on_fail = action_fail_stop;
1035 action->fail_role = RSC_ROLE_STOPPED;
1036 value = "stop resource";
1037 }
1038
1039 } else if (safe_str_eq(value, "standby")) {
1040 action->on_fail = action_fail_standby;
1041 value = "node standby";
1042
1043 } else if (safe_str_eq(value, "ignore")
1044 || safe_str_eq(value, "nothing")) {
1045 action->on_fail = action_fail_ignore;
1046 value = "ignore";
1047
1048 } else if (safe_str_eq(value, "migrate")) {
1049 action->on_fail = action_fail_migrate;
1050 value = "force migration";
1051
1052 } else if (safe_str_eq(value, "stop")) {
1053 action->on_fail = action_fail_stop;
1054 action->fail_role = RSC_ROLE_STOPPED;
1055 value = "stop resource";
1056
1057 } else if (safe_str_eq(value, "restart")) {
1058 action->on_fail = action_fail_recover;
1059 value = "restart (and possibly migrate)";
1060
1061 } else if (safe_str_eq(value, "restart-container")) {
1062 if (container) {
1063 action->on_fail = action_fail_restart_container;
1064 value = "restart container (and possibly migrate)";
1065
1066 } else {
1067 value = NULL;
1068 }
1069
1070 } else {
1071 pe_err("Resource %s: Unknown failure type (%s)", action->rsc->id, value);
1072 value = NULL;
1073 }
1074
1075
1076 if (value == NULL && container) {
1077 action->on_fail = action_fail_restart_container;
1078 value = "restart container (and possibly migrate) (default)";
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089 } else if (((value == NULL) || !is_set(action->rsc->flags, pe_rsc_managed)) &&
1090 (is_rsc_baremetal_remote_node(action->rsc, data_set) &&
1091 !(safe_str_eq(action->task, CRMD_ACTION_STATUS) && interval == 0) &&
1092 (safe_str_neq(action->task, CRMD_ACTION_START)))) {
1093
1094 if (!is_set(action->rsc->flags, pe_rsc_managed)) {
1095 action->on_fail = action_fail_stop;
1096 action->fail_role = RSC_ROLE_STOPPED;
1097 value = "stop unmanaged baremetal remote node (enforcing default)";
1098
1099 } else {
1100 if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1101 value = "fence baremetal remote node (default)";
1102 } else {
1103 value = "recover baremetal remote node connection (default)";
1104 }
1105
1106 if (action->rsc->remote_reconnect_interval) {
1107 action->fail_role = RSC_ROLE_STOPPED;
1108 }
1109 action->on_fail = action_fail_reset_remote;
1110 }
1111
1112 } else if (value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
1113 if (is_set(data_set->flags, pe_flag_stonith_enabled)) {
1114 action->on_fail = action_fail_fence;
1115 value = "resource fence (default)";
1116
1117 } else {
1118 action->on_fail = action_fail_block;
1119 value = "resource block (default)";
1120 }
1121
1122 } else if (value == NULL) {
1123 action->on_fail = action_fail_recover;
1124 value = "restart (and possibly migrate) (default)";
1125 }
1126
1127 pe_rsc_trace(action->rsc, "\t%s failure handling: %s", action->task, value);
1128
1129 value = NULL;
1130 if (xml_obj != NULL) {
1131 value = g_hash_table_lookup(action->meta, "role_after_failure");
1132 }
1133 if (value != NULL && action->fail_role == RSC_ROLE_UNKNOWN) {
1134 action->fail_role = text2role(value);
1135 }
1136
1137 if (action->fail_role == RSC_ROLE_UNKNOWN) {
1138 if (safe_str_eq(action->task, CRMD_ACTION_PROMOTE)) {
1139 action->fail_role = RSC_ROLE_SLAVE;
1140 } else {
1141 action->fail_role = RSC_ROLE_STARTED;
1142 }
1143 }
1144 pe_rsc_trace(action->rsc, "\t%s failure results in: %s", action->task,
1145 role2text(action->fail_role));
1146
1147 field = XML_OP_ATTR_START_DELAY;
1148 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_START_DELAY);
1149 if (value) {
1150 unpack_start_delay(value, action->meta);
1151 } else {
1152 value = g_hash_table_lookup(action->meta, XML_OP_ATTR_ORIGIN);
1153 unpack_interval_origin(value, action->meta, xml_obj, interval, data_set->now);
1154 }
1155
1156 field = XML_ATTR_TIMEOUT;
1157 value = g_hash_table_lookup(action->meta, field);
1158 timeout = unpack_timeout(value, action, xml_obj, interval, data_set->config_hash);
1159 g_hash_table_replace(action->meta, strdup(XML_ATTR_TIMEOUT), crm_itoa(timeout));
1160
1161 #if ENABLE_VERSIONED_ATTRS
1162 unpack_versioned_meta(rsc_details->versioned_meta, xml_obj, interval,
1163 data_set->now);
1164 #endif
1165 }
1166
1167 static xmlNode *
1168 find_rsc_op_entry_helper(resource_t * rsc, const char *key, gboolean include_disabled)
1169 {
1170 unsigned long long number = 0;
1171 gboolean do_retry = TRUE;
1172 char *local_key = NULL;
1173 const char *name = NULL;
1174 const char *value = NULL;
1175 const char *interval = NULL;
1176 char *match_key = NULL;
1177 xmlNode *op = NULL;
1178 xmlNode *operation = NULL;
1179
1180 retry:
1181 for (operation = __xml_first_child(rsc->ops_xml); operation != NULL;
1182 operation = __xml_next_element(operation)) {
1183 if (crm_str_eq((const char *)operation->name, "op", TRUE)) {
1184 name = crm_element_value(operation, "name");
1185 interval = crm_element_value(operation, XML_LRM_ATTR_INTERVAL);
1186 value = crm_element_value(operation, "enabled");
1187 if (!include_disabled && value && crm_is_true(value) == FALSE) {
1188 continue;
1189 }
1190
1191 number = crm_get_interval(interval);
1192 match_key = generate_op_key(rsc->id, name, number);
1193 if (safe_str_eq(key, match_key)) {
1194 op = operation;
1195 }
1196 free(match_key);
1197
1198 if (rsc->clone_name) {
1199 match_key = generate_op_key(rsc->clone_name, name, number);
1200 if (safe_str_eq(key, match_key)) {
1201 op = operation;
1202 }
1203 free(match_key);
1204 }
1205
1206 if (op != NULL) {
1207 free(local_key);
1208 return op;
1209 }
1210 }
1211 }
1212
1213 free(local_key);
1214 if (do_retry == FALSE) {
1215 return NULL;
1216 }
1217
1218 do_retry = FALSE;
1219 if (strstr(key, CRMD_ACTION_MIGRATE) || strstr(key, CRMD_ACTION_MIGRATED)) {
1220 local_key = generate_op_key(rsc->id, "migrate", 0);
1221 key = local_key;
1222 goto retry;
1223
1224 } else if (strstr(key, "_notify_")) {
1225 local_key = generate_op_key(rsc->id, "notify", 0);
1226 key = local_key;
1227 goto retry;
1228 }
1229
1230 return NULL;
1231 }
1232
1233 xmlNode *
1234 find_rsc_op_entry(resource_t * rsc, const char *key)
1235 {
1236 return find_rsc_op_entry_helper(rsc, key, FALSE);
1237 }
1238
1239 void
1240 print_node(const char *pre_text, node_t * node, gboolean details)
1241 {
1242 if (node == NULL) {
1243 crm_trace("%s%s: <NULL>", pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1244 return;
1245 }
1246
1247 CRM_ASSERT(node->details);
1248 crm_trace("%s%s%sNode %s: (weight=%d, fixed=%s)",
1249 pre_text == NULL ? "" : pre_text,
1250 pre_text == NULL ? "" : ": ",
1251 node->details->online ? "" : "Unavailable/Unclean ",
1252 node->details->uname, node->weight, node->fixed ? "True" : "False");
1253
1254 if (details) {
1255 char *pe_mutable = strdup("\t\t");
1256 GListPtr gIter = node->details->running_rsc;
1257
1258 crm_trace("\t\t===Node Attributes");
1259 g_hash_table_foreach(node->details->attrs, print_str_str, pe_mutable);
1260 free(pe_mutable);
1261
1262 crm_trace("\t\t=== Resources");
1263
1264 for (; gIter != NULL; gIter = gIter->next) {
1265 resource_t *rsc = (resource_t *) gIter->data;
1266
1267 print_resource(LOG_DEBUG_4, "\t\t", rsc, FALSE);
1268 }
1269 }
1270 }
1271
1272
1273
1274
1275 void
1276 print_str_str(gpointer key, gpointer value, gpointer user_data)
1277 {
1278 crm_trace("%s%s %s ==> %s",
1279 user_data == NULL ? "" : (char *)user_data,
1280 user_data == NULL ? "" : ": ", (char *)key, (char *)value);
1281 }
1282
1283 void
1284 print_resource(int log_level, const char *pre_text, resource_t * rsc, gboolean details)
1285 {
1286 long options = pe_print_log | pe_print_pending;
1287
1288 if (rsc == NULL) {
1289 do_crm_log(log_level - 1, "%s%s: <NULL>",
1290 pre_text == NULL ? "" : pre_text, pre_text == NULL ? "" : ": ");
1291 return;
1292 }
1293 if (details) {
1294 options |= pe_print_details;
1295 }
1296 rsc->fns->print(rsc, pre_text, options, &log_level);
1297 }
1298
1299 void
1300 pe_free_action(action_t * action)
1301 {
1302 if (action == NULL) {
1303 return;
1304 }
1305 g_list_free_full(action->actions_before, free);
1306 g_list_free_full(action->actions_after, free);
1307 if (action->extra) {
1308 g_hash_table_destroy(action->extra);
1309 }
1310 if (action->meta) {
1311 g_hash_table_destroy(action->meta);
1312 }
1313 #if ENABLE_VERSIONED_ATTRS
1314 if (action->rsc) {
1315 pe_free_rsc_action_details(action);
1316 }
1317 #endif
1318 free(action->cancel_task);
1319 free(action->reason);
1320 free(action->task);
1321 free(action->uuid);
1322 free(action->node);
1323 free(action);
1324 }
1325
1326 GListPtr
1327 find_recurring_actions(GListPtr input, node_t * not_on_node)
1328 {
1329 const char *value = NULL;
1330 GListPtr result = NULL;
1331 GListPtr gIter = input;
1332
1333 CRM_CHECK(input != NULL, return NULL);
1334
1335 for (; gIter != NULL; gIter = gIter->next) {
1336 action_t *action = (action_t *) gIter->data;
1337
1338 value = g_hash_table_lookup(action->meta, XML_LRM_ATTR_INTERVAL);
1339 if (value == NULL) {
1340
1341 } else if (safe_str_eq(value, "0")) {
1342
1343 } else if (safe_str_eq(CRMD_ACTION_CANCEL, action->task)) {
1344
1345 } else if (not_on_node == NULL) {
1346 crm_trace("(null) Found: %s", action->uuid);
1347 result = g_list_prepend(result, action);
1348
1349 } else if (action->node == NULL) {
1350
1351 } else if (action->node->details != not_on_node->details) {
1352 crm_trace("Found: %s", action->uuid);
1353 result = g_list_prepend(result, action);
1354 }
1355 }
1356
1357 return result;
1358 }
1359
1360 enum action_tasks
1361 get_complex_task(resource_t * rsc, const char *name, gboolean allow_non_atomic)
1362 {
1363 enum action_tasks task = text2task(name);
1364
1365 if (rsc == NULL) {
1366 return task;
1367
1368 } else if (allow_non_atomic == FALSE || rsc->variant == pe_native) {
1369 switch (task) {
1370 case stopped_rsc:
1371 case started_rsc:
1372 case action_demoted:
1373 case action_promoted:
1374 crm_trace("Folding %s back into its atomic counterpart for %s", name, rsc->id);
1375 return task - 1;
1376 break;
1377 default:
1378 break;
1379 }
1380 }
1381 return task;
1382 }
1383
1384 action_t *
1385 find_first_action(GListPtr input, const char *uuid, const char *task, node_t * on_node)
1386 {
1387 GListPtr gIter = NULL;
1388
1389 CRM_CHECK(uuid || task, return NULL);
1390
1391 for (gIter = input; gIter != NULL; gIter = gIter->next) {
1392 action_t *action = (action_t *) gIter->data;
1393
1394 if (uuid != NULL && safe_str_neq(uuid, action->uuid)) {
1395 continue;
1396
1397 } else if (task != NULL && safe_str_neq(task, action->task)) {
1398 continue;
1399
1400 } else if (on_node == NULL) {
1401 return action;
1402
1403 } else if (action->node == NULL) {
1404 continue;
1405
1406 } else if (on_node->details == action->node->details) {
1407 return action;
1408 }
1409 }
1410
1411 return NULL;
1412 }
1413
1414 GListPtr
1415 find_actions(GListPtr input, const char *key, const node_t *on_node)
1416 {
1417 GListPtr gIter = input;
1418 GListPtr result = NULL;
1419
1420 CRM_CHECK(key != NULL, return NULL);
1421
1422 for (; gIter != NULL; gIter = gIter->next) {
1423 action_t *action = (action_t *) gIter->data;
1424
1425 if (safe_str_neq(key, action->uuid)) {
1426 crm_trace("%s does not match action %s", key, action->uuid);
1427 continue;
1428
1429 } else if (on_node == NULL) {
1430 crm_trace("Action %s matches (ignoring node)", key);
1431 result = g_list_prepend(result, action);
1432
1433 } else if (action->node == NULL) {
1434 crm_trace("Action %s matches (unallocated, assigning to %s)",
1435 key, on_node->details->uname);
1436
1437 action->node = node_copy(on_node);
1438 result = g_list_prepend(result, action);
1439
1440 } else if (on_node->details == action->node->details) {
1441 crm_trace("Action %s on %s matches", key, on_node->details->uname);
1442 result = g_list_prepend(result, action);
1443
1444 } else {
1445 crm_trace("Action %s on node %s does not match requested node %s",
1446 key, action->node->details->uname,
1447 on_node->details->uname);
1448 }
1449 }
1450
1451 return result;
1452 }
1453
1454 GListPtr
1455 find_actions_exact(GListPtr input, const char *key, node_t * on_node)
1456 {
1457 GListPtr gIter = input;
1458 GListPtr result = NULL;
1459
1460 CRM_CHECK(key != NULL, return NULL);
1461
1462 for (; gIter != NULL; gIter = gIter->next) {
1463 action_t *action = (action_t *) gIter->data;
1464
1465 crm_trace("Matching %s against %s", key, action->uuid);
1466 if (safe_str_neq(key, action->uuid)) {
1467 crm_trace("Key mismatch: %s vs. %s", key, action->uuid);
1468 continue;
1469
1470 } else if (on_node == NULL || action->node == NULL) {
1471 crm_trace("on_node=%p, action->node=%p", on_node, action->node);
1472 continue;
1473
1474 } else if (safe_str_eq(on_node->details->id, action->node->details->id)) {
1475 result = g_list_prepend(result, action);
1476 }
1477 crm_trace("Node mismatch: %s vs. %s", on_node->details->id, action->node->details->id);
1478 }
1479
1480 return result;
1481 }
1482
1483 static void
1484 resource_node_score(resource_t * rsc, node_t * node, int score, const char *tag)
1485 {
1486 node_t *match = NULL;
1487
1488 if ((rsc->exclusive_discover || (node->rsc_discover_mode == pe_discover_never))
1489 && safe_str_eq(tag, "symmetric_default")) {
1490
1491
1492
1493
1494 return;
1495
1496 } else if (rsc->children) {
1497 GListPtr gIter = rsc->children;
1498
1499 for (; gIter != NULL; gIter = gIter->next) {
1500 resource_t *child_rsc = (resource_t *) gIter->data;
1501
1502 resource_node_score(child_rsc, node, score, tag);
1503 }
1504 }
1505
1506 pe_rsc_trace(rsc, "Setting %s for %s on %s: %d", tag, rsc->id, node->details->uname, score);
1507 match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
1508 if (match == NULL) {
1509 match = node_copy(node);
1510 g_hash_table_insert(rsc->allowed_nodes, (gpointer) match->details->id, match);
1511 }
1512 match->weight = merge_weights(match->weight, score);
1513 }
1514
1515 void
1516 resource_location(resource_t * rsc, node_t * node, int score, const char *tag,
1517 pe_working_set_t * data_set)
1518 {
1519 if (node != NULL) {
1520 resource_node_score(rsc, node, score, tag);
1521
1522 } else if (data_set != NULL) {
1523 GListPtr gIter = data_set->nodes;
1524
1525 for (; gIter != NULL; gIter = gIter->next) {
1526 node_t *node_iter = (node_t *) gIter->data;
1527
1528 resource_node_score(rsc, node_iter, score, tag);
1529 }
1530
1531 } else {
1532 GHashTableIter iter;
1533 node_t *node_iter = NULL;
1534
1535 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
1536 while (g_hash_table_iter_next(&iter, NULL, (void **)&node_iter)) {
1537 resource_node_score(rsc, node_iter, score, tag);
1538 }
1539 }
1540
1541 if (node == NULL && score == -INFINITY) {
1542 if (rsc->allocated_to) {
1543 crm_info("Deallocating %s from %s", rsc->id, rsc->allocated_to->details->uname);
1544 free(rsc->allocated_to);
1545 rsc->allocated_to = NULL;
1546 }
1547 }
1548 }
1549
1550 #define sort_return(an_int, why) do { \
1551 free(a_uuid); \
1552 free(b_uuid); \
1553 crm_trace("%s (%d) %c %s (%d) : %s", \
1554 a_xml_id, a_call_id, an_int>0?'>':an_int<0?'<':'=', \
1555 b_xml_id, b_call_id, why); \
1556 return an_int; \
1557 } while(0)
1558
1559 gint
1560 sort_op_by_callid(gconstpointer a, gconstpointer b)
1561 {
1562 int a_call_id = -1;
1563 int b_call_id = -1;
1564
1565 char *a_uuid = NULL;
1566 char *b_uuid = NULL;
1567
1568 const xmlNode *xml_a = a;
1569 const xmlNode *xml_b = b;
1570
1571 const char *a_xml_id = crm_element_value_const(xml_a, XML_ATTR_ID);
1572 const char *b_xml_id = crm_element_value_const(xml_b, XML_ATTR_ID);
1573
1574 if (safe_str_eq(a_xml_id, b_xml_id)) {
1575
1576
1577
1578
1579
1580 pe_err("Duplicate lrm_rsc_op entries named %s", a_xml_id);
1581 sort_return(0, "duplicate");
1582 }
1583
1584 crm_element_value_const_int(xml_a, XML_LRM_ATTR_CALLID, &a_call_id);
1585 crm_element_value_const_int(xml_b, XML_LRM_ATTR_CALLID, &b_call_id);
1586
1587 if (a_call_id == -1 && b_call_id == -1) {
1588
1589
1590
1591 sort_return(0, "pending");
1592
1593 } else if (a_call_id >= 0 && a_call_id < b_call_id) {
1594 sort_return(-1, "call id");
1595
1596 } else if (b_call_id >= 0 && a_call_id > b_call_id) {
1597 sort_return(1, "call id");
1598
1599 } else if (b_call_id >= 0 && a_call_id == b_call_id) {
1600
1601
1602
1603
1604 int last_a = -1;
1605 int last_b = -1;
1606
1607 crm_element_value_const_int(xml_a, XML_RSC_OP_LAST_CHANGE, &last_a);
1608 crm_element_value_const_int(xml_b, XML_RSC_OP_LAST_CHANGE, &last_b);
1609
1610 crm_trace("rc-change: %d vs %d", last_a, last_b);
1611 if (last_a >= 0 && last_a < last_b) {
1612 sort_return(-1, "rc-change");
1613
1614 } else if (last_b >= 0 && last_a > last_b) {
1615 sort_return(1, "rc-change");
1616 }
1617 sort_return(0, "rc-change");
1618
1619 } else {
1620
1621
1622
1623
1624 int a_id = -1;
1625 int b_id = -1;
1626 int dummy = -1;
1627
1628 const char *a_magic = crm_element_value_const(xml_a, XML_ATTR_TRANSITION_MAGIC);
1629 const char *b_magic = crm_element_value_const(xml_b, XML_ATTR_TRANSITION_MAGIC);
1630
1631 CRM_CHECK(a_magic != NULL && b_magic != NULL, sort_return(0, "No magic"));
1632 if(!decode_transition_magic(a_magic, &a_uuid, &a_id, &dummy, &dummy, &dummy, &dummy)) {
1633 sort_return(0, "bad magic a");
1634 }
1635 if(!decode_transition_magic(b_magic, &b_uuid, &b_id, &dummy, &dummy, &dummy, &dummy)) {
1636 sort_return(0, "bad magic b");
1637 }
1638
1639
1640
1641
1642
1643
1644 if (safe_str_neq(a_uuid, b_uuid) || a_id == b_id) {
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654 if (b_call_id == -1) {
1655 sort_return(-1, "transition + call");
1656
1657 } else if (a_call_id == -1) {
1658 sort_return(1, "transition + call");
1659 }
1660
1661 } else if ((a_id >= 0 && a_id < b_id) || b_id == -1) {
1662 sort_return(-1, "transition");
1663
1664 } else if ((b_id >= 0 && a_id > b_id) || a_id == -1) {
1665 sort_return(1, "transition");
1666 }
1667 }
1668
1669
1670 CRM_CHECK(FALSE, sort_return(0, "default"));
1671
1672 }
1673
1674 time_t
1675 get_effective_time(pe_working_set_t * data_set)
1676 {
1677 if(data_set) {
1678 if (data_set->now == NULL) {
1679 crm_trace("Recording a new 'now'");
1680 data_set->now = crm_time_new(NULL);
1681 }
1682 return crm_time_get_seconds_since_epoch(data_set->now);
1683 }
1684
1685 crm_trace("Defaulting to 'now'");
1686 return time(NULL);
1687 }
1688
1689 gboolean
1690 get_target_role(resource_t * rsc, enum rsc_role_e * role)
1691 {
1692 enum rsc_role_e local_role = RSC_ROLE_UNKNOWN;
1693 const char *value = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET_ROLE);
1694
1695 CRM_CHECK(role != NULL, return FALSE);
1696
1697 if (value == NULL || safe_str_eq("started", value)
1698 || safe_str_eq("default", value)) {
1699 return FALSE;
1700 }
1701
1702 local_role = text2role(value);
1703 if (local_role == RSC_ROLE_UNKNOWN) {
1704 crm_config_err("%s: Unknown value for %s: %s", rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1705 return FALSE;
1706
1707 } else if (local_role > RSC_ROLE_STARTED) {
1708 if (uber_parent(rsc)->variant == pe_master) {
1709 if (local_role > RSC_ROLE_SLAVE) {
1710
1711 return FALSE;
1712 }
1713
1714 } else {
1715 crm_config_err("%s is not part of a master/slave resource, a %s of '%s' makes no sense",
1716 rsc->id, XML_RSC_ATTR_TARGET_ROLE, value);
1717 return FALSE;
1718 }
1719 }
1720
1721 *role = local_role;
1722 return TRUE;
1723 }
1724
1725 gboolean
1726 order_actions(action_t * lh_action, action_t * rh_action, enum pe_ordering order)
1727 {
1728 GListPtr gIter = NULL;
1729 action_wrapper_t *wrapper = NULL;
1730 GListPtr list = NULL;
1731
1732 if (order == pe_order_none) {
1733 return FALSE;
1734 }
1735
1736 if (lh_action == NULL || rh_action == NULL) {
1737 return FALSE;
1738 }
1739
1740 crm_trace("Ordering Action %s before %s", lh_action->uuid, rh_action->uuid);
1741
1742
1743 CRM_ASSERT(lh_action != rh_action);
1744
1745
1746 gIter = lh_action->actions_after;
1747 for (; gIter != NULL; gIter = gIter->next) {
1748 action_wrapper_t *after = (action_wrapper_t *) gIter->data;
1749
1750 if (after->action == rh_action && (after->type & order)) {
1751 return FALSE;
1752 }
1753 }
1754
1755 wrapper = calloc(1, sizeof(action_wrapper_t));
1756 wrapper->action = rh_action;
1757 wrapper->type = order;
1758
1759 list = lh_action->actions_after;
1760 list = g_list_prepend(list, wrapper);
1761 lh_action->actions_after = list;
1762
1763 wrapper = NULL;
1764
1765
1766
1767
1768 wrapper = calloc(1, sizeof(action_wrapper_t));
1769 wrapper->action = lh_action;
1770 wrapper->type = order;
1771 list = rh_action->actions_before;
1772 list = g_list_prepend(list, wrapper);
1773 rh_action->actions_before = list;
1774 return TRUE;
1775 }
1776
1777 action_t *
1778 get_pseudo_op(const char *name, pe_working_set_t * data_set)
1779 {
1780 action_t *op = NULL;
1781
1782 if(data_set->singletons) {
1783 op = g_hash_table_lookup(data_set->singletons, name);
1784 }
1785 if (op == NULL) {
1786 op = custom_action(NULL, strdup(name), name, NULL, TRUE, TRUE, data_set);
1787 set_bit(op->flags, pe_action_pseudo);
1788 set_bit(op->flags, pe_action_runnable);
1789 }
1790
1791 return op;
1792 }
1793
1794 void
1795 destroy_ticket(gpointer data)
1796 {
1797 ticket_t *ticket = data;
1798
1799 if (ticket->state) {
1800 g_hash_table_destroy(ticket->state);
1801 }
1802 free(ticket->id);
1803 free(ticket);
1804 }
1805
1806 ticket_t *
1807 ticket_new(const char *ticket_id, pe_working_set_t * data_set)
1808 {
1809 ticket_t *ticket = NULL;
1810
1811 if (ticket_id == NULL || strlen(ticket_id) == 0) {
1812 return NULL;
1813 }
1814
1815 if (data_set->tickets == NULL) {
1816 data_set->tickets =
1817 g_hash_table_new_full(crm_str_hash, g_str_equal, g_hash_destroy_str, destroy_ticket);
1818 }
1819
1820 ticket = g_hash_table_lookup(data_set->tickets, ticket_id);
1821 if (ticket == NULL) {
1822
1823 ticket = calloc(1, sizeof(ticket_t));
1824 if (ticket == NULL) {
1825 crm_err("Cannot allocate ticket '%s'", ticket_id);
1826 return NULL;
1827 }
1828
1829 crm_trace("Creaing ticket entry for %s", ticket_id);
1830
1831 ticket->id = strdup(ticket_id);
1832 ticket->granted = FALSE;
1833 ticket->last_granted = -1;
1834 ticket->standby = FALSE;
1835 ticket->state = crm_str_table_new();
1836
1837 g_hash_table_insert(data_set->tickets, strdup(ticket->id), ticket);
1838 }
1839
1840 return ticket;
1841 }
1842
1843 static void
1844 filter_parameters(xmlNode * param_set, const char *param_string, bool need_present)
1845 {
1846 if (param_set && param_string) {
1847 xmlAttrPtr xIter = param_set->properties;
1848
1849 while (xIter) {
1850 const char *prop_name = (const char *)xIter->name;
1851 char *name = crm_strdup_printf(" %s ", prop_name);
1852 char *match = strstr(param_string, name);
1853
1854 free(name);
1855
1856
1857 xIter = xIter->next;
1858
1859 if (need_present && match == NULL) {
1860 crm_trace("%s not found in %s", prop_name, param_string);
1861 xml_remove_prop(param_set, prop_name);
1862
1863 } else if (need_present == FALSE && match) {
1864 crm_trace("%s found in %s", prop_name, param_string);
1865 xml_remove_prop(param_set, prop_name);
1866 }
1867 }
1868 }
1869 }
1870
1871 #if ENABLE_VERSIONED_ATTRS
1872 static void
1873 append_versioned_params(xmlNode *versioned_params, const char *ra_version, xmlNode *params)
1874 {
1875 GHashTable *hash = pe_unpack_versioned_parameters(versioned_params, ra_version);
1876 char *key = NULL;
1877 char *value = NULL;
1878 GHashTableIter iter;
1879
1880 g_hash_table_iter_init(&iter, hash);
1881 while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value)) {
1882 crm_xml_add(params, key, value);
1883 }
1884 g_hash_table_destroy(hash);
1885 }
1886 #endif
1887
1888 static op_digest_cache_t *
1889 rsc_action_digest(resource_t * rsc, const char *task, const char *key,
1890 node_t * node, xmlNode * xml_op, pe_working_set_t * data_set)
1891 {
1892 op_digest_cache_t *data = NULL;
1893
1894 data = g_hash_table_lookup(node->details->digest_cache, key);
1895 if (data == NULL) {
1896 GHashTable *local_rsc_params = crm_str_table_new();
1897 action_t *action = custom_action(rsc, strdup(key), task, node, TRUE, FALSE, data_set);
1898 #if ENABLE_VERSIONED_ATTRS
1899 xmlNode *local_versioned_params = create_xml_node(NULL, XML_TAG_RSC_VER_ATTRS);
1900 const char *ra_version = NULL;
1901 #endif
1902
1903 const char *op_version;
1904 const char *restart_list = NULL;
1905 const char *secure_list = " passwd password ";
1906
1907 data = calloc(1, sizeof(op_digest_cache_t));
1908 CRM_ASSERT(data != NULL);
1909
1910 get_rsc_attributes(local_rsc_params, rsc, node, data_set);
1911 #if ENABLE_VERSIONED_ATTRS
1912 pe_get_versioned_attributes(local_versioned_params, rsc, node, data_set);
1913 #endif
1914
1915 data->params_all = create_xml_node(NULL, XML_TAG_PARAMS);
1916
1917
1918 if (container_fix_remote_addr_in(rsc, data->params_all, "addr")) {
1919 crm_trace("Fixed addr for %s on %s", rsc->id, node->details->uname);
1920 }
1921
1922 g_hash_table_foreach(local_rsc_params, hash2field, data->params_all);
1923 g_hash_table_foreach(action->extra, hash2field, data->params_all);
1924 g_hash_table_foreach(rsc->parameters, hash2field, data->params_all);
1925 g_hash_table_foreach(action->meta, hash2metafield, data->params_all);
1926
1927 if(xml_op) {
1928 secure_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_SECURE);
1929 restart_list = crm_element_value(xml_op, XML_LRM_ATTR_OP_RESTART);
1930
1931 op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
1932 #if ENABLE_VERSIONED_ATTRS
1933 ra_version = crm_element_value(xml_op, XML_ATTR_RA_VERSION);
1934 #endif
1935
1936 } else {
1937 op_version = CRM_FEATURE_SET;
1938 }
1939
1940 #if ENABLE_VERSIONED_ATTRS
1941 append_versioned_params(local_versioned_params, ra_version, data->params_all);
1942 append_versioned_params(rsc->versioned_parameters, ra_version, data->params_all);
1943
1944 {
1945 pe_rsc_action_details_t *details = pe_rsc_action_details(action);
1946 append_versioned_params(details->versioned_parameters, ra_version, data->params_all);
1947 }
1948 #endif
1949
1950 filter_action_parameters(data->params_all, op_version);
1951
1952 g_hash_table_destroy(local_rsc_params);
1953 pe_free_action(action);
1954
1955 data->digest_all_calc = calculate_operation_digest(data->params_all, op_version);
1956
1957 if (is_set(data_set->flags, pe_flag_sanitized)) {
1958 data->params_secure = copy_xml(data->params_all);
1959 if(secure_list) {
1960 filter_parameters(data->params_secure, secure_list, FALSE);
1961 }
1962 data->digest_secure_calc = calculate_operation_digest(data->params_secure, op_version);
1963 }
1964
1965 if(xml_op && crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST) != NULL) {
1966 data->params_restart = copy_xml(data->params_all);
1967 if (restart_list) {
1968 filter_parameters(data->params_restart, restart_list, TRUE);
1969 }
1970 data->digest_restart_calc = calculate_operation_digest(data->params_restart, op_version);
1971 }
1972
1973 g_hash_table_insert(node->details->digest_cache, strdup(key), data);
1974 }
1975
1976 return data;
1977 }
1978
1979 op_digest_cache_t *
1980 rsc_action_digest_cmp(resource_t * rsc, xmlNode * xml_op, node_t * node,
1981 pe_working_set_t * data_set)
1982 {
1983 op_digest_cache_t *data = NULL;
1984
1985 char *key = NULL;
1986 int interval = 0;
1987
1988 const char *op_version;
1989 const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
1990 const char *interval_s = crm_element_value(xml_op, XML_LRM_ATTR_INTERVAL);
1991
1992 const char *digest_all;
1993 const char *digest_restart;
1994
1995 CRM_ASSERT(node != NULL);
1996
1997 op_version = crm_element_value(xml_op, XML_ATTR_CRM_VERSION);
1998 digest_all = crm_element_value(xml_op, XML_LRM_ATTR_OP_DIGEST);
1999 digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
2000
2001 interval = crm_parse_int(interval_s, "0");
2002 key = generate_op_key(rsc->id, task, interval);
2003 data = rsc_action_digest(rsc, task, key, node, xml_op, data_set);
2004
2005 data->rc = RSC_DIGEST_MATCH;
2006 if (digest_restart && data->digest_restart_calc && strcmp(data->digest_restart_calc, digest_restart) != 0) {
2007 pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (restart:%s) %s",
2008 key, node->details->uname,
2009 crm_str(digest_restart), data->digest_restart_calc,
2010 op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2011 data->rc = RSC_DIGEST_RESTART;
2012
2013 } else if (digest_all == NULL) {
2014
2015 data->rc = RSC_DIGEST_UNKNOWN;
2016
2017 } else if (strcmp(digest_all, data->digest_all_calc) != 0) {
2018 pe_rsc_info(rsc, "Parameters to %s on %s changed: was %s vs. now %s (%s:%s) %s",
2019 key, node->details->uname,
2020 crm_str(digest_all), data->digest_all_calc,
2021 (interval > 0)? "reschedule" : "reload",
2022 op_version, crm_element_value(xml_op, XML_ATTR_TRANSITION_MAGIC));
2023 data->rc = RSC_DIGEST_ALL;
2024 }
2025
2026 free(key);
2027 return data;
2028 }
2029
2030 #define STONITH_DIGEST_TASK "stonith-on"
2031
2032 static op_digest_cache_t *
2033 fencing_action_digest_cmp(resource_t * rsc, node_t * node, pe_working_set_t * data_set)
2034 {
2035 char *key = generate_op_key(rsc->id, STONITH_DIGEST_TASK, 0);
2036 op_digest_cache_t *data = rsc_action_digest(rsc, STONITH_DIGEST_TASK, key, node, NULL, data_set);
2037
2038 const char *digest_all = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_ALL);
2039 const char *digest_secure = pe_node_attribute_raw(node, CRM_ATTR_DIGESTS_SECURE);
2040
2041
2042
2043
2044
2045
2046 char *search_all = crm_strdup_printf("%s:%s:%s", rsc->id, (const char*)g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE), data->digest_all_calc);
2047 char *search_secure = crm_strdup_printf("%s:%s:%s", rsc->id, (const char*)g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE), data->digest_secure_calc);
2048
2049 data->rc = RSC_DIGEST_ALL;
2050 if (digest_all == NULL) {
2051
2052 data->rc = RSC_DIGEST_UNKNOWN;
2053
2054 } else if (strstr(digest_all, search_all)) {
2055 data->rc = RSC_DIGEST_MATCH;
2056
2057 } else if(digest_secure && data->digest_secure_calc) {
2058 if(strstr(digest_secure, search_secure)) {
2059 if (is_set(data_set->flags, pe_flag_sanitized)) {
2060 printf("Only 'private' parameters to %s for unfencing %s changed\n",
2061 rsc->id, node->details->uname);
2062 }
2063 data->rc = RSC_DIGEST_MATCH;
2064 }
2065 }
2066
2067 if (data->rc == RSC_DIGEST_ALL && is_set(data_set->flags, pe_flag_sanitized) && data->digest_secure_calc) {
2068 if (is_set(data_set->flags, pe_flag_sanitized)) {
2069 printf("Parameters to %s for unfencing %s changed, try '%s:%s:%s'\n",
2070 rsc->id, node->details->uname, rsc->id,
2071 (const char *) g_hash_table_lookup(rsc->meta, XML_ATTR_TYPE),
2072 data->digest_secure_calc);
2073 }
2074 }
2075
2076 free(key);
2077 free(search_all);
2078 free(search_secure);
2079
2080 return data;
2081 }
2082
2083 const char *rsc_printable_id(resource_t *rsc)
2084 {
2085 if (is_not_set(rsc->flags, pe_rsc_unique)) {
2086 return ID(rsc->xml);
2087 }
2088 return rsc->id;
2089 }
2090
2091 void
2092 clear_bit_recursive(resource_t * rsc, unsigned long long flag)
2093 {
2094 GListPtr gIter = rsc->children;
2095
2096 clear_bit(rsc->flags, flag);
2097 for (; gIter != NULL; gIter = gIter->next) {
2098 resource_t *child_rsc = (resource_t *) gIter->data;
2099
2100 clear_bit_recursive(child_rsc, flag);
2101 }
2102 }
2103
2104 void
2105 set_bit_recursive(resource_t * rsc, unsigned long long flag)
2106 {
2107 GListPtr gIter = rsc->children;
2108
2109 set_bit(rsc->flags, flag);
2110 for (; gIter != NULL; gIter = gIter->next) {
2111 resource_t *child_rsc = (resource_t *) gIter->data;
2112
2113 set_bit_recursive(child_rsc, flag);
2114 }
2115 }
2116
2117 static GListPtr
2118 find_unfencing_devices(GListPtr candidates, GListPtr matches)
2119 {
2120 for (GListPtr gIter = candidates; gIter != NULL; gIter = gIter->next) {
2121 resource_t *candidate = gIter->data;
2122 const char *provides = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_PROVIDES);
2123 const char *requires = g_hash_table_lookup(candidate->meta, XML_RSC_ATTR_REQUIRES);
2124
2125 if(candidate->children) {
2126 matches = find_unfencing_devices(candidate->children, matches);
2127 } else if (is_not_set(candidate->flags, pe_rsc_fence_device)) {
2128 continue;
2129
2130 } else if (crm_str_eq(provides, "unfencing", FALSE) || crm_str_eq(requires, "unfencing", FALSE)) {
2131 matches = g_list_prepend(matches, candidate);
2132 }
2133 }
2134 return matches;
2135 }
2136
2137
2138 action_t *
2139 pe_fence_op(node_t * node, const char *op, bool optional, const char *reason, pe_working_set_t * data_set)
2140 {
2141 char *op_key = NULL;
2142 action_t *stonith_op = NULL;
2143
2144 if(op == NULL) {
2145 op = data_set->stonith_action;
2146 }
2147
2148 op_key = crm_strdup_printf("%s-%s-%s", CRM_OP_FENCE, node->details->uname, op);
2149
2150 if(data_set->singletons) {
2151 stonith_op = g_hash_table_lookup(data_set->singletons, op_key);
2152 }
2153
2154 if(stonith_op == NULL) {
2155 stonith_op = custom_action(NULL, op_key, CRM_OP_FENCE, node, TRUE, TRUE, data_set);
2156
2157 add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET, node->details->uname);
2158 add_hash_param(stonith_op->meta, XML_LRM_ATTR_TARGET_UUID, node->details->id);
2159 add_hash_param(stonith_op->meta, "stonith_action", op);
2160
2161 if(is_remote_node(node) && is_set(data_set->flags, pe_flag_enable_unfencing)) {
2162
2163
2164
2165
2166
2167
2168
2169
2170 long max = 1024;
2171 long digests_all_offset = 0;
2172 long digests_secure_offset = 0;
2173
2174 char *digests_all = malloc(max);
2175 char *digests_secure = malloc(max);
2176 GListPtr matches = find_unfencing_devices(data_set->resources, NULL);
2177
2178 for (GListPtr gIter = matches; gIter != NULL; gIter = gIter->next) {
2179 resource_t *match = gIter->data;
2180 op_digest_cache_t *data = fencing_action_digest_cmp(match, node, data_set);
2181
2182 if(data->rc == RSC_DIGEST_ALL) {
2183 optional = FALSE;
2184 crm_notice("Unfencing %s (remote): because the definition of %s changed", node->details->uname, match->id);
2185 if (is_set(data_set->flags, pe_flag_sanitized)) {
2186
2187 fprintf(stdout, " notice: Unfencing %s (remote): because the definition of %s changed\n", node->details->uname, match->id);
2188 }
2189 }
2190
2191 digests_all_offset += snprintf(
2192 digests_all+digests_all_offset, max-digests_all_offset,
2193 "%s:%s:%s,", match->id, (const char*)g_hash_table_lookup(match->meta, XML_ATTR_TYPE), data->digest_all_calc);
2194
2195 digests_secure_offset += snprintf(
2196 digests_secure+digests_secure_offset, max-digests_secure_offset,
2197 "%s:%s:%s,", match->id, (const char*)g_hash_table_lookup(match->meta, XML_ATTR_TYPE), data->digest_secure_calc);
2198 }
2199 g_hash_table_insert(stonith_op->meta,
2200 strdup(XML_OP_ATTR_DIGESTS_ALL),
2201 digests_all);
2202 g_hash_table_insert(stonith_op->meta,
2203 strdup(XML_OP_ATTR_DIGESTS_SECURE),
2204 digests_secure);
2205 }
2206
2207 } else {
2208 free(op_key);
2209 }
2210
2211 if(optional == FALSE && pe_can_fence(data_set, node)) {
2212 pe_action_required(stonith_op, NULL, reason);
2213 } else if(reason && stonith_op->reason == NULL) {
2214 stonith_op->reason = strdup(reason);
2215 }
2216
2217 return stonith_op;
2218 }
2219
2220 void
2221 trigger_unfencing(
2222 resource_t * rsc, node_t *node, const char *reason, action_t *dependency, pe_working_set_t * data_set)
2223 {
2224 if(is_not_set(data_set->flags, pe_flag_enable_unfencing)) {
2225
2226 return;
2227
2228 } else if (rsc != NULL && is_not_set(rsc->flags, pe_rsc_fence_device)) {
2229
2230 return;
2231
2232 } else if(node
2233 && node->details->online
2234 && node->details->unclean == FALSE
2235 && node->details->shutdown == FALSE) {
2236 action_t *unfence = pe_fence_op(node, "on", FALSE, reason, data_set);
2237
2238 if(dependency) {
2239 order_actions(unfence, dependency, pe_order_optional);
2240 }
2241
2242 } else if(rsc) {
2243 GHashTableIter iter;
2244
2245 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
2246 while (g_hash_table_iter_next(&iter, NULL, (void **)&node)) {
2247 if(node->details->online && node->details->unclean == FALSE && node->details->shutdown == FALSE) {
2248 trigger_unfencing(rsc, node, reason, dependency, data_set);
2249 }
2250 }
2251 }
2252 }
2253
2254 gboolean
2255 add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref)
2256 {
2257 tag_t *tag = NULL;
2258 GListPtr gIter = NULL;
2259 gboolean is_existing = FALSE;
2260
2261 CRM_CHECK(tags && tag_name && obj_ref, return FALSE);
2262
2263 tag = g_hash_table_lookup(tags, tag_name);
2264 if (tag == NULL) {
2265 tag = calloc(1, sizeof(tag_t));
2266 if (tag == NULL) {
2267 return FALSE;
2268 }
2269 tag->id = strdup(tag_name);
2270 tag->refs = NULL;
2271 g_hash_table_insert(tags, strdup(tag_name), tag);
2272 }
2273
2274 for (gIter = tag->refs; gIter != NULL; gIter = gIter->next) {
2275 const char *existing_ref = (const char *) gIter->data;
2276
2277 if (crm_str_eq(existing_ref, obj_ref, TRUE)){
2278 is_existing = TRUE;
2279 break;
2280 }
2281 }
2282
2283 if (is_existing == FALSE) {
2284 tag->refs = g_list_append(tag->refs, strdup(obj_ref));
2285 crm_trace("Added: tag=%s ref=%s", tag->id, obj_ref);
2286 }
2287
2288 return TRUE;
2289 }
2290
2291 void pe_action_set_flag_reason(const char *function, long line,
2292 pe_action_t *action, pe_action_t *reason, const char *text,
2293 enum pe_action_flags flags, bool overwrite)
2294 {
2295 bool unset = FALSE;
2296 bool update = FALSE;
2297 const char *change = NULL;
2298
2299 if(is_set(flags, pe_action_runnable)) {
2300 unset = TRUE;
2301 change = "unrunnable";
2302 } else if(is_set(flags, pe_action_optional)) {
2303 unset = TRUE;
2304 change = "required";
2305 } else if(is_set(flags, pe_action_failure_is_fatal)) {
2306 change = "fatally failed";
2307 } else if(is_set(flags, pe_action_migrate_runnable)) {
2308 unset = TRUE;
2309 overwrite = TRUE;
2310 change = "unrunnable";
2311 } else if(is_set(flags, pe_action_dangle)) {
2312 change = "dangling";
2313 } else if(is_set(flags, pe_action_requires_any)) {
2314 change = "required";
2315 } else {
2316 crm_err("Unknown flag change to %s by %s: 0x%.16x",
2317 flags, action->uuid, (reason? reason->uuid : 0));
2318 }
2319
2320 if(unset) {
2321 if(is_set(action->flags, flags)) {
2322 action->flags = crm_clear_bit(function, line, action->uuid, action->flags, flags);
2323 update = TRUE;
2324 }
2325
2326 } else {
2327 if(is_not_set(action->flags, flags)) {
2328 action->flags = crm_set_bit(function, line, action->uuid, action->flags, flags);
2329 update = TRUE;
2330 }
2331 }
2332
2333 if((change && update) || text) {
2334 char *reason_text = NULL;
2335 if(reason == NULL) {
2336 pe_action_set_reason(action, text, overwrite);
2337
2338 } else if(reason->rsc == NULL) {
2339 reason_text = crm_strdup_printf("%s %s%c %s", change, reason->task, text?':':0, text?text:"");
2340 } else {
2341 reason_text = crm_strdup_printf("%s %s %s%c %s", change, reason->rsc->id, reason->task, text?':':0, text?text:"NA");
2342 }
2343
2344 if(reason_text && action->rsc != reason->rsc) {
2345 pe_action_set_reason(action, reason_text, overwrite);
2346 }
2347 free(reason_text);
2348 }
2349 }
2350
2351 void pe_action_set_reason(pe_action_t *action, const char *reason, bool overwrite)
2352 {
2353 if(action->reason && overwrite) {
2354 pe_rsc_trace(action->rsc, "Changing %s reason from '%s' to '%s'", action->uuid, action->reason, reason);
2355 free(action->reason);
2356 action->reason = NULL;
2357 }
2358 if(action->reason == NULL) {
2359 if(reason) {
2360 pe_rsc_trace(action->rsc, "Set %s reason to '%s'", action->uuid, reason);
2361 action->reason = strdup(reason);
2362 } else {
2363 action->reason = NULL;
2364 }
2365 }
2366 }