В предстоящем выпуске Red Hat Ansible Engine 2.9 вас ждут впечатляющие улучшения, и некоторые из них описаны в этой статье. Как обычно, мы разрабатывали улучшения Ansible Network в открытую, при поддержке сообщества. Присоединяйтесь — загляните на доску задач на GitHub и изучите план развития для выпуска Red Hat Ansible Engine 2.9 на странице wiki для Ansible Network.


Как мы недавно объявили, Red Hat Ansible Automation Platform теперь включает Ansible Tower, Ansible Engine и весь контент Ansible Network. Сейчас большинство популярных сетевых платформ реализуется через модули Ansible. Например:


  • Arista EOS
  • Cisco IOS
  • Cisco IOS XR
  • Cisco NX-OS
  • Juniper Junos
  • VyOS

Полный список платформ, которые полностью поддерживаются Red Hat через подписку Ansible Automation, опубликован здесь.


Чему мы научились


В последние четыре года мы много узнали о разработке платформы для автоматизации сети. Еще мы узнали о том, как применяются артефакты платформы в плейбуках и ролях Ansible со стороны конечных пользователей. И вот что мы выяснили:


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

Когда мы обсуждали наши долгосрочные планы развития больше года назад, наши корпоративные клиенты просили о следующем:


  • Сбор фактов нужно лучше стандартизировать и согласовать с рабочим процессом автоматизации для любых устройств.
  • Обновление конфигураций на устройстве тоже нужно стандартизировать и согласовать, чтобы модули Ansible обрабатывали вторую половину цикла после сбора фактов.
  • Нужны строгие и поддерживаемые методы преобразования конфигурации устройства в структурированные данные. На этой основе источник истины можно будет переместить с сетевого устройства.

Улучшения фактов


Сбор фактов с сетевых устройств с помощью Ansible нередко происходит наугад. Сетевые платформы в разной степени оснащены возможностями сбора фактов, но у них почти нет — или даже совсем нет — функций для парсинга и стандартизации представления данных в парах ключ-значение. Читайте пост Кена Селенцы (Ken Celenza) о том, как сложно и мучительно бывает анализировать и стандартизировать данные фактов.


Возможно, вы заметили, как мы работали над ролью Ansible Network Engine. Естественно, 24 тысячи загрузок спустя роль Network Engine быстро стала одной из самых популярных ролей Ansible в Ansible Galaxy для сценариев автоматизации сети. Прежде чем мы перенесли многое из этого в Ansible 2.8, чтобы подготовиться к тому, что понадобится в Ansible 2.9, эта роль Ansible предоставила первый набор инструментов для помощи в парсинге команд, управлении командами и сборе данных для сетевых устройств.


Если вы разбираетесь в использовании Network Engine, это очень эффективный способ сбора, парсинга и стандартизации данных фактов для использования в Ansible. Минус этой роли в том, что нужно создавать целую кучу парсеров для каждой платформы и для всей сетевой активности. Чтобы понять, как сложно создавать, поставлять и обслуживать парсеры, посмотрите на 1200 с лишним парсеров от ребят из Cisco.


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


Каждый модуль фактов сети в Ansible 2.9 теперь может анализировать конфигурацию сетевого устройства и возвращать структурированные данные — без дополнительных библиотек, ролей Ansible или кастомных парсеров.


Начиная с Ansible 2.9 при каждом выпуске обновленного сетевого модуля модуль фактов улучшается, чтобы предоставлять данные об этом разделе конфигурации. То есть развитие фактов и модулей теперь происходит в одном темпе, и у них всегда будет общая структура данных.


Конфигурацию ресурсов на сетевом устройстве можно извлечь и преобразовать в структурированные данные двумя способами. Обоими способами можно собрать и преобразовать определенный список ресурсов с помощью нового ключевого слова gather_network_resources. Имена ресурсов соответствуют именам модулей, и это очень удобно.


Во время сбора фактов:


С помощью ключевого слова gather_facts можно извлечь текущую конфигурацию устройства в начале плейбука, а потом использовать ее на протяжении всего плейбука. Укажите отдельные ресурсы, которые нужно извлечь с устройства.


- hosts: arista
  module_defaults:
    eos_facts:
      gather_subset: min
      gather_network_resources:
      - interfaces
  gather_facts: True

Вы могли заметить что-то новое в этих примерах, а именно — gather_facts: true теперь доступно для нативного сбора фактов для сетевых устройств.


