Начало работы с 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 <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.3R8/junos">     <stp-interface-information>         <stp-instance>             <instance-id>0</instance-id>             <stp-interfaces junos:style="brief">                 <stp-interface-entry>                     <interface-name>ge-0/0/23.0</interface-name>                     <port-number junos:format="128:536">                         536                     </port-number>                     <port-priority>128</port-priority>                     <designated-port-number junos:format="128:536">                         536                     </designated-port-number>                     <designated-port-priority>128</designated-port-priority>                     <port-cost>20000</port-cost>                     <port-state>DIS</port-state>                     <designated-bridge-mac junos:format="32768.54e032fdeb41">                         54e032fdeb41                     </designated-bridge-mac>                     <designated-bridge-priority>32768</designated-bridge-priority>                     <port-role>DIS</port-role>                 </stp-interface-entry>                 <stp-interface-entry>                     <interface-name>xe-0/1/0.0</interface-name>                     <port-number junos:format="128:561">                         561                     </port-number>                     <port-priority>128</port-priority>                     <designated-port-number junos:format="128:691">                         691                     </designated-port-number>                     <designated-port-priority>128</designated-port-priority>                     <port-cost>2000</port-cost>                     <port-state>FWD</port-state>                     <designated-bridge-mac junos:format="32768.3c94d5902981">                         3c94d5902981                     </designated-bridge-mac>                     <designated-bridge-priority>32768</designated-bridge-priority>                     <port-role>ROOT</port-role>                 </stp-interface-entry>                 <stp-interface-entry>                     <interface-name>xe-0/1/2.0</interface-name>                     <port-number junos:format="128:563">                         563                     </port-number>                     <port-priority>128</port-priority>                     <designated-port-number junos:format="128:563">                         563                     </designated-port-number>                     <designated-port-priority>128</designated-port-priority>                     <port-cost>2000</port-cost>                     <port-state>FWD</port-state>                     <designated-bridge-mac junos:format="32768.54e032fdeb41">                     <designated-port-priority>128</designated-port-priority>                     <port-cost>20000</port-cost>                     <port-state>DIS</port-state>                     <designated-bridge-mac junos:format="32768.54e032fdeb41">                         54e032fdeb41                     </designated-bridge-mac>                     <designated-bridge-priority>32768</designated-bridge-priority>                     <port-role>DIS</port-role>                 </stp-interface-entry>                 <stp-interface-entry>                     <interface-name>xe-0/1/0.0</interface-name>                     <port-number junos:format="128:561">                         561                     </port-number>                     <port-priority>128</port-priority>                     <designated-port-number junos:format="128:691">                         691                     </designated-port-number>                     <designated-port-priority>128</designated-port-priority>                     <port-cost>2000</port-cost>                     <port-state>FWD</port-state>                     <designated-bridge-mac junos:format="32768.3c94d5902981">                         3c94d5902981                     </designated-bridge-mac>                     <designated-bridge-priority>32768</designated-bridge-priority>                     <port-role>ROOT</port-role>                 </stp-interface-entry>                 <stp-interface-entry>                     <interface-name>xe-0/1/2.0</interface-name>                     <port-number junos:format="128:563">                         563                     </port-number>                     <port-priority>128</port-priority>                     <designated-port-number junos:format="128:563">                         563                     </designated-port-number>                     <designated-port-priority>128</designated-port-priority>                     <port-cost>2000</port-cost>                     <port-state>FWD</port-state>                     <designated-bridge-mac junos:format="32768.54e032fdeb41">                         54e032fdeb41                         </designated-bridge-mac>                     <designated-bridge-priority>32768</designated-bridge-priority>                     <port-role>DESG</port-role>                 </stp-interface-entry>             </stp-interfaces>         </stp-instance>     </stp-interface-information>     <cli>         <banner>{master:0}</banner>     </cli> </rpc-reply>  {master:0} 

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

YAML

Вернемся к полученному XML. Нас интересуют элементы <stp-interface-entry> и входящие в них <interface-name>, <port-state> и <port-role>. Чтобы получить доступ к этим элементам, нужно определить таблицу и выборку. Это делается в отдельном 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 

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

  • STPInterfaces — название таблицы. Может быть любым.
  • rpc — команда, посылаемая устройству. Можно посмотреть с помощью display-фильтра xml rpc в Junos CLI:
    dteslya@SW1> show spanning-tree interface | display xml rpc  <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.3R8/junos">     <rpc>         <get-stp-bridge-interface-information>         </get-stp-bridge-interface-information>     </rpc>     <cli>         <banner>{master:0}</banner>     </cli> </rpc-reply> 
  • item — интересующий элемент таблицы. Указывается с помощью XPath относительно первого элемента следующего после тэга <rpc-reply>, т.е. <stp-interface-information> в нашем случае.
  • key — ключ, с помощью которого можно ссылаться на интересующие записи в таблице. В нашем случае ключем будет <interface-name>.
  • view — ссылка на выборку, которая извлекает данные из элемента таблицы, определенного ранее.
  • STPInterfacesView — название выборки. Может быть любым.

Наконец, в 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.

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

ссылка на оригинал статьи http://habrahabr.ru/post/261775/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *