Начало работы с Junos PyEZ

Сейчас очень популярна тема сетевой автоматизации. Одним из инструментов такой автоматизации в мире Juniper является библиотека PyEZ, разрабатываемая командой Джереми Шульмана (Jeremy Schulman). PyEZ — это микро-фреймворк для удаленного управления и автоматизации устройств Juniper, написанный на языке Python. Основным преимуществом PyEZ является его простота и нацеленность на аудиторию сетевых инженеров, а не программистов.

Некоторые возможности PyEZ:

  • Сбор «фактов», таких как серийный номер, версия ОС и т.д.
  • Извлечение оперативной (аналог команд show) информации
  • Извлечение конфигурации
  • Изменение конфигурации


В этой статье я бы хотел остановиться на возможности извлечения оперативной информации на примере коммутатора EX4200.

Подготовка к работе


  1. Установка самого фреймворка сводится к одной команде:
    pip install junos-eznc
    
    

    На моей Ubuntu 14.04 все установилось без проблем, но если вдруг — рекомендую почитать официальную вики-страничку.
  2. Для доступа на сетевые устройства PyEZ использует протокол NETCONF, который необходимо включить.
    set system services netconf ssh
    
    

    NETCONF в свою очередь работает поверх SSH, поэтому убедитесь что SSH настроен и создана учетная запись для доступа на устройство.

На данном этапе все должно быть готово к работе. Для проверки можно попробовать подключиться к устройству и снять базовую информацию.

dteslya@ubuntu:~$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pprint import pprint
>>> from jnpr.junos import Device
>>> dev = Device(host='1.2.3.4')   
>>> dev
Device(1.2.3.4)
>>> dev.open()
Device(1.2.3.4)
>>> pprint(dev.facts)
{'2RE': True,
 'HOME': '/var/home/dteslya',
 'RE0': {'last_reboot_reason': 'Router rebooted after a normal shutdown.',
         'mastership_state': 'master',
         'model': 'EX4200-24F',
         'status': 'OK',
         'up_time': '2 days, 3 hours, 34 minutes, 40 seconds'},
 'domain': None,
 'fqdn': 'SW1',
 'hostname': 'SW1',
 'ifd_style': 'SWITCH',
 'master': 'RE0',
 'model': 'EX4200-24F',
 'personality': 'SWITCH',
 'serialnumber': '',
 'switch_style': 'VLAN',
 'vc_capable': True,
 'version': '12.3R8.7',
 'version_RE0': '12.3R8.7',
 'version_info': junos.version_info(major=(12, 3), type=R, minor=8, build=7)}
>>> dev.close()
>>>

Поясню, что здесь происходит. Сначала импортируются два класса: стандартный pprint для форматированного вывода и Device из библиотеки PyEZ. Далее объявляется само устройство, к которому будем подключаться. При объявлении устройства достаточно указать только IP-адрес, тогда будет применена аутентификация по ключу, а имя пользователя будет взято из переменной среды $USER. Опционально можно указать имя пользователя и пароль для аутентицикации по паролю (подробнее опять же на вики). Затем идет подключение к устройству и сбор «фактов», которые выводятся с помощью pprint, после чего подключение закрывается.

Теперь можно перейти к более интересным примерам использования PyEZ.

Постановка задачи


Рассмотрим задачу опроса коммутаторов и снятия информации о топологии Spanning Tree. Грубо говоря, нужно пройтись по коммутаторам и вывести список портов каждого коммутатора с указанием состояния STP.

Junos CLI


Посмотрим как получить такую информацию используя CLI.

dteslya@SW1> show spanning-tree interface    

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/23.0    128:536      128:536  32768.54e032fdeb41     20000  DIS    DIS  
xe-0/1/0.0     128:561      128:691  32768.3c94d5902981      2000  FWD    ROOT 
xe-0/1/2.0     128:563      128:563  32768.54e032fdeb41      2000  FWD    DESG 

{master:0}

Junos XML


Теперь посмотрим, как это выглядит «на самом деле», т.е. в XML.

show spanning-tree interface | display xml
dteslya@SW1> show spanning-tree interface | display xml

    
        
            0
            
                
                    ge-0/0/23.0
                    
                        536
                    
                    128
                    
                        536
                    
                    128
                    20000
                    DIS
                    
                        54e032fdeb41
                    
                    32768
                    DIS
                
                
                    xe-0/1/0.0
                    
                        561
                    
                    128
                    
                        691
                    
                    128
                    2000
                    FWD
                    
                        3c94d5902981
                    
                    32768
                    ROOT
                
                
                    xe-0/1/2.0
                    
                        563
                    
                    128
                    
                        563
                    
                    128
                    2000
                    FWD
                    
                    128
                    20000
                    DIS
                    
                        54e032fdeb41
                    
                    32768
                    DIS
                
                
                    xe-0/1/0.0
                    
                        561
                    
                    128
                    
                        691
                    
                    128
                    2000
                    FWD
                    
                        3c94d5902981
                    
                    32768
                    ROOT
                
                
                    xe-0/1/2.0
                    
                        563
                    
                    128
                    
                        563
                    
                    128
                    2000
                    FWD
                    
                        54e032fdeb41    
                    
                    32768
                    DESG
                
            
        
    
    
        {master:0}
    


{master:0}


Тут стоит сделать отступление и рассказать о подходе, используемом PyEZ для извлечения конфигурационной и оперативной (running state) информации из устройств. Для этого вводятся понятия таблиц (Tables) и выборок (Views). Если проводить аналогию с базами данных, то в Junos существует «оперативная база данных», которая состоит из набора таблиц. Например, командой show route можно посмотреть таблицу маршрутизации, а командой show interfaces — таблицу интерфейсов. В свою очередь Views, т.е. выборки, это способ представления информации из таблиц. Например, show route protocol ospf покажет только маршруты полученные по OSPF, т.е. выборку из всей таблицы маршрутизации.

YAML


Вернемся к полученному XML. Нас интересуют элементы и входящие в них , и. Чтобы получить доступ к этим элементам, нужно определить таблицу и выборку. Это делается в отдельном YAML-файле.

---
STPInterfaces:
  rpc: get-stp-bridge-interface-information
  item: stp-instance/stp-interfaces/stp-interface-entry
  key: interface-name
  view: STPInterfacesView
  
STPInterfacesView:
  fields:
    state: port-state
    role: port-role

Пройдемся по содержимому:


Наконец, в STPInterfacesView определяем интересующие поля.

На мой взгляд, правильно составить YAML-файл — это самое сложное во всем описываемом процессе. Очень рекомендую почитать туториал по XPath.

Python shell


Теперь посмотрим, как это можно использовать в Python. Предположим, что YAML-файл был сохранен как stp.yml.

Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from jnpr.junos import Device
>>> from jnpr.junos.factory import loadyaml
>>> yml_file = "stp.yml"
>>> globals().update(loadyaml(yml_file))
>>> dev = Device(host='1.2.3.4')
>>> dev.open()
Device(1.2.3.4)
>>> tbl = STPInterfaces(dev)
>>> tbl.get()
STPInterfaces:1.2.3.4: 3 items
>>> for key in tbl:
...     print key.name, key.role, key.state
... 
ge-0/0/23.0 DIS DIS
xe-0/1/0.0 ROOT FWD
xe-0/1/2.0 DESG FWD
>>> dev.close()
>>>


Получаем тот же список портов, как и в CLI.

Полезные ссылки:


© Habrahabr.ru