on 01-23-2024 07:52 AM
Note:
This article is about a script designed to be executable across all switches that offer SSH support, generally devices introduced from the year 2010 and onward. It is specifically tailored for Cisco devices operating:
-IOS,
-IOS-XE,
-IOS-XR,
-NX-OS,
-and SG300.
The script proves particularly valuable in scenarios where switches lack compatibility with Cisco DNA (Example 2960 or SG300), serving as an effective alternative for streamlined and efficient management. My tests are built on IOS and IOS-XE devices.
Prerequisites:
Before you proceed with learning about using Netmiko for VLAN automation on Cisco devices, it's essential to have a foundational understanding of the following:
-Basic Networking Concepts
-Cisco Device Configuration
-Python Programming Basics
-SSH Access to Cisco Devices
Automating VLAN Creation on Cisco devices: Streamlining Network Management with Python and Netmiko
In the dynamic world of networking, managing VLANs (Virtual Local Area Networks) on many devices can be a time-consuming and error-prone task. Manually configuring VLANs on multiple Cisco devices can quickly become tedious and inefficient. Fortunately, automation can significantly alleviate this burden, saving you time and effort while enhancing the overall efficiency of your network management operations.
Why do we sometimes need to automate the VLAN creation process?
The VLAN creation process on a Cisco switch is easy and straightforward, we only need to use some commands to get it done:
Switch(config)# vlan 150 (press enter)
Switch(config-vlan)# name Main-VLAN (press enter)
And then if we are using a trunk port with a limited number of VLANs, we need to add our new created VLAN to that Trunk port.
That process is easy and needs no more than a few seconds to be done, but what if we have many switches that need to have the same VLAN in our network?! Then we need a way to automate this process and get it done as fast as possible
What is Netmiko anyway?
Netmiko https://pynet.twb-tech.com/blog/netmiko-python-library.html is an open-source Python library that allows you to interact with networking devices using SSH. It provides a high-level interface for configuring and managing network devices, making it easier to automate network tasks.
Here are some of the key features of Netmiko:
Setting Up the Environment:
-Install Ubuntu (bare metal or VM) or have it installed on your Windows machine (Windows Subsystem for Linux WSL)
To set up Ubuntu on Windows Subsystem for Linux (WSL), follow these steps:
wsl --install
Restart-Computer
sudo apt update
sudo apt upgrade
-On Ubuntu we need to install Python, Netmiko and Paramiko using these commands:
sudo apt install python3
sudo apt install python3-pip
pip3 install Netmiko
pip3 install paramiko
What is Paramiko anyway?
Paramiko and Netmiko are both Python libraries used for network automation and managing network devices. to use Netmiko, you need to have Paramiko installed. Netmiko is built on top of Paramiko and relies on its SSH implementation for establishing connections and executing commands on network devices. You can choose to import Paramiko to your script or not if you are using Netmiko, because Netmiko already imports Paramiko internally.
Sudo apt update:
in Ubuntu “sudo apt update” is used to update the package lists for repositories configured on your system. It's important to run "sudo apt update" periodically to keep your package lists up to date. After running this command, you can use "sudo apt upgrade" to upgrade the installed packages to their latest versions, if any updates are available.
Sudo apt install python3:
This command installs Python 3 and its related packages on your Ubuntu system. Once installed, you'll have access to the Python 3 interpreter and the necessary tools to develop and run Python programs.
Sudo apt install python3 pip:
python3-pip installs pip for Python 3. Pip is a package manager used to install and manage Python packages from the Python Package Index (PyPI).
Running a Netmiko script:
To run a netmiko script, you will need two files: one file with a .py extension and another file with a .json extension. The .py file is the main script that contains the logic and the commands to be executed on the network devices. The .json file is a file that contains only a list of IP addresses of the network devices, as a Python dictionary. The credentials of the network devices, such as username, password, and secret, will be collected by asking the user to enter them interactively.
The advantage of using a .json file for the IP addresses is that it allows you to store the device information in a structured and readable format, and it also enables you to use a loop or a file to control multiple devices at once. You can also use different .json files for different groups of devices or different environments, such as production, testing, or development.
Creating the .py and .json files in Ubuntu:
To create these files we use Nano, which is a lightweight and user-friendly command-line text editor that allows you to create and modify text files directly from the terminal.
To create the .py file run this command in Ubuntu:
nano create-vlan.py
(inside create-vlan.py paste the script text that you take from this article)
Press Ctrl+O to save, and then press Ctrl+X to exit
Your .py file should look something like this:
To create the .json file run this command in Ubuntu:
nano devices.json
Your .json file should look something like this:
Notice!!
• Use your switches IP addresses!
• You can add as many switches (IP addresses) as you like, only be careful with the last one it does not need to have a comma!!
With that been said, let’s look at the script:
Our script will first prompt for the administrator username, the administrative password and then the Enable password of the device. Then, it will display two new prompts, one about the desired VLAN ID and the other about the desired VLAN-name that we want to create or check. If the VLAN already exists, the script will verify that it is properly configured on the relevant trunk ports, which are configured with the "switchport trunk allowed vlan add" command. If the VLAN does not exist, the script will create it and then configure it on the appropriate trunk ports.
Here is the script:
# Import the netmiko library for network automation
from netmiko import ConnectHandler
# Import the getpass library for getting user input securely
from getpass import getpass
# Import the json library for parsing JSON files
import json
# Import the os library for interacting with the operating system
import os
# Import the re library for regular expressions
import re
# Import the paramiko library for SSH connections
import paramiko
# Prompt the user to enter their username, password, and enable password
username = getpass ('Enter Your UserName:')
password = getpass('Enter Your Password:')
secret = getpass('Enter Your Enable Password:')
# Prompt the user to enter the VLAN ID and name that they want to check or create
which_vlan = input("wich VLAN do you want to check?: ")
vlan_name = input("vlan name?: ")
# Get the current working directory
working_dir = os.getcwd()
# Try to open and read the switches.json file that contains the IP addresses of the switches
try:
with open(working_dir + '/switches.json', 'r') as json_file:
ip_list = json.load(json_file)
# If the file is not found, print an error message
except:
print('No ip list found')
# Loop through the IP addresses in the ip_list dictionary
for ip in ip_list.values():
# Create a device dictionary with the device type, IP address, username, password, and secret
device = {
'device_type': 'cisco_ios',
'ip': ip,
'username': username,
'password': password,
'secret': secret
}
# Establish a connection to the device using netmiko
net_connect = ConnectHandler(**device)
# Enter the enable mode
net_connect.enable()
# Send the command 'show run | include hostname' and parse the output using textfsm
show_run_hostname = net_connect.send_command('show run | include hostname', use_textfsm=True)
# Use a regular expression to extract the hostname from the output
match = re.search(r'^hostname\s+([^\n]*)', show_run_hostname, re.IGNORECASE)
# Assign the hostname to a variable, or "N/A" if not found
hostname = match.group(1) if match else "N/A"
# Print 60 asterisks in green color
print('\033[32m' + '*'*60 + '\033[0m')
# Print another 60 asterisks in green color
print('\033[32m' + '*'*60 + '\033[0m')
# Print the IP address and the hostname of the device
print(f'Connecting to {ip} {hostname}')
# Enter the enable mode again
net_connect.enable()
# Send the command 'show vlan b' and parse the output using textfsm
show_vlan_command = net_connect.send_command('show vlan b', use_textfsm=True)
# Initialize a flag variable to indicate if the VLAN is already configured
vlan_already_there = False
# Loop through the output of the show vlan command
for i in show_vlan_command:
# If the VLAN ID matches the user input, print a message and set the flag to True
if i['vlan_id'] == which_vlan:
print('The VLAN is already configured')
vlan_already_there = True
# If the VLAN is not already configured, create a new VLAN with the user input
if not vlan_already_there:
# Create a list of commands to create the VLAN and assign a name
create_new_vlan = [ f'vlan {which_vlan}', f'name {vlan_name}' ]
# Send the commands to the device using netmiko
create_vlan = net_connect.send_config_set(create_new_vlan)
# Send the command 'show vlan b | include <VLAN ID>' and parse the output using textfsm
show_vlan_command = net_connect.send_command(f'show vlan b | include {which_vlan}', use_textfsm=True)
# Print the output of the show vlan command
print(show_vlan_command)
# Send the command 'show interfaces status' and parse the output using textfsm
show_interface_command = net_connect.send_command('show interfaces status', use_textfsm=True)
# Initialize an empty list to store the trunk interfaces
result = []
# Loop through the output of the show interfaces command
for d in show_interface_command:
# If the VLAN is trunk, append the interface to the result list
if d['vlan']=='trunk':
result.append(d)
# Initialize a counter variable
y = 0
# Loop through the result list
while y < len(result):
# Assign the port name to a variable
a = result[y]['port']
# Print the port name and indicate that it is a trunk interface
print(f'{a} interface is a trunk')
# Create a list of commands to add the new VLAN to the trunk interface
add_new_vlan_to_trunk = [
(f'interface {a}'),
(f'switchport trunk allowed vlan add {which_vlan}'),
]
# Send the command 'show run interface <port> | in allowed' and parse the output using textfsm
show_run_command = net_connect.send_command(f'show run interface {a} | in allowed', use_textfsm=True)
# Initialize a flag variable to indicate if the trunk is allowed
trunk_is_allowed = 0
# If the output is empty, print a message and set the flag to 1
if show_run_command == "":
print("trunk is: switch port trunk")
trunk_is_allowed = 1
# Initialize a flag variable to indicate if the VLAN is in the trunk
vlan_in_trunk = False
# If the output is not empty and contains the VLAN ID, print a message and set the flag to True
if show_run_command != "" and (f'{which_vlan}') in show_run_command:
vlan_in_trunk = True
print(f'For VLAN {which_vlan}, the configuration is already present on the trunk interface {a}')
# If the VLAN is not in the trunk and the trunk is not allowed, send the commands to add the VLAN to the trunk
if not vlan_in_trunk and trunk_is_allowed < 1:
add_vlan_to_trunk = net_connect.send_config_set(add_new_vlan_to_trunk)
print(f'new vlan {which_vlan} has been allowed on trunk interface {a}')
# Increment the counter variable
y += 1
Notice!
Lines start with # are comments that you can ignore.
Testing and Verification:
In this example I will create VLAN 113 and name it Test113:
To run the script, we use this command on Ubuntu:
Python3 create-vlan.py
I got 3 switches to test my script on, only the last switch with IP address 172.22.1.130 has a trunk port configured with a limited number of VLANs on it.
Trunk is: switch port trunk means that the trunk interface on that switch is configured using the command switchport mode trunk.
New vlan 113 has been allowed on trunk interface Gi0/2 means that the interface Gi0/2 on that switch is a trunk interface configured with the command switchport trunk allowed vlan add command.
113 Test113 active means that the VLAN 113 is created and is active.
So, what happens if we run the script again trying to create the same VLAN-ID 113?
The VLAN is already configured means that the VLAN 113 is already created on the switch.
For VLAN 113, the configuration is already present on the trunk interface Gi0/2 means that the VLAN 113 is already added to that trunk interface.
Conclusion:
In this article, I have shown how to use Python and Netmiko to automate the VLAN creation process on Cisco devices. By using these Python modules, I can easily connect to multiple switches, check if the VLAN already exists, create a new VLAN if needed, and add it to the trunk interfaces. This saves me time and effort, and ensures consistency and accuracy across my network. I hope this article has been helpful for network administrators who want to use automation to make their life easier. Of course, this script is not perfect and can be improved in many ways. I welcome any feedback or suggestions from the readers. I am not a programmer, but a network administrator who loves to learn new things and share them with others.
• Python Official Documentation
• Netmiko GitHub Repository
https://github.com/ktbyers/netmiko
• Youtube
https://www.youtube.com/watch?v=5dahqpYiH4g
https://www.youtube.com/watch?v=R7-2DAsPIbE
https://www.youtube.com/watch?v=NSnrvVhbuy8&t=3s
• Stack Overflow - Netmiko
https://stackoverflow.com/questions/tagged/netmiko
• Network Automation using Python 3: An Administrator's Handbook
Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: