user2023
user2023

Reputation: 478

Script to geth count of Memory, CPU and Swap

I have a below script which is working but seems too slow, I'm not expert on the shell as still in learning process hence not getting much idea to make it more smarter.

Will appreciate any ideas on this.

MY CODE:

#!/bin/bash
CurrntTime=$(date +'%m/%d/%Y %T')

read -rsp $'Please Enter password below: ' SSHPASS
export SSHPASS
echo -e  "\n"
printf "%s %-38s  %s\n" "Server_Name                         CPU  Memory  Swap"
printf '%s\n' "-------------------------------------------------------"

for server in $(cat /home/user1/mem)
do
cpu_info=$(sshpass -e ssh -q -t  $server sudo grep processor /proc/cpuinfo | awk 'NF==3{count++} END {printf count}')
mem_info=$(sshpass -e ssh -q -t $server sudo free -g | awk '/Mem:/{printf $2}')
swap_info=$(sshpass -e ssh -q -t $server sudo free -g | awk '/Swap:/{printf $2}')
printf "%s %-38s  %s\n" "$server          $cpu_info   $mem_info     $swap_info"

done | tee -a  2>/dev/null

SCRIPT OUTPUT:

$ ./cpu-memory-count.sh
Please Enter password below:

Server_Name                          CPU  Memory  Swap
-------------------------------------------------------
udc0150.exmapl.udc.com          8   15     2
udc0196.exmapl.udc.com          8   15     2
udc0193.exmapl.udc.com          8   15     2
udc0160.exmapl.udc.com          8   15     2
udc0146.exmapl.udc.com          1   15     2

Note: I am not saving output to any of the file rather just getting them printed on the console.

EDIT:

Due to some security reasons we are not able to use ansible and key-baed access hence i used sshpass along with ssh need to become sudo where it required root privileges to get the information.

Upvotes: 1

Views: 517

Answers (1)

KamilCuk
KamilCuk

Reputation: 140960

  1. Do not use sshpass. Instead copy private key to remote locations. see ssh-copy-id.
  2. Do not create 3 separate connections to each server. Create one connection per server.
  3. Connect to servers in parallel.
  4. Do not allocate psuedoterminal when you do not use terminal features...
  5. I see no reason to use sudo to get to /proc/cpuinfo nor to free. grep has -c option. And there's nproc.
  6. Remove useless | tee -a from the end.
  7. Do not reinvent the wheel and use a tool - research ansible and similar automation utilities.

That said, I could see a function, export it, then run bash from inside xargs. GNU xargs has -P option to run stuff in parallel:

work() {
   server=$1
   # ONE connection
   tmp=$(ssh "$server" bash -c 'nproc; free -g')
   # parsing later
   cpu_info=$(<<<"$tmp" awk 'NR==1')
   mem_info=$(<<<"$tmp" awk '/Mem:/{printf $2}')
   swap_info=$(<<<"$tmp" awk '/Swap:/{printf $2}')
   # outputting
   printf "%-40s %5s %5s %5s\n" "$server" "$cpu_info" "$mem_info" "$swap_info"
}
export -f work
< /home/user1/mem xargs -P0 -n1 -d'\n' bash -c 'work "$@"' _

Could you please explain 'work "$@"' _ , as i'm still learning. if you could that will be really helpfu

< /home/user1/mem redirects the content of the file /home/user1/mem to standard input of the command. The command is xargs. xargs reads -d'\n' data separates with newlines (lines...) from the standard input, and passes -n1 one argument to the command that followed. So it executes bash -c 'work "$@"' _ <the_line> on each line. -P0 makes it do that concurrently.

From man bash we can read:

-c If the -c option is present, then commands are read from the first non-option argument command_string. If there are arguments after the command_string, the first argument is assigned to $0 and any remaining arguments are assigned to the positional parameters. The assign‐ ment to $0 sets the name of the shell, which is used in warning and error messages.

and:

@ Expands to the positional parameters, starting from one. In contexts where word splitting is performed, this expands each positional pa‐ rameter to a separate word; if not within double quotes, these words are subject to word splitting. In contexts where word splitting is not performed, this expands to a single word with each positional parameter separated by a space. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$@" is equivalent to "$1" "$2" ... If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$@" and $@ expand to nothing (i.e., they are removed).

In bash -c 'work "$@"' _ <the_line>:

  • command bash is executed with 4 arguments - -c work "$@" _ and the line content
  • bash sees -c
    • the next argument work "$@" is the script to execute
    • "$@" will expand to "$1" "$2" ...
    • Actually, here there will be only 1 argument each time, so "$@" is going to be just equal to "$1" anyway.
  • _ is assigned to $0. TBH it's ignored. It's common to use -- or - or _ or just anything.
  • <the_line> is assigned to $1

Upvotes: 3

Related Questions