root/lib/pacemaker/pcmk_sched_instances.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. can_run_everywhere
  2. can_run_instance
  3. ban_unavailable_allowed_nodes
  4. new_node_table
  5. apply_parent_colocations
  6. cmp_instance_by_colocation
  7. did_fail
  8. node_is_allowed
  9. pcmk__cmp_instance_number
  10. pcmk__cmp_instance
  11. assign_instance
  12. reset_allowed_node_counts
  13. preferred_node
  14. pcmk__assign_instances
  15. check_instance_state
  16. pcmk__create_instance_actions
  17. get_instance_list
  18. free_instance_list
  19. pcmk__instance_matches
  20. find_compatible_instance_on_node
  21. pcmk__find_compatible_instance
  22. unassign_if_mandatory
  23. find_instance_action
  24. orig_action_name
  25. update_interleaved_actions
  26. can_interleave_actions
  27. update_noninterleaved_actions
  28. pcmk__instance_update_ordered_actions
  29. pcmk__collective_action_flags
  30. pcmk__add_collective_constraints

   1 /*
   2  * Copyright 2004-2023 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 /* This file is intended for code usable with both clone instances and bundle
  11  * replica containers.
  12  */
  13 
  14 #include <crm_internal.h>
  15 #include <crm/msg_xml.h>
  16 #include <pacemaker-internal.h>
  17 #include "libpacemaker_private.h"
  18 
  19 /*!
  20  * \internal
  21  * \brief Check whether a clone or bundle has instances for all available nodes
  22  *
  23  * \param[in] collective  Clone or bundle to check
  24  *
  25  * \return true if \p collective has enough instances for all of its available
  26  *         allowed nodes, otherwise false
  27  */
  28 static bool
  29 can_run_everywhere(const pe_resource_t *collective)
     /* [previous][next][first][last][top][bottom][index][help] */
  30 {
  31     GHashTableIter iter;
  32     pe_node_t *node = NULL;
  33     int available_nodes = 0;
  34     int max_instances = 0;
  35 
  36     switch (collective->variant) {
  37         case pe_clone:
  38             max_instances = pe__clone_max(collective);
  39             break;
  40         case pe_container:
  41             max_instances = pe__bundle_max(collective);
  42             break;
  43         default:
  44             return false; // Not actually possible
  45     }
  46 
  47     g_hash_table_iter_init(&iter, collective->allowed_nodes);
  48     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
  49         if (pcmk__node_available(node, false, false)
  50             && (max_instances < ++available_nodes)) {
  51             return false;
  52         }
  53     }
  54     return true;
  55 }
  56 
  57 /*!
  58  * \internal
  59  * \brief Check whether a node is allowed to run an instance
  60  *
  61  * \param[in] instance      Clone instance or bundle container to check
  62  * \param[in] node          Node to check
  63  * \param[in] max_per_node  Maximum number of instances allowed to run on a node
  64  *
  65  * \return true if \p node is allowed to run \p instance, otherwise false
  66  */
  67 static bool
  68 can_run_instance(const pe_resource_t *instance, const pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
  69                  int max_per_node)
  70 {
  71     pe_node_t *allowed_node = NULL;
  72 
  73     if (pcmk_is_set(instance->flags, pe_rsc_orphan)) {
  74         pe_rsc_trace(instance, "%s cannot run on %s: orphaned",
  75                      instance->id, pe__node_name(node));
  76         return false;
  77     }
  78 
  79     if (!pcmk__node_available(node, false, false)) {
  80         pe_rsc_trace(instance,
  81                      "%s cannot run on %s: node cannot run resources",
  82                      instance->id, pe__node_name(node));
  83         return false;
  84     }
  85 
  86     allowed_node = pcmk__top_allowed_node(instance, node);
  87     if (allowed_node == NULL) {
  88         crm_warn("%s cannot run on %s: node not allowed",
  89                  instance->id, pe__node_name(node));
  90         return false;
  91     }
  92 
  93     if (allowed_node->weight < 0) {
  94         pe_rsc_trace(instance, "%s cannot run on %s: parent score is %s there",
  95                      instance->id, pe__node_name(node),
  96                      pcmk_readable_score(allowed_node->weight));
  97         return false;
  98     }
  99 
 100     if (allowed_node->count >= max_per_node) {
 101         pe_rsc_trace(instance,
 102                      "%s cannot run on %s: node already has %d instance%s",
 103                      instance->id, pe__node_name(node), max_per_node,
 104                      pcmk__plural_s(max_per_node));
 105         return false;
 106     }
 107 
 108     pe_rsc_trace(instance, "%s can run on %s (%d already running)",
 109                  instance->id, pe__node_name(node), allowed_node->count);
 110     return true;
 111 }
 112 
 113 /*!
 114  * \internal
 115  * \brief Ban a clone instance or bundle replica from unavailable allowed nodes
 116  *
 117  * \param[in,out] instance      Clone instance or bundle replica to ban
 118  * \param[in]     max_per_node  Maximum instances allowed to run on a node
 119  */
 120 static void
 121 ban_unavailable_allowed_nodes(pe_resource_t *instance, int max_per_node)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123     if (instance->allowed_nodes != NULL) {
 124         GHashTableIter iter;
 125         pe_node_t *node = NULL;
 126 
 127         g_hash_table_iter_init(&iter, instance->allowed_nodes);
 128         while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) {
 129             if (!can_run_instance(instance, node, max_per_node)) {
 130                 pe_rsc_trace(instance, "Banning %s from unavailable node %s",
 131                              instance->id, pe__node_name(node));
 132                 node->weight = -INFINITY;
 133                 for (GList *child_iter = instance->children;
 134                      child_iter != NULL; child_iter = child_iter->next) {
 135                     pe_resource_t *child = (pe_resource_t *) child_iter->data;
 136                     pe_node_t *child_node = NULL;
 137 
 138                     child_node = pe_hash_table_lookup(child->allowed_nodes,
 139                                                       node->details->id);
 140                     if (child_node != NULL) {
 141                         pe_rsc_trace(instance,
 142                                      "Banning %s child %s "
 143                                      "from unavailable node %s",
 144                                      instance->id, child->id,
 145                                      pe__node_name(node));
 146                         child_node->weight = -INFINITY;
 147                     }
 148                 }
 149             }
 150         }
 151     }
 152 }
 153 
 154 /*!
 155  * \internal
 156  * \brief Create a hash table with a single node in it
 157  *
 158  * \param[in] node  Node to copy into new table
 159  *
 160  * \return Newly created hash table containing a copy of \p node
 161  * \note The caller is responsible for freeing the result with
 162  *       g_hash_table_destroy().
 163  */
 164 static GHashTable *
 165 new_node_table(pe_node_t *node)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167     GHashTable *table = pcmk__strkey_table(NULL, free);
 168 
 169     node = pe__copy_node(node);
 170     g_hash_table_insert(table, (gpointer) node->details->id, node);
 171     return table;
 172 }
 173 
 174 /*!
 175  * \internal
 176  * \brief Apply a resource's parent's colocation scores to a node table
 177  *
 178  * \param[in]     rsc    Resource whose colocations should be applied
 179  * \param[in,out] nodes  Node table to apply colocations to
 180  */
 181 static void
 182 apply_parent_colocations(const pe_resource_t *rsc, GHashTable **nodes)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184     GList *iter = NULL;
 185     pcmk__colocation_t *colocation = NULL;
 186     pe_resource_t *other = NULL;
 187     float factor = 0.0;
 188 
 189     /* Because the this_with_colocations() and with_this_colocations() methods
 190      * boil down to copies of rsc_cons and rsc_cons_lhs for clones and bundles,
 191      * we can use those here directly for efficiency.
 192      */
 193     for (iter = rsc->parent->rsc_cons; iter != NULL; iter = iter->next) {
 194         colocation = (pcmk__colocation_t *) iter->data;
 195         other = colocation->primary;
 196         factor = colocation->score / (float) INFINITY,
 197         other->cmds->add_colocated_node_scores(other, rsc->id, nodes,
 198                                                colocation->node_attribute,
 199                                                factor,
 200                                                pcmk__coloc_select_default);
 201     }
 202     for (iter = rsc->parent->rsc_cons_lhs; iter != NULL; iter = iter->next) {
 203         colocation = (pcmk__colocation_t *) iter->data;
 204         if (!pcmk__colocation_has_influence(colocation, rsc)) {
 205             continue;
 206         }
 207         other = colocation->dependent;
 208         factor = colocation->score / (float) INFINITY,
 209         other->cmds->add_colocated_node_scores(other, rsc->id, nodes,
 210                                                colocation->node_attribute,
 211                                                factor,
 212                                                pcmk__coloc_select_nonnegative);
 213     }
 214 }
 215 
 216 /*!
 217  * \internal
 218  * \brief Compare clone or bundle instances based on colocation scores
 219  *
 220  * Determine the relative order in which two clone or bundle instances should be
 221  * assigned to nodes, considering the scores of colocation constraints directly
 222  * or indirectly involving them.
 223  *
 224  * \param[in] instance1  First instance to compare
 225  * \param[in] instance2  Second instance to compare
 226  *
 227  * \return A negative number if \p instance1 should be assigned first,
 228  *         a positive number if \p instance2 should be assigned first,
 229  *         or 0 if assignment order doesn't matter
 230  */
 231 static int
 232 cmp_instance_by_colocation(const pe_resource_t *instance1,
     /* [previous][next][first][last][top][bottom][index][help] */
 233                            const pe_resource_t *instance2)
 234 {
 235     int rc = 0;
 236     pe_node_t *node1 = NULL;
 237     pe_node_t *node2 = NULL;
 238     pe_node_t *current_node1 = pe__current_node(instance1);
 239     pe_node_t *current_node2 = pe__current_node(instance2);
 240     GHashTable *colocated_scores1 = NULL;
 241     GHashTable *colocated_scores2 = NULL;
 242 
 243     CRM_ASSERT((instance1 != NULL) && (instance1->parent != NULL)
 244                && (instance2 != NULL) && (instance2->parent != NULL)
 245                && (current_node1 != NULL) && (current_node2 != NULL));
 246 
 247     // Create node tables initialized with each node
 248     colocated_scores1 = new_node_table(current_node1);
 249     colocated_scores2 = new_node_table(current_node2);
 250 
 251     // Apply parental colocations
 252     apply_parent_colocations(instance1, &colocated_scores1);
 253     apply_parent_colocations(instance2, &colocated_scores2);
 254 
 255     // Find original nodes again, with scores updated for colocations
 256     node1 = g_hash_table_lookup(colocated_scores1, current_node1->details->id);
 257     node2 = g_hash_table_lookup(colocated_scores2, current_node2->details->id);
 258 
 259     // Compare nodes by updated scores
 260     if (node1->weight < node2->weight) {
 261         crm_trace("Assign %s (%d on %s) after %s (%d on %s)",
 262                   instance1->id, node1->weight, pe__node_name(node1),
 263                   instance2->id, node2->weight, pe__node_name(node2));
 264         rc = 1;
 265 
 266     } else if (node1->weight > node2->weight) {
 267         crm_trace("Assign %s (%d on %s) before %s (%d on %s)",
 268                   instance1->id, node1->weight, pe__node_name(node1),
 269                   instance2->id, node2->weight, pe__node_name(node2));
 270         rc = -1;
 271     }
 272 
 273     g_hash_table_destroy(colocated_scores1);
 274     g_hash_table_destroy(colocated_scores2);
 275     return rc;
 276 }
 277 
 278 /*!
 279  * \internal
 280  * \brief Check whether a resource or any of its children are failed
 281  *
 282  * \param[in] rsc  Resource to check
 283  *
 284  * \return true if \p rsc or any of its children are failed, otherwise false
 285  */
 286 static bool
 287 did_fail(const pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 288 {
 289     if (pcmk_is_set(rsc->flags, pe_rsc_failed)) {
 290         return true;
 291     }
 292     for (GList *iter = rsc->children; iter != NULL; iter = iter->next) {
 293         if (did_fail((const pe_resource_t *) iter->data)) {
 294             return true;
 295         }
 296     }
 297     return false;
 298 }
 299 
 300 /*!
 301  * \internal
 302  * \brief Check whether a node is allowed to run a resource
 303  *
 304  * \param[in]     rsc   Resource to check
 305  * \param[in,out] node  Node to check (will be set NULL if not allowed)
 306  *
 307  * \return true if *node is either NULL or allowed for \p rsc, otherwise false
 308  */
 309 static bool
 310 node_is_allowed(const pe_resource_t *rsc, pe_node_t **node)
     /* [previous][next][first][last][top][bottom][index][help] */
 311 {
 312     if (*node != NULL) {
 313         pe_node_t *allowed = pe_hash_table_lookup(rsc->allowed_nodes,
 314                                                   (*node)->details->id);
 315         if ((allowed == NULL) || (allowed->weight < 0)) {
 316             pe_rsc_trace(rsc, "%s: current location (%s) is unavailable",
 317                          rsc->id, pe__node_name(*node));
 318             *node = NULL;
 319             return false;
 320         }
 321     }
 322     return true;
 323 }
 324 
 325 /*!
 326  * \internal
 327  * \brief Compare two clone or bundle instances' instance numbers
 328  *
 329  * \param[in] a  First instance to compare
 330  * \param[in] b  Second instance to compare
 331  *
 332  * \return A negative number if \p a's instance number is lower,
 333  *         a positive number if \p b's instance number is lower,
 334  *         or 0 if their instance numbers are the same
 335  */
 336 gint
 337 pcmk__cmp_instance_number(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339     const pe_resource_t *instance1 = (const pe_resource_t *) a;
 340     const pe_resource_t *instance2 = (const pe_resource_t *) b;
 341     char *div1 = NULL;
 342     char *div2 = NULL;
 343 
 344     CRM_ASSERT((instance1 != NULL) && (instance2 != NULL));
 345 
 346     // Clone numbers are after a colon, bundle numbers after a dash
 347     div1 = strrchr(instance1->id, ':');
 348     if (div1 == NULL) {
 349         div1 = strrchr(instance1->id, '-');
 350     }
 351     div2 = strrchr(instance2->id, ':');
 352     if (div2 == NULL) {
 353         div2 = strrchr(instance2->id, '-');
 354     }
 355     CRM_ASSERT((div1 != NULL) && (div2 != NULL));
 356 
 357     return (gint) (strtol(div1 + 1, NULL, 10) - strtol(div2 + 1, NULL, 10));
 358 }
 359 
 360 /*!
 361  * \internal
 362  * \brief Compare clone or bundle instances according to assignment order
 363  *
 364  * Compare two clone or bundle instances according to the order they should be
 365  * assigned to nodes, preferring (in order):
 366  *
 367  *  - Active instance that is less multiply active
 368  *  - Instance that is not active on a disallowed node
 369  *  - Instance with higher configured priority
 370  *  - Active instance whose current node can run resources
 371  *  - Active instance whose parent is allowed on current node
 372  *  - Active instance whose current node has fewer other instances
 373  *  - Active instance
 374  *  - Instance that isn't failed
 375  *  - Instance whose colocations result in higher score on current node
 376  *  - Instance with lower ID in lexicographic order
 377  *
 378  * \param[in] a          First instance to compare
 379  * \param[in] b          Second instance to compare
 380  *
 381  * \return A negative number if \p a should be assigned first,
 382  *         a positive number if \p b should be assigned first,
 383  *         or 0 if assignment order doesn't matter
 384  */
 385 gint
 386 pcmk__cmp_instance(gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help] */
 387 {
 388     int rc = 0;
 389     pe_node_t *node1 = NULL;
 390     pe_node_t *node2 = NULL;
 391     unsigned int nnodes1 = 0;
 392     unsigned int nnodes2 = 0;
 393 
 394     bool can1 = true;
 395     bool can2 = true;
 396 
 397     const pe_resource_t *instance1 = (const pe_resource_t *) a;
 398     const pe_resource_t *instance2 = (const pe_resource_t *) b;
 399 
 400     CRM_ASSERT((instance1 != NULL) && (instance2 != NULL));
 401 
 402     node1 = instance1->fns->active_node(instance1, &nnodes1, NULL);
 403     node2 = instance2->fns->active_node(instance2, &nnodes2, NULL);
 404 
 405     /* If both instances are running and at least one is multiply
 406      * active, prefer instance that's running on fewer nodes.
 407      */
 408     if ((nnodes1 > 0) && (nnodes2 > 0)) {
 409         if (nnodes1 < nnodes2) {
 410             crm_trace("Assign %s (active on %d) before %s (active on %d): "
 411                       "less multiply active",
 412                       instance1->id, nnodes1, instance2->id, nnodes2);
 413             return -1;
 414 
 415         } else if (nnodes1 > nnodes2) {
 416             crm_trace("Assign %s (active on %d) after %s (active on %d): "
 417                       "more multiply active",
 418                       instance1->id, nnodes1, instance2->id, nnodes2);
 419             return 1;
 420         }
 421     }
 422 
 423     /* An instance that is either inactive or active on an allowed node is
 424      * preferred over an instance that is active on a no-longer-allowed node.
 425      */
 426     can1 = node_is_allowed(instance1, &node1);
 427     can2 = node_is_allowed(instance2, &node2);
 428     if (can1 && !can2) {
 429         crm_trace("Assign %s before %s: not active on a disallowed node",
 430                   instance1->id, instance2->id);
 431         return -1;
 432 
 433     } else if (!can1 && can2) {
 434         crm_trace("Assign %s after %s: active on a disallowed node",
 435                   instance1->id, instance2->id);
 436         return 1;
 437     }
 438 
 439     // Prefer instance with higher configured priority
 440     if (instance1->priority > instance2->priority) {
 441         crm_trace("Assign %s before %s: priority (%d > %d)",
 442                   instance1->id, instance2->id,
 443                   instance1->priority, instance2->priority);
 444         return -1;
 445 
 446     } else if (instance1->priority < instance2->priority) {
 447         crm_trace("Assign %s after %s: priority (%d < %d)",
 448                   instance1->id, instance2->id,
 449                   instance1->priority, instance2->priority);
 450         return 1;
 451     }
 452 
 453     // Prefer active instance
 454     if ((node1 == NULL) && (node2 == NULL)) {
 455         crm_trace("No assignment preference for %s vs. %s: inactive",
 456                   instance1->id, instance2->id);
 457         return 0;
 458 
 459     } else if (node1 == NULL) {
 460         crm_trace("Assign %s after %s: active", instance1->id, instance2->id);
 461         return 1;
 462 
 463     } else if (node2 == NULL) {
 464         crm_trace("Assign %s before %s: active", instance1->id, instance2->id);
 465         return -1;
 466     }
 467 
 468     // Prefer instance whose current node can run resources
 469     can1 = pcmk__node_available(node1, false, false);
 470     can2 = pcmk__node_available(node2, false, false);
 471     if (can1 && !can2) {
 472         crm_trace("Assign %s before %s: current node can run resources",
 473                   instance1->id, instance2->id);
 474         return -1;
 475 
 476     } else if (!can1 && can2) {
 477         crm_trace("Assign %s after %s: current node can't run resources",
 478                   instance1->id, instance2->id);
 479         return 1;
 480     }
 481 
 482     // Prefer instance whose parent is allowed to run on instance's current node
 483     node1 = pcmk__top_allowed_node(instance1, node1);
 484     node2 = pcmk__top_allowed_node(instance2, node2);
 485     if ((node1 == NULL) && (node2 == NULL)) {
 486         crm_trace("No assignment preference for %s vs. %s: "
 487                   "parent not allowed on either instance's current node",
 488                   instance1->id, instance2->id);
 489         return 0;
 490 
 491     } else if (node1 == NULL) {
 492         crm_trace("Assign %s after %s: parent not allowed on current node",
 493                   instance1->id, instance2->id);
 494         return 1;
 495 
 496     } else if (node2 == NULL) {
 497         crm_trace("Assign %s before %s: parent allowed on current node",
 498                   instance1->id, instance2->id);
 499         return -1;
 500     }
 501 
 502     // Prefer instance whose current node is running fewer other instances
 503     if (node1->count < node2->count) {
 504         crm_trace("Assign %s before %s: fewer active instances on current node",
 505                   instance1->id, instance2->id);
 506         return -1;
 507 
 508     } else if (node1->count > node2->count) {
 509         crm_trace("Assign %s after %s: more active instances on current node",
 510                   instance1->id, instance2->id);
 511         return 1;
 512     }
 513 
 514     // Prefer instance that isn't failed
 515     can1 = did_fail(instance1);
 516     can2 = did_fail(instance2);
 517     if (!can1 && can2) {
 518         crm_trace("Assign %s before %s: not failed",
 519                   instance1->id, instance2->id);
 520         return -1;
 521     } else if (can1 && !can2) {
 522         crm_trace("Assign %s after %s: failed",
 523                   instance1->id, instance2->id);
 524         return 1;
 525     }
 526 
 527     // Prefer instance with higher cumulative colocation score on current node
 528     rc = cmp_instance_by_colocation(instance1, instance2);
 529     if (rc != 0) {
 530         return rc;
 531     }
 532 
 533     // Prefer instance with lower instance number
 534     rc = pcmk__cmp_instance_number(instance1, instance2);
 535     if (rc < 0) {
 536         crm_trace("Assign %s before %s: instance number",
 537                   instance1->id, instance2->id);
 538     } else if (rc > 0) {
 539         crm_trace("Assign %s after %s: instance number",
 540                   instance1->id, instance2->id);
 541     } else {
 542         crm_trace("No assignment preference for %s vs. %s",
 543                   instance1->id, instance2->id);
 544     }
 545     return rc;
 546 }
 547 
 548 /*!
 549  * \internal
 550  * \brief Choose a node for an instance
 551  *
 552  * \param[in,out] instance      Clone instance or bundle replica container
 553  * \param[in]     prefer        If not NULL, attempt early assignment to this
 554  *                              node, if still the best choice; otherwise,
 555  *                              perform final assignment
 556  * \param[in]     max_per_node  Assign at most this many instances to one node
 557  *
 558  * \return true if \p instance could be assigned to a node, otherwise false
 559  */
 560 static bool
 561 assign_instance(pe_resource_t *instance, const pe_node_t *prefer,
     /* [previous][next][first][last][top][bottom][index][help] */
 562                 int max_per_node)
 563 {
 564     pe_node_t *chosen = NULL;
 565     pe_node_t *allowed = NULL;
 566 
 567     CRM_ASSERT(instance != NULL);
 568     pe_rsc_trace(instance, "Assigning %s (preferring %s)", instance->id,
 569                  ((prefer == NULL)? "no node" : prefer->details->uname));
 570 
 571     if (!pcmk_is_set(instance->flags, pe_rsc_provisional)) {
 572         // Instance is already assigned
 573         return instance->fns->location(instance, NULL, FALSE) != NULL;
 574     }
 575 
 576     if (pcmk_is_set(instance->flags, pe_rsc_allocating)) {
 577         pe_rsc_debug(instance,
 578                      "Assignment loop detected involving %s colocations",
 579                      instance->id);
 580         return false;
 581     }
 582 
 583     if (prefer != NULL) { // Possible early assignment to preferred node
 584 
 585         // Get preferred node with instance's scores
 586         allowed = g_hash_table_lookup(instance->allowed_nodes,
 587                                       prefer->details->id);
 588 
 589         if ((allowed == NULL) || (allowed->weight < 0)) {
 590             pe_rsc_trace(instance,
 591                          "Not assigning %s to preferred node %s: unavailable",
 592                          instance->id, pe__node_name(prefer));
 593             return false;
 594         }
 595     }
 596 
 597     ban_unavailable_allowed_nodes(instance, max_per_node);
 598 
 599     if (prefer == NULL) { // Final assignment
 600         chosen = instance->cmds->assign(instance, NULL);
 601 
 602     } else { // Possible early assignment to preferred node
 603         GHashTable *backup = pcmk__copy_node_table(instance->allowed_nodes);
 604 
 605         chosen = instance->cmds->assign(instance, prefer);
 606 
 607         // Revert nodes if preferred node won't be assigned
 608         if ((chosen != NULL) && (chosen->details != prefer->details)) {
 609             crm_info("Not assigning %s to preferred node %s: %s is better",
 610                      instance->id, pe__node_name(prefer),
 611                      pe__node_name(chosen));
 612             g_hash_table_destroy(instance->allowed_nodes);
 613             instance->allowed_nodes = backup;
 614             pcmk__unassign_resource(instance);
 615             chosen = NULL;
 616         } else if (backup != NULL) {
 617             g_hash_table_destroy(backup);
 618         }
 619     }
 620 
 621     // The parent tracks how many instances have been assigned to each node
 622     if (chosen != NULL) {
 623         allowed = pcmk__top_allowed_node(instance, chosen);
 624         if (allowed == NULL) {
 625             /* The instance is allowed on the node, but its parent isn't. This
 626              * shouldn't be possible if the resource is managed, and we won't be
 627              * able to limit the number of instances assigned to the node.
 628              */
 629             CRM_LOG_ASSERT(!pcmk_is_set(instance->flags, pe_rsc_managed));
 630 
 631         } else {
 632             allowed->count++;
 633         }
 634     }
 635     return chosen != NULL;
 636 }
 637 
 638 /*!
 639  * \internal
 640  * \brief Reset the node counts of a resource's allowed nodes to zero
 641  *
 642  * \param[in,out] rsc  Resource to reset
 643  *
 644  * \return Number of nodes that are available to run resources
 645  */
 646 static unsigned int
 647 reset_allowed_node_counts(pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 648 {
 649     unsigned int available_nodes = 0;
 650     pe_node_t *node = NULL;
 651     GHashTableIter iter;
 652 
 653     g_hash_table_iter_init(&iter, rsc->allowed_nodes);
 654     while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
 655         node->count = 0;
 656         if (pcmk__node_available(node, false, false)) {
 657             available_nodes++;
 658         }
 659     }
 660     return available_nodes;
 661 }
 662 
 663 /*!
 664  * \internal
 665  * \brief Check whether an instance has a preferred node
 666  *
 667  * \param[in] rsc               Clone or bundle being assigned (for logs only)
 668  * \param[in] instance          Clone instance or bundle replica container
 669  * \param[in] optimal_per_node  Optimal number of instances per node
 670  *
 671  * \return Instance's current node if still available, otherwise NULL
 672  */
 673 static const pe_node_t *
 674 preferred_node(const pe_resource_t *rsc, const pe_resource_t *instance,
     /* [previous][next][first][last][top][bottom][index][help] */
 675                int optimal_per_node)
 676 {
 677     const pe_node_t *node = NULL;
 678     const pe_node_t *parent_node = NULL;
 679 
 680     // Check whether instance is active, healthy, and not yet assigned
 681     if ((instance->running_on == NULL)
 682         || !pcmk_is_set(instance->flags, pe_rsc_provisional)
 683         || pcmk_is_set(instance->flags, pe_rsc_failed)) {
 684         return NULL;
 685     }
 686 
 687     // Check whether instance's current node can run resources
 688     node = pe__current_node(instance);
 689     if (!pcmk__node_available(node, true, false)) {
 690         pe_rsc_trace(rsc, "Not assigning %s to %s early (unavailable)",
 691                      instance->id, pe__node_name(node));
 692         return NULL;
 693     }
 694 
 695     // Check whether node already has optimal number of instances assigned
 696     parent_node = pcmk__top_allowed_node(instance, node);
 697     if ((parent_node != NULL) && (parent_node->count >= optimal_per_node)) {
 698         pe_rsc_trace(rsc,
 699                      "Not assigning %s to %s early "
 700                      "(optimal instances already assigned)",
 701                      instance->id, pe__node_name(node));
 702         return NULL;
 703     }
 704 
 705     return node;
 706 }
 707 
 708 /*!
 709  * \internal
 710  * \brief Assign collective instances to nodes
 711  *
 712  * \param[in,out] collective    Clone or bundle resource being assigned
 713  * \param[in,out] instances     List of clone instances or bundle containers
 714  * \param[in]     max_total     Maximum instances to assign in total
 715  * \param[in]     max_per_node  Maximum instances to assign to any one node
 716  */
 717 void
 718 pcmk__assign_instances(pe_resource_t *collective, GList *instances,
     /* [previous][next][first][last][top][bottom][index][help] */
 719                        int max_total, int max_per_node)
 720 {
 721     // Reuse node count to track number of assigned instances
 722     unsigned int available_nodes = reset_allowed_node_counts(collective);
 723 
 724     int optimal_per_node = 0;
 725     int assigned = 0;
 726     GList *iter = NULL;
 727     pe_resource_t *instance = NULL;
 728     const pe_node_t *current = NULL;
 729 
 730     if (available_nodes > 0) {
 731         optimal_per_node = max_total / available_nodes;
 732     }
 733     if (optimal_per_node < 1) {
 734         optimal_per_node = 1;
 735     }
 736 
 737     pe_rsc_debug(collective,
 738                  "Assigning up to %d %s instance%s to up to %u node%s "
 739                  "(at most %d per host, %d optimal)",
 740                  max_total, collective->id, pcmk__plural_s(max_total),
 741                  available_nodes, pcmk__plural_s(available_nodes),
 742                  max_per_node, optimal_per_node);
 743 
 744     // Assign as many instances as possible to their current location
 745     for (iter = instances; (iter != NULL) && (assigned < max_total);
 746          iter = iter->next) {
 747         instance = (pe_resource_t *) iter->data;
 748 
 749         current = preferred_node(collective, instance, optimal_per_node);
 750         if ((current != NULL)
 751             && assign_instance(instance, current, max_per_node)) {
 752             pe_rsc_trace(collective, "Assigned %s to current node %s",
 753                          instance->id, pe__node_name(current));
 754             assigned++;
 755         }
 756     }
 757 
 758     pe_rsc_trace(collective, "Assigned %d of %d instance%s to current node",
 759                  assigned, max_total, pcmk__plural_s(max_total));
 760 
 761     for (iter = instances; iter != NULL; iter = iter->next) {
 762         instance = (pe_resource_t *) iter->data;
 763 
 764         if (!pcmk_is_set(instance->flags, pe_rsc_provisional)) {
 765             continue; // Already assigned
 766         }
 767 
 768         if (instance->running_on != NULL) {
 769             current = pe__current_node(instance);
 770             if (pcmk__top_allowed_node(instance, current) == NULL) {
 771                 const char *unmanaged = "";
 772 
 773                 if (!pcmk_is_set(instance->flags, pe_rsc_managed)) {
 774                     unmanaged = "Unmanaged resource ";
 775                 }
 776                 crm_notice("%s%s is running on %s which is no longer allowed",
 777                            unmanaged, instance->id, pe__node_name(current));
 778             }
 779         }
 780 
 781         if (assigned >= max_total) {
 782             pe_rsc_debug(collective,
 783                          "Not assigning %s because maximum %d instances "
 784                          "already assigned",
 785                          instance->id, max_total);
 786             resource_location(instance, NULL, -INFINITY,
 787                               "collective_limit_reached", collective->cluster);
 788 
 789         } else if (assign_instance(instance, NULL, max_per_node)) {
 790             assigned++;
 791         }
 792     }
 793 
 794     pe_rsc_debug(collective, "Assigned %d of %d possible instance%s of %s",
 795                  assigned, max_total, pcmk__plural_s(max_total),
 796                  collective->id);
 797 }
 798 
 799 enum instance_state {
 800     instance_starting   = (1 << 0),
 801     instance_stopping   = (1 << 1),
 802 
 803     /* This indicates that some instance is restarting. It's not the same as
 804      * instance_starting|instance_stopping, which would indicate that some
 805      * instance is starting, and some instance (not necessarily the same one) is
 806      * stopping.
 807      */
 808     instance_restarting = (1 << 2),
 809 
 810     instance_active     = (1 << 3),
 811 
 812     instance_all        = instance_starting|instance_stopping
 813                           |instance_restarting|instance_active,
 814 };
 815 
 816 /*!
 817  * \internal
 818  * \brief Check whether an instance is active, starting, and/or stopping
 819  *
 820  * \param[in]     instance  Clone instance or bundle replica container
 821  * \param[in,out] state     Whether any instance is starting, stopping, etc.
 822  */
 823 static void
 824 check_instance_state(const pe_resource_t *instance, uint32_t *state)
     /* [previous][next][first][last][top][bottom][index][help] */
 825 {
 826     const GList *iter = NULL;
 827     uint32_t instance_state = 0; // State of just this instance
 828 
 829     // No need to check further if all conditions have already been detected
 830     if (pcmk_all_flags_set(*state, instance_all)) {
 831         return;
 832     }
 833 
 834     // If instance is a collective (a cloned group), check its children instead
 835     if (instance->variant > pe_native) {
 836         for (iter = instance->children;
 837              (iter != NULL) && !pcmk_all_flags_set(*state, instance_all);
 838              iter = iter->next) {
 839             check_instance_state((const pe_resource_t *) iter->data, state);
 840         }
 841         return;
 842     }
 843 
 844     // If we get here, instance is a primitive
 845 
 846     if (instance->running_on != NULL) {
 847         instance_state |= instance_active;
 848     }
 849 
 850     // Check each of the instance's actions for runnable start or stop
 851     for (iter = instance->actions;
 852          (iter != NULL) && !pcmk_all_flags_set(instance_state,
 853                                                instance_starting
 854                                                |instance_stopping);
 855          iter = iter->next) {
 856 
 857         const pe_action_t *action = (const pe_action_t *) iter->data;
 858         const bool optional = pcmk_is_set(action->flags, pe_action_optional);
 859 
 860         if (pcmk__str_eq(RSC_START, action->task, pcmk__str_none)) {
 861             if (!optional && pcmk_is_set(action->flags, pe_action_runnable)) {
 862                 pe_rsc_trace(instance, "Instance is starting due to %s",
 863                              action->uuid);
 864                 instance_state |= instance_starting;
 865             } else {
 866                 pe_rsc_trace(instance, "%s doesn't affect %s state (%s)",
 867                              action->uuid, instance->id,
 868                              (optional? "optional" : "unrunnable"));
 869             }
 870 
 871         } else if (pcmk__str_eq(RSC_STOP, action->task, pcmk__str_none)) {
 872             /* Only stop actions can be pseudo-actions for primitives. That
 873              * indicates that the node they are on is being fenced, so the stop
 874              * is implied rather than actually executed.
 875              */
 876             if (!optional
 877                 && pcmk_any_flags_set(action->flags,
 878                                       pe_action_pseudo|pe_action_runnable)) {
 879                 pe_rsc_trace(instance, "Instance is stopping due to %s",
 880                              action->uuid);
 881                 instance_state |= instance_stopping;
 882             } else {
 883                 pe_rsc_trace(instance, "%s doesn't affect %s state (%s)",
 884                              action->uuid, instance->id,
 885                              (optional? "optional" : "unrunnable"));
 886             }
 887         }
 888     }
 889 
 890     if (pcmk_all_flags_set(instance_state,
 891                            instance_starting|instance_stopping)) {
 892         instance_state |= instance_restarting;
 893     }
 894     *state |= instance_state;
 895 }
 896 
 897 /*!
 898  * \internal
 899  * \brief Create actions for collective resource instances
 900  *
 901  * \param[in,out] collective    Clone or bundle resource to create actions for
 902  * \param[in,out] instances     List of clone instances or bundle containers
 903  */
 904 void
 905 pcmk__create_instance_actions(pe_resource_t *collective, GList *instances)
     /* [previous][next][first][last][top][bottom][index][help] */
 906 {
 907     uint32_t state = 0;
 908 
 909     pe_action_t *stop = NULL;
 910     pe_action_t *stopped = NULL;
 911 
 912     pe_action_t *start = NULL;
 913     pe_action_t *started = NULL;
 914 
 915     pe_rsc_trace(collective, "Creating collective instance actions for %s",
 916                  collective->id);
 917 
 918     // Create actions for each instance appropriate to its variant
 919     for (GList *iter = instances; iter != NULL; iter = iter->next) {
 920         pe_resource_t *instance = (pe_resource_t *) iter->data;
 921 
 922         instance->cmds->create_actions(instance);
 923         check_instance_state(instance, &state);
 924     }
 925 
 926     // Create pseudo-actions for rsc start and started
 927     start = pe__new_rsc_pseudo_action(collective, RSC_START,
 928                                       !pcmk_is_set(state, instance_starting),
 929                                       true);
 930     started = pe__new_rsc_pseudo_action(collective, RSC_STARTED,
 931                                         !pcmk_is_set(state, instance_starting),
 932                                         false);
 933     started->priority = INFINITY;
 934     if (pcmk_any_flags_set(state, instance_active|instance_starting)) {
 935         pe__set_action_flags(started, pe_action_runnable);
 936     }
 937 
 938     // Create pseudo-actions for rsc stop and stopped
 939     stop = pe__new_rsc_pseudo_action(collective, RSC_STOP,
 940                                      !pcmk_is_set(state, instance_stopping),
 941                                      true);
 942     stopped = pe__new_rsc_pseudo_action(collective, RSC_STOPPED,
 943                                         !pcmk_is_set(state, instance_stopping),
 944                                         true);
 945     stopped->priority = INFINITY;
 946     if (!pcmk_is_set(state, instance_restarting)) {
 947         pe__set_action_flags(stop, pe_action_migrate_runnable);
 948     }
 949 
 950     if (collective->variant == pe_clone) {
 951         pe__create_clone_notif_pseudo_ops(collective, start, started, stop,
 952                                           stopped);
 953     }
 954 }
 955 
 956 /*!
 957  * \internal
 958  * \brief Get a list of clone instances or bundle replica containers
 959  *
 960  * \param[in] rsc  Clone or bundle resource
 961  *
 962  * \return Clone instances if \p rsc is a clone, or a newly created list of
 963  *         \p rsc's replica containers if \p rsc is a bundle
 964  * \note The caller must call free_instance_list() on the result when the list
 965  *       is no longer needed.
 966  */
 967 static inline GList *
 968 get_instance_list(const pe_resource_t *rsc)
     /* [previous][next][first][last][top][bottom][index][help] */
 969 {
 970     if (rsc->variant == pe_container) {
 971         return pe__bundle_containers(rsc);
 972     } else {
 973         return rsc->children;
 974     }
 975 }
 976 
 977 /*!
 978  * \internal
 979  * \brief Free any memory created by get_instance_list()
 980  *
 981  * \param[in]     rsc   Clone or bundle resource passed to get_instance_list()
 982  * \param[in,out] list  Return value of get_instance_list() for \p rsc
 983  */
 984 static inline void
 985 free_instance_list(const pe_resource_t *rsc, GList *list)
     /* [previous][next][first][last][top][bottom][index][help] */
 986 {
 987     if (list != rsc->children) {
 988         g_list_free(list);
 989     }
 990 }
 991 
 992 /*!
 993  * \internal
 994  * \brief Check whether an instance is compatible with a role and node
 995  *
 996  * \param[in] instance  Clone instance or bundle replica container
 997  * \param[in] node      Instance must match this node
 998  * \param[in] role      If not RSC_ROLE_UNKNOWN, instance must match this role
 999  * \param[in] current   If true, compare instance's original node and role,
1000  *                      otherwise compare assigned next node and role
1001  *
1002  * \return true if \p instance is compatible with \p node and \p role,
1003  *         otherwise false
1004  */
1005 bool
1006 pcmk__instance_matches(const pe_resource_t *instance, const pe_node_t *node,
     /* [previous][next][first][last][top][bottom][index][help] */
1007                        enum rsc_role_e role, bool current)
1008 {
1009     pe_node_t *instance_node = NULL;
1010 
1011     CRM_CHECK((instance != NULL) && (node != NULL), return false);
1012 
1013     if ((role != RSC_ROLE_UNKNOWN)
1014         && (role != instance->fns->state(instance, current))) {
1015         pe_rsc_trace(instance,
1016                      "%s is not a compatible instance (role is not %s)",
1017                      instance->id, role2text(role));
1018         return false;
1019     }
1020 
1021     if (!is_set_recursive(instance, pe_rsc_block, true)) {
1022         // We only want instances that haven't failed
1023         instance_node = instance->fns->location(instance, NULL, current);
1024     }
1025 
1026     if (instance_node == NULL) {
1027         pe_rsc_trace(instance,
1028                      "%s is not a compatible instance (not assigned to a node)",
1029                      instance->id);
1030         return false;
1031     }
1032 
1033     if (instance_node->details != node->details) {
1034         pe_rsc_trace(instance,
1035                      "%s is not a compatible instance (assigned to %s not %s)",
1036                      instance->id, pe__node_name(instance_node),
1037                      pe__node_name(node));
1038         return false;
1039     }
1040 
1041     return true;
1042 }
1043 
1044 /*!
1045  * \internal
1046  * \brief Find an instance that matches a given resource by node and role
1047  *
1048  * \param[in] match_rsc  Resource that instance must match (for logging only)
1049  * \param[in] rsc        Clone or bundle resource to check for matching instance
1050  * \param[in] node       Instance must match this node
1051  * \param[in] role       If not RSC_ROLE_UNKNOWN, instance must match this role
1052  * \param[in] current    If true, compare instance's original node and role,
1053  *                       otherwise compare assigned next node and role
1054  *
1055  * \return \p rsc instance matching \p node and \p role if any, otherwise NULL
1056  */
1057 static pe_resource_t *
1058 find_compatible_instance_on_node(const pe_resource_t *match_rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
1059                                  const pe_resource_t *rsc,
1060                                  const pe_node_t *node, enum rsc_role_e role,
1061                                  bool current)
1062 {
1063     GList *instances = NULL;
1064 
1065     instances = get_instance_list(rsc);
1066     for (GList *iter = instances; iter != NULL; iter = iter->next) {
1067         pe_resource_t *instance = (pe_resource_t *) iter->data;
1068 
1069         if (pcmk__instance_matches(instance, node, role, current)) {
1070             pe_rsc_trace(match_rsc, "Found %s %s instance %s compatible with %s on %s",
1071                          role == RSC_ROLE_UNKNOWN? "matching" : role2text(role),
1072                          rsc->id, instance->id, match_rsc->id,
1073                          pe__node_name(node));
1074             free_instance_list(rsc, instances); // Only frees list, not contents
1075             return instance;
1076         }
1077     }
1078     free_instance_list(rsc, instances);
1079 
1080     pe_rsc_trace(match_rsc, "No %s %s instance found compatible with %s on %s",
1081                  ((role == RSC_ROLE_UNKNOWN)? "matching" : role2text(role)),
1082                  rsc->id, match_rsc->id, pe__node_name(node));
1083     return NULL;
1084 }
1085 
1086 /*!
1087  * \internal
1088  * \brief Find a clone instance or bundle container compatible with a resource
1089  *
1090  * \param[in] match_rsc  Resource that instance must match
1091  * \param[in] rsc        Clone or bundle resource to check for matching instance
1092  * \param[in] role       If not RSC_ROLE_UNKNOWN, instance must match this role
1093  * \param[in] current    If true, compare instance's original node and role,
1094  *                       otherwise compare assigned next node and role
1095  *
1096  * \return Compatible (by \p role and \p match_rsc location) instance of \p rsc
1097  *         if any, otherwise NULL
1098  */
1099 pe_resource_t *
1100 pcmk__find_compatible_instance(const pe_resource_t *match_rsc,
     /* [previous][next][first][last][top][bottom][index][help] */
1101                                const pe_resource_t *rsc, enum rsc_role_e role,
1102                                bool current)
1103 {
1104     pe_resource_t *instance = NULL;
1105     GList *nodes = NULL;
1106     const pe_node_t *node = match_rsc->fns->location(match_rsc, NULL, current);
1107 
1108     // If match_rsc has a node, check only that node
1109     if (node != NULL) {
1110         return find_compatible_instance_on_node(match_rsc, rsc, node, role,
1111                                                 current);
1112     }
1113 
1114     // Otherwise check for an instance matching any of match_rsc's allowed nodes
1115     nodes = pcmk__sort_nodes(g_hash_table_get_values(match_rsc->allowed_nodes),
1116                              NULL);
1117     for (GList *iter = nodes; (iter != NULL) && (instance == NULL);
1118          iter = iter->next) {
1119         instance = find_compatible_instance_on_node(match_rsc, rsc,
1120                                                     (pe_node_t *) iter->data,
1121                                                     role, current);
1122     }
1123 
1124     if (instance == NULL) {
1125         pe_rsc_debug(rsc, "No %s instance found compatible with %s",
1126                      rsc->id, match_rsc->id);
1127     }
1128     g_list_free(nodes);
1129     return instance;
1130 }
1131 
1132 /*!
1133  * \internal
1134  * \brief Unassign an instance if mandatory ordering has no interleave match
1135  *
1136  * \param[in]     first          'First' action in an ordering
1137  * \param[in]     then           'Then' action in an ordering
1138  * \param[in,out] then_instance  'Then' instance that has no interleave match
1139  * \param[in]     type           Group of enum pe_ordering flags to apply
1140  * \param[in]     current        If true, "then" action is stopped or demoted
1141  *
1142  * \return true if \p then_instance was unassigned, otherwise false
1143  */
1144 static bool
1145 unassign_if_mandatory(const pe_action_t *first, const pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
1146                       pe_resource_t *then_instance, uint32_t type, bool current)
1147 {
1148     // Allow "then" instance to go down even without an interleave match
1149     if (current) {
1150         pe_rsc_trace(then->rsc,
1151                      "%s has no instance to order before stopping "
1152                      "or demoting %s",
1153                      first->rsc->id, then_instance->id);
1154 
1155     /* If the "first" action must be runnable, but there is no "first"
1156      * instance, the "then" instance must not be allowed to come up.
1157      */
1158     } else if (pcmk_any_flags_set(type, pe_order_runnable_left
1159                                         |pe_order_implies_then)) {
1160         pe_rsc_info(then->rsc,
1161                     "Inhibiting %s from being active "
1162                     "because there is no %s instance to interleave",
1163                     then_instance->id, first->rsc->id);
1164         return pcmk__assign_resource(then_instance, NULL, true);
1165     }
1166     return false;
1167 }
1168 
1169 /*!
1170  * \internal
1171  * \brief Find first matching action for a clone instance or bundle container
1172  *
1173  * \param[in] action       Action in an interleaved ordering
1174  * \param[in] instance     Clone instance or bundle container being interleaved
1175  * \param[in] action_name  Action to look for
1176  * \param[in] node         If not NULL, require action to be on this node
1177  * \param[in] for_first    If true, \p instance is the 'first' resource in the
1178  *                         ordering, otherwise it is the 'then' resource
1179  *
1180  * \return First action for \p instance (or in some cases if \p instance is a
1181  *         bundle container, its containerized resource) that matches
1182  *         \p action_name and \p node if any, otherwise NULL
1183  */
1184 static pe_action_t *
1185 find_instance_action(const pe_action_t *action, const pe_resource_t *instance,
     /* [previous][next][first][last][top][bottom][index][help] */
1186                      const char *action_name, const pe_node_t *node,
1187                      bool for_first)
1188 {
1189     const pe_resource_t *rsc = NULL;
1190     pe_action_t *matching_action = NULL;
1191 
1192     /* If instance is a bundle container, sometimes we should interleave the
1193      * action for the container itself, and sometimes for the containerized
1194      * resource.
1195      *
1196      * For example, given "start bundle A then bundle B", B likely requires the
1197      * service inside A's container to be active, rather than just the
1198      * container, so we should interleave the action for A's containerized
1199      * resource. On the other hand, it's possible B's container itself requires
1200      * something from A, so we should interleave the action for B's container.
1201      *
1202      * Essentially, for 'first', we should use the containerized resource for
1203      * everything except stop, and for 'then', we should use the container for
1204      * everything except promote and demote (which can only be performed on the
1205      * containerized resource).
1206      */
1207     if ((for_first && !pcmk__str_any_of(action->task, CRMD_ACTION_STOP,
1208                                         CRMD_ACTION_STOPPED, NULL))
1209 
1210         || (!for_first && pcmk__str_any_of(action->task, CRMD_ACTION_PROMOTE,
1211                                            CRMD_ACTION_PROMOTED,
1212                                            CRMD_ACTION_DEMOTE,
1213                                            CRMD_ACTION_DEMOTED, NULL))) {
1214 
1215         rsc = pcmk__get_rsc_in_container(instance);
1216     }
1217     if (rsc == NULL) {
1218         rsc = instance; // No containerized resource, use instance itself
1219     } else {
1220         node = NULL; // Containerized actions are on bundle-created guest
1221     }
1222 
1223     matching_action = find_first_action(rsc->actions, NULL, action_name, node);
1224     if (matching_action != NULL) {
1225         return matching_action;
1226     }
1227 
1228     if (pcmk_is_set(instance->flags, pe_rsc_orphan)
1229         || pcmk__str_any_of(action_name, RSC_STOP, RSC_DEMOTE, NULL)) {
1230         crm_trace("No %s action found for %s%s",
1231                   action_name,
1232                   pcmk_is_set(instance->flags, pe_rsc_orphan)? "orphan " : "",
1233                   instance->id);
1234     } else {
1235         crm_err("No %s action found for %s to interleave (bug?)",
1236                 action_name, instance->id);
1237     }
1238     return NULL;
1239 }
1240 
1241 /*!
1242  * \internal
1243  * \brief Get the original action name of a bundle or clone action
1244  *
1245  * Given an action for a bundle or clone, get the original action name,
1246  * mapping notify to the action being notified, and if the instances are
1247  * primitives, mapping completion actions to the action that was completed
1248  * (for example, stopped to stop).
1249  *
1250  * \param[in] action  Clone or bundle action to check
1251  *
1252  * \return Original action name for \p action
1253  */
1254 static const char *
1255 orig_action_name(const pe_action_t *action)
     /* [previous][next][first][last][top][bottom][index][help] */
1256 {
1257     const pe_resource_t *instance = action->rsc->children->data; // Any instance
1258     char *action_type = NULL;
1259     const char *action_name = action->task;
1260     enum action_tasks orig_task = no_action;
1261 
1262     if (pcmk__strcase_any_of(action->task, CRMD_ACTION_NOTIFY,
1263                              CRMD_ACTION_NOTIFIED, NULL)) {
1264         // action->uuid is RSC_(confirmed-){pre,post}_notify_ACTION_INTERVAL
1265         CRM_CHECK(parse_op_key(action->uuid, NULL, &action_type, NULL),
1266                   return task2text(no_action));
1267         action_name = strstr(action_type, "_notify_");
1268         CRM_CHECK(action_name != NULL, return task2text(no_action));
1269         action_name += strlen("_notify_");
1270     }
1271     orig_task = get_complex_task(instance, action_name);
1272     free(action_type);
1273     return task2text(orig_task);
1274 }
1275 
1276 /*!
1277  * \internal
1278  * \brief Update two interleaved actions according to an ordering between them
1279  *
1280  * Given information about an ordering of two interleaved actions, update the
1281  * actions' flags (and runnable_before members if appropriate) as appropriate
1282  * for the ordering. Effects may cascade to other orderings involving the
1283  * actions as well.
1284  *
1285  * \param[in,out] first     'First' action in an ordering
1286  * \param[in,out] then      'Then' action in an ordering
1287  * \param[in]     node      If not NULL, limit scope of ordering to this node
1288  * \param[in]     filter    Action flags to limit scope of certain updates (may
1289  *                          include pe_action_optional to affect only mandatory
1290  *                          actions, and pe_action_runnable to affect only
1291  *                          runnable actions)
1292  * \param[in]     type      Group of enum pe_ordering flags to apply
1293  *
1294  * \return Group of enum pcmk__updated flags indicating what was updated
1295  */
1296 static uint32_t
1297 update_interleaved_actions(pe_action_t *first, pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
1298                            const pe_node_t *node, uint32_t filter,
1299                            uint32_t type)
1300 {
1301     GList *instances = NULL;
1302     uint32_t changed = pcmk__updated_none;
1303     const char *orig_first_task = orig_action_name(first);
1304 
1305     // Stops and demotes must be interleaved with instance on current node
1306     bool current = pcmk__ends_with(first->uuid, "_" CRMD_ACTION_STOPPED "_0")
1307                    || pcmk__ends_with(first->uuid,
1308                                       "_" CRMD_ACTION_DEMOTED "_0");
1309 
1310     // Update the specified actions for each "then" instance individually
1311     instances = get_instance_list(then->rsc);
1312     for (GList *iter = instances; iter != NULL; iter = iter->next) {
1313         pe_resource_t *first_instance = NULL;
1314         pe_resource_t *then_instance = iter->data;
1315 
1316         pe_action_t *first_action = NULL;
1317         pe_action_t *then_action = NULL;
1318 
1319         // Find a "first" instance to interleave with this "then" instance
1320         first_instance = pcmk__find_compatible_instance(then_instance,
1321                                                         first->rsc,
1322                                                         RSC_ROLE_UNKNOWN,
1323                                                         current);
1324 
1325         if (first_instance == NULL) { // No instance can be interleaved
1326             if (unassign_if_mandatory(first, then, then_instance, type,
1327                                       current)) {
1328                 pcmk__set_updated_flags(changed, first, pcmk__updated_then);
1329             }
1330             continue;
1331         }
1332 
1333         first_action = find_instance_action(first, first_instance,
1334                                             orig_first_task, node, true);
1335         if (first_action == NULL) {
1336             continue;
1337         }
1338 
1339         then_action = find_instance_action(then, then_instance, then->task,
1340                                            node, false);
1341         if (then_action == NULL) {
1342             continue;
1343         }
1344 
1345         if (order_actions(first_action, then_action, type)) {
1346             pcmk__set_updated_flags(changed, first,
1347                                     pcmk__updated_first|pcmk__updated_then);
1348         }
1349 
1350         changed |= then_instance->cmds->update_ordered_actions(
1351             first_action, then_action, node,
1352             first_instance->cmds->action_flags(first_action, node), filter,
1353             type, then->rsc->cluster);
1354     }
1355     free_instance_list(then->rsc, instances);
1356     return changed;
1357 }
1358 
1359 /*!
1360  * \internal
1361  * \brief Check whether two actions in an ordering can be interleaved
1362  *
1363  * \param[in] first  'First' action in the ordering
1364  * \param[in] then   'Then' action in the ordering
1365  *
1366  * \return true if \p first and \p then can be interleaved, otherwise false
1367  */
1368 static bool
1369 can_interleave_actions(const pe_action_t *first, const pe_action_t *then)
     /* [previous][next][first][last][top][bottom][index][help] */
1370 {
1371     bool interleave = false;
1372     pe_resource_t *rsc = NULL;
1373 
1374     if ((first->rsc == NULL) || (then->rsc == NULL)) {
1375         crm_trace("Not interleaving %s with %s: not resource actions",
1376                   first->uuid, then->uuid);
1377         return false;
1378     }
1379 
1380     if (first->rsc == then->rsc) {
1381         crm_trace("Not interleaving %s with %s: same resource",
1382                   first->uuid, then->uuid);
1383         return false;
1384     }
1385 
1386     if ((first->rsc->variant < pe_clone) || (then->rsc->variant < pe_clone)) {
1387         crm_trace("Not interleaving %s with %s: not clones or bundles",
1388                   first->uuid, then->uuid);
1389         return false;
1390     }
1391 
1392     if (pcmk__ends_with(then->uuid, "_stop_0")
1393         || pcmk__ends_with(then->uuid, "_demote_0")) {
1394         rsc = first->rsc;
1395     } else {
1396         rsc = then->rsc;
1397     }
1398 
1399     interleave = crm_is_true(g_hash_table_lookup(rsc->meta,
1400                                                  XML_RSC_ATTR_INTERLEAVE));
1401     pe_rsc_trace(rsc, "'%s then %s' will %sbe interleaved (based on %s)",
1402                  first->uuid, then->uuid, (interleave? "" : "not "), rsc->id);
1403     return interleave;
1404 }
1405 
1406 /*!
1407  * \internal
1408  * \brief Update non-interleaved instance actions according to an ordering
1409  *
1410  * Given information about an ordering of two non-interleaved actions, update
1411  * the actions' flags (and runnable_before members if appropriate) as
1412  * appropriate for the ordering. Effects may cascade to other orderings
1413  * involving the actions as well.
1414  *
1415  * \param[in,out] instance  Clone instance or bundle container
1416  * \param[in,out] first     "First" action in ordering
1417  * \param[in]     then      "Then" action in ordering (for \p instance's parent)
1418  * \param[in]     node      If not NULL, limit scope of ordering to this node
1419  * \param[in]     flags     Action flags for \p first for ordering purposes
1420  * \param[in]     filter    Action flags to limit scope of certain updates (may
1421  *                          include pe_action_optional to affect only mandatory
1422  *                          actions, and pe_action_runnable to affect only
1423  *                          runnable actions)
1424  * \param[in]     type      Group of enum pe_ordering flags to apply
1425  *
1426  * \return Group of enum pcmk__updated flags indicating what was updated
1427  */
1428 static uint32_t
1429 update_noninterleaved_actions(pe_resource_t *instance, pe_action_t *first,
     /* [previous][next][first][last][top][bottom][index][help] */
1430                               const pe_action_t *then, const pe_node_t *node,
1431                               uint32_t flags, uint32_t filter, uint32_t type)
1432 {
1433     pe_action_t *instance_action = NULL;
1434     uint32_t instance_flags = 0;
1435     uint32_t changed = pcmk__updated_none;
1436 
1437     // Check whether instance has an equivalent of "then" action
1438     instance_action = find_first_action(instance->actions, NULL, then->task,
1439                                         node);
1440     if (instance_action == NULL) {
1441         return changed;
1442     }
1443 
1444     // Check whether action is runnable
1445     instance_flags = instance->cmds->action_flags(instance_action, node);
1446     if (!pcmk_is_set(instance_flags, pe_action_runnable)) {
1447         return changed;
1448     }
1449 
1450     // If so, update actions for the instance
1451     changed = instance->cmds->update_ordered_actions(first, instance_action,
1452                                                      node, flags, filter, type,
1453                                                      instance->cluster);
1454 
1455     // Propagate any changes to later actions
1456     if (pcmk_is_set(changed, pcmk__updated_then)) {
1457         for (GList *after_iter = instance_action->actions_after;
1458              after_iter != NULL; after_iter = after_iter->next) {
1459             pe_action_wrapper_t *after = after_iter->data;
1460 
1461             pcmk__update_action_for_orderings(after->action, instance->cluster);
1462         }
1463     }
1464 
1465     return changed;
1466 }
1467 
1468 /*!
1469  * \internal
1470  * \brief Update two actions according to an ordering between them
1471  *
1472  * Given information about an ordering of two clone or bundle actions, update
1473  * the actions' flags (and runnable_before members if appropriate) as
1474  * appropriate for the ordering. Effects may cascade to other orderings
1475  * involving the actions as well.
1476  *
1477  * \param[in,out] first     'First' action in an ordering
1478  * \param[in,out] then      'Then' action in an ordering
1479  * \param[in]     node      If not NULL, limit scope of ordering to this node
1480  *                          (only used when interleaving instances)
1481  * \param[in]     flags     Action flags for \p first for ordering purposes
1482  * \param[in]     filter    Action flags to limit scope of certain updates (may
1483  *                          include pe_action_optional to affect only mandatory
1484  *                          actions, and pe_action_runnable to affect only
1485  *                          runnable actions)
1486  * \param[in]     type      Group of enum pe_ordering flags to apply
1487  * \param[in,out] data_set  Cluster working set
1488  *
1489  * \return Group of enum pcmk__updated flags indicating what was updated
1490  */
1491 uint32_t
1492 pcmk__instance_update_ordered_actions(pe_action_t *first, pe_action_t *then,
     /* [previous][next][first][last][top][bottom][index][help] */
1493                                       const pe_node_t *node, uint32_t flags,
1494                                       uint32_t filter, uint32_t type,
1495                                       pe_working_set_t *data_set)
1496 {
1497     if (then->rsc == NULL) {
1498         return pcmk__updated_none;
1499 
1500     } else if (can_interleave_actions(first, then)) {
1501         return update_interleaved_actions(first, then, node, filter, type);
1502 
1503     } else {
1504         uint32_t changed = pcmk__updated_none;
1505         GList *instances = get_instance_list(then->rsc);
1506 
1507         // Update actions for the clone or bundle resource itself
1508         changed |= pcmk__update_ordered_actions(first, then, node, flags,
1509                                                 filter, type, data_set);
1510 
1511         // Update the 'then' clone instances or bundle containers individually
1512         for (GList *iter = instances; iter != NULL; iter = iter->next) {
1513             pe_resource_t *instance = iter->data;
1514 
1515             changed |= update_noninterleaved_actions(instance, first, then,
1516                                                      node, flags, filter, type);
1517         }
1518         free_instance_list(then->rsc, instances);
1519         return changed;
1520     }
1521 }
1522 
1523 #define pe__clear_action_summary_flags(flags, action, flag) do {        \
1524         flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE,     \
1525                                      "Action summary", action->rsc->id, \
1526                                      flags, flag, #flag);               \
1527     } while (0)
1528 
1529 /*!
1530  * \internal
1531  * \brief Return action flags for a given clone or bundle action
1532  *
1533  * \param[in,out] action     Action for a clone or bundle
1534  * \param[in]     instances  Clone instances or bundle containers
1535  * \param[in]     node       If not NULL, limit effects to this node
1536  *
1537  * \return Flags appropriate to \p action on \p node
1538  */
1539 enum pe_action_flags
1540 pcmk__collective_action_flags(pe_action_t *action, const GList *instances,
     /* [previous][next][first][last][top][bottom][index][help] */
1541                               const pe_node_t *node)
1542 {
1543     bool any_runnable = false;
1544     enum pe_action_flags flags;
1545     const char *action_name = orig_action_name(action);
1546 
1547     // Set original assumptions (optional and runnable may be cleared below)
1548     flags = pe_action_optional|pe_action_runnable|pe_action_pseudo;
1549 
1550     for (const GList *iter = instances; iter != NULL; iter = iter->next) {
1551         const pe_resource_t *instance = iter->data;
1552         const pe_node_t *instance_node = NULL;
1553         pe_action_t *instance_action = NULL;
1554         enum pe_action_flags instance_flags;
1555 
1556         // Node is relevant only to primitive instances
1557         if (instance->variant == pe_native) {
1558             instance_node = node;
1559         }
1560 
1561         instance_action = find_first_action(instance->actions, NULL,
1562                                             action_name, instance_node);
1563         if (instance_action == NULL) {
1564             pe_rsc_trace(action->rsc, "%s has no %s action on %s",
1565                          instance->id, action_name, pe__node_name(node));
1566             continue;
1567         }
1568 
1569         pe_rsc_trace(action->rsc, "%s has %s for %s on %s",
1570                      instance->id, instance_action->uuid, action_name,
1571                      pe__node_name(node));
1572 
1573         instance_flags = instance->cmds->action_flags(instance_action, node);
1574 
1575         // If any instance action is mandatory, so is the collective action
1576         if (pcmk_is_set(flags, pe_action_optional)
1577             && !pcmk_is_set(instance_flags, pe_action_optional)) {
1578             pe_rsc_trace(instance, "%s is mandatory because %s is",
1579                          action->uuid, instance_action->uuid);
1580             pe__clear_action_summary_flags(flags, action, pe_action_optional);
1581             pe__clear_action_flags(action, pe_action_optional);
1582         }
1583 
1584         // If any instance action is runnable, so is the collective action
1585         if (pcmk_is_set(instance_flags, pe_action_runnable)) {
1586             any_runnable = true;
1587         }
1588     }
1589 
1590     if (!any_runnable) {
1591         pe_rsc_trace(action->rsc,
1592                      "%s is not runnable because no instance can run %s",
1593                      action->uuid, action_name);
1594         pe__clear_action_summary_flags(flags, action, pe_action_runnable);
1595         if (node == NULL) {
1596             pe__clear_action_flags(action, pe_action_runnable);
1597         }
1598     }
1599 
1600     return flags;
1601 }
1602 
1603 /*!
1604  * \internal
1605  * \brief Add a collective resource's colocations to a list for an instance
1606  *
1607  * \param[in,out] list        Colocation list to add to
1608  * \param[in]     instance    Clone or bundle instance or instance group member
1609  * \param[in]     collective  Clone or bundle resource with colocations to add
1610  * \param[in]     with_this   If true, add collective's "with this" colocations,
1611  *                            otherwise add its "this with" colocations
1612  */
1613 void
1614 pcmk__add_collective_constraints(GList **list, const pe_resource_t *instance,
     /* [previous][next][first][last][top][bottom][index][help] */
1615                                  const pe_resource_t *collective,
1616                                  bool with_this)
1617 {
1618     const GList *colocations = NULL;
1619     bool everywhere = false;
1620 
1621     CRM_CHECK((list != NULL) && (instance != NULL), return);
1622 
1623     if (collective == NULL) {
1624         return;
1625     }
1626     switch (collective->variant) {
1627         case pe_clone:
1628         case pe_container:
1629             break;
1630         default:
1631             return;
1632     }
1633 
1634     everywhere = can_run_everywhere(collective);
1635 
1636     if (with_this) {
1637         colocations = collective->rsc_cons_lhs;
1638     } else {
1639         colocations = collective->rsc_cons;
1640     }
1641 
1642     for (const GList *iter = colocations; iter != NULL; iter = iter->next) {
1643         const pcmk__colocation_t *colocation = iter->data;
1644 
1645         if (with_this
1646             && !pcmk__colocation_has_influence(colocation, instance)) {
1647            continue;
1648         }
1649         if (!everywhere || (colocation->score < 0)
1650             || (!with_this && (colocation->score == INFINITY))) {
1651 
1652             if (with_this) {
1653                 pcmk__add_with_this(list, colocation);
1654             } else {
1655                 pcmk__add_this_with(list, colocation);
1656             }
1657         }
1658     }
1659 }

/* [previous][next][first][last][top][bottom][index][help] */