Finally the power to Automate Network Device Standardization!!!
In this demo I will actually be starting small, adding SW4 and SW5 to write a script similar to the last lab, only instead of sending config line by line, it will open a file on the NetAuto Host that will contain configs to be written.
This was actually the height of Automation to me in terms of standardizing networks, being able to at very least send out an NTP configuration to all devices, however in this example I will be configuring a couple new “Access Layer” switches with VLANs, a Port-Channel / Trunk, and configuring host interfaces with Portfast / VLAN assignments.
Once I get a feel for how this works on these Access Switches, I will be putting together a best practice template to deploy network wide, and keeping that on hand to propose possibly to production networks to standardize stronger credentials / NTP / Etc.
To before with lets take a look at the new script I will be running shown below
Its actually a very easy script, though again not optimal as creds are clear text:
This of course calls out SW4 and SW5 that are bare bones outside of creds and the MGMT IP to reach them, then it moves onto Line 17 which reads a bit funny to me.
“with open(file) as f:” begins a Loop I have not used yet, which means with this do that, which in this case that is all the configs contained within the file “access_switch_configs”.
Then a Python list is made to defines all_devices as our two Dictionaries above it, and this time instead of loops or sending manual commands, we are sending the variable “lines” which is defined to open and write the contents / commands in the file.
Speaking of the file I just wrote it in notepad as shown below:
vlan 20
name Engineering
vlan 30
name IT Department
int range gi1/0 – 1
switchport trunk encap dot
switchport mode trunk
channel-group 5 mode desirable
int vlan 20
ip add 192.168.20.250 255.255.255.0
no shut
int vlan 30
ip add 192.168.30.250 255.255.255.0
no shut
int range gi0/0 – 3
switchport mode access
switchport access vlan 20
description Engineering
span portfast
no shut
int range gi 3/0 – 3
switchport mode access
switchport access vlan 30
description IT Department
span portfast
no shut
end
wr
I’ve made sure interfaces match on both sides, so this should work for SW4 and SW5
So I will save this config to the NetAutoHost with ‘nano access_switch_configs’ to open a plain text file and paste this into it, then create the above Python script on the host.
With that being said, file and script locked and loaded, lets do this! :
^^ If you cannot read that, its the script immediately crashing and burning 🙂
It seems to hit a snag immediately upon opening the file, so I must have gotten something wrong with the formatting, for those interested the full output of that train wreck can be read below here:
root@NetworkAutomation-1:~# nano access_switch_configs
root@NetworkAutomation-1:~# nano AccessSwitches.py
root@NetworkAutomation-1:~#
root@NetworkAutomation-1:~# python3 AccessSwitches.py
[‘vlan 20’, ‘name Engineering’, ‘vlan 30’, ‘name IT Department’, ‘int range gi1/0 – 1’, ‘switchport trunk encap dot’, ‘switchport mode trunk’, ‘channel-group 5 mode desirable’, ‘int vlan 20’, ‘ip add 192.168.20.250 255.255.255.0’, ‘no shut’, ‘int vlan 30’, ‘ip add 192.168.30.250 255.255.255.0’, ‘no shut’, ‘int range gi0/0 – 3’, ‘switchport mode access’, ‘switchport access vlan 20’, ‘description Engineering’, ‘span portfast’, ‘no shut’, ‘int range gi 3/0 – 3’, ‘switchport mode access’, ‘switchport access vlan 30’, ‘description IT Department’, ‘span portfast’, ‘no shut’, ‘end’, ‘wr’, ”]
Traceback (most recent call last):
File “/usr/local/lib/python3.8/dist-packages/paramiko/channel.py”, line 699, in recv
out = self.in_buffer.read(nbytes, self.timeout)
File “/usr/local/lib/python3.8/dist-packages/paramiko/buffered_pipe.py”, line 164, in read
raise PipeTimeout()
paramiko.buffered_pipe.PipeTimeout
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “/usr/local/lib/python3.8/dist-packages/netmiko/base_connection.py”, line 550, in _read_channel_expect
new_data = self.remote_conn.recv(MAX_BUFFER)
File “/usr/local/lib/python3.8/dist-packages/paramiko/channel.py”, line 701, in recv
raise socket.timeout()
socket.timeout
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File “AccessSwitches.py”, line 25, in <module>
output = net_connect.send_config_set(lines)
File “/usr/local/lib/python3.8/dist-packages/netmiko/base_connection.py”, line 1766, in send_config_set
new_output = self.read_until_pattern(pattern=pattern)
File “/usr/local/lib/python3.8/dist-packages/netmiko/base_connection.py”, line 627, in read_until_pattern
return self._read_channel_expect(*args, **kwargs)
File “/usr/local/lib/python3.8/dist-packages/netmiko/base_connection.py”, line 560, in _read_channel_expect
raise NetmikoTimeoutException(
netmiko.ssh_exception.NetmikoTimeoutException: Timed-out reading channel, data not available.
root@NetworkAutomation-1:~#
I bet I know what happened in this instance actually in looking at examples
It seems like the file being read by Python should have a similar format with indentation and all to a running config output, so let try this again here:
I wrote it up quick in VSC to ensure proper spacing and indentation, the copy / pasted back onto the NetAuto Host with the same Python Script, so we should be good to go.
Now lets see some magic light up my Access Layer Switches via Netmiko!
Drats!!! Another crash and burn, although I think I did need that formatting change, but something is not correct with my script here that is being executed.
Then again when looking at my script, I thought back to the basics of network troubleshooting, and tried to ping SW4 from NetAuto Host:
I am so glad my head is attached to my shoulders some day, I cannot believe I did not test basic connectivity before I started troubleshooting the friggin scripts! (Though I do still believe I needed proper running-config formatting either way).
Tried it again, crashed and burned again, though I have a new theory – Naming!
I was sketchy about this line here and having any kind of references directly to anything like switches / netmiko / etc (as I said not to do in a previous post) may conflict with something, and some of the errors do indicate with the file name “access_switch_configs” so I have changed it to the following:
AccessSwitches.py for the script and access_switch_configs for the file, I’m not sure what I was thinking, however both are now changed to the following on my net host:
It did still spit out weird text at first from the file, then actually worked this time!
Kapow!!!!
I saw that begin to happen and almost ctrl+c to stop the script, but figured I’d let it run to review line errors, and suddenly it just ran on SW4 and SW5, though I did apparently need an ‘end’ in there to get it to ‘wr mem’ at the end but I will take it!
Verification on SW4:
The initial lines is the Automation happening, and then I configure the Port-Channel 5 is Up/Up with Gi0/0 and G1/1 bundled into it, and life is good!
Over on SW5:
This just makes me feel so accomplished getting these to run, despite that odd beginning output, the Automation did work! And to verify on PC1:
SVI’s are working, Port-Channel is up, that is how it is done right there! 🙂
I will halt the lab here for tonight while I am ahead, as that was getting hairy!
I honestly was beginning to doubt I was going to get that to work, however the key was allowing the script to fail, and reading the error output for which lines were causing the issues, as it did lead me to eventually correcting the script so that it worked (despite it not being entirely pretty it did in fact work!) 😀
Until next time!
thanks for sharing. can you help with a similar script that is supposed to open 3 files, one for each switch and write the commands from the files to the 3 switches in turn?
LikeLiked by 1 person
Sure even this example would work the same with 3 different file just using the “with open(‘filename.txt’) as f:” to open file / extract info / close file, so you could really just repeat that 3 times for each file name.
Could you elaborate on what your trying to accomplish, you could probably just create 3 identical scripts that run each other at the end with the other file names in that Open with statement if nothing else 🙂
Lemme know, I have been all over Python, so I would be interested to figure it out!
LikeLike