| #!/bin/sh |
| |
| # Copyright (C) 2011 Dejan Muhamedagic <dmuhamedagic@suse.de> |
| # |
| # This program is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU General Public |
| # License as published by the Free Software Foundation; either |
| # version 2.1 of the License, or (at your option) any later version. |
| # |
| # This software is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| # General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public |
| # License along with this library; if not, write to the Free Software |
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| # |
| |
| # WARNING: |
| # |
| # The CIB secrets interface and implementation is still being |
| # discussed, it may change |
| |
| # |
| # cibsecret: manage the secrets directory /var/lib/heartbeat/lrm/secrets |
| # |
| # secrets are ascii files, holding just one value per file: |
| # /var/lib/heartbeat/lrm/secrets/<rsc>/<param> |
| # |
| # NB: this program depends on utillib.sh |
| # |
| |
| . @OCF_ROOT_DIR@/lib/heartbeat/ocf-shellfuncs |
| |
| LRM_CIBSECRETS=@LRM_CIBSECRETS_DIR@ |
| LRM_LEGACY_CIBSECRETS=@LRM_LEGACY_CIBSECRETS_DIR@ |
| |
| PROG=`basename $0` |
| SSH_OPTS="-o StrictHostKeyChecking=no" |
| |
| usage() { |
| echo "cibsecret - A tool for managing cib secrets"; |
| echo ""; |
| echo "usage: $PROG [-C] <command> <parameters>"; |
| echo "--version Display version information, then exit"; |
| echo ""; |
| echo "-C: don't read/write the CIB" |
| echo "" |
| echo "command: set | delete | stash | unstash | get | check | sync" |
| echo "" |
| echo " set <rsc> <param> <value>" |
| echo "" |
| echo " get <rsc> <param>" |
| echo "" |
| echo " check <rsc> <param>" |
| echo "" |
| echo " stash <rsc> <param> (if not -C)" |
| echo "" |
| echo " unstash <rsc> <param> (if not -C)" |
| echo "" |
| echo " delete <rsc> <param>" |
| echo "" |
| echo " sync" |
| echo "" |
| echo "stash/unstash: move the parameter from/to the CIB (if you already" |
| echo "have the parameter set in the CIB)." |
| echo "" |
| echo "set/delete: add/remove a parameter from the local file." |
| echo "" |
| echo "get: display the parameter from the local file." |
| echo "" |
| echo "check: verify MD5 hash of the parameter from the local file and the CIB." |
| echo "" |
| echo "sync: copy $LRM_CIBSECRETS to other nodes." |
| echo "" |
| echo "Examples:" |
| echo "" |
| echo " $PROG set ipmi_node1 passwd SecreT_PASS" |
| echo "" |
| echo " $PROG stash ipmi_node1 passwd" |
| echo "" |
| echo " $PROG get ipmi_node1 passwd" |
| echo "" |
| echo " $PROG check ipmi_node1 passwd" |
| echo "" |
| echo " $PROG sync" |
| |
| exit $1 |
| } |
| fatal() { |
| echo "ERROR: $*" |
| exit 1 |
| } |
| warn() { |
| echo "WARNING: $*" |
| } |
| info() { |
| echo "INFO: $*" |
| } |
| |
| check_env() { |
| which md5sum >/dev/null 2>&1 || |
| fatal "please install md5sum to run $PROG" |
| if which pssh >/dev/null 2>&1; then |
| rsh=pssh_fun |
| rcp=pscp_fun |
| elif which pdsh >/dev/null 2>&1; then |
| rsh=pdsh_fun |
| rcp=pdcp_fun |
| elif which ssh >/dev/null 2>&1; then |
| rsh=ssh_fun |
| rcp=scp_fun |
| else |
| fatal "please install pssh, pdsh, or ssh to run $PROG" |
| fi |
| ps -ef | grep '[c]rmd' >/dev/null || |
| fatal "pacemaker not running? $PROG needs pacemaker" |
| } |
| |
| get_other_nodes() { |
| crm_node -l | awk '{print $2}' | grep -v `uname -n` |
| } |
| |
| get_live_nodes() { |
| if [ `id -u` = 0 ] && which fping >/dev/null 2>&1; then |
| fping -a $@ 2>/dev/null |
| else |
| local h |
| for h; do ping -c 2 -q $h >/dev/null 2>&1 && echo $h; done |
| fi |
| } |
| |
| check_down_nodes() { |
| local n down_nodes |
| down_nodes=`(for n; do echo $n; done) | sort | uniq -u` |
| if [ -n "$down_nodes" ]; then |
| if [ `echo $down_nodes | wc -w` = 1 ]; then |
| warn "node $down_nodes is down" |
| warn "you'll need to update it using $PROG sync later" |
| else |
| warn "nodes `echo $down_nodes` are down" |
| warn "you'll need to update them using $PROG sync later" |
| fi |
| fi |
| } |
| |
| pssh_fun() { |
| pssh -qi -H "$nodes" -x "$SSH_OPTS" $* |
| } |
| pscp_fun() { |
| pscp -q -H "$nodes" -x "-pr" -x "$SSH_OPTS" $* |
| } |
| pdsh_fun() { |
| local pdsh_nodes=`echo $nodes | tr ' ' ','` |
| export PDSH_SSH_ARGS_APPEND="$SSH_OPTS" |
| pdsh -w $pdsh_nodes $* |
| } |
| pdcp_fun() { |
| local pdsh_nodes=`echo $nodes | tr ' ' ','` |
| export PDSH_SSH_ARGS_APPEND="$SSH_OPTS" |
| pdcp -pr -w $pdsh_nodes $* |
| } |
| ssh_fun() { |
| local h |
| for h in $nodes; do |
| ssh $SSH_OPTS $h $* || return |
| done |
| } |
| scp_fun() { |
| local h src="$1" dest=$2 |
| for h in $nodes; do |
| scp -pr -q $SSH_OPTS $src $h:$dest || return |
| done |
| } |
| # TODO: this procedure should be replaced with csync2 |
| # provided that csync2 has already been configured |
| sync_files() { |
| local crm_nodes=`get_other_nodes` |
| local nodes=`get_live_nodes $crm_nodes` |
| check_down_nodes $nodes $crm_nodes |
| [ "$nodes" = "" ] && { |
| info "no other nodes live" |
| return |
| } |
| info "syncing $LRM_CIBSECRETS to `echo $nodes` ..." |
| $rsh rm -rf $LRM_CIBSECRETS && |
| $rsh mkdir -p `dirname $LRM_CIBSECRETS` && |
| $rcp $LRM_CIBSECRETS `dirname $LRM_CIBSECRETS` |
| } |
| sync_one() { |
| local f=$1 f_all="$1 $1.sign" |
| local crm_nodes=`get_other_nodes` |
| local nodes=`get_live_nodes $crm_nodes` |
| check_down_nodes $nodes $crm_nodes |
| [ "$nodes" = "" ] && { |
| info "no other nodes live" |
| return |
| } |
| info "syncing $f to `echo $nodes` ..." |
| $rsh mkdir -p `dirname $f` && |
| if [ -f "$f" ]; then |
| $rcp "$f_all" `dirname $f` |
| else |
| $rsh rm -f $f_all |
| 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() { |
| local rsc=$1 output |
| output=`$NO_CRM crm_resource -r $rsc -W >/dev/null 2>&1` || |
| fatal "resource $rsc doesn't exist: $output" |
| } |
| get_cib_param() { |
| local rsc=$1 param=$2 |
| check_cib_rsc $rsc |
| $NO_CRM crm_resource -r $rsc -g $param 2>/dev/null |
| } |
| set_cib_param() { |
| local rsc=$1 param=$2 value=$3 |
| check_cib_rsc $rsc |
| $NO_CRM crm_resource -r $rsc -p $param -v "$value" 2>/dev/null |
| } |
| remove_cib_param() { |
| local rsc=$1 param=$2 |
| check_cib_rsc $rsc |
| $NO_CRM crm_resource -r $rsc -d $param 2>/dev/null |
| } |
| |
| localfiles() { |
| local cmd=$1 |
| local rsc=$2 param=$3 value=$4 |
| local local_file=$LRM_CIBSECRETS/$rsc/$param |
| local local_legacy_file=$LRM_LEGACY_CIBSECRETS/$rsc/$param |
| case $cmd in |
| "get") |
| cat $local_file 2>/dev/null || |
| cat $local_legacy_file 2>/dev/null |
| true |
| ;; |
| "getsum") |
| cat $local_file.sign 2>/dev/null || |
| cat $local_legacy_file.sign 2>/dev/null |
| true |
| ;; |
| "set") |
| local md5sum |
| md5sum=`printf $value | md5sum` || |
| fatal "md5sum failed to produce hash for resource $rsc parameter $param" |
| md5sum=`echo $md5sum | awk '{print $1}'` |
| mkdir -p `dirname $local_file` && |
| echo $value > $local_file && |
| echo $md5sum > $local_file.sign && ( |
| sync_one $local_file |
| rm -f $local_legacy_file |
| rm -f $local_legacy_file.sign |
| sync_one $local_legacy_file) |
| ;; |
| "remove") |
| rm -f $local_legacy_file |
| rm -f $local_legacy_file.sign |
| sync_one $local_legacy_file |
| |
| rm -f $local_file |
| rm -f $local_file.sign |
| sync_one $local_file |
| ;; |
| *) |
| # not reached, this is local interface |
| ;; |
| esac |
| } |
| get_local_param() { |
| local rsc=$1 param=$2 |
| localfiles get $rsc $param |
| } |
| set_local_param() { |
| local rsc=$1 param=$2 value=$3 |
| localfiles set $rsc $param $value |
| } |
| remove_local_param() { |
| local rsc=$1 param=$2 |
| localfiles remove $rsc $param |
| } |
| |
| cibsecret_set() { |
| local value=$1 |
| |
| if [ -z "$NO_CRM" ]; then |
| [ "$current" -a "$current" != "$MAGIC" -a "$current" != "$value" ] && |
| fatal "CIB value <$current> different for $rsc parameter $param; please delete it first" |
| fi |
| set_local_param $rsc $param $value && |
| set_cib_param $rsc $param "$MAGIC" |
| } |
| |
| cibsecret_check() { |
| local md5sum local_md5sum |
| is_secret "$current" || |
| fatal "resource $rsc parameter $param not set as secret, nothing to check" |
| local_md5sum=`localfiles getsum $rsc $param` |
| [ "$local_md5sum" ] || |
| fatal "no MD5 hash for resource $rsc parameter $param" |
| md5sum=`printf "$current_local" | md5sum | awk '{print $1}'` |
| [ "$md5sum" = "$local_md5sum" ] || |
| fatal "MD5 hash mismatch for resource $rsc parameter $param" |
| } |
| |
| cibsecret_get() { |
| cibsecret_check |
| echo "$current_local" |
| } |
| |
| cibsecret_delete() { |
| remove_local_param $rsc $param && |
| remove_cib_param $rsc $param |
| } |
| |
| cibsecret_stash() { |
| [ "$NO_CRM" ] && |
| fatal "no access to Pacemaker, stash not supported" |
| [ "$current" = "" ] && |
| fatal "nothing to stash for resource $rsc parameter $param" |
| is_secret "$current" && |
| fatal "resource $rsc parameter $param already set as secret, nothing to stash" |
| cibsecret_set "$current" |
| } |
| |
| cibsecret_unstash() { |
| [ "$NO_CRM" ] && |
| fatal "no access to Pacemaker, unstash not supported" |
| [ "$current_local" = "" ] && |
| fatal "nothing to unstash for resource $rsc parameter $param" |
| is_secret "$current" || |
| warn "resource $rsc parameter $param not set as secret, but we have local value so proceeding anyway" |
| remove_local_param $rsc $param && |
| set_cib_param $rsc $param $current_local |
| } |
| |
| cibsecret_sync() { |
| sync_files |
| } |
| |
| MAGIC="lrm://" |
| umask 0077 |
| |
| if [ "$1" = "-C" ]; then |
| NO_CRM=':' |
| shift 1 |
| fi |
| |
| cmd=$1 |
| rsc=$2 |
| param=$3 |
| value=$4 |
| |
| case "$cmd" in |
| set) [ $# -ne 4 ] && usage 1;; |
| get) [ $# -ne 3 ] && usage 1;; |
| check) [ $# -ne 3 ] && usage 1;; |
| stash) [ $# -ne 3 ] && usage 1;; |
| unstash) [ $# -ne 3 ] && usage 1;; |
| delete) [ $# -ne 3 ] && usage 1;; |
| sync) [ $# -ne 1 ] && usage 1;; |
| --help) usage 0;; |
| --version) |
| crm_attribute --version |
| exit $?;; |
| *) usage 1; |
| esac |
| |
| check_env |
| |
| # we'll need these two often |
| current=`get_cib_param $rsc $param` |
| current_local=`get_local_param $rsc $param` |
| |
| cibsecret_$cmd $value |