Python 3.9.10 or higher on a macOS system or Python 3.9.10 or higher on a Linux system
python -m ensurepip --upgrade
or the py -m ensurepip --upgrade
command.pip install rich
command.pip install netmiko
command.pip install genie
command.pip install pyATS
command.wsl --install
command, which will install and connect you to the Linux VM.resolve.conf
file. Open the file by typing the sudo nano /etc/resolv.conf
command. Once in the file, add the following entry to the file—nameserver 8.8.8.8
—or enter in a different name server IP address of your choice. Exit and then save the file. You should now be able to resolve DNS names.resolv.conf
will get recreated and you will no longer be able to resolve DNS names. You will need to reconfigure your name server to resolve your issue.sudo apt-get update
command, followed by sudo apt install pip
.pip install rich
command.pip install netmiko
command.pip install genie
command.pip install pyATS
command.The scripts used in this tutorial are being run against the Cisco IOS XE Always On Sandbox. The IOS XE Always On Sandbox is a VM that acts and behaves like an IOS router. The Sandbox does not require a reservation and can be shared by many engineers simultaneously over the internet.
Passwords are directly embedded into the scripts in this tutorial. In a real-world production script, you would not hardcode a password directly into a script. However, because the Sandbox password is publicly available, and we want to make it convenient for you to create your scripts, we are hardcoding the password into our scripts in this tutorial.
If you are unable to connect to the IOS XE Always On Sandbox when running the scripts, it is possible that the hostname, username, or password of the Sandbox has changed. To confirm that the Sandbox device is still online and has the same hostname and credentials, you can check its website. I will refer to the IOS XE Always On Sandbox as a router in this tutorial.
Basic Python scripts are typically executed linearly. For example, basic scripts would start executing at the first line and would then execute one line at a time by moving through each line sequentially until the last line was reached.
In order to make our scripts more sophisticated, we can implement conditional statements. Conditional statements enable our script to make decisions. Using conditional statements, a script can decide to execute or not execute lines of code based on whether a condition is True
or False
. When using conditional statements in our script, our script will no longer be executed in a linear fashion because certain parts of the script might be skipped if a certain condition is not met.
One type of conditional statement in Python is an if
statement.
To see how if
statements work, let’s go over some code. Create a new script called numbers.py
. Add the following code into your numbers.py
script:
Let’s break down the code in the following image. In line 1, the user running the script will be prompted to input a number. The number will get stored into the num
variable. Line 3 is where our if
statement begins.
Referencing the following image, to create an if
statement in line 3, we use the if
keyword.
After the if
keyword, we specify the condition (red box below) that we want our script to evaluate.
Our condition is num > 0:
. The condition will evaluate to True
if the num
variable is greater than 0.
Notice we are using a greater-than sign (red arrow below) in our condition. The greater-than sign is referred to as a comparison operator.
If the condition in line 3 evaluates to True
, Python will then execute the block of code in line 4. Notice how the block of code in line 4 is indented to the right of the if
statement in line 3. Python relies on indentation to signify which code should execute if a conditional statement evaluates to True
.
Let’s test out your script. Save and run your script. When prompted, enter a positive number into your script.
linux$ python numbers.py
Please enter a number: 2
2 is a positive number
When we entered a positive number, the condition in line 3 evaluated to True
. Because the condition evaluated to True
, the code in line 4 was executed and the following string printed out: 2 is a positive number
.
What do think will happen if we enter a negative number into our script? Will the condition in line 3 evaluate to True
or False
? Will the code in line 4 get executed?
Run your script, but this time, enter a negative number.
linux$ python numbers.py
Please enter a number: -2
When you enter a negative number, nothing prints out because the condition in line 3 is evaluating to False
. Consequently, the indented code in line 4 is not executed.
What if we want our numbers.py
script to be able to detect negative numbers? To accomplish this, we can use another type of conditional statement, the elif
statement. Elif
statements follow if
statements and are like adding another if
statement to our script. An elif
statement is unique because it is only evaluated if the preceding if
statement is False
. To detect negative numbers in our script, let’s create an elif
statement.
Before we create our elif
statement, we need to choose the correct comparison operator to use in our condition. When we previously created our if
statement in line 3, we used the greater-than sign as our comparison operator. The following image depicts other valid comparison operators. Which comparison operator do you think we will use in our elif
statement to detect negative numbers?
We will use the less-than sign (<
) comparison operator to detect negative numbers in our script.
Add the code in lines 5 and 6 into your numbers.py
script to implement an elif
statement.
What will happen now if we run our script and input a negative number into the script? The condition within the if
statement in line 3 would evaluate to False
. Next, the condition within the elif
statement in line 5 would be evaluated. The condition within the elif
statement in line 5 would evaluate to True
, and the indented code in line 6 would be executed.
To see this in action, save and run your script. When prompted, enter a negative number.
linux$ python numbers.py
Please enter a number: -2
-2 is a negative number
Next, what do you think might happen if we run our script and enter the number 0? Will the condition within the if
statement in line 3 evaluate to True
or False
? Will the code in line 4 be executed? Will the condition within the elif
statement in line 5 be evaluated? If the condition in line 5 is evaluated, will the condition evaluate to True
or False
? Will the code in line 6 be executed?
Let’s find out. Run your script and enter the number 0.
linux$ python numbers.py
Please enter a number: 0
When we ran the script and entered 0 into the script, nothing printed out. We are seeing this behavior because the conditional statements in both lines 3 and 5 are evaluating to False
. Consequently, the indented code in lines 4 and 6 is not being executed.
What if we want our script to be able to detect the number 0? Another type of conditional statement we can use is the else
statement. Else
statements will only run a block of code when all the previous conditional statements have evaluated to False
. Else
statements essentially catch anything that was not caught by the preceding conditional statements.
Let’s create an else
statement. Add the code in lines 7 and 8 into your numbers.py
script.
In line 7, we added an else
statement. This means that if the previous conditional statements in lines 3 and 5 both evaluated to False
, then the indented code in line 8 will be executed.
Save and run your script. When prompted, enter the number 0.
linux$ python numbers.py
Please enter a number: 0
Your number must be zero!
Your script should print out the following string: Your number must be zero!
. When the string prints out, it confirms that the code within the else
statement was executed.
To prevent a potential conflict later in this tutorial, close and then delete your numbers.py
file.
linux$ rm numbers.py
Imagine that you have been tasked with creating a script to check the software version running on a router. If the router is on the correct version of software, your script would then notify the administrator that the router is up to date. If the router is on the incorrect version of software, your script can then notify the administrator that the router needs to be upgraded.
To accomplish the above task, we will send an application programming interface (API) call to the router to obtain the router’s software version. After the software version has been obtained, we will program conditional statements into our script to notify the administrator if the router needs to be upgraded or not.
First, let’s obtain the software version of the router. Create a script called netmiko_test.py
. Copy and paste the following lines of code into your script. Notice that in line 13 of your script, you are using the genie parser to convert the show version
command output from a string to a Python dictionary.
from netmiko import ConnectHandler
HOST = 'sandbox-iosxe-latest-1.cisco.com'
USER = 'admin'
PASSWORD = 'C1sco12345'
TYPE = 'cisco_xe'
r1 = ConnectHandler(host=HOST, username=USER, password=PASSWORD, device_type=TYPE)
response = r1.send_command('show version', use_genie=True)
print(response)
Save and then run your script.
linux$ python netmiko_test.py
{'version': {'xe_version': '17.09.02a', 'version_short': '17.9', 'platform': 'Virtual XE', 'version': '17.9.2a', 'image_id': 'X86_64_LINUX_IOSD-UNIVERSALK9-M', 'label': 'RELEASE SOFTWARE (fc4)', 'os': 'IOS-XE', 'location': 'Cupertino', 'image_type': 'production image', 'copyright_years': '1986-2022', 'compiled_date': 'Wed 30-Nov-22 02:47', 'compiled_by': 'mcpre', 'rom': 'IOS-XE ROMMON', 'hostname': 'Cat8000V', 'uptime': '5 hours, 2 minutes', 'uptime_this_cp': '5 hours, 4 minutes', 'returned_to_rom_by': 'reload', 'system_image': 'bootflash:packages.conf', 'last_reload_reason': 'reload', 'license_type': 'Perpetual', 'chassis': 'C8000V', 'main_mem': '1980715', 'processor_type': 'VXE', 'rtr_type': 'C8000V', 'chassis_sn': '9UWS2FADP45', 'router_operating_mode': 'Autonomous', 'number_of_intfs': {'Gigabit Ethernet': '3'}, 'mem_size': {'non-volatile configuration': '32768', 'physical': '3965344'}, 'disks': {'bootflash:.': {'disk_size': '5234688', 'type_of_disk': 'virtual hard disk'}}, 'curr_config_register': '0x2102'}}
When you run the script, the response from the router’s API is printed out. Take note of how the data is nested. The data appears to be dictionaries nested within a dictionary. Read through the printed response and see if you can find which key-value pair stores the software version of the router.
The answer is below.
You can obtain the software version that your router is running by viewing the value of the xe_version
key. In my lab, the router is running software version 17.09.02a
; however, your software version will likely be a different version number because the router being used in this tutorial is upgraded on a recurring basis. Make sure to use the software version that you obtained from the xe_version
key in the rest of the upcoming steps in this tutorial.
Before we can create our conditional statements to check that the routers are on the correct software version, we must first store the value of the xe_version
key into a variable. To store the value of the xe_version
key into a variable, we must first determine how the xe_version
key is nested within other keys.
Analyze the following image. Notice that the xe_version
key (green outline) is nested with the version
key (red outline). We will to need specify the previously named keys in the correct order to access the value of the xe_version
key.
Next, access and print out the value of the xe_version
key. To do so, add the version
and the xe_version
key to the end of the response
variable in line 15.
Save and then run your script.
linux$ python netmiko_test.py
17.09.02a
Now that you have obtained the value of the xe_version
key, change line 15 to store the value of the xe_version
key into the software_version
variable.
Now that we have stored the router’s software version into a variable, it is time to create our conditional statements.
First, create an if
statement that will detect if your router is on the correct version of software. Add lines 17 and 18 into your netmiko_test.py
script by referencing the following image. Make sure to use the software version that you obtained from the xe_version
key earlier because your software version may differ from mine.
Save and run the script.
linux$ python netmiko_test.py
This router is running software version 17.09.02a and does not need to be upgraded.
Let’s now create an elif
statement. Remember, elif
statements follow if
statements and are like adding another if
statement to our script. Try changing line 17 from an if
statement to an elif
statement.
Save and then run the script.
linux$ python netmiko_test.py
File "/home/bob/netmiko_test.py", line 17
elif software_version == '17.09.02a':
^^^^
SyntaxError: invalid syntax
You should get a SyntaxError
exception when running your script. Why? You are receiving this exception because it is required that you have an if
statement before an elif
statement when creating conditional statements in Python.
Let’s resolve the exception and also enable our script to detect another software version (version 1.2.3x) using another conditional statement. In line 17, add a new if
statement before our elif
statement. In your new if
statement, create a condition that will detect software version 1.2.3x. Add indented code in line 18 that will be executed if the preceding if
statement evaluates to True
.
Save and run your script.
linux$ python netmiko_test.py
This router is running software version 17.09.02a and does not need to be upgraded.
Next, let’s change the elif
statement in line 19 to a software version that is different from the version your router is running.
What do you think will happen if we run the script?
Let’s find out. Save and then run the script.
linux$ python netmiko_test.py
Nothing should print out when our script runs. Why is this happening? The router in my example is on software version 17.09.02a
. The if
and elif
statements on lines 17 and 19, respectively, reference different software versions than 17.09.02a
. Because lines 17 and 19 reference different software versions, both the if
and elif
statements evaluate to False
, and the blocks of code indented within the if
and elif
statements do not get executed.
Let’s add an enhancement to our script. If a router is not on version 1.2.3x or 4.5.6x, we want the script to notify the administrator that the router needs to be upgraded. To accomplish this, we can use an else
statement.
Remember, else
statements will only run their indented block of code when all the previous conditional statements evaluated to False
.
Implement an else
statement in line 21. In line 22, print out a notification that the router needs to be upgraded.
Save and run your script.
linux$ python netmiko_test.py
This router is on software version 17.09.02a and needs to be upgraded.
Because the if
statement in line 17 and the elif
statement in line 19 both evaluated to False
, the code within the else
statement in line 22 should get executed. When running the script, you should get notified that your router needs to be upgraded.
You can also specify more than one condition next to an if
statement. To join the multiple conditions, you use logical operators. There are three logical operators:
and
: Returns True
if both joined conditions are True
or
: Returns True
if only one of the joined conditions is True
not
: Reverses the result; returns False
if the result is True
In the upcoming script, we will join multiple conditions within a single if
statement. The script will use the if
statement to detect if the router is on version 17.09.02a
and if there is at least 2000000000
bytes of storage space remaining in the router’s bootflash directory. If the router meets both of these conditions, the if
statement will evaluate to True
, and a message will be printed to the administrator that the router can be upgraded.
Delete all the lines of code in your netmiko_test.py
script. Next, copy and paste the following code into your empty netmiko_test.py
script:
from netmiko import ConnectHandler
from rich.pretty import pprint
HOST = 'sandbox-iosxe-latest-1.cisco.com'
USER = 'admin'
PASSWORD = 'C1sco12345'
TYPE = 'cisco_xe'
r1 = ConnectHandler(host=HOST, username=USER, password=PASSWORD, device_type=TYPE)
response = r1.send_command('', use_genie=True)
pprint(response)
Before we create our conditional statements, we first need our script to obtain the router’s software version and the amount of storage space remaining in the router’s bootflash directory.
First, let’s obtain the software version of the router by using the show version
command in our script. Update line 12 to include the show version
command. Save the response into the show_version_response
variable. Change the variable name in line 14 to print out the value of the show_version_response
variable.
Save and run your script.
linux$ python netmiko_test.py
{
│ 'version': {
│ │ 'xe_version': '17.09.02a',
│ │ 'version_short': '17.9',
│ │ 'platform': 'Virtual XE',
│ │ 'version': '17.9.2a',
│ │ 'image_id': 'X86_64_LINUX_IOSD-UNIVERSALK9-M',
│ │ 'label': 'RELEASE SOFTWARE (fc4)',
│ │ 'os': 'IOS-XE',
│ │ 'location': 'Cupertino',
│ │ 'image_type': 'production image',
│ │ 'copyright_years': '1986-2022',
│ │ 'compiled_date': 'Wed 30-Nov-22 02:47',
│ │ 'compiled_by': 'mcpre',
│ │ 'rom': 'IOS-XE ROMMON',
│ │ 'hostname': 'Cat8000V',
│ │ 'uptime': '2 days, 9 hours, 40 minutes',
│ │ 'uptime_this_cp': '2 days, 9 hours, 42 minutes',
│ │ 'returned_to_rom_by': 'reload',
│ │ 'system_image': 'bootflash:packages.conf',
│ │ 'last_reload_reason': 'Reload Command',
│ │ 'license_type': 'Perpetual',
│ │ 'chassis': 'C8000V',
│ │ 'main_mem': '1980715',
│ │ 'processor_type': 'VXE',
│ │ 'rtr_type': 'C8000V',
│ │ 'chassis_sn': '9UWS2FADP45',
│ │ 'router_operating_mode': 'Autonomous',
│ │ 'number_of_intfs': {'Gigabit Ethernet': '3'},
│ │ 'mem_size': {'non-volatile configuration': '32768', 'physical': '3965344'},
│ │ 'disks': {'bootflash:.': {'disk_size': '5234688', 'type_of_disk': 'virtual hard disk'}},
│ │ 'curr_config_register': '0x2102'
│ }
}
The router’s software version is stored in the xe_version
key. Next, we will need to access the value of the xe_version
key. To access the value, we need to determine how the xe_version
key is nested within other keys. Can you figure out which key or keys that the xe_version
key is nested within?
The answer is below.
The xe_version
key is nested within the version
key. Now that you have obtained the required keys, change line 14 in your script to store the value of the xe_version
key into the software_version
variable. In line 16, print out the software_version
variable to confirm that the variable has the correct value.
Save and then run your script.
linux$ python netmiko_test.py
17.09.02a
We have successfully stored the software version of the router into a variable.
Next, we need to obtain the amount of storage space remaining in the router’s bootflash directory. We can do so by using the dir
command. Replace line 16 in the script with the code in the following image to send the dir
command to the router. Store the response from the router into the dir_response
variable. In line 18, pretty-print out the response stored in the dir_response
variable.
Save and run the script.
linux$ python netmiko_test.py
{
│ 'dir': {
│ │ 'bootflash:/': {
│ │ │ 'files': {
│ │ │ │ 'tracelogs': {
│ │ │ │ │ 'index': '131078',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '36864',
│ │ │ │ │ 'last_modified_date': 'Sep 4 2023 15:19:05 +00:00'
│ │ │ │ },
│ │ │ │ 'nbar2': {
│ │ │ │ │ 'index': '131215',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 16:43:44 +00:00'
│ │ │ │ },
│ │ │ │ 'nbar2_http_default.tar': {
│ │ │ │ │ 'index': '34',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '2672640',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 16:43:41 +00:00'
│ │ │ │ },
│ │ │ │ 'guest-share': {
│ │ │ │ │ 'index': '131295',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 16:38:11 +00:00'
│ │ │ │ },
│ │ │ │ 'cvac.log': {
│ │ │ │ │ 'index': '28',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '2952',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:11:01 +00:00'
│ │ │ │ },
│ │ │ │ 'license_evlog': {
│ │ │ │ │ 'index': '131110',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:11:01 +00:00'
│ │ │ │ },
│ │ │ │ '.iox_dir_list': {
│ │ │ │ │ 'index': '32',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '301',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:10:47 +00:00'
│ │ │ │ },
│ │ │ │ 'csrlxc-cfg.log': {
│ │ │ │ │ 'index': '31',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '157',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:10:43 +00:00'
│ │ │ │ },
│ │ │ │ 'SHARED-IOX': {
│ │ │ │ │ 'index': '131073',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:10:39 +00:00'
│ │ │ │ },
│ │ │ │ 'throughput_monitor_params': {
│ │ │ │ │ 'index': '27',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '30',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:10:23 +00:00'
│ │ │ │ },
│ │ │ │ 'mode_event_log': {
│ │ │ │ │ 'index': '12',
│ │ │ │ │ 'permissions': '-rwx',
│ │ │ │ │ 'size': '2132',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:09:34 +00:00'
│ │ │ │ },
│ │ │ │ '.installer': {
│ │ │ │ │ 'index': '131074',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Sep 2 2023 04:09:02 +00:00'
│ │ │ │ },
│ │ │ │ 'Line': {
│ │ │ │ │ 'index': '33',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '126408',
│ │ │ │ │ 'last_modified_date': 'Sep 1 2023 19:52:10 +00:00'
│ │ │ │ },
│ │ │ │ 'iox_host_data_share': {
│ │ │ │ │ 'index': '131342',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Mar 15 2023 09:36:12 +00:00'
│ │ │ │ },
│ │ │ │ '.dbpersist': {
│ │ │ │ │ 'index': '131094',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:59 +00:00'
│ │ │ │ },
│ │ │ │ 'onep': {
│ │ │ │ │ 'index': '131112',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:56 +00:00'
│ │ │ │ },
│ │ │ │ '.cvac_version': {
│ │ │ │ │ 'index': '29',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '1',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:53 +00:00'
│ │ │ │ },
│ │ │ │ 'ovf_env.md5': {
│ │ │ │ │ 'index': '30',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '16',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:53 +00:00'
│ │ │ │ },
│ │ │ │ 'pnp-info': {
│ │ │ │ │ 'index': '131109',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:52 +00:00'
│ │ │ │ },
│ │ │ │ 'virtual-instance': {
│ │ │ │ │ 'index': '131107',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:28 +00:00'
│ │ │ │ },
│ │ │ │ 'ios_core.p7b': {
│ │ │ │ │ 'index': '25',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '20109',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:08 +00:00'
│ │ │ │ },
│ │ │ │ 'trustidrootx3_ca_092024.ca': {
│ │ │ │ │ 'index': '26',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '1923',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:08 +00:00'
│ │ │ │ },
│ │ │ │ 'core': {
│ │ │ │ │ 'index': '131077',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:16:02 +00:00'
│ │ │ │ },
│ │ │ │ 'bootlog_history': {
│ │ │ │ │ 'index': '131084',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:15:58 +00:00'
│ │ │ │ },
│ │ │ │ '.prst_sync': {
│ │ │ │ │ 'index': '131083',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:15:57 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-rpboot.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '23',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '51959459',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:45 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-mono-universalk9.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '22',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '797045848',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:45 +00:00'
│ │ │ │ },
│ │ │ │ 'packages.conf': {
│ │ │ │ │ 'index': '24',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '5794',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:45 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_nim_async.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '17',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '13038668',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_ngwic_t1e1.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '16',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '11760716',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_nim_cwan.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '18',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '17724492',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_dreamliner.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '15',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '66636',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_nim_ge.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '19',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '4346952',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_nim_shdsl.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '20',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '11568204',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'c8000v-firmware_nim_xdsl.17.09.02a.SPA.pkg': {
│ │ │ │ │ 'index': '21',
│ │ │ │ │ 'permissions': '-rw-',
│ │ │ │ │ 'size': '5575756',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:43 +00:00'
│ │ │ │ },
│ │ │ │ 'appqoe-service': {
│ │ │ │ │ 'index': '14',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:39 +00:00'
│ │ │ │ },
│ │ │ │ '.rollback_timer': {
│ │ │ │ │ 'index': '13',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '4096',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:38 +00:00'
│ │ │ │ },
│ │ │ │ 'lost+found': {
│ │ │ │ │ 'index': '11',
│ │ │ │ │ 'permissions': 'drwx',
│ │ │ │ │ 'size': '16384',
│ │ │ │ │ 'last_modified_date': 'Feb 27 2023 05:14:13 +00:00'
│ │ │ │ }
│ │ │ },
│ │ │ 'bytes_total': '5183766528',
│ │ │ 'bytes_free': '2909155328'
│ │ },
│ │ 'dir': 'bootflash:/'
Based on the previous output, can you determine which key stores the value for the amount of storage space remaining in the router’s bootflash directory?
The answer is below.
The bytes_free
key stores the value for the amount of storage space remaining in the router’s bootflash directory. Next, we will need to extract the value of the bytes_free
key. To do this, we need to determine how the bytes_free
key is nested within other keys. Can you figure out which key or keys that the bytes_free
key is nested within?
The answer is below.
The bytes_free
key is nested within the dir
and the bootflash:/
keys, respectively. Now that you have obtained the required keys, change line 18 in your script to store the value of the bytes_free
key into the bootflash_space
variable. Also in line 18 we will need to convert the type of data that is stored in the bootflash_space
variable. Enclose line 18 within the int
class so that we can convert the bootflash_space
variable from a string to an integer. Print the bootflash_space
variable to confirm that we have accessed the correct value.
Save and then run your script.
linux$ python netmiko_test.py
2909143040
Let’s recap what we have done so far:
software_version
variable.bootflash_space
variable.Next, we will add an if
statement to our script to achieve the following: If the router is on software version 17.09.02a
and there are 2000000000
bytes of storage space remaining in the bootflash directory, the script will print out a message that the router can be upgraded.
Delete the code in line 20, and then replace the code with the if
statement seen in line 20 below. In line 21, add code that will print a message to the administrator.
Save and run your script.
linux$ python netmiko_test.py
Router is running 17.09.02a. 2909118464 bytes left of space in bootflash. Router can be upgraded.
Next, in lines 22 and 23, implement an else
statement so that we can detect routers that should not be upgraded.
In line 21, change the software version that has to be upgraded from 17.09.02a
to 16.09.02a
.
What do you think will happen when we run our script now?
Save and run your script.
linux$ python netmiko_test.py
Router is running 17.09.02a. 2909159424 bytes left of space in bootflash. Router cannot be upgraded.
You should be notified that the router cannot be upgraded. Why is this occurring? We are using the and
logical operator in our if
statement (line 20), so the if
statement will only evaluate to True
if both conditions are True
. Because one of the conditions evaluates to False
(the software version not equaling 16.09.02a
), the entire if
statement evaluates to False
, and the code on line 21 does not get executed. The if
statement evaluates to False
, so the code within the else
statement (line 23) automatically executes, and a string is printed out that the router cannot be upgraded.
Change line 20 from the and
logical operator to the or
logical operator.
What do you think will happen if we run our script?
Save and then run your script.
linux$ python netmiko_test.py
Router is running 17.09.02a. 2909167616 bytes left of space in bootflash. Router can be upgraded.
Because we are using the or
logical operator, the if
statement will evaluate to True
if just a single condition in our if
statement evaluates to True
. The amount of space left in our bootflash directory is greater than 2000000000 bytes, so the if
statement will automatically evaluate to True
even if the router is not running on version 16.09.02a
.
Nice work! You now understand how to use conditional statements in network automation scripts. Also, if you are interested, I teach at Cisco DevNet Automation Bootcamp.