summaryrefslogtreecommitdiffstats
path: root/lrm/admin/cibsecret.in
diff options
context:
space:
mode:
Diffstat (limited to 'lrm/admin/cibsecret.in')
-rwxr-xr-xlrm/admin/cibsecret.in350
1 files changed, 350 insertions, 0 deletions
diff --git a/lrm/admin/cibsecret.in b/lrm/admin/cibsecret.in
new file mode 100755
index 0000000..5255cdd
--- /dev/null
+++ b/lrm/admin/cibsecret.in
@@ -0,0 +1,350 @@
+#!/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
+
+HA_NOARCHBIN=@datadir@/@PACKAGE_NAME@
+
+. $HA_NOARCHBIN/utillib.sh
+
+LRM_CIBSECRETS=$HA_VARLIB/lrm/secrets
+
+PROG=`basename $0`
+SSH_OPTS="-o StrictHostKeyChecking=no"
+
+usage() {
+ cat<<EOF
+usage: $PROG [-C] <command> <parameters>
+
+-C: don't read/write the CIB
+
+command: set | delete | stash | unstash | get | check | sync
+
+ set <rsc> <param> <value>
+ get <rsc> <param>
+ check <rsc> <param>
+ stash <rsc> <param> (if not -C)
+ unstash <rsc> <param> (if not -C)
+ delete <rsc> <param>
+ sync
+
+stash/unstash: move the parameter from/to the CIB (if you already
+ have the parameter set in the CIB).
+
+set/delete: add/remove a parameter from the local file.
+
+get: display the parameter from the local file.
+
+check: verify MD5 hash of the parameter from the local file and the CIB.
+
+sync: copy $LRM_CIBSECRETS to other nodes.
+
+Examples:
+
+ $PROG set ipmi_node1 passwd SecreT_PASS
+ $PROG stash ipmi_node1 passwd
+ $PROG get ipmi_node1 passwd
+ $PROG check ipmi_node1 passwd
+ $PROG sync
+EOF
+ 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`
+}
+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
+ case $cmd in
+ "get")
+ cat $local_file 2>/dev/null
+ true
+ ;;
+ "getsum")
+ cat $local_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
+ ;;
+ "remove")
+ rm -f $local_file
+ 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
+}
+
+check_env
+
+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;;
+ *) usage 1;
+esac
+
+# we'll need these two often
+current=`get_cib_param $rsc $param`
+current_local=`get_local_param $rsc $param`
+
+cibsecret_$cmd $value