32 #define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name) do { \ 33 __rsc = pcmk__find_constraint_resource(scheduler->priv->resources, \ 35 if (__rsc == NULL) { \ 36 pcmk__config_err("%s: No resource found for %s", __set, __name);\ 37 return pcmk_rc_unpack_error; \ 42 invert_action(
const char *
action)
74 get_ordering_type(
const xmlNode *xml_obj)
95 "removed in a future release " 111 pcmk__s(pcmk__xe_id(xml_obj),
"missing ID"), kind);
129 get_ordering_symmetry(
const xmlNode *xml_obj,
enum pe_order_kind parent_kind,
130 const char *parent_symmetrical_s)
133 bool symmetric =
false;
139 kind = get_ordering_type(xml_obj);
145 if (rc !=
pcmk_rc_ok && parent_symmetrical_s != NULL) {
154 " for '%s' because not valid with " 156 pcmk__xe_id(xml_obj));
182 ordering_flags_for_kind(
enum pe_order_kind kind,
const char *first,
238 get_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);
270 get_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)");
319 clone_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,
372 action_then = invert_action(action_then);
373 action_first = invert_action(action_first);
374 if ((action_then == NULL) || (action_first == NULL)) {
376 "(please specify inverse manually)",
id);
378 uint32_t
flags = ordering_flags_for_kind(kind, action_first,
382 action_first,
flags);
391 int min_required_before = 0;
396 const char *action_then = NULL;
397 const char *action_first = NULL;
398 const char *
id = NULL;
410 if (rsc_first == NULL) {
415 if (rsc_then == NULL) {
420 if (action_first == NULL) {
425 if (action_then == NULL) {
426 action_then = action_first;
429 kind = get_ordering_type(xml_obj);
431 symmetry = get_ordering_symmetry(xml_obj, kind, NULL);
432 flags = ordering_flags_for_kind(kind, action_first, symmetry);
439 min_required_before = get_minimum_first_instances(rsc_first, xml_obj);
440 if (min_required_before > 0) {
441 clone_min_ordering(
id, rsc_first, action_first, rsc_then, action_then,
442 flags, min_required_before);
449 inverse_ordering(
id, kind, rsc_first, action_first,
450 rsc_then, action_then);
491 CRM_CHECK(((first_action != NULL) || (first_rsc != NULL))
492 && ((then_action != NULL) || (then_rsc != NULL)),
493 free(first_action_task); free(then_action_task);
return);
495 if ((first_rsc == NULL) && (first_action != NULL)) {
496 first_rsc = first_action->
rsc;
498 if ((then_rsc == NULL) && (then_action != NULL)) {
499 then_rsc = then_action->
rsc;
506 order->
rsc1 = first_rsc;
507 order->
rsc2 = then_rsc;
510 order->
task1 = first_action_task;
511 order->
task2 = then_action_task;
513 if ((order->
task1 == NULL) && (first_action != NULL)) {
514 order->
task1 = strdup(first_action->
uuid);
517 if ((order->
task2 == NULL) && (then_action != NULL)) {
518 order->
task2 = strdup(then_action->
uuid);
521 if ((order->
rsc1 == NULL) && (first_action != NULL)) {
522 order->
rsc1 = first_action->
rsc;
525 if ((order->
rsc2 == NULL) && (then_action != NULL)) {
526 order->
rsc2 = then_action->
rsc;
531 pcmk__s(order->
task1,
"an underspecified action"),
532 pcmk__s(order->
task2,
"an underspecified action"));
552 unpack_order_set(
const xmlNode *
set,
enum pe_order_kind parent_kind,
555 GList *set_iter = NULL;
556 GList *resources = NULL;
561 int local_kind = parent_kind;
562 bool sequential =
false;
567 const char *
id = pcmk__xe_id(
set);
577 local_kind = get_ordering_type(
set);
579 if (sequential_s == NULL) {
585 symmetry = get_ordering_symmetry(
set, parent_kind, parent_symmetrical_s);
586 flags = ordering_flags_for_kind(local_kind,
action, symmetry);
595 resources = g_list_append(resources, resource);
598 if (pcmk__list_of_1(resources)) {
603 set_iter = resources;
604 while (set_iter != NULL) {
606 set_iter = set_iter->next;
613 for (GList *iter = set_iter; iter != NULL; iter = iter->next) {
621 }
else if (sequential) {
638 flags = ordering_flags_for_kind(local_kind,
action,
641 set_iter = resources;
642 while (set_iter != NULL) {
644 set_iter = set_iter->next;
656 g_list_free(resources);
673 order_rsc_sets(
const char *
id,
const xmlNode *set1,
const xmlNode *set2,
678 const xmlNode *xml_rsc = NULL;
679 const xmlNode *xml_rsc_2 = NULL;
689 bool require_all =
true;
693 if (action_1 == NULL) {
697 if (action_2 == NULL) {
702 action_1 = invert_action(action_1);
703 action_2 = invert_action(action_2);
716 flags = ordering_flags_for_kind(kind, action_1, symmetry);
741 NULL, NULL, NULL, unordered_action,
771 if (xml_rsc != NULL) {
777 const char *rid = NULL;
784 rid = pcmk__xe_id(xml_rsc);
793 const char *rid = NULL;
800 rid = pcmk__xe_id(xml_rsc);
808 if (xml_rsc != NULL) {
814 if ((rsc_1 != NULL) && (rsc_2 != NULL)) {
817 }
else if (rsc_1 != NULL) {
828 }
else if (rsc_2 != NULL) {
875 unpack_order_tags(xmlNode *xml_obj, xmlNode **expanded_xml,
878 const char *id_first = NULL;
879 const char *id_then = NULL;
880 const char *action_first = NULL;
881 const char *action_then = NULL;
888 xmlNode *rsc_set_first = NULL;
889 xmlNode *rsc_set_then = NULL;
890 bool any_sets =
false;
894 if (*expanded_xml != NULL) {
901 if ((id_first == NULL) || (id_then == NULL)) {
908 "valid resource or tag",
909 pcmk__xe_id(xml_obj), id_first);
916 "valid resource or tag",
917 pcmk__xe_id(xml_obj), id_then);
921 if ((rsc_first != NULL) && (rsc_then != NULL)) {
937 *expanded_xml = NULL;
941 if (rsc_set_first != NULL) {
942 if (action_first != NULL) {
958 *expanded_xml = NULL;
962 if (rsc_set_then != NULL) {
963 if (action_then != NULL) {
977 *expanded_xml = NULL;
994 xmlNode *last = NULL;
996 xmlNode *orig_xml = NULL;
997 xmlNode *expanded_xml = NULL;
1010 if (expanded_xml != NULL) {
1012 xml_obj = expanded_xml;
1023 if (expanded_xml != NULL) {
1031 if (order_rsc_sets(
id, last,
set, kind,
scheduler,
1033 if (expanded_xml != NULL) {
1040 && (order_rsc_sets(
id,
set, last, kind,
scheduler,
1042 if (expanded_xml != NULL) {
1059 return unpack_simple_rsc_order(xml_obj,
scheduler);
1070 && (
input->action->rsc != NULL)
1099 iter != NULL; iter = iter->next) {
1104 for (GList *input_iter =
action->actions_before;
1105 input_iter != NULL; input_iter = input_iter->next) {
1107 input = input_iter->data;
1126 iter != NULL; iter = iter->next) {
1131 if (!pcmk__same_node(
action->node, node)
1140 "Not ordering %s before shutdown of %s because " 1141 "resource in maintenance mode",
1142 action->uuid, pcmk__node_name(node));
1147 "Not ordering %s before shutdown of %s because " 1148 "node in maintenance mode",
1149 action->uuid, pcmk__node_name(node));
1157 if (!pcmk_any_flags_set(
action->rsc->flags,
1160 "Not ordering %s before shutdown of %s because " 1161 "resource is unmanaged or blocked",
1162 action->uuid, pcmk__node_name(node));
1167 action->uuid, pcmk__node_name(node));
1187 find_actions_by_task(
const pcmk_resource_t *rsc,
const char *original_key)
1196 guint interval_ms = 0;
1221 GList *then_actions = NULL;
1224 CRM_CHECK((rsc != NULL) && (order != NULL),
return);
1228 order->
id, rsc->
id);
1231 then_actions = g_list_prepend(NULL, order->
action2);
1234 then_actions = find_actions_by_task(rsc, order->
task2);
1237 if (then_actions == NULL) {
1238 pcmk__rsc_trace(rsc,
"Ignoring ordering %d: no %s actions found for %s",
1243 if ((first_action != NULL) && (first_action->
rsc == rsc)
1247 "Detected dangling migration ordering (%s then %s %s)",
1252 if ((first_action == NULL)
1256 "Ignoring ordering %d for %s: No first action found",
1257 order->
id, rsc->
id);
1258 g_list_free(then_actions);
1262 for (GList *iter = then_actions; iter != NULL; iter = iter->next) {
1265 if (first_action != NULL) {
1269 crm_warn(
"%s of %s is unrunnable because there is no %s of %s " 1270 "to order it after", then_action_iter->
task, rsc->
id,
1275 g_list_free(then_actions);
1281 GList *first_actions = NULL;
1286 pcmk__rsc_trace(first_rsc,
"Applying ordering constraint %d (first: %s)",
1287 order->
id, first_rsc->
id);
1289 if (first_action != NULL) {
1290 first_actions = g_list_prepend(NULL, first_action);
1293 first_actions = find_actions_by_task(first_rsc, order->
task1);
1296 if ((first_actions == NULL) && (first_rsc == then_rsc)) {
1298 "Ignoring constraint %d: first (%s for %s) not found",
1299 order->
id, order->
task1, first_rsc->
id);
1301 }
else if (first_actions == NULL) {
1303 char *op_type = NULL;
1304 guint interval_ms = 0;
1310 first_role = first_rsc->
priv->
fns->
state(first_rsc, TRUE);
1315 "Ignoring constraint %d: first (%s for %s) " 1317 order->
id, order->
task1, first_rsc->
id);
1324 "Ignoring constraint %d: first (%s for %s) " 1326 order->
id, order->
task1, first_rsc->
id);
1330 "Creating first (%s for %s) for constraint %d ",
1331 order->
task1, first_rsc->
id, order->
id);
1332 first_action =
custom_action(first_rsc, key, op_type, NULL, TRUE,
1334 first_actions = g_list_prepend(NULL, first_action);
1340 if (then_rsc == NULL) {
1348 for (GList *iter = first_actions; iter != NULL; iter = iter->next) {
1349 first_action = iter->data;
1351 if (then_rsc == NULL) {
1355 order_resource_actions_after(first_action, then_rsc, order);
1359 g_list_free(first_actions);
1364 block_colocation_dependents(gpointer
data, gpointer user_data)
1371 update_action_for_orderings(gpointer
data, gpointer user_data)
1386 crm_trace(
"Applying ordering constraints");
1404 iter != NULL; iter = iter->next) {
1410 rsc_order_first(rsc, order);
1416 order_resource_actions_after(order->
action1, rsc, order);
1419 crm_trace(
"Applying ordering constraint %d (non-resource actions)",
1425 g_list_foreach(sched->
priv->
actions, block_colocation_dependents, NULL);
1431 g_list_foreach(sched->
priv->
actions, update_action_for_orderings, sched);
1446 const char *after_desc = (after->
task == NULL)? after->
uuid : after->
task;
1448 for (GList *iter = list; iter != NULL; iter = iter->next) {
1450 const char *before_desc = before->
task? before->
task : before->
uuid;
1452 crm_debug(
"Ordering %s on %s before %s on %s",
1453 before_desc, pcmk__node_name(before->
node),
1454 after_desc, pcmk__node_name(after->
node));
#define CRM_CHECK(expr, failure_action)
xmlNode * pcmk__xe_resolve_idref(xmlNode *xml, xmlNode *search)
xmlNode * pcmk__xml_copy(xmlNode *parent, xmlNode *src)
xmlNode * pcmk__xe_first_child(const xmlNode *parent, const char *node_name, const char *attr_n, const char *attr_v)
'then' is runnable (and migratable) only if 'first' is runnable
void pcmk__order_after_each(pcmk_action_t *after, GList *list)
Actions are ordered if on same node (or migration target for migrate_to)
pcmk_action_t * get_pseudo_op(const char *name, pcmk_scheduler_t *scheduler)
#define PCMK_XE_RSC_ORDER
User-configured asymmetric ordering.
int pcmk__scan_min_int(const char *text, int *result, int minimum)
bool pcmk__strcase_any_of(const char *s,...) G_GNUC_NULL_TERMINATED
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)
#define pcmk__config_warn(fmt...)
#define pcmk__rsc_trace(rsc, fmt, args...)
#define PCMK_XE_RESOURCE_REF
#define pcmk__config_err(fmt...)
G_GNUC_INTERNAL void pcmk__block_colocation_dependents(pcmk_action_t *action)
pcmk__scheduler_private_t * priv
#define PCMK_ACTION_MIGRATE_TO
#define PCMK_ACTION_DO_SHUTDOWN
G_GNUC_INTERNAL void pcmk__update_action_for_orderings(pcmk_action_t *action, pcmk_scheduler_t *scheduler)
void pcmk__xe_remove_attr(xmlNode *element, const char *name)
const pcmk__rsc_methods_t * fns
bool pcmk__xe_attr_is_true(const xmlNode *node, const char *name)
void pcmk__promotable_restart_ordering(pcmk_resource_t *rsc)
Ordering applies even if 'first' runs on guest node created by 'then'.
#define pcmk__set_relation_flags(ar_flags, flags_to_set)
GList * ordering_constraints
void pcmk__xml_free(xmlNode *xml)
const char * crm_xml_add(xmlNode *node, const char *name, const char *value)
Create an XML attribute with specified name and value.
#define pcmk__rsc_debug(rsc, fmt, args...)
pcmk__node_private_t * priv
int pcmk__xe_get_bool_attr(const xmlNode *node, const char *name, bool *value)
#define PCMK_ACTION_DEMOTE
#define crm_warn(fmt, args...)
#define PCMK_ACTION_CLONE_ONE_OR_MORE
#define crm_debug(fmt, args...)
pcmk_scheduler_t * scheduler
Actions are ordered (optionally, if no other flags are set)
G_GNUC_INTERNAL pcmk_resource_t * pcmk__find_constraint_resource(GList *rsc_list, const char *id)
#define pcmk__clear_action_flags(action, flags_to_clear)
#define PCMK_XA_THEN_ACTION
const char * crm_element_value(const xmlNode *data, const char *name)
Retrieve the value of an XML attribute.
#define crm_trace(fmt, args...)
void pcmk__apply_orderings(pcmk_scheduler_t *sched)
#define pcmk_is_set(g, f)
Convenience alias for pcmk_all_flags_set(), to check single flag.
G_GNUC_INTERNAL bool pcmk__rsc_corresponds_to_guest(const pcmk_resource_t *rsc, const pcmk_node_t *node)
G_GNUC_INTERNAL void pcmk__order_probes(pcmk_scheduler_t *scheduler)
#define PCMK_ACTION_START
pcmk__resource_private_t * priv
enum rsc_role_e(* state)(const pcmk_resource_t *rsc, gboolean current)
pcmk_scheduler_t * scheduler
#define PCMK_META_CLONE_MIN
char * pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms)
Generate an operation key (RESOURCE_ACTION_INTERVAL)
#define pcmk__warn_once(wo_flag, fmt...)
gboolean order_actions(pcmk_action_t *first, pcmk_action_t *then, uint32_t flags)
#define PCMK_XA_REQUIRE_ALL
#define pcmk__order_resource_actions(first_rsc, first_task, then_rsc, then_task, flags)
#define EXPAND_CONSTRAINT_IDREF(__set, __rsc, __name)
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)
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__clear_relation_flags(ar_flags, flags_to_clear)
xmlNode * pcmk__xe_next(const xmlNode *node, const char *element_name)
#define pcmk__assert(expr)
int required_runnable_before
#define PCMK_VALUE_SERIALIZE
void pcmk__disable_invalid_orderings(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)
pcmk_scheduler_t * scheduler
GList * find_actions(GList *input, const char *key, const pcmk_node_t *on_node)
If 'first' is required and runnable, 'then' must be in graph.
#define PCMK_ACTION_STOPPED
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)
#define PCMK_XE_RESOURCE_SET
gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, guint *interval_ms)
#define PCMK_ACTION_PROMOTE
int pcmk_parse_score(const char *score_s, int *score, int default_score)
Parse an integer score from a string.
gboolean crm_is_true(const char *s)
void pcmk__unpack_ordering(xmlNode *xml_obj, pcmk_scheduler_t *scheduler)
#define PCMK_XA_FIRST_ACTION
void pcmk__order_migration_equivalents(pcmk__action_relation_t *order)
#define PCMK_XA_SYMMETRICAL
#define crm_log_xml_trace(xml, text)
#define PCMK_ACTION_PROMOTED
#define PCMK_ACTION_RUNNING
struct pcmk__node_details * details
#define PCMK_ACTION_DEMOTED
#define pcmk__assert_alloc(nmemb, size)
'then' action is runnable if certain number of 'first' instances are
#define PCMK_ACTION_ONE_OR_MORE
#define PCMK_XA_SEQUENTIAL
G_GNUC_INTERNAL xmlNode * pcmk__expand_tags_in_sets(xmlNode *xml_obj, const pcmk_scheduler_t *scheduler)
void pcmk__order_stops_before_shutdown(pcmk_node_t *node, pcmk_action_t *shutdown_op)
#define PCMK_VALUE_MANDATORY
No relation (compare with equality rather than bit set)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
#define PCMK_VALUE_OPTIONAL