pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pcmk_sched_allocate.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2021 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU General Public License version 2
7 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <sys/param.h>
13
14#include <crm/crm.h>
15#include <crm/cib.h>
16#include <crm/msg_xml.h>
17#include <crm/common/xml.h>
19
20#include <glib.h>
21
22#include <crm/pengine/status.h>
23#include <pacemaker-internal.h>
24
26
27extern bool pcmk__is_daemon;
28
29void set_alloc_actions(pe_working_set_t * data_set);
30extern void ReloadRsc(pe_resource_t * rsc, pe_node_t *node, pe_working_set_t * data_set);
31extern gboolean DeleteRsc(pe_resource_t * rsc, pe_node_t * node, gboolean optional, pe_working_set_t * data_set);
32static void apply_remote_node_ordering(pe_working_set_t *data_set);
33static enum remote_connection_state get_remote_node_state(pe_node_t *node);
34
42
43static const char *
44state2text(enum remote_connection_state state)
45{
46 switch (state) {
48 return "unknown";
50 return "alive";
52 return "resting";
54 return "failed";
56 return "stopped";
57 }
58
59 return "impossible";
60}
61
120
121static gboolean
122check_rsc_parameters(pe_resource_t * rsc, pe_node_t * node, xmlNode * rsc_entry,
123 gboolean active_here, pe_working_set_t * data_set)
124{
125 int attr_lpc = 0;
126 gboolean force_restart = FALSE;
127 gboolean delete_resource = FALSE;
128 gboolean changed = FALSE;
129
130 const char *value = NULL;
131 const char *old_value = NULL;
132
133 const char *attr_list[] = {
137 };
138
139 for (; attr_lpc < PCMK__NELEM(attr_list); attr_lpc++) {
140 value = crm_element_value(rsc->xml, attr_list[attr_lpc]);
141 old_value = crm_element_value(rsc_entry, attr_list[attr_lpc]);
142 if (value == old_value /* i.e. NULL */
143 || pcmk__str_eq(value, old_value, pcmk__str_none)) {
144 continue;
145 }
146
147 changed = TRUE;
148 trigger_unfencing(rsc, node, "Device definition changed", NULL, data_set);
149 if (active_here) {
150 force_restart = TRUE;
151 crm_notice("Forcing restart of %s on %s, %s changed: %s -> %s",
152 rsc->id, node->details->uname, attr_list[attr_lpc],
153 crm_str(old_value), crm_str(value));
154 }
155 }
156 if (force_restart) {
157 /* make sure the restart happens */
158 stop_action(rsc, node, FALSE);
160 delete_resource = TRUE;
161
162 } else if (changed) {
163 delete_resource = TRUE;
164 }
165 return delete_resource;
166}
167
168static void
169CancelXmlOp(pe_resource_t * rsc, xmlNode * xml_op, pe_node_t * active_node,
170 const char *reason, pe_working_set_t * data_set)
171{
172 guint interval_ms = 0;
173 pe_action_t *cancel = NULL;
174
175 const char *task = NULL;
176 const char *call_id = NULL;
177
178 CRM_CHECK(xml_op != NULL, return);
179 CRM_CHECK(active_node != NULL, return);
180
181 task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
182 call_id = crm_element_value(xml_op, XML_LRM_ATTR_CALLID);
183 crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
184
185 crm_info("Action " PCMK__OP_FMT " on %s will be stopped: %s",
186 rsc->id, task, interval_ms,
187 active_node->details->uname, (reason? reason : "unknown"));
188
189 cancel = pe_cancel_op(rsc, task, interval_ms, active_node, data_set);
190 add_hash_param(cancel->meta, XML_LRM_ATTR_CALLID, call_id);
191 custom_action_order(rsc, stop_key(rsc), NULL, rsc, NULL, cancel, pe_order_optional, data_set);
192}
193
194static gboolean
195check_action_definition(pe_resource_t * rsc, pe_node_t * active_node, xmlNode * xml_op,
196 pe_working_set_t * data_set)
197{
198 char *key = NULL;
199 guint interval_ms = 0;
200 const op_digest_cache_t *digest_data = NULL;
201 gboolean did_change = FALSE;
202
203 const char *task = crm_element_value(xml_op, XML_LRM_ATTR_TASK);
204 const char *digest_secure = NULL;
205
206 CRM_CHECK(active_node != NULL, return FALSE);
207
208 crm_element_value_ms(xml_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
209 if (interval_ms > 0) {
210 xmlNode *op_match = NULL;
211
212 /* we need to reconstruct the key because of the way we used to construct resource IDs */
213 key = pcmk__op_key(rsc->id, task, interval_ms);
214
215 pe_rsc_trace(rsc, "Checking parameters for %s", key);
216 op_match = find_rsc_op_entry(rsc, key);
217
218 if ((op_match == NULL)
220 CancelXmlOp(rsc, xml_op, active_node, "orphan", data_set);
221 free(key);
222 return TRUE;
223
224 } else if (op_match == NULL) {
225 pe_rsc_debug(rsc, "Orphan action detected: %s on %s", key, active_node->details->uname);
226 free(key);
227 return TRUE;
228 }
229 free(key);
230 key = NULL;
231 }
232
233 crm_trace("Testing " PCMK__OP_FMT " on %s",
234 rsc->id, task, interval_ms, active_node->details->uname);
235 if ((interval_ms == 0) && pcmk__str_eq(task, RSC_STATUS, pcmk__str_casei)) {
236 /* Reload based on the start action not a probe */
237 task = RSC_START;
238
239 } else if ((interval_ms == 0) && pcmk__str_eq(task, RSC_MIGRATED, pcmk__str_casei)) {
240 /* Reload based on the start action not a migrate */
241 task = RSC_START;
242 } else if ((interval_ms == 0) && pcmk__str_eq(task, RSC_PROMOTE, pcmk__str_casei)) {
243 /* Reload based on the start action not a promote */
244 task = RSC_START;
245 }
246
247 digest_data = rsc_action_digest_cmp(rsc, xml_op, active_node, data_set);
248
249 if (pcmk_is_set(data_set->flags, pe_flag_sanitized)) {
250 digest_secure = crm_element_value(xml_op, XML_LRM_ATTR_SECURE_DIGEST);
251 }
252
253 if(digest_data->rc != RSC_DIGEST_MATCH
254 && digest_secure
255 && digest_data->digest_secure_calc
256 && strcmp(digest_data->digest_secure_calc, digest_secure) == 0) {
257 if (!pcmk__is_daemon && data_set->priv != NULL) {
258 pcmk__output_t *out = data_set->priv;
259 out->info(out, "Only 'private' parameters to "
260 PCMK__OP_FMT " on %s changed: %s", rsc->id, task,
261 interval_ms, active_node->details->uname,
263 }
264
265 } else if (digest_data->rc == RSC_DIGEST_RESTART) {
266 /* Changes that force a restart */
267 pe_action_t *required = NULL;
268
269 did_change = TRUE;
270 key = pcmk__op_key(rsc->id, task, interval_ms);
271 crm_log_xml_info(digest_data->params_restart, "params:restart");
272 required = custom_action(rsc, key, task, NULL, TRUE, TRUE, data_set);
273 pe_action_set_flag_reason(__func__, __LINE__, required, NULL,
274 "resource definition change", pe_action_optional, TRUE);
275
276 trigger_unfencing(rsc, active_node, "Device parameters changed", NULL, data_set);
277
278 } else if ((digest_data->rc == RSC_DIGEST_ALL) || (digest_data->rc == RSC_DIGEST_UNKNOWN)) {
279 // Changes that can potentially be handled by an agent reload
280 const char *digest_restart = crm_element_value(xml_op, XML_LRM_ATTR_RESTART_DIGEST);
281
282 did_change = TRUE;
283 trigger_unfencing(rsc, active_node, "Device parameters changed (reload)", NULL, data_set);
284 crm_log_xml_info(digest_data->params_all, "params:reload");
285 key = pcmk__op_key(rsc->id, task, interval_ms);
286
287 if (interval_ms > 0) {
288 pe_action_t *op = NULL;
289
290#if 0
291 /* Always reload/restart the entire resource */
292 ReloadRsc(rsc, active_node, data_set);
293#else
294 /* Re-sending the recurring op is sufficient - the old one will be cancelled automatically */
295 op = custom_action(rsc, key, task, active_node, TRUE, TRUE, data_set);
297#endif
298
299 } else if (digest_restart) {
300 pe_rsc_trace(rsc, "Reloading '%s' action for resource %s", task, rsc->id);
301
302 /* Reload this resource */
303 ReloadRsc(rsc, active_node, data_set);
304 free(key);
305
306 } else {
307 pe_action_t *required = NULL;
308 pe_rsc_trace(rsc, "Resource %s doesn't support agent reloads",
309 rsc->id);
310
311 /* Re-send the start/demote/promote op
312 * Recurring ops will be detected independently
313 */
314 required = custom_action(rsc, key, task, NULL, TRUE, TRUE, data_set);
315 pe_action_set_flag_reason(__func__, __LINE__, required, NULL,
316 "resource definition change", pe_action_optional, TRUE);
317 }
318 }
319
320 return did_change;
321}
322
329static void
330check_params(pe_resource_t *rsc, pe_node_t *node, xmlNode *rsc_op,
331 enum pe_check_parameters check, pe_working_set_t *data_set)
332{
333 const char *reason = NULL;
334 op_digest_cache_t *digest_data = NULL;
335
336 switch (check) {
337 case pe_check_active:
338 if (check_action_definition(rsc, node, rsc_op, data_set)
339 && pe_get_failcount(node, rsc, NULL, pe_fc_effective, NULL,
340 data_set)) {
341
342 reason = "action definition changed";
343 }
344 break;
345
347 digest_data = rsc_action_digest_cmp(rsc, rsc_op, node, data_set);
348 switch (digest_data->rc) {
350 crm_trace("Resource %s history entry %s on %s has no digest to compare",
351 rsc->id, ID(rsc_op), node->details->id);
352 break;
353 case RSC_DIGEST_MATCH:
354 break;
355 default:
356 reason = "resource parameters have changed";
357 break;
358 }
359 break;
360 }
361
362 if (reason) {
363 pe__clear_failcount(rsc, node, reason, data_set);
364 }
365}
366
367static void
368check_actions_for(xmlNode * rsc_entry, pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set)
369{
370 GList *gIter = NULL;
371 int offset = -1;
372 int stop_index = 0;
373 int start_index = 0;
374
375 const char *task = NULL;
376
377 xmlNode *rsc_op = NULL;
378 GList *op_list = NULL;
379 GList *sorted_op_list = NULL;
380
381 CRM_CHECK(node != NULL, return);
382
383 if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
384 pe_resource_t *parent = uber_parent(rsc);
385 if(parent == NULL
386 || pe_rsc_is_clone(parent) == FALSE
387 || pcmk_is_set(parent->flags, pe_rsc_unique)) {
388 pe_rsc_trace(rsc, "Skipping param check for %s and deleting: orphan", rsc->id);
389 DeleteRsc(rsc, node, FALSE, data_set);
390 } else {
391 pe_rsc_trace(rsc, "Skipping param check for %s (orphan clone)", rsc->id);
392 }
393 return;
394
395 } else if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
396 if (check_rsc_parameters(rsc, node, rsc_entry, FALSE, data_set)) {
397 DeleteRsc(rsc, node, FALSE, data_set);
398 }
399 pe_rsc_trace(rsc, "Skipping param check for %s: no longer active on %s",
400 rsc->id, node->details->uname);
401 return;
402 }
403
404 pe_rsc_trace(rsc, "Processing %s on %s", rsc->id, node->details->uname);
405
406 if (check_rsc_parameters(rsc, node, rsc_entry, TRUE, data_set)) {
407 DeleteRsc(rsc, node, FALSE, data_set);
408 }
409
410 for (rsc_op = pcmk__xe_first_child(rsc_entry); rsc_op != NULL;
411 rsc_op = pcmk__xe_next(rsc_op)) {
412
413 if (pcmk__str_eq((const char *)rsc_op->name, XML_LRM_TAG_RSC_OP, pcmk__str_none)) {
414 op_list = g_list_prepend(op_list, rsc_op);
415 }
416 }
417
418 sorted_op_list = g_list_sort(op_list, sort_op_by_callid);
419 calculate_active_ops(sorted_op_list, &start_index, &stop_index);
420
421 for (gIter = sorted_op_list; gIter != NULL; gIter = gIter->next) {
422 xmlNode *rsc_op = (xmlNode *) gIter->data;
423 guint interval_ms = 0;
424
425 offset++;
426
427 if (start_index < stop_index) {
428 /* stopped */
429 continue;
430 } else if (offset < start_index) {
431 /* action occurred prior to a start */
432 continue;
433 }
434
435 task = crm_element_value(rsc_op, XML_LRM_ATTR_TASK);
436 crm_element_value_ms(rsc_op, XML_LRM_ATTR_INTERVAL_MS, &interval_ms);
437
438 if ((interval_ms > 0) &&
440 // Maintenance mode cancels recurring operations
441 CancelXmlOp(rsc, rsc_op, node, "maintenance mode", data_set);
442
443 } else if ((interval_ms > 0) || pcmk__strcase_any_of(task, RSC_STATUS, RSC_START,
444 RSC_PROMOTE, RSC_MIGRATED, NULL)) {
445 /* If a resource operation failed, and the operation's definition
446 * has changed, clear any fail count so they can be retried fresh.
447 */
448
449 if (pe__bundle_needs_remote_name(rsc, data_set)) {
450 /* We haven't allocated resources to nodes yet, so if the
451 * REMOTE_CONTAINER_HACK is used, we may calculate the digest
452 * based on the literal "#uname" value rather than the properly
453 * substituted value. That would mistakenly make the action
454 * definition appear to have been changed. Defer the check until
455 * later in this case.
456 */
457 pe__add_param_check(rsc_op, rsc, node, pe_check_active,
458 data_set);
459
460 } else if (check_action_definition(rsc, node, rsc_op, data_set)
461 && pe_get_failcount(node, rsc, NULL, pe_fc_effective, NULL,
462 data_set)) {
463 pe__clear_failcount(rsc, node, "action definition changed",
464 data_set);
465 }
466 }
467 }
468 g_list_free(sorted_op_list);
469}
470
471static GList *
472find_rsc_list(GList *result, pe_resource_t * rsc, const char *id, gboolean renamed_clones,
473 gboolean partial, pe_working_set_t * data_set)
474{
475 GList *gIter = NULL;
476 gboolean match = FALSE;
477
478 if (id == NULL) {
479 return NULL;
480 }
481
482 if (rsc == NULL) {
483 if (data_set == NULL) {
484 return NULL;
485 }
486 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
487 pe_resource_t *child = (pe_resource_t *) gIter->data;
488
489 result = find_rsc_list(result, child, id, renamed_clones, partial,
490 NULL);
491 }
492 return result;
493 }
494
495 if (partial) {
496 if (strstr(rsc->id, id)) {
497 match = TRUE;
498
499 } else if (renamed_clones && rsc->clone_name && strstr(rsc->clone_name, id)) {
500 match = TRUE;
501 }
502
503 } else {
504 if (strcmp(rsc->id, id) == 0) {
505 match = TRUE;
506
507 } else if (renamed_clones && rsc->clone_name && strcmp(rsc->clone_name, id) == 0) {
508 match = TRUE;
509 }
510 }
511
512 if (match) {
513 result = g_list_prepend(result, rsc);
514 }
515
516 if (rsc->children) {
517 gIter = rsc->children;
518 for (; gIter != NULL; gIter = gIter->next) {
519 pe_resource_t *child = (pe_resource_t *) gIter->data;
520
521 result = find_rsc_list(result, child, id, renamed_clones, partial, NULL);
522 }
523 }
524
525 return result;
526}
527
528static void
529check_actions(pe_working_set_t * data_set)
530{
531 const char *id = NULL;
532 pe_node_t *node = NULL;
533 xmlNode *lrm_rscs = NULL;
534 xmlNode *status = get_object_root(XML_CIB_TAG_STATUS, data_set->input);
535
536 xmlNode *node_state = NULL;
537
538 for (node_state = pcmk__xe_first_child(status); node_state != NULL;
539 node_state = pcmk__xe_next(node_state)) {
540
541 if (pcmk__str_eq((const char *)node_state->name, XML_CIB_TAG_STATE,
543 id = crm_element_value(node_state, XML_ATTR_ID);
544 lrm_rscs = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
545 lrm_rscs = find_xml_node(lrm_rscs, XML_LRM_TAG_RESOURCES, FALSE);
546
547 node = pe_find_node_id(data_set->nodes, id);
548
549 if (node == NULL) {
550 continue;
551
552 /* Still need to check actions for a maintenance node to cancel existing monitor operations */
553 } else if (can_run_resources(node) == FALSE && node->details->maintenance == FALSE) {
554 crm_trace("Skipping param check for %s: can't run resources",
555 node->details->uname);
556 continue;
557 }
558
559 crm_trace("Processing node %s", node->details->uname);
560 if (node->details->online
562 xmlNode *rsc_entry = NULL;
563
564 for (rsc_entry = pcmk__xe_first_child(lrm_rscs);
565 rsc_entry != NULL;
566 rsc_entry = pcmk__xe_next(rsc_entry)) {
567
568 if (pcmk__str_eq((const char *)rsc_entry->name, XML_LRM_TAG_RESOURCE, pcmk__str_none)) {
569
570 if (xml_has_children(rsc_entry)) {
571 GList *gIter = NULL;
572 GList *result = NULL;
573 const char *rsc_id = ID(rsc_entry);
574
575 CRM_CHECK(rsc_id != NULL, return);
576
577 result = find_rsc_list(NULL, NULL, rsc_id, TRUE, FALSE, data_set);
578 for (gIter = result; gIter != NULL; gIter = gIter->next) {
579 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
580
581 if (rsc->variant != pe_native) {
582 continue;
583 }
584 check_actions_for(rsc_entry, rsc, node, data_set);
585 }
586 g_list_free(result);
587 }
588 }
589 }
590 }
591 }
592 }
593}
594
595static void
596apply_placement_constraints(pe_working_set_t * data_set)
597{
598 for (GList *gIter = data_set->placement_constraints;
599 gIter != NULL; gIter = gIter->next) {
600 pe__location_t *cons = gIter->data;
601
602 cons->rsc_lh->cmds->rsc_location(cons->rsc_lh, cons);
603 }
604}
605
606static gboolean
607failcount_clear_action_exists(pe_node_t * node, pe_resource_t * rsc)
608{
609 gboolean rc = FALSE;
610 GList *list = pe__resource_actions(rsc, node, CRM_OP_CLEAR_FAILCOUNT, TRUE);
611
612 if (list) {
613 rc = TRUE;
614 }
615 g_list_free(list);
616 return rc;
617}
618
627static void
628check_migration_threshold(pe_resource_t *rsc, pe_node_t *node,
629 pe_working_set_t *data_set)
630{
631 int fail_count, countdown;
632 pe_resource_t *failed;
633
634 /* Migration threshold of 0 means never force away */
635 if (rsc->migration_threshold == 0) {
636 return;
637 }
638
639 // If we're ignoring failures, also ignore the migration threshold
641 return;
642 }
643
644 /* If there are no failures, there's no need to force away */
645 fail_count = pe_get_failcount(node, rsc, NULL,
647 data_set);
648 if (fail_count <= 0) {
649 return;
650 }
651
652 /* How many more times recovery will be tried on this node */
653 countdown = QB_MAX(rsc->migration_threshold - fail_count, 0);
654
655 /* If failed resource has a parent, we'll force the parent away */
656 failed = rsc;
657 if (!pcmk_is_set(rsc->flags, pe_rsc_unique)) {
658 failed = uber_parent(rsc);
659 }
660
661 if (countdown == 0) {
662 resource_location(failed, node, -INFINITY, "__fail_limit__", data_set);
663 crm_warn("Forcing %s away from %s after %d failures (max=%d)",
664 failed->id, node->details->uname, fail_count,
666 } else {
667 crm_info("%s can fail %d more times on %s before being forced off",
668 failed->id, countdown, node->details->uname);
669 }
670}
671
672static void
673common_apply_stickiness(pe_resource_t * rsc, pe_node_t * node, pe_working_set_t * data_set)
674{
675 if (rsc->children) {
676 GList *gIter = rsc->children;
677
678 for (; gIter != NULL; gIter = gIter->next) {
679 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
680
681 common_apply_stickiness(child_rsc, node, data_set);
682 }
683 return;
684 }
685
687 && rsc->stickiness != 0 && pcmk__list_of_1(rsc->running_on)) {
688 pe_node_t *current = pe_find_node_id(rsc->running_on, node->details->id);
689 pe_node_t *match = pe_hash_table_lookup(rsc->allowed_nodes, node->details->id);
690
691 if (current == NULL) {
692
693 } else if ((match != NULL)
695 pe_resource_t *sticky_rsc = rsc;
696
697 resource_location(sticky_rsc, node, rsc->stickiness, "stickiness", data_set);
698 pe_rsc_debug(sticky_rsc, "Resource %s: preferring current location"
699 " (node=%s, weight=%d)", sticky_rsc->id,
700 node->details->uname, rsc->stickiness);
701 } else {
702 GHashTableIter iter;
703 pe_node_t *nIter = NULL;
704
705 pe_rsc_debug(rsc, "Ignoring stickiness for %s: the cluster is asymmetric"
706 " and node %s is not explicitly allowed", rsc->id, node->details->uname);
707 g_hash_table_iter_init(&iter, rsc->allowed_nodes);
708 while (g_hash_table_iter_next(&iter, NULL, (void **)&nIter)) {
709 crm_err("%s[%s] = %d", rsc->id, nIter->details->uname, nIter->weight);
710 }
711 }
712 }
713
714 /* Check the migration threshold only if a failcount clear action
715 * has not already been placed for this resource on the node.
716 * There is no sense in potentially forcing the resource from this
717 * node if the failcount is being reset anyway.
718 *
719 * @TODO A clear_failcount operation can be scheduled in stage4() via
720 * check_actions_for(), or in stage5() via check_params(). This runs in
721 * stage2(), so it cannot detect those, meaning we might check the migration
722 * threshold when we shouldn't -- worst case, we stop or move the resource,
723 * then move it back next transition.
724 */
725 if (failcount_clear_action_exists(node, rsc) == FALSE) {
726 check_migration_threshold(rsc, node, data_set);
727 }
728}
729
730void
732{
733 GList *gIter = rsc->children;
734
736
737 for (; gIter != NULL; gIter = gIter->next) {
738 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
739
740 complex_set_cmds(child_rsc);
741 }
742}
743
744void
746{
747
748 GList *gIter = data_set->resources;
749
750 for (; gIter != NULL; gIter = gIter->next) {
751 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
752
753 complex_set_cmds(rsc);
754 }
755}
756
757static void
758calculate_system_health(gpointer gKey, gpointer gValue, gpointer user_data)
759{
760 const char *key = (const char *)gKey;
761 const char *value = (const char *)gValue;
762 int *system_health = (int *)user_data;
763
764 if (!gKey || !gValue || !user_data) {
765 return;
766 }
767
768 if (pcmk__starts_with(key, "#health")) {
769 int score;
770
771 /* Convert the value into an integer */
772 score = char2score(value);
773
774 /* Add it to the running total */
775 *system_health = pe__add_scores(score, *system_health);
776 }
777}
778
779static gboolean
780apply_system_health(pe_working_set_t * data_set)
781{
782 GList *gIter = NULL;
783 const char *health_strategy = pe_pref(data_set->config_hash, "node-health-strategy");
784 int base_health = 0;
785
786 if (pcmk__str_eq(health_strategy, "none", pcmk__str_null_matches | pcmk__str_casei)) {
787 /* Prevent any accidental health -> score translation */
788 pcmk__score_red = 0;
791 return TRUE;
792
793 } else if (pcmk__str_eq(health_strategy, "migrate-on-red", pcmk__str_casei)) {
794
795 /* Resources on nodes which have health values of red are
796 * weighted away from that node.
797 */
801
802 } else if (pcmk__str_eq(health_strategy, "only-green", pcmk__str_casei)) {
803
804 /* Resources on nodes which have health values of red or yellow
805 * are forced away from that node.
806 */
810
811 } else if (pcmk__str_eq(health_strategy, "progressive", pcmk__str_casei)) {
812 /* Same as the above, but use the r/y/g scores provided by the user
813 * Defaults are provided by the pe_prefs table
814 * Also, custom health "base score" can be used
815 */
816 base_health = char2score(pe_pref(data_set->config_hash,
817 "node-health-base"));
818
819 } else if (pcmk__str_eq(health_strategy, "custom", pcmk__str_casei)) {
820
821 /* Requires the admin to configure the rsc_location constaints for
822 * processing the stored health scores
823 */
824 /* TODO: Check for the existence of appropriate node health constraints */
825 return TRUE;
826
827 } else {
828 crm_err("Unknown node health strategy: %s", health_strategy);
829 return FALSE;
830 }
831
832 crm_info("Applying automated node health strategy: %s", health_strategy);
833
834 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
835 int system_health = base_health;
836 pe_node_t *node = (pe_node_t *) gIter->data;
837
838 /* Search through the node hash table for system health entries. */
839 g_hash_table_foreach(node->details->attrs, calculate_system_health, &system_health);
840
841 crm_info(" Node %s has an combined system health of %d",
842 node->details->uname, system_health);
843
844 /* If the health is non-zero, then create a new rsc2node so that the
845 * weight will be added later on.
846 */
847 if (system_health != 0) {
848
849 GList *gIter2 = data_set->resources;
850
851 for (; gIter2 != NULL; gIter2 = gIter2->next) {
852 pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
853
854 rsc2node_new(health_strategy, rsc, system_health, NULL, node, data_set);
855 }
856 }
857 }
858
859 return TRUE;
860}
861
862gboolean
864{
865 xmlNode *cib_constraints = get_object_root(XML_CIB_TAG_CONSTRAINTS, data_set->input);
866
867 if (data_set->input == NULL) {
868 return FALSE;
869 }
870
871 if (!pcmk_is_set(data_set->flags, pe_flag_have_status)) {
872 crm_trace("Calculating status");
873 cluster_status(data_set);
874 }
875
876 set_alloc_actions(data_set);
877 apply_system_health(data_set);
878 unpack_constraints(cib_constraints, data_set);
879
880 return TRUE;
881}
882
883/*
884 * Check nodes for resources started outside of the LRM
885 */
886gboolean
888{
889 pe_action_t *probe_node_complete = NULL;
890
891 for (GList *gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
892 pe_node_t *node = (pe_node_t *) gIter->data;
893 const char *probed = pe_node_attribute_raw(node, CRM_OP_PROBED);
894
895 if (node->details->online == FALSE) {
896
897 if (pe__is_remote_node(node) && node->details->remote_rsc
898 && (get_remote_node_state(node) == remote_state_failed)) {
899
900 pe_fence_node(data_set, node, "the connection is unrecoverable", FALSE);
901 }
902 continue;
903
904 } else if (node->details->unclean) {
905 continue;
906
907 } else if (node->details->rsc_discovery_enabled == FALSE) {
908 /* resource discovery is disabled for this node */
909 continue;
910 }
911
912 if (probed != NULL && crm_is_true(probed) == FALSE) {
913 pe_action_t *probe_op = custom_action(NULL, crm_strdup_printf("%s-%s", CRM_OP_REPROBE, node->details->uname),
914 CRM_OP_REPROBE, node, FALSE, TRUE, data_set);
915
917 continue;
918 }
919
920 for (GList *gIter2 = data_set->resources; gIter2 != NULL; gIter2 = gIter2->next) {
921 pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
922
923 rsc->cmds->create_probe(rsc, node, probe_node_complete, FALSE, data_set);
924 }
925 }
926 return TRUE;
927}
928
929static void
930rsc_discover_filter(pe_resource_t *rsc, pe_node_t *node)
931{
932 GList *gIter = rsc->children;
933 pe_resource_t *top = uber_parent(rsc);
934 pe_node_t *match;
935
936 if (rsc->exclusive_discover == FALSE && top->exclusive_discover == FALSE) {
937 return;
938 }
939
940 for (; gIter != NULL; gIter = gIter->next) {
941 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
942 rsc_discover_filter(child_rsc, node);
943 }
944
945 match = g_hash_table_lookup(rsc->allowed_nodes, node->details->id);
946 if (match && match->rsc_discover_mode != pe_discover_exclusive) {
947 match->weight = -INFINITY;
948 }
949}
950
951static time_t
952shutdown_time(pe_node_t *node, pe_working_set_t *data_set)
953{
954 const char *shutdown = pe_node_attribute_raw(node, XML_CIB_ATTR_SHUTDOWN);
955 time_t result = 0;
956
957 if (shutdown) {
958 long long result_ll;
959
960 if (pcmk__scan_ll(shutdown, &result_ll, 0LL) == pcmk_rc_ok) {
961 result = (time_t) result_ll;
962 }
963 }
964 return result? result : get_effective_time(data_set);
965}
966
967static void
968apply_shutdown_lock(pe_resource_t *rsc, pe_working_set_t *data_set)
969{
970 const char *class;
971
972 // Only primitives and (uncloned) groups may be locked
973 if (rsc->variant == pe_group) {
974 for (GList *item = rsc->children; item != NULL;
975 item = item->next) {
976 apply_shutdown_lock((pe_resource_t *) item->data, data_set);
977 }
978 } else if (rsc->variant != pe_native) {
979 return;
980 }
981
982 // Fence devices and remote connections can't be locked
983 class = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS);
985 || pe__resource_is_remote_conn(rsc, data_set)) {
986 return;
987 }
988
989 if (rsc->lock_node != NULL) {
990 // The lock was obtained from resource history
991
992 if (rsc->running_on != NULL) {
993 /* The resource was started elsewhere even though it is now
994 * considered locked. This shouldn't be possible, but as a
995 * failsafe, we don't want to disturb the resource now.
996 */
997 pe_rsc_info(rsc,
998 "Cancelling shutdown lock because %s is already active",
999 rsc->id);
1000 pe__clear_resource_history(rsc, rsc->lock_node, data_set);
1001 rsc->lock_node = NULL;
1002 rsc->lock_time = 0;
1003 }
1004
1005 // Only a resource active on exactly one node can be locked
1006 } else if (pcmk__list_of_1(rsc->running_on)) {
1007 pe_node_t *node = rsc->running_on->data;
1008
1009 if (node->details->shutdown) {
1010 if (node->details->unclean) {
1011 pe_rsc_debug(rsc, "Not locking %s to unclean %s for shutdown",
1012 rsc->id, node->details->uname);
1013 } else {
1014 rsc->lock_node = node;
1015 rsc->lock_time = shutdown_time(node, data_set);
1016 }
1017 }
1018 }
1019
1020 if (rsc->lock_node == NULL) {
1021 // No lock needed
1022 return;
1023 }
1024
1025 if (data_set->shutdown_lock > 0) {
1026 time_t lock_expiration = rsc->lock_time + data_set->shutdown_lock;
1027
1028 pe_rsc_info(rsc, "Locking %s to %s due to shutdown (expires @%lld)",
1029 rsc->id, rsc->lock_node->details->uname,
1030 (long long) lock_expiration);
1031 pe__update_recheck_time(++lock_expiration, data_set);
1032 } else {
1033 pe_rsc_info(rsc, "Locking %s to %s due to shutdown",
1034 rsc->id, rsc->lock_node->details->uname);
1035 }
1036
1037 // If resource is locked to one node, ban it from all other nodes
1038 for (GList *item = data_set->nodes; item != NULL; item = item->next) {
1039 pe_node_t *node = item->data;
1040
1041 if (strcmp(node->details->uname, rsc->lock_node->details->uname)) {
1044 }
1045 }
1046}
1047
1048/*
1049 * \internal
1050 * \brief Stage 2 of cluster status: apply node-specific criteria
1051 *
1052 * Count known nodes, and apply location constraints, stickiness, and exclusive
1053 * resource discovery.
1054 */
1055gboolean
1057{
1058 GList *gIter = NULL;
1059
1060 if (pcmk_is_set(data_set->flags, pe_flag_shutdown_lock)) {
1061 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
1062 apply_shutdown_lock((pe_resource_t *) gIter->data, data_set);
1063 }
1064 }
1065
1066 if (!pcmk_is_set(data_set->flags, pe_flag_no_compat)) {
1067 // @COMPAT API backward compatibility
1068 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1069 pe_node_t *node = (pe_node_t *) gIter->data;
1070
1071 if (node && (node->weight >= 0) && node->details->online
1072 && (node->details->type != node_ping)) {
1073 data_set->max_valid_nodes++;
1074 }
1075 }
1076 }
1077
1078 apply_placement_constraints(data_set);
1079
1080 gIter = data_set->nodes;
1081 for (; gIter != NULL; gIter = gIter->next) {
1082 GList *gIter2 = NULL;
1083 pe_node_t *node = (pe_node_t *) gIter->data;
1084
1085 gIter2 = data_set->resources;
1086 for (; gIter2 != NULL; gIter2 = gIter2->next) {
1087 pe_resource_t *rsc = (pe_resource_t *) gIter2->data;
1088
1089 common_apply_stickiness(rsc, node, data_set);
1090 rsc_discover_filter(rsc, node);
1091 }
1092 }
1093
1094 return TRUE;
1095}
1096
1097/*
1098 * Create internal resource constraints before allocation
1099 */
1100gboolean
1102{
1103
1104 GList *gIter = data_set->resources;
1105
1106 for (; gIter != NULL; gIter = gIter->next) {
1107 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1108
1109 rsc->cmds->internal_constraints(rsc, data_set);
1110 }
1111
1112 return TRUE;
1113}
1114
1115/*
1116 * Check for orphaned or redefined actions
1117 */
1118gboolean
1120{
1121 check_actions(data_set);
1122 return TRUE;
1123}
1124
1125static void *
1126convert_const_pointer(const void *ptr)
1127{
1128 /* Worst function ever */
1129 return (void *)ptr;
1130}
1131
1132static gint
1133sort_rsc_process_order(gconstpointer a, gconstpointer b, gpointer data)
1134{
1135 int rc = 0;
1136 int r1_weight = -INFINITY;
1137 int r2_weight = -INFINITY;
1138
1139 const char *reason = "existence";
1140
1141 GList *nodes = (GList *) data;
1142 const pe_resource_t *resource1 = a;
1143 const pe_resource_t *resource2 = b;
1144
1145 pe_node_t *r1_node = NULL;
1146 pe_node_t *r2_node = NULL;
1147 GList *gIter = NULL;
1148 GHashTable *r1_nodes = NULL;
1149 GHashTable *r2_nodes = NULL;
1150
1151 reason = "priority";
1152 r1_weight = resource1->priority;
1153 r2_weight = resource2->priority;
1154
1155 if (r1_weight > r2_weight) {
1156 rc = -1;
1157 goto done;
1158 }
1159
1160 if (r1_weight < r2_weight) {
1161 rc = 1;
1162 goto done;
1163 }
1164
1165 reason = "no node list";
1166 if (nodes == NULL) {
1167 goto done;
1168 }
1169
1170 r1_nodes = pcmk__native_merge_weights(convert_const_pointer(resource1),
1171 resource1->id, NULL, NULL, 1,
1173 pe__show_node_weights(true, NULL, resource1->id, r1_nodes,
1174 resource1->cluster);
1175
1176 r2_nodes = pcmk__native_merge_weights(convert_const_pointer(resource2),
1177 resource2->id, NULL, NULL, 1,
1179 pe__show_node_weights(true, NULL, resource2->id, r2_nodes,
1180 resource2->cluster);
1181
1182 /* Current location score */
1183 reason = "current location";
1184 r1_weight = -INFINITY;
1185 r2_weight = -INFINITY;
1186
1187 if (resource1->running_on) {
1188 r1_node = pe__current_node(resource1);
1189 r1_node = g_hash_table_lookup(r1_nodes, r1_node->details->id);
1190 if (r1_node != NULL) {
1191 r1_weight = r1_node->weight;
1192 }
1193 }
1194 if (resource2->running_on) {
1195 r2_node = pe__current_node(resource2);
1196 r2_node = g_hash_table_lookup(r2_nodes, r2_node->details->id);
1197 if (r2_node != NULL) {
1198 r2_weight = r2_node->weight;
1199 }
1200 }
1201
1202 if (r1_weight > r2_weight) {
1203 rc = -1;
1204 goto done;
1205 }
1206
1207 if (r1_weight < r2_weight) {
1208 rc = 1;
1209 goto done;
1210 }
1211
1212 reason = "score";
1213 for (gIter = nodes; gIter != NULL; gIter = gIter->next) {
1214 pe_node_t *node = (pe_node_t *) gIter->data;
1215
1216 r1_node = NULL;
1217 r2_node = NULL;
1218
1219 r1_weight = -INFINITY;
1220 if (r1_nodes) {
1221 r1_node = g_hash_table_lookup(r1_nodes, node->details->id);
1222 }
1223 if (r1_node) {
1224 r1_weight = r1_node->weight;
1225 }
1226
1227 r2_weight = -INFINITY;
1228 if (r2_nodes) {
1229 r2_node = g_hash_table_lookup(r2_nodes, node->details->id);
1230 }
1231 if (r2_node) {
1232 r2_weight = r2_node->weight;
1233 }
1234
1235 if (r1_weight > r2_weight) {
1236 rc = -1;
1237 goto done;
1238 }
1239
1240 if (r1_weight < r2_weight) {
1241 rc = 1;
1242 goto done;
1243 }
1244 }
1245
1246 done:
1247 crm_trace("%s (%d) on %s %c %s (%d) on %s: %s",
1248 resource1->id, r1_weight, r1_node ? r1_node->details->id : "n/a",
1249 rc < 0 ? '>' : rc > 0 ? '<' : '=',
1250 resource2->id, r2_weight, r2_node ? r2_node->details->id : "n/a", reason);
1251
1252 if (r1_nodes) {
1253 g_hash_table_destroy(r1_nodes);
1254 }
1255 if (r2_nodes) {
1256 g_hash_table_destroy(r2_nodes);
1257 }
1258
1259 return rc;
1260}
1261
1262static void
1263allocate_resources(pe_working_set_t * data_set)
1264{
1265 GList *gIter = NULL;
1266
1268 /* Allocate remote connection resources first (which will also allocate
1269 * any colocation dependencies). If the connection is migrating, always
1270 * prefer the partial migration target.
1271 */
1272 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
1273 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1274 if (rsc->is_remote_node == FALSE) {
1275 continue;
1276 }
1277 pe_rsc_trace(rsc, "Allocating remote connection resource '%s'",
1278 rsc->id);
1279 rsc->cmds->allocate(rsc, rsc->partial_migration_target, data_set);
1280 }
1281 }
1282
1283 /* now do the rest of the resources */
1284 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
1285 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1286 if (rsc->is_remote_node == TRUE) {
1287 continue;
1288 }
1289 pe_rsc_trace(rsc, "Allocating %s resource '%s'",
1290 crm_element_name(rsc->xml), rsc->id);
1291 rsc->cmds->allocate(rsc, NULL, data_set);
1292 }
1293}
1294
1295/* We always use pe_order_preserve with these convenience functions to exempt
1296 * internally generated constraints from the prohibition of user constraints
1297 * involving remote connection resources.
1298 *
1299 * The start ordering additionally uses pe_order_runnable_left so that the
1300 * specified action is not runnable if the start is not runnable.
1301 */
1302
1303static inline void
1304order_start_then_action(pe_resource_t *lh_rsc, pe_action_t *rh_action,
1305 enum pe_ordering extra, pe_working_set_t *data_set)
1306{
1307 if (lh_rsc && rh_action && data_set) {
1308 custom_action_order(lh_rsc, start_key(lh_rsc), NULL,
1309 rh_action->rsc, NULL, rh_action,
1311 data_set);
1312 }
1313}
1314
1315static inline void
1316order_action_then_stop(pe_action_t *lh_action, pe_resource_t *rh_rsc,
1317 enum pe_ordering extra, pe_working_set_t *data_set)
1318{
1319 if (lh_action && rh_rsc && data_set) {
1320 custom_action_order(lh_action->rsc, NULL, lh_action,
1321 rh_rsc, stop_key(rh_rsc), NULL,
1322 pe_order_preserve | extra, data_set);
1323 }
1324}
1325
1326// Clear fail counts for orphaned rsc on all online nodes
1327static void
1328cleanup_orphans(pe_resource_t * rsc, pe_working_set_t * data_set)
1329{
1330 GList *gIter = NULL;
1331
1332 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1333 pe_node_t *node = (pe_node_t *) gIter->data;
1334
1335 if (node->details->online
1336 && pe_get_failcount(node, rsc, NULL, pe_fc_effective, NULL,
1337 data_set)) {
1338
1339 pe_action_t *clear_op = NULL;
1340
1341 clear_op = pe__clear_failcount(rsc, node, "it is orphaned",
1342 data_set);
1343
1344 /* We can't use order_action_then_stop() here because its
1345 * pe_order_preserve breaks things
1346 */
1347 custom_action_order(clear_op->rsc, NULL, clear_op,
1348 rsc, stop_key(rsc), NULL,
1349 pe_order_optional, data_set);
1350 }
1351 }
1352}
1353
1354gboolean
1356{
1357 pcmk__output_t *out = data_set->priv;
1358 GList *gIter = NULL;
1359
1360 if (!pcmk__str_eq(data_set->placement_strategy, "default", pcmk__str_casei)) {
1361 GList *nodes = g_list_copy(data_set->nodes);
1362
1363 nodes = sort_nodes_by_weight(nodes, NULL, data_set);
1364 data_set->resources =
1365 g_list_sort_with_data(data_set->resources, sort_rsc_process_order, nodes);
1366
1367 g_list_free(nodes);
1368 }
1369
1370 gIter = data_set->nodes;
1371 for (; gIter != NULL; gIter = gIter->next) {
1372 pe_node_t *node = (pe_node_t *) gIter->data;
1373
1374 if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
1375 out->message(out, "node-capacity", node, "Original");
1376 }
1377 }
1378
1379 crm_trace("Allocating services");
1380 /* Take (next) highest resource, assign it and create its actions */
1381
1382 allocate_resources(data_set);
1383
1384 gIter = data_set->nodes;
1385 for (; gIter != NULL; gIter = gIter->next) {
1386 pe_node_t *node = (pe_node_t *) gIter->data;
1387
1388 if (pcmk_is_set(data_set->flags, pe_flag_show_utilization)) {
1389 out->message(out, "node-capacity", node, "Remaining");
1390 }
1391 }
1392
1393 // Process deferred action checks
1394 pe__foreach_param_check(data_set, check_params);
1395 pe__free_param_checks(data_set);
1396
1397 if (pcmk_is_set(data_set->flags, pe_flag_startup_probes)) {
1398 crm_trace("Calculating needed probes");
1399 /* This code probably needs optimization
1400 * ptest -x with 100 nodes, 100 clones and clone-max=100:
1401
1402 With probes:
1403
1404 ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status
1405 ptest[14781]: 2010/09/27_17:56:46 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints
1406 ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints
1407 ptest[14781]: 2010/09/27_17:56:47 notice: TRACE: do_calculations: pengine.c:292 Check actions
1408 ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: do_calculations: pengine.c:299 Allocate resources
1409 ptest[14781]: 2010/09/27_17:56:48 notice: TRACE: stage5: allocate.c:881 Allocating services
1410 ptest[14781]: 2010/09/27_17:56:49 notice: TRACE: stage5: allocate.c:894 Calculating needed probes
1411 ptest[14781]: 2010/09/27_17:56:51 notice: TRACE: stage5: allocate.c:899 Creating actions
1412 ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: stage5: allocate.c:905 Creating done
1413 ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases
1414 ptest[14781]: 2010/09/27_17:56:52 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints
1415 36s
1416 ptest[14781]: 2010/09/27_17:57:28 notice: TRACE: do_calculations: pengine.c:320 Create transition graph
1417
1418 Without probes:
1419
1420 ptest[14637]: 2010/09/27_17:56:21 notice: TRACE: do_calculations: pengine.c:258 Calculate cluster status
1421 ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:278 Applying placement constraints
1422 ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:285 Create internal constraints
1423 ptest[14637]: 2010/09/27_17:56:22 notice: TRACE: do_calculations: pengine.c:292 Check actions
1424 ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: do_calculations: pengine.c:299 Allocate resources
1425 ptest[14637]: 2010/09/27_17:56:23 notice: TRACE: stage5: allocate.c:881 Allocating services
1426 ptest[14637]: 2010/09/27_17:56:24 notice: TRACE: stage5: allocate.c:899 Creating actions
1427 ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: stage5: allocate.c:905 Creating done
1428 ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:306 Processing fencing and shutdown cases
1429 ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:313 Applying ordering constraints
1430 ptest[14637]: 2010/09/27_17:56:25 notice: TRACE: do_calculations: pengine.c:320 Create transition graph
1431 */
1432
1433 probe_resources(data_set);
1434 }
1435
1436 crm_trace("Handle orphans");
1437 if (pcmk_is_set(data_set->flags, pe_flag_stop_rsc_orphans)) {
1438 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
1439 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1440
1441 /* There's no need to recurse into rsc->children because those
1442 * should just be unallocated clone instances.
1443 */
1444 if (pcmk_is_set(rsc->flags, pe_rsc_orphan)) {
1445 cleanup_orphans(rsc, data_set);
1446 }
1447 }
1448 }
1449
1450 crm_trace("Creating actions");
1451
1452 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
1453 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1454
1455 rsc->cmds->create_actions(rsc, data_set);
1456 }
1457
1458 crm_trace("Creating done");
1459 return TRUE;
1460}
1461
1462static gboolean
1463is_managed(const pe_resource_t * rsc)
1464{
1465 GList *gIter = rsc->children;
1466
1467 if (pcmk_is_set(rsc->flags, pe_rsc_managed)) {
1468 return TRUE;
1469 }
1470
1471 for (; gIter != NULL; gIter = gIter->next) {
1472 pe_resource_t *child_rsc = (pe_resource_t *) gIter->data;
1473
1474 if (is_managed(child_rsc)) {
1475 return TRUE;
1476 }
1477 }
1478
1479 return FALSE;
1480}
1481
1482static gboolean
1483any_managed_resources(pe_working_set_t * data_set)
1484{
1485
1486 GList *gIter = data_set->resources;
1487
1488 for (; gIter != NULL; gIter = gIter->next) {
1489 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
1490
1491 if (is_managed(rsc)) {
1492 return TRUE;
1493 }
1494 }
1495 return FALSE;
1496}
1497
1505static void
1506fence_guest(pe_node_t *node, pe_working_set_t *data_set)
1507{
1508 pe_resource_t *container = node->details->remote_rsc->container;
1509 pe_action_t *stop = NULL;
1510 pe_action_t *stonith_op = NULL;
1511
1512 /* The fence action is just a label; we don't do anything differently for
1513 * off vs. reboot. We specify it explicitly, rather than let it default to
1514 * cluster's default action, because we are not _initiating_ fencing -- we
1515 * are creating a pseudo-event to describe fencing that is already occurring
1516 * by other means (container recovery).
1517 */
1518 const char *fence_action = "off";
1519
1520 /* Check whether guest's container resource has any explicit stop or
1521 * start (the stop may be implied by fencing of the guest's host).
1522 */
1523 if (container) {
1524 stop = find_first_action(container->actions, NULL, CRMD_ACTION_STOP, NULL);
1525
1526 if (find_first_action(container->actions, NULL, CRMD_ACTION_START, NULL)) {
1527 fence_action = "reboot";
1528 }
1529 }
1530
1531 /* Create a fence pseudo-event, so we have an event to order actions
1532 * against, and the controller can always detect it.
1533 */
1534 stonith_op = pe_fence_op(node, fence_action, FALSE, "guest is unclean", FALSE, data_set);
1536
1537 /* We want to imply stops/demotes after the guest is stopped, not wait until
1538 * it is restarted, so we always order pseudo-fencing after stop, not start
1539 * (even though start might be closer to what is done for a real reboot).
1540 */
1541 if ((stop != NULL) && pcmk_is_set(stop->flags, pe_action_pseudo)) {
1542 pe_action_t *parent_stonith_op = pe_fence_op(stop->node, NULL, FALSE, NULL, FALSE, data_set);
1543 crm_info("Implying guest node %s is down (action %d) after %s fencing",
1544 node->details->uname, stonith_op->id, stop->node->details->uname);
1545 order_actions(parent_stonith_op, stonith_op,
1547
1548 } else if (stop) {
1549 order_actions(stop, stonith_op,
1551 crm_info("Implying guest node %s is down (action %d) "
1552 "after container %s is stopped (action %d)",
1553 node->details->uname, stonith_op->id,
1554 container->id, stop->id);
1555 } else {
1556 /* If we're fencing the guest node but there's no stop for the guest
1557 * resource, we must think the guest is already stopped. However, we may
1558 * think so because its resource history was just cleaned. To avoid
1559 * unnecessarily considering the guest node down if it's really up,
1560 * order the pseudo-fencing after any stop of the connection resource,
1561 * which will be ordered after any container (re-)probe.
1562 */
1563 stop = find_first_action(node->details->remote_rsc->actions, NULL,
1564 RSC_STOP, NULL);
1565
1566 if (stop) {
1567 order_actions(stop, stonith_op, pe_order_optional);
1568 crm_info("Implying guest node %s is down (action %d) "
1569 "after connection is stopped (action %d)",
1570 node->details->uname, stonith_op->id, stop->id);
1571 } else {
1572 /* Not sure why we're fencing, but everything must already be
1573 * cleanly stopped.
1574 */
1575 crm_info("Implying guest node %s is down (action %d) ",
1576 node->details->uname, stonith_op->id);
1577 }
1578 }
1579
1580 /* Order/imply other actions relative to pseudo-fence as with real fence */
1581 pcmk__order_vs_fence(stonith_op, data_set);
1582}
1583
1584/*
1585 * Create dependencies for stonith and shutdown operations
1586 */
1587gboolean
1589{
1590 pe_action_t *dc_down = NULL;
1591 pe_action_t *stonith_op = NULL;
1592 gboolean integrity_lost = FALSE;
1593 gboolean need_stonith = TRUE;
1594 GList *gIter;
1595 GList *stonith_ops = NULL;
1596 GList *shutdown_ops = NULL;
1597
1598 /* Remote ordering constraints need to happen prior to calculating fencing
1599 * because it is one more place we will mark the node as dirty.
1600 *
1601 * A nice side effect of doing them early is that apply_*_ordering() can be
1602 * simpler because pe_fence_node() has already done some of the work.
1603 */
1604 crm_trace("Creating remote ordering constraints");
1605 apply_remote_node_ordering(data_set);
1606
1607 crm_trace("Processing fencing and shutdown cases");
1608 if (any_managed_resources(data_set) == FALSE) {
1609 crm_notice("Delaying fencing operations until there are resources to manage");
1610 need_stonith = FALSE;
1611 }
1612
1613 /* Check each node for stonith/shutdown */
1614 for (gIter = data_set->nodes; gIter != NULL; gIter = gIter->next) {
1615 pe_node_t *node = (pe_node_t *) gIter->data;
1616
1617 /* Guest nodes are "fenced" by recovering their container resource,
1618 * so handle them separately.
1619 */
1620 if (pe__is_guest_node(node)) {
1621 if (node->details->remote_requires_reset && need_stonith
1622 && pe_can_fence(data_set, node)) {
1623 fence_guest(node, data_set);
1624 }
1625 continue;
1626 }
1627
1628 stonith_op = NULL;
1629
1630 if (node->details->unclean
1631 && need_stonith && pe_can_fence(data_set, node)) {
1632
1633 stonith_op = pe_fence_op(node, NULL, FALSE, "node is unclean", FALSE, data_set);
1634 pe_warn("Scheduling Node %s for STONITH", node->details->uname);
1635
1636 pcmk__order_vs_fence(stonith_op, data_set);
1637
1638 if (node->details->is_dc) {
1639 // Remember if the DC is being fenced
1640 dc_down = stonith_op;
1641
1642 } else {
1643
1645 && (stonith_ops != NULL)) {
1646 /* Concurrent fencing is disabled, so order each non-DC
1647 * fencing in a chain. If there is any DC fencing or
1648 * shutdown, it will be ordered after the last action in the
1649 * chain later.
1650 */
1651 order_actions((pe_action_t *) stonith_ops->data,
1652 stonith_op, pe_order_optional);
1653 }
1654
1655 // Remember all non-DC fencing actions in a separate list
1656 stonith_ops = g_list_prepend(stonith_ops, stonith_op);
1657 }
1658
1659 } else if (node->details->online && node->details->shutdown &&
1660 /* TODO define what a shutdown op means for a remote node.
1661 * For now we do not send shutdown operations for remote nodes, but
1662 * if we can come up with a good use for this in the future, we will. */
1663 pe__is_guest_or_remote_node(node) == FALSE) {
1664
1665 pe_action_t *down_op = sched_shutdown_op(node, data_set);
1666
1667 if (node->details->is_dc) {
1668 // Remember if the DC is being shut down
1669 dc_down = down_op;
1670 } else {
1671 // Remember non-DC shutdowns for later ordering
1672 shutdown_ops = g_list_prepend(shutdown_ops, down_op);
1673 }
1674 }
1675
1676 if (node->details->unclean && stonith_op == NULL) {
1677 integrity_lost = TRUE;
1678 pe_warn("Node %s is unclean!", node->details->uname);
1679 }
1680 }
1681
1682 if (integrity_lost) {
1683 if (!pcmk_is_set(data_set->flags, pe_flag_stonith_enabled)) {
1684 pe_warn("YOUR RESOURCES ARE NOW LIKELY COMPROMISED");
1685 pe_err("ENABLE STONITH TO KEEP YOUR RESOURCES SAFE");
1686
1687 } else if (!pcmk_is_set(data_set->flags, pe_flag_have_quorum)) {
1688 crm_notice("Cannot fence unclean nodes until quorum is"
1689 " attained (or no-quorum-policy is set to ignore)");
1690 }
1691 }
1692
1693 if (dc_down != NULL) {
1694 /* Order any non-DC shutdowns before any DC shutdown, to avoid repeated
1695 * DC elections. However, we don't want to order non-DC shutdowns before
1696 * a DC *fencing*, because even though we don't want a node that's
1697 * shutting down to become DC, the DC fencing could be ordered before a
1698 * clone stop that's also ordered before the shutdowns, thus leading to
1699 * a graph loop.
1700 */
1701 if (pcmk__str_eq(dc_down->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
1702 for (gIter = shutdown_ops; gIter != NULL; gIter = gIter->next) {
1703 pe_action_t *node_stop = (pe_action_t *) gIter->data;
1704
1705 crm_debug("Ordering shutdown on %s before %s on DC %s",
1706 node_stop->node->details->uname,
1707 dc_down->task, dc_down->node->details->uname);
1708
1709 order_actions(node_stop, dc_down, pe_order_optional);
1710 }
1711 }
1712
1713 // Order any non-DC fencing before any DC fencing or shutdown
1714
1716 /* With concurrent fencing, order each non-DC fencing action
1717 * separately before any DC fencing or shutdown.
1718 */
1719 for (gIter = stonith_ops; gIter != NULL; gIter = gIter->next) {
1720 order_actions((pe_action_t *) gIter->data, dc_down,
1722 }
1723 } else if (stonith_ops) {
1724 /* Without concurrent fencing, the non-DC fencing actions are
1725 * already ordered relative to each other, so we just need to order
1726 * the DC fencing after the last action in the chain (which is the
1727 * first item in the list).
1728 */
1729 order_actions((pe_action_t *) stonith_ops->data, dc_down,
1731 }
1732 }
1733 g_list_free(stonith_ops);
1734 g_list_free(shutdown_ops);
1735 return TRUE;
1736}
1737
1738/*
1739 * Determine the sets of independent actions and the correct order for the
1740 * actions in each set.
1741 *
1742 * Mark dependencies of un-runnable actions un-runnable
1743 *
1744 */
1745static GList *
1746find_actions_by_task(GList *actions, pe_resource_t * rsc, const char *original_key)
1747{
1748 GList *list = NULL;
1749
1750 list = find_actions(actions, original_key, NULL);
1751 if (list == NULL) {
1752 /* we're potentially searching a child of the original resource */
1753 char *key = NULL;
1754 char *task = NULL;
1755 guint interval_ms = 0;
1756
1757 if (parse_op_key(original_key, NULL, &task, &interval_ms)) {
1758 key = pcmk__op_key(rsc->id, task, interval_ms);
1759 list = find_actions(actions, key, NULL);
1760
1761 } else {
1762 crm_err("search key: %s", original_key);
1763 }
1764
1765 free(key);
1766 free(task);
1767 }
1768
1769 return list;
1770}
1771
1772static void
1773rsc_order_then(pe_action_t *lh_action, pe_resource_t *rsc,
1774 pe__ordering_t *order)
1775{
1776 GList *gIter = NULL;
1777 GList *rh_actions = NULL;
1778 pe_action_t *rh_action = NULL;
1779 enum pe_ordering type;
1780
1781 CRM_CHECK(rsc != NULL, return);
1782 CRM_CHECK(order != NULL, return);
1783
1784 type = order->type;
1785 rh_action = order->rh_action;
1786 crm_trace("Processing RH of ordering constraint %d", order->id);
1787
1788 if (rh_action != NULL) {
1789 rh_actions = g_list_prepend(NULL, rh_action);
1790
1791 } else if (rsc != NULL) {
1792 rh_actions = find_actions_by_task(rsc->actions, rsc, order->rh_action_task);
1793 }
1794
1795 if (rh_actions == NULL) {
1796 pe_rsc_trace(rsc, "No RH-Side (%s/%s) found for constraint..."
1797 " ignoring", rsc->id, order->rh_action_task);
1798 if (lh_action) {
1799 pe_rsc_trace(rsc, "LH-Side was: %s", lh_action->uuid);
1800 }
1801 return;
1802 }
1803
1804 if ((lh_action != NULL) && (lh_action->rsc == rsc)
1805 && pcmk_is_set(lh_action->flags, pe_action_dangle)) {
1806
1807 pe_rsc_trace(rsc, "Detected dangling operation %s -> %s", lh_action->uuid,
1808 order->rh_action_task);
1810 }
1811
1812 gIter = rh_actions;
1813 for (; gIter != NULL; gIter = gIter->next) {
1814 pe_action_t *rh_action_iter = (pe_action_t *) gIter->data;
1815
1816 if (lh_action) {
1817 order_actions(lh_action, rh_action_iter, type);
1818
1819 } else if (type & pe_order_implies_then) {
1821 crm_warn("Unrunnable %s 0x%.6x", rh_action_iter->uuid, type);
1822 } else {
1823 crm_warn("neither %s 0x%.6x", rh_action_iter->uuid, type);
1824 }
1825 }
1826
1827 g_list_free(rh_actions);
1828}
1829
1830static void
1831rsc_order_first(pe_resource_t *lh_rsc, pe__ordering_t *order,
1832 pe_working_set_t *data_set)
1833{
1834 GList *gIter = NULL;
1835 GList *lh_actions = NULL;
1836 pe_action_t *lh_action = order->lh_action;
1837 pe_resource_t *rh_rsc = order->rh_rsc;
1838
1839 crm_trace("Processing LH of ordering constraint %d", order->id);
1840 CRM_ASSERT(lh_rsc != NULL);
1841
1842 if (lh_action != NULL) {
1843 lh_actions = g_list_prepend(NULL, lh_action);
1844
1845 } else {
1846 lh_actions = find_actions_by_task(lh_rsc->actions, lh_rsc, order->lh_action_task);
1847 }
1848
1849 if (lh_actions == NULL && lh_rsc != rh_rsc) {
1850 char *key = NULL;
1851 char *op_type = NULL;
1852 guint interval_ms = 0;
1853
1854 parse_op_key(order->lh_action_task, NULL, &op_type, &interval_ms);
1855 key = pcmk__op_key(lh_rsc->id, op_type, interval_ms);
1856
1857 if (lh_rsc->fns->state(lh_rsc, TRUE) == RSC_ROLE_STOPPED && pcmk__str_eq(op_type, RSC_STOP, pcmk__str_casei)) {
1858 free(key);
1859 pe_rsc_trace(lh_rsc, "No LH-Side (%s/%s) found for constraint %d with %s - ignoring",
1860 lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task);
1861
1862 } else if ((lh_rsc->fns->state(lh_rsc, TRUE) == RSC_ROLE_UNPROMOTED)
1863 && pcmk__str_eq(op_type, RSC_DEMOTE, pcmk__str_casei)) {
1864 free(key);
1865 pe_rsc_trace(lh_rsc, "No LH-Side (%s/%s) found for constraint %d with %s - ignoring",
1866 lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task);
1867
1868 } else {
1869 pe_rsc_trace(lh_rsc, "No LH-Side (%s/%s) found for constraint %d with %s - creating",
1870 lh_rsc->id, order->lh_action_task, order->id, order->rh_action_task);
1871 lh_action = custom_action(lh_rsc, key, op_type, NULL, TRUE, TRUE, data_set);
1872 lh_actions = g_list_prepend(NULL, lh_action);
1873 }
1874
1875 free(op_type);
1876 }
1877
1878 gIter = lh_actions;
1879 for (; gIter != NULL; gIter = gIter->next) {
1880 pe_action_t *lh_action_iter = (pe_action_t *) gIter->data;
1881
1882 if (rh_rsc == NULL && order->rh_action) {
1883 rh_rsc = order->rh_action->rsc;
1884 }
1885 if (rh_rsc) {
1886 rsc_order_then(lh_action_iter, rh_rsc, order);
1887
1888 } else if (order->rh_action) {
1889 order_actions(lh_action_iter, order->rh_action, order->type);
1890 }
1891 }
1892
1893 g_list_free(lh_actions);
1894}
1895
1897 pe_working_set_t *data_set);
1898
1899static int
1900is_recurring_action(pe_action_t *action)
1901{
1902 guint interval_ms;
1903
1904 if (pcmk__guint_from_hash(action->meta,
1906 &interval_ms) != pcmk_rc_ok) {
1907 return 0;
1908 }
1909 return (interval_ms > 0);
1910}
1911
1912static void
1913apply_container_ordering(pe_action_t *action, pe_working_set_t *data_set)
1914{
1915 /* VMs are also classified as containers for these purposes... in
1916 * that they both involve a 'thing' running on a real or remote
1917 * cluster node.
1918 *
1919 * This allows us to be smarter about the type and extent of
1920 * recovery actions required in various scenarios
1921 */
1922 pe_resource_t *remote_rsc = NULL;
1923 pe_resource_t *container = NULL;
1924 enum action_tasks task = text2task(action->task);
1925
1926 CRM_ASSERT(action->rsc);
1927 CRM_ASSERT(action->node);
1929
1930 remote_rsc = action->node->details->remote_rsc;
1931 CRM_ASSERT(remote_rsc);
1932
1933 container = remote_rsc->container;
1934 CRM_ASSERT(container);
1935
1936 if (pcmk_is_set(container->flags, pe_rsc_failed)) {
1937 pe_fence_node(data_set, action->node, "container failed", FALSE);
1938 }
1939
1940 crm_trace("Order %s action %s relative to %s%s for %s%s",
1941 action->task, action->uuid,
1942 pcmk_is_set(remote_rsc->flags, pe_rsc_failed)? "failed " : "",
1943 remote_rsc->id,
1944 pcmk_is_set(container->flags, pe_rsc_failed)? "failed " : "",
1945 container->id);
1946
1948 /* Migration ops map to "no_action", but we need to apply the same
1949 * ordering as for stop or demote (see get_router_node()).
1950 */
1951 task = stop_rsc;
1952 }
1953
1954 switch (task) {
1955 case start_rsc:
1956 case action_promote:
1957 /* Force resource recovery if the container is recovered */
1958 order_start_then_action(container, action, pe_order_implies_then,
1959 data_set);
1960
1961 /* Wait for the connection resource to be up too */
1962 order_start_then_action(remote_rsc, action, pe_order_none,
1963 data_set);
1964 break;
1965
1966 case stop_rsc:
1967 case action_demote:
1968 if (pcmk_is_set(container->flags, pe_rsc_failed)) {
1969 /* When the container representing a guest node fails, any stop
1970 * or demote actions for resources running on the guest node
1971 * are implied by the container stopping. This is similar to
1972 * how fencing operations work for cluster nodes and remote
1973 * nodes.
1974 */
1975 } else {
1976 /* Ensure the operation happens before the connection is brought
1977 * down.
1978 *
1979 * If we really wanted to, we could order these after the
1980 * connection start, IFF the container's current role was
1981 * stopped (otherwise we re-introduce an ordering loop when the
1982 * connection is restarting).
1983 */
1984 order_action_then_stop(action, remote_rsc, pe_order_none,
1985 data_set);
1986 }
1987 break;
1988
1989 default:
1990 /* Wait for the connection resource to be up */
1991 if (is_recurring_action(action)) {
1992 /* In case we ever get the recovery logic wrong, force
1993 * recurring monitors to be restarted, even if just
1994 * the connection was re-established
1995 */
1996 if(task != no_action) {
1997 order_start_then_action(remote_rsc, action,
1998 pe_order_implies_then, data_set);
1999 }
2000 } else {
2001 order_start_then_action(remote_rsc, action, pe_order_none,
2002 data_set);
2003 }
2004 break;
2005 }
2006}
2007
2008static enum remote_connection_state
2009get_remote_node_state(pe_node_t *node)
2010{
2011 pe_resource_t *remote_rsc = NULL;
2012 pe_node_t *cluster_node = NULL;
2013
2014 CRM_ASSERT(node);
2015
2016 remote_rsc = node->details->remote_rsc;
2017 CRM_ASSERT(remote_rsc);
2018
2019 cluster_node = pe__current_node(remote_rsc);
2020
2021 /* If the cluster node the remote connection resource resides on
2022 * is unclean or went offline, we can't process any operations
2023 * on that remote node until after it starts elsewhere.
2024 */
2025 if(remote_rsc->next_role == RSC_ROLE_STOPPED || remote_rsc->allocated_to == NULL) {
2026 /* The connection resource is not going to run anywhere */
2027
2028 if (cluster_node && cluster_node->details->unclean) {
2029 /* The remote connection is failed because its resource is on a
2030 * failed node and can't be recovered elsewhere, so we must fence.
2031 */
2032 return remote_state_failed;
2033 }
2034
2035 if (!pcmk_is_set(remote_rsc->flags, pe_rsc_failed)) {
2036 /* Connection resource is cleanly stopped */
2037 return remote_state_stopped;
2038 }
2039
2040 /* Connection resource is failed */
2041
2042 if ((remote_rsc->next_role == RSC_ROLE_STOPPED)
2043 && remote_rsc->remote_reconnect_ms
2044 && node->details->remote_was_fenced
2045 && !pe__shutdown_requested(node)) {
2046
2047 /* We won't know whether the connection is recoverable until the
2048 * reconnect interval expires and we reattempt connection.
2049 */
2050 return remote_state_unknown;
2051 }
2052
2053 /* The remote connection is in a failed state. If there are any
2054 * resources known to be active on it (stop) or in an unknown state
2055 * (probe), we must assume the worst and fence it.
2056 */
2057 return remote_state_failed;
2058
2059 } else if (cluster_node == NULL) {
2060 /* Connection is recoverable but not currently running anywhere, see if we can recover it first */
2061 return remote_state_unknown;
2062
2063 } else if(cluster_node->details->unclean == TRUE
2064 || cluster_node->details->online == FALSE) {
2065 /* Connection is running on a dead node, see if we can recover it first */
2066 return remote_state_resting;
2067
2068 } else if (pcmk__list_of_multiple(remote_rsc->running_on)
2069 && remote_rsc->partial_migration_source
2070 && remote_rsc->partial_migration_target) {
2071 /* We're in the middle of migrating a connection resource,
2072 * wait until after the resource migrates before performing
2073 * any actions.
2074 */
2075 return remote_state_resting;
2076
2077 }
2078 return remote_state_alive;
2079}
2080
2085static void
2086apply_remote_ordering(pe_action_t *action, pe_working_set_t *data_set)
2087{
2088 pe_resource_t *remote_rsc = NULL;
2089 enum action_tasks task = text2task(action->task);
2090 enum remote_connection_state state = get_remote_node_state(action->node);
2091
2092 enum pe_ordering order_opts = pe_order_none;
2093
2094 if (action->rsc == NULL) {
2095 return;
2096 }
2097
2098 CRM_ASSERT(action->node);
2100
2101 remote_rsc = action->node->details->remote_rsc;
2102 CRM_ASSERT(remote_rsc);
2103
2104 crm_trace("Order %s action %s relative to %s%s (state: %s)",
2105 action->task, action->uuid,
2106 pcmk_is_set(remote_rsc->flags, pe_rsc_failed)? "failed " : "",
2107 remote_rsc->id, state2text(state));
2108
2110 /* Migration ops map to "no_action", but we need to apply the same
2111 * ordering as for stop or demote (see get_router_node()).
2112 */
2113 task = stop_rsc;
2114 }
2115
2116 switch (task) {
2117 case start_rsc:
2118 case action_promote:
2119 order_opts = pe_order_none;
2120
2121 if (state == remote_state_failed) {
2122 /* Force recovery, by making this action required */
2124 }
2125
2126 /* Ensure connection is up before running this action */
2127 order_start_then_action(remote_rsc, action, order_opts, data_set);
2128 break;
2129
2130 case stop_rsc:
2131 if(state == remote_state_alive) {
2132 order_action_then_stop(action, remote_rsc,
2133 pe_order_implies_first, data_set);
2134
2135 } else if(state == remote_state_failed) {
2136 /* The resource is active on the node, but since we don't have a
2137 * valid connection, the only way to stop the resource is by
2138 * fencing the node. There is no need to order the stop relative
2139 * to the remote connection, since the stop will become implied
2140 * by the fencing.
2141 */
2142 pe_fence_node(data_set, action->node, "resources are active and the connection is unrecoverable", FALSE);
2143
2144 } else if(remote_rsc->next_role == RSC_ROLE_STOPPED) {
2145 /* State must be remote_state_unknown or remote_state_stopped.
2146 * Since the connection is not coming back up in this
2147 * transition, stop this resource first.
2148 */
2149 order_action_then_stop(action, remote_rsc,
2150 pe_order_implies_first, data_set);
2151
2152 } else {
2153 /* The connection is going to be started somewhere else, so
2154 * stop this resource after that completes.
2155 */
2156 order_start_then_action(remote_rsc, action, pe_order_none, data_set);
2157 }
2158 break;
2159
2160 case action_demote:
2161 /* Only order this demote relative to the connection start if the
2162 * connection isn't being torn down. Otherwise, the demote would be
2163 * blocked because the connection start would not be allowed.
2164 */
2165 if(state == remote_state_resting || state == remote_state_unknown) {
2166 order_start_then_action(remote_rsc, action, pe_order_none,
2167 data_set);
2168 } /* Otherwise we can rely on the stop ordering */
2169 break;
2170
2171 default:
2172 /* Wait for the connection resource to be up */
2173 if (is_recurring_action(action)) {
2174 /* In case we ever get the recovery logic wrong, force
2175 * recurring monitors to be restarted, even if just
2176 * the connection was re-established
2177 */
2178 order_start_then_action(remote_rsc, action,
2179 pe_order_implies_then, data_set);
2180
2181 } else {
2182 pe_node_t *cluster_node = pe__current_node(remote_rsc);
2183
2184 if(task == monitor_rsc && state == remote_state_failed) {
2185 /* We would only be here if we do not know the
2186 * state of the resource on the remote node.
2187 * Since we have no way to find out, it is
2188 * necessary to fence the node.
2189 */
2190 pe_fence_node(data_set, action->node, "resources are in an unknown state and the connection is unrecoverable", FALSE);
2191 }
2192
2193 if(cluster_node && state == remote_state_stopped) {
2194 /* The connection is currently up, but is going
2195 * down permanently.
2196 *
2197 * Make sure we check services are actually
2198 * stopped _before_ we let the connection get
2199 * closed
2200 */
2201 order_action_then_stop(action, remote_rsc,
2202 pe_order_runnable_left, data_set);
2203
2204 } else {
2205 order_start_then_action(remote_rsc, action, pe_order_none,
2206 data_set);
2207 }
2208 }
2209 break;
2210 }
2211}
2212
2213static void
2214apply_remote_node_ordering(pe_working_set_t *data_set)
2215{
2216 if (!pcmk_is_set(data_set->flags, pe_flag_have_remote_nodes)) {
2217 return;
2218 }
2219
2220 for (GList *gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
2221 pe_action_t *action = (pe_action_t *) gIter->data;
2222 pe_resource_t *remote = NULL;
2223
2224 // We are only interested in resource actions
2225 if (action->rsc == NULL) {
2226 continue;
2227 }
2228
2229 /* Special case: If we are clearing the failcount of an actual
2230 * remote connection resource, then make sure this happens before
2231 * any start of the resource in this transition.
2232 */
2233 if (action->rsc->is_remote_node &&
2234 pcmk__str_eq(action->task, CRM_OP_CLEAR_FAILCOUNT, pcmk__str_casei)) {
2235
2237 NULL,
2238 action,
2239 action->rsc,
2240 pcmk__op_key(action->rsc->id, RSC_START, 0),
2241 NULL,
2243 data_set);
2244
2245 continue;
2246 }
2247
2248 // We are only interested in actions allocated to a node
2249 if (action->node == NULL) {
2250 continue;
2251 }
2252
2253 if (!pe__is_guest_or_remote_node(action->node)) {
2254 continue;
2255 }
2256
2257 /* We are only interested in real actions.
2258 *
2259 * @TODO This is probably wrong; pseudo-actions might be converted to
2260 * real actions and vice versa later in update_actions() at the end of
2261 * stage7().
2262 */
2263 if (pcmk_is_set(action->flags, pe_action_pseudo)) {
2264 continue;
2265 }
2266
2267 remote = action->node->details->remote_rsc;
2268 if (remote == NULL) {
2269 // Orphaned
2270 continue;
2271 }
2272
2273 /* Another special case: if a resource is moving to a Pacemaker Remote
2274 * node, order the stop on the original node after any start of the
2275 * remote connection. This ensures that if the connection fails to
2276 * start, we leave the resource running on the original node.
2277 */
2278 if (pcmk__str_eq(action->task, RSC_START, pcmk__str_casei)) {
2279 for (GList *item = action->rsc->actions; item != NULL;
2280 item = item->next) {
2281 pe_action_t *rsc_action = item->data;
2282
2283 if ((rsc_action->node->details != action->node->details)
2284 && pcmk__str_eq(rsc_action->task, RSC_STOP, pcmk__str_casei)) {
2285 custom_action_order(remote, start_key(remote), NULL,
2286 action->rsc, NULL, rsc_action,
2287 pe_order_optional, data_set);
2288 }
2289 }
2290 }
2291
2292 /* The action occurs across a remote connection, so create
2293 * ordering constraints that guarantee the action occurs while the node
2294 * is active (after start, before stop ... things like that).
2295 *
2296 * This is somewhat brittle in that we need to make sure the results of
2297 * this ordering are compatible with the result of get_router_node().
2298 * It would probably be better to add XML_LRM_ATTR_ROUTER_NODE as part
2299 * of this logic rather than action2xml().
2300 */
2301 if (remote->container) {
2302 crm_trace("Container ordering for %s", action->uuid);
2303 apply_container_ordering(action, data_set);
2304
2305 } else {
2306 crm_trace("Remote ordering for %s", action->uuid);
2307 apply_remote_ordering(action, data_set);
2308 }
2309 }
2310}
2311
2312static gboolean
2313order_first_probe_unneeded(pe_action_t * probe, pe_action_t * rh_action)
2314{
2315 /* No need to probe the resource on the node that is being
2316 * unfenced. Otherwise it might introduce transition loop
2317 * since probe will be performed after the node is
2318 * unfenced.
2319 */
2320 if (pcmk__str_eq(rh_action->task, CRM_OP_FENCE, pcmk__str_casei)
2321 && probe->node && rh_action->node
2322 && probe->node->details == rh_action->node->details) {
2323 const char *op = g_hash_table_lookup(rh_action->meta, "stonith_action");
2324
2325 if (pcmk__str_eq(op, "on", pcmk__str_casei)) {
2326 return TRUE;
2327 }
2328 }
2329
2330 // Shutdown waits for probe to complete only if it's on the same node
2331 if ((pcmk__str_eq(rh_action->task, CRM_OP_SHUTDOWN, pcmk__str_casei))
2332 && probe->node && rh_action->node
2333 && probe->node->details != rh_action->node->details) {
2334 return TRUE;
2335 }
2336 return FALSE;
2337}
2338
2339static void
2340order_first_probes_imply_stops(pe_working_set_t * data_set)
2341{
2342 GList *gIter = NULL;
2343
2344 for (gIter = data_set->ordering_constraints; gIter != NULL; gIter = gIter->next) {
2345 pe__ordering_t *order = gIter->data;
2346 enum pe_ordering order_type = pe_order_optional;
2347
2348 pe_resource_t *lh_rsc = order->lh_rsc;
2349 pe_resource_t *rh_rsc = order->rh_rsc;
2350 pe_action_t *lh_action = order->lh_action;
2351 pe_action_t *rh_action = order->rh_action;
2352 const char *lh_action_task = order->lh_action_task;
2353 const char *rh_action_task = order->rh_action_task;
2354
2355 GList *probes = NULL;
2356 GList *rh_actions = NULL;
2357
2358 GList *pIter = NULL;
2359
2360 if (lh_rsc == NULL) {
2361 continue;
2362
2363 } else if (rh_rsc && lh_rsc == rh_rsc) {
2364 continue;
2365 }
2366
2367 if (lh_action == NULL && lh_action_task == NULL) {
2368 continue;
2369 }
2370
2371 if (rh_action == NULL && rh_action_task == NULL) {
2372 continue;
2373 }
2374
2375 /* Technically probe is expected to return "not running", which could be
2376 * the alternative of stop action if the status of the resource is
2377 * unknown yet.
2378 */
2379 if (lh_action && !pcmk__str_eq(lh_action->task, RSC_STOP, pcmk__str_casei)) {
2380 continue;
2381
2382 } else if (lh_action == NULL
2383 && lh_action_task
2384 && !pcmk__ends_with(lh_action_task, "_" RSC_STOP "_0")) {
2385 continue;
2386 }
2387
2388 /* Do not probe the resource inside of a stopping container. Otherwise
2389 * it might introduce transition loop since probe will be performed
2390 * after the container starts again.
2391 */
2392 if (rh_rsc && lh_rsc->container == rh_rsc) {
2393 if (rh_action && pcmk__str_eq(rh_action->task, RSC_STOP, pcmk__str_casei)) {
2394 continue;
2395
2396 } else if (rh_action == NULL && rh_action_task
2397 && pcmk__ends_with(rh_action_task,"_" RSC_STOP "_0")) {
2398 continue;
2399 }
2400 }
2401
2402 if (order->type == pe_order_none) {
2403 continue;
2404 }
2405
2406 // Preserve the order options for future filtering
2408 pe__set_order_flags(order_type,
2410 }
2411
2412 if (pcmk_is_set(order->type, pe_order_same_node)) {
2414 }
2415
2416 // Keep the order types for future filtering
2417 if (order->type == pe_order_anti_colocation
2418 || order->type == pe_order_load) {
2419 order_type = order->type;
2420 }
2421
2422 probes = pe__resource_actions(lh_rsc, NULL, RSC_STATUS, FALSE);
2423 if (probes == NULL) {
2424 continue;
2425 }
2426
2427 if (rh_action) {
2428 rh_actions = g_list_prepend(rh_actions, rh_action);
2429
2430 } else if (rh_rsc && rh_action_task) {
2431 rh_actions = find_actions(rh_rsc->actions, rh_action_task, NULL);
2432 }
2433
2434 if (rh_actions == NULL) {
2435 g_list_free(probes);
2436 continue;
2437 }
2438
2439 crm_trace("Processing for LH probe based on ordering constraint %s -> %s"
2440 " (id=%d, type=%.6x)",
2441 lh_action ? lh_action->uuid : lh_action_task,
2442 rh_action ? rh_action->uuid : rh_action_task,
2443 order->id, order->type);
2444
2445 for (pIter = probes; pIter != NULL; pIter = pIter->next) {
2446 pe_action_t *probe = (pe_action_t *) pIter->data;
2447 GList *rIter = NULL;
2448
2449 for (rIter = rh_actions; rIter != NULL; rIter = rIter->next) {
2450 pe_action_t *rh_action_iter = (pe_action_t *) rIter->data;
2451
2452 if (order_first_probe_unneeded(probe, rh_action_iter)) {
2453 continue;
2454 }
2455 order_actions(probe, rh_action_iter, order_type);
2456 }
2457 }
2458
2459 g_list_free(rh_actions);
2460 g_list_free(probes);
2461 }
2462}
2463
2464static void
2465order_first_probe_then_restart_repromote(pe_action_t * probe,
2466 pe_action_t * after,
2467 pe_working_set_t * data_set)
2468{
2469 GList *gIter = NULL;
2470 bool interleave = FALSE;
2471 pe_resource_t *compatible_rsc = NULL;
2472
2473 if (probe == NULL
2474 || probe->rsc == NULL
2475 || probe->rsc->variant != pe_native) {
2476 return;
2477 }
2478
2479 if (after == NULL
2480 // Avoid running into any possible loop
2481 || pcmk_is_set(after->flags, pe_action_tracking)) {
2482 return;
2483 }
2484
2485 if (!pcmk__str_eq(probe->task, RSC_STATUS, pcmk__str_casei)) {
2486 return;
2487 }
2488
2490
2491 crm_trace("Processing based on %s %s -> %s %s",
2492 probe->uuid,
2493 probe->node ? probe->node->details->uname: "",
2494 after->uuid,
2495 after->node ? after->node->details->uname : "");
2496
2497 if (after->rsc
2498 /* Better not build a dependency directly with a clone/group.
2499 * We are going to proceed through the ordering chain and build
2500 * dependencies with its children.
2501 */
2502 && after->rsc->variant == pe_native
2503 && probe->rsc != after->rsc) {
2504
2505 GList *then_actions = NULL;
2506 enum pe_ordering probe_order_type = pe_order_optional;
2507
2508 if (pcmk__str_eq(after->task, RSC_START, pcmk__str_casei)) {
2509 then_actions = pe__resource_actions(after->rsc, NULL, RSC_STOP, FALSE);
2510
2511 } else if (pcmk__str_eq(after->task, RSC_PROMOTE, pcmk__str_casei)) {
2512 then_actions = pe__resource_actions(after->rsc, NULL, RSC_DEMOTE, FALSE);
2513 }
2514
2515 for (gIter = then_actions; gIter != NULL; gIter = gIter->next) {
2516 pe_action_t *then = (pe_action_t *) gIter->data;
2517
2518 // Skip any pseudo action which for example is implied by fencing
2519 if (pcmk_is_set(then->flags, pe_action_pseudo)) {
2520 continue;
2521 }
2522
2523 order_actions(probe, then, probe_order_type);
2524 }
2525 g_list_free(then_actions);
2526 }
2527
2528 if (after->rsc
2529 && after->rsc->variant > pe_group) {
2530 const char *interleave_s = g_hash_table_lookup(after->rsc->meta,
2532
2533 interleave = crm_is_true(interleave_s);
2534
2535 if (interleave) {
2536 /* For an interleaved clone, we should build a dependency only
2537 * with the relevant clone child.
2538 */
2539 compatible_rsc = find_compatible_child(probe->rsc,
2540 after->rsc,
2542 FALSE, data_set);
2543 }
2544 }
2545
2546 for (gIter = after->actions_after; gIter != NULL; gIter = gIter->next) {
2547 pe_action_wrapper_t *after_wrapper = (pe_action_wrapper_t *) gIter->data;
2548 /* pe_order_implies_then is the reason why a required A.start
2549 * implies/enforces B.start to be required too, which is the cause of
2550 * B.restart/re-promote.
2551 *
2552 * Not sure about pe_order_implies_then_on_node though. It's now only
2553 * used for unfencing case, which tends to introduce transition
2554 * loops...
2555 */
2556
2557 if (!pcmk_is_set(after_wrapper->type, pe_order_implies_then)) {
2558 /* The order type between a group/clone and its child such as
2559 * B.start-> B_child.start is:
2560 * pe_order_implies_first_printed | pe_order_runnable_left
2561 *
2562 * Proceed through the ordering chain and build dependencies with
2563 * its children.
2564 */
2565 if (after->rsc == NULL
2566 || after->rsc->variant < pe_group
2567 || probe->rsc->parent == after->rsc
2568 || after_wrapper->action->rsc == NULL
2569 || after_wrapper->action->rsc->variant > pe_group
2570 || after->rsc != after_wrapper->action->rsc->parent) {
2571 continue;
2572 }
2573
2574 /* Proceed to the children of a group or a non-interleaved clone.
2575 * For an interleaved clone, proceed only to the relevant child.
2576 */
2577 if (after->rsc->variant > pe_group
2578 && interleave == TRUE
2579 && (compatible_rsc == NULL
2580 || compatible_rsc != after_wrapper->action->rsc)) {
2581 continue;
2582 }
2583 }
2584
2585 crm_trace("Proceeding through %s %s -> %s %s (type=0x%.6x)",
2586 after->uuid,
2587 after->node ? after->node->details->uname: "",
2588 after_wrapper->action->uuid,
2589 after_wrapper->action->node ? after_wrapper->action->node->details->uname : "",
2590 after_wrapper->type);
2591
2592 order_first_probe_then_restart_repromote(probe, after_wrapper->action, data_set);
2593 }
2594}
2595
2596static void clear_actions_tracking_flag(pe_working_set_t * data_set)
2597{
2598 GList *gIter = NULL;
2599
2600 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
2601 pe_action_t *action = (pe_action_t *) gIter->data;
2602
2603 if (pcmk_is_set(action->flags, pe_action_tracking)) {
2605 }
2606 }
2607}
2608
2609static void
2610order_first_rsc_probes(pe_resource_t * rsc, pe_working_set_t * data_set)
2611{
2612 GList *gIter = NULL;
2613 GList *probes = NULL;
2614
2615 for (gIter = rsc->children; gIter != NULL; gIter = gIter->next) {
2616 pe_resource_t * child = (pe_resource_t *) gIter->data;
2617
2618 order_first_rsc_probes(child, data_set);
2619 }
2620
2621 if (rsc->variant != pe_native) {
2622 return;
2623 }
2624
2625 probes = pe__resource_actions(rsc, NULL, RSC_STATUS, FALSE);
2626
2627 for (gIter = probes; gIter != NULL; gIter= gIter->next) {
2628 pe_action_t *probe = (pe_action_t *) gIter->data;
2629 GList *aIter = NULL;
2630
2631 for (aIter = probe->actions_after; aIter != NULL; aIter = aIter->next) {
2632 pe_action_wrapper_t *after_wrapper = (pe_action_wrapper_t *) aIter->data;
2633
2634 order_first_probe_then_restart_repromote(probe, after_wrapper->action, data_set);
2635 clear_actions_tracking_flag(data_set);
2636 }
2637 }
2638
2639 g_list_free(probes);
2640}
2641
2642static void
2643order_first_probes(pe_working_set_t * data_set)
2644{
2645 GList *gIter = NULL;
2646
2647 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
2648 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2649
2650 order_first_rsc_probes(rsc, data_set);
2651 }
2652
2653 order_first_probes_imply_stops(data_set);
2654}
2655
2656static void
2657order_then_probes(pe_working_set_t * data_set)
2658{
2659#if 0
2660 GList *gIter = NULL;
2661
2662 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
2663 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2664
2665 /* Given "A then B", we would prefer to wait for A to be
2666 * started before probing B.
2667 *
2668 * If A was a filesystem on which the binaries and data for B
2669 * lived, it would have been useful if the author of B's agent
2670 * could assume that A is running before B.monitor will be
2671 * called.
2672 *
2673 * However we can't _only_ probe once A is running, otherwise
2674 * we'd not detect the state of B if A could not be started
2675 * for some reason.
2676 *
2677 * In practice however, we cannot even do an opportunistic
2678 * version of this because B may be moving:
2679 *
2680 * B.probe -> B.start
2681 * B.probe -> B.stop
2682 * B.stop -> B.start
2683 * A.stop -> A.start
2684 * A.start -> B.probe
2685 *
2686 * So far so good, but if we add the result of this code:
2687 *
2688 * B.stop -> A.stop
2689 *
2690 * Then we get a loop:
2691 *
2692 * B.probe -> B.stop -> A.stop -> A.start -> B.probe
2693 *
2694 * We could kill the 'B.probe -> B.stop' dependency, but that
2695 * could mean stopping B "too" soon, because B.start must wait
2696 * for the probes to complete.
2697 *
2698 * Another option is to allow it only if A is a non-unique
2699 * clone with clone-max == node-max (since we'll never be
2700 * moving it). However, we could still be stopping one
2701 * instance at the same time as starting another.
2702
2703 * The complexity of checking for allowed conditions combined
2704 * with the ever narrowing usecase suggests that this code
2705 * should remain disabled until someone gets smarter.
2706 */
2707 pe_action_t *start = NULL;
2708 GList *actions = NULL;
2709 GList *probes = NULL;
2710
2711 actions = pe__resource_actions(rsc, NULL, RSC_START, FALSE);
2712
2713 if (actions) {
2714 start = actions->data;
2715 g_list_free(actions);
2716 }
2717
2718 if(start == NULL) {
2719 crm_err("No start action for %s", rsc->id);
2720 continue;
2721 }
2722
2723 probes = pe__resource_actions(rsc, NULL, RSC_STATUS, FALSE);
2724
2725 for (actions = start->actions_before; actions != NULL; actions = actions->next) {
2726 pe_action_wrapper_t *before = (pe_action_wrapper_t *) actions->data;
2727
2728 GList *pIter = NULL;
2729 pe_action_t *first = before->action;
2730 pe_resource_t *first_rsc = first->rsc;
2731
2732 if(first->required_runnable_before) {
2733 GList *clone_actions = NULL;
2734 for (clone_actions = first->actions_before; clone_actions != NULL; clone_actions = clone_actions->next) {
2735 before = (pe_action_wrapper_t *) clone_actions->data;
2736
2737 crm_trace("Testing %s -> %s (%p) for %s", first->uuid, before->action->uuid, before->action->rsc, start->uuid);
2738
2739 CRM_ASSERT(before->action->rsc);
2740 first_rsc = before->action->rsc;
2741 break;
2742 }
2743
2744 } else if(!pcmk__str_eq(first->task, RSC_START, pcmk__str_casei)) {
2745 crm_trace("Not a start op %s for %s", first->uuid, start->uuid);
2746 }
2747
2748 if(first_rsc == NULL) {
2749 continue;
2750
2751 } else if(uber_parent(first_rsc) == uber_parent(start->rsc)) {
2752 crm_trace("Same parent %s for %s", first_rsc->id, start->uuid);
2753 continue;
2754
2755 } else if(FALSE && pe_rsc_is_clone(uber_parent(first_rsc)) == FALSE) {
2756 crm_trace("Not a clone %s for %s", first_rsc->id, start->uuid);
2757 continue;
2758 }
2759
2760 crm_err("Applying %s before %s %d", first->uuid, start->uuid, uber_parent(first_rsc)->variant);
2761
2762 for (pIter = probes; pIter != NULL; pIter = pIter->next) {
2763 pe_action_t *probe = (pe_action_t *) pIter->data;
2764
2765 crm_err("Ordering %s before %s", first->uuid, probe->uuid);
2766 order_actions(first, probe, pe_order_optional);
2767 }
2768 }
2769 }
2770#endif
2771}
2772
2773static void
2774order_probes(pe_working_set_t * data_set)
2775{
2776 order_first_probes(data_set);
2777 order_then_probes(data_set);
2778}
2779
2780gboolean
2782{
2783 pcmk__output_t *prev_out = data_set->priv;
2784 pcmk__output_t *out = NULL;
2785 GList *gIter = NULL;
2786
2787 crm_trace("Applying ordering constraints");
2788
2789 /* Don't ask me why, but apparently they need to be processed in
2790 * the order they were created in... go figure
2791 *
2792 * Also g_list_append() has horrendous performance characteristics
2793 * So we need to use g_list_prepend() and then reverse the list here
2794 */
2795 data_set->ordering_constraints = g_list_reverse(data_set->ordering_constraints);
2796
2797 for (gIter = data_set->ordering_constraints; gIter != NULL; gIter = gIter->next) {
2798 pe__ordering_t *order = gIter->data;
2799 pe_resource_t *rsc = order->lh_rsc;
2800
2801 crm_trace("Applying ordering constraint: %d", order->id);
2802
2803 if (rsc != NULL) {
2804 crm_trace("rsc_action-to-*");
2805 rsc_order_first(rsc, order, data_set);
2806 continue;
2807 }
2808
2809 rsc = order->rh_rsc;
2810 if (rsc != NULL) {
2811 crm_trace("action-to-rsc_action");
2812 rsc_order_then(order->lh_action, rsc, order);
2813
2814 } else {
2815 crm_trace("action-to-action");
2816 order_actions(order->lh_action, order->rh_action, order->type);
2817 }
2818 }
2819
2820 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
2821 pe_action_t *action = (pe_action_t *) gIter->data;
2822
2824 }
2825
2826 crm_trace("Ordering probes");
2827 order_probes(data_set);
2828
2829 crm_trace("Updating %d actions", g_list_length(data_set->actions));
2830 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
2831 pe_action_t *action = (pe_action_t *) gIter->data;
2832
2833 update_action(action, data_set);
2834 }
2835
2836 // Check for invalid orderings
2837 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
2838 pe_action_t *action = (pe_action_t *) gIter->data;
2839 pe_action_wrapper_t *input = NULL;
2840
2841 for (GList *input_iter = action->actions_before;
2842 input_iter != NULL; input_iter = input_iter->next) {
2843
2844 input = (pe_action_wrapper_t *) input_iter->data;
2845 if (pcmk__ordering_is_invalid(action, input)) {
2846 input->type = pe_order_none;
2847 }
2848 }
2849 }
2850
2851 /* stage7 only ever outputs to the log, so ignore whatever output object was
2852 * previously set and just log instead.
2853 */
2854 out = pcmk__new_logger();
2855 if (out == NULL) {
2856 return FALSE;
2857 }
2858
2859 pcmk__output_set_log_level(out, LOG_NOTICE);
2860 data_set->priv = out;
2861
2862 out->begin_list(out, NULL, NULL, "Actions");
2863 LogNodeActions(data_set);
2864
2865 for (gIter = data_set->resources; gIter != NULL; gIter = gIter->next) {
2866 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2867
2868 LogActions(rsc, data_set);
2869 }
2870
2871 out->end_list(out);
2872 out->finish(out, CRM_EX_OK, true, NULL);
2873 pcmk__output_free(out);
2874
2875 data_set->priv = prev_out;
2876 return TRUE;
2877}
2878
2879static int transition_id = -1;
2880
2887void
2888pcmk__log_transition_summary(const char *filename)
2889{
2891 crm_err("Calculated transition %d (with errors)%s%s",
2892 transition_id,
2893 (filename == NULL)? "" : ", saving inputs in ",
2894 (filename == NULL)? "" : filename);
2895
2896 } else if (was_processing_warning) {
2897 crm_warn("Calculated transition %d (with warnings)%s%s",
2898 transition_id,
2899 (filename == NULL)? "" : ", saving inputs in ",
2900 (filename == NULL)? "" : filename);
2901
2902 } else {
2903 crm_notice("Calculated transition %d%s%s",
2904 transition_id,
2905 (filename == NULL)? "" : ", saving inputs in ",
2906 (filename == NULL)? "" : filename);
2907 }
2908 if (crm_config_error) {
2909 crm_notice("Configuration errors found during scheduler processing,"
2910 " please run \"crm_verify -L\" to identify issues");
2911 }
2912}
2913
2914/*
2915 * Create a dependency graph to send to the transitioner (via the controller)
2916 */
2917gboolean
2919{
2920 GList *gIter = NULL;
2921 const char *value = NULL;
2922 long long limit = 0LL;
2923
2924 transition_id++;
2925 crm_trace("Creating transition graph %d.", transition_id);
2926
2927 data_set->graph = create_xml_node(NULL, XML_TAG_GRAPH);
2928
2929 value = pe_pref(data_set->config_hash, "cluster-delay");
2930 crm_xml_add(data_set->graph, "cluster-delay", value);
2931
2932 value = pe_pref(data_set->config_hash, "stonith-timeout");
2933 crm_xml_add(data_set->graph, "stonith-timeout", value);
2934
2935 crm_xml_add(data_set->graph, "failed-stop-offset", "INFINITY");
2936
2938 crm_xml_add(data_set->graph, "failed-start-offset", "INFINITY");
2939 } else {
2940 crm_xml_add(data_set->graph, "failed-start-offset", "1");
2941 }
2942
2943 value = pe_pref(data_set->config_hash, "batch-limit");
2944 crm_xml_add(data_set->graph, "batch-limit", value);
2945
2946 crm_xml_add_int(data_set->graph, "transition_id", transition_id);
2947
2948 value = pe_pref(data_set->config_hash, "migration-limit");
2949 if ((pcmk__scan_ll(value, &limit, 0LL) == pcmk_rc_ok) && (limit > 0)) {
2950 crm_xml_add(data_set->graph, "migration-limit", value);
2951 }
2952
2953 if (data_set->recheck_by > 0) {
2954 char *recheck_epoch = NULL;
2955
2956 recheck_epoch = crm_strdup_printf("%llu",
2957 (long long) data_set->recheck_by);
2958 crm_xml_add(data_set->graph, "recheck-by", recheck_epoch);
2959 free(recheck_epoch);
2960 }
2961
2962/* errors...
2963 slist_iter(action, pe_action_t, action_list, lpc,
2964 if(action->optional == FALSE && action->runnable == FALSE) {
2965 print_action("Ignoring", action, TRUE);
2966 }
2967 );
2968*/
2969
2970 /* The following code will de-duplicate action inputs, so nothing past this
2971 * should rely on the action input type flags retaining their original
2972 * values.
2973 */
2974
2975 gIter = data_set->resources;
2976 for (; gIter != NULL; gIter = gIter->next) {
2977 pe_resource_t *rsc = (pe_resource_t *) gIter->data;
2978
2979 pe_rsc_trace(rsc, "processing actions for rsc=%s", rsc->id);
2980 rsc->cmds->expand(rsc, data_set);
2981 }
2982
2983 crm_log_xml_trace(data_set->graph, "created resource-driven action list");
2984
2985 /* pseudo action to distribute list of nodes with maintenance state update */
2986 add_maintenance_update(data_set);
2987
2988 /* catch any non-resource specific actions */
2989 crm_trace("processing non-resource actions");
2990
2991 gIter = data_set->actions;
2992 for (; gIter != NULL; gIter = gIter->next) {
2993 pe_action_t *action = (pe_action_t *) gIter->data;
2994
2995 if (action->rsc
2996 && action->node
2997 && action->node->details->shutdown
2998 && !pcmk_is_set(action->rsc->flags, pe_rsc_maintenance)
2999 && !pcmk_any_flags_set(action->flags,
3001 && pcmk__str_eq(action->task, RSC_STOP, pcmk__str_none)
3002 ) {
3003 /* Eventually we should just ignore the 'fence' case
3004 * But for now it's the best way to detect (in CTS) when
3005 * CIB resource updates are being lost
3006 */
3007 if (pcmk_is_set(data_set->flags, pe_flag_have_quorum)
3008 || data_set->no_quorum_policy == no_quorum_ignore) {
3009 crm_crit("Cannot %s node '%s' because of %s:%s%s (%s)",
3010 action->node->details->unclean ? "fence" : "shut down",
3011 action->node->details->uname, action->rsc->id,
3012 pcmk_is_set(action->rsc->flags, pe_rsc_managed)? " blocked" : " unmanaged",
3013 pcmk_is_set(action->rsc->flags, pe_rsc_failed)? " failed" : "",
3014 action->uuid);
3015 }
3016 }
3017
3019 }
3020
3021 crm_log_xml_trace(data_set->graph, "created generic action list");
3022 crm_trace("Created transition graph %d.", transition_id);
3023
3024 return TRUE;
3025}
3026
3027void
3029{
3030 pcmk__output_t *out = data_set->priv;
3031 GList *gIter = NULL;
3032
3033 for (gIter = data_set->actions; gIter != NULL; gIter = gIter->next) {
3034 char *node_name = NULL;
3035 char *task = NULL;
3036 pe_action_t *action = (pe_action_t *) gIter->data;
3037
3038 if (action->rsc != NULL) {
3039 continue;
3040 } else if (pcmk_is_set(action->flags, pe_action_optional)) {
3041 continue;
3042 }
3043
3044 if (pe__is_guest_node(action->node)) {
3045 node_name = crm_strdup_printf("%s (resource: %s)", action->node->details->uname, action->node->details->remote_rsc->container->id);
3046 } else if(action->node) {
3047 node_name = crm_strdup_printf("%s", action->node->details->uname);
3048 }
3049
3050
3051 if (pcmk__str_eq(action->task, CRM_OP_SHUTDOWN, pcmk__str_casei)) {
3052 task = strdup("Shutdown");
3053 } else if (pcmk__str_eq(action->task, CRM_OP_FENCE, pcmk__str_casei)) {
3054 const char *op = g_hash_table_lookup(action->meta, "stonith_action");
3055 task = crm_strdup_printf("Fence (%s)", op);
3056 }
3057
3058 out->message(out, "node-action", task, node_name, action->reason);
3059
3060 free(node_name);
3061 free(task);
3062 }
3063}
xmlNode * get_object_root(const char *object_type, xmlNode *the_root)
Definition cib_utils.c:146
Cluster Configuration.
int pcmk__score_yellow
Definition utils.c:58
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
Definition operations.c:45
int pcmk__score_green
Definition utils.c:57
#define PCMK__NELEM(a)
Definition internal.h:38
#define PCMK__OP_FMT
Definition internal.h:168
int pcmk__score_red
Definition utils.c:56
uint64_t flags
Definition remote.c:3
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
Definition operations.c:185
int char2score(const char *score)
Definition utils.c:61
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
Definition strings.c:415
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
Definition util.h:114
enum action_tasks text2task(const char *task)
Definition common.c:354
void calculate_active_ops(GList *sorted_op_list, int *start_index, int *stop_index)
Definition unpack.c:2253
gboolean was_processing_error
Definition common.c:20
const char * pe_pref(GHashTable *options, const char *name)
Definition common.c:308
action_tasks
Definition common.h:62
@ no_action
Definition common.h:63
@ start_rsc
Definition common.h:67
@ action_demote
Definition common.h:73
@ stop_rsc
Definition common.h:65
@ action_promote
Definition common.h:71
@ monitor_rsc
Definition common.h:64
@ RSC_ROLE_STOPPED
Definition common.h:94
@ RSC_ROLE_UNKNOWN
Definition common.h:93
@ RSC_ROLE_UNPROMOTED
Definition common.h:96
gboolean was_processing_warning
Definition common.c:21
pe_resource_t * uber_parent(pe_resource_t *rsc)
Definition complex.c:903
enum crm_ais_msg_types type
Definition cpg.c:3
char uname[MAX_NAME]
Definition cpg.c:5
char data[0]
Definition cpg.c:10
uint32_t id
Definition cpg.c:0
A dumping ground.
#define CRMD_ACTION_STOP
Definition crm.h:179
#define CRM_SCORE_INFINITY
Definition crm.h:85
#define RSC_PROMOTE
Definition crm.h:207
#define RSC_DEMOTE
Definition crm.h:209
#define CRM_OP_SHUTDOWN
Definition crm.h:144
#define CRM_OP_REPROBE
Definition crm.h:154
#define CRMD_ACTION_MIGRATED
Definition crm.h:174
#define RSC_START
Definition crm.h:201
#define CRM_OP_CLEAR_FAILCOUNT
Definition crm.h:155
#define INFINITY
Definition crm.h:99
#define RSC_STOP
Definition crm.h:204
#define CRMD_ACTION_MIGRATE
Definition crm.h:173
#define CRMD_ACTION_START
Definition crm.h:176
#define RSC_STATUS
Definition crm.h:215
#define RSC_MIGRATED
Definition crm.h:199
#define CRM_OP_PROBED
Definition crm.h:153
#define CRM_OP_FENCE
Definition crm.h:145
#define CRM_TRACE_INIT_DATA(name)
Definition logging.h:143
#define crm_log_xml_info(xml, text)
Definition logging.h:362
#define crm_str(x)
Definition logging.h:376
#define crm_info(fmt, args...)
Definition logging.h:353
#define crm_warn(fmt, args...)
Definition logging.h:351
#define crm_crit(fmt, args...)
Definition logging.h:349
#define crm_notice(fmt, args...)
Definition logging.h:352
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_debug(fmt, args...)
Definition logging.h:355
#define crm_err(fmt, args...)
Definition logging.h:350
gboolean crm_config_error
Definition utils.c:52
#define crm_log_xml_trace(xml, text)
Definition logging.h:364
#define crm_trace(fmt, args...)
Definition logging.h:356
#define XML_LRM_TAG_RSC_OP
Definition msg_xml.h:265
#define ID(x)
Definition msg_xml.h:456
#define XML_BOOLEAN_TRUE
Definition msg_xml.h:140
#define XML_ATTR_TE_NOWAIT
Definition msg_xml.h:401
#define XML_LRM_ATTR_SECURE_DIGEST
Definition msg_xml.h:314
#define XML_LRM_TAG_RESOURCES
Definition msg_xml.h:263
#define XML_CIB_TAG_STATE
Definition msg_xml.h:198
#define XML_CONFIG_ATTR_SHUTDOWN_LOCK
Definition msg_xml.h:387
#define XML_ATTR_ID
Definition msg_xml.h:129
#define XML_CIB_TAG_CONSTRAINTS
Definition msg_xml.h:183
#define XML_ATTR_TRANSITION_MAGIC
Definition msg_xml.h:398
#define XML_LRM_ATTR_RESTART_DIGEST
Definition msg_xml.h:313
#define XML_AGENT_ATTR_PROVIDER
Definition msg_xml.h:267
#define XML_AGENT_ATTR_CLASS
Definition msg_xml.h:266
#define XML_TAG_GRAPH
Definition msg_xml.h:325
#define XML_LRM_ATTR_TASK
Definition msg_xml.h:297
#define XML_CIB_ATTR_SHUTDOWN
Definition msg_xml.h:283
#define XML_ATTR_TYPE
Definition msg_xml.h:132
#define XML_CIB_TAG_STATUS
Definition msg_xml.h:179
#define XML_LRM_ATTR_CALLID
Definition msg_xml.h:309
#define XML_RSC_ATTR_INTERLEAVE
Definition msg_xml.h:224
#define XML_CIB_TAG_LRM
Definition msg_xml.h:262
#define XML_LRM_ATTR_INTERVAL_MS
Definition msg_xml.h:295
#define XML_LRM_TAG_RESOURCE
Definition msg_xml.h:264
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
Definition nvpair.c:530
const char * crm_xml_add_int(xmlNode *node, const char *name, int value)
Create an XML attribute with specified name and integer value.
Definition nvpair.c:432
int crm_element_value_ms(const xmlNode *data, const char *name, guint *dest)
Retrieve the millisecond value of an XML attribute.
Definition nvpair.c:623
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
Definition nvpair.c:324
void pcmk__output_free(pcmk__output_t *out)
Definition output.c:19
void pcmk__output_set_log_level(pcmk__output_t *out, int log_level)
Definition output_log.c:303
const char * action
Definition pcmk_fence.c:30
int rc
Definition pcmk_fence.c:35
gboolean stage3(pe_working_set_t *data_set)
gboolean stage8(pe_working_set_t *data_set)
resource_alloc_functions_t resource_class_alloc_functions[]
void ReloadRsc(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
gboolean DeleteRsc(pe_resource_t *rsc, pe_node_t *node, gboolean optional, pe_working_set_t *data_set)
void LogNodeActions(pe_working_set_t *data_set)
void complex_set_cmds(pe_resource_t *rsc)
gboolean stage4(pe_working_set_t *data_set)
gboolean stage5(pe_working_set_t *data_set)
gboolean stage7(pe_working_set_t *data_set)
void update_colo_start_chain(pe_action_t *action, pe_working_set_t *data_set)
void set_alloc_actions(pe_working_set_t *data_set)
bool pcmk__is_daemon
Definition logging.c:47
void pcmk__log_transition_summary(const char *filename)
gboolean stage6(pe_working_set_t *data_set)
remote_connection_state
@ remote_state_failed
@ remote_state_unknown
@ remote_state_alive
@ remote_state_stopped
@ remote_state_resting
gboolean probe_resources(pe_working_set_t *data_set)
gboolean stage2(pe_working_set_t *data_set)
gboolean stage0(pe_working_set_t *data_set)
void native_append_meta(pe_resource_t *rsc, xmlNode *xml)
GHashTable * pcmk__group_merge_weights(pe_resource_t *rsc, const char *rhs, GHashTable *nodes, const char *attr, float factor, uint32_t flags)
enum pe_action_flags pcmk__bundle_action_flags(pe_action_t *action, pe_node_t *node)
void clone_rsc_colocation_lh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
pe_node_t * pcmk__native_allocate(pe_resource_t *rsc, pe_node_t *preferred, pe_working_set_t *data_set)
gboolean pcmk__bundle_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
void group_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void native_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void pcmk__bundle_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
enum pe_action_flags group_action_flags(pe_action_t *action, pe_node_t *node)
void LogActions(pe_resource_t *rsc, pe_working_set_t *data_set)
void pcmk__bundle_append_meta(pe_resource_t *rsc, xmlNode *xml)
void pcmk__bundle_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
enum pe_action_flags clone_action_flags(pe_action_t *action, pe_node_t *node)
void pcmk__bundle_rsc_colocation_lh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
void pcmk__bundle_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void clone_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
void native_rsc_colocation_lh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
void clone_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
void clone_rsc_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
void clone_append_meta(pe_resource_t *rsc, xmlNode *xml)
void native_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
void group_rsc_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
void native_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
gboolean native_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
pe_node_t * pcmk__bundle_allocate(pe_resource_t *rsc, pe_node_t *preferred, pe_working_set_t *data_set)
gboolean update_action(pe_action_t *action, pe_working_set_t *data_set)
pe_node_t * pcmk__clone_allocate(pe_resource_t *rsc, pe_node_t *preferred, pe_working_set_t *data_set)
void clone_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
void pcmk__bundle_rsc_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
pe_node_t * pcmk__group_allocate(pe_resource_t *rsc, pe_node_t *preferred, pe_working_set_t *data_set)
void group_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void group_rsc_colocation_lh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
gboolean clone_create_probe(pe_resource_t *rsc, pe_node_t *node, pe_action_t *complete, gboolean force, pe_working_set_t *data_set)
void native_create_actions(pe_resource_t *rsc, pe_working_set_t *data_set)
enum pe_graph_flags pcmk__multi_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
enum pe_action_flags native_action_flags(pe_action_t *action, pe_node_t *node)
void pcmk__bundle_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
GHashTable * pcmk__native_merge_weights(pe_resource_t *rsc, const char *rhs, GHashTable *nodes, const char *attr, float factor, uint32_t flags)
void clone_internal_constraints(pe_resource_t *rsc, pe_working_set_t *data_set)
void group_rsc_location(pe_resource_t *rsc, pe__location_t *constraint)
void group_append_meta(pe_resource_t *rsc, xmlNode *xml)
enum pe_graph_flags native_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
void native_rsc_colocation_rh(pe_resource_t *lh_rsc, pe_resource_t *rh_rsc, pcmk__colocation_t *constraint, pe_working_set_t *data_set)
enum pe_graph_flags group_update_actions(pe_action_t *first, pe_action_t *then, pe_node_t *node, enum pe_action_flags flags, enum pe_action_flags filter, enum pe_ordering type, pe_working_set_t *data_set)
void group_expand(pe_resource_t *rsc, pe_working_set_t *data_set)
pcmk__output_t * pcmk__new_logger(void)
gboolean can_run_resources(const pe_node_t *node)
pe_resource_t * find_compatible_child(pe_resource_t *local_child, pe_resource_t *rsc, enum rsc_role_e filter, gboolean current, pe_working_set_t *data_set)
pe_action_t * pe_cancel_op(pe_resource_t *rsc, const char *name, guint interval_ms, pe_node_t *node, pe_working_set_t *data_set)
pe__location_t * rsc2node_new(const char *id, pe_resource_t *rsc, int weight, const char *discovery_mode, pe_node_t *node, pe_working_set_t *data_set)
pe_action_t * sched_shutdown_op(pe_node_t *node, pe_working_set_t *data_set)
GList * sort_nodes_by_weight(GList *nodes, pe_node_t *active_node, pe_working_set_t *data_set)
void graph_element_from_action(pe_action_t *action, pe_working_set_t *data_set)
void pcmk__order_vs_fence(pe_action_t *stonith_op, pe_working_set_t *data_set)
bool pcmk__ordering_is_invalid(pe_action_t *action, pe_action_wrapper_t *input)
int custom_action_order(pe_resource_t *lh_rsc, char *lh_task, pe_action_t *lh_action, pe_resource_t *rh_rsc, char *rh_task, pe_action_t *rh_action, enum pe_ordering type, pe_working_set_t *data_set)
void add_maintenance_update(pe_working_set_t *data_set)
gboolean unpack_constraints(xmlNode *xml_constraints, pe_working_set_t *data_set)
@ pe_weights_init
@ pe_weights_forward
@ no_quorum_ignore
Definition pe_types.h:65
pe_check_parameters
Definition pe_types.h:195
@ pe_check_active
Definition pe_types.h:204
@ pe_check_last_failure
Definition pe_types.h:199
#define pe_flag_have_quorum
Definition pe_types.h:94
#define pe_rsc_managed
Definition pe_types.h:249
pe_ordering
Definition pe_types.h:484
@ pe_order_anti_colocation
Definition pe_types.h:519
@ pe_order_implies_then
Definition pe_types.h:490
@ pe_order_same_node
Definition pe_types.h:511
@ pe_order_none
Definition pe_types.h:485
@ pe_order_preserve
Definition pe_types.h:521
@ pe_order_optional
Definition pe_types.h:486
@ pe_order_implies_first
Definition pe_types.h:489
@ pe_order_runnable_left
Definition pe_types.h:496
@ pe_order_load
Definition pe_types.h:517
@ pe_order_apply_first_non_migratable
Definition pe_types.h:487
#define pe_flag_shutdown_lock
Definition pe_types.h:113
#define pe_flag_symmetric_cluster
Definition pe_types.h:95
#define pe_rsc_unique
Definition pe_types.h:254
#define pe_rsc_orphan
Definition pe_types.h:248
@ node_ping
Definition pe_types.h:71
#define pe_flag_startup_probes
Definition pe_types.h:115
#define pe_flag_start_failure_fatal
Definition pe_types.h:107
@ pe_discover_exclusive
Definition pe_types.h:480
#define pe_flag_concurrent_fencing
Definition pe_types.h:101
@ pe_action_optional
Definition pe_types.h:294
@ pe_action_tracking
Definition pe_types.h:314
@ pe_action_runnable
Definition pe_types.h:293
@ pe_action_dangle
Definition pe_types.h:306
@ pe_action_pseudo
Definition pe_types.h:292
@ pe_action_reschedule
Definition pe_types.h:313
@ pe_group
Definition pe_types.h:38
@ pe_native
Definition pe_types.h:37
#define pe_flag_stonith_enabled
Definition pe_types.h:98
#define pe_flag_no_compat
Definition pe_types.h:131
#define pe_flag_stop_rsc_orphans
Definition pe_types.h:103
#define pe_rsc_maintenance
Definition pe_types.h:276
#define pe_rsc_failed
Definition pe_types.h:267
#define pe_rsc_failure_ignored
Definition pe_types.h:275
#define pe_flag_sanitized
Definition pe_types.h:120
#define pe_flag_have_remote_nodes
Definition pe_types.h:117
#define pe_flag_show_utilization
Definition pe_types.h:134
#define pe_flag_stop_action_orphans
Definition pe_types.h:104
#define pe_rsc_start_pending
Definition pe_types.h:269
#define pe_flag_have_status
Definition pe_types.h:116
GList * pe__resource_actions(const pe_resource_t *rsc, const pe_node_t *node, const char *task, bool require_node)
Find all actions of given type for a resource.
Definition utils.c:1546
#define pe__show_node_weights(level, rsc, text, nodes, data_set)
Definition internal.h:353
GList * find_actions(GList *input, const char *key, const pe_node_t *on_node)
Definition utils.c:1458
pe_action_t * custom_action(pe_resource_t *rsc, char *key, const char *task, pe_node_t *on_node, gboolean optional, gboolean foo, pe_working_set_t *data_set)
Definition utils.c:415
void pe_fence_node(pe_working_set_t *data_set, pe_node_t *node, const char *reason, bool priority_delay)
Schedule a fence action for a node.
Definition unpack.c:97
pe_action_t * pe__clear_resource_history(pe_resource_t *rsc, pe_node_t *node, pe_working_set_t *data_set)
Definition utils.c:2387
pe_action_t * find_first_action(GList *input, const char *uuid, const char *task, pe_node_t *on_node)
Definition utils.c:1428
void pe_action_set_flag_reason(const char *function, long line, pe_action_t *action, pe_action_t *reason, const char *text, enum pe_action_flags flags, bool overwrite)
Definition utils.c:2220
op_digest_cache_t * rsc_action_digest_cmp(pe_resource_t *rsc, xmlNode *xml_op, pe_node_t *node, pe_working_set_t *data_set)
Definition pe_digest.c:392
void pe__foreach_param_check(pe_working_set_t *data_set, void(*cb)(pe_resource_t *, pe_node_t *, xmlNode *, enum pe_check_parameters, pe_working_set_t *))
Definition remote.c:246
const char * pe_node_attribute_raw(pe_node_t *node, const char *name)
Definition common.c:635
void trigger_unfencing(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_action_t *dependency, pe_working_set_t *data_set)
Definition utils.c:2149
#define start_key(rsc)
Definition internal.h:382
int pe_get_failcount(pe_node_t *node, pe_resource_t *rsc, time_t *last_failure, uint32_t flags, xmlNode *xml_op, pe_working_set_t *data_set)
Definition failcounts.c:251
#define pe__clear_order_flags(order_flags, flags_to_clear)
Definition internal.h:118
#define stop_key(rsc)
Definition internal.h:376
#define pe_rsc_debug(rsc, fmt, args...)
Definition internal.h:19
bool pe__bundle_needs_remote_name(pe_resource_t *rsc, pe_working_set_t *data_set)
Definition bundle.c:950
void pe__free_param_checks(pe_working_set_t *data_set)
Definition remote.c:261
#define pe_warn(fmt...)
Definition internal.h:27
void pe__add_param_check(xmlNode *rsc_op, pe_resource_t *rsc, pe_node_t *node, enum pe_check_parameters, pe_working_set_t *data_set)
Definition remote.c:220
gboolean order_actions(pe_action_t *lh_action, pe_action_t *rh_action, enum pe_ordering order)
Definition utils.c:1808
#define pe_rsc_trace(rsc, fmt, args...)
Definition internal.h:20
int pe__add_scores(int score1, int score2)
Definition common.c:516
pe_action_t * pe__clear_failcount(pe_resource_t *rsc, pe_node_t *node, const char *reason, pe_working_set_t *data_set)
Schedule a controller operation to clear a fail count.
Definition failcounts.c:364
@ RSC_DIGEST_ALL
Definition internal.h:471
@ RSC_DIGEST_UNKNOWN
Definition internal.h:474
@ RSC_DIGEST_RESTART
Definition internal.h:469
@ RSC_DIGEST_MATCH
Definition internal.h:467
pe_action_t * pe_fence_op(pe_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pe_working_set_t *data_set)
Definition utils.c:2041
bool pe__shutdown_requested(pe_node_t *node)
Definition utils.c:2312
gint sort_op_by_callid(gconstpointer a, gconstpointer b)
Definition utils.c:1638
void resource_location(pe_resource_t *rsc, pe_node_t *node, int score, const char *tag, pe_working_set_t *data_set)
Definition utils.c:1594
#define pe__set_resource_flags(resource, flags_to_set)
Definition internal.h:47
time_t get_effective_time(pe_working_set_t *data_set)
Definition utils.c:1755
#define stop_action(rsc, node, optional)
Definition internal.h:377
#define pe_rsc_info(rsc, fmt, args...)
Definition internal.h:18
void pe__update_recheck_time(time_t recheck, pe_working_set_t *data_set)
Definition utils.c:2327
#define pe__clear_action_flags(action, flags_to_clear)
Definition internal.h:68
@ pe_fc_effective
Definition internal.h:300
@ pe_fc_fillers
Definition internal.h:301
#define pe__set_order_flags(order_flags, flags_to_set)
Definition internal.h:111
#define pe_err(fmt...)
Definition internal.h:22
#define pe__set_action_flags(action, flags_to_set)
Definition internal.h:59
bool pe_can_fence(pe_working_set_t *data_set, pe_node_t *node)
Definition utils.c:90
void add_hash_param(GHashTable *hash, const char *name, const char *value)
Definition common.c:579
xmlNode * find_rsc_op_entry(pe_resource_t *rsc, const char *key)
Definition utils.c:1327
bool pe__is_guest_node(const pe_node_t *node)
Definition remote.c:33
bool pe__resource_is_remote_conn(const pe_resource_t *rsc, const pe_working_set_t *data_set)
Definition remote.c:17
bool pe__is_guest_or_remote_node(const pe_node_t *node)
Definition remote.c:41
bool pe__is_remote_node(const pe_node_t *node)
Definition remote.c:25
#define CRM_ASSERT(expr)
Definition results.h:42
@ CRM_EX_OK
Definition results.h:217
@ pcmk_rc_ok
Definition results.h:142
#define PCMK_RESOURCE_CLASS_STONITH
Definition services.h:49
Cluster status and scheduling.
gboolean cluster_status(pe_working_set_t *data_set)
Definition status.c:71
pe_node_t * pe_find_node_id(GList *node_list, const char *id)
Definition status.c:418
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition strings.c:483
int pcmk__scan_ll(const char *text, long long *result, long long default_value)
Definition strings.c:97
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
Definition strings.c:955
@ pcmk__str_none
@ pcmk__str_null_matches
@ pcmk__str_casei
bool pcmk__ends_with(const char *s, const char *match)
Definition strings.c:535
int pcmk__guint_from_hash(GHashTable *table, const char *key, guint default_val, guint *result)
Definition strings.c:311
char * digest_secure_calc
Definition internal.h:483
xmlNode * params_restart
Definition internal.h:481
enum rsc_digest_cmp_val rc
Definition internal.h:478
xmlNode * params_all
Definition internal.h:479
This structure contains everything that makes up a single output formatter.
void(* end_list)(pcmk__output_t *out)
int(* message)(pcmk__output_t *out, const char *message_id,...)
void(* finish)(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
void(* begin_list)(pcmk__output_t *out, const char *singular_noun, const char *plural_noun, const char *format,...) G_GNUC_PRINTF(4
int(* info)(pcmk__output_t *out, const char *format,...) G_GNUC_PRINTF(2
pe_resource_t * rsc_lh
Definition internal.h:170
pe_action_t * rh_action
Definition internal.h:187
pe_resource_t * rh_rsc
Definition internal.h:186
enum pe_ordering type
Definition internal.h:178
pe_resource_t * lh_rsc
Definition internal.h:181
pe_action_t * lh_action
Definition internal.h:182
pe_resource_t * rsc
Definition pe_types.h:411
char * uuid
Definition pe_types.h:416
char * task
Definition pe_types.h:415
pe_node_t * node
Definition pe_types.h:412
GList * actions_after
Definition pe_types.h:449
GHashTable * meta
Definition pe_types.h:425
enum pe_action_flags flags
Definition pe_types.h:420
int required_runnable_before
Definition pe_types.h:446
GList * actions_before
Definition pe_types.h:448
enum pe_ordering type
Definition pe_types.h:533
int weight
Definition pe_types.h:241
int rsc_discover_mode
Definition pe_types.h:245
struct pe_node_shared_s * details
Definition pe_types.h:244
GHashTable * attrs
Definition pe_types.h:234
gboolean shutdown
Definition pe_types.h:219
const char * id
Definition pe_types.h:208
gboolean online
Definition pe_types.h:213
const char * uname
Definition pe_types.h:209
pe_resource_t * remote_rsc
Definition pe_types.h:230
gboolean is_dc
Definition pe_types.h:221
gboolean unclean
Definition pe_types.h:217
gboolean remote_requires_reset
Definition pe_types.h:224
gboolean maintenance
Definition pe_types.h:222
gboolean rsc_discovery_enabled
Definition pe_types.h:223
enum node_type type
Definition pe_types.h:210
gboolean remote_was_fenced
Definition pe_types.h:225
GList * running_on
Definition pe_types.h:367
GList * actions
Definition pe_types.h:360
enum pe_obj_types variant
Definition pe_types.h:331
GHashTable * meta
Definition pe_types.h:374
GList * children
Definition pe_types.h:378
int migration_threshold
Definition pe_types.h:345
gboolean exclusive_discover
Definition pe_types.h:353
pe_working_set_t * cluster
Definition pe_types.h:328
pe_resource_t * container
Definition pe_types.h:381
char * clone_name
Definition pe_types.h:323
gboolean is_remote_node
Definition pe_types.h:352
xmlNode * xml
Definition pe_types.h:324
GHashTable * allowed_nodes
Definition pe_types.h:369
pe_node_t * partial_migration_source
Definition pe_types.h:366
pe_node_t * allocated_to
Definition pe_types.h:364
unsigned long long flags
Definition pe_types.h:349
guint remote_reconnect_ms
Definition pe_types.h:346
pe_resource_t * parent
Definition pe_types.h:329
pe_node_t * partial_migration_target
Definition pe_types.h:365
resource_alloc_functions_t * cmds
Definition pe_types.h:334
enum rsc_role_e next_role
Definition pe_types.h:372
resource_object_functions_t * fns
Definition pe_types.h:333
time_t lock_time
Definition pe_types.h:386
pe_node_t * lock_node
Definition pe_types.h:385
const char * placement_strategy
Definition pe_types.h:144
guint shutdown_lock
Definition pe_types.h:189
GHashTable * config_hash
Definition pe_types.h:151
GList * actions
Definition pe_types.h:164
xmlNode * input
Definition pe_types.h:137
GList * resources
Definition pe_types.h:158
xmlNode * graph
Definition pe_types.h:176
unsigned long long flags
Definition pe_types.h:146
enum pe_quorum_policy no_quorum_policy
Definition pe_types.h:149
GList * placement_constraints
Definition pe_types.h:159
GList * ordering_constraints
Definition pe_types.h:160
time_t recheck_by
Definition pe_types.h:187
void(* rsc_location)(pe_resource_t *, pe__location_t *)
void(* expand)(pe_resource_t *, pe_working_set_t *)
pe_node_t *(* allocate)(pe_resource_t *, pe_node_t *, pe_working_set_t *)
gboolean(* create_probe)(pe_resource_t *, pe_node_t *, pe_action_t *, gboolean, pe_working_set_t *)
void(* create_actions)(pe_resource_t *, pe_working_set_t *)
void(* internal_constraints)(pe_resource_t *, pe_working_set_t *)
enum rsc_role_e(* state)(const pe_resource_t *, gboolean)
Definition pe_types.h:53
Wrappers for and extensions to libxml2.
gboolean xml_has_children(const xmlNode *root)
Definition xml.c:2027
xmlNode * find_xml_node(xmlNode *cib, const char *node_path, gboolean must_find)
Definition xml.c:446
xmlNode * create_xml_node(xmlNode *parent, const char *name)
Definition xml.c:696