Skip to content

Instantly share code, notes, and snippets.

@dmytro
Created June 26, 2012 01:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmytro/2992692 to your computer and use it in GitHub Desktop.
Save dmytro/2992692 to your computer and use it in GitHub Desktop.
Various scripts
#!/bin/bash
:<<"=cut"
=head1 NAME
C<run_root_remotely> - use expect and sudo to deploy SSH key to remote
server root account and execute script on the remote via SSH as root
=head1 DESCRIPTION
Assumed that remote user account exists on remote machine and added to
sudoers file.
Single use SSH keys are generated on each run in /tmp directory. Keys
are copied to root account on remote server using expect and sudo.
After remote commands completed, stored locally in /tmp private and
public keys are removed. On remote machine authorized_keys file
restored to pre-run state.
=head1 USAGE
./run_root_remotely <options>
Without options prints this help.
=head2 COMMAND LINE OPTIONS
--host | -h <hostname>
Hostname of the remote server to run command (REQUIRED)
--user | -u <name>
Login name of remote user. If it is not provided, then
it is assumed to be the same as login name of user
running script.
--password | -p <password>
Password of the remote user. If password is not
provided, script will ask for it.
--local | -l <PATH>
PATH on the local host to the script. Script copied to
remote server and executed there via SSH with root privileges.
--remote | -r <PATH>
PATH on the remote host to the script to run. Script
executed on remote host with root privileges.
Both local and remote commands can be specified. In this case both
commands are executed on the remote machine.
=head1 TO-DO
- How to avoid typing password on each run and also do not use as command line option?
=head1 AUTHOR
Dmytro Kovalov, 2012, June 4.
=cut
usage () {
perldoc $0; exit
}
while test $# -gt 0; do
case "$1" in
-h|--host )
HOST=$2; shift 2 ;;
-p|--password )
PASS=$2; shift 2 ;;
-l|--local )
LOCAL_COMMAND=$2; shift 2
# Check existence of local script
[ -f ${LOCAL_COMMAND} ] || { echo "Local command script does not exist."; exit 1; }
;;
-r|--remote )
REMOTE_COMMAND=$2; shift 2;;
--) shift;;
* ) usage ;;
esac
done
[ -z "${HOST}" ] && usage
# Create keys
# ----------------------------------------
SSHDIR=$(mktemp -d /tmp/deploy_keys.XXXX)
ssh-keygen -N "" -t dsa -f ${SSHDIR}/identity 2>&1 > /dev/null
#
# Remote user's password
# ----------------------------------------
[ -z "$PASS" ] && { builtin read -p "Remote server password: " -s PASS; echo; }
KEY=$(cat ${SSHDIR}/identity.pub)
#
# Actual authorized_keys file on remote server
#
A_KEYS=/root/.ssh/authorized_keys
#
# Backup copy of the file, to restore key after completion
#
B_KEYS=/root/.ssh/authorized_keys.${USER}.$(uname -n).$$.bak
#
# Need echo to send result to user's terminal
#
echo $(expect -c "
spawn -noecho ssh -t ${USER}@${HOST} \"sudo -v \; sudo mkdir -p /root/.ssh \; sudo chmod 700 /root/.ssh\; sudo touch ${A_KEYS}\; sudo chown root ${A_KEYS}\; sudo chmod 600 ${A_KEYS}\; sudo cp --force ${A_KEYS} ${B_KEYS}\; echo '${KEY}' | sudo tee -a ${A_KEYS} \; \"
log_user 0
expect {
\"try again\" { send_user \"Wrong server or sudo password\"; exit }
-re \".*Are.*.*yes.*no.\" { send \"yes\r\n\"; exp_continue }
\"${USER}@${HOST}*assword:\" { send \"$PASS\r\" ; exp_continue}
\"sudo*assword for*:\" { send \"$PASS\r\" ; exp_continue }
eof exit
}")
if [ ! -z "${REMOTE_COMMAND}" ]; then
ssh root@${HOST} -i ${SSHDIR}/identity "${REMOTE_COMMAND}"
fi
if [ ! -z "${LOCAL_COMMAND}" ]; then
REMOTE_NAME=/tmp/$(basename ${LOCAL_COMMAND}).${USER}.$$
scp -i ${SSHDIR}/identity "${LOCAL_COMMAND}" root@${HOST}:${REMOTE_NAME} 1> /dev/null
ssh root@${HOST} -i ${SSHDIR}/identity "chmod +x ${REMOTE_NAME}; ${REMOTE_NAME}; rm -f ${REMOTE_NAME}"
fi
#
# Cleanup keys on completion
# ----------------------------------------
ssh -i ${SSHDIR}/identity root@${HOST} "/bin/mv --force ${B_KEYS} ${A_KEYS}"
rm -rf ${SSHDIR}
# Use perldoc functions to see documentation for this file.
:<<"=cut"
=head1 NAME
functions - Common functions for bash scripts
=head1 DESCRIPTIONS
Define some common bash scripts often used in Moria environment. To
use it simply source this file in your script.
=head2 SIDE EFFECTS
Re-sets PATH to /bin:/usr/bin:/sbin:/usr/sbin. If you need more PATHs
add them after sourcing this file.
=head2 VARIABLES
To exit cleanly from parent script functions rely on $PARENT
variable. It must be set in caller script as PARENT=$$
=head1 FUNCTIONS
=head2 osbreed
Returns OS name on STDOUT and sets variable $osbreed
=cut
osbreed () {
export osbreed=$(awk 'NR==1 {print $1; exit}' < /etc/issue 2> /dev/null )
echo $osbreed
}
:<<"=cut"
=head2 am_i_root
Usage:
am_i_root
Kills parent script if it is not run under root.
=cut
am_i_root () {
test $(id -u) -eq 0 || { echo "Must be run as root"; exit 2; }
}
:<<"=cut"
=head2 primary_ip
Detects IP address for the interface which have default route on it.
Returns IP on STDOUT and sets variable $primary_ip.
=cut
primary_ip () {
local IF=$(netstat -r | awk '$0 ~ /^default/ {print $8}')
export primary_ip=$(ifconfig ${IF} | awk '$0 ~ /inet addr:/ { print $2}' | cut -d: -f2)
echo $primary_ip
}
:<<"=cut"
=head2 check_dir
Check that directory exists. Return expanded PATH of the directory on
STDOUT. If not exit with a message and error.
Can be used like:
# dir=\`check_dir PATH\`
=cut
check_dir () {
test -z "$1" && { echo >&2 "Directory name must be provided"; kill $PARENT; exit 2; }
test -d $1 || { echo >&2 "Directory $1 does not exist"; kill $PARENT; exit 1; }
(cd $1 && pwd)
}
:<<"=cut"
=head2 check_file
Check that file exists. Return expanded PATH of the file on
STDOUT. If not exit with a message and error.
Can be used like:
file=\$(check_file PATH)
=cut
check_file () {
test -z "$1" && { echo >&2 "File name must be provided"; kill $PARENT; exit 2; }
test -f $1 || { echo >&2 "File $1 does not exist"; kill $PARENT; exit 1; }
echo $1
}
# END OF FUNCTIONS
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
set -e
osbreed > /dev/null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment