Главная

Sunday, 1 January 2023

Тестирование инфраструктуры c pyATS #3.

Всем привет. 

Продолжаю нашу тему фреймворков для тестирования инфраструктры. Сегодня мой пост является беглым отчетом по выполнению работы "7.6.3 Lab - Automated Testing Using pyATS and Genie" из Cisco DevNet.

Знакомтесь - pyATS (https://developer.cisco.com/pyats/). Это экосистема сквозного тестирования, изначально разработанная компанией Cisco и ставшая открытой в конце 2017 года. Ранее библиотека pyATS называлась Genie; эти названия используются в одном и том же контексте. Ввиду своего происхождения этот фреймворк целиком и полностью ориентирован на тестирование сетей.

Фреймворк доступен в PyPI:

(venv) $ pip install pyats[full]

Для начала рассмотрим некоторые демонстрационные сценарии из GitHub-репозитория:

git clone https://github.com/CiscoTestAutomation/examples

Мы сходу можем прогнать тест-пустышку чтобы оценить как все происходит:

pyats run job examples/basic/basic_example_job.py

Следом можно охватить отчетность по всем проведенным PyATS-тестам в формате HTML:

pyats logs view

P.S.: имейте ввиду - порт web-сервера отчетов динамический.


Ок, реальные тесты начинаются с создания файла испытательной модели (testbed) в формате YAML. Создадим простой testbed-файл testbed-pyats.yml для нашего устройства CSR1000v. Он похож на файл реестра hosts, знакомый нам от Ansible:

testbed: 

    name: pyATS

    credentials:

        default:

            username: admin

            password: super

        enable:

            password: super


devices:

    CSR: 

        alias: CSR

        type: iosxe

        connections:

            defaults:

                class: unicon.Unicon  

            vty:

                ip: 192.168.1.19

                protocol: ssh -o KexAlgorithms=diffie-hellman-group14-sha1

В нашем первом сценарии, pyats_1.py, мы загрузим testbed-файл, подключимся к устройству, выполним команду show version и затем отключимся от устройства:

from pyats.topology import loader

# load testbed

testbed = loader.load('yaml/testbed-pyats.yml')

# access the device

testbed.devices

ios_1 = testbed.devices['CSR']

# establish connectivity

ios_1.connect()

# issue command

print(ios_1.execute('show version'))

# disconnect

ios_1.disconnect()


Запустив этот сценарий, мы увидим смесь из сообщений о подготовке pyATS и вывода самого устройства. Это похоже на сценарии Paramiko, которые мы видели ранее, но в данном случае соединение устанавливает pyATS:

(venv) $ python pyats_1.py

[2019-11-10 08:11:55,901] +++  CSR logfile /tmp/ CSR-default-

20191110T081155900.log +++

[2019-11-10 08:11:55,901] +++ Unicon plugin generic +++

<опущено>

[2019-11-10 08:11:56,249] +++ connection to spawn: ssh -l cisco

172.16.1.20, id: 140357742103464 +++

[2019-11-10 08:11:56,250] connection to  CSR

[2019-11-10 08:11:56,314] +++ initializing handle +++

[2019-11-10 08:11:56,315] +++  CSR: executing command 'term length 0' +++

term length 0  CSR#

[2019-11-10 08:11:56,354] +++  CSR: executing command 'term width 0' +++

term width 0  CSR#

[2019-11-10 08:11:56,386] +++  CSR: executing command 'show version' +++

show version

<опущено>


Второй пример более развернутый. Он включает настройку и установку соединения, сами тесты и последующее отключение от устройства. В сценарии pyats_2.py используются различные декораторы из модуля aetest, входящего в состав pyATS. Помимо методов подготовки и очистки, в классе PingTestCase имеется тест ping:

from pyats import aetest

import re

class CommonSetup(aetest.CommonSetup):

    @aetest.subsection

    def establish_test(self, testbed, iosv1_name = 'CSR'):

        ios1 = testbed.devices[iosv1_name]

        self.parent.parameters.update(ios1 = ios1)


    @aetest.subsection

    def establish_connections(self, steps, ios1):

        with steps.start('Connecting to %s' % ios1.name):

            ios1.connect()


@aetest.loop(device = ('ios1',))


class PingTestcase(aetest.Testcase):

    @aetest.test.loop(destination = ('192.168.1.180','192.168.1.3'))

    def ping(self, device, destination):

        try:

            result = self.parameters[device].ping(destination)

        except Exception as e:

            self.failed('Ping {} from device {} failed with error: {}'.format(

                                destination,

                                device,

                                str(e),

                            ),

                        goto = ['exit'])

        else:

            match = re.search(r'Success rate is (?P<rate>\d+) percent', result)

            success_rate = match.group('rate')


class CommonCleanup(aetest.CommonCleanup):

    @aetest.subsection

    def disconnect(self, steps, ios1):

        with steps.start('Disconnecting from %s' % ios1.name):

            ios1.disconnect()


if __name__ == '__main__':

    import argparse

    from pyats.topology import loader

    parser = argparse.ArgumentParser()

    parser.add_argument('--testbed', dest = 'testbed', type = loader.load)

    args, unknown = parser.parse_known_args()

    aetest.main(**vars(args))


На практике предпочтительнее передавать testbed-файл как аргумент командной строки:

(venv) $ python pyats_2.py --testbed testbed_pyats.yml

Вывод этого сценария похож на тот, что мы видели в предыдущем примере, если не считать дополнительных разделов STEPS Report и Detailed Results в каждом тесте. В выводе также указано имя журнального файла, сохраненного в каталоге /tmp:


Фреймворк pyATS отлично подходит для автоматизированного тестирования. Но, учитывая его происхождение, ему не хватает поддержки других производителей, окромя Cisco.

Мы еще можем использовать фреймворк Genie которая позволяет парсить вывод IOS в формате JSON. Если вы ставили PyATS то Genie у вас уже присутствует. Также Genie  позволяет  зашифровать пароли в testbed. Первое что мы сделаем это создадим новый testbed в диалоговом режиме:

genie create testbed interactive --output yaml/testbed.yml --encode-password

где

  • Device hostname - имя нашего подопытного устройства, мое CSR
  • IP address - его IPv4 address
  • Username - local username used for ssh
  • Default password - local password used for ssh
  • Enable password - у меня совпадает с default
  • Protocol - указываю SSH
  • OS - указываю iosxe.


Мы получим в итоге файлик yaml/testbed.yml такого содержания:

devices:

  CSR:

    connections:

      cli:

        ip: 192.168.1.19

        protocol: ssh -o KexAlgorithms=diffie-hellman-group14-sha1

    credentials:

      default:

        password: '%ENC{w53DmsOUw6jDmMOR}'

        username: admin

      enable:

        password: '%ENC{w53DmsOUw6jDmMOR}'

    os: iosxe

    type: iosxe


Далее можем запросить что угодно с CSR. Собственно вы можете видеть что Genie пересылает 

наши команды устройству и читает ответы на них:

genie parse "show ip interface brief" --testbed-file yaml/testbed.yml --devices CSR

или

genie parse "show version" --testbed-file yaml/testbed.yml --devices CSR


Еще одна полезная возможность это сравнивать конфигурации До и После. Переведем вывод запроса в файл:

genie parse "show ipv6 interface gig 1" --testbed-file yaml/testbed.yml --devices CSR --output verify-ipv6-1

Что-то поменяем в ipv6 и выполним запрос еще раз:

genie parse "show ipv6 interface gig 1" --testbed-file yaml/testbed.yml --devices CSR --output verify-ipv6-2

А теперь смотрим разницу:

genie diff verify-ipv6-1 verify-ipv6-2


На десерт - существует еще один открытый инструмент для проверки сетей Batfish от IntentionNet (https://github.com/batfish/batfish).  Его прямое назначение - проверка изменений в конфигурации перед развертыванием. И он может цепляться не только к Cіsco!)

Вот собственно и все. Пользуйтесь и удачи.

1 comment:

А что вы думаете по этому поводу?