all of our *nix systems are using local user accounts still, so i have come up with a management script to handle useradds / deletions / password resets etc. It is functional, but now i am trying to go through and reduce the number of ssh calls and clean up my messy coding. As it sits right now, this little section could potentially have 8 different ssh connections for just this little function..
I have searched all over to see if there is a way for me to gather more of the information that i am needed to run this code more effeciently (ie less ssh calls) but am having a hard time finding a way to set local variables from remote systems without doing a
VARIABLE=`ssh some_command`
for each one i need to gather
This is just one function in the script so there are things that are ommited such as the gathering of the arrays etc, but if anyone could give me some pointers or ideas for this section, i am sure i could adapt them to the other functions of my script
#!/bin/bash
function delete_user
{
set -x
i=0
for t in ${serverlist_array[@]}; do
SERVER=${serverlist_array[$i]}
# get the servers OS version and type
OSVER=`ssh $USER@$SERVER uname -r`
OSTYPE=`ssh $USER@$SERVER uname -s`
# get path to run root commands
if [ $OSVER = "5.10" ]; then
ADMINCMD=/usr/bin/pfexec
elif [ $OSTYPE = "Linux" ]; then
ADMINCMD=sudo
elif [ ! -z `ssh $USER@$SERVER ls /usr/local/bin/sudo` ]; then
ADMINCMD=/usr/local/bin/sudo
elif [ ! -z `ssh $USER@$SERVER ls /opt/csw/bin/sudo` ]; then
ADMINCMD=/opt/csw/bin/sudo
fi
# determine if account is local or not
if ssh $USER@$SERVER grep -w "/export/home/$USERNAME" /etc/passwd
then
LOCALHOME="true"
else
LOCALHOME="false"
fi
# if the user account doesn't exists, write that out to log file
if [[ -z `ssh $USER@$SERVER cat /etc/passwd | grep -w $USERNAME` ]]; then
echo "$SERVER Account_Doesnt_Exist" >> /tmp/passwdlist
fi
# While the user account exists on this server, create the account
while [[ -n `ssh $USER@$SERVER cat /etc/passwd | grep -w $USERNAME` ]]
do
# Determine is home directory lives local or on nas. Remove if local..
if [ $LOCALHOME = "true" ]; then
echo "Deleting user account AND local home directory on $SERVER"
ssh -t $USER@$SERVER $ADMINCMD /usr/sbin/userdel -r $USERNAME
else
echo "Deleting user account on $SERVER"
ssh -t $USER@$SERVER $ADMINCMD /usr/sbin/userdel $USERNAME
echo "PLEASE REMEMBER TO DELETE THE USERS HOME DIRECTORY ON THE HNAS!!"
fi
if [ -z `ssh $USER@$SERVER cat /etc/passwd | grep -w $USERNAME` ]; then
echo "$SERVER Account_Deleted" >> /tmp/passwdlist
else
echo "$SERVER Deletion_FAILED!!" >> /tmp/passwdlist
fi
done
i=$((i+1))
done
}
You can reduce the number of ssh connections by doing more things with one ssh call. You can run entire scripts, not just single commands:
$ ssh username@host /bin/sh -s a b 3 <<"EOF"
# Note that 'read' won't work as expected inside the <<"EOF" block
# because stdin isn't the terminal, it's the script!
echo
echo "arg1 is $1"
echo "arg2 is $2"
echo "arg3 is $3"
[ "$3" -gt 1 ] && echo "$3 > 1"
exit 42
# This EOF must be at the beginning of the line
EOF
Password:
arg1 is a
arg2 is b
arg3 is 3
3 > 1
$ echo "ssh returned $?"
ssh returned 42
$
---------- Post updated at 10:16 AM ---------- Previous update was at 10:11 AM ----------
i appreciate the pointers.. i may just have my scripts built to do things a non-optimal way, but because of the way they are currently designed, your examples dont appear to work for my situation.
My script(s) all run from a single server (doesnt matter which since it is a shared nas mount) and goes out and executes the commands on to the remote systems.. so for your example of
ssh username@host /bin/sh -s "$username" <<"EOF"
if ! /usr/sbin/userdel "$1"
then
echo "Couldn't delete remote user" >> /tmp/passwdlist
exit 1
fi
if grep -w "$1" /etc/passwd > /dev/null
then
echo "Deleting user failed" >> /tmp/passwdlist
exit 1
fi
echo "Deleting user succeeded" >> /tmp/passwdlist
exit 0
EOF
i am not able get the echo'd information back to the source server that is running it since it is running the echo on the remote system side. I use that info for the synopsis once it is done looping thru all servers..
For the other tip you gave me to reduce my ssh calls, again the issue is that i can echo the arguments, but i can't use that information since the source server knows nothing of the arguments on the remote system.. So my echo will return the uname output, but the source can't use that to determine what is needed to run the commands as root..
although everything you had helped with is functionally correct, it doesnt work for my script layout.. This is most likely an issue of my script(s) not being laid out the best way. Should i instead be pushing the scripts execution off to the remote servers instead of trying to run it all from a single source?
again, i do truly appreciate the help.. i seem to be able to come up with functional scripts, but i am still learning how to make clean, effecient, functional scripts!
ok.. that makes sense.. however the issue that i now run into with that, is i get all of the other shell output in addition to the "Deleting user succeded" output
That's very odd -- a shell run noninteractively really shouldn't be doing that! Try exec /bin/sh instead of just /bin/sh. If that doesn't work try an alternative shell, /bin/ksh or /bin/bash or what have you, instead of basic sh...
i was able to get things working properly.. my issue ended up being more with the SSH and sudo interactions and when i needed to use the -t and when i needed to use -Tt.. For some commands, i had to pull them out and move them into their own ssh connection (ie passwd)
In looking at your suggestions, i also was able to get rid of a lot of unneeded testing that i was doing in my script.
I think i have been able to clean up at least 100 lines of unneeded code with your pointer..
so just wanted to say thx!
---------- Post updated at 03:12 PM ---------- Previous update was at 02:57 PM ----------
1 last quick question.. as part of one of my scripts, i am creating the user account.. How do i need to surround the $5 in the bottom code box below in order for it to display the whole comment field? Previously, when using all my numerous ssh calls, i had been using
Currently as it sits below, for a comment field that contains "test user" i am only getting test as the comment.. i have tried numerous variations of ", and ' with no luck
ssh -qTt $USER@$SERVER /bin/bash -s "$USERNAME" "$ADMINCMD" "$OSVER" "$UIDNUM" "$COMMENT" >> /tmp/passwdlist <<"EOF"
case "$3" in
5.10 ) # Create the Solaris 10 account with the user in the Primary Admin profile
if ! "$2" /usr/sbin/useradd -u "$4" -g 111 -G 14 -s /bin/ksh -c ""$5"" -P "Primary Administrator" "$1" > /dev/n
ull
then
echo "`hostname`|Couldn't create user account"
exit 1
fi
# Verify account has been created by checking /etc/passwd
if grep -w "$1" /etc/passwd > /dev/null
then
echo "`hostname`|User account created"
exit 1
fi
;;
* ) # Create the account
if ! "$2" /usr/sbin/useradd -u "$4" -g 111 -G 14 -s /bin/ksh -M -c ""$5"" "$1" > /dev/null
then
echo "`hostname`|Couldn't create user account"
exit 1
fi
# If OSVER is greater than 5, assume a linux kernel and put user in wheel and users group
case "$3" in
2.* ) "$2" /usr/sbin/usermod -G 10,100 "$1"
;;
esac
# Verify account has been created by checking /etc/passwd
if grep -w "$1" /etc/passwd > /dev/null
then
echo "`hostname`|User account created"
exit 1
fi
;;
esac
EOF
When you ssh, one layer of quotes gets stripped out. ssh username@host echo "stuff in quotes" becomes echo stuff in quotes . You have to add in literal quote characters to preserve quotes.
hmmm.. i'm still having issues with that last piece.. could you show me what i am doing wrong in this code? The issue is with the $5 part of the useradd command.. (i added some echo tests at the top to try to help figure out the errors of my ways, and snipped out some case statements for berevity)
ssh -qTt $USER@$SERVER /bin/bash -s "$USERNAME" "$ADMINCMD" "$OSVER" "$UIDNUM" "\'$COMMENT\'" "$LAWSON" "$ROLENAME" "$EXPIRY" "$SERVER" >> /tmp/passwdlist <<"EOF"
case $9 in
* ) echo "\'$5\'" > /tmp/testuser; echo \'$5\' >> /tmp/testuser; echo "'$5'" >> /tmp/testuser
if ! "$2" /usr/sbin/useradd -u "$4" -s /bin/ksh -c "$5" -d /home/"$1" "$1" > /dev/null
then
echo "`hostname`|Couldn't create user account"
#exit 1
else
echo "`hostname`|User account created"
#exit 1
fi
# if expiration is not empty, set on account
if [ ! -z "$8" ]; then
"$2" /usr/sbin/usermod -e "$8" "$1"
fi
# if user needs to be added to a role, set it here
if [ ! "$7" = "exclude" ] && [ ! "$7" = "dontexclude" ]; then
"$2" /usr/sbin/usermod -R "$7" "$1"
fi
;;
esac
i had added the echo testers and as it sits when using a comment field containing "test user", my current output in /tmp/testuser is
\''test\'
''test'
''test'
and below is how the script for this particular command looks when running it with set -x