Bulk-update
From Initech Technical Wiki
#!/bin/bash # Written by Tim Price, 18/12/2014 # # The purpose of this script is to be able to apply carefully considered bulk updates to any number of rancid # managed devices easily and automatically. # # This script takes one argument from the command line, a search string. The search string could be all or part of # a device ip address, a device type (as defined in router.db and recognised by rancid) or device description(#1). # The script will present a checkbox list (all items checked by default) of all the devices that match that search # parameter which will allow you to fine-tune your selection of devices to apply the update to. # This will be followed by a multi-line text editing prompt where commands that would be valid for CLI input to # devices are entered. The commands entered at the second prompt are not validated for syntax or sanity in any way, # the user is trusted implicitely, therefore you must take extreme care. It is recommended to lab test all code # used for bulk updates and carefully consider the list of hosts that the code will applied to. # # Also note that 'conf t' and 'wr mem' for cisco and 'configure' and 'commit' for juniper are not implied, they # must be part of your script. # # (1). Device descriptions are formed by syncing Cacti information into the .cloginrc file for rancid to use. the # device descriptions are a concatination of the Cacti graph tree name and the device name and are stored as # hash (#) prefixed comments before each entry in the .cloginrc file for rancid. Because the structure # of the .cloginrc file is maintained automatically by another script it is expected that the structure # will remain consistent to this format. # declare MENU_TEMP=`mktemp` declare COMMAND_TEMP=`mktemp` declare COMMAND_TEMP2=`mktemp` declare -a MENU_OPTIONS function cleanup { unlink $MENU_TEMP unlink $COMMAND_TEMP unlink $COMMAND_TEMP2 if [ ! -z $1 ]; then echo "#################################################" echo "" echo $1 echo "" echo "#################################################" fi exit } # Bail out if the current user is not the 'rancid' user. This is important because rancid basically doesn't # work unless you're logged in as the rancid user. `sudo su - rancid` fixes this normally. if [ `whoami` != "rancid" ]; then cleanup "You must be the rancid user to run this, exiting" fi # Test to see if a search term was provided to the program at startup. We don't care either way but the program # behaviour will differ depending. If no search term was provided then all the devices in the .cloginrc file # are presented in the checkbox list for deselection. if [ -z "$1" ] ; then IP_LIST=`cat ~rancid/.cloginrc | egrep "^add\s" |awk '{print $3}' | sort | uniq | grep -v "\*"` else declare IP_LIST for GROUP in `grep '^LIST_OF_GROUPS' /etc/rancid/rancid.conf | sed -r -e "s/LIST_OF_GROUPS(\s*)?=(\s*)?\"(.*)\"/\3/"` do IP_LIST="$IP_LIST"`egrep -i $1 ~rancid/"${GROUP}"/routers.up | awk -F: '{print $1}'` done if [ -z "$IP_LIST" ]; then IP_LIST=`egrep -i -A 1 $1 ~rancid/.cloginrc | egrep "^add\s" |awk '{print $3}' | sort | uniq | grep -v "\*"` fi fi # If nothing matches the search term or there is nothing in the .cloginrc file then bail out. if [ -z "$IP_LIST" ]; then $0 cleanup fi # This compiles the list of array of IP addresses, device descriptions and 'on' checkbox statuses for the dialog menu binary. COUNT=0 for IP in $IP_LIST do DESC=`egrep -B 1 "\s$IP\s" ~rancid/.cloginrc | egrep "^(\s*)?#" | sed -r -e "s/(\s*)?#(\s*)?//g"` MENU_OPTIONS=( "${MENU_OPTIONS[@]}" "${IP}" ) MENU_OPTIONS=( "${MENU_OPTIONS[@]}" "${DESC}" ) MENU_OPTIONS=( "${MENU_OPTIONS[@]}" "on" ) COUNT=$((COUNT+1)) done # Present the dialog checklist menu, save the selected items to the temporary file defined in the script header. If no # devices are selected then bail out and cleanup temp files. if [ "$COUNT" -gt "0" ] ; then dialog --separate-output --checklist "The following devices match your search term of $1 please select one to connect" 0 0 0 "${MENU_OPTIONS[@]}" 2>$MENU_TEMP if [ "$?" != "0" ]; then cleanup else if [ ! -s $MENU_TEMP ]; then cleanup "No devices selected, exiting" fi # IP=$(<$MENU_TEMP) fi else cleanup fi # Firstly echo some words of wisdom to the temporary file defined in the header for storing the device commands, then # present it to the user for editing. Save the output back to the same file. echo "# Enter your commands here, hash (#) prepended lines will be ignored." > $COMMAND_TEMP echo "# Remember to 'conf t' and 'wr mem' for cisco or 'configure' and 'commit' for juniper" >> $COMMAND_TEMP echo "" >> $COMMAND_TEMP echo "" >> $COMMAND_TEMP dialog --editbox $COMMAND_TEMP 0 0 2> $COMMAND_TEMP2 if [ "$?" != "0" ]; then cleanup fi # Strip all the comments out of the command file sed -i '/^#\|^\s#\|^\s*#\|^$/d' $COMMAND_TEMP2 # Bail out if there are no commands present in the command file after stripping out blank lines and comments if [ ! -s $COMMAND_TEMP2 ]; then cleanup "No commands entered, exiting" fi # Load in IP addresses from first dialog for for each run the command file against it. IPS=$(<$MENU_TEMP) clear for IP in $IPS do for GROUP in `grep '^LIST_OF_GROUPS' /etc/rancid/rancid.conf | sed -r -e "s/LIST_OF_GROUPS(\s*)?=(\s*)?\"(.*)\"/\3/"` do TYPE=`grep "^${IP}:" ~rancid/${GROUP}"/router.db" | awk -F: '{print $2}'` LOGIN_COMMAND=`egrep "\s"\'"${TYPE}"\'"\s" ~rancid/bin/rancid-fe | awk '{print $3}' |sed -r -e s/\'\(,\)\?//g | xargs -I arg1 egrep "\s*open\(INPUT,\".*login " ~rancid/bin/arg1 |awk '{print $1}' |sed -e s/open\(INPUT,\"//` $LOGIN_COMMAND -x $COMMAND_TEMP2 $IP done done cleanup "Bulk update completed"