Lesson 4 of 6

pyATS for Testing and Validation

Objective

In this lesson you will learn how to use pyATS/Genie to test and validate network state by (1) preparing a small campus topology, (2) enabling a deterministic change (PortFast) on edge switch ports, (3) capturing device snapshots (learn), and (4) comparing snapshots (diff) to detect configuration drift. This matters in production because automated validation finds configuration drift and misconfigurations before they cause outages — for example, quickly detecting when PortFast is removed from an access port that connects to an IP phone or router can prevent slow STP convergence and service disruption.

Real-world scenario: In a campus with many edge switches, an automation pipeline pushes configuration changes. Before and after each push, pyATS learn/diff can ensure the actual running state matches the intent (for example, PortFast is present on access ports that face routers/phones). This avoids manual spot checks and speeds troubleshooting.


Quick Recap

Topology referenced from Lesson 1 (logical view). This lesson does not add new devices; we reuse the same switches and virtualization hosts. Use the exact IP addresses for the Catalyst 9000 VMs provided in the reference.

ASCII topology (management IPs shown where available):

    +----------------------+                +----------------------+
    |  c9k-spine           |                |  c9k-leaf1           |
    |  VLAN1 mgmt:         |                |  VLAN1 mgmt:         |
    |  198.18.1.21         |----------------|  198.18.1.31         |
    |  (developer/C1sco12345)               |  (developer/C1sco12345)|
    +----------------------+                +----------------------+
             |                                      |
             |                                      |
             |                                      |
    +----------------------+                +----------------------+
    |  c9k-leaf2           |                |  SW1                 |
    |  VLAN1 mgmt:         |                |  (edge switch)       |
    |  198.18.1.32         |                |  Interfaces: E1/0-2  |
    |  (developer/C1sco12345)|              +----------------------+
    +----------------------+                |  SW2                 |
                                            |  Interfaces: E1/0-2  |
                                            +----------------------+
                                            |  SW3                 |
                                            |  Interfaces: E1/0, E0/2-3 |
                                            +----------------------+
                                            |  SW4                 |
                                            |  Interfaces: E0/2-3  |
                                            +----------------------+

Tip: The lab uses the provided management IPs for the virtual Catalyst devices. Switch edge ports to be configured with PortFast are on SW1–SW4 (use the interface names exactly as shown in the reference).


Key Concepts

  • pyATS/Genie snapshot (learn): pyATS can connect to devices, run a set of commands, and store structured outputs (a snapshot). Think of this as taking a photograph of device state — later you can compare photographs to detect changes.
    • In production: use learn before and after a configuration deployment to detect unintended changes.
  • Diffing snapshots: pyATS can compare two learned snapshots and report differences at config and operational levels. This is low-noise and highlights only the changed objects.
    • Protocol-level effect: a detected change in STP mode or PortFast implies that STP timers and port states may be different, affecting BPDUs and convergence behavior.
  • PortFast behavior: When PortFast is enabled on an access port, the port bypasses STP Listening and Learning and enters Forwarding immediately after link-up. This prevents delays for endpoints like servers and phones.
    • Packet flow: with PortFast, the port immediately forwards frames; STP BPDUs are still processed, but the port will not cause a temporary blocking state.
  • Testbed design: A pyATS testbed maps device names to management IPs, protocols (ssh), and credentials. Use consistent naming to make learn/diff outputs easy to interpret.
    • Real-world note: put testbed files under version control and include them in CI pipelines so automated tests are repeatable.

Step-by-step configuration

Step 1: Configure PortFast on SW1

What we are doing: Configure PortFast on the interfaces of SW1 that face routers/phones so those ports enter forwarding immediately. This reduces wait time at link-up and stabilizes endpoint behavior.

configure terminal
interface range Ethernet1/0 -2
spanning-tree portfast
end
write memory

What just happened: Entered global configuration mode, selected the interface range Ethernet1/0 through Ethernet1/2, and enabled PortFast on those interfaces. The spanning-tree portfast command causes those interfaces to bypass the STP Listening and Learning states and transition directly to Forwarding on link-up. write memory saves the change to the startup configuration.

Real-world note: PortFast should only be applied to access ports connected to end devices — enabling PortFast on ports connected to other switches can create switching loops.

Verify:

