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