1    	/*
2    	 * Copyright 2004-2025 the Pacemaker project contributors
3    	 *
4    	 * The version control history for this file may have further details.
5    	 *
6    	 * This source code is licensed under the GNU General Public License version 2
7    	 * or later (GPLv2+) WITHOUT ANY WARRANTY.
8    	 */
9    	
10   	#include <crm_internal.h>
11   	
12   	#include <stdbool.h>
13   	
14   	#include <libxml/tree.h>            // xmlNode
15   	
16   	#include <crm/common/xml.h>
17   	#include <pacemaker-internal.h>
18   	
19   	#include "libpacemaker_private.h"
20   	
21   	struct assign_data {
22   	    const pcmk_node_t *prefer;
23   	    bool stop_if_fail;
24   	};
25   	
26   	/*!
27   	 * \internal
28   	 * \brief Assign a single bundle replica's resources (other than container)
29   	 *
30   	 * \param[in,out] replica    Replica to assign
31   	 * \param[in]     user_data  Preferred node, if any
32   	 *
33   	 * \return true (to indicate that any further replicas should be processed)
34   	 */
35   	static bool
36   	assign_replica(pcmk__bundle_replica_t *replica, void *user_data)
37   	{
38   	    pcmk_node_t *container_host = NULL;
39   	
40   	    struct assign_data *assign_data = user_data;
41   	    const pcmk_node_t *prefer = assign_data->prefer;
42   	    bool stop_if_fail = assign_data->stop_if_fail;
43   	
44   	    const pcmk_resource_t *bundle = pe__const_top_resource(replica->container,
45   	                                                           true);
46   	
47   	    if (replica->ip != NULL) {
48   	        pcmk__rsc_trace(bundle, "Assigning bundle %s IP %s",
49   	                        bundle->id, replica->ip->id);
50   	        replica->ip->priv->cmds->assign(replica->ip, prefer, stop_if_fail);
51   	    }
52   	
53   	    container_host = replica->container->priv->assigned_node;
54   	    if (replica->remote != NULL) {
55   	        if (pcmk__is_pacemaker_remote_node(container_host)) {
56   	            /* REMOTE_CONTAINER_HACK: "Nested" connection resources must be on
57   	             * the same host because Pacemaker Remote only supports a single
58   	             * active connection.
59   	             */
60   	            pcmk__new_colocation("#replica-remote-with-host-remote", NULL,
61   	                                 PCMK_SCORE_INFINITY, replica->remote,
62   	                                 container_host->priv->remote, NULL,
63   	                                 NULL, pcmk__coloc_influence);
64   	        }
65   	        pcmk__rsc_trace(bundle, "Assigning bundle %s connection %s",
66   	                        bundle->id, replica->remote->id);
67   	        replica->remote->priv->cmds->assign(replica->remote, prefer,
68   	                                            stop_if_fail);
69   	    }
70   	
(50) Event example_checked: Example 1: "replica->child" has its value checked in "replica->child != NULL".
Also see events: [null_field][dereference][example_checked][example_checked][example_checked][example_checked]
71   	    if (replica->child != NULL) {
72   	        pcmk_node_t *node = NULL;
73   	        GHashTableIter iter;
74   	
75   	        g_hash_table_iter_init(&iter, replica->child->priv->allowed_nodes);
76   	        while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) {
77   	            if (!pcmk__same_node(node, replica->node)) {
78   	                node->assign->score = -PCMK_SCORE_INFINITY;
79   	            } else if (!pcmk__threshold_reached(replica->child, node, NULL)) {
80   	                node->assign->score = PCMK_SCORE_INFINITY;
81   	            }
82   	        }
83   	
84   	        pcmk__set_rsc_flags(replica->child->priv->parent,
85   	                            pcmk__rsc_assigning);
86   	        pcmk__rsc_trace(bundle, "Assigning bundle %s replica child %s",
87   	                        bundle->id, replica->child->id);
88   	        replica->child->priv->cmds->assign(replica->child, replica->node,
89   	                                           stop_if_fail);
90   	        pcmk__clear_rsc_flags(replica->child->priv->parent,
91   	                              pcmk__rsc_assigning);
92   	    }
93   	    return true;
94   	}
95   	
96   	/*!
97   	 * \internal
98   	 * \brief Assign a bundle resource to a node
99   	 *
100  	 * \param[in,out] rsc           Resource to assign to a node
101  	 * \param[in]     prefer        Node to prefer, if all else is equal
102  	 * \param[in]     stop_if_fail  If \c true and a primitive descendant of \p rsc
103  	 *                              can't be assigned to a node, set the
104  	 *                              descendant's next role to stopped and update
105  	 *                              existing actions
106  	 *
107  	 * \return Node that \p rsc is assigned to, if assigned entirely to one node
108  	 *
109  	 * \note If \p stop_if_fail is \c false, then \c pcmk__unassign_resource() can
110  	 *       completely undo the assignment. A successful assignment can be either
111  	 *       undone or left alone as final. A failed assignment has the same effect
112  	 *       as calling pcmk__unassign_resource(); there are no side effects on
113  	 *       roles or actions.
114  	 */
115  	pcmk_node_t *
116  	pcmk__bundle_assign(pcmk_resource_t *rsc, const pcmk_node_t *prefer,
117  	                    bool stop_if_fail)
118  	{
119  	    GList *containers = NULL;
120  	    pcmk_resource_t *bundled_resource = NULL;
121  	    struct assign_data assign_data = { prefer, stop_if_fail };
122  	
123  	    pcmk__assert(pcmk__is_bundle(rsc));
124  	
125  	    pcmk__rsc_trace(rsc, "Assigning bundle %s", rsc->id);
126  	    pcmk__set_rsc_flags(rsc, pcmk__rsc_assigning);
127  	
128  	    pe__show_node_scores(!pcmk__is_set(rsc->priv->scheduler->flags,
129  	                                       pcmk__sched_output_scores),
130  	                         rsc, __func__, rsc->priv->allowed_nodes,
131  	                         rsc->priv->scheduler);
132  	
133  	    // Assign all containers first, so we know what nodes the bundle will be on
134  	    containers = g_list_sort(pe__bundle_containers(rsc), pcmk__cmp_instance);
135  	    pcmk__assign_instances(rsc, containers, pe__bundle_max(rsc),
136  	                           rsc->priv->fns->max_per_node(rsc));
137  	    g_list_free(containers);
138  	
139  	    // Then assign remaining replica resources
140  	    pe__foreach_bundle_replica(rsc, assign_replica, (void *) &assign_data);
141  	
142  	    // Finally, assign the bundled resources to each bundle node
143  	    bundled_resource = pe__bundled_resource(rsc);
144  	    if (bundled_resource != NULL) {
145  	        pcmk_node_t *node = NULL;
146  	        GHashTableIter iter;
147  	
148  	        g_hash_table_iter_init(&iter, bundled_resource->priv->allowed_nodes);
149  	        while (g_hash_table_iter_next(&iter, NULL, (gpointer *) & node)) {
150  	            if (pe__node_is_bundle_instance(rsc, node)) {
151  	                node->assign->score = 0;
152  	            } else {
153  	                node->assign->score = -PCMK_SCORE_INFINITY;
154  	            }
155  	        }
156  	        bundled_resource->priv->cmds->assign(bundled_resource, prefer,
157  	                                                stop_if_fail);
158  	    }
159  	
160  	    pcmk__clear_rsc_flags(rsc, pcmk__rsc_assigning|pcmk__rsc_unassigned);
161  	    return NULL;
162  	}
163  	
164  	/*!
165  	 * \internal
166  	 * \brief Create actions for a bundle replica's resources (other than child)
167  	 *
168  	 * \param[in,out] replica    Replica to create actions for
169  	 * \param[in]     user_data  Unused
170  	 *
171  	 * \return true (to indicate that any further replicas should be processed)
172  	 */
173  	static bool
174  	create_replica_actions(pcmk__bundle_replica_t *replica, void *user_data)
175  	{
176  	    if (replica->ip != NULL) {
177  	        replica->ip->priv->cmds->create_actions(replica->ip);
178  	    }
179  	    if (replica->container != NULL) {
180  	        replica->container->priv->cmds->create_actions(replica->container);
181  	    }
182  	    if (replica->remote != NULL) {
183  	        replica->remote->priv->cmds->create_actions(replica->remote);
184  	    }
185  	    return true;
186  	}
187  	
188  	/*!
189  	 * \internal
190  	 * \brief Create all actions needed for a given bundle resource
191  	 *
192  	 * \param[in,out] rsc  Bundle resource to create actions for
193  	 */
194  	void
195  	pcmk__bundle_create_actions(pcmk_resource_t *rsc)
196  	{
197  	    pcmk_action_t *action = NULL;
198  	    GList *containers = NULL;
199  	    pcmk_resource_t *bundled_resource = NULL;
200  	
201  	    pcmk__assert(pcmk__is_bundle(rsc));
202  	
203  	    pe__foreach_bundle_replica(rsc, create_replica_actions, NULL);
204  	
205  	    containers = pe__bundle_containers(rsc);
206  	    pcmk__create_instance_actions(rsc, containers);
207  	    g_list_free(containers);
208  	
209  	    bundled_resource = pe__bundled_resource(rsc);
210  	    if (bundled_resource != NULL) {
211  	        bundled_resource->priv->cmds->create_actions(bundled_resource);
212  	
213  	        if (pcmk__is_set(bundled_resource->flags, pcmk__rsc_promotable)) {
214  	            pe__new_rsc_pseudo_action(rsc, PCMK_ACTION_PROMOTE, true, true);
215  	            action = pe__new_rsc_pseudo_action(rsc, PCMK_ACTION_PROMOTED,
216  	                                               true, true);
217  	            action->priority = PCMK_SCORE_INFINITY;
218  	
219  	            pe__new_rsc_pseudo_action(rsc, PCMK_ACTION_DEMOTE, true, true);
220  	            action = pe__new_rsc_pseudo_action(rsc, PCMK_ACTION_DEMOTED,
221  	                                               true, true);
222  	            action->priority = PCMK_SCORE_INFINITY;
223  	        }
224  	    }
225  	}
226  	
227  	/*!
228  	 * \internal
229  	 * \brief Create internal constraints for a bundle replica's resources
230  	 *
231  	 * \param[in,out] replica    Replica to create internal constraints for
232  	 * \param[in,out] user_data  Replica's parent bundle
233  	 *
234  	 * \return true (to indicate that any further replicas should be processed)
235  	 */
236  	static bool
237  	replica_internal_constraints(pcmk__bundle_replica_t *replica, void *user_data)
238  	{
239  	    pcmk_resource_t *bundle = user_data;
240  	
241  	    replica->container->priv->cmds->internal_constraints(replica->container);
242  	
243  	    // Start bundle -> start replica container
244  	    pcmk__order_starts(bundle, replica->container,
245  	                       pcmk__ar_unrunnable_first_blocks
246  	                       |pcmk__ar_then_implies_first_graphed);
247  	
248  	    // Stop bundle -> stop replica child and container
(53) Event example_checked: Example 4: "replica->child" has its value checked in "replica->child != NULL".
Also see events: [null_field][dereference][example_checked][example_checked][example_checked][example_checked]
249  	    if (replica->child != NULL) {
250  	        pcmk__order_stops(bundle, replica->child,
251  	                          pcmk__ar_then_implies_first_graphed);
252  	    }
253  	    pcmk__order_stops(bundle, replica->container,
254  	                      pcmk__ar_then_implies_first_graphed);
255  	
256  	    // Start replica container -> bundle is started
257  	    pcmk__order_resource_actions(replica->container, PCMK_ACTION_START, bundle,
258  	                                 PCMK_ACTION_RUNNING,
259  	                                 pcmk__ar_first_implies_then_graphed);
260  	
261  	    // Stop replica container -> bundle is stopped
262  	    pcmk__order_resource_actions(replica->container, PCMK_ACTION_STOP, bundle,
263  	                                 PCMK_ACTION_STOPPED,
264  	                                 pcmk__ar_first_implies_then_graphed);
265  	
266  	    if (replica->ip != NULL) {
267  	        replica->ip->priv->cmds->internal_constraints(replica->ip);
268  	
269  	        // Replica IP address -> replica container (symmetric)
270  	        pcmk__order_starts(replica->ip, replica->container,
271  	                           pcmk__ar_unrunnable_first_blocks
272  	                           |pcmk__ar_guest_allowed);
273  	        pcmk__order_stops(replica->container, replica->ip,
274  	                          pcmk__ar_then_implies_first|pcmk__ar_guest_allowed);
275  	
276  	        pcmk__new_colocation("#ip-with-container", NULL, PCMK_SCORE_INFINITY,
277  	                             replica->ip, replica->container, NULL, NULL,
278  	                             pcmk__coloc_influence);
279  	    }
280  	
281  	    if (replica->remote != NULL) {
282  	        /* This handles ordering and colocating remote relative to container
283  	         * (via "#resource-with-container"). Since IP is also ordered and
284  	         * colocated relative to the container, we don't need to do anything
285  	         * explicit here with IP.
286  	         */
287  	        replica->remote->priv->cmds->internal_constraints(replica->remote);
288  	    }
289  	
(54) Event example_checked: Example 5: "replica->child" has its value checked in "replica->child != NULL".
Also see events: [null_field][dereference][example_checked][example_checked][example_checked][example_checked]
290  	    if (replica->child != NULL) {
291  	        pcmk__assert(replica->remote != NULL);
292  	        // "Start remote then child" is implicit in scheduler's remote logic
293  	    }
294  	    return true;
295  	}
296  	
297  	/*!
298  	 * \internal
299  	 * \brief Create implicit constraints needed for a bundle resource
300  	 *
301  	 * \param[in,out] rsc  Bundle resource to create implicit constraints for
302  	 */
303  	void
304  	pcmk__bundle_internal_constraints(pcmk_resource_t *rsc)
305  	{
306  	    pcmk_resource_t *bundled_resource = NULL;
307  	
308  	    pcmk__assert(pcmk__is_bundle(rsc));
309  	
310  	    pe__foreach_bundle_replica(rsc, replica_internal_constraints, rsc);
311  	
312  	    bundled_resource = pe__bundled_resource(rsc);
313  	    if (bundled_resource == NULL) {
314  	        return;
315  	    }
316  	
317  	    // Start bundle -> start bundled clone
318  	    pcmk__order_resource_actions(rsc, PCMK_ACTION_START, bundled_resource,
319  	                                 PCMK_ACTION_START,
320  	                                 pcmk__ar_then_implies_first_graphed);
321  	
322  	    // Bundled clone is started -> bundle is started
323  	    pcmk__order_resource_actions(bundled_resource, PCMK_ACTION_RUNNING,
324  	                                 rsc, PCMK_ACTION_RUNNING,
325  	                                 pcmk__ar_first_implies_then_graphed);
326  	
327  	    // Stop bundle -> stop bundled clone
328  	    pcmk__order_resource_actions(rsc, PCMK_ACTION_STOP, bundled_resource,
329  	                                 PCMK_ACTION_STOP,
330  	                                 pcmk__ar_then_implies_first_graphed);
331  	
332  	    // Bundled clone is stopped -> bundle is stopped
333  	    pcmk__order_resource_actions(bundled_resource, PCMK_ACTION_STOPPED,
334  	                                 rsc, PCMK_ACTION_STOPPED,
335  	                                 pcmk__ar_first_implies_then_graphed);
336  	
337  	    bundled_resource->priv->cmds->internal_constraints(bundled_resource);
338  	
339  	    if (!pcmk__is_set(bundled_resource->flags, pcmk__rsc_promotable)) {
340  	        return;
341  	    }
342  	    pcmk__promotable_restart_ordering(rsc);
343  	
344  	    // Demote bundle -> demote bundled clone
345  	    pcmk__order_resource_actions(rsc, PCMK_ACTION_DEMOTE, bundled_resource,
346  	                                 PCMK_ACTION_DEMOTE,
347  	                                 pcmk__ar_then_implies_first_graphed);
348  	
349  	    // Bundled clone is demoted -> bundle is demoted
350  	    pcmk__order_resource_actions(bundled_resource, PCMK_ACTION_DEMOTED,
351  	                                 rsc, PCMK_ACTION_DEMOTED,
352  	                                 pcmk__ar_first_implies_then_graphed);
353  	
354  	    // Promote bundle -> promote bundled clone
355  	    pcmk__order_resource_actions(rsc, PCMK_ACTION_PROMOTE,
356  	                                 bundled_resource, PCMK_ACTION_PROMOTE,
357  	                                 pcmk__ar_then_implies_first_graphed);
358  	
359  	    // Bundled clone is promoted -> bundle is promoted
360  	    pcmk__order_resource_actions(bundled_resource, PCMK_ACTION_PROMOTED,
361  	                                 rsc, PCMK_ACTION_PROMOTED,
362  	                                 pcmk__ar_first_implies_then_graphed);
363  	}
364  	
365  	struct match_data {
366  	    const pcmk_node_t *node;    // Node to compare against replica
367  	    pcmk_resource_t *container; // Replica container corresponding to node
368  	};
369  	
370  	/*!
371  	 * \internal
372  	 * \brief Check whether a replica container is assigned to a given node
373  	 *
374  	 * \param[in]     replica    Replica to check
375  	 * \param[in,out] user_data  struct match_data with node to compare against
376  	 *
377  	 * \return true if the replica does not match (to indicate further replicas
378  	 *         should be processed), otherwise false
379  	 */
380  	static bool
381  	match_replica_container(const pcmk__bundle_replica_t *replica, void *user_data)
382  	{
383  	    struct match_data *match_data = user_data;
384  	
385  	    if (pcmk__instance_matches(replica->container, match_data->node,
386  	                               pcmk_role_unknown, false, NULL)) {
387  	        match_data->container = replica->container;
388  	        return false; // Match found, don't bother searching further replicas
389  	    }
390  	    return true; // No match, keep searching
391  	}
392  	
393  	/*!
394  	 * \internal
395  	 * \brief Get the host to which a bundle node is assigned
396  	 *
397  	 * \param[in] node  Possible bundle node to check
398  	 *
399  	 * \return Node to which the container for \p node is assigned if \p node is a
400  	 *         bundle node, otherwise \p node itself
401  	 */
402  	static const pcmk_node_t *
403  	get_bundle_node_host(const pcmk_node_t *node)
404  	{
405  	    if (pcmk__is_bundle_node(node)) {
406  	        const pcmk_resource_t *container = NULL;
407  	
408  	        container = node->priv->remote->priv->launcher;
409  	        return container->priv->fns->location(container, NULL,
410  	                                              pcmk__rsc_node_assigned);
411  	    }
412  	    return node;
413  	}
414  	
415  	/*!
416  	 * \internal
417  	 * \brief Find a bundle container compatible with a dependent resource
418  	 *
419  	 * \param[in] dependent  Dependent resource in colocation with bundle
420  	 * \param[in] bundle     Bundle that \p dependent is colocated with
421  	 *
422  	 * \return A container from \p bundle assigned to the same node as \p dependent
423  	 *         if assigned, otherwise assigned to any of dependent's allowed nodes,
424  	 *         otherwise NULL.
425  	 */
426  	static pcmk_resource_t *
427  	compatible_container(const pcmk_resource_t *dependent,
428  	                     const pcmk_resource_t *bundle)
429  	{
430  	    GList *scratch = NULL;
431  	    struct match_data match_data = { NULL, NULL };
432  	
433  	    // If dependent is assigned, only check there
434  	    match_data.node = dependent->priv->fns->location(dependent, NULL,
435  	                                                     pcmk__rsc_node_assigned);
436  	    match_data.node = get_bundle_node_host(match_data.node);
437  	    if (match_data.node != NULL) {
438  	        pe__foreach_const_bundle_replica(bundle, match_replica_container,
439  	                                         &match_data);
440  	        return match_data.container;
441  	    }
442  	
443  	    // Otherwise, check for any of the dependent's allowed nodes
444  	    scratch = g_hash_table_get_values(dependent->priv->allowed_nodes);
445  	    scratch = pcmk__sort_nodes(scratch, NULL);
446  	    for (const GList *iter = scratch; iter != NULL; iter = iter->next) {
447  	        match_data.node = iter->data;
448  	        match_data.node = get_bundle_node_host(match_data.node);
449  	        if (match_data.node == NULL) {
450  	            continue;
451  	        }
452  	
453  	        pe__foreach_const_bundle_replica(bundle, match_replica_container,
454  	                                         &match_data);
455  	        if (match_data.container != NULL) {
456  	            break;
457  	        }
458  	    }
459  	    g_list_free(scratch);
460  	    return match_data.container;
461  	}
462  	
463  	struct coloc_data {
464  	    const pcmk__colocation_t *colocation;
465  	    pcmk_resource_t *dependent;
466  	    GList *container_hosts;
467  	    int priority_delta;
468  	};
469  	
470  	/*!
471  	 * \internal
472  	 * \brief Apply a colocation score to replica node scores or resource priority
473  	 *
474  	 * \param[in]     replica    Replica of primary bundle resource in colocation
475  	 * \param[in,out] user_data  struct coloc_data for colocation being applied
476  	 *
477  	 * \return true (to indicate that any further replicas should be processed)
478  	 */
479  	static bool
480  	replica_apply_coloc_score(const pcmk__bundle_replica_t *replica,
481  	                          void *user_data)
482  	{
483  	    struct coloc_data *coloc_data = user_data;
484  	    pcmk_node_t *chosen = NULL;
485  	    pcmk_resource_t *container = replica->container;
486  	
487  	    if (coloc_data->colocation->score < PCMK_SCORE_INFINITY) {
488  	        int priority_delta =
489  	            container->priv->cmds->apply_coloc_score(coloc_data->dependent,
490  	                                                     container,
491  	                                                     coloc_data->colocation,
492  	                                                     false);
493  	
494  	        coloc_data->priority_delta =
495  	            pcmk__add_scores(coloc_data->priority_delta, priority_delta);
496  	        return true;
497  	    }
498  	
499  	    chosen = container->priv->fns->location(container, NULL,
500  	                                            pcmk__rsc_node_assigned);
501  	    if ((chosen == NULL)
502  	        || is_set_recursive(container, pcmk__rsc_blocked, true)) {
503  	        return true;
504  	    }
505  	
(52) Event example_checked: Example 3: "replica->child" has its value checked in "replica->child == NULL".
Also see events: [null_field][dereference][example_checked][example_checked][example_checked][example_checked]
506  	    if ((coloc_data->colocation->primary_role >= pcmk_role_promoted)
507  	        && ((replica->child == NULL)
508  	            || (replica->child->priv->next_role < pcmk_role_promoted))) {
509  	        return true;
510  	    }
511  	
512  	    pcmk__rsc_trace(pe__const_top_resource(container, true),
513  	                    "Allowing mandatory colocation %s using %s @%d",
514  	                    coloc_data->colocation->id, pcmk__node_name(chosen),
515  	                    chosen->assign->score);
516  	    coloc_data->container_hosts = g_list_prepend(coloc_data->container_hosts,
517  	                                                 chosen);
518  	    return true;
519  	}
520  	
521  	/*!
522  	 * \internal
523  	 * \brief Apply a colocation's score to node scores or resource priority
524  	 *
525  	 * Given a colocation constraint, apply its score to the dependent's
526  	 * allowed node scores (if we are still placing resources) or priority (if
527  	 * we are choosing promotable clone instance roles).
528  	 *
529  	 * \param[in,out] dependent      Dependent resource in colocation
530  	 * \param[in]     primary        Primary resource in colocation
531  	 * \param[in]     colocation     Colocation constraint to apply
532  	 * \param[in]     for_dependent  true if called on behalf of dependent
533  	 *
534  	 * \return The score added to the dependent's priority
535  	 */
536  	int
537  	pcmk__bundle_apply_coloc_score(pcmk_resource_t *dependent,
538  	                               const pcmk_resource_t *primary,
539  	                               const pcmk__colocation_t *colocation,
540  	                               bool for_dependent)
541  	{
542  	    struct coloc_data coloc_data = { colocation, dependent, NULL, 0 };
543  	
544  	    /* This should never be called for the bundle itself as a dependent.
545  	     * Instead, we add its colocation constraints to its containers and bundled
546  	     * primitive and call the apply_coloc_score() method for them as dependents.
547  	     */
548  	    pcmk__assert(pcmk__is_bundle(primary) && pcmk__is_primitive(dependent)
549  	                 && (colocation != NULL) && !for_dependent);
550  	
551  	    if (pcmk__is_set(primary->flags, pcmk__rsc_unassigned)) {
552  	        pcmk__rsc_trace(primary,
553  	                        "Skipping applying colocation %s "
554  	                        "because %s is still provisional",
555  	                        colocation->id, primary->id);
556  	        return 0;
557  	    }
558  	    pcmk__rsc_trace(primary, "Applying colocation %s (%s with %s at %s)",
559  	                    colocation->id, dependent->id, primary->id,
560  	                    pcmk_readable_score(colocation->score));
561  	
562  	    /* If the constraint dependent is a clone or bundle, "dependent" here is one
563  	     * of its instances. Look for a compatible instance of this bundle.
564  	     */
565  	    if (colocation->dependent->priv->variant > pcmk__rsc_variant_group) {
566  	        const pcmk_resource_t *primary_container = NULL;
567  	
568  	        primary_container = compatible_container(dependent, primary);
569  	        if (primary_container != NULL) { // Success, we found one
570  	            pcmk__rsc_debug(primary, "Pairing %s with %s",
571  	                            dependent->id, primary_container->id);
572  	
573  	            return dependent->priv->cmds->apply_coloc_score(dependent,
574  	                                                            primary_container,
575  	                                                            colocation, true);
576  	        }
577  	
578  	        if (colocation->score >= PCMK_SCORE_INFINITY) {
579  	            // Failure, and it's fatal
580  	            pcmk__notice("%s cannot run because there is no compatible "
581  	                         "instance of %s to colocate with",
582  	                         dependent->id, primary->id);
583  	            pcmk__assign_resource(dependent, NULL, true, true);
584  	
585  	        } else { // Failure, but we can ignore it
586  	            pcmk__rsc_debug(primary,
587  	                            "%s cannot be colocated with any instance of %s",
588  	                            dependent->id, primary->id);
589  	        }
590  	        return 0;
591  	    }
592  	
593  	    pe__foreach_const_bundle_replica(primary, replica_apply_coloc_score,
594  	                                     &coloc_data);
595  	
596  	    if (colocation->score >= PCMK_SCORE_INFINITY) {
597  	        pcmk__colocation_intersect_nodes(dependent, primary, colocation,
598  	                                         coloc_data.container_hosts, false);
599  	    }
600  	    g_list_free(coloc_data.container_hosts);
601  	    return coloc_data.priority_delta;
602  	}
603  	
604  	// Bundle implementation of pcmk__assignment_methods_t:with_this_colocations()
605  	void
606  	pcmk__with_bundle_colocations(const pcmk_resource_t *rsc,
607  	                              const pcmk_resource_t *orig_rsc, GList **list)
608  	{
609  	    const pcmk_resource_t *bundled_rsc = NULL;
610  	
611  	    pcmk__assert(pcmk__is_bundle(rsc) && (orig_rsc != NULL) && (list != NULL));
612  	
613  	    // The bundle itself and its containers always get its colocations
614  	    if ((orig_rsc == rsc)
615  	        || pcmk__is_set(orig_rsc->flags, pcmk__rsc_replica_container)) {
616  	
617  	        pcmk__add_with_this_list(list, rsc->priv->with_this_colocations,
618  	                                 orig_rsc);
619  	        return;
620  	    }
621  	
622  	    /* The bundled resource gets the colocations if it's promotable and we've
623  	     * begun choosing roles
624  	     */
625  	    bundled_rsc = pe__bundled_resource(rsc);
626  	    if ((bundled_rsc == NULL)
627  	        || !pcmk__is_set(bundled_rsc->flags, pcmk__rsc_promotable)
628  	        || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
629  	        return;
630  	    }
631  	
632  	    if (orig_rsc == bundled_rsc) {
633  	        if (pe__clone_flag_is_set(orig_rsc,
634  	                                  pcmk__clone_promotion_constrained)) {
635  	            /* orig_rsc is the clone and we're setting roles (or have already
636  	             * done so)
637  	             */
638  	            pcmk__add_with_this_list(list, rsc->priv->with_this_colocations,
639  	                                     orig_rsc);
640  	        }
641  	
642  	    } else if (!pcmk__is_set(orig_rsc->flags, pcmk__rsc_unassigned)) {
643  	        /* orig_rsc is an instance and is already assigned. If something
644  	         * requests colocations for orig_rsc now, it's for setting roles.
645  	         */
646  	        pcmk__add_with_this_list(list, rsc->priv->with_this_colocations,
647  	                                 orig_rsc);
648  	    }
649  	}
650  	
651  	// Bundle implementation of pcmk__assignment_methods_t:this_with_colocations()
652  	void
653  	pcmk__bundle_with_colocations(const pcmk_resource_t *rsc,
654  	                              const pcmk_resource_t *orig_rsc, GList **list)
655  	{
656  	    const pcmk_resource_t *bundled_rsc = NULL;
657  	
658  	    pcmk__assert(pcmk__is_bundle(rsc) && (orig_rsc != NULL) && (list != NULL));
659  	
660  	    // The bundle itself and its containers always get its colocations
661  	    if ((orig_rsc == rsc)
662  	        || pcmk__is_set(orig_rsc->flags, pcmk__rsc_replica_container)) {
663  	
664  	        pcmk__add_this_with_list(list, rsc->priv->this_with_colocations,
665  	                                 orig_rsc);
666  	        return;
667  	    }
668  	
669  	    /* The bundled resource gets the colocations if it's promotable and we've
670  	     * begun choosing roles
671  	     */
672  	    bundled_rsc = pe__bundled_resource(rsc);
673  	    if ((bundled_rsc == NULL)
674  	        || !pcmk__is_set(bundled_rsc->flags, pcmk__rsc_promotable)
675  	        || (pe__const_top_resource(orig_rsc, false) != bundled_rsc)) {
676  	        return;
677  	    }
678  	
679  	    if (orig_rsc == bundled_rsc) {
680  	        if (pe__clone_flag_is_set(orig_rsc,
681  	                                  pcmk__clone_promotion_constrained)) {
682  	            /* orig_rsc is the clone and we're setting roles (or have already
683  	             * done so)
684  	             */
685  	            pcmk__add_this_with_list(list, rsc->priv->this_with_colocations,
686  	                                     orig_rsc);
687  	        }
688  	
689  	    } else if (!pcmk__is_set(orig_rsc->flags, pcmk__rsc_unassigned)) {
690  	        /* orig_rsc is an instance and is already assigned. If something
691  	         * requests colocations for orig_rsc now, it's for setting roles.
692  	         */
693  	        pcmk__add_this_with_list(list, rsc->priv->this_with_colocations,
694  	                                 orig_rsc);
695  	    }
696  	}
697  	
698  	/*!
699  	 * \internal
700  	 * \brief Return action flags for a given bundle resource action
701  	 *
702  	 * \param[in,out] action  Bundle resource action to get flags for
703  	 * \param[in]     node    If not NULL, limit effects to this node
704  	 *
705  	 * \return Flags appropriate to \p action on \p node
706  	 */
707  	uint32_t
708  	pcmk__bundle_action_flags(pcmk_action_t *action, const pcmk_node_t *node)
709  	{
710  	    GList *containers = NULL;
711  	    uint32_t flags = 0;
712  	    pcmk_resource_t *bundled_resource = NULL;
713  	
714  	    pcmk__assert((action != NULL) && pcmk__is_bundle(action->rsc));
715  	
716  	    bundled_resource = pe__bundled_resource(action->rsc);
717  	    if (bundled_resource != NULL) {
718  	        GList *children = bundled_resource->priv->children;
719  	
720  	        // Clone actions are done on the bundled clone resource, not container
721  	        switch (get_complex_task(bundled_resource, action->task)) {
722  	            case pcmk__action_unspecified:
723  	            case pcmk__action_notify:
724  	            case pcmk__action_notified:
725  	            case pcmk__action_promote:
726  	            case pcmk__action_promoted:
727  	            case pcmk__action_demote:
728  	            case pcmk__action_demoted:
729  	                return pcmk__collective_action_flags(action, children, node);
730  	            default:
731  	                break;
732  	        }
733  	    }
734  	
735  	    containers = pe__bundle_containers(action->rsc);
736  	    flags = pcmk__collective_action_flags(action, containers, node);
737  	    g_list_free(containers);
738  	    return flags;
739  	}
740  	
741  	/*!
742  	 * \internal
743  	 * \brief Apply a location constraint to a bundle replica
744  	 *
745  	 * \param[in,out] replica    Replica to apply constraint to
746  	 * \param[in,out] user_data  Location constraint to apply
747  	 *
748  	 * \return true (to indicate that any further replicas should be processed)
749  	 */
750  	static bool
751  	apply_location_to_replica(pcmk__bundle_replica_t *replica, void *user_data)
752  	{
753  	    pcmk__location_t *location = user_data;
754  	
755  	    replica->container->priv->cmds->apply_location(replica->container,
756  	                                                   location);
757  	    if (replica->ip != NULL) {
758  	        replica->ip->priv->cmds->apply_location(replica->ip, location);
759  	    }
760  	    return true;
761  	}
762  	
763  	/*!
764  	 * \internal
765  	 * \brief Apply a location constraint to a bundle resource's allowed node scores
766  	 *
767  	 * \param[in,out] rsc       Bundle resource to apply constraint to
768  	 * \param[in,out] location  Location constraint to apply
769  	 */
770  	void
771  	pcmk__bundle_apply_location(pcmk_resource_t *rsc, pcmk__location_t *location)
772  	{
773  	    pcmk_resource_t *bundled_resource = NULL;
774  	
775  	    pcmk__assert((location != NULL) && pcmk__is_bundle(rsc));
776  	
777  	    pcmk__apply_location(rsc, location);
778  	    pe__foreach_bundle_replica(rsc, apply_location_to_replica, location);
779  	
780  	    bundled_resource = pe__bundled_resource(rsc);
781  	    if ((bundled_resource != NULL)
782  	        && ((location->role_filter == pcmk_role_unpromoted)
783  	            || (location->role_filter == pcmk_role_promoted))) {
784  	
785  	        bundled_resource->priv->cmds->apply_location(bundled_resource,
786  	                                                     location);
787  	        bundled_resource->priv->location_constraints =
788  	            g_list_prepend(bundled_resource->priv->location_constraints,
789  	                           location);
790  	    }
791  	}
792  	
793  	#define XPATH_REMOTE "//nvpair[@name='" PCMK_REMOTE_RA_ADDR "']"
794  	
795  	/*!
796  	 * \internal
797  	 * \brief Add a bundle replica's actions to transition graph
798  	 *
799  	 * \param[in,out] replica    Replica to add to graph
800  	 * \param[in]     user_data  Bundle that replica belongs to (for logging only)
801  	 *
802  	 * \return true (to indicate that any further replicas should be processed)
803  	 */
804  	static bool
805  	add_replica_actions_to_graph(pcmk__bundle_replica_t *replica, void *user_data)
806  	{
807  	    if ((replica->remote != NULL)
808  	        && pe__bundle_needs_remote_name(replica->remote)) {
809  	
810  	        /* REMOTE_CONTAINER_HACK: Allow remote nodes to run containers that
811  	         * run the remote executor inside, without needing a separate IP for
812  	         * the container. This is done by configuring the inner remote's
813  	         * connection host as the magic string "#uname", then
814  	         * replacing it with the underlying host when needed.
815  	         */
816  	        xmlNode *nvpair = pcmk__xpath_find_one(replica->remote->priv->xml->doc,
817  	                                               XPATH_REMOTE, LOG_ERR);
818  	        const char *calculated_addr = NULL;
819  	
820  	        // Replace the value in replica->remote->xml (if appropriate)
821  	        calculated_addr = pe__add_bundle_remote_name(replica->remote, nvpair,
822  	                                                     PCMK_XA_VALUE);
823  	        if (calculated_addr != NULL) {
824  	            /* Since this is for the bundle as a resource, and not any
825  	             * particular action, replace the value in the default
826  	             * parameters (not evaluated for node). create_graph_action()
827  	             * will grab it from there to replace it in node-evaluated
828  	             * parameters.
829  	             */
830  	            GHashTable *params = NULL;
831  	
832  	            params = pe_rsc_params(replica->remote, NULL,
833  	                                   replica->remote->priv->scheduler);
834  	            pcmk__insert_dup(params, PCMK_REMOTE_RA_ADDR, calculated_addr);
835  	        } else {
836  	            pcmk_resource_t *bundle = user_data;
837  	
838  	            /* The only way to get here is if the remote connection is
839  	             * neither currently running nor scheduled to run. That means we
840  	             * won't be doing any operations that require addr (only start
841  	             * requires it; we additionally use it to compare digests when
842  	             * unpacking status, promote, and migrate_from history, but
843  	             * that's already happened by this point).
844  	             */
845  	            pcmk__rsc_info(bundle,
846  	                           "Unable to determine address for bundle %s "
847  	                           "remote connection", bundle->id);
848  	        }
849  	    }
850  	    if (replica->ip != NULL) {
851  	        replica->ip->priv->cmds->add_actions_to_graph(replica->ip);
852  	    }
853  	    replica->container->priv->cmds->add_actions_to_graph(replica->container);
854  	    if (replica->remote != NULL) {
855  	        replica->remote->priv->cmds->add_actions_to_graph(replica->remote);
856  	    }
857  	    return true;
858  	}
859  	
860  	/*!
861  	 * \internal
862  	 * \brief Add a bundle resource's actions to the transition graph
863  	 *
864  	 * \param[in,out] rsc  Bundle resource whose actions should be added
865  	 */
866  	void
867  	pcmk__bundle_add_actions_to_graph(pcmk_resource_t *rsc)
868  	{
869  	    pcmk_resource_t *bundled_resource = NULL;
870  	
871  	    pcmk__assert(pcmk__is_bundle(rsc));
872  	
873  	    bundled_resource = pe__bundled_resource(rsc);
874  	    if (bundled_resource != NULL) {
875  	        bundled_resource->priv->cmds->add_actions_to_graph(bundled_resource);
876  	    }
877  	    pe__foreach_bundle_replica(rsc, add_replica_actions_to_graph, rsc);
878  	}
879  	
880  	struct probe_data {
881  	    pcmk_resource_t *bundle;    // Bundle being probed
882  	    pcmk_node_t *node;          // Node to create probes on
883  	    bool any_created;           // Whether any probes have been created
884  	};
885  	
886  	/*!
887  	 * \internal
888  	 * \brief Order a bundle replica's start after another replica's probe
889  	 *
890  	 * \param[in,out] replica    Replica to order start for
891  	 * \param[in,out] user_data  Replica with probe to order after
892  	 *
893  	 * \return true (to indicate that any further replicas should be processed)
894  	 */
895  	static bool
896  	order_replica_start_after(pcmk__bundle_replica_t *replica, void *user_data)
897  	{
898  	    pcmk__bundle_replica_t *probed_replica = user_data;
899  	
900  	    if ((replica == probed_replica) || (replica->container == NULL)) {
901  	        return true;
902  	    }
903  	    pcmk__new_ordering(probed_replica->container,
904  	                       pcmk__op_key(probed_replica->container->id,
905  	                                    PCMK_ACTION_MONITOR, 0),
906  	                       NULL, replica->container,
907  	                       pcmk__op_key(replica->container->id, PCMK_ACTION_START,
908  	                                    0),
909  	                       NULL, pcmk__ar_ordered|pcmk__ar_if_on_same_node,
910  	                       replica->container->priv->scheduler);
911  	    return true;
912  	}
913  	
914  	/*!
915  	 * \internal
916  	 * \brief Create probes for a bundle replica's resources
917  	 *
918  	 * \param[in,out] replica    Replica to create probes for
919  	 * \param[in,out] user_data  struct probe_data
920  	 *
921  	 * \return true (to indicate that any further replicas should be processed)
922  	 */
923  	static bool
924  	create_replica_probes(pcmk__bundle_replica_t *replica, void *user_data)
925  	{
926  	    struct probe_data *probe_data = user_data;
927  	    pcmk_resource_t *bundle = probe_data->bundle;
928  	
929  	    /* This is guaranteed when constructing probe_data in pcmk__bundle_create_probe,
930  	     * but this makes static analysis happy.
931  	     */
932  	    pcmk__assert(bundle != NULL);
933  	
934  	    if ((replica->ip != NULL)
935  	        && replica->ip->priv->cmds->create_probe(replica->ip,
936  	                                                 probe_data->node)) {
937  	        probe_data->any_created = true;
938  	    }
(51) Event example_checked: Example 2: "replica->child" has its value checked in "replica->child != NULL".
Also see events: [null_field][dereference][example_checked][example_checked][example_checked][example_checked]
939  	    if ((replica->child != NULL)
940  	        && pcmk__same_node(probe_data->node, replica->node)
941  	        && replica->child->priv->cmds->create_probe(replica->child,
942  	                                                    probe_data->node)) {
943  	        probe_data->any_created = true;
944  	    }
945  	    if (replica->container->priv->cmds->create_probe(replica->container,
946  	                                                     probe_data->node)) {
947  	        probe_data->any_created = true;
948  	
949  	        /* If we're limited to one replica per host (due to
950  	         * the lack of an IP range probably), then we don't
951  	         * want any of our peer containers starting until
952  	         * we've established that no other copies are already
953  	         * running.
954  	         *
955  	         * Partly this is to ensure that the maximum replicas per host is
956  	         * observed, but also to ensure that the containers
957  	         * don't fail to start because the necessary port
958  	         * mappings (which won't include an IP for uniqueness)
959  	         * are already taken
960  	         */
961  	        if (bundle->priv->fns->max_per_node(bundle) == 1) {
962  	            pe__foreach_bundle_replica(bundle, order_replica_start_after,
963  	                                       replica);
964  	        }
965  	    }
966  	    if ((replica->remote != NULL)
967  	        && replica->remote->priv->cmds->create_probe(replica->remote,
968  	                                                     probe_data->node)) {
969  	        /* Do not probe the remote resource until we know where the container is
970  	         * running. This is required for REMOTE_CONTAINER_HACK to correctly
971  	         * probe remote resources.
972  	         */
973  	        char *probe_uuid = pcmk__op_key(replica->remote->id,
974  	                                        PCMK_ACTION_MONITOR, 0);
975  	        pcmk_action_t *probe = NULL;
976  	
977  	        probe = find_first_action(replica->remote->priv->actions, probe_uuid,
978  	                                  NULL, probe_data->node);
979  	        free(probe_uuid);
980  	        if (probe != NULL) {
981  	            probe_data->any_created = true;
982  	            pcmk__rsc_trace(bundle, "Ordering %s probe on %s",
983  	                            replica->remote->id,
984  	                            pcmk__node_name(probe_data->node));
985  	            pcmk__new_ordering(replica->container,
986  	                               pcmk__op_key(replica->container->id,
987  	                                            PCMK_ACTION_START, 0),
988  	                               NULL, replica->remote, NULL, probe,
989  	                               pcmk__ar_nested_remote_probe,
990  	                               bundle->priv->scheduler);
991  	        }
992  	    }
993  	    return true;
994  	}
995  	
996  	/*!
997  	 * \internal
998  	 *
999  	 * \brief Schedule any probes needed for a bundle resource on a node
1000 	 *
1001 	 * \param[in,out] rsc   Bundle resource to create probes for
1002 	 * \param[in,out] node  Node to create probe on
1003 	 *
1004 	 * \return true if any probe was created, otherwise false
1005 	 */
1006 	bool
1007 	pcmk__bundle_create_probe(pcmk_resource_t *rsc, pcmk_node_t *node)
1008 	{
1009 	    struct probe_data probe_data = { rsc, node, false };
1010 	
1011 	    pcmk__assert(pcmk__is_bundle(rsc));
1012 	    pe__foreach_bundle_replica(rsc, create_replica_probes, &probe_data);
1013 	    return probe_data.any_created;
1014 	}
1015 	
1016 	/*!
1017 	 * \internal
1018 	 * \brief Output actions for one bundle replica
1019 	 *
1020 	 * \param[in,out] replica    Replica to output actions for
1021 	 * \param[in]     user_data  Unused
1022 	 *
1023 	 * \return true (to indicate that any further replicas should be processed)
1024 	 */
1025 	static bool
1026 	output_replica_actions(pcmk__bundle_replica_t *replica, void *user_data)
1027 	{
1028 	    if (replica->ip != NULL) {
1029 	        replica->ip->priv->cmds->output_actions(replica->ip);
1030 	    }
1031 	    replica->container->priv->cmds->output_actions(replica->container);
1032 	    if (replica->remote != NULL) {
1033 	        replica->remote->priv->cmds->output_actions(replica->remote);
1034 	    }
1035 	    if (replica->child != NULL) {
1036 	        replica->child->priv->cmds->output_actions(replica->child);
1037 	    }
1038 	    return true;
1039 	}
1040 	
1041 	/*!
1042 	 * \internal
1043 	 * \brief Output a summary of scheduled actions for a bundle resource
1044 	 *
1045 	 * \param[in,out] rsc  Bundle resource to output actions for
1046 	 */
1047 	void
1048 	pcmk__output_bundle_actions(pcmk_resource_t *rsc)
1049 	{
1050 	    pcmk__assert(pcmk__is_bundle(rsc));
1051 	    pe__foreach_bundle_replica(rsc, output_replica_actions, NULL);
1052 	}
1053 	
1054 	// Bundle implementation of pcmk__assignment_methods_t:add_utilization()
1055 	void
1056 	pcmk__bundle_add_utilization(const pcmk_resource_t *rsc,
1057 	                             const pcmk_resource_t *orig_rsc, GList *all_rscs,
1058 	                             GHashTable *utilization)
1059 	{
1060 	    pcmk_resource_t *container = NULL;
1061 	
1062 	    pcmk__assert(pcmk__is_bundle(rsc));
1063 	
1064 	    if (!pcmk__is_set(rsc->flags, pcmk__rsc_unassigned)) {
1065 	        return;
1066 	    }
1067 	
1068 	    /* All bundle replicas are identical, so using the utilization of the first
1069 	     * is sufficient for any. Only the implicit container resource can have
1070 	     * utilization values.
1071 	     */
1072 	    container = pe__first_container(rsc);
1073 	    if (container != NULL) {
1074 	        container->priv->cmds->add_utilization(container, orig_rsc, all_rscs,
1075 	                                               utilization);
1076 	    }
1077 	}
1078 	
1079 	// Bundle implementation of pcmk__assignment_methods_t:shutdown_lock()
1080 	void
1081 	pcmk__bundle_shutdown_lock(pcmk_resource_t *rsc)
1082 	{
1083 	    pcmk__assert(pcmk__is_bundle(rsc));
1084 	    // Bundles currently don't support shutdown locks
1085 	}
1086