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