Skip to content

Lab 16 - Refactoring Code Using Loops

In the last lab, you learned how to use a for loop and looped over a list of strings, list of dictionaries, and even a dictionary. You'll use that knowledge now to re-factor your last challenge lab.

The solution for Challenge Lab 13 looked like this:

#! /usr/bin/env python

from netmiko import ConnectHandler

print("Connecting to device | CSR1")

csr1 = ConnectHandler(
    host="csr1", username="ntc", password="ntc123", device_type="cisco_ios"
)

print("Saving configuration | CSR1")

csr1.send_command("wr mem")

print("Backing up configuration | CSR1")

csr1.send_command("term len 0")
csr1_config = csr1.send_command("show run")

print("Writing config to file | CSR1\n")

with open("/home/ntc/labs/python/configs/csr1.cfg", "w") as config_file:
    config_file.write(csr1_config)

print("Connecting to device | CSR2")

csr2 = ConnectHandler(
    host="csr2", username="ntc", password="ntc123", device_type="cisco_ios"
)

print("Saving configuration | CSR2")

csr2.send_command("wr mem")

print("Backing up configuration | CSR2")

csr2.send_command("term len 0")
csr2_config = csr2.send_command("show run")

print("Writing config to file | CSR2\n")

with open("/home/ntc/labs/python/configs/csr2.cfg", "w") as config_file:
    config_file.write(csr2_config)

Task 1 - Refactor Challenge Lab 13

The goal is to update this script eliminating all of the duplicated code, introducing a for loop that iterates over csr1 and csr2.

Step 1-1

In your code editor, open the /home/ntc/labs/python/backup.py script and save it as backup-loops.py in the same folder.

Step 1-2

Without changing anything for csr2, create a list of one device (for testing) just after importing ConnectHandler:

#! /usr/bin/env python

from netmiko import ConnectHandler

devices = ["csr1"]

Step 1-3

Add a for loop that loops over devices and updates all lines that have a "csr1" string in replacing it with the variable called device that will be in the for loop, e.g. for device in devices:

The updated script should look like this with device replacing csr1 where necessary:

#! /usr/bin/env python

from netmiko import ConnectHandler

devices = ["csr1"]

for device in devices:
    print(f"Connecting to device | {device}")

    csr1 = ConnectHandler(
        host=device, username="ntc", password="ntc123", device_type="cisco_ios"
    )

    print(f"Saving configuration | {device}")

    csr1.send_command("wr mem")

    print(f"Backing up configuration | {device}")

    csr1.send_command("term len 0")
    csr1_config = csr1.send_command("show run")

    print(f"Writing config to file | {device}\n")

    with open(f"/home/ntc/labs/python/configs/{device}.cfg", "w") as config_file:
        config_file.write(csr1_config)

# LEAVE THE REST OF THIS CODE ALONE FOR NOW, AS IT WILL BE REDUNDANT SOON ENOUGH

print("Connecting to device | CSR2")

csr2 = ConnectHandler(
    host="csr2", username="ntc", password="ntc123", device_type="cisco_ios"
)

print("Saving configuration | CSR2")

csr2.send_command("wr mem")

print("Backing up configuration | CSR2")

csr2.send_command("term len 0")
csr2_config = csr2.send_command("show run")

print("Writing config to file | CSR2\n")

with open("/home/ntc/labs/python/configs/csr2.cfg", "w") as config_file:
    config_file.write(csr2_config)

Note: You may notice the variables holding the connection object and configuration are still named csr1 and csr1_config, even if you're now looping over a list of potentially different devices. The refactoring is not complete yet and you'll fix that a bit later - but it does not affect the functioning of the script since they are just labels!

Step 1-4

Save the backup-loops.py file and then execute it, to ensure it still works as expected:

ntc@ntc-training:~$ cd /home/ntc/labs/python/

ntc@ntc-training:python$ python backup-loops.py
Connecting to device | csr1
Saving configuration | csr1
Backing up configuration | csr1
Writing config to file | csr1

Connecting to device | CSR2
Saving configuration | CSR2
Backing up configuration | CSR2
Writing config to file | CSR2

You should also check the configs/csr1.cfg file to ensure it has the correct contents!

Step 1-5

Add "csr2" to the devices list created in Step 2. Hopefully you realize that you can now delete all of the code for csr2!

This is what what updated script should look like:

#! /usr/bin/env python

from netmiko import ConnectHandler

devices = ["csr1", "csr2"]

for device in devices:
    print(f"Connecting to device | {device}")

    csr1 = ConnectHandler(
        host=device, username="ntc", password="ntc123", device_type="cisco_ios"
    )

    print(f"Saving configuration | {device}")

    csr1.send_command("wr mem")

    print(f"Backing up configuration | {device}")

    csr1.send_command("term len 0")
    csr1_config = csr1.send_command("show run")

    print(f"Writing config to file | {device}\n")

    with open(f"/home/ntc/labs/python/configs/{device}.cfg", "w") as config_file:
        config_file.write(csr1_config)

Step 1-6

Save the backup-loops.py file and then execute it, to ensure it still works as expected:

ntc@ntc-training:python$ python backup-loops.py
Connecting to device | csr1
Saving configuration | csr1
Backing up configuration | csr1
Writing config to file | csr1

Connecting to device | csr2
Saving configuration | csr2
Backing up configuration | csr2
Writing config to file | csr2

You should also check the configs/csr1.cfg and configs/csr2.cfg files to ensure they have the correct contents!

Step 1-7

Since you're using a for loop now, you should clean up variable names so they don't reference to a particular device. Change csr1 to net_device and change csr1_config to net_config.

The updated script should look like this:

#! /usr/bin/env python

from netmiko import ConnectHandler

devices = ["csr1", "csr2"]

for device in devices:
    print(f"Connecting to device | {device}")

    net_device = ConnectHandler(
        host=device, username="ntc", password="ntc123", device_type="cisco_ios"
    )

    print(f"Saving configuration | {device}")

    net_device.send_command("wr mem")

    print(f"Backing up configuration | {device}")

    net_device.send_command("term len 0")
    net_config = net_device.send_command("show run")

    print(f"Writing config to file | {device}\n")

    with open(f"/home/ntc/labs/python/configs/{device}.cfg", "w") as config_file:
        config_file.write(net_config)

Step 1-8

Save and backup the config for csr3 as well.

The only change you have to make is update the devices list to:

devices = ["csr1", "csr2" ,"csr3"]

Step 1-9

Save the backup-loops.py file and then execute it:

ntc@ntc-training:python$ python backup-loops.py
Connecting to device | csr1
Saving configuration | csr1
Backing up configuration | csr1
Writing config to file | csr1

Connecting to device | csr2
Saving configuration | csr2
Backing up configuration | csr2
Writing config to file | csr2

Connecting to device | csr3
Saving configuration | csr3
Backing up configuration | csr3
Writing config to file | csr3

You should also check the configuration backups to ensure they have the correct contents (open them in your editor, use the cat command, or use a quick test as shown below)!

ntc@ntc-training:python$ grep hostname configs/*
configs/csr1.cfg:hostname csr1
configs/csr2.cfg:hostname csr2
configs/csr3.cfg:hostname csr3