API Python для Juniper Networks

Узнайте о сетях Juniper и PyEZ в этом гостевом посте Эрика Чоу, автора книги Освоение сети Python — второе издание.

Сети Juniper всегда были фаворитом среди поставщиков услуг. Если вы посмотрите на вертикаль поставщиков услуг, будет понятно, что автоматизация сетевого оборудования находится в верхней части списка их требований. До появления облачных центров обработки данных у поставщиков услуг было больше всего сетевого оборудования.

Типичная корпоративная сеть может иметь несколько избыточных подключений к Интернету в штаб-квартире корпорации с несколькими удаленными узлами, соединенными со штаб-квартирой с помощью частной сети MPLS поставщика услуг. Для поставщика услуг именно они должны создавать, предоставлять, управлять и устранять неполадки в соединениях и базовых сетях.

Они зарабатывают деньги, продавая полосу пропускания вместе с управляемыми услугами с добавленной стоимостью. Для поставщиков услуг было бы разумно инвестировать в автоматизацию, чтобы использовать наименьшее количество инженерных часов, чтобы сеть продолжала работать. В случае их использования сетевая автоматизация является ключом к их конкурентному преимуществу.

Разница между сетевыми потребностями поставщика услуг и облачным центром обработки данных заключается в том, что традиционно поставщики услуг объединяют больше услуг в одном устройстве. Хорошим примером может служить многопротокольная коммутация по меткам (MPLS), которую предоставляют почти все основные поставщики услуг, но редко адаптируют в сетях предприятий или центров обработки данных. Компания Juniper определила эту потребность и преуспела в выполнении требований поставщиков услуг по автоматизации.

В этой статье вы познакомитесь с некоторыми API-интерфейсами автоматизации Juniper.

Juniper и NETCONF

Протокол конфигурации сети (NETCONF) является стандартом IETF, который был впервые опубликован в 2006 году как RFC 4741, а затем пересмотрен в RFC 6241. Сети Juniper внесли большой вклад в оба стандарта RFC. Фактически, Juniper был единственным автором RFC 4741. Понятно, что устройства Juniper полностью поддерживают NETCONF, и он служит базовым уровнем для большинства его инструментов автоматизации и сред. Некоторые из основных характеристик NETCONF включают следующее:

  1. Он использует расширяемый язык разметки (XML) для кодирования данных.
  2. Он использует удаленные вызовы процедур (RPC). Поэтому в случае использования HTTP в качестве транспорта конечная точка URL-адреса идентична, а предполагаемая операция указывается в теле запроса.
  3. Концептуально он основан на слоях сверху вниз. Слои включают контент, операции, сообщения и транспорт:
    1.PNG

Сети Juniper обеспечивают обширную Руководство разработчика протокола управления NETCONF XML в своей технической библиотеке. Пришло время взглянуть на его использование.

Подготовка устройства

Чтобы начать использовать NETCONF, создайте отдельного пользователя, а также включите необходимые службы:

set system login user netconf uid 2001
    set system login user netconf class super-user
    set system login user netconf authentication encrypted-password
     "$1$0EkA.XVf$cm80A0GC2dgSWJIYWv7Pt1"
    set system services ssh
    set system services telnet
    set system services netconf ssh port 830

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

netconf@foo> show configuration | display set
    set version 12.1R1.9
    set system host-name foo
    set system domain-name bar
<omitted>

Формат XML удобен, когда вам нужно увидеть XML-структуру конфигурации:

netconf@foo> show configuration | display xml
<rpc-reply xmlns:junos="
<configuration junos:commit-seconds="1485561328"junos:commit-
localtime="2017-01-27 23:55:28 UTC"junos:commit-user="netconf">
<version>12.1R1.9</version>
<system>
<host-name>foo</host-name>
<domain-name>bar</domain-name>

Теперь вы готовы рассмотреть свой первый пример Juniper NETCONF.

Примеры Juniper NETCONF

Вот довольно простой пример выполнения show version. Назовите этот файл junos_netconf_1.py:

#!/usr/bin/env python3

  from ncclient import manager

  conn = manager.connect(
      host="192.168.24.252",
      port="830",
      username="netconf",
      password='juniper!',
      timeout=10,
      device_params={'name':'junos'},
      hostkey_verify=False)

  result = conn.command('show version', format="text")
  print(result)
  conn.close_session()

Все поля в скрипте должны говорить сами за себя, за исключением device_params. Начиная с ncclient 0.4.1, был добавлен обработчик устройств для указания разных поставщиков или платформ. Например, имя может быть Juniper, CSR, Nexus или Huawei. Вы также добавили hostkey_verify=False, поскольку используете самозаверяющий сертификат с устройства Juniper.

Возвращаемый результат — это rpc-reply, закодированный в XML с выходным элементом:

<rpc-reply message-id="urn:uuid:7d9280eb-1384-45fe-be48-
    b7cd14ccf2b7">
<output>
Hostname: foo
    Model: olive
    JUNOS Base OS boot [12.1R1.9]
    JUNOS Base OS Software Suite [12.1R1.9]
<omitted>
    JUNOS Runtime Software Suite [12.1R1.9]
    JUNOS Routing Software Suite [12.1R1.9]
</output>
</rpc-reply>

Вы можете проанализировать вывод XML, чтобы просто включить выходной текст:

print(result.xpath('output')[0].text)

В junos_netconf_2.py вы можете внести изменения в конфигурацию устройства. Начните с некоторых новых операций импорта для создания новых элементов XML и объекта диспетчера соединений:

      #!/usr/bin/env python3

      from ncclient import manager
      from ncclient.xml_ import new_ele, sub_ele

      conn = manager.connect(host="192.168.24.252", port="830", 
    username="netconf" , password='juniper!', timeout=10, 
    device_params={'name':'junos'}, hostkey_v erify=False)

Заблокируйте конфигурацию и внесите изменения в конфигурацию:

      # lock configuration and make configuration changes
      conn.lock()

      # build configuration
      config = new_ele('system')
      sub_ele(config, 'host-name').text="master"
      sub_ele(config, 'domain-name').text="python"

В разделе конфигурации сборки создайте новый элемент system с подэлементами host-name и domain-name. Если вас интересовала структура иерархии, вы можете увидеть из XML-дисплея, что структура узла с системой является родителем для имени хоста и имени домена:

<system>
<host-name>foo</host-name>
<domain-name>bar</domain-name>
    ...
</system>

После того, как конфигурация будет построена, сценарий отправит конфигурацию и зафиксирует изменения конфигурации. Это обычные шаги передовой практики (заблокировать, настроить, разблокировать, зафиксировать) для изменений конфигурации Juniper:

      # send, validate, and commit config
      conn.load_configuration(config=config)
      conn.validate()
      commit_config = conn.commit()
      print(commit_config.tostring)

      # unlock config
      conn.unlock()

      # close session
      conn.close_session()

В следующем примере код объединяется с несколькими функциями Python:

# make a connection object
def connect(host, port, user, password):
    connection = manager.connect(host=host, port=port, username=user,
            password=password, timeout=10, device_params={'name':'junos'},
            hostkey_verify=False)
    return connection

# execute show commands
def show_cmds(conn, cmd):
    result = conn.command(cmd, format="text")
    return result

# push out configuration
def config_cmds(conn, config):
    conn.lock()
    conn.load_configuration(config=config)
    commit_config = conn.commit()
    return commit_config.tostring

Этот файл может выполняться сам по себе или может быть импортирован для использования другими скриптами Python.
Juniper также предоставляет библиотеку Python для использования со своими устройствами под названием PyEZ. Сейчас вы взглянете на несколько примеров использования библиотеки.

Juniper PyEZ для разработчиков

PyEZ — это высокоуровневая реализация Python, которая лучше интегрируется с вашим существующим кодом Python. Используя API Python, вы можете выполнять стандартные задачи по эксплуатации и настройке, не обладая глубокими знаниями интерфейса командной строки Junos.
Juniper поддерживает комплексную Руководство разработчика Junos PyEZ в их технической библиотеке. Если вы заинтересованы в использовании PyEZ, настоятельно рекомендуется хотя бы просмотреть различные разделы руководства.

Установка и подготовка

Инструкции по установке для каждой из операционных систем можно найти на Страница установки Junos PyEZ. Вот инструкции по установке Ubuntu 16.04.

Ниже приведены некоторые пакеты зависимостей:

$ sudo apt-get install -y python3-pip python3-dev libxml2-dev libxslt1-dev libssl-dev libffi-dev

Пакеты PyEZ можно установить через pip:

$ sudo pip3 install junos-eznc
$ sudo pip install junos-eznc

На устройстве Juniper NETCONF необходимо настроить как базовый XML API для PyEZ:

set system services netconf ssh port 830

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

set system login user netconf uid 2001
set system login user netconf class super-user
set system login user netconf authentication encrypted-password "$1$0EkA.XVf$cm80A0GC2dgSWJIYWv7Pt1"

Для аутентификации по ключу ssh сначала создайте пару ключей на своем хосте:

$ ssh-keygen -t rsa

По умолчанию открытый ключ будет называться id_rsa.pub в каталоге ~/.ssh/, а закрытый ключ будет называться id_rsa в том же каталоге. Относитесь к закрытому ключу как к паролю, которым вы никогда не делитесь. Открытый ключ можно свободно распространять.

В этом случае переместите открытый ключ в каталог /tmp и включите модуль HTTP-сервера Python 3 для создания доступного URL-адреса:

$ mv ~/.ssh/id_rsa.pub /tmp
$ cd /tmp
$ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 ...

Примечание. Для Python 2 вместо этого используйте python -m SimpleHTTPServer.

На устройстве Juniper вы можете создать пользователя и связать открытый ключ, загрузив открытый ключ с веб-сервера Python 3:

netconf@foo# set system login user echou class super-user authentication load-key-file 
/var/home/netconf/...transferring.file........100% of 394 B 2482 kBps

Теперь, если вы попытаетесь подключиться по ssh с закрытым ключом со станции управления, пользователь будет автоматически аутентифицирован:

