Imagine you are the administrator of three computer labs. Some of the machines have had their versions of Java and Python updated, but you're not sure how many, or which ones. You could go to each computer individually and check.
But you're not going to do that.
By building a Python script to connect to your machines and check version levels, you can automatically build a list of the version of installed applications on each computer.
The version management system in this chapter shows how you can use Telnet to retrieve version information for a list of applications (in this program, the applications checked will be Java, Python, and Perl). The program will then write the results of the check to a CSV log file.
The application will perform the following functions:
Before the program is run, any remote computers to be connected to from the application must be set up.
The computers connected to in this application were Linux machines, but the application could easily be adapted to also connect to Windows machines.
Remote computers need to have the following features enabled:
You can get to the program by navigating to the directory corresponding to this chapter. Once again, the files are available for download from the website (www.wrox.com
). To run the application, simply go to a command prompt, and from the directory on your system where the Chapter 7 program files are located, type the following:
python version_checker.py <ip address> <applications>
The command-line options are as follows:
<ip address> — Enter the IP address to connect to.
<applications> — Enter the applications, enclosed in quotes. The applications can be selected from the following:
If the following is typed at the command line, the script will connect to IP address 192.168.1.108 and check the versions of Java, Python, and Perl:
python version_checker.py 192.168.1.108 "java python perl"
The result will look something like this:
I:Applied_PythonChapter_7>python version_checker.py 192.168.1.108 "java python perl" HOST - 192.168.1.108 Java version = 1.6.0_0 Python version = 2.5.1 Perl version = 5.8.8
If the following is typed at the command line, the script will connect to IP address 192.168.1.108 and check the versions of Java and Perl:
python version_checker.py 192.168.1.108 "java perl"
The result will look something like this:
I:Applied_PythonChapter_7>python version_checker.py 192.168.1.108 "java perl" HOST - 192.168.1.108 Java version = 1.6.0_0 Perl version = 5.8.8
If the following is typed at the command line, the script will connect to IP address 192.168.1.108 and check the versions of Perl and Python:
python version_checker.py 192.168.1.108 "perl python"
Notice that the order of the applications listed does not matter. The result will look something like this:
I:Applied_PythonChapter_7>python version_checker.py 192.168.1.108 "perl python" HOST - 192.168.1.108 Python version = 2.5.1 Perl version = 5.8.8
If the following is typed at the command line, the script will connect to IP address 192.168.1.108 and check the version of Perl:
python version_checker.py 192.168.1.108 "perl"
The result will look something like this:
I:Applied_PythonChapter_7>python version_checker.py 192.168.1.108 " perl" HOST - 192.168.1.108 Perl version = 5.8.8
If you don't enter all the options, a message like the following one will be displayed:
I:Applied_PythonChapter_7>python version_checker.py 192.168.1.108 Insufficient arguments: suggested use - python version_checker.py <ip address> "<applications to check>" NOTES: 1. Replace <ip address> with the ip address you want to check. 2. Replace <applications to check> with any combination of the following applications (in quotes): java python perl EXAMPLE: python version_checker.py 1.1.1.1 "python java" This command will check the versions of Python and Java on computer with ip address 1.1.1.1.
After you have run a few reports, you can view the CSV log of the version checks. If you open the CSV file in a spreadsheet program, it will look something like what is shown in Figure 7-1.
To run the script against several different machines in batch mode, you could simply create a shell script (or batch file, if on Windows) that runs the script against several different machines, as in the following example:
python version_checker.py 192.168.1.108 "java python perl" python version_checker.py 192.168.1.109 "java perl" python version_checker.py 192.168.1.110 "java python perl" python version_checker.py 192.168.1.111 "python perl" python version_checker.py 192.168.1.112 "python" python version_checker.py 192.168.1.113 "perl python" python version_checker.py 192.168.1.114 "java" python version_checker.py 192.168.1.115 "perl" python version_checker.py 192.168.1.116 "java python perl" python version_checker.py 192.168.1.117 "java perl" python version_checker.py 192.168.1.118 "python perl" python version_checker.py 192.168.1.119 "perl" python version_checker.py 192.168.1.120 "java python perl" python version_checker.py 192.168.1.121 "java perl" python version_checker.py 192.168.1.122 "python" python version_checker.py 192.168.1.123 "java python perl"
This is the first application that doesn't have any kind of a "driveable" user interface — it uses the command line to pass options to the script. This enables a script to be more easily implemented in another script or batch file, which is why it was handled this way in this case.
There are three modules in this application:
version_checker.py
is the main program. It receives the command-line option, prints error messages, and calls functions in other modules to do the checking and output to the CSV file.
check_versions.py
logs in to the remote machine and returns the version of the particular application being checked.
csv_report.py
takes a version check result and writes it to the CSV log file.
version_checker.py
is the main program. It calls the functions to run checks and output the results to a CSV. It also displays output to the screen. Table 7-1 shows the version_checker
module functions.
check_versions.py
is called by version_checker.py
and checks versions of the respective applications being checked. Table 7-2 shows the check_versions
module functions.
Table 7.2. Table 7-2
Function | Return Type | Description |
---|---|---|
| string | Takes hostname, username, and password as arguments, connects to the host, checks the version of Java, and returns that version to the caller |
| string | Takes hostname, username, and password as arguments, connects to the host, checks the version of Python, and returns that version to the caller |
| string | Takes hostname, username, and password as arguments, connects to the host, checks the version of Perl, and returns that version to the caller |
csv_report.py
takes the results of a version check and outputs the results to the CSV report log. Table 7-3 shows the csv_report
module function.
Essentially, this application takes parameters at the command line, logs in (through Telnet) to a remote computer, checks the version of an identified application, and reports the result to the screen and to a CSV log file.
In the interests of page space, I've omitted the code headers, but make sure you use them. Your coworkers will thank you.
The version_checker
module is the program users actually run on the command line. It contains code that's run at the module level, and two functions:
import sys import check_versions, csv_report HOST = sys.argv[1] USER = "jars" PASSWORD = "jars" def check_arguments(): if (len(sys.argv)) < 3: print """ Insufficient arguments: suggested use - python version_checker.py <ip address> "<applications to check>" NOTES: 1. Replace <ip address> with the ip address you want to check. 2. Replace <applications to check> with any combination of the following applications (in quotes): java python perl EXAMPLE: python version_checker.py 1.1.1.1 "python java" This command will check the versions of Python and Java on computer with ip address 1.1.1.1.""" sys.exit() def get_versions(): print "HOST - ", HOST if "java" in sys.argv[2]: java_version = check_versions.check_java(HOST, USER, PASSWORD) csv_report.write_csv_log(HOST, "Java", java_version) print "Java version = ", java_version if "python" in sys.argv[2]: python_version = check_versions.check_python(HOST, USER, PASSWORD) csv_report.write_csv_log(HOST, "Python", python_version) print "Python version = ", python_version if "perl" in sys.argv[2]: perl_version = check_versions.check_perl(HOST, USER, PASSWORD) csv_report.write_csv_log(HOST, "Perl", perl_version) print "Perl version = ", perl_version check_arguments() get_versions()
The main program starts off by importing the modules it needs:
import sys import check_versions, csv_report
Then variables are initialized for the host, user, and password:
HOST = sys.argv[1] USER = "jars" PASSWORD = "jars"
Note two things about the preceding code:
Down at the bottom of the module (after the function definitions), the program runs the functions to check both the arguments and the versions:
check_arguments() get_versions()
check_arguments()
checks the command-line arguments entered at the command line to ensure that the correct number of arguments appears. If not, it generates an error and exits:
def check_arguments(): if len(sys.argv) < 3: print """ Insufficient arguments: suggested use - python version_checker.py <ip address> "<applications to check>" NOTES: 1. Replace <ip address> with the ip address you want to check. 2. Replace <applications to check> with any combination of the following applications (in quotes): java python perl EXAMPLE:
python version_checker.py 1.1.1.1 "python java" This command will check the versions of Python and Java on computer with ip address 1.1.1.1.""" sys.exit()
The function initially determines whether two arguments appear (the first argument is the Python script name, so there should be three elements in sys.argv
):
if len(sys.argv) < 3:
If there are fewer than two command-line arguments, it prints an error/help message:
print """ Insufficient arguments: suggested use - python version_checker.py <ip address> "<applications to check>" NOTES: 1. Replace <ip address> with the ip address you want to check. 2. Replace <applications to check> with any combination of the following applications (in quotes): java python perl EXAMPLE: python version_checker.py 1.1.1.1 "python java" This command will check the versions of Python and Java on computer with ip address 1.1.1.1."""
The last line of the if
loop (and the function) is a command to exit:
sys.exit(1)
Notice that you exit with a 1. Non-zero exit codes are for situations in which something has gone wrong, so if you exit the program in an error condition, it makes sense to pass a 1.
The get_versions()
function launches the various functions to check the application version, based on what the user entered on the command line:
def get_versions(): print "HOST - ", HOST if sys.argv[2].find("java") != −1: java_version = check_versions.check_java(HOST, USER, PASSWORD) csv_report.write_csv_log(HOST, "Java", java_version) print "Java version = ", java_version if sys.argv[2].find("python") != −1: python_version = check_versions.check_python(HOST, USER, PASSWORD) csv_report.write_csv_log(HOST, "Python", python_version) print "Python version = ", python_version if sys.argv[2].find("perl") != −1: perl_version = check_versions.check_perl(HOST, USER, PASSWORD) csv_report.write_csv_log(HOST, "Perl", perl_version) print "Perl version = ", perl_version
The first thing the function does is print a header with the IP address of the entered host:
print "HOST - ", HOST
Then the function implements an if
block to determine whether "java" was entered on the command line. If it was, then the check_java()
function is called and the result is assigned to the variable java_version
:
java_version = check_versions.check_java(HOST, USER, PASSWORD)
Then the write_csv_log()
function is called to write the result to the CSV log file:
csv_report.write_csv_log(HOST, "Java", java_version)
The if
block ends by printing the result to the screen:
print "Java version = ", java_version
Then the function implements an if
block to determine whether "python" was entered on the command line. If it was, then the check_python()
function is called and the result is assigned to the variable python_version:
python_version = check_versions.check_python(HOST, USER, PASSWORD)
Then the write_csv_log()
function is called to write the result to the CSV log file:
csv_report.write_csv_log(HOST, "Python", python_version)
The if
block ends by printing the result to the screen:
print "Python version = ", python_version
Then the function implements an if
block to determine whether perl
was entered on the command line. If it was, then the check_perl()
function is called and the result is assigned to the variable perl_version
:
perl_version = check_versions.check_perl(HOST, USER, PASSWORD)
Then the write_csv_log()
function is called to write the result to the CSV log file:
csv_report.write_csv_log(HOST, "Perl", perl_version)
The if
block ends by printing the result to the screen:
print "Perl version = ", perl_version
The check_versions.py
module is responsible for logging into the remote computer, checking the version of the application, and returning the result to the calling program:
import sys import telnetlib def check_java(host, user, password): java_version = "" tn = telnetlib.Telnet(host) tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ") tn.write("java -version ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ") for line in result_list:
if line.startswith("java version"): java_version = line[14:21] return java_version def check_python(host, user, password): python_version = "" tn = telnetlib.Telnet(host) tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ") tn.write("python -V ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ") for line in result_list: if line.startswith("Python "): python_version = line[7:] return python_version def check_perl(host, user, password): perl_version = "" tn = telnetlib.Telnet(host) tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ") tn.write("perl -version ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ") for line in result_list: if line.startswith("This is perl"): perl_version = line[15:20] return perl_version
The check_java()
function logs into the identified server and runs the java –version
command, which returns the version of Java. It captures the result of that command and returns it to the calling program:
def check_java(host, user, password): java_version = "" tn = telnetlib.Telnet(host) tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ") tn.write("java -version ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ") for line in result_list: if line.startswith("java version"): java_version = line[14:21] return java_version
After initializing variables, the function opens a Telnet connection to the host:
tn = telnetlib.Telnet(host)
The function then logs in, providing username and password:
tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ")
Then the Java version is captured and the screen output assigned to a variable:
tn.write("java -version ") tn.write("exit ") result = tn.read_all()
The Java version is then parsed out of the output of the Telnet session:
result_list = result.split(" ") for line in result_list: if line.startswith("java version"): java_version = line[14:21]
Finally, the Java version is returned to the calling program:
return java_version
The check_python()
function logs into the identified server and runs the python −V
command, which returns the version of Python. It captures the result of that command and returns it to the calling program:
def check_python(host, user, password): python_version = "" tn = telnetlib.Telnet(host) tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ") tn.write("python -V ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ") for line in result_list: if line.startswith("Python "): python_version = line[7:] return python_version
After initializing variables, the function opens a Telnet connection to the host:
tn = telnetlib.Telnet(host)
The function then logs in, providing username and password:
tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ")
Then the Python version is captured and the screen output assigned to a variable:
tn.write("python -V ") tn.write("exit ") result = tn.read_all()
The Python version is then parsed out of the output of the Telnet session:
result_list = result.split(" ") for line in result_list: if line.startswith("Python "): python_version = line[7:]
Finally, the Python version is returned to the calling program:
return python_version
The check_perl()
function logs into the identified server and runs the perl–version
command, which queries the version of Perl. It captures the result of that query and returns it to the calling program:
def check_perl(host, user, password): perl_version = "" tn = telnetlib.Telnet(host) tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ") tn.write("perl -version ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ")
for line in result_list: if line.startswith("This is perl"): perl_version = line[15:20] return perl_version
After initializing variables, the function opens a Telnet connection to the host:
tn = telnetlib.Telnet(host)
The function then logs in, providing username and password:
tn.read_until("login: ") tn.write(user + " ") if password: tn.read_until("Password: ") tn.write(password + " ")
Then the Java version is captured and the screen output assigned to a variable:
tn.write("perl -version ") tn.write("exit ") result = tn.read_all()
The Java version is then parsed out of the output of the Telnet session:
tn.write("java -version ") tn.write("exit ") result = tn.read_all() result_list = result.split(" ") for line in result_list: if line.startswith("This is perl"): perl_version = line[15:20]
Finally, the Perl version is returned to the calling program:
return perl_version
The csv_report.py
module captures version check information and writes it to the CSV log file.
The write_csv_log()
function writes the version check information to the CSV log file. The log file, versionchecklog.csv
, is in the program directory. It can be viewed, sorted, and queried with a spreadsheet program.
Here is the function:
def write_csv_log(host, application, version): today = datetime.datetime.now().strftime("%m/%d/%Y") row = [today, host, application, version] try: writer = csv.writer(open("versionchecklog.csv", "a")) writer.writerow(row) except: print "Error writing to file!" sys.exit(1)
The first line of the function formats the current date and assigns it to a variable:
today = datetime.datetime.now().strftime("%m/%d/%Y")
Then it assigns to a list the date, the IP address, the application, and the version:
row = [today, host, application, version]
Finally, the function uses a try
/except
block to open the CSV file and write the row to the CSV file:
try: writer = csv.writer(open("versionchecklog.csv", "a")) writer.writerow(row) except: print "Error writing to file!" sys.exit(1)
This program takes a multitude of parameters, so that is where testing should be focused. Here are some testing ideas:
Enter all possible combinations of applications, including changing case and changing the order of applications.
Set up a batch file to run a series of IP addresses, to ensure that the system does not time out.
Log in to multiple operating systems, to ensure that there are no issues with that.
There are several ways this project could be enhanced, including the following:
Modify the program to accept application names in any format (i.e., uppercase or lowercase).
Modify the program to accept hostnames in addition to IP addresses.
This program did not take into account two security considerations that would need to be addressed in a real-world scenario:
The program uses a single login and password for every hostname. You could allow command-line arguments to enable users to pass a username and password when the script is run.
Telnet, a protocol that was invented in 1969, is fairly insecure. For increased security, use SSH. (There are open-source Python SSH modules available on the web — just do a Google search and you'll have more tools than you know what to do with.)
In this chapter, you learned how to use Python as a telnet client, and to capture and process telnet output.
One of the most important domains for an interpreted language like Python is in the area of system administration. Whether it is moving files, checking the status of processes, or (in the case of this project) checking version levels on a list of computers on a network, Python is ideally suited to the task. Being a cross-platform language, it enables you to access Windows, Linux/Unix, and even Macintosh computers if necessary.
3.133.127.37