diff --git a/include/crm/crm.h b/include/crm/crm.h index c116ab8366..389b6aa30f 100644 --- a/include/crm/crm.h +++ b/include/crm/crm.h @@ -1,232 +1,232 @@ /* * Copyright 2004-2020 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 CRM__H # define CRM__H #ifdef __cplusplus extern "C" { #endif /** * \file * \brief A dumping ground * \ingroup core */ # include # include # include # include # include # include /*! * The CRM feature set assists with compatibility in mixed-version clusters. * The major version number increases when nodes with different versions * would not work (rolling upgrades are not allowed). The minor version * number increases when mixed-version clusters are allowed only during * rolling upgrades (a node with the oldest feature set will be elected DC). The * minor-minor version number is ignored, but allows resource agents to detect * cluster support for various features. * * The feature set also affects the processing of old saved CIBs (such as for * many scheduler regression tests). * * Particular feature points currently used by pacemaker: * * >2.1: Operation updates include timing data * >=3.0.5: XML v2 digests are created * >=3.0.8: Peers do not need acks for cancellations * >=3.0.9: DC will send its own shutdown request to all peers * XML v2 patchsets are created by default * >=3.0.13: Fail counts include operation name and interval * >=3.2.0: DC supports PCMK_LRM_OP_INVALID and PCMK_LRM_OP_NOT_CONNECTED */ -# define CRM_FEATURE_SET "3.6.0" +# define CRM_FEATURE_SET "3.6.1" # define EOS '\0' # define DIMOF(a) ((int) (sizeof(a)/sizeof(a[0])) ) # ifndef MAX_NAME # define MAX_NAME 256 # endif # ifndef __GNUC__ # define __builtin_expect(expr, result) (expr) # endif /* Some handy macros used by the Linux kernel */ # define __likely(expr) __builtin_expect(expr, 1) # define __unlikely(expr) __builtin_expect(expr, 0) # define CRM_META "CRM_meta" extern char *crm_system_name; /* *INDENT-OFF* */ // Used for some internal IPC timeouts (maybe should be configurable option) # define MAX_IPC_DELAY 120 // How we represent "infinite" scores # define CRM_SCORE_INFINITY 1000000 # define CRM_INFINITY_S "INFINITY" # define CRM_PLUS_INFINITY_S "+" CRM_INFINITY_S # define CRM_MINUS_INFINITY_S "-" CRM_INFINITY_S /* @COMPAT API < 2.0.0 Deprecated "infinity" aliases * * INFINITY might be defined elsewhere (e.g. math.h), so undefine it first. * This, of course, complicates any attempt to use the other definition in any * code that includes this header. */ # undef INFINITY # define INFINITY_S "INFINITY" # define MINUS_INFINITY_S "-INFINITY" # define INFINITY 1000000 /* Sub-systems */ # define CRM_SYSTEM_DC "dc" # define CRM_SYSTEM_DCIB "dcib" /* The master CIB */ # define CRM_SYSTEM_CIB "cib" # define CRM_SYSTEM_CRMD "crmd" # define CRM_SYSTEM_LRMD "lrmd" # define CRM_SYSTEM_PENGINE "pengine" # define CRM_SYSTEM_TENGINE "tengine" # define CRM_SYSTEM_STONITHD "stonithd" # define CRM_SYSTEM_MCP "pacemakerd" // Names of internally generated node attributes # define CRM_ATTR_UNAME "#uname" # define CRM_ATTR_ID "#id" # define CRM_ATTR_KIND "#kind" # define CRM_ATTR_ROLE "#role" # define CRM_ATTR_IS_DC "#is_dc" # define CRM_ATTR_CLUSTER_NAME "#cluster-name" # define CRM_ATTR_SITE_NAME "#site-name" # define CRM_ATTR_UNFENCED "#node-unfenced" # define CRM_ATTR_DIGESTS_ALL "#digests-all" # define CRM_ATTR_DIGESTS_SECURE "#digests-secure" # define CRM_ATTR_RA_VERSION "#ra-version" # define CRM_ATTR_PROTOCOL "#attrd-protocol" /* Valid operations */ # define CRM_OP_NOOP "noop" # define CRM_OP_JOIN_ANNOUNCE "join_announce" # define CRM_OP_JOIN_OFFER "join_offer" # define CRM_OP_JOIN_REQUEST "join_request" # define CRM_OP_JOIN_ACKNAK "join_ack_nack" # define CRM_OP_JOIN_CONFIRM "join_confirm" # define CRM_OP_PING "ping" # define CRM_OP_NODE_INFO "node-info" # define CRM_OP_THROTTLE "throttle" # define CRM_OP_VOTE "vote" # define CRM_OP_NOVOTE "no-vote" # define CRM_OP_HELLO "hello" # define CRM_OP_PECALC "pe_calc" # define CRM_OP_QUIT "quit" # define CRM_OP_LOCAL_SHUTDOWN "start_shutdown" # define CRM_OP_SHUTDOWN_REQ "req_shutdown" # define CRM_OP_SHUTDOWN "do_shutdown" # define CRM_OP_FENCE "stonith" # define CRM_OP_REGISTER "register" # define CRM_OP_IPC_FWD "ipc_fwd" # define CRM_OP_INVOKE_LRM "lrm_invoke" # define CRM_OP_LRM_REFRESH "lrm_refresh" /* Deprecated */ # define CRM_OP_LRM_QUERY "lrm_query" # define CRM_OP_LRM_DELETE "lrm_delete" # define CRM_OP_LRM_FAIL "lrm_fail" # define CRM_OP_PROBED "probe_complete" # define CRM_OP_REPROBE "probe_again" # define CRM_OP_CLEAR_FAILCOUNT "clear_failcount" # define CRM_OP_REMOTE_STATE "remote_state" # define CRM_OP_RELAXED_SET "one-or-more" # define CRM_OP_RELAXED_CLONE "clone-one-or-more" # define CRM_OP_RM_NODE_CACHE "rm_node_cache" # define CRM_OP_MAINTENANCE_NODES "maintenance_nodes" /* Possible cluster membership states */ # define CRMD_JOINSTATE_DOWN "down" # define CRMD_JOINSTATE_PENDING "pending" # define CRMD_JOINSTATE_MEMBER "member" # define CRMD_JOINSTATE_NACK "banned" # define CRMD_ACTION_DELETE "delete" # define CRMD_ACTION_CANCEL "cancel" # define CRMD_ACTION_RELOAD "reload" # define CRMD_ACTION_MIGRATE "migrate_to" # define CRMD_ACTION_MIGRATED "migrate_from" # define CRMD_ACTION_START "start" # define CRMD_ACTION_STARTED "running" # define CRMD_ACTION_STOP "stop" # define CRMD_ACTION_STOPPED "stopped" # define CRMD_ACTION_PROMOTE "promote" # define CRMD_ACTION_PROMOTED "promoted" # define CRMD_ACTION_DEMOTE "demote" # define CRMD_ACTION_DEMOTED "demoted" # define CRMD_ACTION_NOTIFY "notify" # define CRMD_ACTION_NOTIFIED "notified" # define CRMD_ACTION_STATUS "monitor" # define CRMD_ACTION_METADATA "meta-data" # define CRMD_METADATA_CALL_TIMEOUT 30000 /* short names */ # define RSC_DELETE CRMD_ACTION_DELETE # define RSC_CANCEL CRMD_ACTION_CANCEL # define RSC_MIGRATE CRMD_ACTION_MIGRATE # define RSC_MIGRATED CRMD_ACTION_MIGRATED # define RSC_START CRMD_ACTION_START # define RSC_STARTED CRMD_ACTION_STARTED # define RSC_STOP CRMD_ACTION_STOP # define RSC_STOPPED CRMD_ACTION_STOPPED # define RSC_PROMOTE CRMD_ACTION_PROMOTE # define RSC_PROMOTED CRMD_ACTION_PROMOTED # define RSC_DEMOTE CRMD_ACTION_DEMOTE # define RSC_DEMOTED CRMD_ACTION_DEMOTED # define RSC_NOTIFY CRMD_ACTION_NOTIFY # define RSC_NOTIFIED CRMD_ACTION_NOTIFIED # define RSC_STATUS CRMD_ACTION_STATUS # define RSC_METADATA CRMD_ACTION_METADATA /* *INDENT-ON* */ typedef GList *GListPtr; # include # include static inline const char * crm_action_str(const char *task, guint interval_ms) { if ((task != NULL) && (interval_ms == 0) && (strcasecmp(task, RSC_STATUS) == 0)) { return "probe"; } return task; } #ifdef __cplusplus } #endif #endif diff --git a/tools/cibsecret.in b/tools/cibsecret.in index 568833c5c4..b232e3f0d1 100644 --- a/tools/cibsecret.in +++ b/tools/cibsecret.in @@ -1,409 +1,428 @@ #!/bin/sh # Copyright 2011-2020 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. # # cibsecret # # Manage the secrets directory (by default, /var/lib/pacemaker/lrm/secrets). # Secrets are ASCII files, holding one value per file: # // +# These constants must track crm_exit_t values +CRM_EX_OK=0 +CRM_EX_ERROR=1 +CRM_EX_NOT_INSTALLED=5 +CRM_EX_USAGE=64 +CRM_EX_UNAVAILABLE=69 +CRM_EX_OSFILE=72 +CRM_EX_CONFIG=78 +CRM_EX_DIGEST=104 +CRM_EX_NOSUCH=105 +CRM_EX_EXISTS=108 + LRM_CIBSECRETS="@LRM_CIBSECRETS_DIR@" PROG="$(basename "$0")" SSH_OPTS="-o StrictHostKeyChecking=no" MAGIC="lrm://" usage() { cat <] [] Options: --help Show this message, then exit --version Display version information, then exit -C Don't read or write the CIB Commands and their parameters: set Set the value of a sensitive resource parameter. get Display the locally stored value of a sensitive resource parameter. check Verify that the locally stored value of a sensitive resource parameter matches its locally stored MD5 hash. stash Make a non-sensitive resource parameter that is already in the CIB sensitive (move its value to a locally stored and protected file). This may not be used with -C. unstash Make a sensitive resource parameter that is already in the CIB non-sensitive (move its value from the locally stored file to the CIB). This may not be used with -C. delete Remove a sensitive resource parameter value. sync Copy all locally stored secrets to all other nodes. This command manages sensitive resource parameter values that should not be stored directly in Pacemaker's Cluster Information Base (CIB). Such values are handled by storing a special string directly in the CIB that tells Pacemaker to look in a separate, protected file for the actual value. The secret files are not encrypted, but protected by file system permissions such that only root can read or modify them. Since the secret files are stored locally, they must be synchronized across all cluster nodes. This command handles the synchronization using (in order of preference) pssh, pdsh, or ssh, so one of those must be installed. Before synchronizing, this command will ping the cluster nodes to determine which are alive, using fping if it is installed, otherwise the ping command. Installing fping is strongly recommended for better performance. Known limitations: This command can only be run from full cluster nodes (not Pacemaker Remote nodes). Changes are not atomic, so the cluster may use different values while a change is in progress. To avoid problems, it is recommended to put the cluster in maintenance mode when making changes with this command. Changes in secret values do not trigger a reload or restart of the affected resource, since they do not change the CIB. If a response is desired before the next cluster recheck interval, any CIB change (such as setting a node attribute) will trigger it. If any node is down when changes to secrets are made, or a new node is later added to the cluster, it may have different values when it joins the cluster, before "$PROG sync" is run. To avoid this, it is recommended to run the sync command (from another node) before starting Pacemaker on the node. Examples: $PROG set ipmi_node1 passwd SecreT_PASS $PROG get ipmi_node1 passwd $PROG check ipmi_node1 passwd $PROG stash ipmi_node2 passwd $PROG sync EOF exit "$1" } check_usage() { case "$1" in set) [ "$2" -ne 4 ] && usage 1 ;; get) [ "$2" -ne 3 ] && usage 1 ;; check) [ "$2" -ne 3 ] && usage 1 ;; stash) [ "$2" -ne 3 ] && usage 1 ;; unstash) [ "$2" -ne 3 ] && usage 1 ;; delete) [ "$2" -ne 3 ] && usage 1 ;; sync) [ "$2" -ne 1 ] && usage 1 ;; - --help) usage 0 ;; + --help) usage $CRM_EX_OK ;; --version) crm_attribute --version; exit $? ;; - *) usage 1 ;; + *) usage $CRM_EX_USAGE ;; esac } fatal() { + rc=$1 + shift echo "ERROR: $*" - exit 1 + exit $rc } warn() { echo "WARNING: $*" } info() { echo "INFO: $*" } check_env() { which md5sum >/dev/null 2>&1 || - fatal "please install md5sum to run $PROG" + fatal $CRM_EX_NOT_INSTALLED "please install md5sum to run $PROG" if which pssh >/dev/null 2>&1; then rsh=pssh_fun rcp_to_from=pscp_fun # -q is a SUSE patch not present in upstream pssh PSSH_QUIET_OPTION="" pssh -q 2>&1|grep "no such option: -q" > /dev/null || PSSH_QUIET_OPTION="-q" elif which pdsh >/dev/null 2>&1; then rsh=pdsh_fun rcp_to_from=pdcp_fun elif which ssh >/dev/null 2>&1; then rsh=ssh_fun rcp_to_from=scp_fun else - fatal "please install pssh, pdsh, or ssh to run $PROG" + fatal $CRM_EX_NOT_INSTALLED "please install pssh, pdsh, or ssh to run $PROG" fi ps -ef | grep '[p]acemaker-controld' >/dev/null || - fatal "pacemaker not running? $PROG needs pacemaker" + fatal $CRM_EX_UNAVAILABLE "pacemaker not running? $PROG needs pacemaker" } # This must be called (and return success) before calling $rsh or $rcp_to_from get_live_peers() { # Get local node name GLP_LOCAL_NODE="$(crm_node -n)" - [ $? -eq 0 ] || fatal "couldn't get local node name" + [ $? -eq 0 ] || fatal $CRM_EX_UNAVAILABLE "couldn't get local node name" # Get a list of all other cluster nodes GLP_ALL_PEERS="$(crm_node -l)" - [ $? -eq 0 ] || fatal "couldn't determine cluster nodes" + [ $? -eq 0 ] || fatal $CRM_EX_UNAVAILABLE "couldn't determine cluster nodes" GLP_ALL_PEERS="$(echo "$GLP_ALL_PEERS" | awk '{print $2}' | grep -v "^${GLP_LOCAL_NODE}$")" # Make a list of those that respond to pings if [ "$(id -u)" = "0" ] && which fping >/dev/null 2>&1; then LIVE_NODES=$(fping -a $GLP_ALL_PEERS 2>/dev/null) else LIVE_NODES="" for GLP_NODE in $GLP_ALL_PEERS; do \ ping -c 2 -q "$GLP_NODE" >/dev/null 2>&1 && LIVE_NODES="$LIVE_NODES $GLP_NODE" done fi # Warn the user about any that didn't respond to pings GLP_DOWN="$( (for GLP_NODE in $LIVE_NODES $GLP_ALL_PEERS; do echo "$GLP_NODE"; done) | sort | uniq -u)" if [ "$(echo "$GLP_DOWN" | wc -w)" = "1" ]; then warn "node $GLP_DOWN is down" warn "you'll need to update it using \"$PROG sync\" later" elif [ -n "$GLP_DOWN" ]; then warn "nodes $(echo "$GLP_DOWN" | tr '\n' ' ')are down" warn "you'll need to update them using \"$PROG sync\" later" fi if [ "$LIVE_NODES" = "" ]; then info "no other nodes live" return 1 fi return 0 } pssh_fun() { pssh $PSSH_QUIET_OPTION -i -H "$LIVE_NODES" -x "$SSH_OPTS" -- "$@" } pscp_fun() { PSCP_DEST="$1" shift pscp $PSSH_QUIET_OPTION -H "$LIVE_NODES" -x "-pr" -x "$SSH_OPTS" -- "$@" "$PSCP_DEST" } pdsh_fun() { PDSH_NODES=$(echo "$LIVE_NODES" | tr '[:space:]' ',') export PDSH_SSH_ARGS_APPEND="$SSH_OPTS" pdsh -w "$PDSH_NODES" -- "$@" } pdcp_fun() { PDCP_DEST="$1" shift PDCP_NODES=$(echo "$LIVE_NODES" | tr '[:space:]' ',') export PDSH_SSH_ARGS_APPEND="$SSH_OPTS" pdcp -pr -w "$PDCP_NODES" -- "$@" "$PDCP_DEST" } ssh_fun() { for SSH_NODE in $LIVE_NODES; do ssh $SSH_OPTS "$SSH_NODE" -- "$@" || return done } scp_fun() { SCP_DEST="$1" shift for SCP_NODE in $LIVE_NODES; do scp -pqr $SSH_OPTS "$@" "$SCP_NODE:$SCP_DEST" || return done } # TODO: this procedure should be replaced with csync2 # provided that csync2 has already been configured sync_files() { get_live_peers || return info "syncing $LRM_CIBSECRETS to $(echo "$LIVE_NODES" | tr '\n' ' ') ..." $rsh rm -rf "$LRM_CIBSECRETS" && $rsh mkdir -p "$(dirname "$LRM_CIBSECRETS")" && $rcp_to_from "$(dirname "$LRM_CIBSECRETS")" "$LRM_CIBSECRETS" } sync_one() { SO_FILE="$1" get_live_peers || return info "syncing $SO_FILE to $(echo "$LIVE_NODES" | tr '\n' ' ') ..." $rsh mkdir -p "$(dirname "$SO_FILE")" && if [ -f "$SO_FILE" ]; then $rcp_to_from "$(dirname "$SO_FILE")" "$SO_FILE" "${SO_FILE}.sign" else $rsh rm -f "$SO_FILE" "${SO_FILE}.sign" fi } is_secret() { # assume that the secret is in the CIB if we cannot talk to cib [ "$NO_CRM" ] || test "$1" = "$MAGIC" } check_cib_rsc() { - CCR_OUT="$($NO_CRM crm_resource -r "$1" -W 2>&1)" || fatal "$CCR_OUT" + CCR_OUT="$($NO_CRM crm_resource -r "$1" -W 2>&1)" || fatal $CRM_EX_NOSUCH "$CCR_OUT" } get_cib_param() { GCP_RSC="$1" GCP_PARAM="$2" $NO_CRM crm_resource -r "$GCP_RSC" -g "$GCP_PARAM" 2>/dev/null } set_cib_param() { SET_RSC="$1" SET_PARAM="$2" SET_VAL="$3" $NO_CRM crm_resource -r "$SET_RSC" -p "$SET_PARAM" -v "$SET_VAL" 2>/dev/null } remove_cib_param() { RM_RSC="$1" RM_PARAM="$2" $NO_CRM crm_resource -r "$RM_RSC" -d "$RM_PARAM" 2>/dev/null } localfiles() { LF_CMD="$1" LF_RSC="$2" LF_PARAM="$3" LF_VALUE="$4" LF_FILE="$LRM_CIBSECRETS/$LF_RSC/$LF_PARAM" case "$LF_CMD" in get) cat "$LF_FILE" 2>/dev/null true ;; getsum) cat "${LF_FILE}.sign" 2>/dev/null true ;; set) LF_SUM="$(printf %s "$LF_VALUE" | md5sum)" || - fatal "md5sum failed to produce hash for resource $LF_RSC parameter $LF_PARAM" + fatal $CRM_EX_ERROR "md5sum failed to produce hash for resource $LF_RSC parameter $LF_PARAM" LF_SUM="$(echo "$LF_SUM" | awk '{print $1}')" mkdir -p "$(dirname "$LF_FILE")" && echo "$LF_VALUE" > "$LF_FILE" && echo "$LF_SUM" > "${LF_FILE}.sign" && sync_one "$LF_FILE" ;; remove) rm -f "$LF_FILE" "${LF_FILE}.sign" sync_one "$LF_FILE" ;; esac } cibsecret_set() { CS_VALUE="$1" check_cib_rsc "$rsc" CIBSET_CURRENT="$(get_cib_param "$rsc" "$param")" [ -z "$NO_CRM" ] && [ ! -z "$CIBSET_CURRENT" ] && [ "$CIBSET_CURRENT" != "$MAGIC" ] && [ "$CIBSET_CURRENT" != "$CS_VALUE" ] && - fatal "CIB value <$CIBSET_CURRENT> different for $rsc parameter $param; please delete it first" + fatal $CRM_EX_CONFIG "CIB value <$CIBSET_CURRENT> different for $rsc parameter $param; please delete it first" localfiles set "$rsc" "$param" "$CS_VALUE" && set_cib_param "$rsc" "$param" "$MAGIC" } cibsecret_check() { check_cib_rsc "$rsc" is_secret "$(get_cib_param "$rsc" "$param")" || - fatal "resource $rsc parameter $param not set as secret, nothing to check" + fatal $CRM_EX_CONFIG "resource $rsc parameter $param not set as secret, nothing to check" CSC_LOCAL_SUM="$(localfiles getsum "$rsc" "$param")" [ "$CSC_LOCAL_SUM" ] || - fatal "no MD5 hash for resource $rsc parameter $param" + fatal $CRM_EX_OSFILE "no MD5 hash for resource $rsc parameter $param" CSC_LOCAL_VALUE="$(localfiles get "$rsc" "$param")" CSC_CALC_SUM="$(printf "%s" "$CSC_LOCAL_VALUE" | md5sum | awk '{print $1}')" [ "$CSC_CALC_SUM" = "$CSC_LOCAL_SUM" ] || - fatal "MD5 hash mismatch for resource $rsc parameter $param" + fatal $CRM_EX_DIGEST "MD5 hash mismatch for resource $rsc parameter $param" } cibsecret_get() { cibsecret_check localfiles get "$rsc" "$param" } cibsecret_delete() { check_cib_rsc "$rsc" localfiles remove "$rsc" "$param" && remove_cib_param "$rsc" "$param" } cibsecret_stash() { - [ "$NO_CRM" ] && fatal "no access to Pacemaker, stash not supported" + [ "$NO_CRM" ] && fatal $CRM_EX_USAGE "no access to Pacemaker, stash not supported" check_cib_rsc "$rsc" CIBSTASH_CURRENT="$(get_cib_param "$rsc" "$param")" [ "$CIBSTASH_CURRENT" = "" ] && - fatal "nothing to stash for resource $rsc parameter $param" + fatal $CRM_EX_NOSUCH "nothing to stash for resource $rsc parameter $param" is_secret "$CIBSTASH_CURRENT" && - fatal "resource $rsc parameter $param already set as secret, nothing to stash" + fatal $CRM_EX_EXISTS "resource $rsc parameter $param already set as secret, nothing to stash" cibsecret_set "$CIBSTASH_CURRENT" } cibsecret_unstash() { - [ "$NO_CRM" ] && fatal "no access to Pacemaker, unstash not supported" + [ "$NO_CRM" ] && fatal $CRM_EX_USAGE "no access to Pacemaker, unstash not supported" UNSTASH_LOCAL_VALUE="$(localfiles get "$rsc" "$param")" [ "$UNSTASH_LOCAL_VALUE" = "" ] && - fatal "nothing to unstash for resource $rsc parameter $param" + fatal $CRM_EX_NOSUCH "nothing to unstash for resource $rsc parameter $param" check_cib_rsc "$rsc" is_secret "$(get_cib_param "$rsc" "$param")" || warn "resource $rsc parameter $param not set as secret, but we have local value so proceeding anyway" localfiles remove "$rsc" "$param" && set_cib_param "$rsc" "$param" "$UNSTASH_LOCAL_VALUE" } cibsecret_sync() { sync_files } # Grab arguments if [ "$1" = "-C" ]; then NO_CRM=':' shift fi cmd="$1" rsc="$2" param="$3" value="$4" # Ensure we have everything we need check_usage "$cmd" $# check_env umask 0077 # for dirname() function (@TODO why are we replacing dirname?) . "@OCF_ROOT_DIR@/lib/heartbeat/ocf-shellfuncs" "cibsecret_$cmd" "$value" +rc=$? + +if [ $rc -ne 0 ]; then + fatal $CRM_EX_ERROR "$cmd(): failed with rc: $rc" +fi # vim: set expandtab tabstop=8 softtabstop=4 shiftwidth=4 textwidth=80: