Posts Tagged ‘bash’

Linux : Running a script across many hosts in a network

Friday, February 24th, 2012

In any environment that has many systems it is useful to be able to run a script or tool across many different hosts to ensure that they are all the same or other automation-esq problems. Many people suggest that you need to install configuration or systems management tools for such a task. I disagree. For simple tasks you can use built in functions within bash to simplify your life.

In this example I will run a megaraid command across all hosts in a /16 network to set the local raid card’s clock.

for network in {1..254};
  do 
    for host in {1..254};
     do 
       echo "10.1.$network.$host"
       ssh 10.1.$network.$host /opt/MegaRAID/MegaCli/MegaCli64 -AdpSetTime `date +%Y%m%d` `date +%H:%M:%S` -aALL -NoLog
       ssh 10.1.$network.$host /opt/MegaRAID/MegaCli/MegaCli64 -AdpGetTime -aALL -NoLog | grep -E 'Date:|Time:'
     done
 done

In this script it builds an IP using the bash range {} command which builds a sequence of numbers which match the IP ranges. That way we can ssh to every host from 10.1.1.1 to 10.1.254.254. That is a massive network and would take considerable time to complete. However the example is an easy one to register. It will then set the time, and then query to ensure that the time has been set correctly. The logic can be transposed to anything you want.

Adding User Credentials

By default the login here uses the user that you are logged in as. If you have a system that requires different credentials try changing the ssh to ssh <user>@<hostname> from ssh <hostname>. Also note that it requires SSH key based authentication to work properly. If you want to use sudo then you may need to adjust the sudoers or use expect to adjust the command (or use root which is not recommended).

Running as a one liner

The above script can be run as a one-liner if you put a ; at the end of each line and join the lines together. I have put the logic into a proper structure so that people can follow the logic of the script.

Running as a script

If you want to run this as a script.. which means you probably want to do something more advanced like doing expect then it is worth while adding a #!/bin/bash or similar line to the begining of the first line like so

#!/bin/bash
for network in {1..254};
  do 
   for host in {1..254};
      do 
        echo "10.1.$network.$host"
        ssh 10.1.$network.$host /opt/MegaRAID/MegaCli/MegaCli64 -AdpSetTime `date +%Y%m%d` `date +%H:%M:%S` -aALL -NoLog
        ssh 10.1.$network.$host /opt/MegaRAID/MegaCli/MegaCli64 -AdpGetTime -aALL -NoLog | grep -E 'Date:|Time:'
      done
 done

Running the script concurrently

To cut down the amount of time that the script runs you can run it concurrently by splitting of sub processes as a part of the for loop. Try this

#!/bin/bash
for network in {1..254};
  do 
   for host in {1..254};
     (
     do 
       echo "10.1.$network.$host"
       ssh 10.1.$network.$host /opt/MegaRAID/MegaCli/MegaCli64 -AdpSetTime `date +%Y%m%d` `date +%H:%M:%S` -aALL -NoLog
       ssh 10.1.$network.$host /opt/MegaRAID/MegaCli/MegaCli64 -AdpGetTime -aALL -NoLog | grep -E 'Date:|Time:'
     done
     )
 done