A use case I was presented recently was how multiple switches can be upgraded via automation tooling.
Prerequesits
As with any automation, standardisation is key. For this to work the switches should be close to the same model, the ports should be configured the same way, and the configuration running should be the same.
This will configure the interface GigabitEthernet0/5 in trunk mode for VLANs 200-220, and 250
Terraform Code
Project Structure
terraform/
├── main.tf
├── variables.tf
├── terraform.tfvars
main.tf
– Main Terraform Config
terraform {
required_providers {
ios = {
source = "netascode/ios"
version = ">= 0.5.0"
}
}
}
provider "ios" {
for_each = toset(var.switches)
host = each.value
username = var.username
password = var.password
}
resource "ios_vlan" "vlan_config" {
for_each = {
for switch in var.switches : switch => switch
}
vlan_id = flatten([
for vlan in concat(range(200, 221), [250]) : [
{
id = vlan
name = "VLAN_${vlan}"
}
]
])
provider = ios[each.key]
}
resource "ios_interface_trunk" "port_config" {
for_each = {
for switch in var.switches : switch => switch
}
name = var.trunk_port
trunk_encapsulation = "dot1q"
trunk_allowed_vlans = join(",", concat([1], range(200, 221), [250]))
trunk_native_vlan = 1
provider = ios[each.key]
}
variables.tf
– Variables and Descriptions
variable "switches" {
description = "List of switch IPs"
type = list(string)
}
variable "username" {
description = "SSH username"
type = string
sensitive = true
}
variable "password" {
description = "SSH password"
type = string
sensitive = true
}
variable "trunk_port" {
description = "Trunk interface name"
type = string
default = "GigabitEthernet0/5"
}
terraform.tfvars
– Your Inputs
switches = [
"192.168.1.101",
"192.168.1.102",
"192.168.1.103",
"192.168.1.104",
"192.168.1.105"
]
username = "admin"
password = "password"
How to Use It
cd terraform
terraform init
terraform plan
terraform apply
Python code
Whenever I google automation and Cisco switches it comes up that Python is the desired language.
Requirements:
- Python 3.x
netmiko
installed (pip install netmiko
)- IPs/user/pass of the 5 switches
from netmiko import ConnectHandler
# List of switches with credentials
switches = [
{'device_type': 'cisco_ios', 'host': '192.168.1.101', 'username': 'admin', 'password': 'password'},
{'device_type': 'cisco_ios', 'host': '192.168.1.102', 'username': 'admin', 'password': 'password'},
{'device_type': 'cisco_ios', 'host': '192.168.1.103', 'username': 'admin', 'password': 'password'},
{'device_type': 'cisco_ios', 'host': '192.168.1.104', 'username': 'admin', 'password': 'password'},
{'device_type': 'cisco_ios', 'host': '192.168.1.105', 'username': 'admin', 'password': 'password'}
]
# VLANs to add
vlans = list(range(200, 221)) + [250]
# Trunk port to modify
trunk_port = "GigabitEthernet0/5"
# Generate configuration commands
vlan_commands = [f"vlan {vlan}" for vlan in vlans]
trunk_command = f"interface {trunk_port}\nswitchport trunk allowed vlan add {','.join(map(str, vlans))}"
# Full config block
config_commands = vlan_commands + [f"interface {trunk_port}",
f"switchport trunk allowed vlan add {','.join(map(str, vlans))}"]
# Process each switch
for switch in switches:
print(f"Connecting to {switch['host']}...")
try:
connection = ConnectHandler(**switch)
output = connection.send_config_set(config_commands)
print(f"Configuration applied to {switch['host']}:\n{output}")
connection.save_config()
connection.disconnect()
except Exception as e:
print(f"Error with {switch['host']}: {e}")
Ansible Code
What about writing this in Ansible
Requirements
Make sure you install the Cisco Ansible Collection:
ansible-galaxy collection install cisco.ios
File Structure
.
├── inventory.yml
└── update_vlans.yml
inventory.yml
– Your Inventory of Cisco Switches
all:
hosts:
switch1:
ansible_host: 192.168.1.101
switch2:
ansible_host: 192.168.1.102
switch3:
ansible_host: 192.168.1.103
switch4:
ansible_host: 192.168.1.104
switch5:
ansible_host: 192.168.1.105
vars:
ansible_user: admin
ansible_password: password
ansible_network_os: cisco.ios.ios
ansible_connection: network_cli
update_vlans.yml
– The Ansible Playbook
---
- name: Update trunk port and VLANs on Cisco switches
hosts: all
gather_facts: no
tasks:
- name: Create VLANs 200-220 and 250
cisco.ios.ios_vlan:
vlan_id: "{{ item }}"
name: "VLAN_{{ item }}"
state: present
loop: "{{ range(200, 221) | list + [250] }}"
- name: Add VLANs to trunk port GigabitEthernet0/5
cisco.ios.ios_config:
lines:
- "switchport trunk allowed vlan add {{ vlan_list | join(',') }}"
parents: "interface GigabitEthernet0/5"
vars:
vlan_list: "{{ range(200, 221) | list + [250] }}"
Run the Playbook
ansible-playbook -i inventory.yml update_vlans.yml