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