
He estado un poco alejado del blog por que he estado trabajando en un pequeño proyecto que me ha quitado mas del tiempo esperado.
Con lo que respecta a este script, comentar que nace de la necesidad de ejecutar varios comandos a la vez en varias maquinas remotas por SSH. Antes de tener este script, lo que estaba haciendo era conectarme a las maquinas remotas por SSH y ejecutar los comandos en serie, es decir, tenía un script con un bucle para ejecutar ‘X‘ y ‘Z‘ comando en todas la maquinas remotas, el problema de esto era que los comandos debían ser ejecutados sobre 3000 maquinas, con previsión de tener que hacerlo hasta en un total de 6000
Con este script lo que he conseguido es enviar uno o varios comandos hasta un total de 8000 dispositivos a la vez. Para ver mejor la problemática: tenia que conectarme por SSH al dispositivo, realizar unas modificaciones en ciertos ficheros del sistema y a continuación reiniciar el dispositivo, esto con 3000 dispositivos tomaba hasta 1 h 30 min el proceso era el siguiente:
for device in deviceslist; do ssh $device execute command1 and execute command2 done
Con el nuevo script el proceso es diferente, y para ejecutar los comandos del segundo equipo en la lista, no espera a que los comandos del dispositivo primero hayan sido ejecutados, es decir se realizan todas las conexiones en paralelo y en este caso toma 2 segundos para ejecutar los comandos, como veis la diferencia es ABISMAL. La complejidad del script no es muy grande.
A continuación dejo el código del script, pero como sabéis, si realizo alguna modificación en el script lo haré en mi GitHub, así que si quieres la última versión pásate por aquí
#!/bin/bash # dependencias: sshpass # Comando a enviar a los dispositivos commandToSend="touch commandSender.txt" #read -p "Inserta el comando a enviar: " commandToSend # ficheros de logs logOK="/root/commsenderlogOK.txt" logKO="/root/commsenderlogKO.txt" # password pass_dev='password' commandSender() { # Funcion principal encargada de enviar los comandos a los dispositivos # las ordenes pasadas con la variable $commandToSend if [[ ! $(ping -w1 $1 | grep "100% packet loss") ]]; then echo "DEV: $ip UP" echo "$ip" >> $logOK; sshpass -p $pass_dev ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $1 "$commandToSend" 2> /dev/null 1>&2 else echo "DEV: $ip DOWN" echo "$ip" >> $logKO; fi } help() { # Funcion encargada de mostrar ayuda al usuario echo "-j [0-8000]" echo " Numero de conexiones que se generan en paralelo. Cualquier numero entre 0 y 8000" echo " Por ejemplo:" echo " commandsender.sh -j 300" echo " Establecera 300 conexiones en paralelo a 300 dispositivos, y entonces" echo " esperara a que todos los comandos hayan sido ejecutados para continuar" echo " con las siguientes 300 conexiones." echo "" echo " Valor por defecto: -j 100" echo "" echo "-f nombre_archivo" echo " Si desea usar otro nombre escribalo usando esta opción." echo " Por ejemplo:" echo " commandsender.sh -f /tmp/direccionesips.txt" echo "" echo " Valor por defecto: /root/ips.txt" echo "" echo "-h" echo " Muestra la ayuda del script." echo "" } # se obtienen las valores pasados en las opciones while getopts ":j:f:h" opt; do case "$opt" in j) maxJobs=$OPTARG ;; f) ipsFile=$OPTARG ;; h) help; exit ;; *) echo "Opción invalida. -$OPTARG"; exit ;; esac done # si la variable $ipsFile es nula por que el usuario # no la ha declarado, por defecto usamos /root/ips.txt if [ -z $ipsFile ]; then ipsFile="/root/ips.txt"; else if [ ! -f $ipsFile ]; then echo "El archivo $ipsFile no existe."; exit 1; fi fi # Si la variable $maxJobs es nula por que el usuario # no ha pasado dicha opcion, por defecto usamos 100 if [ -z $maxJobs ]; then maxJobs=100; fi # Obtenemos todas las IPs del fichero listado_devices=$(cat $ipsFile) for ip in $listado_devices; do runningJobs=$(($runningJobs + 1)) commandSender $ip & if [ $runningJobs -eq $maxJobs ]; then wait; runningJobs=0; fi done
Hay una limitación que he comentado en el script y es el numero de conexiones, en este caso 8000 esto es debido a que el numero máximo de PID (jobs) que puede tener un PPID esta limitado a ese numero. He estado leyendo y no existen otra razón que pueda limitar las conexiones multiples. En Linux también se definen limites por conexiones TCP pero en este caso el limite suele ser muy alto y no debería ser un problema.