Использование модуля сетевых фактов напрямую:


- name: collect interface configuration facts
  eos_facts:
    gather_subset: min
    gather_network_resources:
    - interfaces

Плейбук возвращает следующие факты об интерфейсе:


ansible_facts:
   ansible_network_resources:
      interfaces:
      - enabled: true
        name: Ethernet1
        mtu: '1476'
      - enabled: true
        name: Loopback0
      - enabled: true
        name: Loopback1
      - enabled: true
        mtu: '1476'
        name: Tunnel0
      - enabled: true
        name: Ethernet1
      - enabled: true
        name: Tunnel1
      - enabled: true
        name: Ethernet1

Обратите внимание, как Ansible извлекает нативную конфигурацию с устройства Arista и преобразует ее в структурированные данные, чтобы использовать в виде стандартных пар ключ-значение для последующих задач и операций.


Факты интерфейса можно добавить в хранимые переменные Ansible и использовать сразу или потом как входные данные для модуля ресурса eos_interfaces без дополнительной обработки или преобразования.


Модули ресурсов


Итак, мы извлекли факты, нормализовали данные, вписали их в стандартизированную внутреннюю схему структуры данных и получили готовый источник истины. Ура! Это, конечно, здорово, но нам по-прежнему нужно как-то преобразовать пары ключ-значение обратно в конкретную конфигурацию, которую ожидает конкретная платформа устройства. Теперь нам нужны модули для определенных платформ, чтобы удовлетворить эти новые требования сбора фактов и нормализации.


Что такое модуль ресурса? Разделы конфигурации устройства можно представить себе как ресурсы, предоставляемые этим устройством. Модули сетевых ресурсов намеренно ограничены одним ресурсом, и их можно складывать, как кирпичики, для настройки сложных сетевых сервисов. В результате требования и спецификация для модуля ресурса естественным образом упрощаются, ведь модуль ресурса может считывать и настраивать определенный сетевой сервис на сетевом устройстве.


Чтобы объяснить, что делает модуль ресурса, давайте посмотрим на пример плейбука, который показывает идемподентную операцию с использованием новых фактов сетевого ресурса и модуля eos_l3_interface.


- name: example of facts being pushed right back to device.
  hosts: arista
  gather_facts: false
  tasks:
  - name: grab arista eos facts
    eos_facts:
      gather_subset: min
      gather_network_resources: l3_interfaces

  - name: ensure that the IP address information is accurate
    eos_l3_interfaces:
      config: "{{ ansible_network_resources['l3_interfaces'] }}"
      register: result

  - name: ensure config did not change
    assert:
      that: not result.changed

Как видите, собранные с устройства данные переданы напрямую в соответствующий модуль ресурсов без преобразования. При запуске плейбук извлекает значения с устройства и сравнивает их с ожидаемыми. В этом примере полученные значения соответствуют ожидаемым (то есть выполняется проверка отклонений конфигурации) и выдается сообщение, изменилась ли конфигурация.


Идеальный способ обнаружить отклонение конфигурации — сохранять факты в хранимые переменные Ansible и периодически использовать их вместе с модулем ресурса в режиме проверки. Это простой метод увидеть, не изменил ли кто-нибудь значения вручную. В большинстве случаев организации разрешают изменения и конфигурацию вручную, хотя многие операции выполняются через Ansible Automation.


Чем новые модули ресурса отличаются от предыдущих?


Для инженера по автоматизации сетей существуют 3 главных отличия модулей ресурса в Ansible 2.9 от предыдущих версий.


1) Для определенного сетевого ресурса (который также можно представить себе как раздел конфигурации) модули и факты будут развиваться во всех поддерживаемых сетевых операционных системах одновременно. Мы думаем, что, если Ansible поддерживает конфигурацию ресурса на одной сетевой платформе, мы должны поддерживать ее везде. Это упрощает использование модулей ресурсов, потому что инженер по автоматизации сетей теперь может настроить ресурс (например, LLDP) во всех сетевых операционных системах с нативными и поддерживаемыми модулями.


2) Модули ресурсов теперь включают значение состояния.


  • merged: конфигурация объединена с предоставленной конфигурацией (по умолчанию);
  • replaced: конфигурация ресурса будет заменена на предоставленную конфигурацию;
  • overridden: конфигурация ресурса будет заменена на предоставленную конфигурацию; лишние экземпляры ресурсов будут удалены;
  • deleted: конфигурация ресурса будет удалена/восстановлена по умолчанию.


