0

I'm completely new to the scripts and hence need help to fix this.

We've around 3000 VMs & 450 Physical servers which are Linux based servers (few of then ubuntu starting from 9.x & few of them are Susu starting 8.X & majority of them are RHEL starting from 4.x till 7.4) on all of them I need to add few hostname entries with IP details into their respective /etc/hosts files.

I've different users on each server with full sudoers access which I can use Hence I've created a CSV file with hostname, username & password format. which contains required details to log in. Filename is "hostname_logins.csv"

I need to upload a file (i.e. hostname_list to each of these servers and then update those same details in each of the servers host files.

I'll be running this script using one RHEL 6 server. (All of the other hosts are resolvable from this server & are reachable, I've confirmed it already.)

hence need help to fix this script.

script not sure what's wrong in it as I'm a new to scripts:

#!/bin/bash

while read hostname_login user_name user_password
do
        scp -p ./hostname_list $user_name:$user_password@$hostname_login:/tmp
        ssh -eS $user_name:$user_password@$hostname_login [bash -c "echo rishee | sudo -S mv /tmp/hostname_list ./hostname_list && cp -p /etc/hosts /etc/hosts.bkp && cat ./hostname_list >> /etc/hosts && rm -f ./hostname_list"]
done < hostname_logins.csv

I need to make this as a single script which will work on all these servers. thanks in advance.

Hrish
  • 87
  • 1
  • 8
  • 2
    Why not just use DNS to add your entries too? Seems like a lot of work to do the same thing DNS does. – SpiderIce Oct 17 '17 at 19:16

1 Answers1

3

I have not tried reading CSV in shell, so this is going to be an incomplete reply. I usually use Perl or AWK to do such things.

The first problem is that shell is using blank to delimit the fields in the line, so you have to break up the fields on "," (comma) instead. So

IFS=","
while read hostname_login....

however, if it is "real" CSV, then it might look like this

"hostname_login",username,"userpass"

ie with variability as to whether it has quotes. If this is not the case, you are home free.

I am not familiar with the [bash -c] syntax in your ssh, so I can not comment on it. I would tend to use single quotes (') instead.

I think you can skip the step of mv-ing the /tmp/hostname_list to the home directory. You can just do

 ssh -eS $user_name:$user_password@$hostname_login [echo rishee | sudo -S cp -p /etc/hosts /etc/hosts.bkp && cat /tmp/hostname_list >> /etc/hosts && rm -f /tmp/hostname_list"]

I will update my answer once I have determined if that [ ] thing is a real thing. I have only ever used it in pattern matching context, and as an alias for test in conditionals. (ie for filename in hostname[0-9]; do ... or if [ -n "$var" ]; then...)

There will also be challenges with ssh+sudo where ssh fails to allocate a pty and sudo takes a fit over that. I would have to hunt around, but I feel like we addressed that by an adjustment to /etc/sudo.config or something, which is less than optimal.

As written, also, you only do the sudo for that initial mv /tmp/hostname ./hostname.

Personally, since your file content is static, I would simplify the whole escape sequence stuff with by pre-writing what you want to run at the other end, and copying that:

cat > hostname_list_script.sh

#/bin/bash

if ! cp -p /etc/hosts /etc/hosts.bkp; then 
  echo "Failed to backup /etc/hosts"
  exit 1 
fi

cat <<EOM  >> /etc/hosts
^D
cat hostname_list >> hostname_list_script.sh
EOM
^D

The file you are copying now has a little bit of text at the top, the contents you are hoping to append, and then some text at the bottom, ie

[...]
fi

cat <<EOM >> /etc/hosts
10.90.70.5  hostname1
10.90.70.4  hostname2
10.90.70.6  hostname3
EOM

Then your main script can read

#/bin/bash

IFS=","

while read hostname_login user_name user_password
do 
   scp -p ./hostname_list_script.sh $user_name:$user_password@$hostname_login:/tmp 
   echo sudo_password | ssh -t -eS $user_name:$user_password@$hostname_login '/usr/bin/sudo -S -s bash /tmp/hostname_list_script.sh'
done < hostname_logins.csv

Actually, I see another problem. I think you need to change up the password passed to sudo based on the login:

 echo $user_password | ssh ....

I think it is doubtful that sudo will take a static password on all the machines when the login password is different for each.

CAVEAT EMPTOR: I have not tested the above for the mentioned problem of pty availability, and whether you don't need to quote the bash script argument to sudo. In my head this works, but you might need to fiddle with the quoting to get it right. I did not need to update my /etc/hosts file so I did not test it.

Also as Spiderice mentioned, it might be easier to install BIND (DNS Nameserver) on one of your machines, and just do a script that adds that machine's IP address to /etc/resolv.conf instead of appending to /etc/hosts. When I first started reading your question, I wondered if we were also going to have to get involved in removing hosts and de-duplicating your /etc/hosts entry. I wonder if this might be the next question a few months from now when some of the hosts you are adding today disappear or get renamed.

My suggestion in working out how to make such a thing work would be build up in pieces. So first debug the while loop:

#!/bin/bash
while read hostname_login user_name user_password
do 
    echo "$hostname_login / $user_name / $user_password"
done  < hostname_logins.csv

then grab the top 4 lines from hostname_logins.csv file and evolve the contents of your while loop, first add on doing the file copy inside your while loop. Next from the command line work on the ssh execution line going to one host. Once you have that one all worked out, you would then paste your evolved line inside the while loop in the script. Test out again on your 4 host test set, and once you are sure you have that all worked out, then feed it your full list of hosts.