How many times you have worked with networks that are outright insecure, vulnerable and unpatched?
How often do you hear any of these:
a) We don't have time to upgrade.
b) We don't have an SDN or a programmable API to do this.
c) We got hacked because of a known software vulnerability.
d) We just had a major incident because the software base is so old.
e) We didn't know networks need to be patched.
In reality most organizations have massive LAN networks. Therefore all points from a) to e) lead to a huge maintenance debt because they can't keep up with the patching requirements.
This project solves the problem by implementing a Python based shell program that automates typical software management tasks required to operate and patch modern IOS-XE switches.
The design requirements for the project are:
# Get the code.
git clone https://github.com/timo-juhani/lan_upgrade.git
# Check that Python is installed.
python -V
# Install pip and venv.
sudo apt install python3-pip
pip install virtualenv
# Create a virtual environment.
python -m venv lan-upgrade
# Activate virtual environment.
source lan-upgrade/bin/activate
# Install required packages.
pip install -r requirements.txt
Sometimes it's a pain in the butt to deal with all Linux and Python dependencies. Especially so if you're using the program without Internet connectivity. In those case Docker image becomes handy. To bypass this via dolorosa build yourself a container that is easy to port between hosts regardless of Internet access.
# Build the image.
docker build -t lan-upgrade .
# Confirm.
docker images
docker run lan-upgrade -h
There are two ways to work with the program: 1) inventory mode and 2) HOST mode. The first one uses a .csv file called inventory.csv which resides in the folder root by default. Both ways are fairly easy to work with. The second one i.e. HOST mode accepts device parameters as shell arguments which is handy if you are only dealing with a single device and/or don't care about managing a separate inventory file.
SSH username:password combination is used. It can be either provided as a shell argument (raw or env variable for instance) or as a user input while the program runs.
./lan_upgrade.py -u admin -p pass123 -I activate
In inventory mode you just punch in the device parameters in .csv format (please see the sample) and let the code rely on them. Parameters required are the ones you probably expected:
# Inventory mode is enabled with -I flag
./lan_upgrade.py -I activate
It's a good idea to initially choose "no" as "upgrade" value for all devices in your inventory so that you can get familiar with the tool without sweating about the misfired upgrade.
In HOST mode you just provide same parameters as in inventory mode but the method of doing that is via shell intead of using inventory.csv. The only difference is that in HOST mode there is no "upgrade" argument. The simple expectation is that when you choose to use HOST mode you have made a decision that the device is good to be upgraded if you run anything but info operations on it.
# HOST mode requires setting the right flags. If it looks like a cluster mess, think of using env
# variables, a shell alias or a shell script - there are many ways to streamline the process to your
# taste.
# H = hostname
# O = operating system, at this point only cisco_xe supported
# S = software binary which is stored in folder root
# T = target device's management IP address
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 info -s
Alive test keeps testing the devices with Ping until they respond again. This is handy during those long moments when devices are, for instance, rebooting after an upgrade. Furthermore, it makes sense to start the upgrade process by checking all your devices responding from their IP addresses.
./lan_upgrade.py -I info -a
Make sure the device(s) is reachable by pinging it and SSH'ing into it. Do this before running any other info or installation operations to make sure all is set.
./lan_upgrade.py -I info -r
Devices that are in bundle mode should be migrated to install mode prior to trying to upgrade them. Using the info operation together with bundle flag it's easy to scan through the inventory and figure out which devices needs to be converted.
# Inventory mode.
./lan_upgrade.py -I info -b
# HOST mode.
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 info -b
Next, you'd like to know which devices need to be upgraded and which ones are already on the target version. Using the info operation with scan software flag is the way to answer that question.
The information gathered on this step and a common undestanding of the network topology gives you enough knowledge to select devices that you'd like to upgrade by marking the upgrade parameter as "yes" in the inventory.
# Inventory mode.
./lan_upgrade.py -I info -s
# HOST mode.
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 info -s
Before trying to upgrade it's a good idea to check whether the devices are crammed with old unused versions that can be safely removed.
./lan_upgrade -I clean
Warning: Upgrade is a disruptive operation!
Think, plan, pause and execute only if the maintenance has been scheduled.
Don't be a cowboy.
This is the most controlled approach that offers multiple points of return and none of them is via ROMMON. In most cases you would prefer to do upgrades using staging because it allows the upgrade prep-work and even adding the image to the device done during normal business hours. During the maintenance window you'd then activate the image which triggers the device to reload. Even after if you see something odd and are not comfortable to commit the new version you have a change to abort the upgrade.
Add operation is simply for adding the target image to image repository on the device by expanding the .bin file to .pkg files.
First thing it does is to find out whether an upgrade is truly needed and wanted by checking the inventory file and comparing the target version to the running version on the target device.
Then it checks whether the image is already on the device and if not it uploads it there with SCP if there is enough disk space. Once the image is on the flash the program makes sure it is intact by verifying the MD5 hash. If the hash is alright it adds the image using the install add command.
Activate operation changes packages.conf to match with the new .pkg files of the target image. This operation comes with a reboot. Also, activate operation starts a rollback timer. This rollback feature implemented on IOS-XE does an automatic rollback to the previous version unless you commit the target version.
So if everything goes as planned after activate operation you'd check when the devices control channels are alive again and then commit the target version. If some something unfortunate happens
or you made a mistake there are two courses of action:
# Inventory mode
# Add image to the device's image repository for later activation.
./lan_upgrade.py -I add
# Activates the added image.
# Warning: This cause the device to reboot
./lan_upgrade.py -I activate
# While the devices are rebooting use alive and reachability checks to see when they come up again.
./lan_upgrade.py -I info -a
./lan_upgrade.py -I info -r
# Commits the activated image.
./lan_upgrade.py -I commit
# Checks that software has been upgraded.
./lan_upgrade.py -I info -s
# HOST mode
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 add
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 activate
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 commit
OK, so I warned about the risks of going el pitolero as you get after that badge of honor by focusing on shots fired instead of shots on target. Once more, plan your updates correctly and reload your devices in pre-planned maintenance windows.
But let's imagine for a moment that you feel an urge like you have never felt before. A superior dark force compels you into a heinous action on a nice Friday afternoon when all your buddies are dreaming of heating sauna and drinking a few cold ones. Instead of all the warnings you decide to demote yourself to junior engineer status again, risk ruining everyone's calm afternoon and go for that final quick update.
For your appetite of destruction the program has full-install operation to go through all stages of the update using a one-shot CLI command that doesn't ask any user acknowledgements whatsoever.
In all seriousness try to avoid this approach. And if you have to use it use it a controlled place where there is no real risk of hurting uptime. A typical justification for using the one-shot is that the devices sit in the lab and you can reboot them as you please. Also full-install is used by the program when doing the coversion from bundle mode to install mode.
./lan_upgrade.py -I full-install
Most likely some of the devices in your LAN are running in BUNDLE mode. To convert from BUNDLE to INSTALL mode you can simply let the program do that for you.
# Inventory mode
./lan_upgrade -I convert
# HOST mode
./lan_upgrade.py -H sdn-e30 -O cisco_xe -S cat9k_lite_iosxe.17.09.04a.SPA.bin -T 10.1.106.11 convert
The program sends logs to stdout and application.log file. The default logging level is set to info. But there could be times when you want to have the full debug capability enabled which allows you to see what is sent to the device and how it responds back in native IOS-XE messages.
# Switch on the debug mode
./lan_upgrade.py -I info -s -d
As mentioned before it is handy have Docker as an option in those environments with limited network access to public resources such as Linux package repositories or PyPI. Using the program with Docker is quite simple but it requires some considerations in regards to networking and storage.
# The container is run like this.
# -it flags runs the container with interactive shell which allows entering username and password.
# --network flag sets the container network which allows the container to join a VPN tunnel in case it's used.
# -v (--volume) flag sets the container volume to publish SW images and inventory to the container.
# After that the execution is similar to the shell program. Dockerfile sets the entrypoint on the program.
docker run -it --network=host -v ${PWD}:/lan-upgrade/ lan-upgrade -I info -s
This project will evolve as the organizations adopt new ways of managing their networks and IOS-XE code develops. The program will never cover all detailed aspects of software management. Instead, it lives by values of pareto principle, action before procrastination and power to the many instead of privileges to the few. As outdated software persist in Top 10 security issues year after year this project provides means to respond against one of the more structural problems affecting our industry today.
Patch'em up.
Stay safe,
T-J
Code Exchange Community
Get help, share code, and collaborate with other developers in the Code Exchange community.View Community