diff --git a/include/crm/common/nodes.h b/include/crm/common/nodes.h index eb5be4f191..cbc0cefca6 100644 --- a/include/crm/common/nodes.h +++ b/include/crm/common/nodes.h @@ -1,193 +1,194 @@ /* * 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 // bool #include // gboolean, GList, GHashTable #include // 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" //! Possible node types enum node_type { pcmk_node_variant_cluster = 1, //!< Cluster layer node pcmk_node_variant_remote = 2, //!< Pacemaker Remote node node_ping = 0, //!< \deprecated Do not use #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) //! \deprecated Use pcmk_node_variant_cluster instead node_member = pcmk_node_variant_cluster, //! \deprecated Use pcmk_node_variant_remote instead node_remote = pcmk_node_variant_remote, #endif }; //! When to probe a resource on a node (as specified in location constraints) 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) //! \deprecated Use pcmk_probe_always instead pe_discover_always = pcmk_probe_always, //! \deprecated Use pcmk_probe_never instead pe_discover_never = pcmk_probe_never, //! \deprecated Use pcmk_probe_exclusive instead pe_discover_exclusive = pcmk_probe_exclusive, #endif }; //! Basic node information (all node objects for the same node share this) 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 gboolean online; //!< Whether online gboolean standby; //!< Whether in standby mode gboolean standby_onfail; //!< Whether in standby mode due to on-fail gboolean pending; //!< Whether controller membership is pending gboolean unclean; //!< Whether node requires fencing gboolean unseen; //!< Whether node has never joined cluster gboolean shutdown; //!< Whether shutting down gboolean expected_up; //!< Whether expected join state is member gboolean is_dc; //!< Whether node is cluster's DC 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; 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 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 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); /*! * \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 e6776d44f8..f7361046a2 100644 --- a/lib/common/nodes.c +++ b/lib/common/nodes.c @@ -1,59 +1,78 @@ /* * 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 #include // xmlNode #include /*! * \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); +} + 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); } } diff --git a/lib/common/tests/nodes/Makefile.am b/lib/common/tests/nodes/Makefile.am index 25d80fa10c..bbf2c3e465 100644 --- a/lib/common/tests/nodes/Makefile.am +++ b/lib/common/tests/nodes/Makefile.am @@ -1,18 +1,19 @@ # # 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_node_is_online_test \ +check_PROGRAMS = pcmk_node_is_clean_test \ + pcmk_node_is_online_test \ pcmk_node_is_pending_test \ pcmk__xe_add_node_test TESTS = $(check_PROGRAMS) diff --git a/lib/common/tests/nodes/pcmk_node_is_clean_test.c b/lib/common/tests/nodes/pcmk_node_is_clean_test.c new file mode 100644 index 0000000000..0534633fdf --- /dev/null +++ b/lib/common/tests/nodes/pcmk_node_is_clean_test.c @@ -0,0 +1,54 @@ +/* + * 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 + +#include // NULL +#include // TRUE, FALSE + +#include +#include + +static void +null_is_unclean(void **state) +{ + assert_false(pcmk_node_is_clean(NULL)); +} + +static void +node_is_clean(void **state) +{ + struct pe_node_shared_s shared = { + .unclean = FALSE, + }; + + pcmk_node_t node = { + .details = &shared, + }; + + assert_true(pcmk_node_is_clean(&node)); +} + +static void +node_is_unclean(void **state) +{ + struct pe_node_shared_s shared = { + .unclean = TRUE, + }; + pcmk_node_t node = { + .details = &shared, + }; + + assert_false(pcmk_node_is_clean(&node)); +} + +PCMK__UNIT_TEST(NULL, NULL, + cmocka_unit_test(null_is_unclean), + cmocka_unit_test(node_is_clean), + cmocka_unit_test(node_is_unclean))