diff options
Diffstat (limited to 'include/crm/common')
39 files changed, 2291 insertions, 140 deletions
diff --git a/include/crm/common/Makefile.am b/include/crm/common/Makefile.am index 7d417e4..83a4197 100644 --- a/include/crm/common/Makefile.am +++ b/include/crm/common/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2004-2022 the Pacemaker project contributors +# Copyright 2004-2023 the Pacemaker project contributors # # The version control history for this file may have further details. # @@ -11,45 +11,34 @@ MAINTAINERCLEANFILES = Makefile.in headerdir=$(pkgincludedir)/crm/common -header_HEADERS = acl.h \ - agents.h \ - agents_compat.h \ - cib.h \ - ipc.h \ - ipc_attrd_internal.h \ - ipc_controld.h \ - ipc_pacemakerd.h \ - ipc_schedulerd.h \ - iso8601.h \ - logging.h \ - logging_compat.h \ - mainloop.h \ - mainloop_compat.h \ - nvpair.h \ - output.h \ - results.h \ - results_compat.h \ - util.h \ - util_compat.h \ - xml.h \ - xml_compat.h +header_HEADERS = acl.h \ + actions.h \ + agents.h \ + agents_compat.h \ + cib.h \ + ipc.h \ + ipc_controld.h \ + ipc_pacemakerd.h \ + ipc_schedulerd.h \ + iso8601.h \ + logging.h \ + logging_compat.h \ + mainloop.h \ + mainloop_compat.h \ + nodes.h \ + nvpair.h \ + output.h \ + resources.h \ + results.h \ + results_compat.h \ + roles.h \ + scheduler.h \ + scheduler_types.h \ + tags.h \ + tickets.h \ + util.h \ + util_compat.h \ + xml.h \ + xml_compat.h -noinst_HEADERS = acl_internal.h \ - alerts_internal.h \ - attrd_internal.h \ - cmdline_internal.h \ - health_internal.h \ - internal.h \ - io_internal.h \ - ipc_internal.h \ - iso8601_internal.h \ - lists_internal.h \ - logging_internal.h \ - messages_internal.h \ - options_internal.h \ - output_internal.h \ - remote_internal.h \ - results_internal.h \ - strings_internal.h \ - unittest_internal.h \ - xml_internal.h +noinst_HEADERS = $(wildcard *internal.h) diff --git a/include/crm/common/action_relation_internal.h b/include/crm/common/action_relation_internal.h new file mode 100644 index 0000000..e789131 --- /dev/null +++ b/include/crm/common/action_relation_internal.h @@ -0,0 +1,132 @@ +/* + * Copyright 2023 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_ACTION_RELATION_INTERNAL__H +# define PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H + +/*! + * Flags to indicate the relationship between two actions + * + * @COMPAT The values and semantics of these flags should not be changed until + * the deprecated enum pe_ordering is dropped from the public API. + */ +enum pcmk__action_relation_flags { + //! No relation (compare with equality rather than bit set) + pcmk__ar_none = 0U, + + //! Actions are ordered (optionally, if no other flags are set) + pcmk__ar_ordered = (1U << 0), + + //! Relation applies only if 'first' cannot be part of a live migration + pcmk__ar_if_first_unmigratable = (1U << 1), + + /*! + * If 'then' is required, 'first' becomes required (and becomes unmigratable + * if 'then' is); also, if 'first' is a stop of a blocked resource, 'then' + * becomes unrunnable + */ + pcmk__ar_then_implies_first = (1U << 4), + + /*! + * If 'first' is required, 'then' becomes required; if 'first' is a stop of + * a blocked resource, 'then' becomes unrunnable + */ + pcmk__ar_first_implies_then = (1U << 5), + + /*! + * If 'then' is required and for a promoted instance, 'first' becomes + * required (and becomes unmigratable if 'then' is) + */ + pcmk__ar_promoted_then_implies_first = (1U << 6), + + /*! + * 'first' is runnable only if 'then' is both runnable and migratable, + * and 'first' becomes required if 'then' is + */ + pcmk__ar_unmigratable_then_blocks = (1U << 7), + + //! 'then' is runnable (and migratable) only if 'first' is runnable + pcmk__ar_unrunnable_first_blocks = (1U << 8), + + //! If 'first' is unrunnable, 'then' becomes a real, unmigratable action + pcmk__ar_first_else_then = (1U << 9), + + //! If 'first' is required, 'then' action for instance on same node is + pcmk__ar_first_implies_same_node_then = (1U << 10), + + /*! + * Disable relation if 'first' is unrunnable and for an active resource, + * otherwise order actions and make 'then' unrunnable if 'first' is. + * + * This is used to order a bundle replica's start of its container before a + * probe of its remote connection resource, in case the connection uses the + * REMOTE_CONTAINER_HACK to replace the connection address with where the + * container is running. + */ + pcmk__ar_nested_remote_probe = (1U << 11), + + /*! + * If 'first' is for a blocked resource, make 'then' unrunnable. + * + * If 'then' is required, make 'first' required, make 'first' unmigratable + * if 'then' is unmigratable, and make 'then' unrunnable if 'first' is + * unrunnable. + * + * If 'then' is unrunnable and for the same resource as 'first', make + * 'first' required if it is runnable, and make 'first' unmigratable if + * 'then' is unmigratable. + * + * This is used for "stop then start primitive" (restarts) and + * "stop group member then stop previous member". + */ + pcmk__ar_intermediate_stop = (1U << 12), + + /*! + * The actions must be serialized if in the same transition but can be in + * either order. (In practice, we always arrange them as 'first' then + * 'then', so they end up being essentially the same as optional orderings.) + * + * @TODO Handle more intelligently -- for example, we could schedule the + * action with the fewest inputs first, so we're more likely to execute at + * least one if there is a failure during the transition. Or, we could + * prefer certain action types over others, or base it on resource priority. + */ + pcmk__ar_serialize = (1U << 14), + + //! Relation applies only if actions are on same node + pcmk__ar_if_on_same_node = (1U << 15), + + //! If 'then' is required, 'first' must be added to the transition graph + pcmk__ar_then_implies_first_graphed = (1U << 16), + + //! If 'first' is required and runnable, 'then' must be in graph + pcmk__ar_first_implies_then_graphed = (1U << 17), + + //! User-configured asymmetric ordering + pcmk__ar_asymmetric = (1U << 20), + + //! Actions are ordered if on same node (or migration target for migrate_to) + pcmk__ar_if_on_same_node_or_target = (1U << 21), + + //! 'then' action is runnable if certain number of 'first' instances are + pcmk__ar_min_runnable = (1U << 22), + + //! Ordering applies only if 'first' is required and on same node as 'then' + pcmk__ar_if_required_on_same_node = (1U << 23), + + //! Ordering applies even if 'first' runs on guest node created by 'then' + pcmk__ar_guest_allowed = (1U << 24), + + //! If 'then' action becomes required, 'first' becomes optional + pcmk__ar_then_cancels_first = (1U << 25), +}; + +typedef struct pe_action_wrapper_s pcmk__related_action_t; + +#endif // PCMK__CRM_COMMON_ACTION_RELATION_INTERNAL__H diff --git a/include/crm/common/actions.h b/include/crm/common/actions.h new file mode 100644 index 0000000..5d2784d --- /dev/null +++ b/include/crm/common/actions.h @@ -0,0 +1,467 @@ +/* + * Copyright 2004-2023 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_ACTIONS__H +#define PCMK__CRM_COMMON_ACTIONS__H + +#include <stdbool.h> // bool +#include <strings.h> // strcasecmp() +#include <glib.h> // gboolean, guint +#include <libxml/tree.h> // xmlNode + +#include <crm/lrmd_events.h> // lrmd_event_data_t + +#include <glib.h> // GList, GHashTable +#include <libxml/tree.h> // xmlNode + +#include <crm/common/nodes.h> +#include <crm/common/resources.h> // enum rsc_start_requirement, etc. +#include <crm/common/scheduler_types.h> // pcmk_resource_t, pcmk_node_t + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief APIs related to actions + * \ingroup core + */ + +//! Default timeout (in milliseconds) for non-metadata actions +#define PCMK_DEFAULT_ACTION_TIMEOUT_MS 20000 + +// @COMPAT We don't need a separate timeout for metadata, much less a longer one +//! \deprecated Default timeout (in milliseconds) for metadata actions +#define PCMK_DEFAULT_METADATA_TIMEOUT_MS 30000 + +// Action names as strings +#define PCMK_ACTION_CANCEL "cancel" +#define PCMK_ACTION_CLEAR_FAILCOUNT "clear_failcount" +#define PCMK_ACTION_CLONE_ONE_OR_MORE "clone-one-or-more" +#define PCMK_ACTION_DELETE "delete" +#define PCMK_ACTION_DEMOTE "demote" +#define PCMK_ACTION_DEMOTED "demoted" +#define PCMK_ACTION_DO_SHUTDOWN "do_shutdown" +#define PCMK_ACTION_LIST "list" +#define PCMK_ACTION_LRM_DELETE "lrm_delete" +#define PCMK_ACTION_LOAD_STOPPED "load_stopped" +#define PCMK_ACTION_MAINTENANCE_NODES "maintenance_nodes" +#define PCMK_ACTION_META_DATA "meta-data" +#define PCMK_ACTION_MIGRATE_FROM "migrate_from" +#define PCMK_ACTION_MIGRATE_TO "migrate_to" +#define PCMK_ACTION_MONITOR "monitor" +#define PCMK_ACTION_NOTIFIED "notified" +#define PCMK_ACTION_NOTIFY "notify" +#define PCMK_ACTION_OFF "off" +#define PCMK_ACTION_ON "on" +#define PCMK_ACTION_ONE_OR_MORE "one-or-more" +#define PCMK_ACTION_PROMOTE "promote" +#define PCMK_ACTION_PROMOTED "promoted" +#define PCMK_ACTION_REBOOT "reboot" +#define PCMK_ACTION_RELOAD "reload" +#define PCMK_ACTION_RELOAD_AGENT "reload-agent" +#define PCMK_ACTION_RUNNING "running" +#define PCMK_ACTION_START "start" +#define PCMK_ACTION_STATUS "status" +#define PCMK_ACTION_STONITH "stonith" +#define PCMK_ACTION_STOP "stop" +#define PCMK_ACTION_STOPPED "stopped" +#define PCMK_ACTION_VALIDATE_ALL "validate-all" + +//! Possible actions (including some pseudo-actions) +enum action_tasks { + pcmk_action_unspecified = 0, //!< Unspecified or unknown action + pcmk_action_monitor, //!< Monitor + + // Each "completed" action must be the regular action plus 1 + + pcmk_action_stop, //!< Stop + pcmk_action_stopped, //!< Stop completed + + pcmk_action_start, //!< Start + pcmk_action_started, //!< Start completed + + pcmk_action_notify, //!< Notify + pcmk_action_notified, //!< Notify completed + + pcmk_action_promote, //!< Promote + pcmk_action_promoted, //!< Promoted + + pcmk_action_demote, //!< Demote + pcmk_action_demoted, //!< Demoted + + pcmk_action_shutdown, //!< Shut down node + pcmk_action_fence, //!< Fence node + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_action_unspecified instead + no_action = pcmk_action_unspecified, + + //! \deprecated Use pcmk_action_monitor instead + monitor_rsc = pcmk_action_monitor, + + //! \deprecated Use pcmk_action_stop instead + stop_rsc = pcmk_action_stop, + + //! \deprecated Use pcmk_action_stopped instead + stopped_rsc = pcmk_action_stopped, + + //! \deprecated Use pcmk_action_start instead + start_rsc = pcmk_action_start, + + //! \deprecated Use pcmk_action_started instead + started_rsc = pcmk_action_started, + + //! \deprecated Use pcmk_action_notify instead + action_notify = pcmk_action_notify, + + //! \deprecated Use pcmk_action_notified instead + action_notified = pcmk_action_notified, + + //! \deprecated Use pcmk_action_promote instead + action_promote = pcmk_action_promote, + + //! \deprecated Use pcmk_action_promoted instead + action_promoted = pcmk_action_promoted, + + //! \deprecated Use pcmk_action_demote instead + action_demote = pcmk_action_demote, + + //! \deprecated Use pcmk_action_demoted instead + action_demoted = pcmk_action_demoted, + + //! \deprecated Use pcmk_action_shutdown instead + shutdown_crm = pcmk_action_shutdown, + + //! \deprecated Use pcmk_action_fence instead + stonith_node = pcmk_action_fence, +#endif +}; + +//! Possible responses to a resource action failure +enum action_fail_response { + /* The order is (partially) significant here; the values from + * pcmk_on_fail_ignore through pcmk_on_fail_fence_node are in order of + * increasing severity. + * + * @COMPAT The values should be ordered and numbered per the "TODO" comments + * below, so all values are in order of severity and there is room for + * future additions, but that would break API compatibility. + * @TODO For now, we just use a function to compare the values specially, but + * at the next compatibility break, we should arrange things + * properly so we can compare with less than and greater than. + */ + + // @TODO Define as 10 + pcmk_on_fail_ignore = 0, //!< Act as if failure didn't happen + + // @TODO Define as 30 + pcmk_on_fail_restart = 1, //!< Restart resource + + // @TODO Define as 60 + pcmk_on_fail_ban = 2, //!< Ban resource from current node + + // @TODO Define as 70 + pcmk_on_fail_block = 3, //!< Treat resource as unmanaged + + // @TODO Define as 80 + pcmk_on_fail_stop = 4, //!< Stop resource and leave stopped + + // @TODO Define as 90 + pcmk_on_fail_standby_node = 5, //!< Put resource's node in standby + + // @TODO Define as 100 + pcmk_on_fail_fence_node = 6, //!< Fence resource's node + + // @COMPAT Values below here are out of desired order for API compatibility + + // @TODO Define as 50 + pcmk_on_fail_restart_container = 7, //!< Restart resource's container + + // @TODO Define as 40 + /*! + * Fence the remote node created by the resource if fencing is enabled, + * otherwise attempt to restart the resource (used internally for some + * remote connection failures). + */ + pcmk_on_fail_reset_remote = 8, + + // @TODO Define as 20 + pcmk_on_fail_demote = 9, //!< Demote if promotable, else stop + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_on_fail_ignore instead + action_fail_ignore = pcmk_on_fail_ignore, + + //! \deprecated Use pcmk_on_fail_restart instead + action_fail_recover = pcmk_on_fail_restart, + + //! \deprecated Use pcmk_on_fail_ban instead + action_fail_migrate = pcmk_on_fail_ban, + + //! \deprecated Use pcmk_on_fail_block instead + action_fail_block = pcmk_on_fail_block, + + //! \deprecated Use pcmk_on_fail_stop instead + action_fail_stop = pcmk_on_fail_stop, + + //! \deprecated Use pcmk_on_fail_standby_node instead + action_fail_standby = pcmk_on_fail_standby_node, + + //! \deprecated Use pcmk_on_fail_fence_node instead + action_fail_fence = pcmk_on_fail_fence_node, + + //! \deprecated Use pcmk_on_fail_restart_container instead + action_fail_restart_container = pcmk_on_fail_restart_container, + + //! \deprecated Use pcmk_on_fail_reset_remote instead + action_fail_reset_remote = pcmk_on_fail_reset_remote, + + //! \deprecated Use pcmk_on_fail_demote instead + action_fail_demote = pcmk_on_fail_demote, +#endif +}; + +//! Action scheduling flags +enum pe_action_flags { + //! No action flags set (compare with equality rather than bit set) + pcmk_no_action_flags = 0, + + //! Whether action does not require invoking an agent + pcmk_action_pseudo = (1 << 0), + + //! Whether action is runnable + pcmk_action_runnable = (1 << 1), + + //! Whether action should not be executed + pcmk_action_optional = (1 << 2), + + //! Whether action should be added to transition graph even if optional + pcmk_action_always_in_graph = (1 << 3), + + //! Whether operation-specific instance attributes have been unpacked yet + pcmk_action_attrs_evaluated = (1 << 4), + + //! Whether action is allowed to be part of a live migration + pcmk_action_migratable = (1 << 7), + + //! Whether action has been added to transition graph + pcmk_action_added_to_graph = (1 << 8), + + //! Whether action is a stop to abort a dangling migration + pcmk_action_migration_abort = (1 << 11), + + /*! + * Whether action is an ordering point for minimum required instances + * (used to implement ordering after clones with clone-min configured, + * and ordered sets with require-all=false) + */ + pcmk_action_min_runnable = (1 << 12), + + //! Whether action is recurring monitor that must be rescheduled if active + pcmk_action_reschedule = (1 << 13), + + //! Whether action has already been processed by a recursive procedure + pcmk_action_detect_loop = (1 << 14), + + //! Whether action's inputs have been de-duplicated yet + pcmk_action_inputs_deduplicated = (1 << 15), + + //! Whether action can be executed on DC rather than own node + pcmk_action_on_dc = (1 << 16), + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_action_pseudo instead + pe_action_pseudo = pcmk_action_pseudo, + + //! \deprecated Use pcmk_action_runnable instead + pe_action_runnable = pcmk_action_runnable, + + //! \deprecated Use pcmk_action_optional instead + pe_action_optional = pcmk_action_optional, + + //! \deprecated Use pcmk_action_always_in_graph instead + pe_action_print_always = pcmk_action_always_in_graph, + + //! \deprecated Use pcmk_action_attrs_evaluated instead + pe_action_have_node_attrs = pcmk_action_attrs_evaluated, + + //! \deprecated Do not use + pe_action_implied_by_stonith = (1 << 6), + + //! \deprecated Use pcmk_action_migratable instead + pe_action_migrate_runnable = pcmk_action_migratable, + + //! \deprecated Use pcmk_action_added_to_graph instead + pe_action_dumped = pcmk_action_added_to_graph, + + //! \deprecated Do not use + pe_action_processed = (1 << 9), + + //! \deprecated Do not use + pe_action_clear = (1 << 10), + + //! \deprecated Use pcmk_action_migration_abort instead + pe_action_dangle = pcmk_action_migration_abort, + + //! \deprecated Use pcmk_action_min_runnable instead + pe_action_requires_any = pcmk_action_min_runnable, + + //! \deprecated Use pcmk_action_reschedule instead + pe_action_reschedule = pcmk_action_reschedule, + + //! \deprecated Use pcmk_action_detect_loop instead + pe_action_tracking = pcmk_action_detect_loop, + + //! \deprecated Use pcmk_action_inputs_deduplicated instead + pe_action_dedup = pcmk_action_inputs_deduplicated, + + //! \deprecated Use pcmk_action_on_dc instead + pe_action_dc = pcmk_action_on_dc, +#endif +}; + +/* @COMPAT enum pe_link_state and enum pe_ordering are currently needed for + * struct pe_action_wrapper_s (which is public) but should be removed at an + * API compatibility break when that can be refactored and made internal + */ + +//!@{ +//! \deprecated Do not use +enum pe_link_state { + pe_link_not_dumped = 0, + pe_link_dumped = 1, +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + pe_link_dup = 2, +#endif +}; + +enum pe_ordering { + pe_order_none = 0x0, +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + pe_order_optional = 0x1, + pe_order_apply_first_non_migratable = 0x2, + pe_order_implies_first = 0x10, + pe_order_implies_then = 0x20, + pe_order_promoted_implies_first = 0x40, + pe_order_implies_first_migratable = 0x80, + pe_order_runnable_left = 0x100, + pe_order_pseudo_left = 0x200, + pe_order_implies_then_on_node = 0x400, + pe_order_probe = 0x800, + pe_order_restart = 0x1000, + pe_order_stonith_stop = 0x2000, + pe_order_serialize_only = 0x4000, + pe_order_same_node = 0x8000, + pe_order_implies_first_printed = 0x10000, + pe_order_implies_then_printed = 0x20000, + pe_order_asymmetrical = 0x100000, + pe_order_load = 0x200000, + pe_order_one_or_more = 0x400000, + pe_order_anti_colocation = 0x800000, + pe_order_preserve = 0x1000000, + pe_order_then_cancels_first = 0x2000000, + pe_order_trace = 0x4000000, + pe_order_implies_first_master = pe_order_promoted_implies_first, +#endif +}; + +// Action sequenced relative to another action +// @COMPAT This should be internal +struct pe_action_wrapper_s { + // @COMPAT This should be uint32_t + enum pe_ordering type; // Group of enum pcmk__action_relation_flags + + // @COMPAT This should be a bool + enum pe_link_state state; // Whether action has been added to graph yet + + pcmk_action_t *action; // Action to be sequenced +}; +//!@} + +//! Implementation of pcmk_action_t +struct pe_action_s { + int id; //!< Counter to identify action + + /*! + * When the controller aborts a transition graph, it sets an abort priority. + * If this priority is higher, the action will still be executed anyway. + * Pseudo-actions are always allowed, so this is irrelevant for them. + */ + int priority; + + pcmk_resource_t *rsc; //!< Resource to apply action to, if any + pcmk_node_t *node; //!< Node to execute action on, if any + xmlNode *op_entry; //!< Action XML configuration, if any + char *task; //!< Action name + char *uuid; //!< Action key + char *cancel_task; //!< If task is "cancel", the action being cancelled + char *reason; //!< Readable description of why action is needed + + //@ COMPAT Change to uint32_t at a compatibility break + enum pe_action_flags flags; //!< Group of enum pe_action_flags + + enum rsc_start_requirement needs; //!< Prerequisite for recovery + enum action_fail_response on_fail; //!< Response to failure + enum rsc_role_e fail_role; //!< Resource role if action fails + GHashTable *meta; //!< Meta-attributes relevant to action + GHashTable *extra; //!< Action-specific instance attributes + + /* Current count of runnable instance actions for "first" action in an + * ordering dependency with pcmk__ar_min_runnable set. + */ + int runnable_before; //!< For Pacemaker use only + + /*! + * Number of instance actions for "first" action in an ordering dependency + * with pcmk__ar_min_runnable set that must be runnable before this action + * can be runnable. + */ + int required_runnable_before; + + // Actions in a relation with this one (as pcmk__related_action_t *) + GList *actions_before; //!< For Pacemaker use only + GList *actions_after; //!< For Pacemaker use only + + /* This is intended to hold data that varies by the type of action, but is + * not currently used. Some of the above fields could be moved here except + * for API backward compatibility. + */ + void *action_details; //!< For Pacemaker use only +}; + +// For parsing various action-related string specifications +gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, + guint *interval_ms); +gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, + int *action_id, int *target_rc); +gboolean decode_transition_magic(const char *magic, char **uuid, + int *transition_id, int *action_id, + int *op_status, int *op_rc, int *target_rc); + +// @COMPAT Either these shouldn't be in libcrmcommon or lrmd_event_data_t should +int rsc_op_expected_rc(const lrmd_event_data_t *event); +gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc); + +bool crm_op_needs_metadata(const char *rsc_class, const char *op); + +xmlNode *crm_create_op_xml(xmlNode *parent, const char *prefix, + const char *task, const char *interval_spec, + const char *timeout); + +bool pcmk_is_probe(const char *task, guint interval); +bool pcmk_xe_is_probe(const xmlNode *xml_op); +bool pcmk_xe_mask_probe_failure(const xmlNode *xml_op); + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_ACTIONS__H diff --git a/include/crm/common/actions_internal.h b/include/crm/common/actions_internal.h new file mode 100644 index 0000000..7e794e6 --- /dev/null +++ b/include/crm/common/actions_internal.h @@ -0,0 +1,57 @@ +/* + * Copyright 2004-2023 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_ACTIONS_INTERNAL__H +#define PCMK__CRM_COMMON_ACTIONS_INTERNAL__H + +#include <stdbool.h> // bool +#include <glib.h> // guint +#include <libxml/tree.h> // xmlNode + +#include <crm/common/actions.h> // PCMK_ACTION_MONITOR +#include <crm/common/strings_internal.h> // pcmk__str_eq() + +#ifdef __cplusplus +extern "C" { +#endif + +//! printf-style format to create operation key from resource, action, interval +#define PCMK__OP_FMT "%s_%s_%u" + +char *pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms); +char *pcmk__notify_key(const char *rsc_id, const char *notify_type, + const char *op_type); +char *pcmk__transition_key(int transition_id, int action_id, int target_rc, + const char *node); +void pcmk__filter_op_for_digest(xmlNode *param_set); +bool pcmk__is_fencing_action(const char *action); + +/*! + * \internal + * \brief Get a human-friendly action name + * + * \param[in] action_name Actual action name + * \param[in] interval_ms Action interval (in milliseconds) + * + * \return Action name suitable for display + */ +static inline const char * +pcmk__readable_action(const char *action_name, guint interval_ms) { + if ((interval_ms == 0) + && pcmk__str_eq(action_name, PCMK_ACTION_MONITOR, pcmk__str_none)) { + return "probe"; + } + return action_name; +} + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_ACTIONS_INTERNAL__H diff --git a/include/crm/common/alerts_internal.h b/include/crm/common/alerts_internal.h index ef64fab..dc67427 100644 --- a/include/crm/common/alerts_internal.h +++ b/include/crm/common/alerts_internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the Pacemaker project contributors + * Copyright 2015-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -76,7 +76,6 @@ void pcmk__add_alert_key(GHashTable *table, enum pcmk__alert_keys_e name, const char *value); void pcmk__add_alert_key_int(GHashTable *table, enum pcmk__alert_keys_e name, int value); -bool pcmk__alert_in_patchset(xmlNode *msg, bool config); static inline const char * pcmk__alert_flag2text(enum pcmk__alert_flags flag) diff --git a/include/crm/common/cib_internal.h b/include/crm/common/cib_internal.h new file mode 100644 index 0000000..c41c12e --- /dev/null +++ b/include/crm/common/cib_internal.h @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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_CIB_INTERNAL__H +#define PCMK__CRM_COMMON_CIB_INTERNAL__H + +#ifdef __cplusplus +extern "C" { +#endif + +const char *pcmk__cib_abs_xpath_for(const char *element); + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__COMMON_CIB_INTERNAL__H diff --git a/include/crm/common/clone_internal.h b/include/crm/common/clone_internal.h new file mode 100644 index 0000000..494ee74 --- /dev/null +++ b/include/crm/common/clone_internal.h @@ -0,0 +1,33 @@ +/* + * Copyright 2004-2023 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_CLONE_INTERNAL__H +# define PCMK__CRM_COMMON_CLONE_INTERNAL__H + +#ifdef __cplusplus +extern "C" { +#endif + +// Clone resource flags (used in variant data) +enum pcmk__clone_flags { + // Whether instances should be started sequentially + pcmk__clone_ordered = (1 << 0), + + // Whether promotion scores have been added + pcmk__clone_promotion_added = (1 << 1), + + // Whether promotion constraints have been added + pcmk__clone_promotion_constrained = (1 << 2), +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_CLONE_INTERNAL__H diff --git a/include/crm/common/digests_internal.h b/include/crm/common/digests_internal.h new file mode 100644 index 0000000..7598de2 --- /dev/null +++ b/include/crm/common/digests_internal.h @@ -0,0 +1,33 @@ +/* + * Copyright 2004-2023 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_DIGESTS_INTERNAL__H +# define PCMK__CRM_COMMON_DIGESTS_INTERNAL__H + +#include <libxml/tree.h> // xmlNode + +#ifdef __cplusplus +extern "C" { +#endif + +// Digest comparison results +enum pcmk__digest_result { + pcmk__digest_unknown, // No digest available for comparison + pcmk__digest_match, // Digests match + pcmk__digest_mismatch, // Any parameter changed (potentially reloadable) + pcmk__digest_restart, // Parameters that require a restart changed +}; + +bool pcmk__verify_digest(xmlNode *input, const char *expected); + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_DIGESTS_INTERNAL__H diff --git a/include/crm/common/failcounts_internal.h b/include/crm/common/failcounts_internal.h new file mode 100644 index 0000000..4ad01bf --- /dev/null +++ b/include/crm/common/failcounts_internal.h @@ -0,0 +1,41 @@ +/* + * Copyright 2004-2023 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_FAILCOUNTS_INTERNAL__H +# define PCMK__CRM_COMMON_FAILCOUNTS_INTERNAL__H + +#ifdef __cplusplus +extern "C" { +#endif + +// Options when getting resource fail counts +enum pcmk__fc_flags { + pcmk__fc_default = (1 << 0), + pcmk__fc_effective = (1 << 1), // Don't count expired failures + pcmk__fc_fillers = (1 << 2), // If container, include filler failures +}; + +/*! + * \internal + * \enum pcmk__rsc_node + * \brief Type of resource location lookup to perform + */ +enum pcmk__rsc_node { + pcmk__rsc_node_assigned = 0, //!< Where resource is assigned + pcmk__rsc_node_current = 1, //!< Where resource is running + + // @COMPAT: Use in native_location() at a compatibility break + pcmk__rsc_node_pending = 2, //!< Where resource is pending +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_FAILCOUNTS_INTERNAL__H diff --git a/include/crm/common/group_internal.h b/include/crm/common/group_internal.h new file mode 100644 index 0000000..9e1424d --- /dev/null +++ b/include/crm/common/group_internal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2004-2023 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_GROUP_INTERNAL__H +# define PCMK__CRM_COMMON_GROUP_INTERNAL__H + +#ifdef __cplusplus +extern "C" { +#endif + +// Group resource flags (used in variant data) +enum pcmk__group_flags { + pcmk__group_ordered = (1 << 0), // Members start sequentially + pcmk__group_colocated = (1 << 1), // Members must be on same node +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_GROUP_INTERNAL__H diff --git a/include/crm/common/health_internal.h b/include/crm/common/health_internal.h index 277a4c9..f98529c 100644 --- a/include/crm/common/health_internal.h +++ b/include/crm/common/health_internal.h @@ -18,7 +18,7 @@ extern "C" { * \internal * \brief Possible node health strategies * - * \note It would be nice to use this in pe_working_set_t but that will have to + * \note It would be nice to use this in pcmk_scheduler_t but that will have to * wait for an API backward compatibility break. */ enum pcmk__health_strategy { diff --git a/include/crm/common/internal.h b/include/crm/common/internal.h index bd98780..3078606 100644 --- a/include/crm/common/internal.h +++ b/include/crm/common/internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the Pacemaker project contributors + * Copyright 2015-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -20,6 +20,8 @@ #include <crm/common/util.h> // crm_strdup_printf() #include <crm/common/logging.h> // do_crm_log_unlikely(), etc. #include <crm/common/mainloop.h> // mainloop_io_t, struct ipc_client_callbacks +#include <crm/common/actions_internal.h> +#include <crm/common/digests_internal.h> #include <crm/common/health_internal.h> #include <crm/common/io_internal.h> #include <crm/common/iso8601_internal.h> @@ -50,11 +52,6 @@ int pcmk__substitute_secrets(const char *rsc_id, GHashTable *params); #endif -/* internal digest-related utilities (from digest.c) */ - -bool pcmk__verify_digest(xmlNode *input, const char *expected); - - /* internal main loop utilities (from mainloop.c) */ int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, @@ -164,20 +161,6 @@ int pcmk__pidfile_matches(const char *filename, pid_t expected_pid, int pcmk__lock_pidfile(const char *filename, const char *name); -/* internal functions related to resource operations (from operations.c) */ - -// printf-style format to create operation ID from resource, action, interval -#define PCMK__OP_FMT "%s_%s_%u" - -char *pcmk__op_key(const char *rsc_id, const char *op_type, guint interval_ms); -char *pcmk__notify_key(const char *rsc_id, const char *notify_type, - const char *op_type); -char *pcmk__transition_key(int transition_id, int action_id, int target_rc, - const char *node); -void pcmk__filter_op_for_digest(xmlNode *param_set); -bool pcmk__is_fencing_action(const char *action); - - // bitwise arithmetic utilities /*! diff --git a/include/crm/common/ipc.h b/include/crm/common/ipc.h index 3d4ee10..397c8b1 100644 --- a/include/crm/common/ipc.h +++ b/include/crm/common/ipc.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2022 the Pacemaker project contributors + * Copyright 2004-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -170,8 +170,8 @@ void crm_ipc_close(crm_ipc_t * client); void crm_ipc_destroy(crm_ipc_t * client); void pcmk_free_ipc_event(struct iovec *event); -int crm_ipc_send(crm_ipc_t * client, xmlNode * message, enum crm_ipc_flags flags, - int32_t ms_timeout, xmlNode ** reply); +int crm_ipc_send(crm_ipc_t *client, const xmlNode *message, + enum crm_ipc_flags flags, int32_t ms_timeout, xmlNode **reply); int crm_ipc_get_fd(crm_ipc_t * client); bool crm_ipc_connected(crm_ipc_t * client); diff --git a/include/crm/common/ipc_internal.h b/include/crm/common/ipc_internal.h index 5099dda..b391e83 100644 --- a/include/crm/common/ipc_internal.h +++ b/include/crm/common/ipc_internal.h @@ -96,6 +96,10 @@ extern "C" { int pcmk__ipc_is_authentic_process_active(const char *name, uid_t refuid, gid_t refgid, pid_t *gotpid); +int pcmk__connect_generic_ipc(crm_ipc_t *ipc); +int pcmk__ipc_fd(crm_ipc_t *ipc, int *fd); +int pcmk__connect_ipc(pcmk_ipc_api_t *api, enum pcmk_ipc_dispatch dispatch_type, + int attempts); /* * Server-related @@ -112,6 +116,7 @@ struct pcmk__remote_s { int tcp_socket; mainloop_io_t *source; time_t uptime; + char *start_state; /* CIB-only */ char *token; @@ -245,11 +250,11 @@ int pcmk__ipc_send_ack_as(const char *function, int line, pcmk__client_t *c, #define pcmk__ipc_send_ack(c, req, flags, tag, ver, st) \ pcmk__ipc_send_ack_as(__func__, __LINE__, (c), (req), (flags), (tag), (ver), (st)) -int pcmk__ipc_prepare_iov(uint32_t request, xmlNode *message, +int pcmk__ipc_prepare_iov(uint32_t request, const xmlNode *message, uint32_t max_send_size, struct iovec **result, ssize_t *bytes); -int pcmk__ipc_send_xml(pcmk__client_t *c, uint32_t request, xmlNode *message, - uint32_t flags); +int pcmk__ipc_send_xml(pcmk__client_t *c, uint32_t request, + const xmlNode *message, uint32_t flags); int pcmk__ipc_send_iov(pcmk__client_t *c, struct iovec *iov, uint32_t flags); xmlNode *pcmk__client_data2xml(pcmk__client_t *c, void *data, uint32_t *id, uint32_t *flags); diff --git a/include/crm/common/logging.h b/include/crm/common/logging.h index 2878fba..eea4cec 100644 --- a/include/crm/common/logging.h +++ b/include/crm/common/logging.h @@ -11,6 +11,7 @@ # define PCMK__CRM_COMMON_LOGGING__H # include <stdio.h> +# include <stdint.h> // uint8_t, uint32_t # include <glib.h> # include <qb/qblog.h> # include <libxml/tree.h> @@ -120,7 +121,9 @@ unsigned int set_crm_log_level(unsigned int level); unsigned int get_crm_log_level(void); -void pcmk_log_xml_impl(uint8_t level, const char *text, const xmlNode *xml); +void pcmk_log_xml_as(const char *file, const char *function, uint32_t line, + uint32_t tags, uint8_t level, const char *text, + const xmlNode *xml); /* * Throughout the macros below, note the leading, pre-comma, space in the @@ -270,7 +273,8 @@ pcmk__clip_log_level(int level) __LINE__, 0); \ } \ if (crm_is_callsite_active(xml_cs, _level, 0)) { \ - pcmk_log_xml_impl(_level, text, xml); \ + pcmk_log_xml_as(__FILE__, __func__, __LINE__, 0, \ + _level, text, (xml)); \ } \ break; \ } \ diff --git a/include/crm/common/logging_compat.h b/include/crm/common/logging_compat.h index cfdb562..b57a802 100644 --- a/include/crm/common/logging_compat.h +++ b/include/crm/common/logging_compat.h @@ -10,6 +10,7 @@ #ifndef PCMK__CRM_COMMON_LOGGING_COMPAT__H # define PCMK__CRM_COMMON_LOGGING_COMPAT__H +#include <stdint.h> // uint8_t #include <glib.h> #include <libxml/tree.h> @@ -78,6 +79,9 @@ void log_data_element(int log_level, const char *file, const char *function, int line, const char *prefix, const xmlNode *data, int depth, int legacy_options); +//! \deprecated Do not use Pacemaker for general-purpose logging +void pcmk_log_xml_impl(uint8_t level, const char *text, const xmlNode *xml); + #ifdef __cplusplus } #endif diff --git a/include/crm/common/logging_internal.h b/include/crm/common/logging_internal.h index 479dcab..981ddf3 100644 --- a/include/crm/common/logging_internal.h +++ b/include/crm/common/logging_internal.h @@ -19,6 +19,18 @@ extern "C" { # include <crm/common/logging.h> # include <crm/common/output_internal.h> +typedef void (*pcmk__config_error_func) (void *ctx, const char *msg, ...); +typedef void (*pcmk__config_warning_func) (void *ctx, const char *msg, ...); + +extern pcmk__config_error_func pcmk__config_error_handler; +extern pcmk__config_warning_func pcmk__config_warning_handler; + +extern void *pcmk__config_error_context; +extern void *pcmk__config_warning_context; + +void pcmk__set_config_error_handler(pcmk__config_error_func error_handler, void *error_context); +void pcmk__set_config_warning_handler(pcmk__config_warning_func warning_handler, void *warning_context); + /*! * \internal * \brief Log a configuration error @@ -26,9 +38,13 @@ extern "C" { * \param[in] fmt printf(3)-style format string * \param[in] ... Arguments for format string */ -# define pcmk__config_err(fmt...) do { \ - crm_config_error = TRUE; \ - crm_err(fmt); \ +# define pcmk__config_err(fmt...) do { \ + crm_config_error = TRUE; \ + if (pcmk__config_error_handler == NULL) { \ + crm_err(fmt); \ + } else { \ + pcmk__config_error_handler(pcmk__config_error_context, fmt); \ + } \ } while (0) /*! @@ -38,9 +54,13 @@ extern "C" { * \param[in] fmt printf(3)-style format string * \param[in] ... Arguments for format string */ -# define pcmk__config_warn(fmt...) do { \ - crm_config_warning = TRUE; \ - crm_warn(fmt); \ +# define pcmk__config_warn(fmt...) do { \ + crm_config_warning = TRUE; \ + if (pcmk__config_warning_handler == NULL) { \ + crm_warn(fmt); \ + } else { \ + pcmk__config_warning_handler(pcmk__config_warning_context, fmt); \ + } \ } while (0) /*! @@ -74,6 +94,76 @@ extern "C" { /*! * \internal + * \brief Log XML changes line-by-line in a formatted fashion + * + * \param[in] level Priority at which to log the messages + * \param[in] xml XML to log + * + * \note This does nothing when \p level is \c LOG_STDOUT. + */ +#define pcmk__log_xml_changes(level, xml) do { \ + uint8_t _level = pcmk__clip_log_level(level); \ + static struct qb_log_callsite *xml_cs = NULL; \ + \ + switch (_level) { \ + case LOG_STDOUT: \ + case LOG_NEVER: \ + break; \ + default: \ + if (xml_cs == NULL) { \ + xml_cs = qb_log_callsite_get(__func__, __FILE__, \ + "xml-changes", _level, \ + __LINE__, 0); \ + } \ + if (crm_is_callsite_active(xml_cs, _level, 0)) { \ + pcmk__log_xml_changes_as(__FILE__, __func__, __LINE__, \ + 0, _level, xml); \ + } \ + break; \ + } \ + } while(0) + +/*! + * \internal + * \brief Log an XML patchset line-by-line in a formatted fashion + * + * \param[in] level Priority at which to log the messages + * \param[in] patchset XML patchset to log + * + * \note This does nothing when \p level is \c LOG_STDOUT. + */ +#define pcmk__log_xml_patchset(level, patchset) do { \ + uint8_t _level = pcmk__clip_log_level(level); \ + static struct qb_log_callsite *xml_cs = NULL; \ + \ + switch (_level) { \ + case LOG_STDOUT: \ + case LOG_NEVER: \ + break; \ + default: \ + if (xml_cs == NULL) { \ + xml_cs = qb_log_callsite_get(__func__, __FILE__, \ + "xml-patchset", _level, \ + __LINE__, 0); \ + } \ + if (crm_is_callsite_active(xml_cs, _level, 0)) { \ + pcmk__log_xml_patchset_as(__FILE__, __func__, __LINE__, \ + 0, _level, patchset); \ + } \ + break; \ + } \ + } while(0) + +void pcmk__log_xml_changes_as(const char *file, const char *function, + uint32_t line, uint32_t tags, uint8_t level, + const xmlNode *xml); + +void pcmk__log_xml_patchset_as(const char *file, const char *function, + uint32_t line, uint32_t tags, uint8_t level, + const xmlNode *patchset); + +/*! + * \internal * \brief Initialize logging for command line tools * * \param[in] name The name of the program diff --git a/include/crm/common/nodes.h b/include/crm/common/nodes.h new file mode 100644 index 0000000..fbc3758 --- /dev/null +++ b/include/crm/common/nodes.h @@ -0,0 +1,144 @@ +/* + * Copyright 2004-2023 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 <glib.h> // gboolean, GList, GHashTable + +#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_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 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) +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_NODES__H diff --git a/include/crm/common/nvpair.h b/include/crm/common/nvpair.h index aebc199..185bdc3 100644 --- a/include/crm/common/nvpair.h +++ b/include/crm/common/nvpair.h @@ -46,7 +46,6 @@ void hash2smartfield(gpointer key, gpointer value, gpointer user_data); GHashTable *xml2list(const xmlNode *parent); const char *crm_xml_add(xmlNode *node, const char *name, const char *value); -const char *crm_xml_replace(xmlNode *node, const char *name, const char *value); const char *crm_xml_add_int(xmlNode *node, const char *name, int value); const char *crm_xml_add_ll(xmlNode *node, const char *name, long long value); const char *crm_xml_add_ms(xmlNode *node, const char *name, guint ms); diff --git a/include/crm/common/options_internal.h b/include/crm/common/options_internal.h index 4157b58..5c561fd 100644 --- a/include/crm/common/options_internal.h +++ b/include/crm/common/options_internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the Pacemaker project contributors + * Copyright 2006-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -26,7 +26,7 @@ _Noreturn void pcmk__cli_help(char cmd); */ const char *pcmk__env_option(const char *option); -void pcmk__set_env_option(const char *option, const char *value); +void pcmk__set_env_option(const char *option, const char *value, bool compat); bool pcmk__env_option_enabled(const char *daemon, const char *option); @@ -76,18 +76,52 @@ long pcmk__auto_watchdog_timeout(void); bool pcmk__valid_sbd_timeout(const char *value); // Constants for environment variable names +#define PCMK__ENV_AUTHKEY_LOCATION "authkey_location" #define PCMK__ENV_BLACKBOX "blackbox" +#define PCMK__ENV_CALLGRIND_ENABLED "callgrind_enabled" #define PCMK__ENV_CLUSTER_TYPE "cluster_type" #define PCMK__ENV_DEBUG "debug" +#define PCMK__ENV_DH_MAX_BITS "dh_max_bits" +#define PCMK__ENV_DH_MIN_BITS "dh_min_bits" +#define PCMK__ENV_FAIL_FAST "fail_fast" +#define PCMK__ENV_IPC_BUFFER "ipc_buffer" +#define PCMK__ENV_IPC_TYPE "ipc_type" #define PCMK__ENV_LOGFACILITY "logfacility" #define PCMK__ENV_LOGFILE "logfile" +#define PCMK__ENV_LOGFILE_MODE "logfile_mode" #define PCMK__ENV_LOGPRIORITY "logpriority" -#define PCMK__ENV_MCP "mcp" +#define PCMK__ENV_NODE_ACTION_LIMIT "node_action_limit" #define PCMK__ENV_NODE_START_STATE "node_start_state" +#define PCMK__ENV_PANIC_ACTION "panic_action" #define PCMK__ENV_PHYSICAL_HOST "physical_host" +#define PCMK__ENV_REMOTE_ADDRESS "remote_address" +#define PCMK__ENV_REMOTE_PID1 "remote_pid1" +#define PCMK__ENV_REMOTE_PORT "remote_port" +#define PCMK__ENV_RESPAWNED "respawned" +#define PCMK__ENV_SCHEMA_DIRECTORY "schema_directory" +#define PCMK__ENV_SERVICE "service" +#define PCMK__ENV_STDERR "stderr" +#define PCMK__ENV_TLS_PRIORITIES "tls_priorities" +#define PCMK__ENV_TRACE_BLACKBOX "trace_blackbox" +#define PCMK__ENV_TRACE_FILES "trace_files" +#define PCMK__ENV_TRACE_FORMATS "trace_formats" +#define PCMK__ENV_TRACE_FUNCTIONS "trace_functions" +#define PCMK__ENV_TRACE_TAGS "trace_tags" +#define PCMK__ENV_VALGRIND_ENABLED "valgrind_enabled" + +// @COMPAT Drop at 3.0.0; default is plenty +#define PCMK__ENV_CIB_TIMEOUT "cib_timeout" + +// @COMPAT Drop at 3.0.0; likely last used in 1.1.24 +#define PCMK__ENV_MCP "mcp" + +// @COMPAT Drop at 3.0.0; added unused in 1.1.9 #define PCMK__ENV_QUORUM_TYPE "quorum_type" + +/* @COMPAT Drop at 3.0.0; added to debug shutdown issues when Pacemaker is + * managed by systemd, but no longer useful. + */ #define PCMK__ENV_SHUTDOWN_DELAY "shutdown_delay" -#define PCMK__ENV_STDERR "stderr" // Constants for cluster option names #define PCMK__OPT_NODE_HEALTH_BASE "node-health-base" diff --git a/include/crm/common/output_internal.h b/include/crm/common/output_internal.h index e7b631e..274bd85 100644 --- a/include/crm/common/output_internal.h +++ b/include/crm/common/output_internal.h @@ -763,6 +763,11 @@ pcmk__output_get_log_level(const pcmk__output_t *out); void pcmk__output_set_log_level(pcmk__output_t *out, uint8_t log_level); +void pcmk__output_set_log_filter(pcmk__output_t *out, const char *file, + const char *function, uint32_t line, + uint32_t tags); + + /*! * \internal * \brief Create and return a new XML node with the given name, as a child of the diff --git a/include/crm/common/remote_internal.h b/include/crm/common/remote_internal.h index 8473668..030c7a4 100644 --- a/include/crm/common/remote_internal.h +++ b/include/crm/common/remote_internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2008-2022 the Pacemaker project contributors + * Copyright 2008-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -14,7 +14,7 @@ typedef struct pcmk__remote_s pcmk__remote_t; -int pcmk__remote_send_xml(pcmk__remote_t *remote, xmlNode *msg); +int pcmk__remote_send_xml(pcmk__remote_t *remote, const xmlNode *msg); int pcmk__remote_ready(const pcmk__remote_t *remote, int timeout_ms); int pcmk__read_remote_message(pcmk__remote_t *remote, int timeout_ms); xmlNode *pcmk__remote_message_xml(pcmk__remote_t *remote); diff --git a/include/crm/common/resources.h b/include/crm/common/resources.h new file mode 100644 index 0000000..043dc1c --- /dev/null +++ b/include/crm/common/resources.h @@ -0,0 +1,502 @@ +/* + * Copyright 2004-2023 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_RESOURCES__H +# define PCMK__CRM_COMMON_RESOURCES__H + +#include <sys/types.h> // time_t +#include <libxml/tree.h> // xmlNode +#include <glib.h> // gboolean, guint, GList, GHashTable + +#include <crm/common/roles.h> // enum rsc_role_e +#include <crm/common/scheduler_types.h> // pcmk_resource_t, etc. + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief Scheduler API for resources + * \ingroup core + */ + +//! Resource variants supported by Pacemaker +enum pe_obj_types { + // Order matters: some code compares greater or lesser than + pcmk_rsc_variant_unknown = -1, //!< Unknown resource variant + pcmk_rsc_variant_primitive = 0, //!< Primitive resource + pcmk_rsc_variant_group = 1, //!< Group resource + pcmk_rsc_variant_clone = 2, //!< Clone resource + pcmk_rsc_variant_bundle = 3, //!< Bundle resource + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_rsc_variant_unknown instead + pe_unknown = pcmk_rsc_variant_unknown, + + //! \deprecated Use pcmk_rsc_variant_primitive instead + pe_native = pcmk_rsc_variant_primitive, + + //! \deprecated Use pcmk_rsc_variant_group instead + pe_group = pcmk_rsc_variant_group, + + //! \deprecated Use pcmk_rsc_variant_clone instead + pe_clone = pcmk_rsc_variant_clone, + + //! \deprecated Use pcmk_rsc_variant_bundle instead + pe_container = pcmk_rsc_variant_bundle, +#endif +}; + +//! What resource needs before it can be recovered from a failed node +enum rsc_start_requirement { + pcmk_requires_nothing = 0, //!< Resource can be recovered immediately + pcmk_requires_quorum = 1, //!< Resource can be recovered if quorate + pcmk_requires_fencing = 2, //!< Resource can be recovered after fencing + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_requires_nothing instead + rsc_req_nothing = pcmk_requires_nothing, + + //! \deprecated Use pcmk_requires_quorum instead + rsc_req_quorum = pcmk_requires_quorum, + + //! \deprecated Use pcmk_requires_fencing instead + rsc_req_stonith = pcmk_requires_fencing, +#endif +}; + +//! How to recover a resource that is incorrectly active on multiple nodes +enum rsc_recovery_type { + pcmk_multiply_active_restart = 0, //!< Stop on all, start on desired + pcmk_multiply_active_stop = 1, //!< Stop on all and leave stopped + pcmk_multiply_active_block = 2, //!< Do nothing to resource + pcmk_multiply_active_unexpected = 3, //!< Stop unexpected instances + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_multiply_active_restart instead + recovery_stop_start = pcmk_multiply_active_restart, + + //! \deprecated Use pcmk_multiply_active_stop instead + recovery_stop_only = pcmk_multiply_active_stop, + + //! \deprecated Use pcmk_multiply_active_block instead + recovery_block = pcmk_multiply_active_block, + + //! \deprecated Use pcmk_multiply_active_unexpected instead + recovery_stop_unexpected = pcmk_multiply_active_unexpected, +#endif +}; + +//! Resource scheduling flags +enum pcmk_rsc_flags { + //! No resource flags set (compare with equality rather than bit set) + pcmk_no_rsc_flags = 0ULL, + + //! Whether resource has been removed from the configuration + pcmk_rsc_removed = (1ULL << 0), + + //! Whether resource is managed + pcmk_rsc_managed = (1ULL << 1), + + //! Whether resource is blocked from further action + pcmk_rsc_blocked = (1ULL << 2), + + //! Whether resource has been removed but has a container + pcmk_rsc_removed_filler = (1ULL << 3), + + //! Whether resource has clone notifications enabled + pcmk_rsc_notify = (1ULL << 4), + + //! Whether resource is not an anonymous clone instance + pcmk_rsc_unique = (1ULL << 5), + + //! Whether resource's class is "stonith" + pcmk_rsc_fence_device = (1ULL << 6), + + //! Whether resource can be promoted and demoted + pcmk_rsc_promotable = (1ULL << 7), + + //! Whether resource has not yet been assigned to a node + pcmk_rsc_unassigned = (1ULL << 8), + + //! Whether resource is in the process of being assigned to a node + pcmk_rsc_assigning = (1ULL << 9), + + //! Whether resource is in the process of modifying allowed node scores + pcmk_rsc_updating_nodes = (1ULL << 10), + + //! Whether resource is in the process of scheduling actions to restart + pcmk_rsc_restarting = (1ULL << 11), + + //! Whether resource must be stopped (instead of demoted) if it is failed + pcmk_rsc_stop_if_failed = (1ULL << 12), + + //! Whether a reload action has been scheduled for resource + pcmk_rsc_reload = (1ULL << 13), + + //! Whether resource is a remote connection allowed to run on a remote node + pcmk_rsc_remote_nesting_allowed = (1ULL << 14), + + //! Whether resource has "critical" meta-attribute enabled + pcmk_rsc_critical = (1ULL << 15), + + //! Whether resource is considered failed + pcmk_rsc_failed = (1ULL << 16), + + //! Flag for non-scheduler code to use to detect recursion loops + pcmk_rsc_detect_loop = (1ULL << 17), + + //! \deprecated Do not use + pcmk_rsc_runnable = (1ULL << 18), + + //! Whether resource has pending start action in history + pcmk_rsc_start_pending = (1ULL << 19), + + //! \deprecated Do not use + pcmk_rsc_starting = (1ULL << 20), + + //! \deprecated Do not use + pcmk_rsc_stopping = (1ULL << 21), + + //! Whether resource is multiply active with recovery set to stop_unexpected + pcmk_rsc_stop_unexpected = (1ULL << 22), + + //! Whether resource is allowed to live-migrate + pcmk_rsc_migratable = (1ULL << 23), + + //! Whether resource has an ignorable failure + pcmk_rsc_ignore_failure = (1ULL << 24), + + //! Whether resource is an implicit container resource for a bundle replica + pcmk_rsc_replica_container = (1ULL << 25), + + //! Whether resource, its node, or entire cluster is in maintenance mode + pcmk_rsc_maintenance = (1ULL << 26), + + //! \deprecated Do not use + pcmk_rsc_has_filler = (1ULL << 27), + + //! Whether resource can be started or promoted only on quorate nodes + pcmk_rsc_needs_quorum = (1ULL << 28), + + //! Whether resource requires fencing before recovery if on unclean node + pcmk_rsc_needs_fencing = (1ULL << 29), + + //! Whether resource can be started or promoted only on unfenced nodes + pcmk_rsc_needs_unfencing = (1ULL << 30), +}; + +//! Search options for resources (exact resource ID always matches) +enum pe_find { + //! Also match clone instance ID from resource history + pcmk_rsc_match_history = (1 << 0), + + //! Also match anonymous clone instances by base name + pcmk_rsc_match_anon_basename = (1 << 1), + + //! Match only clones and their instances, by either clone or instance ID + pcmk_rsc_match_clone_only = (1 << 2), + + //! If matching by node, compare current node instead of assigned node + pcmk_rsc_match_current_node = (1 << 3), + + //! \deprecated Do not use + pe_find_inactive = (1 << 4), + + //! Match clone instances (even unique) by base name as well as exact ID + pcmk_rsc_match_basename = (1 << 5), + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_rsc_match_history instead + pe_find_renamed = pcmk_rsc_match_history, + + //! \deprecated Use pcmk_rsc_match_anon_basename instead + pe_find_anon = pcmk_rsc_match_anon_basename, + + //! \deprecated Use pcmk_rsc_match_clone_only instead + pe_find_clone = pcmk_rsc_match_clone_only, + + //! \deprecated Use pcmk_rsc_match_current_node instead + pe_find_current = pcmk_rsc_match_current_node, + + //! \deprecated Use pcmk_rsc_match_basename instead + pe_find_any = pcmk_rsc_match_basename, +#endif +}; + +//!@{ +//! \deprecated Do not use +enum pe_restart { + pe_restart_restart, + pe_restart_ignore, +}; + +enum pe_print_options { + pe_print_log = (1 << 0), + pe_print_html = (1 << 1), + pe_print_ncurses = (1 << 2), + pe_print_printf = (1 << 3), + pe_print_dev = (1 << 4), // Ignored + pe_print_details = (1 << 5), // Ignored + pe_print_max_details = (1 << 6), // Ignored + pe_print_rsconly = (1 << 7), + pe_print_ops = (1 << 8), + pe_print_suppres_nl = (1 << 9), + pe_print_xml = (1 << 10), + pe_print_brief = (1 << 11), + pe_print_pending = (1 << 12), + pe_print_clone_details = (1 << 13), + pe_print_clone_active = (1 << 14), // Print clone instances only if active + pe_print_implicit = (1 << 15) // Print implicitly created resources +}; +//!@} + +// Resource assignment methods (implementation defined by libpacemaker) +//! This type should be considered internal to Pacemaker +typedef struct resource_alloc_functions_s pcmk_assignment_methods_t; + +//! Resource object methods +typedef struct resource_object_functions_s { + /*! + * \brief Parse variant-specific resource XML from CIB into struct members + * + * \param[in,out] rsc Partially unpacked resource + * \param[in,out] scheduler Scheduler data + * + * \return TRUE if resource was unpacked successfully, otherwise FALSE + */ + gboolean (*unpack)(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler); + + /*! + * \brief Search for a resource ID in a resource and its children + * + * \param[in] rsc Search this resource and its children + * \param[in] id Search for this resource ID + * \param[in] on_node If not NULL, limit search to resources on this node + * \param[in] flags Group of enum pe_find flags + * + * \return Resource that matches search criteria if any, otherwise NULL + */ + pcmk_resource_t *(*find_rsc)(pcmk_resource_t *rsc, const char *search, + const pcmk_node_t *node, int flags); + + /*! + * \brief Get value of a resource instance attribute + * + * \param[in,out] rsc Resource to check + * \param[in] node Node to use to evaluate rules + * \param[in] create Ignored + * \param[in] name Name of instance attribute to check + * \param[in,out] scheduler Scheduler data + * + * \return Value of requested attribute if available, otherwise NULL + * \note The caller is responsible for freeing the result using free(). + */ + char *(*parameter)(pcmk_resource_t *rsc, pcmk_node_t *node, gboolean create, + const char *name, pcmk_scheduler_t *scheduler); + + //! \deprecated Do not use + void (*print)(pcmk_resource_t *rsc, const char *pre_text, long options, + void *print_data); + + /*! + * \brief Check whether a resource is active + * + * \param[in] rsc Resource to check + * \param[in] all If \p rsc is collective, all instances must be active + * + * \return TRUE if \p rsc is active, otherwise FALSE + */ + gboolean (*active)(pcmk_resource_t *rsc, gboolean all); + + /*! + * \brief Get resource's current or assigned role + * + * \param[in] rsc Resource to check + * \param[in] current If TRUE, check current role, otherwise assigned role + * + * \return Current or assigned role of \p rsc + */ + enum rsc_role_e (*state)(const pcmk_resource_t *rsc, gboolean current); + + /*! + * \brief List nodes where a resource (or any of its children) is + * + * \param[in] rsc Resource to check + * \param[out] list List to add result to + * \param[in] current If 0, list nodes where \p rsc is assigned; + * if 1, where active; if 2, where active or pending + * + * \return If list contains only one node, that node, otherwise NULL + */ + pcmk_node_t *(*location)(const pcmk_resource_t *rsc, GList **list, + int current); + + /*! + * \brief Free all memory used by a resource + * + * \param[in,out] rsc Resource to free + */ + void (*free)(pcmk_resource_t *rsc); + + /*! + * \brief Increment cluster's instance counts for a resource + * + * Given a resource, increment its cluster's ninstances, disabled_resources, + * and blocked_resources counts for the resource and its descendants. + * + * \param[in,out] rsc Resource to count + */ + void (*count)(pcmk_resource_t *rsc); + + /*! + * \brief Check whether a given resource is in a list of resources + * + * \param[in] rsc Resource ID to check for + * \param[in] only_rsc List of resource IDs to check + * \param[in] check_parent If TRUE, check top ancestor as well + * + * \return TRUE if \p rsc, its top parent if requested, or '*' is in + * \p only_rsc, otherwise FALSE + */ + gboolean (*is_filtered)(const pcmk_resource_t *rsc, GList *only_rsc, + gboolean check_parent); + + /*! + * \brief Find a node (and optionally count all) where resource is active + * + * \param[in] rsc Resource to check + * \param[out] count_all If not NULL, set this to count of active nodes + * \param[out] count_clean If not NULL, set this to count of clean nodes + * + * \return A node where the resource is active, preferring the source node + * if the resource is involved in a partial migration, or a clean, + * online node if the resource's "requires" is "quorum" or + * "nothing", otherwise NULL. + */ + pcmk_node_t *(*active_node)(const pcmk_resource_t *rsc, + unsigned int *count_all, + unsigned int *count_clean); + + /*! + * \brief Get maximum resource instances per node + * + * \param[in] rsc Resource to check + * + * \return Maximum number of \p rsc instances that can be active on one node + */ + unsigned int (*max_per_node)(const pcmk_resource_t *rsc); +} pcmk_rsc_methods_t; + +//! Implementation of pcmk_resource_t +struct pe_resource_s { + char *id; //!< Resource ID in configuration + char *clone_name; //!< Resource instance ID in history + + //! Resource configuration (possibly expanded from template) + xmlNode *xml; + + //! Original resource configuration, if using template + xmlNode *orig_xml; + + //! Configuration of resource operations (possibly expanded from template) + xmlNode *ops_xml; + + pcmk_scheduler_t *cluster; //!< Cluster that resource is part of + pcmk_resource_t *parent; //!< Resource's parent resource, if any + enum pe_obj_types variant; //!< Resource variant + void *variant_opaque; //!< Variant-specific (and private) data + pcmk_rsc_methods_t *fns; //!< Resource object methods + pcmk_assignment_methods_t *cmds; //!< Resource assignment methods + + enum rsc_recovery_type recovery_type; //!< How to recover if failed + + enum pe_restart restart_type; //!< \deprecated Do not use + int priority; //!< Configured priority + int stickiness; //!< Extra preference for current node + int sort_index; //!< Promotion score on assigned node + int failure_timeout; //!< Failure timeout + int migration_threshold; //!< Migration threshold + guint remote_reconnect_ms; //!< Retry interval for remote connections + char *pending_task; //!< Pending action in history, if any + unsigned long long flags; //!< Group of enum pcmk_rsc_flags + + // @TODO Merge these into flags + gboolean is_remote_node; //!< Whether this is a remote connection + gboolean exclusive_discover; //!< Whether exclusive probing is enabled + + /* Pay special attention to whether you want to use rsc_cons_lhs and + * rsc_cons directly, which include only colocations explicitly involving + * this resource, or call libpacemaker's pcmk__with_this_colocations() and + * pcmk__this_with_colocations() functions, which may return relevant + * colocations involving the resource's ancestors as well. + */ + + //!@{ + //! This field should be treated as internal to Pacemaker + GList *rsc_cons_lhs; // Colocations of other resources with this one + GList *rsc_cons; // Colocations of this resource with others + GList *rsc_location; // Location constraints for resource + GList *actions; // Actions scheduled for resource + GList *rsc_tickets; // Ticket constraints for resource + //!@} + + pcmk_node_t *allocated_to; //!< Node resource is assigned to + + //! The destination node, if migrate_to completed but migrate_from has not + pcmk_node_t *partial_migration_target; + + //! The source node, if migrate_to completed but migrate_from has not + pcmk_node_t *partial_migration_source; + + //! Nodes where resource may be active + GList *running_on; + + //! Nodes where resource has been probed (key is node ID, not name) + GHashTable *known_on; + + //! Nodes where resource may run (key is node ID, not name) + GHashTable *allowed_nodes; + + enum rsc_role_e role; //!< Resource's current role + enum rsc_role_e next_role; //!< Resource's scheduled next role + + GHashTable *meta; //!< Resource's meta-attributes + GHashTable *parameters; //!< \deprecated Use pe_rsc_params() instead + GHashTable *utilization; //!< Resource's utilization attributes + + GList *children; //!< Resource's child resources, if any + + // Source nodes where stop is needed after migrate_from and migrate_to + GList *dangling_migrations; + + pcmk_resource_t *container; //!< Resource containing this one, if any + GList *fillers; //!< Resources contained by this one, if any + + // @COMPAT These should be made const at next API compatibility break + pcmk_node_t *pending_node; //!< Node on which pending_task is happening + pcmk_node_t *lock_node; //!< Resource shutdown-locked to this node + + time_t lock_time; //!< When shutdown lock started + + /*! + * Resource parameters may have node-attribute-based rules, which means the + * values can vary by node. This table has node names as keys and parameter + * name/value tables as values. Use pe_rsc_params() to get the table for a + * given node rather than use this directly. + */ + GHashTable *parameter_cache; +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_RESOURCES__H diff --git a/include/crm/common/results.h b/include/crm/common/results.h index 224bcbe..87d00d2 100644 --- a/include/crm/common/results.h +++ b/include/crm/common/results.h @@ -108,6 +108,9 @@ enum pcmk_rc_e { /* When adding new values, use consecutively lower numbers, update the array * in lib/common/results.c, and test with crm_error. */ + pcmk_rc_compression = -1039, + pcmk_rc_ns_resolution = -1038, + pcmk_rc_no_transaction = -1037, pcmk_rc_bad_xml_patch = -1036, pcmk_rc_bad_input = -1035, pcmk_rc_disabled = -1034, @@ -360,7 +363,6 @@ int pcmk_rc2legacy(int rc); int pcmk_legacy2rc(int legacy_rc); const char *pcmk_strerror(int rc); const char *pcmk_errorname(int rc); -const char *bz2_strerror(int rc); const char *crm_exit_name(crm_exit_t exit_code); const char *crm_exit_str(crm_exit_t exit_code); _Noreturn crm_exit_t crm_exit(crm_exit_t rc); diff --git a/include/crm/common/results_compat.h b/include/crm/common/results_compat.h index 00ac6b2..278e48e 100644 --- a/include/crm/common/results_compat.h +++ b/include/crm/common/results_compat.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 the Pacemaker project contributors + * Copyright 2022-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -25,6 +25,9 @@ extern "C" { * release. */ +//! \deprecated Do not use +const char *bz2_strerror(int rc); + //! \deprecated Use pcmk_rc2exitc(pcmk_legacy2rc(rc)) instead crm_exit_t crm_errno2exit(int rc); diff --git a/include/crm/common/results_internal.h b/include/crm/common/results_internal.h index be62780..09907e9 100644 --- a/include/crm/common/results_internal.h +++ b/include/crm/common/results_internal.h @@ -69,6 +69,9 @@ void pcmk__reset_result(pcmk__action_result_t *result); void pcmk__copy_result(const pcmk__action_result_t *src, pcmk__action_result_t *dst); +int pcmk__gaierror2rc(int gai); +int pcmk__bzlib2rc(int bz2); + /*! * \internal * \brief Check whether a result is OK diff --git a/include/crm/common/roles.h b/include/crm/common/roles.h new file mode 100644 index 0000000..1498097 --- /dev/null +++ b/include/crm/common/roles.h @@ -0,0 +1,62 @@ +/* + * Copyright 2004-2023 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_ROLES__H +# define PCMK__CRM_COMMON_ROLES__H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief Scheduler API for resource roles + * \ingroup core + */ + +/*! + * Possible roles that a resource can be in + * (order matters; values can be compared with less than and greater than) + */ +enum rsc_role_e { + pcmk_role_unknown = 0, //!< Resource role is unknown + pcmk_role_stopped = 1, //!< Stopped + pcmk_role_started = 2, //!< Started + pcmk_role_unpromoted = 3, //!< Unpromoted + pcmk_role_promoted = 4, //!< Promoted + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_role_unknown instead + RSC_ROLE_UNKNOWN = pcmk_role_unknown, + + //! \deprecated Use pcmk_role_stopped instead + RSC_ROLE_STOPPED = pcmk_role_stopped, + + //! \deprecated Use pcmk_role_started instead + RSC_ROLE_STARTED = pcmk_role_started, + + //! \deprecated Use pcmk_role_unpromoted instead + RSC_ROLE_UNPROMOTED = pcmk_role_unpromoted, + + //! \deprecated Use pcmk_role_unpromoted instead + RSC_ROLE_SLAVE = pcmk_role_unpromoted, + + //! \deprecated Use pcmk_role_promoted instead + RSC_ROLE_PROMOTED = pcmk_role_promoted, + + //! \deprecated Use pcmk_role_promoted instead + RSC_ROLE_MASTER = pcmk_role_promoted, +#endif +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_ROLES__H diff --git a/include/crm/common/roles_internal.h b/include/crm/common/roles_internal.h new file mode 100644 index 0000000..e304f13 --- /dev/null +++ b/include/crm/common/roles_internal.h @@ -0,0 +1,30 @@ +/* + * Copyright 2004-2023 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_ROLES_INTERNAL__H +# define PCMK__CRM_COMMON_ROLES_INTERNAL__H + +#ifdef __cplusplus +extern "C" { +#endif + +// String equivalents of enum rsc_role_e +#define PCMK__ROLE_UNKNOWN "Unknown" +#define PCMK__ROLE_STOPPED "Stopped" +#define PCMK__ROLE_STARTED "Started" +#define PCMK__ROLE_UNPROMOTED "Unpromoted" +#define PCMK__ROLE_PROMOTED "Promoted" +#define PCMK__ROLE_UNPROMOTED_LEGACY "Slave" +#define PCMK__ROLE_PROMOTED_LEGACY "Master" + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_ROLES_INTERNAL__H diff --git a/include/crm/common/scheduler.h b/include/crm/common/scheduler.h new file mode 100644 index 0000000..96f9a62 --- /dev/null +++ b/include/crm/common/scheduler.h @@ -0,0 +1,238 @@ +/* + * Copyright 2004-2023 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_SCHEDULER__H +# define PCMK__CRM_COMMON_SCHEDULER__H + +#include <sys/types.h> // time_t +#include <libxml/tree.h> // xmlNode +#include <glib.h> // guint, GList, GHashTable + +#include <crm/common/iso8601.h> // crm_time_t + +#include <crm/common/actions.h> +#include <crm/common/nodes.h> +#include <crm/common/resources.h> +#include <crm/common/roles.h> +#include <crm/common/scheduler_types.h> +#include <crm/common/tags.h> +#include <crm/common/tickets.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief Scheduler API + * \ingroup core + */ + +//! Possible responses to loss of quorum +enum pe_quorum_policy { + pcmk_no_quorum_freeze, //<! Do not recover resources from outside partition + pcmk_no_quorum_stop, //<! Stop all resources in partition + pcmk_no_quorum_ignore, //<! Act as if partition still holds quorum + pcmk_no_quorum_fence, //<! Fence all nodes in partition + pcmk_no_quorum_demote, //<! Demote promotable resources and stop all others + +#if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) + //! \deprecated Use pcmk_no_quorum_freeze instead + no_quorum_freeze = pcmk_no_quorum_freeze, + + //! \deprecated Use pcmk_no_quorum_stop instead + no_quorum_stop = pcmk_no_quorum_stop, + + //! \deprecated Use pcmk_no_quorum_ignore instead + no_quorum_ignore = pcmk_no_quorum_ignore, + + //! \deprecated Use pcmk_no_quorum_fence instead + no_quorum_suicide = pcmk_no_quorum_fence, + + //! \deprecated Use pcmk_no_quorum_demote instead + no_quorum_demote = pcmk_no_quorum_demote, +#endif +}; + +//! Scheduling options and conditions +enum pcmk_scheduler_flags { + //! No scheduler flags set (compare with equality rather than bit set) + pcmk_sched_none = 0ULL, + + // These flags are dynamically determined conditions + + //! Whether partition has quorum (via have-quorum property) + pcmk_sched_quorate = (1ULL << 0), + + //! Whether cluster is symmetric (via symmetric-cluster property) + pcmk_sched_symmetric_cluster = (1ULL << 1), + + //! Whether cluster is in maintenance mode (via maintenance-mode property) + pcmk_sched_in_maintenance = (1ULL << 3), + + //! Whether fencing is enabled (via stonith-enabled property) + pcmk_sched_fencing_enabled = (1ULL << 4), + + //! Whether cluster has a fencing resource (via CIB resources) + pcmk_sched_have_fencing = (1ULL << 5), + + //! Whether any resource provides or requires unfencing (via CIB resources) + pcmk_sched_enable_unfencing = (1ULL << 6), + + //! Whether concurrent fencing is allowed (via concurrent-fencing property) + pcmk_sched_concurrent_fencing = (1ULL << 7), + + /*! + * Whether resources removed from the configuration should be stopped (via + * stop-orphan-resources property) + */ + pcmk_sched_stop_removed_resources = (1ULL << 8), + + /*! + * Whether recurring actions removed from the configuration should be + * cancelled (via stop-orphan-actions property) + */ + pcmk_sched_cancel_removed_actions = (1ULL << 9), + + //! Whether to stop all resources (via stop-all-resources property) + pcmk_sched_stop_all = (1ULL << 10), + + /*! + * Whether start failure should be treated as if migration-threshold is 1 + * (via start-failure-is-fatal property) + */ + pcmk_sched_start_failure_fatal = (1ULL << 12), + + //! \deprecated Do not use + pcmk_sched_remove_after_stop = (1ULL << 13), + + //! Whether unseen nodes should be fenced (via startup-fencing property) + pcmk_sched_startup_fencing = (1ULL << 14), + + /*! + * Whether resources should be left stopped when their node shuts down + * cleanly (via shutdown-lock property) + */ + pcmk_sched_shutdown_lock = (1ULL << 15), + + /*! + * Whether resources' current state should be probed (when unknown) before + * scheduling any other actions (via the enable-startup-probes property) + */ + pcmk_sched_probe_resources = (1ULL << 16), + + //! Whether the CIB status section has been parsed yet + pcmk_sched_have_status = (1ULL << 17), + + //! Whether the cluster includes any Pacemaker Remote nodes (via CIB) + pcmk_sched_have_remote_nodes = (1ULL << 18), + + // The remaining flags are scheduling options that must be set explicitly + + /*! + * Whether to skip unpacking the CIB status section and stop the scheduling + * sequence after applying node-specific location criteria (skipping + * assignment, ordering, actions, etc.). + */ + pcmk_sched_location_only = (1ULL << 20), + + //! Whether sensitive resource attributes have been masked + pcmk_sched_sanitized = (1ULL << 21), + + //! Skip counting of total, disabled, and blocked resource instances + pcmk_sched_no_counts = (1ULL << 23), + + /*! + * Skip deprecated code kept solely for backward API compatibility + * (internal code should always set this) + */ + pcmk_sched_no_compat = (1ULL << 24), + + //! Whether node scores should be output instead of logged + pcmk_sched_output_scores = (1ULL << 25), + + //! Whether to show node and resource utilization (in log or output) + pcmk_sched_show_utilization = (1ULL << 26), + + /*! + * Whether to stop the scheduling sequence after unpacking the CIB, + * calculating cluster status, and applying node health (skipping + * applying node-specific location criteria, assignment, etc.) + */ + pcmk_sched_validate_only = (1ULL << 27), +}; + +//! Implementation of pcmk_scheduler_t +struct pe_working_set_s { + // Be careful about when each piece of information is available and final + + xmlNode *input; //!< CIB XML + crm_time_t *now; //!< Current time for evaluation purposes + char *dc_uuid; //!< Node ID of designated controller + pcmk_node_t *dc_node; //!< Node object for DC + const char *stonith_action; //!< Default fencing action + const char *placement_strategy; //!< Value of placement-strategy property + + // @COMPAT Change to uint64_t at a compatibility break + unsigned long long flags; //!< Group of enum pcmk_scheduler_flags + + int stonith_timeout; //!< Value of stonith-timeout property + enum pe_quorum_policy no_quorum_policy; //!< Response to loss of quorum + GHashTable *config_hash; //!< Cluster properties + + //!< Ticket constraints unpacked from ticket state + GHashTable *tickets; + + //! Actions for which there can be only one (such as "fence node X") + GHashTable *singletons; + + GList *nodes; //!< Nodes in cluster + GList *resources; //!< Resources in cluster + GList *placement_constraints; //!< Location constraints + GList *ordering_constraints; //!< Ordering constraints + GList *colocation_constraints; //!< Colocation constraints + + //!< Ticket constraints unpacked by libpacemaker + GList *ticket_constraints; + + GList *actions; //!< Scheduled actions + xmlNode *failed; //!< History entries of failed actions + xmlNode *op_defaults; //!< Configured operation defaults + xmlNode *rsc_defaults; //!< Configured resource defaults + int num_synapse; //!< Number of transition graph synapses + int max_valid_nodes; //!< \deprecated Do not use + int order_id; //!< ID to use for next created ordering + int action_id; //!< ID to use for next created action + xmlNode *graph; //!< Transition graph + GHashTable *template_rsc_sets; //!< Mappings of template ID to resource ID + + // @COMPAT Replace this with a fencer variable (only place it's used) + const char *localhost; //!< \deprecated Do not use + + GHashTable *tags; //!< Configuration tags (ID -> pcmk_tag_t *) + int blocked_resources; //!< Number of blocked resources in cluster + int disabled_resources; //!< Number of disabled resources in cluster + GList *param_check; //!< History entries that need to be checked + GList *stop_needed; //!< Containers that need stop actions + time_t recheck_by; //!< Hint to controller when to reschedule + int ninstances; //!< Total number of resource instances + guint shutdown_lock; //!< How long to lock resources (seconds) + int priority_fencing_delay; //!< Priority fencing delay + + // pcmk__output_t * + void *priv; //!< For Pacemaker use only + + guint node_pending_timeout; //!< Pending join times out after this (ms) +}; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_SCHEDULER__H diff --git a/include/crm/common/scheduler_internal.h b/include/crm/common/scheduler_internal.h new file mode 100644 index 0000000..1f1da9f --- /dev/null +++ b/include/crm/common/scheduler_internal.h @@ -0,0 +1,67 @@ +/* + * Copyright 2004-2023 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_SCHEDULER_INTERNAL__H +# define PCMK__CRM_COMMON_SCHEDULER_INTERNAL__H + +#include <crm/common/action_relation_internal.h> +#include <crm/common/clone_internal.h> +#include <crm/common/digests_internal.h> +#include <crm/common/failcounts_internal.h> +#include <crm/common/group_internal.h> +#include <crm/common/roles_internal.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Some warnings are too noisy when logged every time a give function is called + * (for example, using a deprecated feature). As an alternative, we allow + * warnings to be logged once per scheduler sequence (transition). Each of those + * warnings needs a flag defined here. + */ +enum pcmk__sched_warnings { + pcmk__wo_blind = (1 << 0), + pcmk__wo_restart_type = (1 << 1), + pcmk__wo_role_after = (1 << 2), + pcmk__wo_poweroff = (1 << 3), + pcmk__wo_require_all = (1 << 4), + pcmk__wo_order_score = (1 << 5), + pcmk__wo_neg_threshold = (1 << 6), + pcmk__wo_remove_after = (1 << 7), + pcmk__wo_ping_node = (1 << 8), + pcmk__wo_order_inst = (1 << 9), + pcmk__wo_coloc_inst = (1 << 10), + pcmk__wo_group_order = (1 << 11), + pcmk__wo_group_coloc = (1 << 12), + pcmk__wo_upstart = (1 << 13), + pcmk__wo_nagios = (1 << 14), + pcmk__wo_set_ordering = (1 << 15), +}; + +enum pcmk__check_parameters { + /* Clear fail count if parameters changed for un-expired start or monitor + * last_failure. + */ + pcmk__check_last_failure, + + /* Clear fail count if parameters changed for start, monitor, promote, or + * migrate_from actions for active resources. + */ + pcmk__check_active, +}; + +// Group of enum pcmk__sched_warnings flags for warnings we want to log once +extern uint32_t pcmk__warnings; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_SCHEDULER_INTERNAL__H diff --git a/include/crm/common/scheduler_types.h b/include/crm/common/scheduler_types.h new file mode 100644 index 0000000..5c4a193 --- /dev/null +++ b/include/crm/common/scheduler_types.h @@ -0,0 +1,39 @@ +/* + * Copyright 2023 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_SCHEDULER_TYPES__H +# define PCMK__CRM_COMMON_SCHEDULER_TYPES__H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief Type aliases needed to define scheduler objects + * \ingroup core + */ + +//! Node object (including information that may vary depending on resource) +typedef struct pe_node_s pcmk_node_t; + +//! Resource object +typedef struct pe_resource_s pcmk_resource_t; + +//! Action object +typedef struct pe_action_s pcmk_action_t; + +//! Scheduler object +typedef struct pe_working_set_s pcmk_scheduler_t; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_SCHEDULER_TYPES__H diff --git a/include/crm/common/tags.h b/include/crm/common/tags.h new file mode 100644 index 0000000..3f4861d --- /dev/null +++ b/include/crm/common/tags.h @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2023 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_TAGS__H +# define PCMK__CRM_COMMON_TAGS__H + +#include <glib.h> // GList + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief Scheduler API for configuration tags + * \ingroup core + */ + +//! Configuration tag object +typedef struct pe_tag_s { + char *id; //!< XML ID of tag + GList *refs; //!< XML IDs of objects that reference the tag +} pcmk_tag_t; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_TAGS__H diff --git a/include/crm/common/tickets.h b/include/crm/common/tickets.h new file mode 100644 index 0000000..40079e9 --- /dev/null +++ b/include/crm/common/tickets.h @@ -0,0 +1,39 @@ +/* + * Copyright 2004-2023 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_TICKETS__H +# define PCMK__CRM_COMMON_TICKETS__H + +#include <sys/types.h> // time_t +#include <glib.h> // gboolean, GHashTable + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief Scheduler API for tickets + * \ingroup core + */ + +//! Ticket constraint object +typedef struct pe_ticket_s { + char *id; //!< XML ID of ticket constraint or state + gboolean granted; //!< Whether cluster has been granted the ticket + time_t last_granted; //!< When cluster was last granted the ticket + gboolean standby; //!< Whether ticket is temporarily suspended + GHashTable *state; //!< XML attributes from ticket state +} pcmk_ticket_t; + +#ifdef __cplusplus +} +#endif + +#endif // PCMK__CRM_COMMON_TICKETS__H diff --git a/include/crm/common/unittest_internal.h b/include/crm/common/unittest_internal.h index b8f78cf..1fc8501 100644 --- a/include/crm/common/unittest_internal.h +++ b/include/crm/common/unittest_internal.h @@ -1,5 +1,5 @@ /* - * Copyright 2022 the Pacemaker project contributors + * Copyright 2022-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -65,6 +65,44 @@ } \ } while (0); +/*! + * \internal + * \brief Assert that a statement exits with the expected exit status. + * + * \param[in] stmt Statement to execute; can be an expression. + * \param[in] rc The expected exit status. + * + * This functions just like \c pcmk__assert_asserts, except that it tests for + * an expected exit status. Abnormal termination or incorrect exit status is + * treated as a failure of the test. + * + * In the event that stmt does not exit at all, the special code \c CRM_EX_NONE + * will be returned. It is expected that this code is not used anywhere, thus + * always causing an error. + */ +#define pcmk__assert_exits(rc, stmt) \ + do { \ + pid_t p = fork(); \ + if (p == 0) { \ + struct rlimit cores = { 0, 0 }; \ + setrlimit(RLIMIT_CORE, &cores); \ + stmt; \ + _exit(CRM_EX_NONE); \ + } else if (p > 0) { \ + int wstatus = 0; \ + if (waitpid(p, &wstatus, 0) == -1) { \ + fail_msg("waitpid failed"); \ + } \ + if (!WIFEXITED(wstatus)) { \ + fail_msg("statement terminated abnormally"); \ + } else if (WEXITSTATUS(wstatus) != rc) { \ + fail_msg("statement exited with %d, not expected %d", WEXITSTATUS(wstatus), rc); \ + } \ + } else { \ + fail_msg("unable to fork for assert test"); \ + } \ + } while (0); + /* Generate the main function of most unit test files. Typically, group_setup * and group_teardown will be NULL. The rest of the arguments are a list of * calls to cmocka_unit_test or cmocka_unit_test_setup_teardown to run the diff --git a/include/crm/common/util.h b/include/crm/common/util.h index 8acdff9..c75a55e 100644 --- a/include/crm/common/util.h +++ b/include/crm/common/util.h @@ -18,10 +18,8 @@ # include <signal.h> # include <glib.h> -# include <libxml/tree.h> - -# include <crm/lrmd.h> # include <crm/common/acl.h> +# include <crm/common/actions.h> # include <crm/common/agents.h> # include <crm/common/results.h> @@ -59,26 +57,6 @@ char *crm_strdup_printf(char const *format, ...) G_GNUC_PRINTF(1, 2); guint crm_parse_interval_spec(const char *input); -/* public operation functions (from operations.c) */ -gboolean parse_op_key(const char *key, char **rsc_id, char **op_type, - guint *interval_ms); -gboolean decode_transition_key(const char *key, char **uuid, int *transition_id, - int *action_id, int *target_rc); -gboolean decode_transition_magic(const char *magic, char **uuid, - int *transition_id, int *action_id, - int *op_status, int *op_rc, int *target_rc); -int rsc_op_expected_rc(const lrmd_event_data_t *event); -gboolean did_rsc_op_fail(lrmd_event_data_t *event, int target_rc); -bool crm_op_needs_metadata(const char *rsc_class, const char *op); -xmlNode *crm_create_op_xml(xmlNode *parent, const char *prefix, - const char *task, const char *interval_spec, - const char *timeout); -#define CRM_DEFAULT_OP_TIMEOUT_S "20s" - -bool pcmk_is_probe(const char *task, guint interval); -bool pcmk_xe_is_probe(const xmlNode *xml_op); -bool pcmk_xe_mask_probe_failure(const xmlNode *xml_op); - int compare_version(const char *version1, const char *version2); /* coverity[+kill] */ diff --git a/include/crm/common/util_compat.h b/include/crm/common/util_compat.h index 9e02e12..7a60208 100644 --- a/include/crm/common/util_compat.h +++ b/include/crm/common/util_compat.h @@ -1,5 +1,5 @@ /* - * Copyright 2004-2021 the Pacemaker project contributors + * Copyright 2004-2023 the Pacemaker project contributors * * The version control history for this file may have further details. * @@ -11,6 +11,7 @@ # define PCMK__CRM_COMMON_UTIL_COMPAT__H # include <glib.h> +# include <libxml/tree.h> # include <crm/common/util.h> #ifdef __cplusplus @@ -29,6 +30,9 @@ extern "C" { //! \deprecated Use crm_parse_interval_spec() instead #define crm_get_interval crm_parse_interval_spec +//! \deprecated Do not use +#define CRM_DEFAULT_OP_TIMEOUT_S "20s" + //! \deprecated Use !pcmk_is_set() or !pcmk_all_flags_set() instead static inline gboolean is_not_set(long long word, long long bit) @@ -69,6 +73,9 @@ int pcmk_scan_nvpair(const char *input, char **name, char **value); char *pcmk_format_nvpair(const char *name, const char *value, const char *units); +//! \deprecated Use \c crm_xml_add() or \c xml_remove_prop() instead +const char *crm_xml_replace(xmlNode *node, const char *name, const char *value); + //! \deprecated Use a standard printf()-style function instead char *pcmk_format_named_time(const char *name, time_t epoch_time); diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h index 682b31c..ac839d3 100644 --- a/include/crm/common/xml.h +++ b/include/crm/common/xml.h @@ -52,8 +52,6 @@ typedef const xmlChar *pcmkXmlStr; gboolean add_message_xml(xmlNode * msg, const char *field, xmlNode * xml); xmlNode *get_message_xml(const xmlNode *msg, const char *field); -xmlDoc *getDocPtr(xmlNode * node); - /* * \brief xmlCopyPropList ACLs-sensitive replacement expading i++ notation * @@ -132,12 +130,13 @@ xmlNode *stdin2xml(void); xmlNode *string2xml(const char *input); -int write_xml_fd(xmlNode * xml_node, const char *filename, int fd, gboolean compress); -int write_xml_file(xmlNode * xml_node, const char *filename, gboolean compress); +int write_xml_fd(const xmlNode *xml, const char *filename, int fd, + gboolean compress); +int write_xml_file(const xmlNode *xml, const char *filename, gboolean compress); -char *dump_xml_formatted(xmlNode * msg); -char *dump_xml_formatted_with_text(xmlNode * msg); -char *dump_xml_unformatted(xmlNode * msg); +char *dump_xml_formatted(const xmlNode *xml); +char *dump_xml_formatted_with_text(const xmlNode *xml); +char *dump_xml_unformatted(const xmlNode *xml); /* * Diff related Functions @@ -170,25 +169,17 @@ xmlNode *get_xpath_object(const char *xpath, xmlNode * xml_obj, int error_level) xmlNode *get_xpath_object_relative(const char *xpath, xmlNode * xml_obj, int error_level); static inline const char * -crm_element_name(const xmlNode *xml) -{ - return xml? (const char *)(xml->name) : NULL; -} - -static inline const char * crm_map_element_name(const xmlNode *xml) { - const char *name = crm_element_name(xml); - - if (strcmp(name, "master") == 0) { + if (xml == NULL) { + return NULL; + } else if (strcmp((const char *) xml->name, "master") == 0) { return "clone"; } else { - return name; + return (const char *) xml->name; } } -gboolean xml_has_children(const xmlNode * root); - char *calculate_on_disk_digest(xmlNode * local_cib); char *calculate_operation_digest(xmlNode * local_cib, const char *version); char *calculate_xml_versioned_digest(xmlNode * input, gboolean sort, gboolean do_filter, @@ -196,7 +187,7 @@ char *calculate_xml_versioned_digest(xmlNode * input, gboolean sort, gboolean do /* schema-related functions (from schemas.c) */ gboolean validate_xml(xmlNode * xml_blob, const char *validation, gboolean to_logs); -gboolean validate_xml_verbose(xmlNode * xml_blob); +gboolean validate_xml_verbose(const xmlNode *xml_blob); /*! * \brief Update CIB XML to most recent schema version @@ -258,7 +249,7 @@ xmlNode *first_named_child(const xmlNode *parent, const char *name); xmlNode *crm_next_same_xml(const xmlNode *sibling); xmlNode *sorted_xml(xmlNode * input, xmlNode * parent, gboolean recursive); -xmlXPathObjectPtr xpath_search(xmlNode * xml_top, const char *path); +xmlXPathObjectPtr xpath_search(const xmlNode *xml_top, const char *path); void crm_foreach_xpath_result(xmlNode *xml, const char *xpath, void (*helper)(xmlNode*, void*), void *user_data); xmlNode *expand_idref(xmlNode * input, xmlNode * top); @@ -289,7 +280,8 @@ int xml_apply_patchset(xmlNode *xml, xmlNode *patchset, bool check_version); void patchset_process_digest(xmlNode *patch, xmlNode *source, xmlNode *target, bool with_digest); -void save_xml_to_file(xmlNode * xml, const char *desc, const char *filename); +void save_xml_to_file(const xmlNode *xml, const char *desc, + const char *filename); char * crm_xml_escape(const char *text); void crm_xml_sanitize_id(char *id); diff --git a/include/crm/common/xml_compat.h b/include/crm/common/xml_compat.h index bb49b68..85e39ff 100644 --- a/include/crm/common/xml_compat.h +++ b/include/crm/common/xml_compat.h @@ -31,6 +31,9 @@ extern "C" { #define XML_PARANOIA_CHECKS 0 //! \deprecated This function will be removed in a future release +xmlDoc *getDocPtr(xmlNode *node); + +//! \deprecated This function will be removed in a future release int add_node_nocopy(xmlNode * parent, const char *name, xmlNode * child); //! \deprecated This function will be removed in a future release @@ -51,13 +54,23 @@ gboolean apply_xml_diff(xmlNode *old_xml, xmlNode *diff, xmlNode **new_xml); //! \deprecated Do not use (will be removed in a future release) void crm_destroy_xml(gpointer data); -//! \deprecated Use crm_xml_add() with "true" or "false" instead +//! \deprecated Check children member directly +gboolean xml_has_children(const xmlNode *root); + +//! \deprecated Use crm_xml_add() with "true" or "false" instead static inline const char * crm_xml_add_boolean(xmlNode *node, const char *name, gboolean value) { return crm_xml_add(node, name, (value? "true" : "false")); } +//! \deprecated Use name member directly +static inline const char * +crm_element_name(const xmlNode *xml) +{ + return (xml == NULL)? NULL : (const char *) xml->name; +} + #ifdef __cplusplus } #endif diff --git a/include/crm/common/xml_internal.h b/include/crm/common/xml_internal.h index 43b3b8c..ddb4384 100644 --- a/include/crm/common/xml_internal.h +++ b/include/crm/common/xml_internal.h @@ -21,6 +21,7 @@ # include <crm/crm.h> /* transitively imports qblog.h */ # include <crm/common/output_internal.h> +# include <libxml/relaxng.h> /*! * \brief Base for directing lib{xml2,xslt} log into standard libqb backend @@ -135,9 +136,6 @@ enum pcmk__xml_fmt_options { //! Include indentation and newlines pcmk__xml_fmt_pretty = (1 << 1), - //! Include full XML subtree (with any text), using libxml serialization - pcmk__xml_fmt_full = (1 << 2), - //! Include the opening tag of an XML element, and include XML comments pcmk__xml_fmt_open = (1 << 3), @@ -147,7 +145,6 @@ enum pcmk__xml_fmt_options { //! Include the closing tag of an XML element pcmk__xml_fmt_close = (1 << 5), - // @COMPAT Remove when log_data_element() is removed //! Include XML text nodes pcmk__xml_fmt_text = (1 << 6), @@ -190,6 +187,16 @@ int pcmk__xml_show_changes(pcmk__output_t *out, const xmlNode *xml); #define PCMK__XP_REMOTE_NODE_STATUS \ "//" XML_TAG_CIB "//" XML_CIB_TAG_STATUS "//" XML_CIB_TAG_STATE \ "[@" XML_NODE_IS_REMOTE "='true']" +/*! + * \internal + * \brief Serialize XML (using libxml) into provided descriptor + * + * \param[in] fd File descriptor to (piece-wise) write to + * \param[in] cur XML subtree to proceed + * + * \return a standard Pacemaker return code + */ +int pcmk__xml2fd(int fd, xmlNode *cur); enum pcmk__xml_artefact_ns { pcmk__xml_artefact_ns_legacy_rng = 1, @@ -235,6 +242,22 @@ char *pcmk__xml_artefact_path(enum pcmk__xml_artefact_ns ns, /*! * \internal + * \brief Check whether an XML element is of a particular type + * + * \param[in] xml XML element to compare + * \param[in] name XML element name to compare + * + * \return \c true if \p xml is of type \p name, otherwise \c false + */ +static inline bool +pcmk__xe_is(const xmlNode *xml, const char *name) +{ + return (xml != NULL) && (xml->name != NULL) && (name != NULL) + && (strcmp((const char *) xml->name, name) == 0); +} + +/*! + * \internal * \brief Return first non-text child node of an XML node * * \param[in] parent XML node to check @@ -411,4 +434,15 @@ pcmk__xe_foreach_child(xmlNode *xml, const char *child_element_name, int (*handler)(xmlNode *xml, void *userdata), void *userdata); +static inline const char * +pcmk__xml_attr_value(const xmlAttr *attr) +{ + return ((attr == NULL) || (attr->children == NULL))? NULL + : (const char *) attr->children->content; +} + +gboolean pcmk__validate_xml(xmlNode *xml_blob, const char *validation, + xmlRelaxNGValidityErrorFunc error_handler, + void *error_handler_context); + #endif // PCMK__XML_INTERNAL__H |