shell-network/modules/remote.mod

241 lines
7.7 KiB
Bash

#!/bin/bash
module_load ssh
module_load bundle
module_load helpers
module_load ssh-copy
remote_function () {
[[ $2 ]] && module_load $2
if declare -f $1; then
local file
file=$(mkrfilename function)
$(declare -f $1) > $file
echo $file
else
>&2 echo fatal: unable to source funtion $1, aborting
return 1
fi
}
remote_script () {
local sshargs;local user;local supass;local cfn; local rfn; local args;
local script; local host; local dr; local supass; local env_vars;
local login; local slogin; local shell=bash; local sargs
local hostname; local bscript; local ruser; local usesudo; local save
help() {
cat <<EOF
usage: remote_script <remote_script options> host script <script args> -- <ssh script options>
host and script are required, script can be either path to a file containing a script to a UCI module
-f, <func> run a function in the passed script, otherwise script is assumed to be bash executed.
-x, <func> create script of just a function from some script file or module
| will automatically set -f to run that function.
-b <shell> use another shell processor other than default bash
-d, dry run. don't run the rscript just output the command that will be run
-u, <ruser> remote user to run script as. default is ssh host user or root if using sudo.
| if -u is other than ssh login user then -s or -p must be set
-s, execute remote script using sudo
-p, <supass> sudo password. If set the remote command will be run as root or the user of -u <user>
| if command has 'ssh script option' of '-- -p <upasswd>' and -s is set this will set -p <upasswd> automatically
-l, use login shell on remote
-e, <SOME_VAR="some value"> set some environment variables to run. Can be used more than once for multiple values
-h, this help text
EOF
}
debug $( ( IFS=$','; echo all arguments: "$*" ) )
for ((d=1; d<$#+1; ++d)); do
# echo in loop $d, ${!d}
[[ ${!d} == "--" ]] && sargs=true && break
done
if [[ $sargs ]]; then # if there are extra ssh arguments
sshargs=("${@:$d+1:$#}")
debug $( ( IFS=$','; echo "ssh arguments: ${sshargs[*]}" ) )
set -- "${@:1:$d-1}"
# args=("${@:1:$d-1}")
debug $( ( IFS=$','; echo remaining arguments to parse: "$*" ) )
else
set -- "${@:1}"
# args=("${@:1}")
fi
# echo pre ssh args: "$@"
# echo args "${args[@]}"
# parse remote_script options
local OPTION
local OPTARG
local OPTIND
while getopts 'b:le:hdu:sf:p:x:' OPTION; do
# echo OPTION $OPTION ARG $OPTARG INDX $OPTIND
case "$OPTION" in
s)
# using sudo, password will come from ssh user password or if you supply it with -p
usesudo=true
;;
b)
# use another shell the than default bash
shell="$OPTARG"
;;
f)
# run a function within the script
# any function arguments appear after script
cfn="-f $OPTARG"
;;
d)
# dry run
dr=true
;;
e)
env_vars+=" $(escape_spaces "$OPTARG")"
;;
u)
# run remote command as another user
ruser=$OPTARG
# usesudo=true
;;
l)
login="-l"
;;
x)
rfn=$OPTARG
;;
p)
supass=$OPTARG
;;
h)
help
return 0
;;
*)
>&2 echo fatal: unknown remote script option $OPTION, aborting
help
return 1
;;
esac
done
shift $((OPTIND - 1))
[[ $# -lt 1 ]] && echo fatal: remote_script requires a 'host' && help && return 1
host=$1; shift 1
[[ ! $host ]] && echo fatal: no host was passed unable to excute a remote script && return 3
user=$(get_user_host $host)
[[ ! $user ]] && echo fatal: unable to determine user at host $host, aborting remote script && return 4
hostname=$(get_hostname_host $host)
# script can come from
if [[ $rfn ]]; then
# if ! declare -f $rfn >/dev/null; then
# if ! module_load $1; then
# [[ -f $1 ]] && source $1
# fi
if ! declare -f $rfn >/dev/null; then echo fatal: remote-script, unable to extract funtion $rfn, aborting; return 1; fi
# # a passed script was used
# shift
# fi
script=$(mkrfilename temp_function)
declare -f $rfn > $script
cfn="-f $rfn"
else
script=$1
shift 1
fi
[[ ! $script ]] && echo fatal: must pass a script to remote run && help && return 1
debug echo host: $host user: $user hostname:$hostname script:$script function to run: $cfn
bscript=$(mkrfilename bundle_script )
if ! bundle -c $cfn $script $bscript; then
>&2 echo fatal: remote_script unable to bundle script for sending, aborting; return 1;
fi
if [[ $usesudo ]] || [[ $supass ]]; then
[[ $usesudo ]] && supass=$(parse_option "${sshargs[*]}" -p)
if [[ $supass ]]; then
[[ $login ]] && slogin="-i"
usesudo="echo '${supass}' | sudo $slogin -u ${ruser:-root} --stdin 2>/dev/null"
echo remote script to be run as ${ruser:-root} using sudo
else
echo sudo requested but no sudo password supplied, aborting
return 5
fi
fi
debug remote script arguments $(escape_args "$@")
debug ssh arguments $(escape_args "${sshargs[@]}")
rscript=${save:-$(mkrfilename REMOTE_SCRIPT)}
# sshcp -y -d $host $bscript $rscript -- "${sshargs[@]}"
# return
if sshcp -d $host $bscript $rscript -- "${sshargs[@]}"; then
# make remote script excuteable
ssh "${sshargs[@]}" "$host" "chmod +x $rscript"
ssh "${sshargs[@]}" "$host" "$usesudo" "$env_vars" "$shell" $login "$rscript" "$(escape_args "$@")"
# now delete it, save script if passed an explicit name
if ! ssh "${sshargs[@]}" $host rm -f $rscript; then echo unable to delete temporary remote file at $host:$rscript; fi
# ssh "${sshargs[@]}" "$host" "cat $rscript"
else
>&2 echo fatal: remote_script failed because script could not be copied; return 1;
fi
rm -f $bscript
[[ $rfn ]] && [[ "${script}" =~ "temp_function" ]] && rm -f $script
}
# END REMOTE SCRIPT
# # if script was executed then call the function
(return 0 2>/dev/null) ||remote_script $@
# can be used with a file or HEREDOC
# todo test with < $file or with a pipe
remote_stdin () {
local file
echo "remote send multiple commands for cli, type commands"
echo "then cntrl-d to end and send"
file=$( mkrfilename remote_script )
cat > $file
remote_script $1 "$file" "$@"
rm -f $file &> /dev/null
}
remote_test () {
local pass
echo "to run: remote_test host password"
[[ $2 ]] && pass="-- -p $2"
echo "------------ test one, no login shell, regular user ------------------"
echo "running: remote_script -f -x remote_test_script -e ENV_TEST="test env variable" $1 remote arg1 "arg 2" arg3 arg4 $pass"
remote_script -x remote_test_script -e ENV_TEST="test env variable" $1 remote arg1 "arg 2" arg3 arg4 $pass
echo "------------ test two, login shell, regular user ------------------"
remote_script -l -x remote_test_script -e ENV_TEST="test env variable" $1 remote arg1 "arg 2" arg3 arg4 $pass
echo "------------ test three, no login shell, root/sudo user ------------------"
remote_script -s -x remote_test_script -e ENV_TEST="test env variable" $1 remote arg1 "arg 2" arg3 arg4 $pass
echo "------------ test four, login shell, root/sudo user ------------------"
remote_script -s -l -x remote_test_script -e ENV_TEST="test env variable" $1 remote arg1 "arg 2" arg3 arg4 $pass
echo "-------------------- done tests ----------------"
}
remote_test_script () {
shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'
env | grep SHELL_BASE
echo ENV_TEST: $ENV_TEST
echo running on machine: $(hostnamectl hostname)
echo as user:home $(whoami):$HOME
echo argument1 $1
echo argument2 $2
echo remaining arguments: "${@:3}"
}