33#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \
34 __rsc = pcmk__find_constraint_resource(scheduler->priv->resources, \
36 if (__rsc == NULL) { \
37 pcmk__config_err("%s: No resource found for %s", __set, __name);\
38 return pcmk_rc_unpack_error; \
43invert_action(
const char *
action)
75get_ordering_type(
const xmlNode *xml_obj)
96 "removed in a future release "
112 pcmk__s(pcmk__xe_id(xml_obj),
"missing ID"), kind);
130get_ordering_symmetry(
const xmlNode *xml_obj,
enum pe_order_kind parent_kind,
131 const char *parent_symmetrical_s)
134 bool symmetric =
false;
140 kind = get_ordering_type(xml_obj);
146 if (rc !=
pcmk_rc_ok && parent_symmetrical_s != NULL) {
155 " for '%s' because not valid with "
157 pcmk__xe_id(xml_obj));
183ordering_flags_for_kind(
enum pe_order_kind kind,
const char *first,
211 if (pcmk__is_up_action(first)) {
238get_ordering_resource(
const xmlNode *xml,
const char *resource_attr,
244 if (rsc_id == NULL) {
246 pcmk__xe_id(xml), resource_attr);
253 "does not exist", pcmk__xe_id(xml), rsc_id);
270get_minimum_first_instances(
const pcmk_resource_t *rsc,
const xmlNode *xml)
272 const char *clone_min = NULL;
273 bool require_all =
false;
275 if (!pcmk__is_clone(rsc)) {
280 if (clone_min != NULL) {
281 int clone_min_int = 0;
284 return clone_min_int;
295 "constraints is deprecated and will be removed in a "
297 "meta-attribute instead)");
319clone_min_ordering(
const char *
id,
322 uint32_t
flags,
int clone_min)
338 iter != NULL; iter = iter->next) {
343 NULL, NULL, NULL, clone_min_met,
373 const char *inverted_first = invert_action(action_first);
374 const char *inverted_then = invert_action(action_then);
376 if ((inverted_then == NULL) || (inverted_first == NULL)) {
378 "(please specify inverse manually)",
id);
383 flags = ordering_flags_for_kind(kind, inverted_first,
386 rsc_first, inverted_first,
flags);
394 int min_required_before = 0;
399 const char *action_then = NULL;
400 const char *action_first = NULL;
401 const char *
id = NULL;
413 if (rsc_first == NULL) {
418 if (rsc_then == NULL) {
423 if (action_first == NULL) {
428 if (action_then == NULL) {
429 action_then = action_first;
432 kind = get_ordering_type(xml_obj);
434 symmetry = get_ordering_symmetry(xml_obj, kind, NULL);
435 flags = ordering_flags_for_kind(kind, action_first, symmetry);
442 min_required_before = get_minimum_first_instances(rsc_first, xml_obj);
443 if (min_required_before > 0) {
444 clone_min_ordering(
id, rsc_first, action_first, rsc_then, action_then,
445 flags, min_required_before);
452 inverse_ordering(
id, kind, rsc_first, action_first,
453 rsc_then, action_then);
494 CRM_CHECK(((first_action != NULL) || (first_rsc != NULL))
495 && ((then_action != NULL) || (then_rsc != NULL)),
496 free(first_action_task); free(then_action_task);
return);
498 if ((first_rsc == NULL) && (first_action != NULL)) {
499 first_rsc = first_action->
rsc;
501 if ((then_rsc == NULL) && (then_action != NULL)) {
502 then_rsc = then_action->
rsc;
509 order->
rsc1 = first_rsc;
510 order->
rsc2 = then_rsc;
513 order->
task1 = first_action_task;
514 order->
task2 = then_action_task;
516 if ((order->
task1 == NULL) && (first_action != NULL)) {
517 order->
task1 = strdup(first_action->
uuid);
520 if ((order->
task2 == NULL) && (then_action != NULL)) {
521 order->
task2 = strdup(then_action->
uuid);
524 if ((order->
rsc1 == NULL) && (first_action != NULL)) {
525 order->
rsc1 = first_action->
rsc;
528 if ((order->
rsc2 == NULL) && (then_action != NULL)) {
529 order->
rsc2 = then_action->
rsc;
534 pcmk__s(order->
task1,
"an underspecified action"),
535 pcmk__s(order->
task2,
"an underspecified action"));
555unpack_order_set(
const xmlNode *set,
enum pe_order_kind parent_kind,
558 GList *set_iter = NULL;
559 GList *resources = NULL;
564 int local_kind = parent_kind;
565 bool sequential =
false;
570 const char *
id = pcmk__xe_id(set);
580 local_kind = get_ordering_type(set);
582 if (sequential_s == NULL) {
588 symmetry = get_ordering_symmetry(set, parent_kind, parent_symmetrical_s);
589 flags = ordering_flags_for_kind(local_kind,
action, symmetry);
598 resources = g_list_append(resources, resource);
601 if (pcmk__list_of_1(resources)) {
606 set_iter = resources;
607 while (set_iter != NULL) {
609 set_iter = set_iter->next;
616 for (GList *iter = set_iter; iter != NULL; iter = iter->next) {
624 }
else if (sequential) {
641 flags = ordering_flags_for_kind(local_kind,
action,
644 set_iter = resources;
645 while (set_iter != NULL) {
647 set_iter = set_iter->next;
659 g_list_free(resources);
676order_rsc_sets(
const char *
id,
const xmlNode *set1,
const xmlNode *set2,
681 const xmlNode *xml_rsc = NULL;
682 const xmlNode *xml_rsc_2 = NULL;
692 bool require_all =
true;
696 if (action_1 == NULL) {
700 if (action_2 == NULL) {
705 action_1 = invert_action(action_1);
706 action_2 = invert_action(action_2);
719 flags = ordering_flags_for_kind(kind, action_1, symmetry);
744 NULL, NULL, NULL, unordered_action,
774 if (xml_rsc != NULL) {
780 const char *rid = NULL;
787 rid = pcmk__xe_id(xml_rsc);
796 const char *rid = NULL;
803 rid = pcmk__xe_id(xml_rsc);
811 if (xml_rsc != NULL) {
817 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
820 }
else if (rsc_1 != NULL) {
831 }
else if (rsc_2 != NULL) {
878unpack_order_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
881 const char *id_first = NULL;
882 const char *id_then = NULL;
883 const char *action_first = NULL;
884 const char *action_then = NULL;
891 xmlNode *rsc_set_first = NULL;
892 xmlNode *rsc_set_then = NULL;
893 bool any_sets =
false;
897 if (*expanded_xml != NULL) {
904 if ((id_first == NULL) || (id_then == NULL)) {
911 "valid resource or tag",
912 pcmk__xe_id(xml_obj), id_first);
919 "valid resource or tag",
920 pcmk__xe_id(xml_obj), id_then);
924 if ((rsc_first != NULL) && (rsc_then != NULL)) {
940 *expanded_xml = NULL;
944 if (rsc_set_first != NULL) {
945 if (action_first != NULL) {
961 *expanded_xml = NULL;
965 if (rsc_set_then != NULL) {
966 if (action_then != NULL) {
980 *expanded_xml = NULL;
997 xmlNode *last = NULL;
999 xmlNode *orig_xml = NULL;
1000 xmlNode *expanded_xml = NULL;
1013 if (expanded_xml != NULL) {
1015 xml_obj = expanded_xml;
1026 if (expanded_xml != NULL) {
1034 if (order_rsc_sets(
id, last, set, kind,
scheduler,
1036 if (expanded_xml != NULL) {
1043 && (order_rsc_sets(
id, set, last, kind,
scheduler,
1045 if (expanded_xml != NULL) {
1062 return unpack_simple_rsc_order(xml_obj,
scheduler);
1073 && (
input->action->rsc != NULL)
1102 iter != NULL; iter = iter->next) {
1107 for (GList *input_iter =
action->actions_before;
1108 input_iter != NULL; input_iter = input_iter->next) {
1110 input = input_iter->data;
1129 iter != NULL; iter = iter->next) {
1134 if (!pcmk__same_node(
action->node, node)
1143 "Not ordering %s before shutdown of %s because "
1144 "resource in maintenance mode",
1145 action->uuid, pcmk__node_name(node));
1150 "Not ordering %s before shutdown of %s because "
1151 "node in maintenance mode",
1152 action->uuid, pcmk__node_name(node));
1162 if (!pcmk_any_flags_set(
action->rsc->flags,
1165 "Not ordering %s before shutdown of %s because "
1166 "resource is unmanaged or blocked",
1167 action->uuid, pcmk__node_name(node));
1172 action->uuid, pcmk__node_name(node));
1192find_actions_by_task(
const pcmk_resource_t *rsc,
const char *original_key)
1201 guint interval_ms = 0;
1226 GList *then_actions = NULL;
1229 CRM_CHECK((rsc != NULL) && (order != NULL),
return);
1233 order->
id, rsc->
id);
1236 then_actions = g_list_prepend(NULL, order->
action2);
1239 then_actions = find_actions_by_task(rsc, order->
task2);
1242 if (then_actions == NULL) {
1243 pcmk__rsc_trace(rsc,
"Ignoring ordering %d: no %s actions found for %s",
1248 if ((first_action != NULL) && (first_action->
rsc == rsc)
1252 "Detected dangling migration ordering (%s then %s %s)",
1257 if ((first_action == NULL)
1261 "Ignoring ordering %d for %s: No first action found",
1262 order->
id, rsc->
id);
1263 g_list_free(then_actions);
1267 for (GList *iter = then_actions; iter != NULL; iter = iter->next) {
1270 if (first_action != NULL) {
1275 crm_warn(
"%s of %s is unrunnable because there is no %s of %s "
1276 "to order it after", then_action_iter->task, rsc->
id,
1281 g_list_free(then_actions);
1287 GList *first_actions = NULL;
1292 pcmk__rsc_trace(first_rsc,
"Applying ordering constraint %d (first: %s)",
1293 order->
id, first_rsc->
id);
1295 if (first_action != NULL) {
1296 first_actions = g_list_prepend(NULL, first_action);
1299 first_actions = find_actions_by_task(first_rsc, order->
task1);
1302 if ((first_actions == NULL) && (first_rsc == then_rsc)) {
1304 "Ignoring constraint %d: first (%s for %s) not found",
1305 order->
id, order->
task1, first_rsc->
id);
1307 }
else if (first_actions == NULL) {
1309 char *op_type = NULL;
1310 guint interval_ms = 0;
1316 first_role = first_rsc->
priv->
fns->
state(first_rsc,
true);
1321 "Ignoring constraint %d: first (%s for %s) "
1323 order->
id, order->
task1, first_rsc->
id);
1330 "Ignoring constraint %d: first (%s for %s) "
1332 order->
id, order->
task1, first_rsc->
id);
1336 "Creating first (%s for %s) for constraint %d ",
1337 order->
task1, first_rsc->
id, order->
id);
1338 first_action =
custom_action(first_rsc, key, op_type, NULL, TRUE,
1340 first_actions = g_list_prepend(NULL, first_action);
1346 if (then_rsc == NULL) {
1354 for (GList *iter = first_actions; iter != NULL; iter = iter->next) {
1355 first_action = iter->data;
1357 if (then_rsc == NULL) {
1361 order_resource_actions_after(first_action, then_rsc, order);
1365 g_list_free(first_actions);
1370block_colocation_dependents(gpointer
data, gpointer user_data)
1377update_action_for_orderings(gpointer
data, gpointer user_data)
1392 crm_trace(
"Applying ordering constraints");
1410 iter != NULL; iter = iter->next) {
1416 rsc_order_first(rsc, order);
1422 order_resource_actions_after(order->
action1, rsc, order);
1425 crm_trace(
"Applying ordering constraint %d (non-resource actions)",
1431 g_list_foreach(sched->
priv->
actions, block_colocation_dependents, NULL);
1437 g_list_foreach(sched->
priv->
actions, update_action_for_orderings, sched);
1452 const char *after_desc = (after->
task == NULL)? after->
uuid : after->
task;
1454 for (GList *iter = list; iter != NULL; iter = iter->next) {
1456 const char *before_desc = before->
task? before->
task : before->
uuid;
1458 crm_debug(
"Ordering %s on %s before %s on %s",
1459 before_desc, pcmk__node_name(before->
node),
1460 after_desc, pcmk__node_name(after->
node));
@ pcmk__ar_first_implies_then
@ pcmk__ar_asymmetric
User-configured asymmetric ordering.
@ pcmk__ar_then_implies_first
@ pcmk__ar_min_runnable
'then' action is runnable if certain number of 'first' instances are
@ pcmk__ar_none
No relation (compare with equality rather than bit set)
@ pcmk__ar_first_implies_then_graphed
If 'first' is required and runnable, 'then' must be in graph.
@ pcmk__ar_unrunnable_first_blocks
'then' is runnable (and migratable) only if 'first' is runnable
@ pcmk__ar_ordered
Actions are ordered (optionally, if no other flags are set)
@ pcmk__ar_if_on_same_node_or_target
Actions are ordered if on same node (or migration target for migrate_to)
@ pcmk__ar_guest_allowed
Ordering applies even if 'first' runs on guest node created by 'then'.
#define pcmk__clear_relation_flags(ar_flags, flags_to_clear)
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
#define PCMK_ACTION_PROMOTED
#define PCMK_ACTION_RUNNING
#define PCMK_ACTION_ONE_OR_MORE
#define PCMK_ACTION_PROMOTE
#define PCMK_ACTION_START
#define PCMK_ACTION_MIGRATE_TO
#define PCMK_ACTION_STOPPED
#define PCMK_ACTION_CLONE_ONE_OR_MORE
#define PCMK_ACTION_DEMOTED
#define PCMK_ACTION_DEMOTE
#define PCMK_ACTION_DO_SHUTDOWN
@ pcmk__action_migration_abort
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
#define pcmk__clear_action_flags(action, flags_to_clear)
#define pcmk__assert_alloc(nmemb, size)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
G_GNUC_INTERNAL void pcmk__block_colocation_dependents(pcmk_action_t *action)
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pcmk_action_t *action, pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL bool pcmk__tag_to_set(xmlNode *xml_obj, xmlNode **rsc_set, const char *attr, bool convert_rsc, const pcmk_scheduler_t *scheduler)
G_GNUC_INTERNAL bool pcmk__graph_has_loop(const pcmk_action_t *init_action, const pcmk_action_t *action, pcmk__related_action_t *input)
G_GNUC_INTERNAL bool pcmk__valid_resource_or_tag(const pcmk_scheduler_t *scheduler, const char *id, pcmk_resource_t **rsc, pcmk__idref_t **tag)
G_GNUC_INTERNAL bool pcmk__rsc_corresponds_to_guest(const pcmk_resource_t *rsc, const pcmk_node_t *node)
void pcmk__order_migration_equivalents(pcmk__action_relation_t *order)
G_GNUC_INTERNAL void pcmk__order_probes(pcmk_scheduler_t *scheduler)
#define crm_warn(fmt, args...)
#define CRM_CHECK(expr, failure_action)
#define crm_debug(fmt, args...)
#define crm_log_xml_trace(xml, text)
#define crm_trace(fmt, args...)
#define pcmk__config_warn(fmt...)
#define pcmk__config_err(fmt...)
#define pcmk__warn_once(wo_flag, fmt...)
pcmk_scheduler_t * scheduler
#define PCMK_VALUE_SERIALIZE
#define PCMK_VALUE_OPTIONAL
#define PCMK_META_CLONE_MIN
#define PCMK_VALUE_MANDATORY
void pcmk__order_stops_before_shutdown(pcmk_node_t *node, pcmk_action_t *shutdown_op)
void pcmk__apply_orderings(pcmk_scheduler_t *sched)
void pcmk__new_ordering(pcmk_resource_t *first_rsc, char *first_action_task, pcmk_action_t *first_action, pcmk_resource_t *then_rsc, char *then_action_task, pcmk_action_t *then_action, uint32_t flags, pcmk_scheduler_t *sched)
#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name)
void pcmk__disable_invalid_orderings(pcmk_scheduler_t *scheduler)
@ pe_order_kind_mandatory
@ pe_order_kind_serialize
void pcmk__order_after_each(pcmk_action_t *after, GList *list)
@ ordering_symmetric_inverse
void pcmk__unpack_ordering(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
void pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
pcmk_action_t * get_pseudo_op(const char *name, pcmk_scheduler_t *scheduler)
GList * find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
pcmk_action_t * custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler)
Create or update an action object.
#define pcmk__assert(expr)
@ pcmk_role_unpromoted
Unpromoted.
@ pcmk_role_stopped
Stopped.
#define pcmk__rsc_trace(rsc, fmt, args...)
#define pcmk__rsc_debug(rsc, fmt, args...)
int pcmk_parse_score(const char *score_s, int *score, int default_score)
Parse an integer score from a string.
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
gboolean crm_is_true(const char *s)
int pcmk__scan_min_int(const char *text, int *result, int minimum)
int required_runnable_before
pcmk_scheduler_t * scheduler
pcmk_scheduler_t * scheduler
const pcmk__rsc_methods_t * fns
pcmk__resource_private_t * priv
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, bool current)
GList * ordering_constraints
pcmk__scheduler_private_t * priv
pcmk__node_private_t * priv
struct pcmk__node_details * details
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
xmlNode * pcmk__xe_resolve_idref(xmlNode *xml, xmlNode *search)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
void pcmk__xml_free(xmlNode *xml)
#define PCMK_XA_REQUIRE_ALL
#define PCMK_XA_SYMMETRICAL
#define PCMK_XE_RESOURCE_REF
#define PCMK_XE_RSC_ORDER
#define PCMK_XE_RESOURCE_SET
#define PCMK_XA_THEN_ACTION
#define PCMK_XA_SEQUENTIAL
#define PCMK_XA_FIRST_ACTION