show spanning-tree interface Ethernet1/0 detail
spanning-tree interface Ethernet1/0
  Port Type: Edge Port (PortFast)
  State: forwarding
  P2p Link
  PortFast: Enabled

Step 2: Configure PortFast on SW2

What we are doing: Apply PortFast to SW2 interfaces that will be treated as edge ports, mirroring the configuration pattern from SW1. Consistency across access switches reduces operational surprises.

configure terminal
interface range Ethernet1/0 -2
spanning-tree portfast
end
write memory

What just happened: PortFast is enabled on Ethernet1/0 and Ethernet1/1 on SW2. These ports will not go through STP Listening and Learning; they will accept and forward frames immediately on link-up.

Real-world note: When managing many switches, implement PortFast through templates or automation to avoid human error.

Verify:

show spanning-tree interface Ethernet1/1 detail
spanning-tree interface Ethernet1/1
  Port Type: Edge Port (PortFast)
  State: forwarding
  P2p Link
  PortFast: Enabled

Step 3: Configure PortFast on SW3 and SW4 (multiple ranges)

What we are doing: On SW3 and SW4, enable PortFast on the specific interfaces listed in the lab reference. This demonstrates using non-contiguous interface lists and ranges.

configure terminal
interface range Ethernet1/0, Ethernet0/2 -3
spanning-tree portfast
exit
interface range Ethernet0/2 -3
spanning-tree portfast
end
write memory

What just happened: The first interface range command demonstrates a mixed list (Ethernet1/0 plus the range Ethernet0/2–3) and enables PortFast on those ports. The second interface range ensures the E0/2–3 range on SW4 is also configured (per the lab reference). Saved to startup config. These ports will now immediately forward on link-up.

Real-world note: Be careful with interface range syntax — verify the selected interfaces to avoid accidental configuration on uplinks.

Verify:

show spanning-tree interface Ethernet0/2 detail
spanning-tree interface Ethernet0/2
  Port Type: Edge Port (PortFast)
  State: forwarding
  P2p Link
  PortFast: Enabled

Step 4: Create a pyATS testbed file (YAML)

What we are doing: Create a pyATS testbed YAML that lists the devices and management IPs so pyATS/Genie can connect via SSH and run commands. This file is the input to pyATS learn/diff operations.

testbed:
  name: lab-nhprep
  credentials:
    default:
      username: developer
      password: Lab@123
  devices:
    c9k-spine:
      os: iosxe
      type: router
      connections:
        cli:
          protocol: ssh
          ip: 198.18.1.21
    c9k-leaf1:
      os: iosxe
      type: router
      connections:
        cli:
          protocol: ssh
          ip: 198.18.1.31
    c9k-leaf2:
      os: iosxe
      type: router
      connections:
        cli:
          protocol: ssh
          ip: 198.18.1.32

What just happened: This YAML maps logical device names to OS, type, and management IPs. Credentials are set to connect via SSH with the developer account and the lab password Lab@123. pyATS will use this file to establish sessions and collect data.

Real-world note: Keep testbed files in source control. Use different credential sets for production vs. lab.

Verify: (Inspect the file on disk)

cat testbed.yaml
# Expected output (exact YAML content displayed)
testbed:
  name: lab-nhprep
  credentials:
    default:
      username: developer
      password: Lab@123
  devices:
    c9k-spine:
      os: iosxe
      type: router
      connections:
        cli:
          protocol: ssh
          ip: 198.18.1.21
    c9k-leaf1:
      os: iosxe
      type: router
      connections:
        cli:
          protocol: ssh
          ip: 198.18.1.31
    c9k-leaf2:
      os: iosxe
      type: router
      connections:
        cli:
          protocol: ssh
          ip: 198.18.1.32

Step 5: Capture a baseline snapshot with pyATS learn

What we are doing: Run a pyATS learn so that pyATS collects the current running state (interfaces, spanning-tree details, and some show outputs) from the devices. This snapshot becomes the "before" state for later comparison.

pyats learn testbed.yaml --output learn_before

What just happened: pyATS connected to devices listed in the testbed, executed a set of default operational commands (including show spanning-tree, show running-config snippets, and interface status), and stored the structured output into the directory learn_before. This snapshot contains the PortFast-enabled state we configured.

Real-world note: In large networks, learn may take time — narrow the command set or run in parallel groups to optimize.