3) Модули ресурса теперь включают стабильные возвращаемые значения. Когда модуль сетевого ресурса внес (или предложил) необходимые изменения в сетевом устройстве, он возвращает те же пары ключ-значение в плейбук.


  • before: конфигурация на устройстве в виде структурированных данных до задачи;
  • after: если устройство изменилось (или может измениться, если используется режим проверки), получившаяся конфигурация будет возвращена в виде структурированных данных;
  • commands: любые команды конфигурации, запущенные на устройстве, чтобы привести его в желаемое состояние.



Что все это значит? Почему это важно?


В этом посте описывается много сложных концепций, но мы надеемся, что в конце концов вы лучше поймете, что корпоративные клиенты просят о сборе фактов, нормализации данных и конфигурации цикла для платформы автоматизации. Но почему им нужны эти улучшения? Сейчас многие организации занимаются цифровой трансформацией, чтобы сделать свои ИТ-среды более гибкими и конкурентоспособными. Хорошо это или плохо, но многие сетевые инженеры становятся сетевыми разработчиками — из собственного интереса или по велению руководителей.


Организации понимают, что автоматизация отдельных сетевых шаблонов не решает проблему разрозненности и повышает эффективность только до определенного предела. Платформа Red Hat Ansible Automation Platform предоставляет строгие и нормирующие модели данных ресурсов, чтобы программно управлять базовыми данными на сетевом устройстве. То есть пользователи постепенно отказываются от индивидуальных способов конфигурации в пользу более современных методов с акцентом на технологиях (например, IP-адреса, VLAN, LLDP и т д.), а не на конкретной реализации вендора.


Значит ли это, что дни надежных и проверенных модулей команд и конфигурации сочтены? Ни в коем случае. Ожидаемые модули сетевых ресурсов будут применимы не во всех случаях и не для каждого вендора, так что модули команд и конфигурации еще понадобятся сетевым инженерам для определенных реализаций. Цель модулей ресурсов — упростить большие шаблоны Jinja и нормализовать неструктурированные конфигурации устройства в структурированный формат JSON. С модулями ресурсов существующим сетям будет проще преобразовывать свою конфигурацию в структурированные пары ключ-значение, которые будут представлять собой удобный для чтения источник истины. Если использовать структурированные пары ключ-значение, можно перейти от запуска конфигураций на каждом устройстве к работе с независимыми структурированными данными и вывести сети на первый план при подходе «инфраструктура как код».


Какие модули ресурсов появятся в Ansible Engine 2.9?


Прежде чем подробно рассказать, что будет в Ansible 2.9, давайте вспомним, как мы разделили весь объем работ.


Мы выделили 7 категорий и каждой назначили определенные сетевые ресурсы:



Примечание: ресурсы, выделенные жирным, были запланированы и реализованы в Ansible 2.9.
На основе отзывов от корпоративных клиентов и сообщества логично было сначала заняться теми модулями, которые связаны с протоколами топологии сети, виртуализацией и интерфейсами.
Следующие модули ресурсов разработаны командой Ansible Network и соответствуют платформам, которые поддерживает Red Hat:



Следующие модули разработаны сообществом Ansible:


  • exos_lldp_global — от Extreme Networks.
  • nxos_bfd_interfaces — от Cisco
  • nxos_telemetry — от Cisco

Как видите, концепция модулей ресурсов вписывается в нашу стратегию ориентации на платформы. То есть мы включаем необходимые возможности и функции в сам Ansible, чтобы поддержать стандартизацию при разработке сетевых модулей, а еще упростить работу пользователей на уровне ролей и плейбуков Ansible. Чтобы расширить разработку модулей ресурсов, команда Ansible выпустила инструмент Module Builder.


Планы на Ansible 2.10 и дальше


После выпуска Ansible 2.9 мы займемся следующим набором модулей ресурсов для Ansible 2.10, которые можно будет использовать для дальнейшей настройки топологии и политики сети, например ACL, OSPF и BGP. План развития еще можно корректировать, так что, если у вас есть комментарии, сообщите об этом в сообществе Ansible Network.


Ресурсы и начало работы


Пресс-релиз об Ansible Automation Platform
Блог Ansible Automation Platform
Будущее доставки контента в Ansible
Размышления об изменении структуры проекта Ansible

