Cisco pyATS testbed is a YAML representation of your network’s topology. It defines the devices, their connection details (such as IP addresses and credentials), and optionally their interface connectivities.

It is called a testbed because it serves as a foundational configuration for automated testing and validation of network infrastructures. However, if device connectivities are ignored, it functions similarly to an inventory in other automation tools like Netmiko and Scrapli in Nornir.

Cisco pyATS Testbed Fundamental

Cisco pyATS Testbed definition

The Cisco pyATS testbed functions similarly to an inventory in other automation tools, particularly in the way it’s used during the course.

what is cisco pyATS testbed
what is cisco pyATS testbed

It provides a structured listing of network devices, but its capabilities go beyond that. The testbed can also include additional details, such as the network topology, which defines how devices are interconnected. This information becomes valuable when running automated test cases, as it allows for monitoring the status of device links, verifying connectivity, and assessing traffic flow across these links.

The testbed, therefore, serves not only as an inventory but also as a dynamic framework for testing and validating the health and performance of network infrastructures.

comprehensive Testbed example in cisco pyATS

This is an example testbed from the Cisco pyATS documentation, which includes network servers such as a file server and an NTP server, along with a list of devices and their connectivity topology.

While this example showcases a comprehensive testbed with various network elements, what we primarily use during the course is a simplified inventory.

This inventory typically contains the list of devices, how to connect to each device, and the necessary credentials for establishing those connections.

Example Testbed File
Example Testbed File

pyATS Testbed Structure

This is a simple sample testbed file that includes only the “devices” section, featuring two devices: R1 and R2. The “connections” method used is “cli”, although other popular options such as “rest” and “netconf” are also available. In this lesson, we will look at a sample for each of these methods. A device can support multiple connection types.

The “credentials” section defines the “username” and “password” used to authenticate when connecting to each device. Additionally, you can specify an “enable” password if required to access privileged modes on the device.

The “os” field specifies the device’s operating system. Some common options include iosxr, iosxe, ios, nxos, and linux, among others.

---
devices:
  R1:
    connections:
      cli:
        ip: 192.168.2.91
        protocol: ssh
    credentials:
      default:
        password: rayka-co.com
        username: rayka
    os: iosxe
    type: iosxe
  R2:
    connections:
      cli:
        ip: 192.168.2.92
        protocol: ssh
    credentials:
      default:
        password: rayka-co.com
        username: rayka
    os: iosxe
    type: iosxe

Check and Validate the Syntax and Format of Testbed YAML Files

It’s a good idea to check both the syntax of your YAML file and the validity of your testbed file before using them.

To check the syntax of the YAML file, we use yamllint. You can install it with the following command:

pip install yamllint

After installation, run the following command to check the syntax of your testbed.yaml file:

yamllint testbed.yaml

If no output is displayed, it means the syntax is correct. Otherwise, you will receive an error indicating where the issue is.

In addition, you can validate the format and syntax of the testbed file using the pyats validate testbed command.

(majid) root@majid-ubuntu:/home/majid/devnet/pyats# pyats validate testbed testbed-cli.yaml
...
Loading testbed file: testbed-cli.yaml
--------------------------------------------------------------------------------

Testbed Name:
    testbed-cli

