As of yet, we haven’t done anything about the actual configuration of the device. Before we can apply the desired configuration we need some kind of input data. Lots of things could potentially be used for this including:
Currently, I don’t know any of this. I’ve just connected a switch to a port in my home network. Of course, I in the role of the installer knows where I connected the new device, but the ZTP server doesn’t. In this chapter, we will try to connect to the device after it has been provisioned and find out some information about it.
Even if you have the above information it is nice to be able to connect to the device after it has been booted up to validate that everything is working as it should.
An empty Cisco IOS device won’t allow incoming connections by default. This means that we need to add this configuration to the file being downloaded from the TFTP server. Open up the network-confg file on the server and add the needed lines.
hostname staging
ip domain-name networklore.com
lldp run
aaa new-model
aaa authentication login LOCALDB local
aaa authorization exec LOCALDB-AUTHZ local
username staging priv 15 secret DeploymentK3y
line vty 0 4
authorization exec LOCALDB-AUTHZ
login authentication LOCALDB
crypto key generate rsa general-keys modulus 2048
end
This configuration will only be used so that we can reach the device, we also enable LLDP so that we can see connected neighbors.
The next step is to connect to the device being provisioned and gather information. At this stage it’s really up to you how you want to solve this. Within this tutorial I’m going to add Napalm to the TFTP server, you are however free to just see this a s placeholder. This could just as well be that you trigger an Ansible playbook, call an API in Salt or fire of a trigger with Stackstorm.
Before we can use Napalm we need to add it to the Virtualenv.
pip install napalm
Add the file /opt/ztp/app/network.py
import time
from napalm import get_network_driver
def get_napalm_connection(host, device_type, attempts=360, timeout=1):
driver = get_network_driver(device_type)
device = driver(hostname=host, username='staging',
password='DeploymentK3y')
for _ in range(attempts):
try:
device.open()
return device
except:
time.sleep(timeout)
return False
We will try to establish a connection to the device immediately after it has downloaded the file from the TFTP server. As it takes a while to apply the initial configuration and generate an ssh key we will have to try this connection multiple times. By default this function will try to connect 360 times and wait 1 second between each attempt. If it isn’t successful after that time it will fail.
Next we modify the /opt/ztp/app/tasks.py file.
from app.network import get_napalm_connection
from app.notifications import notify_slack
def ztp_start(host, file):
msg = '{} downloaded {}'.format(host, file)
notify_slack(msg)
dev = get_napalm_connection(host, 'ios')
if dev:
notify_slack('{} connection established'.format(host))
else:
notify_slack('{} connection failed, giving up'.format(host))
return
facts = dev.get_facts()
notify_slack('{}: {}/{}'.format(host, facts['model'],
facts['serial_number']))
lldp = dev.get_lldp_neighbors()
for interface in lldp:
for neighbor in lldp[interface]:
notify_slack('{}:{} -> {}: {}'.format(
host, interface, neighbor['hostname'],
neighbor['port']))
dev.close()
With this code, the person who is installing the device will be able to get a notification when the new device first downloads a file and also if the system isn’t able to connect to the device after that. A failed connection could mean that there’s some error with the cabling, or that the wrong device is used and troubleshooting can start.
It the connection is successful we collect information and present it to the installer.
The information presented to the installer at this point is probably most relevant when something is incorrect. Currently, we can see that the new device is connected to the Fa0/7 interface in the upstream switch. A good check would be to validate that this is, in fact, correct according to your inventory, we could let the installer know that something is wrong. We were expecting a WS-C2960C-8TC-L to be connected to this port. Since we haven’t saved the configuration yet the installer can just pull the plug and try again.
As we have control of all the things that can happen within our code we can collect pretty much anything we want. From here we could hand the device over to a Napalm script which does a config replace.