$ ssh -i ~/.ssh/id_rsa 192.168.24.252
--- JUNOS 12.1R1.9 built 2012-03-24 12:52:33 UTC
echou@foo>

Чтобы убедиться, что оба метода аутентификации работают с PyEZ, попробуйте комбинацию имени пользователя и пароля:

Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from jnpr.junos import Device
>>> dev = Device(host="192.168.24.252", user="netconf", password='juniper!')
>>> dev.open()
Device(192.168.24.252)
>>> dev.facts
{'serialnumber': '', 'personality': 'UNKNOWN', 'model': 'olive', 'ifd_style': 'CLASSIC', '2RE': False, 'HOME': '/var/home/juniper', 'version_info': junos.version_info(major=(12, 1), type=R, minor=1, build=9), 'switch_style': 'NONE', 'fqdn': 'foo.bar', 'hostname': 'foo', 'version': '12.1R1.9', 'domain': 'bar', 'vc_capable': False}
>>> dev.close()

Вы также можете попробовать использовать аутентификацию по ключу SSH:

>>> from jnpr.junos import Device
>>> dev1 = Device(host="192.168.24.252", user="echou", ssh_private_key_file="/home/echou/.ssh/id_rsa")
>>> dev1.open()
Device(192.168.24.252)
>>> dev1.facts
{'HOME': '/var/home/echou', 'model': 'olive', 'hostname': 'foo', 'switch_style': 'NONE', 'personality': 'UNKNOWN', '2RE': False, 'domain': 'bar', 'vc_capable': False, 'version': '12.1R1.9', 'serialnumber': '', 'fqdn': 'foo.bar', 'ifd_style': 'CLASSIC', 'version_info': junos.version_info(major=(12, 1), type=R, minor=1, build=9)}
>>> dev1.close()

Большой! Теперь вы готовы рассмотреть несколько примеров для PyEZ.

Примеры PyEZ

В предыдущей интерактивной подсказке вы уже видели, что при подключении устройства объект автоматически получает несколько фактов об устройстве. В первом примере, junos_pyez_1.py, вы подключались к устройству и выполняли вызов RPC для show interface em1:

      #!/usr/bin/env python3
      from jnpr.junos import Device
      import xml.etree.ElementTree as ET
      import pprint

      dev = Device(host="192.168.24.252", user="juniper", passwd='juniper!')

      try:
          dev.open()
      except Exception as err:
          print(err)
          sys.exit(1)

      result = 
    dev.rpc.get_interface_information(interface_name="em1", terse=True)
      pprint.pprint(ET.tostring(result))

      dev.close()

Класс устройства имеет свойство rpc, которое включает все рабочие команды. Это довольно круто, потому что между тем, что вы можете делать в CLI, и API нет проскальзывания. Загвоздка в том, что вам нужно узнать тег элемента xml rpc. Как узнать, что в первом примере show interface em1 равно get_interface_information? У вас есть три способа узнать эту информацию:

  1. Вы можете обратиться к Справочнику по эксплуатации Junos XML API для разработчиков.
  2. Вы можете использовать CLI и отобразить эквивалент XML RPC и заменить тире (-) между словами на подчеркивание (_).
  3. Вы также можете сделать это программно, используя библиотеку PyEZ.
    Как правило, второй вариант используется для прямого получения вывода:
    netconf@foo> show interfaces em1 | display xml rpc
<rpc-reply xmlns:junos="
<rpc>
<get-interface-information>
<interface-name>em1</interface-name>
</get-interface-information>
</rpc>
<cli>
<banner></banner>
</cli>
</rpc-reply>

Вот пример использования PyEZ программно (третий вариант):

>>> dev1.display_xml_rpc('show interfaces em1', format="text")
    '<get-interface-information>n <interface-name>em1</interface-
name>n</get-interface-information>n'

Конечно, вам также нужно будет внести изменения в конфигурацию. В примере конфигурации junos_pyez_2.py импортируйте дополнительный метод Config() из PyEZ:

      #!/usr/bin/env python3
      from jnpr.junos import Device
      from jnpr.junos.utils.config import Config

Используйте тот же блок для подключения к устройству:

      dev = Device(host="192.168.24.252", user="juniper", 
    passwd='juniper!')

      try:
          dev.open()
      except Exception as err:
          print(err)
          sys.exit(1)

Новый метод Config() загрузит XML-данные и внесет изменения в конфигурацию:

      config_change = """
<system>
<host-name>master</host-name>
<domain-name>python</domain-name>
</system>
      """

      cu = Config(dev)
      cu.lock()
      cu.load(config_change)
      cu.commit()
      cu.unlock()

      dev.close()

Примеры PyEZ просты по дизайну. Надеюсь, их было достаточно, чтобы объяснить вам, как вы можете использовать PyEZ для своих потребностей в автоматизации Junos.

Если вы нашли эту статью полезной, вы можете изучить Освоение сети Python — второе издание. Написанная Эриком Чоу, опытным техническим специалистом с более чем 18-летним опытом, книга содержит практические примеры использования Python для автоматизации сетевых устройств, DevOps и SDN и обязательна к прочтению сетевыми инженерами и программистами.

Похожие записи

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

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