Major rework - drist - a remote deployment tool HTML git clone git://bitreich.org/drist/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/drist/ DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- DIR commit 1ddb1582cfb17a5d79fd9725907a1b329dacbd6b DIR parent c6481050031bc54fa99a6fcfa7d3408850040883 HTML Author: Solene Rapenne <solene@perso.pw> Date: Wed, 26 Aug 2020 21:13:06 +0200 Major rework Files are now copied in a temporary subtree and files must be copied on the system from the script. This is safer in many ways and result is predictable. Drop "absent" function Drop simulate flag If previous behavior is prefered, you should stay with previous version Diffstat: M drist | 165 ++++++++++++++++--------------- M drist.1 | 28 +++++++++------------------- 2 files changed, 94 insertions(+), 99 deletions(-) --- DIR diff --git a/drist b/drist @@ -1,20 +1,71 @@ #!/bin/sh -SIMULATE=0 SUDO=0 SUDO_BIN=sudo EXEC="" SSHONCE=0 TRUNCATE=0 +TEMPDIR="" usage() { - echo "$0 [-n] [-d] [-s [-e sudo|doas]] server" + echo "$0 [-n] [-d] [-s [-e sudo|doas]] server [...]" exit 0 } +# $1 = directory name +# $2 = remote server +copy_files() { + # -l = keep symlink / -D = special device + if [ -d "${1}" ] + then + LIST=$(mktemp /tmp/drist-rsync.XXXXXXXXXX) + if [ -f "$LIST" ] + then + printf 'Copying files from "%s" to temporary directory %s:\n' "$1" "$3" + find "${1}"/ -type f -or -type l | cut -d '/' -f 2- | tee "${LIST}" | sed 's/^/ \//' + rsync -e "ssh $SSH_PARAMS" -lD --files-from="${LIST}" "${1}/" "${2}":"/${3}" + rm "$LIST" + fi + fi +} + +# $1 = script filename +# $2 = remote server +# $3 = tempdir +remote_script() { + if [ -f "${1}" ] + then + printf 'Executing file "%s":\n' "$1" + ssh $SSH_PARAMS "${2}" "cd ${3} && DRIST=${3}/script && + cat - > \$DRIST && + chmod u+x \$DRIST && + ${EXEC} \$DRIST" < "$1" + fi +} + +# $1 = remote server +create_temp() { + TEMPDIR=$(ssh $SSH_PARAMS "$1" "mktemp -d ~/.drist_files_XXXXXXXXXXXXXXX") + if [ "$TEMPDIR" = "" ]; then + echo "mktemp error, aborting" + fi +} + +# $1 = remote server +# $2 = temporary directory +delete_temp() { + if echo "${2}" | grep drist_files_ >/dev/null ; then + ssh $SSH_PARAMS "$1" "rm -fr ${2}" + else + echo "Problem, TEMPDIR was reset during execution, current value is = $2" + exit 2 + fi +} + + +# RUNTIME BEGINS HERE while getopts pndse: arg; do case ${arg} in - n) SIMULATE=1 ;; d) TRUNCATE=1 ;; s) SUDO=1 ;; e) SUDO_BIN="${OPTARG}" ;; @@ -36,93 +87,47 @@ then SSH_PARAMS=-o"ControlMaster=auto"" "-o"ControlPath=/tmp/drist_ssh_%h_%p_%r.sock"" "-o"ControlPersist=1m" fi -# check if host exists -if [ "$#" -ne 1 ]; then - usage +# start looping over server list +if [ -f "$1" ] +then + SERVER_LIST="$(cat $1 | tr '\n' ' ')" else - HOSTNAME=$(ssh $SSH_PARAMS "$1" "${EXEC} uname -n") + SERVER_LIST="$@" +fi + +if [ "${SERVER_LIST}" = "" ] +then + echo "No server specified" + exit 1 +fi + +for remote_server in ${SERVER_LIST} +do + echo "Running on ${remote_server}" + + # check if host exists + HOSTNAME=$(ssh $SSH_PARAMS "${remote_server}" "${EXEC} uname -n") if [ "$?" -ne 0 ]; then - echo "Error while ssh ${1}" + echo "Error while ssh ${remote_server}" exit 2 fi if [ "$TRUNCATE" -eq 1 ]; then HOSTNAME="${HOSTNAME%%.*}" fi -fi - -# $1 = directory name -# $2 = remote server -copy_files() { - # -l = keep symlink / -D = special device - if [ -d "${1}" ] - then - LIST=$(mktemp /tmp/drist-rsync.XXXXXXXXXX) - if [ -f "$LIST" ] - then - printf 'Copying files from folder "%s":\n' "$1" - find "${1}"/ -type f -or -type l | cut -d '/' -f 2- | tee "${LIST}" | sed 's/^/ \//' - if [ "$SIMULATE" -ne 1 ] - then - rsync -e "ssh $SSH_PARAMS" --rsync-path="${EXEC} rsync" -lDp --files-from="${LIST}" "${1}/" "${2}":/ - fi - rm "$LIST" - fi - fi -} -# $1 = script filename -# $2 = remote server -remote_script() { - if [ -f "${1}" ] - then - printf 'Executing file "%s":\n' "$1" - if [ "$SIMULATE" -ne 1 ] - then - dr="$(mktemp ./drist.XXXXXXXXXXXX)" - ssh $SSH_PARAMS "${2}" "DRIST=${dr} && - cat - > \$DRIST && - chmod u+x \$DRIST && - ${EXEC} \$DRIST ; - rm \$DRIST" < "$1" - rm "$dr" - fi - fi -} + create_temp "${remote_server}" + copy_files "files" "${remote_server}" "$TEMPDIR" + copy_files "files-${HOSTNAME}" "${remote_server}" "$TEMPDIR" + remote_script "script" "${remote_server}" "$TEMPDIR" + remote_script "script-${HOSTNAME}" "${remote_server}" "$TEMPDIR" + delete_temp "${remote_server}" "$TEMPDIR" -# $1 = directory name -# $2 = remote server -delete_files() { - if [ -d "${1}" ] + # close socket if persistance is actived + if [ "$SSHONCE" -eq 1 ] then - LIST=$(mktemp /tmp/drist-rsync.XXXXXXXXXX) - if [ -f "$LIST" ] - then - printf 'Removing files from folder "%s":\n' "$1" - find "$1" -type f | sed 's/"/\\&/' | \ - awk -v path="${1}" '{ printf "\"%s\" ",substr($0,length(path)+1)}' | \ - tee "${LIST}" | sed 's/^/ /' - printf '\n' # add a new line - - if [ "$SIMULATE" -ne 1 ] - then - test -s "$LIST" && ssh $SSH_PARAMS "$2" "${EXEC} rm $(cat $LIST)" - fi - rm $LIST - fi + ssh $SSH_PARAMS -O exit -N "$1" fi -} - - -copy_files "files" "$1" -copy_files "files-${HOSTNAME}" "$1" -delete_files "absent" "$1" -delete_files "absent-${HOSTNAME}" "$1" -remote_script "script" "$1" -remote_script "script-${HOSTNAME}" "$1" -# close socket if persistance is actived -if [ "$SSHONCE" -eq 1 ] -then - ssh $SSH_PARAMS -O exit -N "$1" -fi + unset TEMPDIR HOSTNAME +done DIR diff --git a/drist.1 b/drist.1 @@ -10,7 +10,7 @@ .Op Fl n .Op Fl d .Op Fl s Op Fl e Ar sudo|doas -.Ar server +.Ar server ... .Sh OPTIONS .Op Fl p to use persistent ssh connection, allowing to ssh only once @@ -59,41 +59,33 @@ by calling After that following steps will be executed: .Bl -enum -offset indent -compact .It -If folder +If directory .Ar files exists, its content is copied to .Ar server using -.Xr rsync 1 . +.Xr rsync 1 +in a temporary directory in ~/.drist_files_XXXXXXXX .It -If folder +If directory .Ar files- Ns Em HOSTNAME exists, its content is copied to .Ar server using -.Xr rsync 1 . -.It -If folder -.Ar absent -exists, filenames in it are deleted on -.Ar server . -.It -If folder -.Ar absent- Ns Em HOSTNAME -exists, filenames in it are deleted on -.Ar server . +.Xr rsync 1 +in a temporary directory in ~/.drist_files_XXXXXXXX . .It If file .Ar script exists, it is copied to .Ar server -and executed there. +and executed from the temporary directory. .It If file .Ar script- Ns Em HOSTNAME exists, it is copied to .Ar server -and executed there. +and executed from the temporary directory. .El .Pp The presence of each of those files or directories is optional. @@ -101,8 +93,6 @@ The presence of each of those files or directories is optional. All files in either .Ar files or -.Ar absent -or .Ar files- Ns Em HOSTNAME etc. are relative to the root (/) directory. The specific files for