1 /*
2 * Copyright 2022-2026 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 #include <crm_internal.h>
11
12 #include <stdbool.h>
13
14 #include <libxml/tree.h> // xmlNode
15
16 #include <crm/common/nvpair.h>
17
18 /*!
19 * \internal
20 * \brief Free a node object
21 *
22 * \param[in,out] user_data Node object to free
23 */
24 void
25 pcmk__free_node(gpointer user_data)
26 {
27 pcmk_node_t *node = user_data;
28 const bool is_remote = pcmk__is_pacemaker_remote_node(node);
29
|
(1) Event path: |
Condition "node == NULL", taking false branch. |
30 if (node == NULL) {
31 return;
32 }
|
(2) Event path: |
Condition "node->details == NULL", taking false branch. |
33 if (node->details == NULL) {
34 free(node);
35 return;
36 }
37
38 /* This may be called after freeing resources, which means that we can't
39 * use node->private->name for Pacemaker Remote nodes.
40 */
|
(3) Event path: |
Switch case default. |
|
(4) Event path: |
Condition "trace_cs == NULL", taking true branch. |
|
(5) Event path: |
Condition "crm_is_callsite_active(trace_cs, _level, 0)", taking false branch. |
|
(6) Event path: |
Breaking from switch. |
41 pcmk__trace("Freeing node %s",
42 (is_remote? "(guest or remote)" : pcmk__node_name(node)));
43
|
CID (unavailable; MK=cfd2ff71bbe260566cb58e4dc5633223) (#1 of 3): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(7) Event assign_union_field: |
The union field "in" of "_pp" is written. |
|
(8) Event inconsistent_union_field_access: |
In "_pp.out", the union field used: "out" is inconsistent with the field most recently stored: "in". |
44 g_clear_pointer(&node->priv->attrs, g_hash_table_destroy);
45 g_clear_pointer(&node->priv->utilization, g_hash_table_destroy);
46 g_clear_pointer(&node->priv->digest_cache, g_hash_table_destroy);
47 g_list_free(node->details->running_rsc);
48 g_list_free(node->priv->assigned_resources);
49 free(node->priv);
50 free(node->details);
51 free(node->assign);
52 free(node);
53 }
54
55 /*!
56 * \internal
57 * \brief Free a copy of a node object
58 *
59 * \param[in] data Node copy (created by pe__copy_node()) to free
60 */
61 void
62 pcmk__free_node_copy(void *data)
63 {
64 if (data != NULL) {
65 pcmk_node_t *node = data;
66
67 if (node->assign != NULL) {
68 // This is the only member allocated separately for a node copy
69 free(node->assign);
70 }
71 free(node);
72 }
73 }
74
75 /*!
76 * \internal
77 * \brief Check whether a node is online
78 *
79 * \param[in] node Node to check
80 *
81 * \return true if \p node is online, otherwise false
82 */
83 bool
84 pcmk_node_is_online(const pcmk_node_t *node)
85 {
86 return (node != NULL) && node->details->online;
87 }
88
89 /*!
90 * \internal
91 * \brief Check whether a node is pending
92 *
93 * Check whether a node is pending. A node is pending if it is a member of the
94 * cluster but not the controller group, which means it is in the process of
95 * either joining or leaving the cluster.
96 *
97 * \param[in] node Node to check
98 *
99 * \return true if \p node is pending, otherwise false
100 */
101 bool
102 pcmk_node_is_pending(const pcmk_node_t *node)
103 {
104 return (node != NULL) && node->details->pending;
105 }
106
107 /*!
108 * \internal
109 * \brief Check whether a node is clean
110 *
111 * Check whether a node is clean. A node is clean if it is a cluster node or
112 * remote node that has been seen by the cluster at least once, or the
113 * startup-fencing cluster option is false; and the node, and its host if a
114 * guest or bundle node, are not scheduled to be fenced.
115 *
116 * \param[in] node Node to check
117 *
118 * \return true if \p node is clean, otherwise false
119 */
120 bool
121 pcmk_node_is_clean(const pcmk_node_t *node)
122 {
123 return (node != NULL) && !(node->details->unclean);
124 }
125
126 /*!
127 * \internal
128 * \brief Check whether a node is shutting down
129 *
130 * \param[in] node Node to check
131 *
132 * \return true if \p node is shutting down, otherwise false
133 */
134 bool
135 pcmk_node_is_shutting_down(const pcmk_node_t *node)
136 {
137 return (node != NULL) && node->details->shutdown;
138 }
139
140 /*!
141 * \internal
142 * \brief Check whether a node is in maintenance mode
143 *
144 * \param[in] node Node to check
145 *
146 * \return true if \p node is in maintenance mode, otherwise false
147 */
148 bool
149 pcmk_node_is_in_maintenance(const pcmk_node_t *node)
150 {
151 return (node != NULL) && node->details->maintenance;
152 }
153
154 /*!
155 * \internal
156 * \brief Call a function for each resource active on a node
157 *
158 * Call a caller-supplied function with a caller-supplied argument for each
159 * resource that is active on a given node. If the function returns false, this
160 * function will return immediately without processing any remaining resources.
161 *
162 * \param[in] node Node to check
163 *
164 * \return Result of last call of \p fn (or false if none)
165 */
166 bool
167 pcmk_foreach_active_resource(pcmk_node_t *node,
168 bool (*fn)(pcmk_resource_t *, void *),
169 void *user_data)
170 {
171 bool result = false;
172
173 if ((node != NULL) && (fn != NULL)) {
174 for (GList *item = node->details->running_rsc; item != NULL;
175 item = item->next) {
176
177 result = fn((pcmk_resource_t *) item->data, user_data);
178 if (!result) {
179 break;
180 }
181 }
182 }
183 return result;
184 }
185
186 /*!
187 * \internal
188 * \brief Find a node by name in a list of nodes
189 *
190 * \param[in] nodes List of nodes (as pcmk_node_t*)
191 * \param[in] node_name Name of node to find
192 *
193 * \return Node from \p nodes that matches \p node_name if any, otherwise NULL
194 */
195 pcmk_node_t *
196 pcmk__find_node_in_list(const GList *nodes, const char *node_name)
197 {
198 if (node_name != NULL) {
199 for (const GList *iter = nodes; iter != NULL; iter = iter->next) {
200 pcmk_node_t *node = (pcmk_node_t *) iter->data;
201
202 if (pcmk__str_eq(node->priv->name, node_name, pcmk__str_casei)) {
203 return node;
204 }
205 }
206 }
207 return NULL;
208 }
209
210 #define XP_SHUTDOWN "//" PCMK__XE_NODE_STATE "[@" PCMK_XA_UNAME "='%s']/" \
211 PCMK__XE_TRANSIENT_ATTRIBUTES "/" PCMK_XE_INSTANCE_ATTRIBUTES "/" \
212 PCMK_XE_NVPAIR "[@" PCMK_XA_NAME "='" PCMK__NODE_ATTR_SHUTDOWN "']"
213
214 /*!
215 * \brief Get value of a node's shutdown attribute from CIB, if present
216 *
217 * \param[in] cib CIB to check
218 * \param[in] node Name of node to check
219 *
220 * \return Value of shutdown attribute for \p node in \p cib if any,
221 * otherwise NULL
222 * \note The return value is a pointer into \p cib and so is valid only for the
223 * lifetime of that object.
224 */
225 const char *
226 pcmk_cib_node_shutdown(xmlNode *cib, const char *node)
227 {
228 if ((cib != NULL) && (node != NULL)) {
229 char *xpath = pcmk__assert_asprintf(XP_SHUTDOWN, node);
230 xmlNode *match = pcmk__xpath_find_one(cib->doc, xpath, LOG_TRACE);
231
232 free(xpath);
233 if (match != NULL) {
234 return pcmk__xe_get(match, PCMK_XA_VALUE);
235 }
236 }
237 return NULL;
238 }
239