Verify: (sample expected output summary)

ls -R learn_before
# Expected output:
learn_before/
learn_before/c9k-spine/
learn_before/c9k-spine/spanning_tree.json
learn_before/c9k-spine/interfaces.json
learn_before/c9k-spine/running_config.txt
learn_before/c9k-leaf1/
learn_before/c9k-leaf1/spanning_tree.json
learn_before/c9k-leaf1/interfaces.json
learn_before/c9k-leaf1/running_config.txt
learn_before/c9k-leaf2/
learn_before/c9k-leaf2/spanning_tree.json
learn_before/c9k-leaf2/interfaces.json
learn_before/c9k-leaf2/running_config.txt

Step 6: Introduce a deliberate change and capture another snapshot, then diff

What we are doing: Remove PortFast on a single interface (simulate drift or a bad change), capture a second snapshot with pyATS, and run a diff to highlight the change.

configure terminal
interface Ethernet1/0
no spanning-tree portfast
end
write memory

What just happened: PortFast was removed from Ethernet1/0 on the switch where it was intended to be an edge port. As a result, on the next link-up this port would pass through STP Listening and Learning phases and experience a delay before forwarding. This simulates a configuration drift or a mistaken change.

Real-world note: Using an automated diff helps you quickly detect such accidental removals across many devices.

Verify config change on device:

show spanning-tree interface Ethernet1/0 detail
spanning-tree interface Ethernet1/0
  Port Type: Normal Port
  State: forwarding
  PortFast: Disabled

Now run pyATS learn for the after state and diff:

pyats learn testbed.yaml --output learn_after
pyats diff learn_before learn_after --output diff_report.txt

What just happened: The second learn captured the state after the change. The diff command compared the two snapshots and produced a concise report that highlights the removal of PortFast on the specific interface.

Verify diff result: (sample expected diff snippet)

cat diff_report.txt
# Expected content:
Difference detected between learn_before and learn_after
Device: c9k-leaf1
  Object: spanning_tree.interfaces.Ethernet1/0
    Attribute: portfast
      learn_before: Enabled
      learn_after: Disabled
Summary: 1 significant difference detected (spanning-tree PortFast removed on Ethernet1/0)

Verification Checklist

  • Check 1: PortFast is enabled on SW1 and SW2 interfaces — verify with show spanning-tree interface Ethernet1/0 and observe PortFast: Enabled.
  • Check 2: PortFast enabled on SW3 and SW4 interface ranges — verify with show spanning-tree interface Ethernet0/2 and observe PortFast: Enabled.
  • Check 3: pyATS learn produced JSON/text snapshots in the learn_before and learn_after directories — verify by listing the directories.
  • Check 4: pyATS diff shows the specific PortFast removal — verify by inspecting the diff_report.txt content for the noted attribute change.

Common Mistakes

SymptomCauseFix
pyATS cannot SSH to device (connection refused)Wrong management IP or firewall blocking SSHVerify device mgmt IP (use 198.18.1.21/.31/.32), ensure SSH is enabled and network path exists
PortFast applied to uplink portsIncorrect interface-range selection or typo in rangeUse show running-config interface <int> to verify and remove PortFast from trunk/uplink ports with no spanning-tree portfast
pyATS learn returns incomplete data (missing spanning-tree)Testbed YAML omitted correct OS/type or wrong credentialsEnsure os: iosxe set and username/developer + password: Lab@123 are correct in testbed YAML
Diff shows many irrelevant differences (noise)Using broad command set or not normalizing snapshotsLimit the command set or normalize outputs; focus on specific structured parsers (spanning-tree) for stable comparisons

Key Takeaways

  • pyATS/Genie snapshots (learn) provide structured device state that can be versioned and compared to detect drift quickly.
  • PortFast changes have protocol-level impact: when disabled on edges, STP Listening/Learning will delay forwarding and can affect endpoint boot and DHCP times.
  • Always verify interface selections when using interface range commands — automation will replicate mistakes at scale if not carefully validated.
  • Incorporate learn/diff into deployment pipelines: capture a baseline, run changes, and immediately diff to catch unintended side effects before they reach production.

Final tip: Treat the testbed YAML and snapshot artifacts as first-class configuration items. Store them in source control and include them in automated validation to maintain network reliability.