Python Network Programming
上QQ阅读APP看书,第一时间看更新

Step 2 – Create the backend Python code

Now, let's see the back end Python code (checks.py) that will accept these inputs from HTML form and perform its task. The code is as follows:

#!/usr/bin/env python
import cgi
import paramiko
import time
import re
import sys
import os
import requests
import urllib
import datetime
from datetime import datetime
from threading import Thread
from random import randrange

form = cgi.FieldStorage()
searchterm = form.getvalue('searchbox')
cmds = form.getvalue('cmds')
changeid = form.getvalue('changeid')
prepost=form.getvalue('prepost')
searchterm=searchterm.split(",")
xval=""
xval=datetime.now().strftime("%Y-%m-%d_%H_%M_%S")

returns = {}
def getoutput(devip,cmd):
try:
output=""
mpath="C:/iistest/logs/"
fname=changeid+"_"+devip+"_"+prepost+"_"+xval+".txt"
fopen=open(mpath+fname,"w")
remote_conn_pre = paramiko.SSHClient()
remote_conn_pre.set_missing_host_key_policy(paramiko.AutoAddPolicy())
remote_conn_pre.connect(devip, username='cisco', password='cisco', look_for_keys=False, allow_agent=False)
remote_conn = remote_conn_pre.invoke_shell()
remote_conn.settimeout(60)
command=cmd
remote_conn.send(command+"\n")
time.sleep(15)
output=(remote_conn.recv(250000)).decode()
fopen.write(output)
remote_conn.close()
fopen.close()
returns[devip]=("Success: <a href='http://localhost/test/logs/"+fname+"' target='_blank'>"+fname +"</a> Created")
except:
returns[devip]="Error. Unable to fetch details"

try:
xtmp=""
cmdval="terminal length 0\n"
if (str(cmds).count("show") > 1):
for cmdvalue in cmds:
if ("show" in cmdvalue):
if ("show log" in cmdvalue):
cmdvalue="terminal shell\nshow log | tail 100"
cmdval=cmdval+cmdvalue+"\n\n"
else:
if ("show" in cmds):
if ("show log" in cmds):
cmds="terminal shell\nshow log | tail 100"
cmdval=cmdval+cmds+"\n\n"
threads_imagex= []
for devip in searchterm:
devip=devip.strip()
t = Thread(target=getoutput, args=(devip,cmdval,))
t.start()
time.sleep(randrange(1,2,1)/20)
threads_imagex.append(t)

for t in threads_imagex:
t.join()

print("Content-type: text/html")
print()
xval=""
for key in returns:
print ("<b>"+key+"</b>:"+returns[key]+"<br>")

print ("<br>Next step: <a href='http://localhost/test/selectfiles.aspx'> Click here to compare files </a>")
print ("<br>Next step: <a href='http://localhost/test/prepostcheck.html'> Click here to perform pre/post check </a>")

except:
print("Content-type: text/html")
print()
print("Error fetching details. Need manual validation")
print ("<br>Next step: <a href='http://localhost/test/selectfiles.aspx'> Click here to compare files </a>")
print ("<br>Next step: <a href='http://localhost/test/prepostcheck.html'> Click here to perform pre/post check </a>")

This code accepts input from a web page using the CGI parameter. Various values from the web page are parsed into the variables using the following code snippet:

form = cgi.FieldStorage()
searchterm = form.getvalue('searchbox')
cmds = form.getvalue('cmds')
changeid = form.getvalue('changeid')
prepost=form.getvalue('prepost')

Once we have these values, the additional logic is to log in into the given device(s) using the paramiko library, fetch the output of the show commands, and save it in a file under the logs folder with the output. An important aspect to note here is the way we are constructing the filename:

#xval=datetime.now().strftime("%Y-%m-%d_%H_%M_%S")
#and
#fname=changeid+"_"+devip+"_"+prepost+"_"+xval+".txt"

The fname is the filename into which we would write the output, but the filename is built dynamically with the inputs provided by the maintenance ID, device IP, pre/post status, and the time the file was created. This is to ensure that we know the device for which we are performing a pre or a post check, and at what time the file was created, to ensure we have a correct pre and post check combination.

The function getoutput() is invoked from a thread (in a multi-threaded function call) to fetch the output and store it in the newly created file. A multi-threading process is called, because if we want to perform pre or post checks in multiple devices, we can provide a comma separated IP address list in web, and Python script will in parallel invoke the show commands on all devices and create multiple pre or post check files, based on hostnames.

Let's create a precheck file for some commands in our example, where we fill in some values and click on the Submit button:

While the gathering of data is in progress, the yellow message will be displayed to confirm that the back end work is going on.

Once the task is completed, this is what we see (as returned from the Python code):

As we see, the code returns a success, which means that it was able to fetch the output of the commands that we want to validate. The filename is dynamically created, based on our selection on the main page.

A click on the .txt filename that is generated as a clickable URL (which can be used to reconfirm if we got the correct output of commands we selected earlier), shows the following output:

Now, let's perform the same steps and create a postcheck file. 

We go back to the main page, and keeping the other values the same, we just select the radio button to Postcheck instead of Precheck. Do ensure that we select the same set of commands, since a pre and post check only make sense if we have the same data to work with:

In a similar way, once the backend execution completes, we have a postcheck file created as follows:

Notice the filename, the timestamp, and the post word changes based on our selection.