238 lines
7.7 KiB
Bash
238 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 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, <suppass> sudo password. If set teh 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
|
|
|
|
}
|
|
|
|
# parse ssh arguments from the rest
|
|
debug $( ( IFS=$','; echo all arguments: "$*" ) )
|
|
for ((d=1; d<$#; ++d)); do
|
|
[[ ${!d} == "--" ]] && break
|
|
done
|
|
|
|
if [[ $d -lt $# ]]; then # if there are extra ssh arguments
|
|
debug found -- at $d
|
|
sshargs=("${@:$d+1:$#}")
|
|
debug $( ( IFS=$','; echo "ssh arguments: ${sshargs[*]}" ) )
|
|
# [[ ! ${sshargs[0]} ]] && { echo missing remote machine, must provide at least a hostname, -- hostname; return 3; }
|
|
args=("${@:1:$d-1}")
|
|
# reset script arguments to just those before --
|
|
set -- "${args[@]}"
|
|
debug $( ( IFS=$','; echo remaining arguments to parse: "$*" ) )
|
|
fi
|
|
|
|
# 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 source funtion $rfn, aborting; return 1; fi
|
|
fi
|
|
shift
|
|
local file
|
|
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)}
|
|
if sshcp -d $host $bscript $rscript -- "${sshargs[@]}"; then
|
|
# make remote script excuteable
|
|
ssh "${sshargs[@]}" "$host" "chmod +x $rscript"
|
|
# run the script
|
|
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}"
|
|
}
|