This is an old revision of the document!
Command Many Systems Part2: Send Cmd
General Information
Script using techniques from Part 1 to send commands in a variety of ways to a different number of systems.
Checklist
- Distro(s): Any
- Other: Use of SSH Public/Private keys so nothing prompts for a password in the loop.
- Understanding of Part 1
Script Usage
Help screen for send-cmd.sh:
./send-cmd.sh -h
==== Send Command ==== Description: Execute a command on the specified system(s). --Usage-- send-cmd.sh <SYSTEM-OPTION> -c 'command to send' [OTHER OPTIONS] SYSTEM OPTIONS -s system => Single system hostname(unquoted). -s 'system1 system2' => Multiple system hostnames(quoted). -s filename => File with system name(s). -g system-group => Spacewalk system group. -a => All Spacewalk registered systems. COMMAND SYNTAX -c 'command to send' => Send the quoted command.(Can be unquoted if only 1 word) OTHER OPTIONS -h => Display usage. -p => Send commands in parallel. -w num => Set the max workers for parallel mode (default:10) -v => Verbose output. --Other Requirements-- -> Spacecmd and config file setup required.(-g or -a only) -> Run as a user with system list privileges on the Spacewalk server.(-g or -a only)
The Scripts
Main Script File
Main send-cmd.sh script file.
- send-cmd.sh
#!/bin/bash # Name: send-cmd.sh # Description: Execute a command(s) on the specified system(s) # Last Updated: 11/25/2016 # Recent Changes:-Added support for sending to multiple system names as an argument # -Added support for sending to system names in a file # -Added support for parallel processing ################################################################################ ##### Customize These Variables ##### # Spacecmd command and any default arguments spacecmd_cmd="spacecmd -q" # Max number of workers at a time max_workers=5 # Worker script worker_script="/admin/scripts/worker_send-cmd.sh" ##### End of Customize Variables ##### #===================================== # Functions; Main starts after #===================================== function show_usage { echo -e "\n==== Send Command ====" echo -e "\nDescription: Execute a command on the specified system(s)." echo -e "\n--Usage--" echo -e "send-cmd.sh [SYSTEM-OPTION] -c 'command to send'" echo -e "\nSYSTEM OPTIONS" echo -e "-s system => Single system name(unquoted)." echo -e "-s 'system1 system2' => Multiple systems(quoted)." echo -e "-s filename => File with system name(s)." echo -e "-g system-group => Spacewalk system group." echo -e "-a => All Spacewalk registered systems." echo -e "\nOTHER OPTIONS" echo -e "-h => Display usage." echo -e "-c 'command to send' => Send the quoted command." echo -e "-p => Send commands in parallel.(max workers=${max_workers})" echo -e "\n--Other Requirements--" echo -e "-> Spacecmd and config file setup required.(-g or -a only)" echo -e "-> Run as a user with system list privileges on the Spacewalk server.(-g or -a only)" echo -e } #======================= # Get Script Arguments #======================= # Reset POSIX variable in case it has been used previously in this shell OPTIND=1 ## Default settings ## # Do not send to all systems by default all_systems="no" # Send commands in serial by default parallel_cmds="no" ## Get command line arguments ## while getopts "hs:g:ac:p" opt; do case "${opt}" in h) # -h (help) argument show_usage exit 0 ;; s) # -s system system_name="${OPTARG}" # Determine if cmd type is single system(s) argument or filename if [[ -f ${system_name} ]]; then cmd_type="file" else cmd_type="single" fi ;; g) # -g system-group system_group="${OPTARG}" cmd_type="group" ;; a) # -a (all systems) all_systems="yes" cmd_type="all" ;; c) # command to send send_cmd="${OPTARG}" ;; p) # send commands in parallel parallel_cmds="yes" ;; *) # invalid argument show_usage exit 0 ;; esac done ## Argument Sanity Checks ## # Scenario: No arguments set if [[ ${all_systems} == "no" ]]; then if [[ -z ${system_name} && -z ${system_group} ]]; then echo -e "\n>> ERROR! You must decide on what system(s) will be sent the command." show_usage exit 1 fi fi # Scenario: All systems AND single system(s) argument/filename set if [[ ${all_systems} == "yes" && ${system_name} ]]; then echo -e "\n>> ERROR! Incompatible arguments (all systems and a single system(s) argument/file)." show_usage exit 1 fi # Scenario: All systems AND system group set if [[ ${all_systems} == "yes" && ${system_group} ]]; then echo -e "\n>> ERROR! Incompatible arguments (all systems and a system group)." show_usage exit 1 fi # Scenario: Single system(s) argument AND system group set if [[ ${system_name} && ${system_group} ]]; then echo -e "\n>> ERROR! Incompatible arguments (single system(s) argument/file and a system group)." show_usage exit 1 fi # Scenario: No command set if [[ -z ${send_cmd} ]]; then echo -e "\n>> ERROR! You must enter a command to send." show_usage exit 1 fi ## Command Type: Single or Filename ## #=================== # Pre-checks: Ensure dependencies exist #=================== # Only check for Spacewalk dependencies if NOT sending to a single system(s) argument/file if [[ -z ${system_name} ]]; then # Check for Spacecmd which spacecmd &> /dev/null if [[ $? -ne 0 ]]; then echo "\n>> Error! The command 'spacecmd' is not found or not in PATH. Exiting..." exit 1 fi # Check to see if a spacecmd config file exists if [[ ! -f ${HOME}/.spacecmd/config ]]; then echo -e "\n>> Error! No spacecmd config file found at: ${HOME}/.spacecmd/config. Exiting..." exit 1 fi fi #=================== # Main starts here #=================== echo -e "=============================" echo -e "####=== Send Command ====####" echo -e "=============================" echo -e "NOTE: Commands with spaces and multiple system names must be quoted.\n" if [[ ${system_name} ]]; then if [[ ${cmd_type} == "file" ]]; then echo -e "Send command to these system(s) from file(${system_name}): \n$(cat ${system_name})" else echo -e "Send command to system(s): ${system_name}" fi elif [[ ${system_group} ]]; then echo -e "Send command to systems in this Spacewalk group: ${system_group}" else echo -e "Send command to ALL systems." fi if [[ ${parallel_cmds} == "yes" ]]; then echo -e "Send Mode: Parallel with workers" else echo -e "Send Mode: Serial" fi echo -e "Command to send: ${send_cmd}" echo -e "\n=>Continue?[y/n]:\c" read run_script if [[ ${run_script} != "y" ]]; then echo -e "\n>>Will not run the send command script. Exiting..." exit 1 fi # If we are using parallel commands, set the current number of workers if [[ ${parallel_cmds} == "yes" ]]; then current_workers=0 fi case ${cmd_type} in single) ## Single system(s) argument ## echo -e "\n>> Sending command(s) to system(s)..." if [[ ${parallel_cmds} == "yes" ]]; then # Parallel Execution for node in $(echo ${system_name}); do # If the current number of workers equals the max, wait for them to complete, then reset to zero if [[ ${current_workers} -ge ${max_workers} ]]; then wait current_workers=0 fi # Start a new worker in the background (${worker_script} ${node} "${send_cmd}") & # Increase the number of current workers current_workers=$(( ${current_workers} + 1 )) done # Wait for all remaining workers to complete wait else # Serial Execution for node in $(echo ${system_name}); do echo "->${node}" ssh -qt -o ConnectTimeout=5 ${node} "${send_cmd}" done fi ;; file) ## File with one or more systems ## echo -e "\n>> Sending command(s) to system(s) in file (${system_name})..." if [[ ${parallel_cmds} == "yes" ]]; then # Parallel Execution for node in $(cat ${system_name}); do # If the current number of workers equals the max, wait for them to complete, then reset to zero if [[ ${current_workers} -ge ${max_workers} ]]; then wait current_workers=0 fi # Start a new worker in the background (${worker_script} ${node} "${send_cmd}") & # Increase the number of current workers current_workers=$(( ${current_workers} + 1 )) done # Wait for all remaining workers to complete wait else # Serial Execution for node in $(cat ${system_name}); do echo "->${node}" ssh -qt -o ConnectTimeout=5 ${node} "${send_cmd}" done fi ;; group) ## Group of systems (Spacewalk Group) ## echo -e "\n>> Sending command(s) to a group of systems (${system_group})..." # Check to see if the Spacewalk group exists; exit if it does not ${spacecmd_cmd} group_list | grep ${system_group} > /dev/null if [[ $? -ne 0 ]]; then echo -e "-> ERROR! Could not find Spacewalk group: ${system_group}" exit 1 fi if [[ ${parallel_cmds} == "yes" ]]; then # Parallel Execution for node in $(${spacecmd_cmd} group_listsystems ${system_group}); do # If the current number of workers equals the max, wait for them to complete, then reset to zero if [[ ${current_workers} -ge ${max_workers} ]]; then wait current_workers=0 fi # Start a new worker in the background (${worker_script} ${node} "${send_cmd}") & # Increase the number of current workers current_workers=$(( ${current_workers} + 1 )) done # Wait for all remaining workers to complete wait else # Serial Execution for node in $(${spacecmd_cmd} group_listsystems ${system_group}); do echo "->${node}" ssh -qt -o ConnectTimeout=5 ${node} "${send_cmd}" done fi ;; all) ## All Systems ## echo -e "\n>> Sending command(s) to All systems..." if [[ ${parallel_cmds} == "yes" ]]; then # Parallel Execution for node in $(${spacecmd_cmd} system_list); do # If the current number of workers equals the max, wait for them to complete, then reset to zero if [[ ${current_workers} -ge ${max_workers} ]]; then wait current_workers=0 fi # Start a new worker in the background (${worker_script} ${node} "${send_cmd}") & # Increase the number of current workers by one current_workers=$(( ${current_workers} + 1 )) done # Wait for all remaining workers to complete wait else # Serial Execution for node in $(${spacecmd_cmd} system_list); do echo "->${node}" ssh -qt -o ConnectTimeout=5 ${node} "${send_cmd}" done fi ;; esac echo -e "\n=============================" echo -e "=- Send Command Completed. -=" echo -e "============================="
Worker Script File
Worker script file used for parallel commands only.
- worker_send-cmd.sh
#!/bin/bash # Name: worker_send-cmd.sh # Description: Worker script for the parent "send-cmd.sh" # Last Updated: 2016-11-25 # Recent Changes:-File rename ############################################################## if [[ -z ${1} ]]; then echo -e "ERROR! This worker script requires arguments and is meant to be executed via its parent script." echo -e "For usage see: ./send-cmd.sh -h" exit 1 fi # Set system name to the first argument system_name="${1}" # Shift arguments and set the command to send as the remaining arguments shift send_cmd="$@" # Send command to system and capture output echo "-> Working on ${system_name}..." output="$(ssh -qt -o ConnectTimeout=5 ${system_name} "${send_cmd}")" # Show formatted output echo -e ">> Returned output from ${system_name}:\n${output}"