[Day #15 PyATS Series] Building a Reusable Test Template for All Vendors using pyATS for Cisco – Python for Network Engineer

[Day #15 PyATS Series] Building a Reusable Test Template for All Vendors using pyATS for Cisco [Python for Network Engineer]


Introduction

Welcome to Day 15 of the 101 Days of pyATS (Vendor-Agnostic) journey. As a network engineer stepping into the world of automation, one of the first challenges you’ll face is code duplication. When you manage networks with multiple vendors—Cisco, Arista, Palo Alto, Fortinet—it’s common to write different test scripts for each device type.

This not only wastes time but makes your automation framework hard to maintain and scale.

This is where reusable test templates with pyATS become game-changers.

By the end of this guide, you’ll know how to:

  • Build a single test template that works across vendors
  • Abstract device-specific commands using Genie parsers
  • Validate device health and connectivity with one testscript
  • Scale tests to 1000+ devices without rewriting code

If you’re serious about becoming a Python for Network Engineer, understanding reusable templates will set you apart and prepare you for real-world, multi-vendor network automation.


Topology Overview

For this demonstration, imagine a typical enterprise network:

  • All devices have management IPs reachable from the pyATS controller.
  • Devices support SSH access.
  • Test scripts are executed centrally and connect to each device using the testbed.yaml file.
  • The goal is to run a single test template to:
    • Collect interface status
    • Perform ping reachability
    • Validate software version

Topology & Communications

  • Transport Protocol: SSH (for CLI commands)
  • Framework: pyATS with Genie parsers
  • Execution: pyATS AEtest testscript
  • Devices:
    • Cisco IOS-XE (router/switch)
    • Arista EOS (switch)
    • Palo Alto firewall
    • Fortinet firewall

pyATS handles communication via Unicon. With Genie, we can parse outputs into Python dictionaries, making test logic vendor-neutral.


Workflow Script – reusable_test_template.py

from pyats import aetest
from genie.testbed import load
from genie.utils import Dq

class CommonSetup(aetest.CommonSetup):
    @aetest.subsection
    def connect_to_devices(self, testbed):
        self.parent.parameters['testbed'] = load(testbed)
        for device in self.parent.parameters['testbed'].devices.values():
            device.connect(log_stdout=False)
            self.parent.parameters[device.name] = device

class InterfaceHealthTest(aetest.Testcase):
    @aetest.test
    def verify_interfaces(self, testbed):
        for device in testbed.devices.values():
            output = device.parse('show interface status')
            down_interfaces = Dq(output).contains('notconnect').get_values('interface')
            if down_interfaces:
                self.failed(f"Device {device.name} has down interfaces: {down_interfaces}")
            else:
                self.passed(f"All interfaces are up on {device.name}")

class PingReachabilityTest(aetest.Testcase):
    @aetest.test
    def ping_test(self, testbed):
        for device in testbed.devices.values():
            result = device.ping('8.8.8.8')
            if not result:
                self.failed(f"Ping failed from {device.name}")
            else:
                self.passed(f"Ping successful from {device.name}")

class SoftwareVersionTest(aetest.Testcase):
    @aetest.test
    def check_version(self, testbed):
        for device in testbed.devices.values():
            version_output = device.parse('show version')
            software_version = version_output.get('version') or version_output.get('os', 'unknown')
            print(f"{device.name} running software: {software_version}")
            if '15.' not in software_version and 'EOS' not in software_version:
                self.failed(f"Unexpected software version on {device.name}")
            else:
                self.passed(f"Valid software version on {device.name}")

class CommonCleanup(aetest.CommonCleanup):
    @aetest.subsection
    def disconnect_all(self, testbed):
        for device in testbed.devices.values():
            device.disconnect()

Explanation by Line

  • CommonSetup: Establishes connections to all devices once, reused by all tests.
  • InterfaceHealthTest: Uses Genie parse to fetch structured interface status, checking for notconnect.
  • PingReachabilityTest: Vendor-neutral ping method.
  • SoftwareVersionTest: Parses software version, ensuring compliance with desired releases.
  • CommonCleanup: Gracefully disconnects from devices.
  • Reusability: This single script can run across all vendors—no need to rewrite for each OS.

testbed.yml Example

devices:
  cisco_router:
    os: iosxe
    type: router
    connections:
      cli:
        protocol: ssh
        ip: 10.0.0.1
    credentials:
      default:
        username: admin
        password: cisco123

  arista_switch:
    os: eos
    type: switch
    connections:
      cli:
        protocol: ssh
        ip: 10.0.0.2
    credentials:
      default:
        username: admin
        password: arista123

  palo_alto_fw:
    os: panos
    type: firewall
    connections:
      cli:
        protocol: ssh
        ip: 10.0.0.3
    credentials:
      default:
        username: admin
        password: palo123

  fortigate_fw:
    os: fortinet
    type: firewall
    connections:
      cli:
        protocol: ssh
        ip: 10.0.0.4
    credentials:
      default:
        username: admin
        password: forti123

Post-validation CLI Screenshots (Expected Output)

After running:

pyats run job reusable_test_template.py --testbed testbed.yml

Sample console output:

Connecting to all devices...
All interfaces are up on cisco_router
Ping successful from cisco_router
Valid software version on cisco_router
---
All interfaces are up on arista_switch
Ping successful from arista_switch
Valid software version on arista_switch
---
All interfaces are up on palo_alto_fw
Ping successful from palo_alto_fw
Valid software version on palo_alto_fw
---
All interfaces are up on fortigate_fw
Ping successful from fortigate_fw
Valid software version on fortigate_fw

Test Result: PASSED for all devices

FAQs

Q1: What is the main benefit of using a reusable test template in pyATS?

A reusable template allows you to write a single test script that works across multiple vendors (Cisco, Arista, Palo Alto, Fortinet) without changing the logic for each device. It simplifies maintenance, scales easily to thousands of devices, and enforces standardized testing practices across your network automation framework.


Q2: How does pyATS handle different command outputs from different vendors?

pyATS uses Genie parsers that normalize raw CLI output into structured Python dictionaries. This means you can use the same script to run commands on different operating systems (IOS-XE, EOS, PAN-OS, FortiOS) without manually writing separate parsing logic.


Q3: Can I add or remove tests from the reusable template without affecting other parts of the script?

Yes. The template is modular, built with aetest.Testcase classes. You can easily add new test cases (e.g., CPU, memory checks) or remove existing ones without breaking other sections. This modular approach makes it highly adaptable for different testing needs.


Q4: How does the test template scale to 1000+ devices?

The reusable template, combined with a properly defined testbed.yml, allows pyATS to dynamically connect to multiple devices in parallel or sequentially. Since all devices are abstracted in the testbed, the script doesn’t need manual edits to handle large-scale networks.


Q5: What if a device OS is not officially supported by pyATS or Genie parsers?

If Genie doesn’t provide a parser for a certain OS or command, you can:

  • Use custom parsers in pyATS
  • Use raw CLI output and Python regex for temporary parsing
  • Submit contributions to Genie’s open-source parsers
    This flexibility ensures you can still integrate unsupported devices into your test template.

Q6: Can we integrate reusable templates with CI/CD pipelines?

Absolutely. Reusable pyATS templates are designed for automation pipelines. You can run them on Jenkins, GitLab CI/CD, or Ansible Tower, triggering them after configuration changes or scheduled intervals for continuous network validation.


Q7: How do we handle vendor-specific features in a generic template?

You can use conditional logic within the script (e.g., if device.os == 'iosxe') to handle commands or validations that only exist on a specific vendor. The rest of the script remains reusable for common checks like interface health or reachability.


Q8: Is this reusable template approach suitable for beginners learning Python for Network Engineers?

Yes. In fact, reusable templates reduce coding complexity by avoiding repeated scripts for each vendor. Beginners can focus on learning test structures, parsers, and validations without worrying about device-specific syntax, making it an ideal starting point for Python for Network Engineer learning paths.


YouTube Link

Watch the Complete Python for Network Engineer: Building a Reusable Test Template for All Vendors using pyATS for Cisco [Python for Network Engineer] Lab Demo & Explanation on our channel:

Master Python Network Automation, Ansible, REST API & Cisco DevNet
Master Python Network Automation, Ansible, REST API & Cisco DevNet
Master Python Network Automation, Ansible, REST API & Cisco DevNet
Why Robot Framework for Network Automation?

Join Our Training

Mastering pyATS and building scalable, reusable test frameworks is a must-have skill for modern network engineers.

Trainer Sagar Dhawan runs a 3-month instructor-led training program that teaches:

  • Python for Network Engineers
  • pyATS testing and reusable framework design
  • Multi-vendor automation with Genie parsers
  • Building CI/CD pipelines for network testing
  • Real-world labs with Cisco, Arista, Palo Alto, and Fortinet devices

Turn yourself into a network automation expert – learn by doing, not theory.

Enroll now: https://course.networkjourney.com/python-ansible-api-cisco-devnet-for-network-engineers

Make your scripts vendor-agnostic, scalable, and production-ready with Python for Network Engineer best practices.

Enroll Now & Future‑Proof Your Career
Emailinfo@networkjourney.com
WhatsApp / Call: +91 97395 21088