Использование Ansible
Ansible является системой управления конфигурациями, изначально создаваемой для управления серверной инфраструктурой, однако, в процессе развития в систему были добавлены модули для работы с сетевым оборудованием различных производителей.
К сожалению, в сравнении с серверами, функционал Ansible для работы с сетевым оборудованием достаточно скромен, но выполнение базовых операций поддерживается. Например, одним из принципов системы Ansible является его иммутабельность, т.е., если на сервере установлен желаемый пакет и администратор повторит запуск задания на установку этого пакета, то Ansible это распознает и задание выполнять не будет. Это было бы удобно использовать и для конфигураций сетевого оборудования, однако такой функционал пока не реализован.
Скрипты Ansible поддерживают два режима работы: ad-hoc команды и playbook. Ad-hoc команды предназначены для выполнения разового действия с устройствами или группой устройств и выполняется из командной строки. Playbook представляет собой файл сценария, состоящий из нескольких задач, выполняемых последовательно. Для каждой из задач может быть определён набор параметров и задачи могут выполняться зависимо, например, если первая задача выполнилась с ошибкой, то последующие задачи выполняться не будут.
Независимо от режима работы, выполнение задачи вызывается из модуля. Набор модулей устанавливается вместе с Ansible и делится на две части: работа базовых модулей гарантирована при развитии системы и выходе новых версий продукта, поддержка дополнительных модулей в будущих версиях Ansible не гарантируется. В демонстрационных примерах будут использоваться модули net_put и net_get для отправки и получения файла с устройства соответственно, а также модуль routeros_command для отправки команд. Вывод результатов будет выполнен с помощью связки модулей register и debug.
Схема работы
Схема работы Ansible представлена на рисунке 3.1.
Рисунок 3.1 — Схема работы Ansible
Алгоритм работы Ansible выглядит следующим образом:
- Администратор запускает задание в Ansible;
- Ansible выполняет параллельное подключение к списку устройств, указанных в задании. Число параллельных сессий по умолчанию равно 5, подключение выполняется по протоколу SSH, поддерживается соединение через логин/пароль и сертификат;
- Ansible выполняет сбор информации об устройстве;
- Ansible выполняет задание;
- Если заданий на выполнение больше нет, то Ansible отключается от устройства, если есть — выполняются последующие задания.
Поскольку работа Ansible выполняется через протокол SSH, то необходимо, что на устройствах была активирована поддержка этого протокола и не выполнялось блокировки подключения в файрволе.
Существует возможность подключения Ansible к устройствам через протокол telnet. Для этого в задании следует использовать модуль telnet, однако в рамках данной статьи будет использоваться способ «по умолчанию».
Файловая структура
Для работы Ansible требуется определить набор параметров. Параметры можно разделить на два типа: набор конфигурационных параметров и набор пользовательских параметров.
Конфигурационные параметры системы хранятся в файле ansible.cfg, который расположен в директории, из которой вы запускаете Ansible. Если нет необходимости, то конфигурационные параметры можно не определять, в этом случае будут использоваться параметры по-умолчанию. В рассматриваемых примерах будет использоваться файл следующего содержания:
Листинг ansible.cfg
[defaults]
inventory = ./hosts
Первая строка указывает на использование параметров по-умолчанию, а вторая на переопределение параметра inventory. Данный параметр определяет путь к файлу со списком устройств.
Набор пользовательских параметров определяется задачами, которые будут выполняться с помощью Ansible. Минимально необходимый список параметров — inventory-файл со списком устройств, в рассматриваем случае используется файл hosts.
Листинг hosts
[routers]
172.16.16.14
172.16.16.13
172.16.16.12
Inventory-файл позволяет создать группы устройств, в которые включить IP-адреса или доменные имена, а также группы, состоящие из групп устройств. В дальнейшем, при выполнении задач нет нужды перечислять все адреса устройств, для которых необходимо выполнить это задание, достаточно указать название группы. В рассматриваемом случае создана группа routers, в которую включены маршрутизаторы, указанные на рисунке 3.1.
К пользовательским параметрам также относятся параметры подключения к устройствам. Механизм определения параметров подключения достаточно гибок: можно указать их для всех устройств, группы устройств или конкретного маршрутизатора.
Переменные группы должны быть расположены в файле с названием группы в директории group_vars, а переменные хоста в файле с адресом хоста директории host_vars. В рассматриваемой задаче подключение будет выполняться с помощью логина и пароля, для устройств R3 и R4 используется пользователь user/user, а для R2 — spw/spw. Структура размещения файлов представлена на рисунке 3.2.
Листинг routers.yml
ansible_connection: network_cli
ansible_network_os: routeros
ansible_user: user
ansible_password: user
Листинг 172.16.16.12.yml
ansible_user: spw
ansible_password: spw
Рисунок 3.2 Демонстрация примеров
Демонстрация примеров будет выполнена через playbook, которые расположены в директории, из которой будет запущен Ansible (см. рисунок 3.2). К playbook относятся файлы data_get.yml, data_set.yml, file_get.yml, file_set.yml.
Файлы с пользовательскими параметрами и playbook оформляются, как YAML-структура. Следует обратить внимание, что структура таких файлов чувствительна к синтаксису, причём пробелы и отступы тоже являются частью синтаксиса.
Установка Ansible
Управляющий хост с Ansible должен быть под управлением ОС Linux. На официальном сайте Ansible представлена подробная документация по установке, использованию и модулям системы (https://docs.ansible.com/). Один из русскоязычных материалов по первым шагам в Ansible представлен по ссылке: https://natenka.gitbooks.io/pyneng/content/book/Part_VI.html.
Демонстрация работы Ansible
При рассмотрении практических примеров будет использована схема сети, представленная на рисунке 3.1, набор и содержимое конфигурационных файлов, рассмотренные в этом разделе.
Конфигурация маршрутизаторов, используемых в демонстрационном стенде:
R2:
/ip address
add address=172.16.16.12/28 interface=ether1 network=172.16.16.0
/system identity
set name=R2
/user
add name=spw password=spw group=full
R3:
/ip address
add address=172.16.16.13/28 interface=ether1 network=172.16.16.0
/system identity
set name=R3
/user
add name=user password=user group=full
R4:
/interface bridge port
add bridge=bridge1 interface=ether3
add bridge=bridge1 interface=ether4
add bridge=bridge1 interface=ether5
add bridge=bridge1 interface=ether2-master
add bridge=bridge1 interface=wlan1
/ip address
add address=172.16.16.14/28 interface=ether1 network=172.16.16.0
/system identity
set name=R4
/user
add name=user password=user group=full
Вывод информации об устройстве
Составим playbook, который будет выполнять на маршрутизаторах команду “/system routerboard print” и результат выполнения выводить в терминал командной строки. Текст playbook data_get.yml приведён ниже.
Листинг data_get.yml
- name: Getting data from routers
hosts: routers
gather_facts: false
tasks:
- name: system command
routeros_command:
commands: /system routerboard print
register: system_print
- name: debug print
debug: var=system_print.stdout_lines
В первом блоке содержатся параметры, применяемые ко всему playbook. В частности, указано его описание, определён список устройств, к которым он будет применён и отключен сбор фактов (см. алгоритм работы Ansible).
Далее идёт блок со списком задач. Первая задача использует модуль routeros_command и в качестве параметра этой задаче передаётся строка команды, которую нужно выполнить. Результат выполнения запоминается с помощью модуля register. Обратите внимание, что в рамках одной задачи может использоваться несколько модулей.
Вторая задача описывает вывод на экран результата работы, который был зафиксирован на предыдущем этапе в переменной system_print. Для вывода используется модуль debug.
Результат выполнения playbook представлен на рисунке 3.3. Видно, что playbook был успешно выполнен по отношению ко всем устройствам группы routers. Также можно отметить, что для R2 и R3 параметр “routerboard: no”, т.к. в роли этих маршрутизаторов используются CHR.
Рисунок 3.3 Результат выполнения playbook data_get.yml
Отправка файла на устройство
Составим playbook, который будет загружать файл предварительно сформированного скрипта spw_script на устройство R4. Содержимое playbook file_set.yml представлено ниже.
Листинг file_set.yml
- name: Set file to router
hosts: 172.16.16.14
gather_facts: false
tasks:
- name: file upload
net_put:
src: ./spw_script
protocol: sftp
- name: File demonstate after
routeros_command:
commands: /file print
register: file_after
- name: debug print after
debug: var=file_after.stdout_lines
В отличии от playbook, рассмотренного ранее, здесь определён только один хост 172.16.16.14, а не группа хостов routers.
В разделе с заданиями представлено три задачи: первая выполняет загрузку файла скрипта с использованием модуля net_put, вторая выполняет команду отображения списка файлов, а третья выводит результат работы на экран.
Результат выполнения playbook представлен на рисунке 3.4. Видно, что модуль net_put выполняет изменения на устройстве, поэтому отображается оранжевым цветом. Это же указывается в конце выполнения “playbook – changed=1”. Кроме того, можно видеть, что в списке файлов на устройстве появился загружаемый файл.
Playbook выполнен два раза для того, чтобы продемонстрировать иммутабельность модуля net_put. Поскольку файл уже существует, то Ansible не выполняет повторную загрузку.
Рисунок 3.4 Результат выполнения playbook file_set.yml
Получение файла с устройства
Сформируем playbook, который будет создавать backup на устройстве R2 и выполнять его загрузку в директорию, из которой запускается Ansible. Содержимое playbook file_get.yml представлено ниже.
Листинг file_get.yml
- name: Save file from router
hosts: 172.16.16.12
gather_facts: false
tasks:
- name: backup-file create
routeros_command:
commands: /system backup save name=backup_spw
- name: backup-file download
net_get:
src: backup_spw.backup
protocol: sftp
Первая задание выполняет на устройстве R2 сохранение backup-файла, а второе задание скачивает созданный файл с устройства. Результат выполнения playbook представлен на рисунке 3.5.
Рисунок 3.5 Результат выполнения playbook file_get.yml
Выполнение команды
Составим playbook, создающий на устройствах группы routers bridge-интерфейс. Содержимое playbook data_set.yml представлено ниже.
Листинг data_set.yml
- name: Create bridge-interfaces
hosts: routers
gather_facts: false
tasks:
- name: Create bridge
routeros_command:
commands:
- /interface bridge add name=br_spw
- /interface bridge print
register: bridge_print
- name: debug print
debug: var=bridge_print.stdout_lines
Первое задание выполняет две команды на маршрутизаторах: первая команда создаёт bridge-интерфейс с именем br_spw, а вторая выводит список созданных bridge-интерфейсов. Следует обратить внимание, что в рамках одного задания может быть выполнено несколько команд, в этом случае команды должны быть переданы как список. Вторая команда выводит результат работы на экран.
Результат выполнения playbook представлен на рисунке 3.6. Можно заметить, что bridge-интерфейсы успешно созданы, в соответствии с целью playbook.
Рисунок 3.6 Результат выполнения playbook data_set.yml
Результат повторного выполнения playbook data_set.yml представлен на рисунке 3.7. Следует обратить внимание, что модуль routeros_command не обладает иммутабельностью: несмотря на то, что интерфейс br_spw уже создан, Ansible выполняет описанные команды, о чём свидетельствует выводимое сообщение об ошибке.
Рисунок 3.7 Результат повторного выполнения playbook data_set.yml
В демонстрационных примерах пароль для доступа хранится в открытом доступе в файле с пользовательскими переменными. Это является не самым безопасным решением. Использование ключа “-k” при запуске playbook позволит запрашивать пароль перед выполнением заданий. Кроме того, для доступа к устройствам можно использовать заранее сгенерированные сертификаты.
- name: system command
^ here
Ошибка, непонятно, как ее победить
Можно ли с модулем routeros_command скормить рутеру конфигурацию из файла (template.j2)? Или нужно построчно в playbook переписывать?