Testbed Devices:
.
|-- R1 [iosxe/iosxe]
`-- R2 [iosxe/iosxe]

YAML Lint Messages
------------------

Warning Messages
----------------
 - Device 'R1' has no interface definitions
 - Device 'R2' has no interface definitions

pyATS Testbed Connection Methods

CLI is not the only method for connecting to network devices—REST API and NETCONF are two other widely used methods in network automation.

Connection Method Description Commonly Supported By Data Format
SSH (CLI) Sends traditional CLI commands for automation Most Cisco devices (routers, switches, firewalls, ISE) Text (CLI output)
NETCONF Uses YANG-based structured data exchange Cisco routers, switches, ACI (partially) XML
REST API Uses web-based API calls for automation Cisco ACI, Cisco ISE, Cisco DNA Center, modern Cisco devices JSON (mostly), XML (sometimes)

Many devices, such as Cisco routers and switches, support all three methods (CLI over SSH, NETCONF, and REST API) for automation. However, some platforms, like Cisco ACI, primarily support REST API and NETCONF but do not provide CLI-based automation via SSH.

Beyond connection methods, the automation approach also differs In some other aspects:

  • SSH automation relies on sending CLI commands.

  • NETCONF and REST API use structured data models (YANG).

    • NETCONF typically exchanges data in XML format.

    • REST API usually uses JSON format.

Due to these differences, you may need to use multiple connection methods when automating test cases in pyATS or similar frameworks, depending on the device or platform.

Here, you can see testbeds using different connection methods (CLI, NETCONF, and REST API).

---
devices:
  R1:
    connections:
      cli:
        ip: 192.168.2.91
        protocol: ssh
    credentials:
      default:
        password: rayka-co.com
        username: rayka
    os: iosxe
    type: iosxe
  R2:
    connections:
      cli:
        ip: 192.168.2.92
        protocol: ssh
    credentials:
      default:
        password: rayka-co.com
        username: rayka
    os: iosxe
    type: iosxe
---
devices:
  R1:
    os: iosxe
    type: router
    connections:
      rest:
        class: rest.connector.Rest
        ip: 192.168.2.91
        port: 443
        verify: False
        credentials:
          rest:
            username: rayka
            password: rayka-co.com
---
devices:
  R1:
    os: iosxe
    type: router
    connections:
      netconf:
        class: 'yang.connector.Netconf'
        protocol: ssh
        ip: 192.168.2.91
        port: 830
        credentials:
          default:
            username: rayka
            password: rayka-co.com

Check Testbed Connectivity

The first step after creating a testbed is to ensure that connectivity to the devices configured within the testbed can be successfully established.
To test connectivity, the simplest approach is to write a small script that loads the testbed and attempts to connect to one or more devices.

Below is a sample script that demonstrates how to connect to a single device configured in the testbed using the CLI method:

By using via='cli' in the device.connect command, we specify the connection method to be used. Other options include device.connect(via='rest') and device.connect(via='netconf'), which allow connecting via REST API or NETCONF, respectively.

# Import the loader module from pyATS to handle testbed files
from pyats.topology import loader

# Load the testbed configuration from the specified YAML file
# This file defines the devices and their connection details
testbed = loader.load('2.1.testbed-cli.yaml')

# Access the device named 'R1' from the testbed
# 'R1' should be defined in the testbed YAML file with its connection parameters
device = testbed.devices['R1']

# Establish a CLI (Command-Line Interface) connection to 'R1'
# This uses the connection details specified in the testbed file
device.connect(via='cli')

# Perform desired operations on the device here
# For example, you can execute commands or retrieve information

# Disconnect the CLI session to 'R1'
# It's important to close the connection after operations are complete
device.disconnect()

The result indicates that the Unicon IOS-XE plugin is being used to connect to the devices.

Unicon is a connection management library developed by Cisco for pyATS and genie. It handles the establishment and management of network device connections, as well as executing commands on those devices. In upcoming lessons, we will discuss more about Unicon.

(majid) root@majid-ubuntu:/home/majid/devnet/pyats# python test-cli.py

2025-03-08 03:24:53,160: %UNICON-INFO: +++ R1 logfile /tmp/R1-cli-20250308T032453160.log +++

2025-03-08 03:24:53,161: %UNICON-INFO: +++ Unicon plugin iosxe (unicon.plugins.iosxe) +++


2025-03-08 03:24:53,679: %UNICON-INFO: +++ connection to spawn: ssh -l majid 10.13.14.16, id: 129709476506240 +++

2025-03-08 03:24:53,680: %UNICON-INFO: connection to R1
(majid@10.13.14.16) Password:



R1#

R1#

2025-03-08 03:24:53,886: %UNICON-INFO: +++ R1 with via 'cli': executing command 'show version | include operating mode' +++
show version | include operating mode
R1#

Similarly, these are sample scripts demonstrating how to connect to devices using REST API and NETCONF.

import logging
import urllib3
from pyats.topology import loader
import warnings

warnings.filterwarnings("ignore", message="default_tokens is a deprecated argument")
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
logging.basicConfig(level=logging.DEBUG)

testbed = loader.load('testbed-rest.yaml')
device = testbed.devices['R1']
device.connect(via='rest')
device.rest.disconnect()
import logging
from pyats.topology import loader

logging.basicConfig(level=logging.DEBUG)

testbed = loader.load('testbed-netconf.yaml')
device = testbed.devices['R1']
device.connect(via='netconf')
device.netconf.disconnect()

Avoid Clear Text Password in Testbed

In a real production environment, it is generally not recommended to store clear-text passwords in the testbed file. There are multiple methods to avoid this, but one of the best approaches is to use environment variables and dynamically set the credentials in a Python script.

With this approach, the testbed file itself does not contain the actual password. Instead, we leave the credentials field to be configured at runtime. This ensures better security while maintaining flexibility.

Here is the proper way to handle credentials securely in a pyATS testbed by leveraging environment variables instead of storing passwords in plain text.

Step 1: Define the Testbed File Without Credentials

Since the credentials field is mandatory, we include it in the testbed file but leave the values empty.

---
devices:
  R1:
    connections:
      cli:
        ip: 192.168.2.91
        protocol: ssh
    credentials: {}
    os: iosxe
    type: iosxe

Step 2: Set Credentials Using Environment Variables

In Linux, use the export command to define environment variables for the username and password:

export USERNAME="rayka"
export PASSWORD="rayka-co.com"

This prevents passwords from being stored in configuration files.

Step 3: Use Python to Inject Credentials

In the Python script, we use os.getenv to read environment variables and set the credentials dynamically.

import os
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
device.credentials["default"] = {"username": username, "password": password}
Back to: Network Automation with pyATS & Genie (in Progress) > pyATS Introduction

Leave a Reply

Your email address will not be published. Required fields are marked *


Post comment