Programatically Enable NETCONF and MD-CLI on Nokia – SROS Using Netbox API. (Part 2)

CODE: https://github.com/h4ndzdatm0ld/sros-enable-netconf/blob/master/enable-netconf-netboxapi.py

Okay, so you’re still reading? Lets keep digging into the mind of the network team and see how this exercisce is going..  So far, we’ve got a command line tool that we can target one specific node and deploy a script to enable MD-CLI, Yang Models from Nokia and of course, NETCONF. But, how far does this really get us? Really, it’s usefull to test on a handful of nodes and see the behaviour and response to our scripts in a lab environemnt. I’ve tested it on several SROS 19.10R3 A8’s and SR1’s.

It’s time to elaborate on the script and use the tool the Avifi has already deployed and mainted, Netbox. If you haven’t heard of Netbox, google it. In short it’s an IPAM/DCIM and so much more. The customer has requested we do not make any changes to anything in the subnet 10.0.0.0/16, anything else is fair game.  Lucky for us, the IP’s we need have been tagged with ‘7750’, would you believe that?! We’ll use a filter on our API call to extract the IP’s that we need and loop through them doing, but also leaving out anything in the 10xspace. We’ve taken a step back from the command line driven tool model and make a few things a bit more static, by using default arguements from the argparse package.

Before writing any more code, lets pull an API token from the Netbox server.

Here are the instructions: https://netbox.readthedocs.io/en/stable/api/authentication/

We’ll put this token into our application.. not the most secure way of doing this, but for simplicity – we’ll store it in a var in plain text for now. In my opinion, the authorization handled by the netbox administrator should theoretically prevent us from doing anything catastrophic when providing a user with an API token. .. in a perfect world 😉

Lets get to coding! Screen Shot 2020-05-19 at 1.16.50 PM

I thought about passing the argsparsge args into this function and having the ability to pass in an arguement as a ‘tag’ to filter by on the API call, but I didn’t think that was necessary. Although it could be usefull later and a quick and easy modification.

The code above shows nb as the pynetbox authenticated api requests. We then use the application form ‘ipam.ip_addresses‘ and filter by a tag, in which we pass in as an arguement on the function.

The customer requested we skip over any device in the RFC 10 Space, so we create a conditional statement to evaluate the IP’s. Note this is a very broad catch, it should be redefined if this were production as 192, could very much contain ’10.’. I would recommend adding the startswith() function and be more specific. But for now, this works.

 


for x in SR7750:
ip = get_ip_only(x)
if '10' in ip:
print(f'skipping {ip} – We do not want to edit nodes in this subnet.')
elif '192' in ip:
sros_conn = net_connect = ConnectHandler(**router_dict(args,ip,SSH_PASS))
# Establish a list of pre and post check commands.
print('Connecting to device and executing script…')
send_single(sros_conn, 'show system information | match Name')
enabled = sros_conn.send_command('show system netconf | match State')
if 'Enabled' in enabled:
print(f"{ip} already has NETCONF enabled. Moving on..")
disconnect(sros_conn)
time.sleep(2)
print('\n')
try:
netcbackup(ip, NETCONF_USER, NETCONF_PASS)
except Exception as e:
print(f"{e}")
continue

view raw

condiitional ip

hosted with ❤ by GitHub

 

We loop through the IP results in which we got back from the API call and strip the subnet mask using regular expressions. We than pass the IP into our Netconf connection and proceed to get the configuration. Here is a snippet of the RegEX function to strip the /subnet mask from the IP.


def get_ip_only(ipadd):
''' This function will use REGEX to strip the subnet mask from an IP/MASK addy.
'''
try:
ip = re.sub(r'/.+', '', str(ipadd))
return ip
except Exception as e:
print(f"Issue striping subnetmask from {ipadd}, {e}")

view raw

get_ip

hosted with ❤ by GitHub

Finally, I created a function that will establish the initial netcon connection and get.config. We save the netconf element to a file and open it to be able to parse the xml contents, with xmltodict. With this, we extract the system host name and use it as a var to create a folder directory and a file name. We save the running configuration in xml format.


def netcbackup(ip, NETCONF_USER, NETCONF_PASS):
''' This function will establish a netconf connection and pull the running config. It will write a temp file,
read it and convert the XML to a python dictionary. Once parsed, we'll pull the system name of the device
and create a folder structure by hostname and backup the running config.
'''
try:
# Now let's connect to the device via NETCONF and pull the config to validate
nc = netconfconn(ip, NETCONF_USER, NETCONF_PASS)
# Grab the running configuration on our device, as an NCElement.
config = nc.get_config(source='running')
# XML elemnent as a str.
xmlconfig = to_xml(config.xpath('data')[0])
# Write the running configuration to a temp-file (from the data/configure xpath).
saveFile('temp-config.xml', xmlconfig)
# Lets open the XML file, read it, and convert to a python dictionary and extract some info.
with open('temp-config.xml', 'r') as temp:
content = temp.read()
xml = xmltodict.parse(content)
sys_name = xml['data']['configure']['system']['name']
createFolder(f"Configs/{sys_name}")
saveFile(
f"Configs/{sys_name}/{sys_name}.txt", xmlconfig)
except Exception as e:
print(e)

view raw

netconfbackup

hosted with ❤ by GitHub

Leave a comment