diff --git a/include/crm/common/options_internal.h b/include/crm/common/options_internal.h index 2f95fe0c29..3a0c9aa5a7 100644 --- a/include/crm/common/options_internal.h +++ b/include/crm/common/options_internal.h @@ -1,153 +1,152 @@ /* * Copyright 2006-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PCMK__OPTIONS_INTERNAL__H # define PCMK__OPTIONS_INTERNAL__H # ifndef PCMK__CONFIG_H # define PCMK__CONFIG_H # include // _Noreturn # endif # include // GHashTable # include // bool _Noreturn void pcmk__cli_help(char cmd); /* * Environment variable option handling */ const char *pcmk__env_option(const char *option); void pcmk__set_env_option(const char *option, const char *value, bool compat); bool pcmk__env_option_enabled(const char *daemon, const char *option); /* * Cluster option handling */ typedef struct pcmk__cluster_option_s { const char *name; const char *alt_name; const char *type; const char *values; const char *default_value; bool (*is_valid)(const char *); const char *description_short; const char *description_long; } pcmk__cluster_option_t; const char *pcmk__cluster_option(GHashTable *options, const pcmk__cluster_option_t *option_list, int len, const char *name); gchar *pcmk__format_option_metadata(const char *name, const char *desc_short, const char *desc_long, pcmk__cluster_option_t *option_list, int len); void pcmk__validate_cluster_options(GHashTable *options, pcmk__cluster_option_t *option_list, int len); bool pcmk__valid_interval_spec(const char *value); bool pcmk__valid_boolean(const char *value); bool pcmk__valid_number(const char *value); bool pcmk__valid_positive_number(const char *value); bool pcmk__valid_quorum(const char *value); bool pcmk__valid_script(const char *value); bool pcmk__valid_percentage(const char *value); // from watchdog.c long pcmk__get_sbd_timeout(void); bool pcmk__get_sbd_sync_resource_startup(void); 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_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_SCHEMA_DIR "remote_schema_directory" #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" // Constants for cluster option names -#define PCMK__OPT_NODE_HEALTH_STRATEGY "node-health-strategy" #define PCMK__OPT_NODE_HEALTH_YELLOW "node-health-yellow" // @COMPAT Deprecated since 2.1.0 #define PCMK__OPT_REMOVE_AFTER_STOP "remove-after-stop" // Constants for meta-attribute names #define PCMK__META_ALLOW_UNHEALTHY_NODES "allow-unhealthy-nodes" // Constants for enumerated values for various options #define PCMK__VALUE_CLUSTER "cluster" #define PCMK__VALUE_CUSTOM "custom" #define PCMK__VALUE_FENCING "fencing" #define PCMK__VALUE_GREEN "green" #define PCMK__VALUE_LOCAL "local" #define PCMK__VALUE_MIGRATE_ON_RED "migrate-on-red" #define PCMK__VALUE_NONE "none" #define PCMK__VALUE_NOTHING "nothing" #define PCMK__VALUE_ONLY_GREEN "only-green" #define PCMK__VALUE_PROGRESSIVE "progressive" #define PCMK__VALUE_QUORUM "quorum" #define PCMK__VALUE_RED "red" #define PCMK__VALUE_UNFENCING "unfencing" #define PCMK__VALUE_YELLOW "yellow" #endif // PCMK__OPTIONS_INTERNAL__H diff --git a/include/crm/msg_xml.h b/include/crm/msg_xml.h index f074b7914b..83b0819332 100644 --- a/include/crm/msg_xml.h +++ b/include/crm/msg_xml.h @@ -1,520 +1,521 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PCMK__CRM_MSG_XML__H # define PCMK__CRM_MSG_XML__H # include #if !defined(PCMK_ALLOW_DEPRECATED) || (PCMK_ALLOW_DEPRECATED == 1) #include #endif #ifdef __cplusplus extern "C" { #endif /* This file defines constants for various XML syntax (mainly element and * attribute names). * * For consistency, new constants should start with "PCMK_", followed by "XE" * for XML element names, "XA" for XML attribute names, and "META" for meta * attribute names. Old names that don't follow this policy should eventually be * deprecated and replaced with names that do. */ /* * XML elements */ #define PCMK_XE_DATE_EXPRESSION "date_expression" #define PCMK_XE_OP_EXPRESSION "op_expression" /* This has been deprecated as a CIB element (an alias for with * "promotable" set to "true") since 2.0.0. */ #define PCMK_XE_PROMOTABLE_LEGACY "master" #define PCMK_XE_RSC_EXPRESSION "rsc_expression" /* * XML attributes */ #define PCMK_XA_FORMAT "format" /* These have been deprecated as CIB element attributes (aliases for * "promoted-max" and "promoted-node-max") since 2.0.0. */ #define PCMK_XA_PROMOTED_MAX_LEGACY "master-max" #define PCMK_XA_PROMOTED_NODE_MAX_LEGACY "master-node-max" /* * Meta attributes */ #define PCMK_META_CLONE_MAX "clone-max" #define PCMK_META_CLONE_MIN "clone-min" #define PCMK_META_CLONE_NODE_MAX "clone-node-max" #define PCMK_META_ENABLED "enabled" #define PCMK_META_FAILURE_TIMEOUT "failure-timeout" #define PCMK_META_MIGRATION_THRESHOLD "migration-threshold" #define PCMK_META_PROMOTED_MAX "promoted-max" #define PCMK_META_PROMOTED_NODE_MAX "promoted-node-max" /* * Cluster options */ #define PCMK_OPT_BATCH_LIMIT "batch-limit" #define PCMK_OPT_CLUSTER_DELAY "cluster-delay" #define PCMK_OPT_CLUSTER_INFRASTRUCTURE "cluster-infrastructure" #define PCMK_OPT_CLUSTER_IPC_LIMIT "cluster-ipc-limit" #define PCMK_OPT_CLUSTER_NAME "cluster-name" #define PCMK_OPT_CLUSTER_RECHECK_INTERVAL "cluster-recheck-interval" #define PCMK_OPT_CONCURRENT_FENCING "concurrent-fencing" #define PCMK_OPT_DC_DEADTIME "dc-deadtime" #define PCMK_OPT_DC_VERSION "dc-version" #define PCMK_OPT_ELECTION_TIMEOUT "election-timeout" #define PCMK_OPT_ENABLE_ACL "enable-acl" #define PCMK_OPT_ENABLE_STARTUP_PROBES "enable-startup-probes" #define PCMK_OPT_FENCE_REACTION "fence-reaction" #define PCMK_OPT_HAVE_WATCHDOG "have-watchdog" #define PCMK_OPT_JOIN_FINALIZATION_TIMEOUT "join-finalization-timeout" #define PCMK_OPT_JOIN_INTEGRATION_TIMEOUT "join-integration-timeout" #define PCMK_OPT_LOAD_THRESHOLD "load-threshold" #define PCMK_OPT_MAINTENANCE_MODE "maintenance-mode" #define PCMK_OPT_MIGRATION_LIMIT "migration-limit" #define PCMK_OPT_NO_QUORUM_POLICY "no-quorum-policy" #define PCMK_OPT_NODE_ACTION_LIMIT "node-action-limit" #define PCMK_OPT_NODE_HEALTH_BASE "node-health-base" #define PCMK_OPT_NODE_HEALTH_GREEN "node-health-green" #define PCMK_OPT_NODE_HEALTH_RED "node-health-red" +#define PCMK_OPT_NODE_HEALTH_STRATEGY "node-health-strategy" #define PCMK_OPT_NODE_PENDING_TIMEOUT "node-pending-timeout" #define PCMK_OPT_PE_ERROR_SERIES_MAX "pe-error-series-max" #define PCMK_OPT_PE_INPUT_SERIES_MAX "pe-input-series-max" #define PCMK_OPT_PE_WARN_SERIES_MAX "pe-warn-series-max" #define PCMK_OPT_PLACEMENT_STRATEGY "placement-strategy" #define PCMK_OPT_PRIORITY_FENCING_DELAY "priority-fencing-delay" #define PCMK_OPT_SHUTDOWN_ESCALATION "shutdown-escalation" #define PCMK_OPT_SHUTDOWN_LOCK "shutdown-lock" #define PCMK_OPT_SHUTDOWN_LOCK_LIMIT "shutdown-lock-limit" #define PCMK_OPT_START_FAILURE_IS_FATAL "start-failure-is-fatal" #define PCMK_OPT_STARTUP_FENCING "startup-fencing" #define PCMK_OPT_STONITH_ACTION "stonith-action" #define PCMK_OPT_STONITH_ENABLED "stonith-enabled" #define PCMK_OPT_STONITH_MAX_ATTEMPTS "stonith-max-attempts" #define PCMK_OPT_STONITH_TIMEOUT "stonith-timeout" #define PCMK_OPT_STONITH_WATCHDOG_TIMEOUT "stonith-watchdog-timeout" #define PCMK_OPT_STOP_ALL_RESOURCES "stop-all-resources" #define PCMK_OPT_STOP_ORPHAN_ACTIONS "stop-orphan-actions" #define PCMK_OPT_STOP_ORPHAN_RESOURCES "stop-orphan-resources" #define PCMK_OPT_SYMMETRIC_CLUSTER "symmetric-cluster" #define PCMK_OPT_TRANSITION_DELAY "transition-delay" /* * Older constants that don't follow current naming */ # ifndef F_ORIG # define F_ORIG "src" # endif # ifndef F_SEQ # define F_SEQ "seq" # endif # ifndef F_SUBTYPE # define F_SUBTYPE "subt" # endif # ifndef F_TYPE # define F_TYPE "t" # endif # ifndef F_CLIENTNAME # define F_CLIENTNAME "cn" # endif # ifndef F_XML_TAGNAME # define F_XML_TAGNAME "__name__" # endif # ifndef T_CRM # define T_CRM "crmd" # endif # ifndef T_ATTRD # define T_ATTRD "attrd" # endif # define CIB_OPTIONS_FIRST "cib-bootstrap-options" # define F_CRM_DATA "crm_xml" # define F_CRM_TASK "crm_task" # define F_CRM_HOST_TO "crm_host_to" # define F_CRM_MSG_TYPE F_SUBTYPE # define F_CRM_SYS_TO "crm_sys_to" # define F_CRM_SYS_FROM "crm_sys_from" # define F_CRM_HOST_FROM F_ORIG # define F_CRM_REFERENCE XML_ATTR_REFERENCE # define F_CRM_VERSION XML_ATTR_VERSION # define F_CRM_ORIGIN "origin" # define F_CRM_USER "crm_user" # define F_CRM_JOIN_ID "join_id" # define F_CRM_DC_LEAVING "dc-leaving" # define F_CRM_ELECTION_ID "election-id" # define F_CRM_ELECTION_AGE_S "election-age-sec" # define F_CRM_ELECTION_AGE_US "election-age-nano-sec" # define F_CRM_ELECTION_OWNER "election-owner" # define F_CRM_TGRAPH "crm-tgraph-file" # define F_CRM_TGRAPH_INPUT "crm-tgraph-in" # define F_CRM_THROTTLE_MODE "crm-limit-mode" # define F_CRM_THROTTLE_MAX "crm-limit-max" /*---- Common tags/attrs */ # define XML_DIFF_MARKER "__crm_diff_marker__" # define XML_TAG_CIB "cib" # define XML_TAG_FAILED "failed" # define XML_ATTR_CRM_VERSION "crm_feature_set" # define XML_ATTR_DIGEST "digest" # define XML_ATTR_VALIDATION "validate-with" # define XML_ATTR_QUORUM_PANIC "no-quorum-panic" # define XML_ATTR_HAVE_QUORUM "have-quorum" # define XML_ATTR_GENERATION "epoch" # define XML_ATTR_GENERATION_ADMIN "admin_epoch" # define XML_ATTR_NUMUPDATES "num_updates" # define XML_ATTR_TIMEOUT "timeout" # define XML_ATTR_ORIGIN "crm-debug-origin" # define XML_ATTR_TSTAMP "crm-timestamp" # define XML_CIB_ATTR_WRITTEN "cib-last-written" # define XML_ATTR_VERSION "version" # define XML_ATTR_DESC "description" # define XML_ATTR_ID "id" # define XML_ATTR_NAME "name" # define XML_ATTR_IDREF "id-ref" # define XML_ATTR_ID_LONG "long-id" # define XML_ATTR_TYPE "type" # define XML_ATTR_OP "op" # define XML_ATTR_DC_UUID "dc-uuid" # define XML_ATTR_UPDATE_ORIG "update-origin" # define XML_ATTR_UPDATE_CLIENT "update-client" # define XML_ATTR_UPDATE_USER "update-user" # define XML_BOOLEAN_TRUE "true" # define XML_BOOLEAN_FALSE "false" # define XML_BOOLEAN_YES XML_BOOLEAN_TRUE # define XML_BOOLEAN_NO XML_BOOLEAN_FALSE # define XML_TAG_OPTIONS "options" /*---- top level tags/attrs */ # define XML_ATTR_REQUEST "request" # define XML_ATTR_RESPONSE "response" # define XML_ATTR_UNAME "uname" # define XML_ATTR_REFERENCE "reference" # define XML_CRM_TAG_PING "ping_response" # define XML_PING_ATTR_STATUS "result" # define XML_PING_ATTR_SYSFROM "crm_subsystem" # define XML_PING_ATTR_CRMDSTATE "crmd_state" # define XML_PING_ATTR_PACEMAKERDSTATE "pacemakerd_state" # define XML_PING_ATTR_PACEMAKERDSTATE_INIT "init" # define XML_PING_ATTR_PACEMAKERDSTATE_STARTINGDAEMONS "starting_daemons" # define XML_PING_ATTR_PACEMAKERDSTATE_WAITPING "wait_for_ping" # define XML_PING_ATTR_PACEMAKERDSTATE_RUNNING "running" # define XML_PING_ATTR_PACEMAKERDSTATE_SHUTTINGDOWN "shutting_down" # define XML_PING_ATTR_PACEMAKERDSTATE_SHUTDOWNCOMPLETE "shutdown_complete" # define XML_PING_ATTR_PACEMAKERDSTATE_REMOTE "remote" # define XML_FAIL_TAG_CIB "failed_update" # define XML_FAILCIB_ATTR_ID "id" # define XML_FAILCIB_ATTR_OBJTYPE "object_type" # define XML_FAILCIB_ATTR_OP "operation" # define XML_FAILCIB_ATTR_REASON "reason" /*---- CIB specific tags/attrs */ # define XML_CIB_TAG_SECTION_ALL "all" # define XML_CIB_TAG_CONFIGURATION "configuration" # define XML_CIB_TAG_STATUS "status" # define XML_CIB_TAG_RESOURCES "resources" # define XML_CIB_TAG_NODES "nodes" # define XML_CIB_TAG_CONSTRAINTS "constraints" # define XML_CIB_TAG_CRMCONFIG "crm_config" # define XML_CIB_TAG_OPCONFIG "op_defaults" # define XML_CIB_TAG_RSCCONFIG "rsc_defaults" # define XML_CIB_TAG_ACLS "acls" # define XML_CIB_TAG_ALERTS "alerts" # define XML_CIB_TAG_ALERT "alert" # define XML_CIB_TAG_ALERT_RECIPIENT "recipient" # define XML_CIB_TAG_ALERT_SELECT "select" # define XML_CIB_TAG_ALERT_ATTRIBUTES "select_attributes" # define XML_CIB_TAG_ALERT_FENCING "select_fencing" # define XML_CIB_TAG_ALERT_NODES "select_nodes" # define XML_CIB_TAG_ALERT_RESOURCES "select_resources" # define XML_CIB_TAG_ALERT_ATTR "attribute" # define XML_CIB_TAG_STATE "node_state" # define XML_CIB_TAG_NODE "node" # define XML_CIB_TAG_NVPAIR "nvpair" # define XML_CIB_TAG_PROPSET "cluster_property_set" # define XML_TAG_ATTR_SETS "instance_attributes" # define XML_TAG_META_SETS "meta_attributes" # define XML_TAG_ATTRS "attributes" # define XML_TAG_PARAMS "parameters" # define XML_TAG_PARAM "param" # define XML_TAG_UTILIZATION "utilization" # define XML_TAG_RESOURCE_REF "resource_ref" # define XML_CIB_TAG_RESOURCE "primitive" # define XML_CIB_TAG_GROUP "group" # define XML_CIB_TAG_INCARNATION "clone" # define XML_CIB_TAG_CONTAINER "bundle" # define XML_CIB_TAG_RSC_TEMPLATE "template" # define XML_RSC_ATTR_TARGET "container-attribute-target" # define XML_RSC_ATTR_RESTART "restart-type" # define XML_RSC_ATTR_ORDERED "ordered" # define XML_RSC_ATTR_INTERLEAVE "interleave" # define XML_RSC_ATTR_INCARNATION "clone" # define XML_RSC_ATTR_PROMOTABLE "promotable" # define XML_RSC_ATTR_MANAGED "is-managed" # define XML_RSC_ATTR_TARGET_ROLE "target-role" # define XML_RSC_ATTR_UNIQUE "globally-unique" # define XML_RSC_ATTR_NOTIFY "notify" # define XML_RSC_ATTR_STICKINESS "resource-stickiness" # define XML_RSC_ATTR_MULTIPLE "multiple-active" # define XML_RSC_ATTR_REQUIRES "requires" # define XML_RSC_ATTR_CONTAINER "container" # define XML_RSC_ATTR_INTERNAL_RSC "internal_rsc" # define XML_RSC_ATTR_MAINTENANCE "maintenance" # define XML_RSC_ATTR_REMOTE_NODE "remote-node" # define XML_RSC_ATTR_CLEAR_OP "clear_failure_op" # define XML_RSC_ATTR_CLEAR_INTERVAL "clear_failure_interval" # define XML_RSC_ATTR_REMOTE_RA_ADDR "addr" # define XML_RSC_ATTR_REMOTE_RA_SERVER "server" # define XML_RSC_ATTR_REMOTE_RA_PORT "port" # define XML_RSC_ATTR_CRITICAL "critical" # define XML_REMOTE_ATTR_RECONNECT_INTERVAL "reconnect_interval" # define XML_OP_ATTR_ON_FAIL "on-fail" # define XML_OP_ATTR_START_DELAY "start-delay" # define XML_OP_ATTR_ALLOW_MIGRATE "allow-migrate" # define XML_OP_ATTR_ORIGIN "interval-origin" # define XML_OP_ATTR_PENDING "record-pending" # define XML_OP_ATTR_DIGESTS_ALL "digests-all" # define XML_OP_ATTR_DIGESTS_SECURE "digests-secure" # define XML_CIB_TAG_LRM "lrm" # define XML_LRM_TAG_RESOURCES "lrm_resources" # define XML_LRM_TAG_RESOURCE "lrm_resource" # define XML_LRM_TAG_RSC_OP "lrm_rsc_op" # define XML_AGENT_ATTR_CLASS "class" # define XML_AGENT_ATTR_PROVIDER "provider" //! \deprecated Do not use (will be removed in a future release) # define XML_CIB_ATTR_REPLACE "replace" # define XML_CIB_ATTR_PRIORITY "priority" # define XML_NODE_IS_REMOTE "remote_node" # define XML_NODE_IS_FENCED "node_fenced" # define XML_NODE_IS_MAINTENANCE "node_in_maintenance" # define XML_CIB_ATTR_SHUTDOWN "shutdown" /* Aside from being an old name for the executor, LRM is a misnomer here because * the controller and scheduler use these to track actions, which are not always * executor operations. */ // XML attribute that takes interval specification (user-facing configuration) # define XML_LRM_ATTR_INTERVAL "interval" // XML attribute that takes interval in milliseconds (daemon APIs) // (identical value as above, but different constant allows clearer code intent) # define XML_LRM_ATTR_INTERVAL_MS XML_LRM_ATTR_INTERVAL # define XML_LRM_ATTR_TASK "operation" # define XML_LRM_ATTR_TASK_KEY "operation_key" # define XML_LRM_ATTR_TARGET "on_node" # define XML_LRM_ATTR_TARGET_UUID "on_node_uuid" /*! Actions to be executed on Pacemaker Remote nodes are routed through the * controller on the cluster node hosting the remote connection. That cluster * node is considered the router node for the action. */ # define XML_LRM_ATTR_ROUTER_NODE "router_node" # define XML_LRM_ATTR_RSCID "rsc-id" # define XML_LRM_ATTR_OPSTATUS "op-status" # define XML_LRM_ATTR_RC "rc-code" # define XML_LRM_ATTR_CALLID "call-id" # define XML_LRM_ATTR_OP_DIGEST "op-digest" # define XML_LRM_ATTR_OP_RESTART "op-force-restart" # define XML_LRM_ATTR_OP_SECURE "op-secure-params" # define XML_LRM_ATTR_RESTART_DIGEST "op-restart-digest" # define XML_LRM_ATTR_SECURE_DIGEST "op-secure-digest" # define XML_LRM_ATTR_EXIT_REASON "exit-reason" # define XML_RSC_OP_LAST_CHANGE "last-rc-change" # define XML_RSC_OP_T_EXEC "exec-time" # define XML_RSC_OP_T_QUEUE "queue-time" # define XML_LRM_ATTR_MIGRATE_SOURCE "migrate_source" # define XML_LRM_ATTR_MIGRATE_TARGET "migrate_target" # define XML_TAG_GRAPH "transition_graph" # define XML_GRAPH_TAG_RSC_OP "rsc_op" # define XML_GRAPH_TAG_PSEUDO_EVENT "pseudo_event" # define XML_GRAPH_TAG_CRM_EVENT "crm_event" # define XML_GRAPH_TAG_DOWNED "downed" # define XML_GRAPH_TAG_MAINTENANCE "maintenance" # define XML_TAG_RULE "rule" # define XML_RULE_ATTR_SCORE "score" # define XML_RULE_ATTR_SCORE_ATTRIBUTE "score-attribute" # define XML_RULE_ATTR_ROLE "role" # define XML_RULE_ATTR_BOOLEAN_OP "boolean-op" # define XML_TAG_EXPRESSION "expression" # define XML_EXPR_ATTR_ATTRIBUTE "attribute" # define XML_EXPR_ATTR_OPERATION "operation" # define XML_EXPR_ATTR_VALUE "value" # define XML_EXPR_ATTR_TYPE "type" # define XML_EXPR_ATTR_VALUE_SOURCE "value-source" # define XML_CONS_TAG_RSC_DEPEND "rsc_colocation" # define XML_CONS_TAG_RSC_ORDER "rsc_order" # define XML_CONS_TAG_RSC_LOCATION "rsc_location" # define XML_CONS_TAG_RSC_TICKET "rsc_ticket" # define XML_CONS_TAG_RSC_SET "resource_set" # define XML_CONS_ATTR_SYMMETRICAL "symmetrical" # define XML_LOCATION_ATTR_DISCOVERY "resource-discovery" # define XML_COLOC_ATTR_SOURCE "rsc" # define XML_COLOC_ATTR_SOURCE_ROLE "rsc-role" # define XML_COLOC_ATTR_TARGET "with-rsc" # define XML_COLOC_ATTR_TARGET_ROLE "with-rsc-role" # define XML_COLOC_ATTR_NODE_ATTR "node-attribute" # define XML_COLOC_ATTR_INFLUENCE "influence" //! \deprecated Deprecated since 2.1.5 # define XML_COLOC_ATTR_SOURCE_INSTANCE "rsc-instance" //! \deprecated Deprecated since 2.1.5 # define XML_COLOC_ATTR_TARGET_INSTANCE "with-rsc-instance" # define XML_LOC_ATTR_SOURCE "rsc" # define XML_LOC_ATTR_SOURCE_PATTERN "rsc-pattern" # define XML_ORDER_ATTR_FIRST "first" # define XML_ORDER_ATTR_THEN "then" # define XML_ORDER_ATTR_FIRST_ACTION "first-action" # define XML_ORDER_ATTR_THEN_ACTION "then-action" # define XML_ORDER_ATTR_KIND "kind" //! \deprecated Deprecated since 2.1.5 # define XML_ORDER_ATTR_FIRST_INSTANCE "first-instance" //! \deprecated Deprecated since 2.1.5 # define XML_ORDER_ATTR_THEN_INSTANCE "then-instance" # define XML_TICKET_ATTR_TICKET "ticket" # define XML_TICKET_ATTR_LOSS_POLICY "loss-policy" # define XML_NVPAIR_ATTR_NAME "name" # define XML_NVPAIR_ATTR_VALUE "value" # define XML_NODE_ATTR_RSC_DISCOVERY "resource-discovery-enabled" # define XML_ALERT_ATTR_PATH "path" # define XML_ALERT_ATTR_TIMEOUT "timeout" # define XML_ALERT_ATTR_TSTAMP_FORMAT "timestamp-format" # define XML_ALERT_ATTR_REC_VALUE "value" # define XML_CIB_TAG_GENERATION_TUPPLE "generation_tuple" # define XML_ATTR_TRANSITION_MAGIC "transition-magic" # define XML_ATTR_TRANSITION_KEY "transition-key" # define XML_ATTR_TE_NOWAIT "op_no_wait" # define XML_ATTR_TE_TARGET_RC "op_target_rc" # define XML_TAG_TRANSIENT_NODEATTRS "transient_attributes" //! \deprecated Do not use (will be removed in a future release) # define XML_TAG_DIFF_ADDED "diff-added" //! \deprecated Do not use (will be removed in a future release) # define XML_TAG_DIFF_REMOVED "diff-removed" # define XML_ACL_TAG_USER "acl_target" # define XML_ACL_TAG_USERv1 "acl_user" # define XML_ACL_TAG_GROUP "acl_group" # define XML_ACL_TAG_ROLE "acl_role" # define XML_ACL_TAG_PERMISSION "acl_permission" # define XML_ACL_TAG_ROLE_REF "role" # define XML_ACL_TAG_ROLE_REFv1 "role_ref" # define XML_ACL_ATTR_KIND "kind" # define XML_ACL_TAG_READ "read" # define XML_ACL_TAG_WRITE "write" # define XML_ACL_TAG_DENY "deny" # define XML_ACL_ATTR_REF "reference" # define XML_ACL_ATTR_REFv1 "ref" # define XML_ACL_ATTR_TAG "object-type" # define XML_ACL_ATTR_TAGv1 "tag" # define XML_ACL_ATTR_XPATH "xpath" # define XML_ACL_ATTR_ATTRIBUTE "attribute" # define XML_CIB_TAG_TICKETS "tickets" # define XML_CIB_TAG_TICKET_STATE "ticket_state" # define XML_CIB_TAG_TAGS "tags" # define XML_CIB_TAG_TAG "tag" # define XML_CIB_TAG_OBJ_REF "obj_ref" # define XML_TAG_FENCING_TOPOLOGY "fencing-topology" # define XML_TAG_FENCING_LEVEL "fencing-level" # define XML_ATTR_STONITH_INDEX "index" # define XML_ATTR_STONITH_TARGET "target" # define XML_ATTR_STONITH_TARGET_VALUE "target-value" # define XML_ATTR_STONITH_TARGET_PATTERN "target-pattern" # define XML_ATTR_STONITH_TARGET_ATTRIBUTE "target-attribute" # define XML_ATTR_STONITH_DEVICES "devices" # define XML_TAG_DIFF "diff" # define XML_DIFF_VERSION "version" # define XML_DIFF_VSOURCE "source" # define XML_DIFF_VTARGET "target" # define XML_DIFF_CHANGE "change" # define XML_DIFF_LIST "change-list" # define XML_DIFF_ATTR "change-attr" # define XML_DIFF_RESULT "change-result" # define XML_DIFF_OP "operation" # define XML_DIFF_PATH "path" # define XML_DIFF_POSITION "position" # define ID(x) crm_element_value(x, XML_ATTR_ID) #ifdef __cplusplus } #endif #endif diff --git a/include/crm/pengine/internal.h b/include/crm/pengine/internal.h index 02298d5f45..1dfee80018 100644 --- a/include/crm/pengine/internal.h +++ b/include/crm/pengine/internal.h @@ -1,623 +1,623 @@ /* - * Copyright 2004-2023 the Pacemaker project contributors + * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #ifndef PE_INTERNAL__H # define PE_INTERNAL__H # include # include # include # include # include # include # include # include # include # include const char *pe__resource_description(const pcmk_resource_t *rsc, uint32_t show_opts); bool pe__clone_is_ordered(const pcmk_resource_t *clone); int pe__set_clone_flag(pcmk_resource_t *clone, enum pcmk__clone_flags flag); bool pe__clone_flag_is_set(const pcmk_resource_t *clone, uint32_t flags); bool pe__group_flag_is_set(const pcmk_resource_t *group, uint32_t flags); pcmk_resource_t *pe__last_group_member(const pcmk_resource_t *group); #define pe__set_working_set_flags(scheduler, flags_to_set) do { \ (scheduler)->flags = pcmk__set_flags_as(__func__, __LINE__, \ LOG_TRACE, "Scheduler", crm_system_name, \ (scheduler)->flags, (flags_to_set), #flags_to_set); \ } while (0) #define pe__clear_working_set_flags(scheduler, flags_to_clear) do { \ (scheduler)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_TRACE, "Scheduler", crm_system_name, \ (scheduler)->flags, (flags_to_clear), #flags_to_clear); \ } while (0) #define pe__set_resource_flags(resource, flags_to_set) do { \ (resource)->flags = pcmk__set_flags_as(__func__, __LINE__, \ LOG_TRACE, "Resource", (resource)->id, (resource)->flags, \ (flags_to_set), #flags_to_set); \ } while (0) #define pe__clear_resource_flags(resource, flags_to_clear) do { \ (resource)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_TRACE, "Resource", (resource)->id, (resource)->flags, \ (flags_to_clear), #flags_to_clear); \ } while (0) #define pe__set_action_flags(action, flags_to_set) do { \ (action)->flags = pcmk__set_flags_as(__func__, __LINE__, \ LOG_TRACE, \ "Action", (action)->uuid, \ (action)->flags, \ (flags_to_set), \ #flags_to_set); \ } while (0) #define pe__clear_action_flags(action, flags_to_clear) do { \ (action)->flags = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_TRACE, \ "Action", (action)->uuid, \ (action)->flags, \ (flags_to_clear), \ #flags_to_clear); \ } while (0) #define pe__set_raw_action_flags(action_flags, action_name, flags_to_set) do { \ action_flags = pcmk__set_flags_as(__func__, __LINE__, \ LOG_TRACE, "Action", action_name, \ (action_flags), \ (flags_to_set), #flags_to_set); \ } while (0) #define pe__clear_raw_action_flags(action_flags, action_name, flags_to_clear) do { \ action_flags = pcmk__clear_flags_as(__func__, __LINE__, \ LOG_TRACE, \ "Action", action_name, \ (action_flags), \ (flags_to_clear), \ #flags_to_clear); \ } while (0) #define pe__set_action_flags_as(function, line, action, flags_to_set) do { \ (action)->flags = pcmk__set_flags_as((function), (line), \ LOG_TRACE, \ "Action", (action)->uuid, \ (action)->flags, \ (flags_to_set), \ #flags_to_set); \ } while (0) #define pe__clear_action_flags_as(function, line, action, flags_to_clear) do { \ (action)->flags = pcmk__clear_flags_as((function), (line), \ LOG_TRACE, \ "Action", (action)->uuid, \ (action)->flags, \ (flags_to_clear), \ #flags_to_clear); \ } while (0) #define pe__set_order_flags(order_flags, flags_to_set) do { \ order_flags = pcmk__set_flags_as(__func__, __LINE__, LOG_TRACE, \ "Ordering", "constraint", \ order_flags, (flags_to_set), \ #flags_to_set); \ } while (0) #define pe__clear_order_flags(order_flags, flags_to_clear) do { \ order_flags = pcmk__clear_flags_as(__func__, __LINE__, LOG_TRACE, \ "Ordering", "constraint", \ order_flags, (flags_to_clear), \ #flags_to_clear); \ } while (0) const pcmk_resource_t *pe__const_top_resource(const pcmk_resource_t *rsc, bool include_bundle); int pe__clone_max(const pcmk_resource_t *clone); int pe__clone_node_max(const pcmk_resource_t *clone); int pe__clone_promoted_max(const pcmk_resource_t *clone); int pe__clone_promoted_node_max(const pcmk_resource_t *clone); void pe__create_clone_notifications(pcmk_resource_t *clone); void pe__free_clone_notification_data(pcmk_resource_t *clone); void pe__create_clone_notif_pseudo_ops(pcmk_resource_t *clone, pcmk_action_t *start, pcmk_action_t *started, pcmk_action_t *stop, pcmk_action_t *stopped); pcmk_action_t *pe__new_rsc_pseudo_action(pcmk_resource_t *rsc, const char *task, bool optional, bool runnable); void pe__create_promotable_pseudo_ops(pcmk_resource_t *clone, bool any_promoting, bool any_demoting); bool pe_can_fence(const pcmk_scheduler_t *scheduler, const pcmk_node_t *node); void add_hash_param(GHashTable * hash, const char *name, const char *value); char *native_parameter(pcmk_resource_t *rsc, pcmk_node_t *node, gboolean create, const char *name, pcmk_scheduler_t *scheduler); pcmk_node_t *native_location(const pcmk_resource_t *rsc, GList **list, int current); void pe_metadata(pcmk__output_t *out); void verify_pe_options(GHashTable * options); void native_add_running(pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_scheduler_t *scheduler, gboolean failed); gboolean native_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler); gboolean group_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler); gboolean clone_unpack(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler); gboolean pe__unpack_bundle(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler); pcmk_resource_t *native_find_rsc(pcmk_resource_t *rsc, const char *id, const pcmk_node_t *node, int flags); gboolean native_active(pcmk_resource_t *rsc, gboolean all); gboolean group_active(pcmk_resource_t *rsc, gboolean all); gboolean clone_active(pcmk_resource_t *rsc, gboolean all); gboolean pe__bundle_active(pcmk_resource_t *rsc, gboolean all); //! \deprecated This function will be removed in a future release void native_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data); //! \deprecated This function will be removed in a future release void group_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data); //! \deprecated This function will be removed in a future release void clone_print(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data); //! \deprecated This function will be removed in a future release void pe__print_bundle(pcmk_resource_t *rsc, const char *pre_text, long options, void *print_data); gchar *pcmk__native_output_string(const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, uint32_t show_opts, const char *target_role, bool show_nodes); int pe__name_and_nvpairs_xml(pcmk__output_t *out, bool is_list, const char *tag_name , size_t pairs_count, ...); char *pe__node_display_name(pcmk_node_t *node, bool print_detail); // Clone notifications (pe_notif.c) void pe__order_notifs_after_fencing(const pcmk_action_t *action, pcmk_resource_t *rsc, pcmk_action_t *stonith_op); static inline const char * pe__rsc_bool_str(const pcmk_resource_t *rsc, uint64_t rsc_flag) { return pcmk__btoa(pcmk_is_set(rsc->flags, rsc_flag)); } int pe__clone_xml(pcmk__output_t *out, va_list args); int pe__clone_default(pcmk__output_t *out, va_list args); int pe__group_xml(pcmk__output_t *out, va_list args); int pe__group_default(pcmk__output_t *out, va_list args); int pe__bundle_xml(pcmk__output_t *out, va_list args); int pe__bundle_html(pcmk__output_t *out, va_list args); int pe__bundle_text(pcmk__output_t *out, va_list args); int pe__node_html(pcmk__output_t *out, va_list args); int pe__node_text(pcmk__output_t *out, va_list args); int pe__node_xml(pcmk__output_t *out, va_list args); int pe__resource_xml(pcmk__output_t *out, va_list args); int pe__resource_html(pcmk__output_t *out, va_list args); int pe__resource_text(pcmk__output_t *out, va_list args); void native_free(pcmk_resource_t *rsc); void group_free(pcmk_resource_t *rsc); void clone_free(pcmk_resource_t *rsc); void pe__free_bundle(pcmk_resource_t *rsc); enum rsc_role_e native_resource_state(const pcmk_resource_t *rsc, gboolean current); enum rsc_role_e group_resource_state(const pcmk_resource_t *rsc, gboolean current); enum rsc_role_e clone_resource_state(const pcmk_resource_t *rsc, gboolean current); enum rsc_role_e pe__bundle_resource_state(const pcmk_resource_t *rsc, gboolean current); void pe__count_common(pcmk_resource_t *rsc); void pe__count_bundle(pcmk_resource_t *rsc); void common_free(pcmk_resource_t *rsc); pcmk_node_t *pe__copy_node(const pcmk_node_t *this_node); time_t get_effective_time(pcmk_scheduler_t *scheduler); /* Failure handling utilities (from failcounts.c) */ int pe_get_failcount(const pcmk_node_t *node, pcmk_resource_t *rsc, time_t *last_failure, uint32_t flags, const xmlNode *xml_op); pcmk_action_t *pe__clear_failcount(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *reason, pcmk_scheduler_t *scheduler); /* Functions for finding/counting a resource's active nodes */ bool pe__count_active_node(const pcmk_resource_t *rsc, pcmk_node_t *node, pcmk_node_t **active, unsigned int *count_all, unsigned int *count_clean); pcmk_node_t *pe__find_active_requires(const pcmk_resource_t *rsc, unsigned int *count); static inline pcmk_node_t * pe__current_node(const pcmk_resource_t *rsc) { return (rsc == NULL)? NULL : rsc->fns->active_node(rsc, NULL, NULL); } /* Binary like operators for lists of nodes */ GHashTable *pe__node_list2table(const GList *list); pcmk_action_t *get_pseudo_op(const char *name, pcmk_scheduler_t *scheduler); gboolean order_actions(pcmk_action_t *lh_action, pcmk_action_t *rh_action, uint32_t flags); void pe__show_node_scores_as(const char *file, const char *function, int line, bool to_log, const pcmk_resource_t *rsc, const char *comment, GHashTable *nodes, pcmk_scheduler_t *scheduler); #define pe__show_node_scores(level, rsc, text, nodes, scheduler) \ pe__show_node_scores_as(__FILE__, __func__, __LINE__, \ (level), (rsc), (text), (nodes), (scheduler)) GHashTable *pcmk__unpack_action_meta(pcmk_resource_t *rsc, const pcmk_node_t *node, const char *action_name, guint interval_ms, const xmlNode *action_config); GHashTable *pcmk__unpack_action_rsc_params(const xmlNode *action_xml, GHashTable *node_attrs, pcmk_scheduler_t *data_set); xmlNode *pcmk__find_action_config(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, bool include_disabled); enum rsc_start_requirement pcmk__action_requires(const pcmk_resource_t *rsc, const char *action_name); enum action_fail_response pcmk__parse_on_fail(const pcmk_resource_t *rsc, const char *action_name, guint interval_ms, const char *value); enum rsc_role_e pcmk__role_after_failure(const pcmk_resource_t *rsc, const char *action_name, enum action_fail_response on_fail, GHashTable *meta); pcmk_action_t *custom_action(pcmk_resource_t *rsc, char *key, const char *task, const pcmk_node_t *on_node, gboolean optional, pcmk_scheduler_t *scheduler); # define delete_key(rsc) pcmk__op_key(rsc->id, PCMK_ACTION_DELETE, 0) # define delete_action(rsc, node, optional) custom_action( \ rsc, delete_key(rsc), PCMK_ACTION_DELETE, node, \ optional, rsc->cluster); # define stop_key(rsc) pcmk__op_key(rsc->id, PCMK_ACTION_STOP, 0) # define stop_action(rsc, node, optional) custom_action( \ rsc, stop_key(rsc), PCMK_ACTION_STOP, node, \ optional, rsc->cluster); # define reload_key(rsc) pcmk__op_key(rsc->id, PCMK_ACTION_RELOAD_AGENT, 0) # define start_key(rsc) pcmk__op_key(rsc->id, PCMK_ACTION_START, 0) # define start_action(rsc, node, optional) custom_action( \ rsc, start_key(rsc), PCMK_ACTION_START, node, \ optional, rsc->cluster) # define promote_key(rsc) pcmk__op_key(rsc->id, PCMK_ACTION_PROMOTE, 0) # define promote_action(rsc, node, optional) custom_action( \ rsc, promote_key(rsc), PCMK_ACTION_PROMOTE, node, \ optional, rsc->cluster) # define demote_key(rsc) pcmk__op_key(rsc->id, PCMK_ACTION_DEMOTE, 0) # define demote_action(rsc, node, optional) custom_action( \ rsc, demote_key(rsc), PCMK_ACTION_DEMOTE, node, \ optional, rsc->cluster) extern int pe_get_configured_timeout(pcmk_resource_t *rsc, const char *action, pcmk_scheduler_t *scheduler); pcmk_action_t *find_first_action(const GList *input, const char *uuid, const char *task, const pcmk_node_t *on_node); enum action_tasks get_complex_task(const pcmk_resource_t *rsc, const char *name); GList *find_actions(GList *input, const char *key, const pcmk_node_t *on_node); GList *find_actions_exact(GList *input, const char *key, const pcmk_node_t *on_node); GList *pe__resource_actions(const pcmk_resource_t *rsc, const pcmk_node_t *node, const char *task, bool require_node); extern void pe_free_action(pcmk_action_t *action); void resource_location(pcmk_resource_t *rsc, const pcmk_node_t *node, int score, const char *tag, pcmk_scheduler_t *scheduler); extern int pe__is_newer_op(const xmlNode *xml_a, const xmlNode *xml_b, bool same_node_default); extern gint sort_op_by_callid(gconstpointer a, gconstpointer b); gboolean get_target_role(const pcmk_resource_t *rsc, enum rsc_role_e *role); void pe__set_next_role(pcmk_resource_t *rsc, enum rsc_role_e role, const char *why); pcmk_resource_t *find_clone_instance(const pcmk_resource_t *rsc, const char *sub_id); extern void destroy_ticket(gpointer data); pcmk_ticket_t *ticket_new(const char *ticket_id, pcmk_scheduler_t *scheduler); // Resources for manipulating resource names const char *pe_base_name_end(const char *id); char *clone_strip(const char *last_rsc_id); char *clone_zero(const char *last_rsc_id); static inline bool pe_base_name_eq(const pcmk_resource_t *rsc, const char *id) { if (id && rsc && rsc->id) { // Number of characters in rsc->id before any clone suffix size_t base_len = pe_base_name_end(rsc->id) - rsc->id + 1; return (strlen(id) == base_len) && !strncmp(id, rsc->id, base_len); } return false; } int pe__target_rc_from_xml(const xmlNode *xml_op); gint pe__cmp_node_name(gconstpointer a, gconstpointer b); bool is_set_recursive(const pcmk_resource_t *rsc, long long flag, bool any); pcmk__op_digest_t *pe__calculate_digests(pcmk_resource_t *rsc, const char *task, guint *interval_ms, const pcmk_node_t *node, const xmlNode *xml_op, GHashTable *overrides, bool calc_secure, pcmk_scheduler_t *scheduler); void pe__free_digests(gpointer ptr); pcmk__op_digest_t *rsc_action_digest_cmp(pcmk_resource_t *rsc, const xmlNode *xml_op, pcmk_node_t *node, pcmk_scheduler_t *scheduler); pcmk_action_t *pe_fence_op(pcmk_node_t *node, const char *op, bool optional, const char *reason, bool priority_delay, pcmk_scheduler_t *scheduler); void trigger_unfencing(pcmk_resource_t *rsc, pcmk_node_t *node, const char *reason, pcmk_action_t *dependency, pcmk_scheduler_t *scheduler); char *pe__action2reason(const pcmk_action_t *action, enum pe_action_flags flag); void pe_action_set_reason(pcmk_action_t *action, const char *reason, bool overwrite); void pe__add_action_expected_result(pcmk_action_t *action, int expected_result); void pe__set_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags); void pe__clear_resource_flags_recursive(pcmk_resource_t *rsc, uint64_t flags); void pe__clear_resource_flags_on_all(pcmk_scheduler_t *scheduler, uint64_t flag); gboolean add_tag_ref(GHashTable * tags, const char * tag_name, const char * obj_ref); //! \deprecated This function will be removed in a future release void print_rscs_brief(GList *rsc_list, const char * pre_text, long options, void * print_data, gboolean print_all); int pe__rscs_brief_output(pcmk__output_t *out, GList *rsc_list, unsigned int options); void pe_fence_node(pcmk_scheduler_t *scheduler, pcmk_node_t *node, const char *reason, bool priority_delay); pcmk_node_t *pe_create_node(const char *id, const char *uname, const char *type, const char *score, pcmk_scheduler_t *scheduler); //! \deprecated This function will be removed in a future release void common_print(pcmk_resource_t *rsc, const char *pre_text, const char *name, const pcmk_node_t *node, long options, void *print_data); int pe__common_output_text(pcmk__output_t *out, const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, unsigned int options); int pe__common_output_html(pcmk__output_t *out, const pcmk_resource_t *rsc, const char *name, const pcmk_node_t *node, unsigned int options); GList *pe__bundle_containers(const pcmk_resource_t *bundle); int pe__bundle_max(const pcmk_resource_t *rsc); bool pe__node_is_bundle_instance(const pcmk_resource_t *bundle, const pcmk_node_t *node); pcmk_resource_t *pe__bundled_resource(const pcmk_resource_t *rsc); const pcmk_resource_t *pe__get_rsc_in_container(const pcmk_resource_t *instance); pcmk_resource_t *pe__first_container(const pcmk_resource_t *bundle); void pe__foreach_bundle_replica(pcmk_resource_t *bundle, bool (*fn)(pcmk__bundle_replica_t *, void *), void *user_data); void pe__foreach_const_bundle_replica(const pcmk_resource_t *bundle, bool (*fn)(const pcmk__bundle_replica_t *, void *), void *user_data); pcmk_resource_t *pe__find_bundle_replica(const pcmk_resource_t *bundle, const pcmk_node_t *node); bool pe__bundle_needs_remote_name(pcmk_resource_t *rsc); const char *pe__add_bundle_remote_name(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler, xmlNode *xml, const char *field); const char *pe__node_attribute_calculated(const pcmk_node_t *node, const char *name, const pcmk_resource_t *rsc, enum pcmk__rsc_node node_type, bool force_host); const char *pe_node_attribute_raw(const pcmk_node_t *node, const char *name); bool pe__is_universal_clone(const pcmk_resource_t *rsc, const pcmk_scheduler_t *scheduler); void pe__add_param_check(const xmlNode *rsc_op, pcmk_resource_t *rsc, pcmk_node_t *node, enum pcmk__check_parameters, pcmk_scheduler_t *scheduler); void pe__foreach_param_check(pcmk_scheduler_t *scheduler, void (*cb)(pcmk_resource_t*, pcmk_node_t*, const xmlNode*, enum pcmk__check_parameters)); void pe__free_param_checks(pcmk_scheduler_t *scheduler); bool pe__shutdown_requested(const pcmk_node_t *node); void pe__update_recheck_time(time_t recheck, pcmk_scheduler_t *scheduler, const char *reason); /*! * \internal * \brief Register xml formatting message functions. * * \param[in,out] out Output object to register messages with */ void pe__register_messages(pcmk__output_t *out); void pe__unpack_dataset_nvpairs(const xmlNode *xml_obj, const char *set_name, const pe_rule_eval_data_t *rule_data, GHashTable *hash, const char *always_first, gboolean overwrite, pcmk_scheduler_t *scheduler); bool pe__resource_is_disabled(const pcmk_resource_t *rsc); void pe__clear_resource_history(pcmk_resource_t *rsc, const pcmk_node_t *node); GList *pe__rscs_with_tag(pcmk_scheduler_t *scheduler, const char *tag_name); GList *pe__unames_with_tag(pcmk_scheduler_t *scheduler, const char *tag_name); bool pe__rsc_has_tag(pcmk_scheduler_t *scheduler, const char *rsc, const char *tag); bool pe__uname_has_tag(pcmk_scheduler_t *scheduler, const char *node, const char *tag); bool pe__rsc_running_on_only(const pcmk_resource_t *rsc, const pcmk_node_t *node); bool pe__rsc_running_on_any(pcmk_resource_t *rsc, GList *node_list); GList *pe__filter_rsc_list(GList *rscs, GList *filter); GList * pe__build_node_name_list(pcmk_scheduler_t *scheduler, const char *s); GList * pe__build_rsc_list(pcmk_scheduler_t *scheduler, const char *s); bool pcmk__rsc_filtered_by_node(pcmk_resource_t *rsc, GList *only_node); gboolean pe__bundle_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent); gboolean pe__clone_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent); gboolean pe__group_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent); gboolean pe__native_is_filtered(const pcmk_resource_t *rsc, GList *only_rsc, gboolean check_parent); xmlNode *pe__failed_probe_for_rsc(const pcmk_resource_t *rsc, const char *name); const char *pe__clone_child_id(const pcmk_resource_t *rsc); int pe__sum_node_health_scores(const pcmk_node_t *node, int base_health); int pe__node_health(pcmk_node_t *node); static inline enum pcmk__health_strategy pe__health_strategy(pcmk_scheduler_t *scheduler) { return pcmk__parse_health_strategy(pe_pref(scheduler->config_hash, - PCMK__OPT_NODE_HEALTH_STRATEGY)); + PCMK_OPT_NODE_HEALTH_STRATEGY)); } static inline int pe__health_score(const char *option, pcmk_scheduler_t *scheduler) { return char2score(pe_pref(scheduler->config_hash, option)); } /*! * \internal * \brief Return a string suitable for logging as a node name * * \param[in] node Node to return a node name string for * * \return Node name if available, otherwise node ID if available, * otherwise "unspecified node" if node is NULL or "unidentified node" * if node has neither a name nor ID. */ static inline const char * pe__node_name(const pcmk_node_t *node) { if (node == NULL) { return "unspecified node"; } else if (node->details->uname != NULL) { return node->details->uname; } else if (node->details->id != NULL) { return node->details->id; } else { return "unidentified node"; } } /*! * \internal * \brief Check whether two node objects refer to the same node * * \param[in] node1 First node object to compare * \param[in] node2 Second node object to compare * * \return true if \p node1 and \p node2 refer to the same node */ static inline bool pe__same_node(const pcmk_node_t *node1, const pcmk_node_t *node2) { return (node1 != NULL) && (node2 != NULL) && (node1->details == node2->details); } /*! * \internal * \brief Get the operation key from an action history entry * * \param[in] xml Action history entry * * \return Entry's operation key */ static inline const char * pe__xe_history_key(const xmlNode *xml) { if (xml == NULL) { return NULL; } else { /* @COMPAT Pacemaker <= 1.1.5 did not add the key, and used the ID * instead. Checking for that allows us to process old saved CIBs, * including some regression tests. */ const char *key = crm_element_value(xml, XML_LRM_ATTR_TASK_KEY); return pcmk__str_empty(key)? ID(xml) : key; } } #endif diff --git a/lib/common/health.c b/lib/common/health.c index ee412be7a8..5d82839130 100644 --- a/lib/common/health.c +++ b/lib/common/health.c @@ -1,70 +1,72 @@ /* - * Copyright 2022 the Pacemaker project contributors + * Copyright 2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include +#include + /*! * \internal * \brief Ensure a health strategy value is allowed * * \param[in] value Configured health strategy * * \return true if \p value is an allowed health strategy value, otherwise false */ bool pcmk__validate_health_strategy(const char *value) { return pcmk__strcase_any_of(value, PCMK__VALUE_NONE, PCMK__VALUE_CUSTOM, PCMK__VALUE_ONLY_GREEN, PCMK__VALUE_PROGRESSIVE, PCMK__VALUE_MIGRATE_ON_RED, NULL); } /*! * \internal * \brief Parse node health strategy from a user-provided string * * \param[in] value User-provided configuration value for node-health-strategy * * \return Node health strategy corresponding to \p value */ enum pcmk__health_strategy pcmk__parse_health_strategy(const char *value) { if (pcmk__str_eq(value, PCMK__VALUE_NONE, pcmk__str_null_matches|pcmk__str_casei)) { return pcmk__health_strategy_none; } else if (pcmk__str_eq(value, PCMK__VALUE_MIGRATE_ON_RED, pcmk__str_casei)) { return pcmk__health_strategy_no_red; } else if (pcmk__str_eq(value, PCMK__VALUE_ONLY_GREEN, pcmk__str_casei)) { return pcmk__health_strategy_only_green; } else if (pcmk__str_eq(value, PCMK__VALUE_PROGRESSIVE, pcmk__str_casei)) { return pcmk__health_strategy_progressive; } else if (pcmk__str_eq(value, PCMK__VALUE_CUSTOM, pcmk__str_casei)) { return pcmk__health_strategy_custom; } else { pcmk__config_err("Using default of \"" PCMK__VALUE_NONE "\" for " - PCMK__OPT_NODE_HEALTH_STRATEGY + PCMK_OPT_NODE_HEALTH_STRATEGY " because '%s' is not a valid value", value); return pcmk__health_strategy_none; } } diff --git a/lib/pacemaker/pcmk_sched_nodes.c b/lib/pacemaker/pcmk_sched_nodes.c index aba8288cab..278178285a 100644 --- a/lib/pacemaker/pcmk_sched_nodes.c +++ b/lib/pacemaker/pcmk_sched_nodes.c @@ -1,434 +1,434 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include "libpacemaker_private.h" /*! * \internal * \brief Check whether a node is available to run resources * * \param[in] node Node to check * \param[in] consider_score If true, consider a negative score unavailable * \param[in] consider_guest If true, consider a guest node unavailable whose * resource will not be active * * \return true if node is online and not shutting down, unclean, or in standby * or maintenance mode, otherwise false */ bool pcmk__node_available(const pcmk_node_t *node, bool consider_score, bool consider_guest) { if ((node == NULL) || (node->details == NULL) || !node->details->online || node->details->shutdown || node->details->unclean || node->details->standby || node->details->maintenance) { return false; } if (consider_score && (node->weight < 0)) { return false; } // @TODO Go through all callers to see which should set consider_guest if (consider_guest && pe__is_guest_node(node)) { pcmk_resource_t *guest = node->details->remote_rsc->container; if (guest->fns->location(guest, NULL, FALSE) == NULL) { return false; } } return true; } /*! * \internal * \brief Copy a hash table of node objects * * \param[in] nodes Hash table to copy * * \return New copy of nodes (or NULL if nodes is NULL) */ GHashTable * pcmk__copy_node_table(GHashTable *nodes) { GHashTable *new_table = NULL; GHashTableIter iter; pcmk_node_t *node = NULL; if (nodes == NULL) { return NULL; } new_table = pcmk__strkey_table(NULL, free); g_hash_table_iter_init(&iter, nodes); while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &node)) { pcmk_node_t *new_node = pe__copy_node(node); g_hash_table_insert(new_table, (gpointer) new_node->details->id, new_node); } return new_table; } /*! * \internal * \brief Free a table of node tables * * \param[in,out] data Table to free * * \note This is a \c GDestroyNotify wrapper for \c g_hash_table_destroy(). */ static void destroy_node_tables(gpointer data) { g_hash_table_destroy((GHashTable *) data); } /*! * \internal * \brief Recursively copy the node tables of a resource * * Build a hash table containing copies of the allowed nodes tables of \p rsc * and its entire tree of descendants. The key is the resource ID, and the value * is a copy of the resource's node table. * * \param[in] rsc Resource whose node table to copy * \param[in,out] copy Where to store the copied node tables * * \note \p *copy should be \c NULL for the top-level call. * \note The caller is responsible for freeing \p copy using * \c g_hash_table_destroy(). */ void pcmk__copy_node_tables(const pcmk_resource_t *rsc, GHashTable **copy) { CRM_ASSERT((rsc != NULL) && (copy != NULL)); if (*copy == NULL) { *copy = pcmk__strkey_table(NULL, destroy_node_tables); } g_hash_table_insert(*copy, rsc->id, pcmk__copy_node_table(rsc->allowed_nodes)); for (const GList *iter = rsc->children; iter != NULL; iter = iter->next) { pcmk__copy_node_tables((const pcmk_resource_t *) iter->data, copy); } } /*! * \internal * \brief Recursively restore the node tables of a resource from backup * * Given a hash table containing backup copies of the allowed nodes tables of * \p rsc and its entire tree of descendants, replace the resources' current * node tables with the backed-up copies. * * \param[in,out] rsc Resource whose node tables to restore * \param[in] backup Table of backup node tables (created by * \c pcmk__copy_node_tables()) * * \note This function frees the resources' current node tables. */ void pcmk__restore_node_tables(pcmk_resource_t *rsc, GHashTable *backup) { CRM_ASSERT((rsc != NULL) && (backup != NULL)); g_hash_table_destroy(rsc->allowed_nodes); // Copy to avoid danger with multiple restores rsc->allowed_nodes = g_hash_table_lookup(backup, rsc->id); rsc->allowed_nodes = pcmk__copy_node_table(rsc->allowed_nodes); for (GList *iter = rsc->children; iter != NULL; iter = iter->next) { pcmk__restore_node_tables((pcmk_resource_t *) iter->data, backup); } } /*! * \internal * \brief Copy a list of node objects * * \param[in] list List to copy * \param[in] reset Set copies' scores to 0 * * \return New list of shallow copies of nodes in original list */ GList * pcmk__copy_node_list(const GList *list, bool reset) { GList *result = NULL; for (const GList *iter = list; iter != NULL; iter = iter->next) { pcmk_node_t *new_node = NULL; pcmk_node_t *this_node = iter->data; new_node = pe__copy_node(this_node); if (reset) { new_node->weight = 0; } result = g_list_prepend(result, new_node); } return result; } /*! * \internal * \brief Compare two nodes for assignment preference * * Given two nodes, check which one is more preferred by assignment criteria * such as node score and utilization. * * \param[in] a First node to compare * \param[in] b Second node to compare * \param[in] data Node to prefer if all else equal * * \return -1 if \p a is preferred, +1 if \p b is preferred, or 0 if they are * equally preferred */ static gint compare_nodes(gconstpointer a, gconstpointer b, gpointer data) { const pcmk_node_t *node1 = (const pcmk_node_t *) a; const pcmk_node_t *node2 = (const pcmk_node_t *) b; const pcmk_node_t *preferred = (const pcmk_node_t *) data; int node1_score = -INFINITY; int node2_score = -INFINITY; int result = 0; if (a == NULL) { return 1; } if (b == NULL) { return -1; } // Compare node scores if (pcmk__node_available(node1, false, false)) { node1_score = node1->weight; } if (pcmk__node_available(node2, false, false)) { node2_score = node2->weight; } if (node1_score > node2_score) { crm_trace("%s before %s (score %d > %d)", pe__node_name(node1), pe__node_name(node2), node1_score, node2_score); return -1; } if (node1_score < node2_score) { crm_trace("%s after %s (score %d < %d)", pe__node_name(node1), pe__node_name(node2), node1_score, node2_score); return 1; } // If appropriate, compare node utilization if (pcmk__str_eq(node1->details->data_set->placement_strategy, "minimal", pcmk__str_casei)) { goto equal; } if (pcmk__str_eq(node1->details->data_set->placement_strategy, "balanced", pcmk__str_casei)) { result = pcmk__compare_node_capacities(node1, node2); if (result < 0) { crm_trace("%s before %s (greater capacity by %d attributes)", pe__node_name(node1), pe__node_name(node2), result * -1); return -1; } else if (result > 0) { crm_trace("%s after %s (lower capacity by %d attributes)", pe__node_name(node1), pe__node_name(node2), result); return 1; } } // Compare number of resources already assigned to node if (node1->details->num_resources < node2->details->num_resources) { crm_trace("%s before %s (%d resources < %d)", pe__node_name(node1), pe__node_name(node2), node1->details->num_resources, node2->details->num_resources); return -1; } else if (node1->details->num_resources > node2->details->num_resources) { crm_trace("%s after %s (%d resources > %d)", pe__node_name(node1), pe__node_name(node2), node1->details->num_resources, node2->details->num_resources); return 1; } // Check whether one node is already running desired resource if (preferred != NULL) { if (pe__same_node(preferred, node1)) { crm_trace("%s before %s (preferred node)", pe__node_name(node1), pe__node_name(node2)); return -1; } else if (pe__same_node(preferred, node2)) { crm_trace("%s after %s (not preferred node)", pe__node_name(node1), pe__node_name(node2)); return 1; } } // If all else is equal, prefer node with lowest-sorting name equal: result = strcmp(node1->details->uname, node2->details->uname); if (result < 0) { crm_trace("%s before %s (name)", pe__node_name(node1), pe__node_name(node2)); return -1; } else if (result > 0) { crm_trace("%s after %s (name)", pe__node_name(node1), pe__node_name(node2)); return 1; } crm_trace("%s == %s", pe__node_name(node1), pe__node_name(node2)); return 0; } /*! * \internal * \brief Sort a list of nodes by assigment preference * * \param[in,out] nodes Node list to sort * \param[in] active_node Node where resource being assigned is active * * \return New head of sorted list */ GList * pcmk__sort_nodes(GList *nodes, pcmk_node_t *active_node) { return g_list_sort_with_data(nodes, compare_nodes, active_node); } /*! * \internal * \brief Check whether any node is available to run resources * * \param[in] nodes Nodes to check * * \return true if any node in \p nodes is available to run resources, * otherwise false */ bool pcmk__any_node_available(GHashTable *nodes) { GHashTableIter iter; const pcmk_node_t *node = NULL; if (nodes == NULL) { return false; } g_hash_table_iter_init(&iter, nodes); while (g_hash_table_iter_next(&iter, NULL, (void **) &node)) { if (pcmk__node_available(node, true, false)) { return true; } } return false; } /*! * \internal * \brief Apply node health values for all nodes in cluster * * \param[in,out] scheduler Scheduler data */ void pcmk__apply_node_health(pcmk_scheduler_t *scheduler) { int base_health = 0; enum pcmk__health_strategy strategy; const char *strategy_str = pe_pref(scheduler->config_hash, - PCMK__OPT_NODE_HEALTH_STRATEGY); + PCMK_OPT_NODE_HEALTH_STRATEGY); strategy = pcmk__parse_health_strategy(strategy_str); if (strategy == pcmk__health_strategy_none) { return; } crm_info("Applying node health strategy '%s'", strategy_str); // The progressive strategy can use a base health score if (strategy == pcmk__health_strategy_progressive) { base_health = pe__health_score(PCMK_OPT_NODE_HEALTH_BASE, scheduler); } for (GList *iter = scheduler->nodes; iter != NULL; iter = iter->next) { pcmk_node_t *node = (pcmk_node_t *) iter->data; int health = pe__sum_node_health_scores(node, base_health); // An overall health score of 0 has no effect if (health == 0) { continue; } crm_info("Overall system health of %s is %d", pe__node_name(node), health); // Use node health as a location score for each resource on the node for (GList *r = scheduler->resources; r != NULL; r = r->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) r->data; bool constrain = true; if (health < 0) { /* Negative health scores do not apply to resources with * allow-unhealthy-nodes=true. */ constrain = !crm_is_true(g_hash_table_lookup(rsc->meta, PCMK__META_ALLOW_UNHEALTHY_NODES)); } if (constrain) { pcmk__new_location(strategy_str, rsc, health, NULL, node); } else { pcmk__rsc_trace(rsc, "%s is immune from health ban on %s", rsc->id, pe__node_name(node)); } } } } /*! * \internal * \brief Check for a node in a resource's parent's allowed nodes * * \param[in] rsc Resource whose parent should be checked * \param[in] node Node to check for * * \return Equivalent of \p node from \p rsc's parent's allowed nodes if any, * otherwise NULL */ pcmk_node_t * pcmk__top_allowed_node(const pcmk_resource_t *rsc, const pcmk_node_t *node) { GHashTable *allowed_nodes = NULL; if ((rsc == NULL) || (node == NULL)) { return NULL; } else if (rsc->parent == NULL) { allowed_nodes = rsc->allowed_nodes; } else { allowed_nodes = rsc->parent->allowed_nodes; } return g_hash_table_lookup(allowed_nodes, node->details->id); } diff --git a/lib/pengine/common.c b/lib/pengine/common.c index 93ae5462f3..85098c4c68 100644 --- a/lib/pengine/common.c +++ b/lib/pengine/common.c @@ -1,624 +1,624 @@ /* * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU Lesser General Public License * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #include #include static bool check_placement_strategy(const char *value) { return pcmk__strcase_any_of(value, "default", "utilization", "minimal", "balanced", NULL); } static pcmk__cluster_option_t pe_opts[] = { /* name, old name, type, allowed values, * default value, validator, * short description, * long description */ { PCMK_OPT_NO_QUORUM_POLICY, NULL, "select", "stop, freeze, ignore, demote, suicide", "stop", pcmk__valid_quorum, N_("What to do when the cluster does not have quorum"), NULL }, { PCMK_OPT_SYMMETRIC_CLUSTER, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("Whether resources can run on any node by default"), NULL }, { PCMK_OPT_MAINTENANCE_MODE, NULL, "boolean", NULL, "false", pcmk__valid_boolean, N_("Whether the cluster should refrain from monitoring, starting, " "and stopping resources"), NULL }, { PCMK_OPT_START_FAILURE_IS_FATAL, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("Whether a start failure should prevent a resource from being " "recovered on the same node"), N_("When true, the cluster will immediately ban a resource from a node " "if it fails to start there. When false, the cluster will instead " "check the resource's fail count against its migration-threshold.") }, { PCMK_OPT_ENABLE_STARTUP_PROBES, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("Whether the cluster should check for active resources during start-up"), NULL }, { PCMK_OPT_SHUTDOWN_LOCK, NULL, "boolean", NULL, "false", pcmk__valid_boolean, N_("Whether to lock resources to a cleanly shut down node"), N_("When true, resources active on a node when it is cleanly shut down " "are kept \"locked\" to that node (not allowed to run elsewhere) " "until they start again on that node after it rejoins (or for at " "most shutdown-lock-limit, if set). Stonith resources and " "Pacemaker Remote connections are never locked. Clone and bundle " "instances and the promoted role of promotable clones are " "currently never locked, though support could be added in a future " "release.") }, { PCMK_OPT_SHUTDOWN_LOCK_LIMIT, NULL, "time", NULL, "0", pcmk__valid_interval_spec, N_("Do not lock resources to a cleanly shut down node longer than " "this"), N_("If shutdown-lock is true and this is set to a nonzero time " "duration, shutdown locks will expire after this much time has " "passed since the shutdown was initiated, even if the node has not " "rejoined.") }, // Fencing-related options { PCMK_OPT_STONITH_ENABLED, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("*** Advanced Use Only *** " "Whether nodes may be fenced as part of recovery"), N_("If false, unresponsive nodes are immediately assumed to be harmless, " "and resources that were active on them may be recovered " "elsewhere. This can result in a \"split-brain\" situation, " "potentially leading to data loss and/or service unavailability.") }, { PCMK_OPT_STONITH_ACTION, NULL, "select", "reboot, off, poweroff", PCMK_ACTION_REBOOT, pcmk__is_fencing_action, N_("Action to send to fence device when a node needs to be fenced " "(\"poweroff\" is a deprecated alias for \"off\")"), NULL }, { PCMK_OPT_STONITH_TIMEOUT, NULL, "time", NULL, "60s", pcmk__valid_interval_spec, N_("*** Advanced Use Only *** Unused by Pacemaker"), N_("This value is not used by Pacemaker, but is kept for backward " "compatibility, and certain legacy fence agents might use it.") }, { PCMK_OPT_HAVE_WATCHDOG, NULL, "boolean", NULL, "false", pcmk__valid_boolean, N_("Whether watchdog integration is enabled"), N_("This is set automatically by the cluster according to whether SBD " "is detected to be in use. User-configured values are ignored. " "The value `true` is meaningful if diskless SBD is used and " "`stonith-watchdog-timeout` is nonzero. In that case, if fencing " "is required, watchdog-based self-fencing will be performed via " "SBD without requiring a fencing resource explicitly configured.") }, { PCMK_OPT_CONCURRENT_FENCING, NULL, "boolean", NULL, PCMK__CONCURRENT_FENCING_DEFAULT, pcmk__valid_boolean, N_("Allow performing fencing operations in parallel"), NULL }, { PCMK_OPT_STARTUP_FENCING, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("*** Advanced Use Only *** Whether to fence unseen nodes at start-up"), N_("Setting this to false may lead to a \"split-brain\" situation," "potentially leading to data loss and/or service unavailability.") }, { PCMK_OPT_PRIORITY_FENCING_DELAY, NULL, "time", NULL, "0", pcmk__valid_interval_spec, N_("Apply fencing delay targeting the lost nodes with the highest total resource priority"), N_("Apply specified delay for the fencings that are targeting the lost " "nodes with the highest total resource priority in case we don't " "have the majority of the nodes in our cluster partition, so that " "the more significant nodes potentially win any fencing match, " "which is especially meaningful under split-brain of 2-node " "cluster. A promoted resource instance takes the base priority + 1 " "on calculation if the base priority is not 0. Any static/random " "delays that are introduced by `pcmk_delay_base/max` configured " "for the corresponding fencing resources will be added to this " "delay. This delay should be significantly greater than, safely " "twice, the maximum `pcmk_delay_base/max`. By default, priority " "fencing delay is disabled.") }, { PCMK_OPT_NODE_PENDING_TIMEOUT, NULL, "time", NULL, "0", pcmk__valid_interval_spec, N_("How long to wait for a node that has joined the cluster to join " "the controller process group"), N_("Fence nodes that do not join the controller process group within " "this much time after joining the cluster, to allow the cluster " "to continue managing resources. A value of 0 means never fence " "pending nodes. Setting the value to 2h means fence nodes after " "2 hours.") }, { PCMK_OPT_CLUSTER_DELAY, NULL, "time", NULL, "60s", pcmk__valid_interval_spec, N_("Maximum time for node-to-node communication"), N_("The node elected Designated Controller (DC) will consider an action " "failed if it does not get a response from the node executing the " "action within this time (after considering the action's own " "timeout). The \"correct\" value will depend on the speed and " "load of your network and cluster nodes.") }, { PCMK_OPT_BATCH_LIMIT, NULL, "integer", NULL, "0", pcmk__valid_number, N_("Maximum number of jobs that the cluster may execute in parallel " "across all nodes"), N_("The \"correct\" value will depend on the speed and load of your " "network and cluster nodes. If set to 0, the cluster will " "impose a dynamically calculated limit when any node has a " "high load.") }, { PCMK_OPT_MIGRATION_LIMIT, NULL, "integer", NULL, "-1", pcmk__valid_number, N_("The number of live migration actions that the cluster is allowed " "to execute in parallel on a node (-1 means no limit)") }, /* Orphans and stopping */ { PCMK_OPT_STOP_ALL_RESOURCES, NULL, "boolean", NULL, "false", pcmk__valid_boolean, N_("Whether the cluster should stop all active resources"), NULL }, { PCMK_OPT_STOP_ORPHAN_RESOURCES, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("Whether to stop resources that were removed from the configuration"), NULL }, { PCMK_OPT_STOP_ORPHAN_ACTIONS, NULL, "boolean", NULL, "true", pcmk__valid_boolean, N_("Whether to cancel recurring actions removed from the configuration"), NULL }, { PCMK__OPT_REMOVE_AFTER_STOP, NULL, "boolean", NULL, "false", pcmk__valid_boolean, N_("*** Deprecated *** Whether to remove stopped resources from " "the executor"), N_("Values other than default are poorly tested and potentially dangerous." " This option will be removed in a future release.") }, /* Storing inputs */ { PCMK_OPT_PE_ERROR_SERIES_MAX, NULL, "integer", NULL, "-1", pcmk__valid_number, N_("The number of scheduler inputs resulting in errors to save"), N_("Zero to disable, -1 to store unlimited.") }, { PCMK_OPT_PE_WARN_SERIES_MAX, NULL, "integer", NULL, "5000", pcmk__valid_number, N_("The number of scheduler inputs resulting in warnings to save"), N_("Zero to disable, -1 to store unlimited.") }, { PCMK_OPT_PE_INPUT_SERIES_MAX, NULL, "integer", NULL, "4000", pcmk__valid_number, N_("The number of scheduler inputs without errors or warnings to save"), N_("Zero to disable, -1 to store unlimited.") }, /* Node health */ { - PCMK__OPT_NODE_HEALTH_STRATEGY, NULL, "select", + PCMK_OPT_NODE_HEALTH_STRATEGY, NULL, "select", PCMK__VALUE_NONE ", " PCMK__VALUE_MIGRATE_ON_RED ", " PCMK__VALUE_ONLY_GREEN ", " PCMK__VALUE_PROGRESSIVE ", " PCMK__VALUE_CUSTOM, PCMK__VALUE_NONE, pcmk__validate_health_strategy, N_("How cluster should react to node health attributes"), N_("Requires external entities to create node attributes (named with " "the prefix \"#health\") with values \"red\", " "\"yellow\", or \"green\".") }, { PCMK_OPT_NODE_HEALTH_BASE, NULL, "integer", NULL, "0", pcmk__valid_number, N_("Base health score assigned to a node"), N_("Only used when \"node-health-strategy\" is set to \"progressive\".") }, { PCMK_OPT_NODE_HEALTH_GREEN, NULL, "integer", NULL, "0", pcmk__valid_number, N_("The score to use for a node health attribute whose value is \"green\""), N_("Only used when \"node-health-strategy\" is set to \"custom\" or \"progressive\".") }, { PCMK__OPT_NODE_HEALTH_YELLOW, NULL, "integer", NULL, "0", pcmk__valid_number, N_("The score to use for a node health attribute whose value is \"yellow\""), N_("Only used when \"node-health-strategy\" is set to \"custom\" or \"progressive\".") }, { PCMK_OPT_NODE_HEALTH_RED, NULL, "integer", NULL, "-INFINITY", pcmk__valid_number, N_("The score to use for a node health attribute whose value is \"red\""), N_("Only used when \"node-health-strategy\" is set to \"custom\" or \"progressive\".") }, /*Placement Strategy*/ { PCMK_OPT_PLACEMENT_STRATEGY, NULL, "select", "default, utilization, minimal, balanced", "default", check_placement_strategy, N_("How the cluster should allocate resources to nodes"), NULL }, }; void pe_metadata(pcmk__output_t *out) { const char *desc_short = "Pacemaker scheduler options"; const char *desc_long = "Cluster options used by Pacemaker's scheduler"; gchar *s = pcmk__format_option_metadata("pacemaker-schedulerd", desc_short, desc_long, pe_opts, PCMK__NELEM(pe_opts)); out->output_xml(out, "metadata", s); g_free(s); } void verify_pe_options(GHashTable * options) { pcmk__validate_cluster_options(options, pe_opts, PCMK__NELEM(pe_opts)); } const char * pe_pref(GHashTable * options, const char *name) { return pcmk__cluster_option(options, pe_opts, PCMK__NELEM(pe_opts), name); } const char * fail2text(enum action_fail_response fail) { const char *result = ""; switch (fail) { case pcmk_on_fail_ignore: result = "ignore"; break; case pcmk_on_fail_demote: result = "demote"; break; case pcmk_on_fail_block: result = "block"; break; case pcmk_on_fail_restart: result = "recover"; break; case pcmk_on_fail_ban: result = "migrate"; break; case pcmk_on_fail_stop: result = "stop"; break; case pcmk_on_fail_fence_node: result = "fence"; break; case pcmk_on_fail_standby_node: result = "standby"; break; case pcmk_on_fail_restart_container: result = "restart-container"; break; case pcmk_on_fail_reset_remote: result = "reset-remote"; break; } return result; } enum action_tasks text2task(const char *task) { if (pcmk__str_eq(task, PCMK_ACTION_STOP, pcmk__str_casei)) { return pcmk_action_stop; } else if (pcmk__str_eq(task, PCMK_ACTION_STOPPED, pcmk__str_casei)) { return pcmk_action_stopped; } else if (pcmk__str_eq(task, PCMK_ACTION_START, pcmk__str_casei)) { return pcmk_action_start; } else if (pcmk__str_eq(task, PCMK_ACTION_RUNNING, pcmk__str_casei)) { return pcmk_action_started; } else if (pcmk__str_eq(task, PCMK_ACTION_DO_SHUTDOWN, pcmk__str_casei)) { return pcmk_action_shutdown; } else if (pcmk__str_eq(task, PCMK_ACTION_STONITH, pcmk__str_casei)) { return pcmk_action_fence; } else if (pcmk__str_eq(task, PCMK_ACTION_MONITOR, pcmk__str_casei)) { return pcmk_action_monitor; } else if (pcmk__str_eq(task, PCMK_ACTION_NOTIFY, pcmk__str_casei)) { return pcmk_action_notify; } else if (pcmk__str_eq(task, PCMK_ACTION_NOTIFIED, pcmk__str_casei)) { return pcmk_action_notified; } else if (pcmk__str_eq(task, PCMK_ACTION_PROMOTE, pcmk__str_casei)) { return pcmk_action_promote; } else if (pcmk__str_eq(task, PCMK_ACTION_DEMOTE, pcmk__str_casei)) { return pcmk_action_demote; } else if (pcmk__str_eq(task, PCMK_ACTION_PROMOTED, pcmk__str_casei)) { return pcmk_action_promoted; } else if (pcmk__str_eq(task, PCMK_ACTION_DEMOTED, pcmk__str_casei)) { return pcmk_action_demoted; } return pcmk_action_unspecified; } const char * task2text(enum action_tasks task) { const char *result = ""; switch (task) { case pcmk_action_unspecified: result = "no_action"; break; case pcmk_action_stop: result = PCMK_ACTION_STOP; break; case pcmk_action_stopped: result = PCMK_ACTION_STOPPED; break; case pcmk_action_start: result = PCMK_ACTION_START; break; case pcmk_action_started: result = PCMK_ACTION_RUNNING; break; case pcmk_action_shutdown: result = PCMK_ACTION_DO_SHUTDOWN; break; case pcmk_action_fence: result = PCMK_ACTION_STONITH; break; case pcmk_action_monitor: result = PCMK_ACTION_MONITOR; break; case pcmk_action_notify: result = PCMK_ACTION_NOTIFY; break; case pcmk_action_notified: result = PCMK_ACTION_NOTIFIED; break; case pcmk_action_promote: result = PCMK_ACTION_PROMOTE; break; case pcmk_action_promoted: result = PCMK_ACTION_PROMOTED; break; case pcmk_action_demote: result = PCMK_ACTION_DEMOTE; break; case pcmk_action_demoted: result = PCMK_ACTION_DEMOTED; break; } return result; } const char * role2text(enum rsc_role_e role) { switch (role) { case pcmk_role_stopped: return PCMK__ROLE_STOPPED; case pcmk_role_started: return PCMK__ROLE_STARTED; case pcmk_role_unpromoted: #ifdef PCMK__COMPAT_2_0 return PCMK__ROLE_UNPROMOTED_LEGACY; #else return PCMK__ROLE_UNPROMOTED; #endif case pcmk_role_promoted: #ifdef PCMK__COMPAT_2_0 return PCMK__ROLE_PROMOTED_LEGACY; #else return PCMK__ROLE_PROMOTED; #endif default: // pcmk_role_unknown return PCMK__ROLE_UNKNOWN; } } enum rsc_role_e text2role(const char *role) { if (pcmk__str_eq(role, PCMK__ROLE_UNKNOWN, pcmk__str_casei|pcmk__str_null_matches)) { return pcmk_role_unknown; } else if (pcmk__str_eq(role, PCMK__ROLE_STOPPED, pcmk__str_casei)) { return pcmk_role_stopped; } else if (pcmk__str_eq(role, PCMK__ROLE_STARTED, pcmk__str_casei)) { return pcmk_role_started; } else if (pcmk__strcase_any_of(role, PCMK__ROLE_UNPROMOTED, PCMK__ROLE_UNPROMOTED_LEGACY, NULL)) { return pcmk_role_unpromoted; } else if (pcmk__strcase_any_of(role, PCMK__ROLE_PROMOTED, PCMK__ROLE_PROMOTED_LEGACY, NULL)) { return pcmk_role_promoted; } return pcmk_role_unknown; // Invalid role given } void add_hash_param(GHashTable * hash, const char *name, const char *value) { CRM_CHECK(hash != NULL, return); crm_trace("Adding name='%s' value='%s' to hash table", pcmk__s(name, ""), pcmk__s(value, "")); if (name == NULL || value == NULL) { return; } else if (pcmk__str_eq(value, "#default", pcmk__str_casei)) { return; } else if (g_hash_table_lookup(hash, name) == NULL) { g_hash_table_insert(hash, strdup(name), strdup(value)); } } /*! * \internal * \brief Look up an attribute value on the appropriate node * * If \p node is a guest node and either the \c XML_RSC_ATTR_TARGET meta * attribute is set to "host" for \p rsc or \p force_host is \c true, query the * attribute on the node's host. Otherwise, query the attribute on \p node * itself. * * \param[in] node Node to query attribute value on by default * \param[in] name Name of attribute to query * \param[in] rsc Resource on whose behalf we're querying * \param[in] node_type Type of resource location lookup * \param[in] force_host Force a lookup on the guest node's host, regardless of * the \c XML_RSC_ATTR_TARGET value * * \return Value of the attribute on \p node or on the host of \p node * * \note If \p force_host is \c true, \p node \e must be a guest node. */ const char * pe__node_attribute_calculated(const pcmk_node_t *node, const char *name, const pcmk_resource_t *rsc, enum pcmk__rsc_node node_type, bool force_host) { // @TODO: Use pe__is_guest_node() after merging libpe_{rules,status} bool is_guest = (node != NULL) && (node->details->type == pcmk_node_variant_remote) && (node->details->remote_rsc != NULL) && (node->details->remote_rsc->container != NULL); const char *source = NULL; const char *node_type_s = NULL; const char *reason = NULL; const pcmk_resource_t *container = NULL; const pcmk_node_t *host = NULL; CRM_ASSERT((node != NULL) && (name != NULL) && (rsc != NULL) && (!force_host || is_guest)); /* Ignore XML_RSC_ATTR_TARGET if node is not a guest node. This represents a * user configuration error. */ source = g_hash_table_lookup(rsc->meta, XML_RSC_ATTR_TARGET); if (!force_host && (!is_guest || !pcmk__str_eq(source, "host", pcmk__str_casei))) { return g_hash_table_lookup(node->details->attrs, name); } container = node->details->remote_rsc->container; switch (node_type) { case pcmk__rsc_node_assigned: node_type_s = "assigned"; host = container->allocated_to; if (host == NULL) { reason = "not assigned"; } break; case pcmk__rsc_node_current: node_type_s = "current"; if (container->running_on != NULL) { host = container->running_on->data; } if (host == NULL) { reason = "inactive"; } break; default: // Add support for other enum pcmk__rsc_node values if needed CRM_ASSERT(false); break; } if (host != NULL) { const char *value = g_hash_table_lookup(host->details->attrs, name); pcmk__rsc_trace(rsc, "%s: Value lookup for %s on %s container host %s %s%s", rsc->id, name, node_type_s, pe__node_name(host), ((value != NULL)? "succeeded: " : "failed"), pcmk__s(value, "")); return value; } pcmk__rsc_trace(rsc, "%s: Not looking for %s on %s container host: %s is %s", rsc->id, name, node_type_s, container->id, reason); return NULL; } const char * pe_node_attribute_raw(const pcmk_node_t *node, const char *name) { if(node == NULL) { return NULL; } return g_hash_table_lookup(node->details->attrs, name); } diff --git a/tools/crm_resource_print.c b/tools/crm_resource_print.c index bdf3ad9b60..9db3024060 100644 --- a/tools/crm_resource_print.c +++ b/tools/crm_resource_print.c @@ -1,824 +1,824 @@ /* - * Copyright 2004-2023 the Pacemaker project contributors + * Copyright 2004-2024 the Pacemaker project contributors * * The version control history for this file may have further details. * * This source code is licensed under the GNU General Public License version 2 * or later (GPLv2+) WITHOUT ANY WARRANTY. */ #include #include #include #include #include #include #define cons_string(x) x?x:"NA" static int print_constraint(xmlNode *xml_obj, void *userdata) { pcmk_scheduler_t *scheduler = (pcmk_scheduler_t *) userdata; pcmk__output_t *out = scheduler->priv; xmlNode *lifetime = NULL; const char *id = crm_element_value(xml_obj, XML_ATTR_ID); if (id == NULL) { return pcmk_rc_ok; } // @COMPAT lifetime is deprecated lifetime = first_named_child(xml_obj, "lifetime"); if (pe_evaluate_rules(lifetime, NULL, scheduler->now, NULL) == FALSE) { return pcmk_rc_ok; } if (!pcmk__xe_is(xml_obj, XML_CONS_TAG_RSC_DEPEND)) { return pcmk_rc_ok; } out->info(out, "Constraint %s %s %s %s %s %s %s", xml_obj->name, cons_string(crm_element_value(xml_obj, XML_ATTR_ID)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET)), cons_string(crm_element_value(xml_obj, XML_RULE_ATTR_SCORE)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_SOURCE_ROLE)), cons_string(crm_element_value(xml_obj, XML_COLOC_ATTR_TARGET_ROLE))); return pcmk_rc_ok; } void cli_resource_print_cts_constraints(pcmk_scheduler_t *scheduler) { pcmk__xe_foreach_child(pcmk_find_cib_element(scheduler->input, XML_CIB_TAG_CONSTRAINTS), NULL, print_constraint, scheduler); } void cli_resource_print_cts(pcmk_resource_t *rsc, pcmk__output_t *out) { const char *host = NULL; bool needs_quorum = TRUE; const char *rtype = crm_element_value(rsc->xml, XML_ATTR_TYPE); const char *rprov = crm_element_value(rsc->xml, XML_AGENT_ATTR_PROVIDER); const char *rclass = crm_element_value(rsc->xml, XML_AGENT_ATTR_CLASS); pcmk_node_t *node = pe__current_node(rsc); if (pcmk__str_eq(rclass, PCMK_RESOURCE_CLASS_STONITH, pcmk__str_casei)) { needs_quorum = FALSE; } else { // @TODO check requires in resource meta-data and rsc_defaults } if (node != NULL) { host = node->details->uname; } out->info(out, "Resource: %s %s %s %s %s %s %s %s %d %lld %#.16llx", rsc->xml->name, rsc->id, rsc->clone_name ? rsc->clone_name : rsc->id, rsc->parent ? rsc->parent->id : "NA", rprov ? rprov : "NA", rclass, rtype, host ? host : "NA", needs_quorum, rsc->flags, rsc->flags); g_list_foreach(rsc->children, (GFunc) cli_resource_print_cts, out); } // \return Standard Pacemaker return code int cli_resource_print_operations(const char *rsc_id, const char *host_uname, bool active, pcmk_scheduler_t *scheduler) { pcmk__output_t *out = scheduler->priv; int rc = pcmk_rc_no_output; GList *ops = find_operations(rsc_id, host_uname, active, scheduler); if (!ops) { return rc; } out->begin_list(out, NULL, NULL, "Resource Operations"); rc = pcmk_rc_ok; for (GList *lpc = ops; lpc != NULL; lpc = lpc->next) { xmlNode *xml_op = (xmlNode *) lpc->data; out->message(out, "node-and-op", scheduler, xml_op); } out->end_list(out); return rc; } // \return Standard Pacemaker return code int cli_resource_print(pcmk_resource_t *rsc, pcmk_scheduler_t *scheduler, bool expanded) { pcmk__output_t *out = scheduler->priv; uint32_t show_opts = pcmk_show_pending; GList *all = NULL; all = g_list_prepend(all, (gpointer) "*"); out->begin_list(out, NULL, NULL, "Resource Config"); out->message(out, crm_map_element_name(rsc->xml), show_opts, rsc, all, all); out->message(out, "resource-config", rsc, !expanded); out->end_list(out); g_list_free(all); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("attribute-list", "pcmk_resource_t *", "const char *", "const char *") static int attribute_list_default(pcmk__output_t *out, va_list args) { pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *); const char *attr = va_arg(args, char *); const char *value = va_arg(args, const char *); if (value != NULL) { out->begin_list(out, NULL, NULL, "Attributes"); out->list_item(out, attr, "%s", value); out->end_list(out); return pcmk_rc_ok; } else { out->err(out, "Attribute '%s' not found for '%s'", attr, rsc->id); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("agent-status", "int", "const char *", "const char *", "const char *", "const char *", "const char *", "crm_exit_t", "const char *") static int agent_status_default(pcmk__output_t *out, va_list args) { int status = va_arg(args, int); const char *action = va_arg(args, const char *); const char *name = va_arg(args, const char *); const char *class = va_arg(args, const char *); const char *provider = va_arg(args, const char *); const char *type = va_arg(args, const char *); crm_exit_t rc = va_arg(args, crm_exit_t); const char *exit_reason = va_arg(args, const char *); if (status == PCMK_EXEC_DONE) { /* Operation [for ] ([:]:) * returned ([: ]) */ out->info(out, "Operation %s%s%s (%s%s%s:%s) returned %d (%s%s%s)", action, ((name == NULL)? "" : " for "), ((name == NULL)? "" : name), class, ((provider == NULL)? "" : ":"), ((provider == NULL)? "" : provider), type, (int) rc, services_ocf_exitcode_str((int) rc), ((exit_reason == NULL)? "" : ": "), ((exit_reason == NULL)? "" : exit_reason)); } else { /* Operation [for ] ([:]:) * could not be executed ([: ]) */ out->err(out, "Operation %s%s%s (%s%s%s:%s) could not be executed (%s%s%s)", action, ((name == NULL)? "" : " for "), ((name == NULL)? "" : name), class, ((provider == NULL)? "" : ":"), ((provider == NULL)? "" : provider), type, pcmk_exec_status_str(status), ((exit_reason == NULL)? "" : ": "), ((exit_reason == NULL)? "" : exit_reason)); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("agent-status", "int", "const char *", "const char *", "const char *", "const char *", "const char *", "crm_exit_t", "const char *") static int agent_status_xml(pcmk__output_t *out, va_list args) { int status = va_arg(args, int); const char *action G_GNUC_UNUSED = va_arg(args, const char *); const char *name G_GNUC_UNUSED = va_arg(args, const char *); const char *class G_GNUC_UNUSED = va_arg(args, const char *); const char *provider G_GNUC_UNUSED = va_arg(args, const char *); const char *type G_GNUC_UNUSED = va_arg(args, const char *); crm_exit_t rc = va_arg(args, crm_exit_t); const char *exit_reason = va_arg(args, const char *); char *exit_str = pcmk__itoa(rc); char *status_str = pcmk__itoa(status); pcmk__output_create_xml_node(out, "agent-status", "code", exit_str, "message", services_ocf_exitcode_str((int) rc), "execution_code", status_str, "execution_message", pcmk_exec_status_str(status), "reason", exit_reason, NULL); free(exit_str); free(status_str); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("attribute-list", "pcmk_resource_t *", "const char *", "const char *") static int attribute_list_text(pcmk__output_t *out, va_list args) { pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *); const char *attr = va_arg(args, char *); const char *value = va_arg(args, const char *); if (value != NULL) { pcmk__formatted_printf(out, "%s\n", value); return pcmk_rc_ok; } else { out->err(out, "Attribute '%s' not found for '%s'", attr, rsc->id); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("override", "const char *", "const char *", "const char *") static int override_default(pcmk__output_t *out, va_list args) { const char *rsc_name = va_arg(args, const char *); const char *name = va_arg(args, const char *); const char *value = va_arg(args, const char *); if (rsc_name == NULL) { out->list_item(out, NULL, "Overriding the cluster configuration with '%s' = '%s'", name, value); } else { out->list_item(out, NULL, "Overriding the cluster configuration for '%s' with '%s' = '%s'", rsc_name, name, value); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("override", "const char *", "const char *", "const char *") static int override_xml(pcmk__output_t *out, va_list args) { const char *rsc_name = va_arg(args, const char *); const char *name = va_arg(args, const char *); const char *value = va_arg(args, const char *); xmlNodePtr node = pcmk__output_create_xml_node(out, "override", "name", name, "value", value, NULL); if (rsc_name != NULL) { crm_xml_add(node, "rsc", rsc_name); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("property-list", "pcmk_resource_t *", "const char *") static int property_list_default(pcmk__output_t *out, va_list args) { pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *); const char *attr = va_arg(args, char *); const char *value = crm_element_value(rsc->xml, attr); if (value != NULL) { out->begin_list(out, NULL, NULL, "Properties"); out->list_item(out, attr, "%s", value); out->end_list(out); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("property-list", "pcmk_resource_t *", "const char *") static int property_list_text(pcmk__output_t *out, va_list args) { pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *); const char *attr = va_arg(args, const char *); const char *value = crm_element_value(rsc->xml, attr); if (value != NULL) { pcmk__formatted_printf(out, "%s\n", value); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-agent-action", "int", "const char *", "const char *", "const char *", "const char *", "const char *", "GHashTable *", "crm_exit_t", "int", "const char *", "const char *", "const char *") static int resource_agent_action_default(pcmk__output_t *out, va_list args) { int verbose = va_arg(args, int); const char *class = va_arg(args, const char *); const char *provider = va_arg(args, const char *); const char *type = va_arg(args, const char *); const char *rsc_name = va_arg(args, const char *); const char *action = va_arg(args, const char *); GHashTable *overrides = va_arg(args, GHashTable *); crm_exit_t rc = va_arg(args, crm_exit_t); int status = va_arg(args, int); const char *exit_reason = va_arg(args, const char *); const char *stdout_data = va_arg(args, const char *); const char *stderr_data = va_arg(args, const char *); if (overrides) { GHashTableIter iter; const char *name = NULL; const char *value = NULL; out->begin_list(out, NULL, NULL, "overrides"); g_hash_table_iter_init(&iter, overrides); while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &value)) { out->message(out, "override", rsc_name, name, value); } out->end_list(out); } out->message(out, "agent-status", status, action, rsc_name, class, provider, type, rc, exit_reason); /* hide output for validate-all if not in verbose */ if ((verbose == 0) && pcmk__str_eq(action, PCMK_ACTION_VALIDATE_ALL, pcmk__str_casei)) { return pcmk_rc_ok; } if (stdout_data || stderr_data) { xmlNodePtr doc = NULL; if (stdout_data != NULL) { doc = string2xml(stdout_data); } if (doc != NULL) { out->output_xml(out, "command", stdout_data); xmlFreeNode(doc); } else { out->subprocess_output(out, rc, stdout_data, stderr_data); } } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-agent-action", "int", "const char *", "const char *", "const char *", "const char *", "const char *", "GHashTable *", "crm_exit_t", "int", "const char *", "const char *", "const char *") static int resource_agent_action_xml(pcmk__output_t *out, va_list args) { int verbose G_GNUC_UNUSED = va_arg(args, int); const char *class = va_arg(args, const char *); const char *provider = va_arg(args, const char *); const char *type = va_arg(args, const char *); const char *rsc_name = va_arg(args, const char *); const char *action = va_arg(args, const char *); GHashTable *overrides = va_arg(args, GHashTable *); crm_exit_t rc = va_arg(args, crm_exit_t); int status = va_arg(args, int); const char *exit_reason = va_arg(args, const char *); const char *stdout_data = va_arg(args, const char *); const char *stderr_data = va_arg(args, const char *); xmlNodePtr node = pcmk__output_xml_create_parent(out, "resource-agent-action", "action", action, "class", class, "type", type, NULL); if (rsc_name) { crm_xml_add(node, "rsc", rsc_name); } if (provider) { crm_xml_add(node, "provider", provider); } if (overrides) { GHashTableIter iter; const char *name = NULL; const char *value = NULL; out->begin_list(out, NULL, NULL, "overrides"); g_hash_table_iter_init(&iter, overrides); while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &value)) { out->message(out, "override", rsc_name, name, value); } out->end_list(out); } out->message(out, "agent-status", status, action, rsc_name, class, provider, type, rc, exit_reason); if (stdout_data || stderr_data) { xmlNodePtr doc = NULL; if (stdout_data != NULL) { doc = string2xml(stdout_data); } if (doc != NULL) { out->output_xml(out, "command", stdout_data); xmlFreeNode(doc); } else { out->subprocess_output(out, rc, stdout_data, stderr_data); } } pcmk__output_xml_pop_parent(out); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-check-list", "resource_checks_t *") static int resource_check_list_default(pcmk__output_t *out, va_list args) { resource_checks_t *checks = va_arg(args, resource_checks_t *); const pcmk_resource_t *parent = pe__const_top_resource(checks->rsc, false); if (checks->flags == 0) { return pcmk_rc_no_output; } out->begin_list(out, NULL, NULL, "Resource Checks"); if (pcmk_is_set(checks->flags, rsc_remain_stopped)) { out->list_item(out, "check", "Configuration specifies '%s' should remain stopped", parent->id); } if (pcmk_is_set(checks->flags, rsc_unpromotable)) { out->list_item(out, "check", "Configuration specifies '%s' should not be promoted", parent->id); } if (pcmk_is_set(checks->flags, rsc_unmanaged)) { out->list_item(out, "check", "Configuration prevents cluster from stopping or starting unmanaged '%s'", parent->id); } if (pcmk_is_set(checks->flags, rsc_locked)) { out->list_item(out, "check", "'%s' is locked to node %s due to shutdown", parent->id, checks->lock_node); } if (pcmk_is_set(checks->flags, rsc_node_health)) { out->list_item(out, "check", "'%s' cannot run on unhealthy nodes due to " - PCMK__OPT_NODE_HEALTH_STRATEGY "='%s'", + PCMK_OPT_NODE_HEALTH_STRATEGY "='%s'", parent->id, pe_pref(checks->rsc->cluster->config_hash, - PCMK__OPT_NODE_HEALTH_STRATEGY)); + PCMK_OPT_NODE_HEALTH_STRATEGY)); } out->end_list(out); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-check-list", "resource_checks_t *") static int resource_check_list_xml(pcmk__output_t *out, va_list args) { resource_checks_t *checks = va_arg(args, resource_checks_t *); const pcmk_resource_t *parent = pe__const_top_resource(checks->rsc, false); xmlNodePtr node = pcmk__output_create_xml_node(out, "check", "id", parent->id, NULL); if (pcmk_is_set(checks->flags, rsc_remain_stopped)) { pcmk__xe_set_bool_attr(node, "remain_stopped", true); } if (pcmk_is_set(checks->flags, rsc_unpromotable)) { pcmk__xe_set_bool_attr(node, "promotable", false); } if (pcmk_is_set(checks->flags, rsc_unmanaged)) { pcmk__xe_set_bool_attr(node, "unmanaged", true); } if (pcmk_is_set(checks->flags, rsc_locked)) { crm_xml_add(node, "locked-to", checks->lock_node); } if (pcmk_is_set(checks->flags, rsc_node_health)) { pcmk__xe_set_bool_attr(node, "unhealthy", true); } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-search-list", "GList *", "const char *") static int resource_search_list_default(pcmk__output_t *out, va_list args) { GList *nodes = va_arg(args, GList *); const char *requested_name = va_arg(args, const char *); bool printed = false; int rc = pcmk_rc_no_output; if (!out->is_quiet(out) && nodes == NULL) { out->err(out, "resource %s is NOT running", requested_name); return rc; } for (GList *lpc = nodes; lpc != NULL; lpc = lpc->next) { node_info_t *ni = (node_info_t *) lpc->data; if (!printed) { out->begin_list(out, NULL, NULL, "Nodes"); printed = true; rc = pcmk_rc_ok; } if (out->is_quiet(out)) { out->list_item(out, "node", "%s", ni->node_name); } else { const char *role_text = ""; if (ni->promoted) { #ifdef PCMK__COMPAT_2_0 role_text = " " PCMK__ROLE_PROMOTED_LEGACY; #else role_text = " " PCMK__ROLE_PROMOTED; #endif } out->list_item(out, "node", "resource %s is running on: %s%s", requested_name, ni->node_name, role_text); } } if (printed) { out->end_list(out); } return rc; } PCMK__OUTPUT_ARGS("resource-search-list", "GList *", "const char *") static int resource_search_list_xml(pcmk__output_t *out, va_list args) { GList *nodes = va_arg(args, GList *); const char *requested_name = va_arg(args, const char *); pcmk__output_xml_create_parent(out, "nodes", "resource", requested_name, NULL); for (GList *lpc = nodes; lpc != NULL; lpc = lpc->next) { node_info_t *ni = (node_info_t *) lpc->data; xmlNodePtr sub_node = pcmk__output_create_xml_text_node(out, "node", ni->node_name); if (ni->promoted) { crm_xml_add(sub_node, "state", "promoted"); } } return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-reasons-list", "GList *", "pcmk_resource_t *", "pcmk_node_t *") static int resource_reasons_list_default(pcmk__output_t *out, va_list args) { GList *resources = va_arg(args, GList *); pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *); pcmk_node_t *node = va_arg(args, pcmk_node_t *); const char *host_uname = (node == NULL)? NULL : node->details->uname; out->begin_list(out, NULL, NULL, "Resource Reasons"); if ((rsc == NULL) && (host_uname == NULL)) { GList *lpc = NULL; GList *hosts = NULL; for (lpc = resources; lpc != NULL; lpc = lpc->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data; rsc->fns->location(rsc, &hosts, TRUE); if (hosts == NULL) { out->list_item(out, "reason", "Resource %s is not running", rsc->id); } else { out->list_item(out, "reason", "Resource %s is running", rsc->id); } cli_resource_check(out, rsc, NULL); g_list_free(hosts); hosts = NULL; } } else if ((rsc != NULL) && (host_uname != NULL)) { if (resource_is_running_on(rsc, host_uname)) { out->list_item(out, "reason", "Resource %s is running on host %s", rsc->id, host_uname); } else { out->list_item(out, "reason", "Resource %s is not running on host %s", rsc->id, host_uname); } cli_resource_check(out, rsc, node); } else if ((rsc == NULL) && (host_uname != NULL)) { const char* host_uname = node->details->uname; GList *allResources = node->details->allocated_rsc; GList *activeResources = node->details->running_rsc; GList *unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp); GList *lpc = NULL; for (lpc = activeResources; lpc != NULL; lpc = lpc->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data; out->list_item(out, "reason", "Resource %s is running on host %s", rsc->id, host_uname); cli_resource_check(out, rsc, node); } for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data; out->list_item(out, "reason", "Resource %s is assigned to host %s but not running", rsc->id, host_uname); cli_resource_check(out, rsc, node); } g_list_free(allResources); g_list_free(activeResources); g_list_free(unactiveResources); } else if ((rsc != NULL) && (host_uname == NULL)) { GList *hosts = NULL; rsc->fns->location(rsc, &hosts, TRUE); out->list_item(out, "reason", "Resource %s is %srunning", rsc->id, (hosts? "" : "not ")); cli_resource_check(out, rsc, NULL); g_list_free(hosts); } out->end_list(out); return pcmk_rc_ok; } PCMK__OUTPUT_ARGS("resource-reasons-list", "GList *", "pcmk_resource_t *", "pcmk_node_t *") static int resource_reasons_list_xml(pcmk__output_t *out, va_list args) { GList *resources = va_arg(args, GList *); pcmk_resource_t *rsc = va_arg(args, pcmk_resource_t *); pcmk_node_t *node = va_arg(args, pcmk_node_t *); const char *host_uname = (node == NULL)? NULL : node->details->uname; xmlNodePtr xml_node = pcmk__output_xml_create_parent(out, "reason", NULL); if ((rsc == NULL) && (host_uname == NULL)) { GList *lpc = NULL; GList *hosts = NULL; pcmk__output_xml_create_parent(out, "resources", NULL); for (lpc = resources; lpc != NULL; lpc = lpc->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data; rsc->fns->location(rsc, &hosts, TRUE); pcmk__output_xml_create_parent(out, "resource", "id", rsc->id, "running", pcmk__btoa(hosts != NULL), NULL); cli_resource_check(out, rsc, NULL); pcmk__output_xml_pop_parent(out); g_list_free(hosts); hosts = NULL; } pcmk__output_xml_pop_parent(out); } else if ((rsc != NULL) && (host_uname != NULL)) { if (resource_is_running_on(rsc, host_uname)) { crm_xml_add(xml_node, "running_on", host_uname); } cli_resource_check(out, rsc, node); } else if ((rsc == NULL) && (host_uname != NULL)) { const char* host_uname = node->details->uname; GList *allResources = node->details->allocated_rsc; GList *activeResources = node->details->running_rsc; GList *unactiveResources = pcmk__subtract_lists(allResources, activeResources, (GCompareFunc) strcmp); GList *lpc = NULL; pcmk__output_xml_create_parent(out, "resources", NULL); for (lpc = activeResources; lpc != NULL; lpc = lpc->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data; pcmk__output_xml_create_parent(out, "resource", "id", rsc->id, "running", "true", "host", host_uname, NULL); cli_resource_check(out, rsc, node); pcmk__output_xml_pop_parent(out); } for(lpc = unactiveResources; lpc != NULL; lpc = lpc->next) { pcmk_resource_t *rsc = (pcmk_resource_t *) lpc->data; pcmk__output_xml_create_parent(out, "resource", "id", rsc->id, "running", "false", "host", host_uname, NULL); cli_resource_check(out, rsc, node); pcmk__output_xml_pop_parent(out); } pcmk__output_xml_pop_parent(out); g_list_free(allResources); g_list_free(activeResources); g_list_free(unactiveResources); } else if ((rsc != NULL) && (host_uname == NULL)) { GList *hosts = NULL; rsc->fns->location(rsc, &hosts, TRUE); crm_xml_add(xml_node, "running", pcmk__btoa(hosts != NULL)); cli_resource_check(out, rsc, NULL); g_list_free(hosts); } return pcmk_rc_ok; } static void add_resource_name(pcmk_resource_t *rsc, pcmk__output_t *out) { if (rsc->children == NULL) { out->list_item(out, "resource", "%s", rsc->id); } else { g_list_foreach(rsc->children, (GFunc) add_resource_name, out); } } PCMK__OUTPUT_ARGS("resource-names-list", "GList *") static int resource_names(pcmk__output_t *out, va_list args) { GList *resources = va_arg(args, GList *); if (resources == NULL) { out->err(out, "NO resources configured\n"); return pcmk_rc_no_output; } out->begin_list(out, NULL, NULL, "Resource Names"); g_list_foreach(resources, (GFunc) add_resource_name, out); out->end_list(out); return pcmk_rc_ok; } static pcmk__message_entry_t fmt_functions[] = { { "agent-status", "default", agent_status_default }, { "agent-status", "xml", agent_status_xml }, { "attribute-list", "default", attribute_list_default }, { "attribute-list", "text", attribute_list_text }, { "override", "default", override_default }, { "override", "xml", override_xml }, { "property-list", "default", property_list_default }, { "property-list", "text", property_list_text }, { "resource-agent-action", "default", resource_agent_action_default }, { "resource-agent-action", "xml", resource_agent_action_xml }, { "resource-check-list", "default", resource_check_list_default }, { "resource-check-list", "xml", resource_check_list_xml }, { "resource-search-list", "default", resource_search_list_default }, { "resource-search-list", "xml", resource_search_list_xml }, { "resource-reasons-list", "default", resource_reasons_list_default }, { "resource-reasons-list", "xml", resource_reasons_list_xml }, { "resource-names-list", "default", resource_names }, { NULL, NULL, NULL } }; void crm_resource_register_messages(pcmk__output_t *out) { pcmk__register_messages(out, fmt_functions); }