blob: 6fea8768af6afe2f348da634835bb5603f064dad [file] [log] [blame]
#!/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