Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4512071
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/include/crm/common/nodes.h b/include/crm/common/nodes.h
index 5f6f25ff0c..64c574ad3c 100644
--- a/include/crm/common/nodes.h
+++ b/include/crm/common/nodes.h
@@ -1,230 +1,234 @@
/*
* Copyright 2004-2024 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.
*/
#ifndef PCMK__CRM_COMMON_NODES__H
#define PCMK__CRM_COMMON_NODES__H
#include <stdbool.h> // bool
#include <glib.h> // gboolean, GList, GHashTable
+#include <libxml/tree.h> // xmlNode
#include <crm/common/scheduler_types.h> // pcmk_resource_t, pcmk_scheduler_t
#ifdef __cplusplus
extern "C" {
#endif
/*!
* \file
* \brief Scheduler API for nodes
* \ingroup core
*/
// Special node attributes
#define PCMK_NODE_ATTR_MAINTENANCE "maintenance"
#define PCMK_NODE_ATTR_STANDBY "standby"
#define PCMK_NODE_ATTR_TERMINATE "terminate"
// @COMPAT Make this internal when we can break API backward compatibility
//!@{
//! \deprecated Do not use (public access will be removed in a future release)
enum node_type { // Possible node types
pcmk_node_variant_cluster = 1, // Cluster layer node
pcmk_node_variant_remote = 2, // Pacemaker Remote node
node_ping = 0, // deprecated
#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
node_member = pcmk_node_variant_cluster,
node_remote = pcmk_node_variant_remote,
#endif
};
//!@}
// When to probe a resource on a node (as specified in location constraints)
// @COMPAT Make this internal when we can break API backward compatibility
//!@{
//! \deprecated Do not use (public access will be removed in a future release)
enum pe_discover_e {
pcmk_probe_always = 0, // Always probe resource on node
pcmk_probe_never = 1, // Never probe resource on node
pcmk_probe_exclusive = 2, // Probe only on designated nodes
#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1)
pe_discover_always = pcmk_probe_always,
pe_discover_never = pcmk_probe_never,
pe_discover_exclusive = pcmk_probe_exclusive,
#endif
};
//!@}
// Basic node information (all node objects for the same node share this)
// @COMPAT Make this internal when we can break API backward compatibility
//!@{
//! \deprecated Do not use (public access will be removed in a future release)
struct pe_node_shared_s {
const char *id; // Node ID at the cluster layer
const char *uname; // Node name in cluster
enum node_type type; // Node variant
// @TODO Convert these into a flag group
// NOTE: sbd (as of at least 1.5.2) uses this
//! \deprecated Call pcmk_node_is_online() instead
gboolean online; // Whether online
gboolean standby; // Whether in standby mode
gboolean standby_onfail; // Whether in standby mode due to on-fail
// NOTE: sbd (as of at least 1.5.2) uses this
//! \deprecated Call pcmk_node_is_pending() instead
gboolean pending; // Whether controller membership is pending
// NOTE: sbd (as of at least 1.5.2) uses this
//! \deprecated Call !pcmk_node_is_clean() instead
gboolean unclean; // Whether node requires fencing
gboolean unseen; // Whether node has never joined cluster
// NOTE: sbd (as of at least 1.5.2) uses this
//! \deprecated Call pcmk_node_is_shutting_down() instead
gboolean shutdown; // Whether shutting down
gboolean expected_up; // Whether expected join state is member
gboolean is_dc; // Whether node is cluster's DC
// NOTE: sbd (as of at least 1.5.2) uses this
//! \deprecated Call pcmk_node_is_in_maintenance() instead
gboolean maintenance; // Whether in maintenance mode
gboolean rsc_discovery_enabled; // Whether probes are allowed on node
/*
* Whether this is a guest node whose guest resource must be recovered or a
* remote node that must be fenced
*/
gboolean remote_requires_reset;
/*
* Whether this is a Pacemaker Remote node that was fenced since it was last
* connected by the cluster
*/
gboolean remote_was_fenced;
/*
* Whether this is a Pacemaker Remote node previously marked in its
* node state as being in maintenance mode
*/
gboolean remote_maintenance;
gboolean unpacked; // Whether node history has been unpacked
/*
* Number of resources active on this node (valid after CIB status section
* has been unpacked, as long as pcmk_sched_no_counts was not set)
*/
int num_resources;
// Remote connection resource for node, if it is a Pacemaker Remote node
pcmk_resource_t *remote_rsc;
// NOTE: sbd (as of at least 1.5.2) uses this
// \deprecated Call pcmk_foreach_active_resource() instead
GList *running_rsc; // List of resources active on node
GList *allocated_rsc; // List of resources assigned to node
GHashTable *attrs; // Node attributes
GHashTable *utilization; // Node utilization attributes
GHashTable *digest_cache; // Cache of calculated resource digests
/*
* Sum of priorities of all resources active on node and on any guest nodes
* connected to this node, with +1 for promoted instances (used to compare
* nodes for PCMK_OPT_PRIORITY_FENCING_DELAY)
*/
int priority;
pcmk_scheduler_t *data_set; // Cluster that node is part of
};
//!@}
// Implementation of pcmk_node_t
// @COMPAT Make contents internal when we can break API backward compatibility
//!@{
//! \deprecated Do not use (public access will be removed in a future release)
struct pe_node_s {
int weight; // Node score for a given resource
gboolean fixed; // \deprecated Do not use
int count; // Counter reused by assignment and promotion code
// NOTE: sbd (as of at least 1.5.2) uses this
struct pe_node_shared_s *details; // Basic node information
// @COMPAT This should be enum pe_discover_e
int rsc_discover_mode; // Probe mode (enum pe_discover_e)
};
//!@}
bool pcmk_node_is_online(const pcmk_node_t *node);
bool pcmk_node_is_pending(const pcmk_node_t *node);
bool pcmk_node_is_clean(const pcmk_node_t *node);
bool pcmk_node_is_shutting_down(const pcmk_node_t *node);
bool pcmk_node_is_in_maintenance(const pcmk_node_t *node);
bool pcmk_foreach_active_resource(pcmk_node_t *node,
bool (*fn)(pcmk_resource_t *, void *),
void *user_data);
+
+const char *pcmk_cib_node_shutdown(xmlNode *cib, const char *node);
+
/*!
* \internal
* \brief Return a string suitable for logging as a node name
*
* \param[in] node Node to return a node name string for
*
* \return Node name if available, otherwise node ID if available,
* otherwise "unspecified node" if node is NULL or "unidentified node"
* if node has neither a name nor ID.
*/
static inline const char *
pcmk__node_name(const pcmk_node_t *node)
{
if (node == NULL) {
return "unspecified node";
} else if (node->details->uname != NULL) {
return node->details->uname;
} else if (node->details->id != NULL) {
return node->details->id;
} else {
return "unidentified node";
}
}
/*!
* \internal
* \brief Check whether two node objects refer to the same node
*
* \param[in] node1 First node object to compare
* \param[in] node2 Second node object to compare
*
* \return true if \p node1 and \p node2 refer to the same node
*/
static inline bool
pcmk__same_node(const pcmk_node_t *node1, const pcmk_node_t *node2)
{
return (node1 != NULL) && (node2 != NULL)
&& (node1->details == node2->details);
}
#ifdef __cplusplus
}
#endif
#endif // PCMK__CRM_COMMON_NODES__H
diff --git a/lib/common/nodes.c b/lib/common/nodes.c
index 4edeafbc42..5228ea2618 100644
--- a/lib/common/nodes.c
+++ b/lib/common/nodes.c
@@ -1,163 +1,193 @@
/*
* Copyright 2022-2024 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 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;
}
void
pcmk__xe_add_node(xmlNode *xml, const char *node, int nodeid)
{
CRM_ASSERT(xml != NULL);
if (node != NULL) {
crm_xml_add(xml, PCMK__XA_ATTR_HOST, node);
}
if (nodeid > 0) {
crm_xml_add_int(xml, PCMK__XA_ATTR_HOST_ID, nodeid);
}
}
/*!
* \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->details->uname, 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 = get_xpath_object(xpath, cib, LOG_TRACE);
+
+ free(xpath);
+ if (match != NULL) {
+ return crm_element_value(match, PCMK_XA_VALUE);
+ }
+ }
+ return NULL;
+}
diff --git a/lib/common/tests/nodes/Makefile.am b/lib/common/tests/nodes/Makefile.am
index f52c615e4d..6c4964e1d0 100644
--- a/lib/common/tests/nodes/Makefile.am
+++ b/lib/common/tests/nodes/Makefile.am
@@ -1,23 +1,24 @@
#
# Copyright 2024 the Pacemaker project contributors
#
# The version control history for this file may have further details.
#
# This source code is licensed under the GNU General Public License version 2
# or later (GPLv2+) WITHOUT ANY WARRANTY.
#
include $(top_srcdir)/mk/tap.mk
include $(top_srcdir)/mk/unittest.mk
# Add "_test" to the end of all test program names to simplify .gitignore.
check_PROGRAMS = pcmk__find_node_in_list_test \
+ pcmk__xe_add_node_test \
+ pcmk_cib_node_shutdown_test \
pcmk_foreach_active_resource_test \
pcmk_node_is_clean_test \
pcmk_node_is_in_maintenance_test \
pcmk_node_is_online_test \
pcmk_node_is_pending_test \
- pcmk_node_is_shutting_down_test \
- pcmk__xe_add_node_test
+ pcmk_node_is_shutting_down_test
TESTS = $(check_PROGRAMS)
diff --git a/lib/common/tests/nodes/pcmk_cib_node_shutdown_test.c b/lib/common/tests/nodes/pcmk_cib_node_shutdown_test.c
new file mode 100644
index 0000000000..a64a7283e8
--- /dev/null
+++ b/lib/common/tests/nodes/pcmk_cib_node_shutdown_test.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2024 the Pacemaker project contributors
+ *
+ * The version control history for this file may have further details.
+ *
+ * This source code is licensed under the GNU General Public License version 2
+ * or later (GPLv2+) WITHOUT ANY WARRANTY.
+ */
+
+#include <crm_internal.h>
+
+#include <stdio.h> // NULL
+#include <libxml/tree.h> // xmlNode
+
+#include <crm/common/nodes.h>
+#include <crm/common/unittest_internal.h>
+
+// Minimum CIB structure needed for function's XPath search
+#define CIB_XML \
+ "<" PCMK_XE_CIB ">" \
+ "<" PCMK_XE_STATUS ">" \
+ "<" PCMK__XE_NODE_STATE " " PCMK_XA_UNAME "='node1'>" \
+ "<" PCMK__XE_TRANSIENT_ATTRIBUTES ">" \
+ "<" PCMK_XE_INSTANCE_ATTRIBUTES ">" \
+ "<" PCMK_XE_NVPAIR " " \
+ PCMK_XA_NAME "='" PCMK__NODE_ATTR_SHUTDOWN "' " \
+ PCMK_XA_VALUE "='999'/>" \
+ "</" PCMK_XE_INSTANCE_ATTRIBUTES ">" \
+ "</" PCMK__XE_TRANSIENT_ATTRIBUTES ">" \
+ "</" PCMK__XE_NODE_STATE ">" \
+ "</" PCMK_XE_STATUS ">" \
+ "</" PCMK_XE_CIB ">"
+
+static void
+null_args(void **state)
+{
+ xmlNode *xml = pcmk__xml_parse(CIB_XML);
+
+ assert_non_null(xml);
+ assert_null(pcmk_cib_node_shutdown(NULL, NULL));
+ assert_null(pcmk_cib_node_shutdown(xml, NULL));
+ assert_null(pcmk_cib_node_shutdown(NULL, "node1"));
+ free_xml(xml);
+}
+
+static void
+shutdown_absent(void **state)
+{
+ xmlNode *xml = pcmk__xml_parse(CIB_XML);
+
+ assert_non_null(xml);
+ assert_null(pcmk_cib_node_shutdown(xml, "node"));
+ assert_null(pcmk_cib_node_shutdown(xml, "node10"));
+ free_xml(xml);
+}
+
+static void
+shutdown_present(void **state)
+{
+ xmlNode *xml = pcmk__xml_parse(CIB_XML);
+
+ assert_non_null(xml);
+ assert_string_equal(pcmk_cib_node_shutdown(xml, "node1"), "999");
+ free_xml(xml);
+}
+
+PCMK__UNIT_TEST(NULL, NULL,
+ cmocka_unit_test(null_args),
+ cmocka_unit_test(shutdown_absent),
+ cmocka_unit_test(shutdown_present))
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 25, 3:59 AM (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1952073
Default Alt Text
(17 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment