Suresh Vinasiththamby

Author Archives: Suresh Vinasiththamby

Managing Python Projects with uv

Managing Python Projects with uv

If you have installed Python and worked on a few projects, your usual workflow probably looks something like this. Install Python, make sure pip and venv are available, create a virtual environment for each project, and use pip to install packages inside it. That is how we have been doing things throughout this series, and it works. It is what most of the Python world has been doing for years.

uv is a relatively new tool that bundles all of this into one command. It manages Python version installs, virtual environments, package installs, and dependency locking, all in a single binary. It is written in Rust, which makes it fast (like really fast). Most operations that take pip several seconds finish in milliseconds with uv.

In this part, we will start from a completely fresh Ubuntu machine (24.04) that only has the system Python installed. As you will see in a moment, we do not have pip or venv available yet, and normally we would need to install them separately before we could do anything.

A Fresh Ubuntu VM

Here is what is happening on the fresh Ubuntu VM. python --version fails because Ubuntu does not ship the python Continue reading

Python Regular Expressions

Python Regular Expressions

You have already used regular expressions once in this series when we told deepdiff to ignore uptime fields. I promised we would cover them properly later, and now is the time.

Regular expressions (regex for short) are a way to describe patterns in text. Instead of asking "does this string contain the exact word up?" you can ask "does this string contain any four-digit number followed by a slash and another number?" That kind of question is hard to answer with the string methods we have used so far, but regex handles it easily.

For a network engineer, regex comes up in a bunch of places. Extracting an IP address from a config line. Pulling interface names out of a log message. Parsing show output when there is no ready-made TextFSM template. Validating that a value looks like a MAC address before you use it.

Regex has a reputation for being cryptic, and honestly, it is cryptic. A complex regex pattern can look like someone leaned on the keyboard. But you do not need to master all of it to be useful. Learning even the basics unlocks a lot of what you will actually need day Continue reading

Strata Cloud Manager – Worth the Hype?

Strata Cloud Manager - Worth the Hype?

If you use Palo Alto firewalls, typically you manage them in one of two ways. You either log into each firewall directly and manage it on its own, or you use Panorama, which lets you manage multiple firewalls from a single place.

Most of us were used to this setup, myself included. If you had a handful of firewalls, logging into each one individually is okay. But once you started scaling up to tens or hundreds of firewalls across different sites, Panorama became the go-to option. It let you centrally manage the configurations and monitor logs centrally instead of touching every single firewall by hand.

Strata Cloud Manager (SCM)

However, Palo Alto released yet another option called Strata Cloud Manager (SCM) in 2023, which is hosted by Palo Alto themselves, unlike Panorama, which you manage internally. The idea at a very high level is that the firewalls connect to Strata Cloud Manager (outbound only) through the Internet, and you log into SCM to manage the configurations and push them to the firewalls.

From my experience and speaking to other people, Palo Alto is pushing SCM to customers and adding new features to it. So the unspoken assumption is that any Continue reading

Automating Let’s Encrypt Certificate Renewal for Palo Alto GlobalProtect

Automating Let's Encrypt Certificate Renewal for Palo Alto GlobalProtect

If you manage GlobalProtect VPN certificates on Palo Alto and use Let's Encrypt, at some point you will start thinking about automation. Let's Encrypt certificates have a short lifespan, so renewing them manually every few months isn't really practical. In this post, we will look at automating this process using Ansible, Cloudflare DNS, and the PAN-OS Ansible collection to renew certificates and push them to the firewall.

Prerequisite

Let's say your domain is mydomain.com and it's managed through Cloudflare. You want to generate a certificate for vpn.mydomain.com and have it automatically installed on your Palo Alto firewall as the GlobalProtect portal or gateway certificate, without logging in manually every time it's close to expiry. To do this, you will need:

  • Python/Ansible installed
  • A domain managed through Cloudflare, so certbot can complete the DNS-01 challenge. This doesn't have to be Cloudflare specifically, certbot supports several other DNS providers as well, but this post assumes Cloudflare since that's what we're using here.
  • A Cloudflare API token with permission to edit DNS records for that zone
  • Certbot installed along with the Cloudflare DNS plugin
  • Ansible with the paloaltonetworks.panos collection installed
  • An API key from your Palo Alto firewall so Continue reading

