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