Все началось с задачи создать некоторое количество vlan на пачке коммутаторов, а делать это вручуню совсем не хотелось. Знающие люди посоветовали использовать Ansible. На мануал не претендует, так как опыта использования пока не много, но тем, что получилось, хочу поделиться. Конструктивная критика, замечания и пожелания приветствуются.



Подробности под катом.

Установка


Установка на Centos довольно простая.

yun install ansible

Дальше нужно установить модули от Juniper для Ansible, тут команде Juniper отдельное спасибо.

ansible-galaxy install Juniper.junos

Проверить установленные модули можно командой.

ansible-galaxy list

После установки можно проверить версию

ansible --version
ansible 2.3.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
  python version = 2.7.5 (default, Nov  6 2016, 00:28:07) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]

В файле конфигурации ansible.cfg определены путь к файлу логов и списку устройств, а также опция, отключающая проверку SSH ключей в локальном хранилище при подключении к коммутатору:

[defaults]
inventory      = /etc/ansible/hosts
host_key_checking = False
log_path = /var/log/ansible.log

Список устройств лежит в файле hosts. Хосты можно группировать, группы могут быть членами других групп:

[testswitches]
#SWTEST
192.168.8.192
#SWAC_0901
192.168.8.218

[prodswitches]
#SWAC_1301
192.168.8.81
#SWAC_1302
192.168.8.82

[allswitches:children]
testswitches
prodswitches

Внесение изменений в конфигурацию коммутатора


Нужно создать ansible playbook — сценарий, по которому Ansible будет выполнять определенные действия. Первый playbook для внесения изменений в конфигурацию коммутаторов — changeconfig.yml. Просто создаем пустой файл с расширением yml:

#playbook начинается с ---
---
#задаем имя
- name: Juniper Config Changes
#группа хостов, к которым будет применяться playbook
  hosts: testswitches
#роль, которая будет использоватья - это библиотека от Juniper, которую установили ранее
  roles:
  - Juniper.junos
  connection: local
  gather_facts: no
#тут даем ссылку на интерпретатор Python, если в системе было установлено несколько версий
  vars:
    ansible_python_interpreter: /usr/bin/python
#чтобы не хранить креденшелс в файле, их можно вводить при запуске playbook
  vars_prompt:
  - name: USERNAME
    prompt: Username
    private: no
  - name: PASSWORD
    prompt: Password
    private: yes
#дальше описываем задачу, которую нужно сделать
#timeout увеличен до 120 сек, потому что после commit старые EX2200 некоторое время думают, за это время сессия отваливалась
  tasks:
  - name: Retrieve information from devices running Junos OS
    junos_config:
      host: "{{ inventory_hostname }}"
      username: "{{ USERNAME }}"
      password: "{{ PASSWORD }}"
      timeout: 120
      port: 22
#перечисляем команды так, как бы мы их вносили на самом коммутаторе
      lines:
        - delete interfaces vme unit 0 family inet dhcp
        - set vlans vlan10 description "TestVlan"
        - set vlans vlan10 vlan-id 10

Запускаем playbook командой ansible-playbook changeconfig.yml

Username: admin
Password:
PLAY [Juniper Config Changes] **********************************************
TASK [Retrieve information from devices running Junos OS] 
ok: [192.168.8.218]
changed: [192.168.8.192]
PLAY RECAP ******************************************************
192.168.8.192              : ok=1    changed=1    unreachable=0    failed=0
192.168.8.218              : ok=1    changed=0    unreachable=0    failed=0

Я немного почистил вывод, но в целом, ok показывает, что подключение прошло успешно, changed=1 — что изменения внесены на коммутатор. На 192.168.8.218 нужный влан уже был

Перед запуском можно протестировать, какие именно изменения будут внесены. Для этого нужно запустить команду с параметром ansible-playbook changeconfig.yml -bDC

В логе будут показаны вносимые изменения, но фактически они не будут применены, ключ С позволяет сделать проверку, а bD покажет разницу. В примере ниже на одном из свичей был дескрипшен для влана 10 с именем SRV, ansible его удалит и добавит новый а также создаст сам влан.

*
[edit vlans vlan10]
-   description SRV;
+   description "TestVlan";
+   vlan-id 10;

changed: [192.168.8.192]
ok: [192.168.8.218]


Сбор информации с коммутаторов


Еще один Playbook показывает, как собрать нужные данные с коммутаторов и сохранить результаты в локальный файл. Меня интересовала версия Junos. Ниже я приведу только часть tasks, все, что выше, аналогично предыдущему playbook

  tasks:
  - name: Retrieve information from devices running Junos OS
    junos_command:
      host: "{{ inventory_hostname }}"
      username: "{{ USERNAME }}"
      password: "{{ PASSWORD }}"
      timeout: 120
      port: 22
      commands:
        - show version
#тут мы регистрируем переменную, в которую будет все выводиться, в дебаге можно посмотреть ее структуру и сохранить в файл интересующее поле
    register: printout
  - name: Save Output
#debug: msg="{{printout.stdout_lines}}"
    lineinfile:
      path: versions.log
      create: yes
      line: "{{printout.stdout_lines}}"

Для отладки можно запускать playbook командой ansible-playbook -vvv getversion.yml
Также все логи будут лежать в указанном в конфиге /var/log/ansible.log

В целом Ansible мне понравился, буду осваивать дальше, благодарю за внимание.

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


  1. kafeman
    02.12.2017 18:34

    — delete interfaces vme unit 0 family inet dhcp
    — set vlans vlan10 description «TestVlan»
    — set vlans vlan10 vlan-id 10
    Можно ли как-то описать это декларативно? Одна из главных фишек Ansible в том, чтобы избегать императивных команд.


    1. alk0v Автор
      03.12.2017 00:43

      Поясните пожалуйста, это конкретные команды, которые мне нужно разлить на свичи, что значит «описать декларативно»?


      1. kafeman
        03.12.2017 00:51

        «vlan с ID=10 и описанием „TestVlan“ должен присуствовать»

        По аналогии с docs.ansible.com/ansible/latest/apt_module.html


        1. alk0v Автор
          03.12.2017 01:15

          ок, на этом примере:
          — name: Install a .deb package from the internet.
          apt:
          deb: example.com/python-ppq_0.1-1_all.deb
          Что меняется? Ansible просто ставит конкретный deb пакет.
          Модуль от Juniper сам проверяет, применилась команда или нет, если не применилась, я это увижу в логе. Т.е. тут, в общем, два исхода. Если говорить конкретно про те же вланы, то создать их можно единственным способом — вбив соответствующую команду на коммутаторе, если она уже была вбита ранее, ничего не произойдет, это я и показал в своем примере, когда на одном из свичей она уже была.


          1. kafeman
            03.12.2017 01:27

            Что меняется? Ansible просто ставит конкретный deb пакет.
            Ansible запрашивает информацию об этом пакете. Если он еще не установлен, устанавливает. Если установлен, но не той версии — обновляет, либо, наоборот, откатывает. Вы не говорите «я хочу выполнить apt install something», вы говорите «я хочу, чтобы APT-пакет something последней версии был доступен в системе». Каким образом Ansible этого добьется — уже дело десятое. Может просто выполнить тот же «apt install something», может записать название пакета в какой-то внутренний буфер и попытаться установить все пакеты разом позже. Может придумать что-нибудь еще, что его разработчики посчитают более эффективным. Декларативное описание конфигурации — одна из главных фишек Ansible. В противном случае он бы ничем не отличался от простого Bash-скрипта.


            1. alk0v Автор
              03.12.2017 01:51

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