Line data Source code
1 : /*
2 : * Copyright 2011-2024 the Pacemaker project contributors
3 : *
4 : * The version control history for this file may have further details.
5 : *
6 : * This source code is licensed under the GNU Lesser General Public License
7 : * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 : */
9 :
10 : #ifndef _GNU_SOURCE
11 : # define _GNU_SOURCE
12 : #endif
13 :
14 : #include <crm_internal.h>
15 :
16 : #include <stdio.h>
17 :
18 : #include <crm/common/xml.h>
19 : #include <crm/common/scheduler.h>
20 : #include <crm/common/scheduler_internal.h>
21 :
22 : #define OCF_RESKEY_PREFIX "OCF_RESKEY_"
23 : #define LRM_TARGET_ENV OCF_RESKEY_PREFIX CRM_META "_" PCMK__META_ON_NODE
24 :
25 : /*!
26 : * \internal
27 : * \brief Get the node name that should be used to set node attributes
28 : *
29 : * If given NULL, "auto", or "localhost" as an argument, check the environment
30 : * to detect the node name that should be used to set node attributes. (The
31 : * caller might not know the correct name, for example if the target is part of
32 : * a bundle with \c PCMK_META_CONTAINER_ATTRIBUTE_TARGET set to
33 : * \c PCMK_VALUE_HOST.)
34 : *
35 : * \param[in] name NULL, "auto" or "localhost" to check environment variables,
36 : * or anything else to return NULL
37 : *
38 : * \return Node name that should be used for node attributes based on the
39 : * environment if known, otherwise NULL
40 : */
41 : const char *
42 0 : pcmk__node_attr_target(const char *name)
43 : {
44 0 : if (name == NULL || pcmk__strcase_any_of(name, "auto", "localhost", NULL)) {
45 0 : char buf[128] = OCF_RESKEY_PREFIX;
46 0 : size_t offset = sizeof(OCF_RESKEY_PREFIX) - 1;
47 0 : char *target_var = crm_meta_name(PCMK_META_CONTAINER_ATTRIBUTE_TARGET);
48 0 : char *phys_var = crm_meta_name(PCMK__META_PHYSICAL_HOST);
49 0 : const char *target = NULL;
50 0 : const char *host_physical = NULL;
51 :
52 0 : snprintf(buf + offset, sizeof(buf) - offset, "%s", target_var);
53 0 : target = getenv(buf);
54 :
55 0 : snprintf(buf + offset, sizeof(buf) - offset, "%s", phys_var);
56 0 : host_physical = getenv(buf);
57 :
58 : // It is important to use the name by which the scheduler knows us
59 0 : if (host_physical
60 0 : && pcmk__str_eq(target, PCMK_VALUE_HOST, pcmk__str_casei)) {
61 0 : name = host_physical;
62 :
63 : } else {
64 0 : const char *host_pcmk = getenv(LRM_TARGET_ENV);
65 :
66 0 : if (host_pcmk) {
67 0 : name = host_pcmk;
68 : }
69 : }
70 0 : free(target_var);
71 0 : free(phys_var);
72 :
73 : // TODO? Call pcmk__cluster_local_node_name() if name == NULL
74 : // (currently would require linkage against libcrmcluster)
75 0 : return name;
76 : } else {
77 0 : return NULL;
78 : }
79 : }
80 :
81 : /*!
82 : * \brief Return the name of the node attribute used as a promotion score
83 : *
84 : * \param[in] rsc_id Resource ID that promotion score is for (or NULL to
85 : * check the OCF_RESOURCE_INSTANCE environment variable)
86 : *
87 : * \return Newly allocated string with the node attribute name (or NULL on
88 : * error, including no ID or environment variable specified)
89 : * \note It is the caller's responsibility to free() the result.
90 : */
91 : char *
92 0 : pcmk_promotion_score_name(const char *rsc_id)
93 : {
94 0 : if (pcmk__str_empty(rsc_id)) {
95 0 : rsc_id = getenv("OCF_RESOURCE_INSTANCE");
96 0 : if (pcmk__str_empty(rsc_id)) {
97 0 : return NULL;
98 : }
99 : }
100 0 : return crm_strdup_printf("master-%s", rsc_id);
101 : }
102 :
103 : /*!
104 : * \internal
105 : * \brief Get the value of a node attribute
106 : *
107 : * \param[in] node Node to get attribute for
108 : * \param[in] name Name of node attribute to get
109 : * \param[in] target If this is \c PCMK_VALUE_HOST and \p node is a guest
110 : * (bundle) node, get the value from the guest's host,
111 : * otherwise get the value from \p node itself
112 : * \param[in] node_type If getting the value from \p node's host, this
113 : * indicates whether to check the current or assigned host
114 : *
115 : * \return Value of \p name attribute for \p node
116 : */
117 : const char *
118 0 : pcmk__node_attr(const pcmk_node_t *node, const char *name, const char *target,
119 : enum pcmk__rsc_node node_type)
120 : {
121 0 : const char *value = NULL; // Attribute value to return
122 0 : const char *node_type_s = NULL; // Readable equivalent of node_type
123 0 : const pcmk_node_t *host = NULL;
124 0 : const pcmk_resource_t *container = NULL;
125 :
126 0 : if ((node == NULL) || (name == NULL)) {
127 0 : return NULL;
128 : }
129 :
130 : /* Check the node's own attributes unless this is a guest (bundle) node with
131 : * the container host as the attribute target.
132 : */
133 0 : if (!pcmk__is_guest_or_bundle_node(node)
134 0 : || !pcmk__str_eq(target, PCMK_VALUE_HOST, pcmk__str_casei)) {
135 0 : value = g_hash_table_lookup(node->details->attrs, name);
136 0 : crm_trace("%s='%s' on %s",
137 : name, pcmk__s(value, ""), pcmk__node_name(node));
138 0 : return value;
139 : }
140 :
141 : /* This resource needs attributes set for the container's host instead of
142 : * for the container itself (useful when the container uses the host's
143 : * storage).
144 : */
145 0 : container = node->details->remote_rsc->container;
146 :
147 0 : switch (node_type) {
148 0 : case pcmk__rsc_node_assigned:
149 0 : host = container->allocated_to;
150 0 : if (host == NULL) {
151 0 : crm_trace("Skipping %s lookup for %s because "
152 : "its container %s is unassigned",
153 : name, pcmk__node_name(node), container->id);
154 0 : return NULL;
155 : }
156 0 : node_type_s = "assigned";
157 0 : break;
158 :
159 0 : case pcmk__rsc_node_current:
160 0 : if (container->running_on != NULL) {
161 0 : host = container->running_on->data;
162 : }
163 0 : if (host == NULL) {
164 0 : crm_trace("Skipping %s lookup for %s because "
165 : "its container %s is inactive",
166 : name, pcmk__node_name(node), container->id);
167 0 : return NULL;
168 : }
169 0 : node_type_s = "current";
170 0 : break;
171 :
172 0 : default:
173 : // Add support for other enum pcmk__rsc_node values if needed
174 0 : CRM_ASSERT(false);
175 0 : break;
176 : }
177 :
178 0 : value = g_hash_table_lookup(host->details->attrs, name);
179 0 : crm_trace("%s='%s' for %s on %s container host %s",
180 : name, pcmk__s(value, ""), pcmk__node_name(node), node_type_s,
181 : pcmk__node_name(host));
182 0 : return value;
183 : }
|