Lab 19 - Passing in User Input¶
This lab shows you how to accept input from the user, which may then be used by Python.
- Lab 19 - Passing in User Input
- Task 1 - Update the Modularized Script
- Task 2 - Collecting Input Using the
argparseLibrary - Task 3 - Using
sys.argvto Provide Input - Conclusion
Task 1 - Update the Modularized Script¶
In this lab, you will deploy the generated configuration for SNMP to an end device, but will now collect user input for the parameters that were hard-coded earlier.
Step 1-1¶
In the /home/ntc/labs/python/configs folder, create a file named snmp.cfg with the following contents:
snmp-server community networktocode RO
snmp-server community public RO
snmp-server community ntcrw RW
snmp-server community supersecret RW
snmp-server location new_york
snmp-server contact jane_smith
Step 1-2¶
In the /home/ntc/labs/python/ folder, create a script called interactive.py with the following code:
def print_logger(message, hostname):
print(f"{message} | {hostname}")
def connect_to_device(hostname, username, password, device_type):
print_logger("Connecting to device", hostname)
print_logger(f"username={username}, password={password}, device_type={device_type}", hostname)
def deploy_commands(hostname, config_file):
print_logger("Sending commands from file", hostname)
_file = open(config_file, "r")
commands = _file.read()
_file.close()
print_logger(commands, hostname)
def main(device_hostname, username, password, device_type):
config_file = "./configs/snmp.cfg"
connect_to_device(device_hostname, username, password, device_type)
deploy_commands(device_hostname, config_file)
hostname = "csr1"
username = "ntc"
password = "ntc123"
device_type = "cisco_ios"
main(hostname, username, password, device_type)
Take a bit of time to read the code and understand what each function does!
The goal of this task is to pass in the device, username, password, and device_type variables instead of hard-coding them in the script.
Step 1-3¶
Replace the hard-coded variables in the script with interactive prompts by using the builtin Python input function. The bottom portion of the interactive.py script should look like this:
device = input("Please enter the hostname or IP: ")
username = input("Please enter the username: ")
password = input("Please enter the password: ")
device_type = input("Please enter the device type: ")
main(device, username, password, device_type)
Step 1-4¶
Save and execute the script.
ntc@ntc-training:python$ python interactive.py
Please enter the hostname or IP: csr1
Please enter the username: ntc
Please enter the password: ntc123
Please enter the device type: cisco_ios
Connecting to device | csr1
Sending commands from file | csr1
Disconnecting from device | csr1
Note: You can see the password on the terminal as it was typed, which is not ideal.
Step 1-5¶
Import getpass at the top of your script like this:
Replace input for getpass when entering the password.
Step 1-6¶
The full interactive.py script should look as follows:
from getpass import getpass
def print_logger(message, hostname):
print(f"{message} | {hostname}")
def connect_to_device(hostname, username, password, device_type):
print_logger("Connecting to device", hostname)
print_logger(f"username={username}, password={password}, device_type={device_type}", hostname)
def deploy_commands(hostname, config_file):
print_logger("Sending commands from file", hostname)
_file = open(config_file, "r")
commands = _file.read()
_file.close()
print_logger(commands, hostname)
def main(device_hostname, username, password, device_type):
config_file = "./configs/snmp.cfg"
connect_to_device(device_hostname, username, password, device_type)
deploy_commands(device_hostname, config_file)
device = input("Please enter the hostname or IP: ")
username = input("Please enter the username: ")
password = getpass("Please enter the password: ")
device_type = input("Please enter the device type: ")
main(device, username, password, device_type)
Step 1-7¶
Save and re-run the script.
ntc@ntc-training:python$ python interactive.py
Please enter the hostname or IP: csr1
Please enter the username: ntc
Please enter the password:
Please enter the device type: cisco_ios
Connecting to device | csr1
Sending commands from file | csr1
Disconnecting from device | csr1
Success! You no longer see the typed password on the terminal.
Task 2 - Collecting Input Using the argparse Library¶
Prompting the user is one way to collect input interactively. In this task we will use the Python argparse module to collect input from the user, in a style that mimics most Unix commands.
Our goal here is for the script to help the user on the usage/limitations and understand how to supply default values that users can potentially override.
Step 2-1¶
Perform a Save As on the file you just created in the previous task. Save it as user-flags.py.
Step 2-2¶
Edit this new file in your text editor.
The new code needed to collect user input will use Python's argparse library. Go ahead and import this at the top of your script.
Step 2-3¶
Replace the following interactive prompts in your script...
device = input("Please enter the hostname or IP: ")
username = input("Please enter the username: ")
password = getpass("Please enter the password: ")
device_type = input("Please enter the device type: ")
With the following code:
parser = argparse.ArgumentParser(description="Deploy configuration to a device")
parser.add_argument(
"-i",
"--ip",
help="Enter the IP address or hostname of the device",
required=True,
)
parser.add_argument(
"-d", "--device_type", help="Enter the device type", required=True
)
parser.add_argument(
"-u", "--username", help="Enter the username", required=True
)
parser.add_argument(
"-p", "--password", help="Enter the password", required=True
)
# parse all args and render
args = parser.parse_args()
device = args.ip
username = args.username
password = args.password
device_type = args.device_type
Step 2-4¶
The full user-flags.py script should look as follows:
import argparse
from getpass import getpass
def print_logger(message, hostname):
print(f"{message} | {hostname}")
def connect_to_device(hostname, username, password, device_type):
print_logger("Connecting to device", hostname)
print_logger(f"username={username}, password={password}, device_type={device_type}", hostname)
def deploy_commands(hostname, config_file):
print_logger("Sending commands from file", hostname)
_file = open(config_file, "r")
commands = _file.read()
_file.close()
print_logger(commands, hostname)
def main(device_hostname, username, password, device_type):
config_file = "./configs/snmp.cfg"
connect_to_device(device_hostname, username, password, device_type)
deploy_commands(device_hostname, config_file)
parser = argparse.ArgumentParser(description="Deploy configuration to a device")
parser.add_argument(
"-i",
"--ip",
help="Enter the IP address or hostname of the device",
required=True,
)
parser.add_argument(
"-d", "--device_type", help="Enter the device type", required=True
)
parser.add_argument(
"-u", "--username", help="Enter the username", required=True
)
parser.add_argument(
"-p", "--password", help="Enter the password", required=True
)
# parse all args and render
args = parser.parse_args()
device = args.ip
username = args.username
password = args.password
device_type = args.device_type
main(device, username, password, device_type)
Step 2-5¶
Save and execute this script, first without any arguments:
ntc@ntc-training:python$ python user-flags.py
usage: user-flags.py [-h] -i IP -d DEVICE_TYPE -u USERNAME -p PASSWORD
user-flags.py: error: the following arguments are required: -i/--ip, -d/--device_type, -u/--username, -p/--password
Note the usage instructions and required flags.
Step 2-6¶
Next try and execute the script with the -h or --help flag:
ntc@ntc-training:python$ python user-flags.py -h
usage: user-flags.py [-h] -i IP -d DEVICE_TYPE -u USERNAME -p PASSWORD
Deploy configuration to a device
optional arguments:
-h, --help show this help message and exit
-i IP, --ip IP Enter the IP address or hostname of the device
-d DEVICE_TYPE, --device_type DEVICE_TYPE
Enter the device type
-u USERNAME, --username USERNAME
Enter the username
-p PASSWORD, --password PASSWORD
Enter the password
Step 2-7¶
Finally, execute the script with all required inputs:
ntc@ntc-training:python$ python user-flags.py -i csr1 -d cisco_ios -u ntc -p ntc123
Connecting to device | csr1
Sending commands from file | csr1
Disconnecting from device | csr1
Remember you can also pass in the long-form of the flags using
--username ntcor--username=ntc.
Task 3 - Using sys.argv to Provide Input¶
This task shows the quickest way to get started working with command line arguments. While argparse is recommended for more user-friendly scripts, you may want to use sys.argv for a quick and easy way to pass in a small amount of arguments into a script.
Step 3-1¶
In the /home/ntc/labs/python/ folder, create a script called basic_args.py and open it in your editor.
Step 3-2¶
In the script, add the following code that performs the needed import and prints out the list of command line arguments provided to the script.
Step 3-3¶
Save and execute the script.
Can you tell that a list was printed out? This is a list with one element. We can see that the first and only element in the list is the name of the Python file being executed.
Step 3-4¶
Re-run the script like so:
ntc@ntc-training:python$ python basic_args.py cisco arista juniper
HERE ARE MY ARGUMENTS:
['basic_args.py', 'cisco', 'arista', 'juniper']
Again, notice that the script name is always element 0 and then every other argument is another element in the list, taken in order from your command line.
Step 3-5¶
Add code to print out the first real argument, i.e. "cisco".
Additionally, save sys.argv as args. This will simplfy working with the objects going forward.
#! /usr/bin/env python
import sys
args = sys.argv
print(f"HERE ARE MY ARGUMENTS: {args}")
print(f"This is the first argument: {args[1]}")
Step 3-6¶
Run the script again.
ntc@ntc-training:python$ python basic_args.py cisco arista juniper
HERE ARE MY ARGUMENTS: ['basic_args.py', 'cisco', 'arista', 'juniper']
This is the first argument: cisco
Step 3-7¶
As you can see, using the sys module with the argv variable, it is quite fast and easy to pass in arguments from the command line.
One other trick is to use indexing with lists to only ever print everything BUT the first element.
Note: You can use
[1:]to access the list starting at index 1. You can also do[1:<ending index #>too.
Take a look:
#! /usr/bin/env python
import sys
args = sys.argv
print(f"HERE ARE MY ARGUMENTS: {args}")
print(f"This is the first argument: {args[1]}")
print(f"These are the useful args: {args[1:]}")
Running it gives you the output:
ntc@ntc-training:python$ python basic_args.py cisco arista juniper
HERE ARE MY ARGUMENTS: ['basic_args.py', 'cisco', 'arista', 'juniper']
This is the first argument: cisco
These are the useful args: ['cisco', 'arista', 'juniper']
Conclusion¶
In this lab you have explored multiple ways to create a modular python script to collect user input. Using the user input, the script then was able to connect to network devices and deploy configuration.
It's good practice to reduce the amount of hard-coding of external data in your scripts as much as possible. There are many ways of doing this, be it with interactive prompts, command line parameters, environment variables, configuration files etc.