File: nodes.c

package info (click to toggle)
pacemaker 3.0.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 68,576 kB
  • sloc: xml: 160,564; ansic: 143,744; python: 5,670; sh: 2,969; makefile: 2,426
file content (240 lines) | stat: -rw-r--r-- 6,312 bytes parent folder | download
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;
}