Комментарии (10)


  1. amarao
    17.10.2019 14:04

    Меж тем, локальные переменные (уровня task) для import_role переопределяют переменные для всей плей.


    И это не баг. Это просто WTF, которое надо проглотить и радоваться.


    Пример:


    inventory:


    host1: foo=1

    play.yaml


    - hosts: host1
      tasks:
        - debug: var=foo
        - import_role: name=somerole
          vars:
            foo: 2
        - import_role: name=somerole
          vars:
            foo: 3
        - debug: var=foo

    (Внутри somerole такой же -debug: var=foo).


    Догадайтесь, какие 4 числа будут выведены на экран? (Кандидаты из комбинации чисел 1, 2 и 3).


    1. LuckySB
      17.10.2019 15:35

      Все согласно доке:
      docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable

      TASK [debug] *************************************************************************************************************************************************
      ok: [localhost] => {
      "foo": 1
      }

      TASK [somerole : debug] **************************************************************************************************************************************
      ok: [localhost] => {
      "foo": 2
      }

      TASK [somerole : debug] **************************************************************************************************************************************
      ok: [localhost] => {
      "foo": 3
      }

      TASK [debug] *************************************************************************************************************************************************
      ok: [localhost] => {
      "foo": 1
      }


      ansible --version
      ansible 2.6.2


      1. LuckySB
        17.10.2019 15:40

        ansible --version
        ansible 2.7.13

        TASK [debug] *************************************************************************************************************************************************
        ok: [localhost] => {
        "foo": 3
        }

        TASK [somerole : debug] **************************************************************************************************************************************
        ok: [localhost] => {
        "foo": 2
        }

        TASK [somerole : debug] **************************************************************************************************************************************
        ok: [localhost] => {
        "foo": 3
        }

        TASK [debug] *************************************************************************************************************************************************
        ok: [localhost] => {
        "foo": 3
        }


        найс… что они там курят то?


        1. LuckySB
          17.10.2019 15:49

          замена статического импорта на динамический инклюд возвращает логику, но замедляет выполнение ;)
          - hosts: host1
          tasks:
          - debug: var=foo
          - include_role: name=somerole
          vars:
          foo: 2
          - include_role: name=somerole
          vars:
          foo: 3
          - debug: var=foo


          1. amarao
            17.10.2019 19:07

            Дело не в том, как фиксить, а в том, что они сами себе противоречат.


            Если vars выставляют переменные для всей плебуки, то почему одна роль получает два, а вторая три? А если она выставляет для "кусочка" (т.е. одно import_role), то почему она тогда затрагивает таски над import_role?


            И так у них всегда.


    1. chemtech
      17.10.2019 19:14

      Issue есть? можем там проголосовать чтобы быстрее отреагировали


      1. amarao
        17.10.2019 19:16

        Так это репортить или нет?


        Документация говорит, что это фича. Но я эту фичу не понимаю.


        Since Ansible 2.7 variables defined in vars and defaults for the role are exposed at playbook parsing time. Due to this, these variables will be accessible to roles and tasks executed before the location of the import_role task.


        https://docs.ansible.com/ansible/latest/modules/import_role_module.html


        Т.е. если бы она в этом примере всем 3 сделала — я бы вздохнул и понял. (и всё равно приводил бы этот пример как идиотизм), но комбинация 3, 2, 3, 3 — это совершенно нелогично.


        Баг или фича?


        1. LuckySB
          17.10.2019 21:58

          ну я думаю, что это все таки баг. В мозгах разработчика.

          Потому что сначала при импорте ролей все переменные применяются и в итоге последнее значение записывается.
          а потом при проигрывании опять для каждой роли применяются переменные…
          и зачем они их применяют Джва раза — вот тут непонятное.

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


        1. roller
          18.10.2019 02:24
          -1

          Не будут они это фиксить, иначе есть риск что у кого-нибудь сломаются плейбуки, отлаженные "с этим" багом.


          К сожалению, ансибл похож на php — от рождения сломан во всех местах, и с каждым релизом яма все глубже, и можно только смириться. Выиграет фреймворк, кооторые сумеет заюзать модули ансибл, но будет иметь нормальную архитектуру и язык.


          1. Xop
            19.10.2019 13:25

            Имхо есть шансы у Salt, особенно если появятся удобные средства модульного и интеграционного тестирования стейтов/формул. Да, есть плагин к kitchen — но это только интеграционное, и с multi-node там все грустно. И есть внутренняя система тестов — но если я правильно понимаю для тестирования своих стейтов их придется положить внутрь сальтовских исходников, что вообще за гранью...