1 /*
2 * Copyright 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 PCMK__CRM_COMMON_NODES_INTERNAL__H
11 #define PCMK__CRM_COMMON_NODES_INTERNAL__H
12
13 #include <stdio.h> // NULL
14 #include <stdbool.h> // bool
15 #include <stdint.h> // uint32_t, UINT32_C()
16
17 #include <glib.h>
18 #include <crm/common/nodes.h>
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 /*
25 * Special node attributes
26 */
27
28 #define PCMK__NODE_ATTR_SHUTDOWN "shutdown"
29
30 /* @COMPAT Deprecated since 2.1.8. Use a location constraint with
31 * PCMK_XA_RSC_PATTERN=".*" and PCMK_XA_RESOURCE_DISCOVERY="never" instead of
32 * PCMK__NODE_ATTR_RESOURCE_DISCOVERY_ENABLED="false".
33 */
34 #define PCMK__NODE_ATTR_RESOURCE_DISCOVERY_ENABLED "resource-discovery-enabled"
35
36 enum pcmk__node_variant { // Possible node types
37 pcmk__node_variant_cluster = 1, // Cluster layer node
38 pcmk__node_variant_remote = 2, // Pacemaker Remote node
39 };
40
41 enum pcmk__node_flags {
42 pcmk__node_none = UINT32_C(0),
43
44 // Whether node is in standby mode
45 pcmk__node_standby = (UINT32_C(1) << 0),
46
47 // Whether node is in standby mode due to PCMK_META_ON_FAIL
48 pcmk__node_fail_standby = (UINT32_C(1) << 1),
49
50 // Whether node has ever joined cluster (and thus has node state in CIB)
51 pcmk__node_seen = (UINT32_C(1) << 2),
52
53 // Whether expected join state is member
54 pcmk__node_expected_up = (UINT32_C(1) << 3),
55
56 // Whether probes are allowed on node
57 pcmk__node_probes_allowed = (UINT32_C(1) << 4),
58
59 /* Whether this either is a guest node whose guest resource must be
60 * recovered or a remote node that must be fenced
61 */
62 pcmk__node_remote_reset = (UINT32_C(1) << 5),
63
64 /* Whether this is a Pacemaker Remote node that was fenced since it was last
65 * connected by the cluster
66 */
67 pcmk__node_remote_fenced = (UINT32_C(1) << 6),
68
69 /*
70 * Whether this is a Pacemaker Remote node previously marked in its
71 * node state as being in maintenance mode
72 */
73 pcmk__node_remote_maint = (UINT32_C(1) << 7),
74
75 // Whether node history has been unpacked
76 pcmk__node_unpacked = (UINT32_C(1) << 8),
77 };
78
79 // When to probe a resource on a node (as specified in location constraints)
80 enum pcmk__probe_mode {
81 pcmk__probe_always = 0, // Always probe resource on node
82 pcmk__probe_never = 1, // Never probe resource on node
83 pcmk__probe_exclusive = 2, // Probe only on designated nodes
84 };
85
86 /* Per-node data used in resource assignment
87 *
88 * @COMPAT When we can make the pcmk_node_t implementation internal, move these
89 * there and drop this struct.
90 */
91 struct pcmk__node_assignment {
92 int score; // Node's score for relevant resource
93 int count; // Counter reused by assignment and promotion code
94 enum pcmk__probe_mode probe_mode; // When to probe resource on this node
95 };
96
97 /* Implementation of pcmk__node_private_t (pcmk_node_t objects are shallow
98 * copies, so all pcmk_node_t objects for the same node will share the same
99 * private data)
100 */
101 struct pcmk__node_private {
102 /* Node's XML ID in the CIB (the cluster layer ID for cluster nodes,
103 * the node name for Pacemaker Remote nodes)
104 */
105 const char *id;
106
107 /*
108 * Sum of priorities of all resources active on node and on any guest nodes
109 * connected to this node, with +1 for promoted instances (used to compare
110 * nodes for PCMK_OPT_PRIORITY_FENCING_DELAY)
111 */
112 int priority;
113
114 const char *name; // Node name in cluster
115 enum pcmk__node_variant variant; // Node variant
116 uint32_t flags; // Group of enum pcmk__node_flags
117 GHashTable *attrs; // Node attributes
118 GHashTable *utilization; // Node utilization attributes
119 int num_resources; // Number of active resources on node
120 GList *assigned_resources; // List of resources assigned to node
121 GHashTable *digest_cache; // Cache of calculated resource digests
122 pcmk_resource_t *remote; // Pacemaker Remote connection (if any)
123 pcmk_scheduler_t *scheduler; // Scheduler data that node is part of
124 };
125
126 void pcmk__free_node_copy(void *data);
127 pcmk_node_t *pcmk__find_node_in_list(const GList *nodes, const char *node_name);
128
129 /*!
130 * \internal
131 * \brief Set node flags
132 *
133 * \param[in,out] node Node to set flags for
134 * \param[in] flags_to_set Group of enum pcmk_node_flags to set
135 */
136 #define pcmk__set_node_flags(node, flags_to_set) do { \
137 (node)->priv->flags = pcmk__set_flags_as(__func__, __LINE__, \
138 LOG_TRACE, "Node", pcmk__node_name(node), \
139 (node)->priv->flags, (flags_to_set), #flags_to_set); \
140 } while (0)
141
142 /*!
143 * \internal
144 * \brief Clear node flags
145 *
146 * \param[in,out] node Node to clear flags for
147 * \param[in] flags_to_clear Group of enum pcmk_node_flags to clear
148 */
149 #define pcmk__clear_node_flags(node, flags_to_clear) do { \
150 (node)->priv->flags = pcmk__clear_flags_as(__func__, __LINE__, \
151 LOG_TRACE, "Node", pcmk__node_name(node), \
152 (node)->priv->flags, (flags_to_clear), #flags_to_clear); \
153 } while (0)
154
155 /*!
156 * \internal
157 * \brief Return a string suitable for logging as a node name
158 *
159 * \param[in] node Node to return a node name string for
160 *
161 * \return Node name if available, otherwise node ID if available,
162 * otherwise "unspecified node" if node is NULL or "unidentified node"
163 * if node has neither a name nor ID.
164 */
165 static inline const char *
166 pcmk__node_name(const pcmk_node_t *node)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
167 {
168 if (node == NULL) {
169 return "unspecified node";
170
171 } else if (node->priv->name != NULL) {
172 return node->priv->name;
173
174 } else if (node->priv->id != NULL) {
175 return node->priv->id;
176
177 } else {
178 return "unidentified node";
179 }
180 }
181
182 /*!
183 * \internal
184 * \brief Check whether two node objects refer to the same node
185 *
186 * \param[in] node1 First node object to compare
187 * \param[in] node2 Second node object to compare
188 *
189 * \return true if \p node1 and \p node2 refer to the same node
190 */
191 static inline bool
192 pcmk__same_node(const pcmk_node_t *node1, const pcmk_node_t *node2)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
193 {
194 return (node1 != NULL) && (node2 != NULL)
195 && (node1->priv == node2->priv);
196 }
197
198 #ifdef __cplusplus
199 }
200 #endif
201
202 #endif // PCMK__CRM_COMMON_NODES_INTERNAL__H