1 /* 2 * Copyright 2023-2024 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 Lesser General Public License 7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. 8 */ 9 10 #ifndef PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H 11 #define PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H 12 13 #include <stdbool.h> // bool 14 #include <stdint.h> // uint32_t 15 #include <glib.h> // gpointer 16 #include <crm/common/scheduler_types.h> // pcmk_resource_t, pcmk_action_t 17 18 #ifdef __cplusplus 19 extern "C" { 20 #endif 21 22 // Flags to indicate the relationship between two actions 23 enum pcmk__action_relation_flags { 24 //! No relation (compare with equality rather than bit set) 25 pcmk__ar_none = 0U, 26 27 //! Actions are ordered (optionally, if no other flags are set) 28 pcmk__ar_ordered = (1U << 0), 29 30 //! Relation applies only if 'first' cannot be part of a live migration 31 pcmk__ar_if_first_unmigratable = (1U << 1), 32 33 /*! 34 * If 'then' is required, 'first' becomes required (and becomes unmigratable 35 * if 'then' is); also, if 'first' is a stop of a blocked resource, 'then' 36 * becomes unrunnable 37 */ 38 pcmk__ar_then_implies_first = (1U << 4), 39 40 /*! 41 * If 'first' is required, 'then' becomes required; if 'first' is a stop of 42 * a blocked resource, 'then' becomes unrunnable 43 */ 44 pcmk__ar_first_implies_then = (1U << 5), 45 46 /*! 47 * If 'then' is required and for a promoted instance, 'first' becomes 48 * required (and becomes unmigratable if 'then' is) 49 */ 50 pcmk__ar_promoted_then_implies_first = (1U << 6), 51 52 /*! 53 * 'first' is runnable only if 'then' is both runnable and migratable, 54 * and 'first' becomes required if 'then' is 55 */ 56 pcmk__ar_unmigratable_then_blocks = (1U << 7), 57 58 //! 'then' is runnable (and migratable) only if 'first' is runnable 59 pcmk__ar_unrunnable_first_blocks = (1U << 8), 60 61 //! If 'first' is unrunnable, 'then' becomes a real, unmigratable action 62 pcmk__ar_first_else_then = (1U << 9), 63 64 //! If 'first' is required, 'then' action for instance on same node is 65 pcmk__ar_first_implies_same_node_then = (1U << 10), 66 67 /*! 68 * Disable relation if 'first' is unrunnable and for an active resource, 69 * otherwise order actions and make 'then' unrunnable if 'first' is. 70 * 71 * This is used to order a bundle replica's start of its container before a 72 * probe of its remote connection resource, in case the connection uses the 73 * REMOTE_CONTAINER_HACK to replace the connection address with where the 74 * container is running. 75 */ 76 pcmk__ar_nested_remote_probe = (1U << 11), 77 78 /*! 79 * If 'first' is for a blocked resource, make 'then' unrunnable. 80 * 81 * If 'then' is required, make 'first' required, make 'first' unmigratable 82 * if 'then' is unmigratable, and make 'then' unrunnable if 'first' is 83 * unrunnable. 84 * 85 * If 'then' is unrunnable and for the same resource as 'first', make 86 * 'first' required if it is runnable, and make 'first' unmigratable if 87 * 'then' is unmigratable. 88 * 89 * This is used for "stop then start primitive" (restarts) and 90 * "stop group member then stop previous member". 91 */ 92 pcmk__ar_intermediate_stop = (1U << 12), 93 94 /*! 95 * The actions must be serialized if in the same transition but can be in 96 * either order. (In practice, we always arrange them as 'first' then 97 * 'then', so they end up being essentially the same as optional orderings.) 98 * 99 * @TODO Handle more intelligently -- for example, we could schedule the 100 * action with the fewest inputs first, so we're more likely to execute at 101 * least one if there is a failure during the transition. Or, we could 102 * prefer certain action types over others, or base it on resource priority. 103 */ 104 pcmk__ar_serialize = (1U << 14), 105 106 //! Relation applies only if actions are on same node 107 pcmk__ar_if_on_same_node = (1U << 15), 108 109 //! If 'then' is required, 'first' must be added to the transition graph 110 pcmk__ar_then_implies_first_graphed = (1U << 16), 111 112 //! If 'first' is required and runnable, 'then' must be in graph 113 pcmk__ar_first_implies_then_graphed = (1U << 17), 114 115 //! User-configured asymmetric ordering 116 pcmk__ar_asymmetric = (1U << 20), 117 118 //! Actions are ordered if on same node (or migration target for migrate_to) 119 pcmk__ar_if_on_same_node_or_target = (1U << 21), 120 121 //! 'then' action is runnable if certain number of 'first' instances are 122 pcmk__ar_min_runnable = (1U << 22), 123 124 //! Ordering applies only if 'first' is required and on same node as 'then' 125 pcmk__ar_if_required_on_same_node = (1U << 23), 126 127 //! Ordering applies even if 'first' runs on guest node created by 'then' 128 pcmk__ar_guest_allowed = (1U << 24), 129 130 //! If 'then' action becomes required, 'first' becomes optional 131 pcmk__ar_then_cancels_first = (1U << 25), 132 }; 133 134 /* Action relation object 135 * 136 * The most common type of relation is an ordering, in which case action1 etc. 137 * refers to the "first" action, and action2 etc. refers to the "then" action. 138 */ 139 typedef struct { 140 int id; // Counter to identify relation 141 uint32_t flags; // Group of enum pcmk__action_relation_flags 142 pcmk_resource_t *rsc1; // Resource for first action, if any 143 pcmk_action_t *action1; // First action in relation 144 char *task1; // Action name or key for first action 145 pcmk_resource_t *rsc2; // Resource for second action, if any 146 pcmk_action_t *action2; // Second action in relation 147 char *task2; // Action name or key for second action 148 } pcmk__action_relation_t; 149 150 // Action sequenced relative to another action 151 typedef struct pcmk__related_action { 152 pcmk_action_t *action; // Action to be sequenced 153 uint32_t flags; // Group of enum pcmk__action_relation_flags 154 bool graphed; // Whether action has been added to graph yet 155 } pcmk__related_action_t; 156 157 /*! 158 * \internal 159 * \brief Set action relation flags 160 * 161 * \param[in,out] ar_flags Flag group to modify 162 * \param[in] flags_to_set enum pcmk__action_relation_flags to set 163 */ 164 #define pcmk__set_relation_flags(ar_flags, flags_to_set) do { \ 165 ar_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ 166 "Action relation", "constraint", \ 167 ar_flags, (flags_to_set), \ 168 #flags_to_set); \ 169 } while (0) 170 171 /*! 172 * \internal 173 * \brief Clear action relation flags 174 * 175 * \param[in,out] ar_flags Flag group to modify 176 * \param[in] flags_to_clear enum pcmk__action_relation_flags to clear 177 */ 178 #define pcmk__clear_relation_flags(ar_flags, flags_to_clear) do { \ 179 ar_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \ 180 "Action relation", "constraint", \ 181 ar_flags, (flags_to_clear), \ 182 #flags_to_clear); \ 183 } while (0) 184 185 void pcmk__free_action_relation(gpointer user_data); 186 187 #ifdef __cplusplus 188 } 189 #endif 190 191 #endif // PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H