Testing Your Network with Netpicker

Testing Your Network with Netpicker

In my previous two posts, we covered what Pytest is, what it is traditionally used for, and how we can use it to test your network, checking things like BGP peer status, interface states, and so on. So far, we have looked at how to run these tests using the Pytest CLI command in the terminal.

In this post, we will look at Netpicker, a tool that takes the same Pytest tests and gives you a GUI to run and manage them, instead of relying on the command line.

What is Netpicker?

Netpicker is a tool that brings together config backups, security/compliance checks, and automation in one place. It supports 180+ network vendors, including Cisco, Juniper, Arista, Palo Alto, and Fortinet, and integrates well with tools like NetBox, Nautobot, and Infrahub for inventory, and Slurp'it for network discovery.

Under the hood, Netpicker uses pytest for its testing engine, but wraps it in a web GUI, so instead of running tests from the terminal, you run and manage them from a browser. This means you can run the same kind of pytest tests we covered in the previous two posts, things like checking BGP peer status or interface states, but Continue reading

Minisforum MS-A2 Review for Network Labs/Homelab

Minisforum MS-A2 Review for Network Labs/Homelab

In my previous blog post, I covered setting up network labs on a budget using used mini PCs, and I saw good interest in that post. So, I thought I would write another one sharing my experience using the Minisforum MS-A2 for network labs. As of writing this post, the MS-A2 costs £1160 with an AMD Ryzen 9 9955HX, 32GB of DDR5 RAM, and 1TB of storage. You can buy the barebone version (without RAM and storage) for £727 on Amazon. I bought the 32GB version + 1TB of RAM.

I would have bought the 64GB RAM version (I'd recommend 64GB for anyone buying) if that was available on Amazon, but that option was only available on the Minisforum website, and it ships from their HK warehouse and takes a few days. So I went with Amazon, which came with a single 32GB stick, and then added another 32GB stick myself (RAM costs a fortune as of writing this post 😢)

  • CPU options - AMD Ryzen 9 9955HX / 9 7945HX / 7 7745HX. I went with the 9955HX (16c/32t) for extra headroom running multiple labs at once.
  • RAM - Dual channel DDR5-5600MHz, up to 96GB. Plenty for running Continue reading

UGREEN NASync DXP4800 GT Review and Initial Setup

UGREEN NASync DXP4800 GT Review and Initial Setup

Last year I bought a UGreen NASync DXP2800 for my homelab, along with two Seagate IronWolf 8TB HDDs. This was my first NAS, and I've been using it for just over a year now, and I'm very happy with it. I back up two of my Macs using Time Machine, store a lot of media, documents, photos, videos, etc, pretty much what a NAS is designed to do. I also run some Docker containers and Proxmox Backup Server as a VM. Even though it has an N100 CPU, so far I've never had a single issue in terms of resources. For £249, it was a bargain.

Fast forward to today, and UGreen released the NASync DXP4800 GT, a 4-bay NAS that comes with an AMD Ryzen Embedded R2514, dual 10GbE LAN, and dual M.2 NVMe SSD slots for £529 at the time of writing here in the UK. It looked like a great addition to my homelab setup, giving me a lot more power and flexibility compared to my current NAS. I was lucky enough to get my hands on a unit from UGreen to try out, so let's get into it.

Disclaimer - This unit was sent Continue reading

Panorama Device Groups and Templates (with examples)

Overview

Panorama Device Groups and Templates (with examples)

People who follow my blog may probably know that I'm a big fan of Cisco ASA firewalls and I worked quite extensively with them. When I was first introduced to the Palo Alto firewalls, I was amazed at how easy it is to use the web GUI compare to the ASDM which I absolutely hate.

In my early Palo Alto days, I used to work with just a single HA firewall pair where all the management and configuration were done directly on the firewall - similar to how you configure an ASA via ASDM or CLI.

When I first started working with Panorama, I was struggling to understand device group and template concepts. There were nested device groups, device group hierarchy, templates, templates stacks etc.

After reading various documents and speaking to my colleagues, I managed to get a grasp of the core concepts. At last, I've decided to write a blog post on the concepts I learnt to help fellow engineers. The purpose of this blog post is to simplify the concepts and explain them in plain English.

Source Specific Multicast (SSM) VII

Source Specific Multicast (SSM) VII

In this post, we will look at Source Specific Multicast, or SSM. This is a different approach to multicast that simplifies the overall architecture by removing the need for an RP entirely.

In the previous posts, we covered PIM Sparse Mode, where receivers join a shared tree rooted at the RP and then optionally switch to the shortest path tree toward the source. We also looked at Auto-RP and BSR, which solve the problem of dynamically distributing RP information to all routers. SSM takes a different approach by eliminating the shared tree concept altogether.

Multicast PIM Sparse Mode
Sparse Mode only sends traffic to parts of the network that explicitly request it. Routers with interested receivers send Join messages toward

Any Source Multicast (ASM)

Before we look at SSM, let's briefly talk about Any Source Multicast, or ASM. This is the traditional multicast model we have been using throughout this series.

With ASM, receivers join a multicast group without specifying a source. They simply say 'I want traffic for group 239.1.1.1' and the network figures out how to deliver traffic from any source sending to that group. This is why it is called Any Source Multicast.

Continue reading

Python Pre and Post-Change Validation

Python Pre and Post-Change Validation

If you have made a change on a network device, you have probably done the pre and post check dance at some point. You SSH into the device, run a few show commands, save the output somewhere, apply the change, then run the same commands again and compare the two by eye. It works, but it is slow and easy to get wrong. I have missed things this way, and I know most of you have too.

Once you get comfortable with Python, this is one of the first tasks you will want to automate. Instead of copy-pasting output into a text file and squinting at it, you can pull the data with a script, save it to a JSON file, and then run another script that tells you exactly what changed.

In this chapter, we will build a small pre and post check for BGP. I will show you how to grab BGP neighbor state from a device using NAPALM, save it to a JSON file as the pre snapshot, and then do the same again after the change to get the post snapshot. Once we have both, we will compare them with a library called deepdiff, which Continue reading

Python Working with Structured Data Files

Python Working with Structured Data Files

In the previous sections, we looked at reading and writing plain text files. That was a good starting point, and plain text is still the right choice for things like config backups or log files. But most of the data you deal with in network automation is not plain text, it has structure. A list of devices with their IPs, usernames, and roles. A dictionary of device facts. A nested set of configuration values with groups and per-device overrides.

When your data has structure, you need a format that can represent that structure in a way both humans and computers can understand. This is where structured data files can help. The three main formats you will run into as a network engineer are CSV, JSON, and YAML.

CSV Files

CSV stands for Comma-Separated Values. A CSV file is just a plain text file where each line is a row, and each value in the row is separated by a comma. The first row usually contains column headers.

Here is what a CSV file looks like, saved as devices.csv.

hostname,ip,vendor,role
r1,192.168.202.101,cisco,edge
r2,192.168.202.102,juniper,core
r3,192.168.202.103,arista,edge

If you have ever exported data Continue reading

Python Working With NAPALM

Python Working With NAPALM

At the end of the last part, we looked at the multi-vendor problem. Every time you support a new vendor with Netmiko, you have to remember its command syntax, keep track of the differences, and add more branching logic to your scripts. It works, but it gets messy fast.

NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) is a Python library that solves exactly this problem. Instead of sending vendor-specific commands and dealing with the differences yourself, you use NAPALM's standard set of methods, and NAPALM figures out what to do for each platform behind the scenes. Ask NAPALM to get_config(), and it will send the right command to a Cisco IOS device, the right command to a Juniper device, and the right command to an Arista device, all through the same Python method call.

NAPALM currently supports Cisco IOS, Cisco IOS-XR, Cisco NX-OS, Arista EOS, Juniper Junos, and a few others. It is not as broad as Netmiko in terms of vendor coverage, but for the vendors it does support, the abstraction it provides is well worth it.

There is one more thing worth understanding upfront. NAPALM is not a replacement for Netmiko, it actually uses Continue reading

Python Working with Files

Python Working with Files

Almost every Python script eventually needs to read from or write to a file. You might want to save the output of a command for later, back up device configs to disk, load a list of devices from a text file instead of hardcoding them, or write a log of what your script did. Python makes all of this straightforward once you know how it works.

In this part, we will start with reading text files, cover the proper way to open files using context managers, and then move on to writing and appending. Once we have the basics down, we will build a small config backup script that connects to devices, pulls the running config, and saves each one to its own file on disk.

Reading a Text File

To read a file in Python, you use the built-in open() function. It takes the path to the file as the first argument and returns a file object that you can read from.

Let's say you have a file called devices.txt in the same folder as your script, with the following contents.

192.168.202.101
192.168.202.102
192.168.202.103

Here is the most basic Continue reading

Python Parsing Command Output with TextFSM

Python Parsing Command Output with TextFSM

So far, whenever we have run a command with Netmiko, the output has come back as one big string. That is fine when you just want to print it or eyeball it, but the moment you want to actually do something with the output, filter interfaces that are down, count the number of routes in the table, extract the software version from a show version, you hit a wall. Raw text is hard to work with.

You could split it, use string methods, write clever slicing logic, or reach for regular expressions. Some people do this including myself, and it works, but it is not ideal. The moment the output format changes even slightly, your parsing breaks. And every command needs its own custom parsing code, which quickly becomes a maintenance nightmare.

This is where TextFSM comes in. It is a small library that turns messy device output into clean, structured data, usually a list of dictionaries. Instead of one big blob of text, you get proper Python objects you can loop through, filter, and index. And you do not have to write the parsing logic yourself, because there is a huge community-maintained library of ready-made templates called ntc-templates Continue reading

Python Managing Credentials and Secrets

Python Managing Credentials and Secrets

If you look back at every Netmiko script we have written in this series, you will notice something (very ) uncomfortable, the username and password are sitting right there in the script as plain text. That has been fine for learning, but it is not something you want to do in real scripts.

In this part, we will look at safer ways to manage credentials in your scripts. We will cover a few different approaches, from the simplest (asking the user to type the password when the script runs) to the more common patterns used in real projects (environment variables and .env files). We will also touch on .gitignore

There is no single "correct" way to manage credentials. Different projects and different environments call for different approaches. What matters is that you understand the trade-offs and stop hardcoding passwords into your scripts.

The Problem with Plain Text Credentials

Let's start by being clear about why this matters. Take a look at a script you have written in the last couple of chapters.

device = {
    "device_type": "cisco_ios",
    "host": "192.168.202.101",
    "username": "admin",
    "password": "admin"
}

This looks harmless on your own machine, but think about everything that could Continue reading

Rebuilding My Proxmox Cluster for the Version 9 Upgrade

Rebuilding My Proxmox Cluster for the Version 9 Upgrade

I've been running Proxmox for maybe two years now, and I'd consider myself somewhat of a beginner. I set it up once using Proxmox version 8.x alongside Proxmox Backup Server and pretty much forgot about it. I can spin up new VMs and CTs, or remove existing ones, and that's about it. Fast forward to mid-2026, Proxmox released version 9, and I'd been meaning to upgrade. I went through a few guides and forum posts, and people tended to recommend backing up the VMs and CTs using PBS, then reinstalling Proxmox with the new version and restoring from backup.

TL;DR

I upgraded my Proxmox setup from version 8.x to 9 without doing an in-place upgrade. Instead, I used a spare node already on version 9 as a temporary home and rebuilt the other two nodes one at a time. The idea was to back up everything with PBS, restore onto the spare, then wipe and fresh install version 9 on each node before joining them into a new three-node cluster. Once the cluster was sorted, I also rebuilt pbs-01 to version 4 and cleaned up the old backups. The whole thing was seamless, I didn't lose anything, and Continue reading

Python – Working With Netmiko

Python - Working With Netmiko

In the last part, we got Netmiko up and running, connected to a device, ran a show command, and printed the output. That is enough to write some genuinely useful scripts, but Netmiko can do a lot more than just run a single command.

In this part, we will look at what else Netmiko has to offer. We will cover how to run multiple commands, push configuration changes, load config from a file, save the running config, and use enable mode when the device requires it. We will also look at how to parse command output into structured data instead of raw text, which is a huge time-saver when you are trying to actually use the output for something.

By the end of the chapter, you will have a much better feel for what Netmiko can do, and you will be ready to start writing scripts that actually make changes to your network instead of just reading from it. For the examples in this chapter, I will be using three real Cisco IOS devices in my lab.

devices = [
    {
        "device_type": "cisco_ios",
        "host": "192.168.202.101",
        "username": "admin",
        "password": "admin"
    },
    {
        "device_type": "cisco_ios",
        "host": "192.168.202. Continue reading

Automating Palo Alto HA Firewall Upgrades with Ansible

Automating Palo Alto HA Firewall Upgrades with Ansible

In this blog post, we will cover upgrading Palo Alto firewalls in HA using Ansible. This only covers upgrading minor versions, so it won't work if you are going from 10.x to 11.x, for example. This also only supports an HA pair.

This playbook is based on the repo from Palo Alto itself. There are many playbooks there covering scenarios like upgrading the major version, upgrading the content, and so on, but we will only focus on one specific playbook for HA, which I tweaked a little bit to suit my own setup.

Manual Upgrade Process

Of course, this post assumes you already know how to upgrade the firewalls manually. In case you don't, here are the steps. Palo Alto also recommends upgrading the active unit first and then the passive. You download the image to the active unit and tick the box to sync it to the peer, then suspend the active unit to trigger a failover so the passive takes over. Install the image on the suspended unit, reboot it, and wait for it to come back online so the HA pair syncs again. Once it is back, suspend the current active unit (the original passive) Continue reading

Automatic SSL with Caddy, Cloudflare and Let’s Encrypt

Automatic SSL with Caddy, Cloudflare and Let's Encrypt

I run a lot of applications and services in my homelab, and they usually look something like http://10.10.10.10:8000, http://10.10.10.11:8006, and so on. It works, but it comes with a few annoyances. Browsers constantly complain you about insecure connections, and remembering which IP and port maps to which service gets old fast.

The ideal setup is something like https://netbox-lab.yourdomain.com - a proper domain name with a valid SSL certificate and no port numbers to remember. In this post, I'll show you how to get there using Caddy, Cloudflare, and Let's Encrypt with very minimal effort.

Overview

To make this work, we need the following.

  • A Cloudflare account with a domain (You don't necessarily need Cloudflare. Other DNS providers should work the same way, but this post uses Cloudflare as the example.)
  • An LXC or VM to run Caddy
  • A Cloudflare API token with DNS edit permissions
  • Let's Encrypt Certificates are automatically managed by Caddy

Cloudflare Setup

I already have a domain that I use in my homelab, so I name my services like app.yourdomain.com. I purchased this domain through Cloudflare and manage it there.

To generate an API Continue reading

Using NetBox as a Dynamic Inventory Source for Nornir

Using NetBox as a Dynamic Inventory Source for Nornir

If you have used Nornir before, you already know that the most common way to define your inventory is through YAML files. You list your hosts, groups, and defaults in separate files, and Nornir reads them at runtime. This works fine for small labs or quick scripts, but as your network grows, maintaining those files by hand becomes a problem. Every time you add a device, change an IP, or update a site, you have to remember to update your inventory files as well. It is easy to get out of sync.

This is where a source of truth tool like NetBox can help. NetBox is an open source network source of truth. It is a place to document your devices, IP addresses, sites, roles and pretty much anything about your network. Instead of maintaining a separate YAML inventory alongside NetBox, you can pull your inventory directly from NetBox at runtime. That way, Nornir always works with up to date data, and you only have to manage one source of truth.

In this post, we will cover how to use NetBox as a dynamic inventory source for Nornir using the nornir_netbox plugin. If you are new to Nornir, we have Continue reading