#!/bin/bash -e # # sync-router shell scripts to synchronize cisco configuration and DHCP static # lease files with with GIT repository. Operations performed: # - update header of modified DHCP static lease files, upload # them using using scp and add them to the next commit # - restart Cisco DHCP service after updating static lease files # - copy Cisco startup-config using scp and add to next commit # - update IOS image files on the router when checked in to the # repository, update startup-config file accordingly on router # - commit changes to the git repository # # Version 1.2, latest version at: https://gitlab.lindenaar.net/scripts/cisco # # Copyright (c) 2016 Frederik Lindenaar # # This script is free software: you can redistribute and/or modify it under the # terms of version 3 of the GNU General Public License as published by the Free # Software Foundation, or (at your option) any later version of the license. # # This script is distributed in the hope that it will be useful but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program. If not, visit <http://www.gnu.org/licenses/> to download it. ### Configuration ### router=`basename \`dirname $0 | pwd\`` # name of router - based on directory dhcpfiles=dhcp-\* # list/pattern of dhcp lease files imagefiles=c??00-universalk9-mz.S[SP]A.\* # list/pattern of IOS image files filestore=flash # location of dhcp/IOS files on cisco ### Implementation ### echo updating with $router # Support function to print an error message and quit with an error exit code(1) # parameters: $1 - message to be printed fail() { echo FATAL: ${1?ERROR: no error message provided for fail()}, aborted exit 1 } # Support function to download a file from the router # parameters: $1 - filename to be copied and $2 - (optional) target filename # when no target filename is provided the source file will be downloaded to the # current directory with the same name. Adds downloaded file to git changeset router_file_download() { fromfile=${1?ERROR: at least one filename is required to copy from router} tofile=${2:-$fromfile} if [ "$fromfile" == startup-config ]; then filesrc=nvram else filesrc=$filestore fi echo downloading $tofile from router $filesrc if scp -q $router:$filesrc:$fromfile $tofile; then git add $tofile else fail "download of $tofile failed" fi } # Support function to upload a file to the router # parameters: $1 - filename to be copied and $2 - (optional) target filename # when a target filename is provided the source file will be moved to the target # file after uploading and the target file is added to the git changeset router_file_upload() { fromfile=${1?ERROR: at least one filename is required to copy to router} tofile=${2:-$fromfile} if [ "$tofile" == startup-config ]; then filedst=nvram else filedst=$filestore fi echo uploading new/updated $tofile to router $filedst if scp -q $fromfile $router:$filedst:$tofile; then if [ "$fromfile" != "$tofile" ]; then mv $fromfile $tofile git add $tofile fi else fail "upload of $tofile failed" fi } # Support function to remove a file from the router # parameters: $1 - filename to be removed router_file_remove() { delfile=${1?ERROR: need a filename to remove from router} echo removing $delfile as it is no longer in the repository if ! ssh -q $router "delete /force $filestore:$delfile"; then fail "removal of $delfile failed" fi } # Fetch the start-up configuration from the router router_file_download startup-config # Process the DHCP static lease files that have changed git status -s "$dhcpfiles" | while read status filename token newfilename do case $status in \?\?) echo skipping $filename as it is not yet added to the repository ;; D) router_file_remove $filename ;; R) router_file_remove $filename router_file_upload $newfilename ;; A |M|MM) echo updating and uploading modified file $filename head -2 $filename | while read tag value do case $tag in \*time\*) date +"$tag %h %d %Y %l:%M %p" > .$filename.$$.tmp ;; \*version\*) echo $tag $[ $value + 1 ] >> .$filename.$$.tmp ;; *) fail "found unknown entry \"$tag $value\" in $filename" ;; esac done tail +3 $filename >> .$filename.$$.tmp router_file_upload .$filename.$$.tmp $filename ;; *) fail "unsupported git status \"$status\" for $filename" ;; esac done # Restart the DHCP service on the router if any of the dhcp files changed if git status -s "$dhcpfiles" | egrep -q ^[MAD]; then echo restarting DHCP service cat << EOT | if ! ssh -q $router; then configure terminal no service dhcp service dhcp exit exit EOT fail "unable to restart DHCP service" fi fi # Process the IOS image files that have changed git status -s "$imagefiles" | while read status filename token newfilename do case $status in \?\?) echo skipping $filename as it is not yet added to the repository ;; R) router_file_remove $filename router_file_upload $newfilename ;; D) router_file_remove $filename ;; A |M) router_file_upload $filename ;; *) fail "unsupported git status \"$status\" for $filename" ;; esac done # Update the boot images in the startup-config file if we're updating any images if git status -s "$imagefiles" | egrep -q ^[MADR]; then fgrep -n "boot system $filestore" startup-config | cut -d: -f1 > .startup-config.$$.lines head -$[ `head -1 .startup-config.$$.lines` -1 ] startup-config > .startup-config.$$ git ls-files $imagefiles | sort -r | sed "s/^/boot system $filestore /g" >> .startup-config.$$ tail +$[ `tail -1 .startup-config.$$.lines` +1 ] startup-config >> .startup-config.$$ rm .startup-config.$$.lines router_file_upload .startup-config.$$ startup-config fi # show what has changed in the startup config and commit to the repository git diff --cached startup-config git commit || git reset HEAD startup-config