Bulk-update

From Initech Technical Wiki
Revision as of 22:29, 9 May 2016 by Timprice (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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.
#!/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"