NetApp + Ansible

Меня уже несколько раз на различных мероприятиях спрашивали по поводу первоначального конфигурирования массивов NetApp при помощи Ansible, да и статьи по Ansible, судя по статистике посещаемости моего блога, крайне популярны. Поэтому не будем отставать от трендов перехода к infrastructure as a code и поговорим о том, как быстро и просто сконфигурировать с нуля систему на Ontap.
Главная сложность массивов NetApp (но в том же и их прелесть), что вам для конфигурирования доступно практически всё, что вашей душе угодно. Такого количества параметров нет, пожалуй, ни у одного другого вендора СХД. Но в этом же и сложность, особенно учитывая «многослойность» системы и большое количество абстракций.
Настраивать всё это через GUI удовольствия действительно мало, да и порой это крайне неудобно. Можно использовать консоль — она понятна и читабельна, все команды в целом интуитивно понятны, но они длинные, их много и вам всё равно необходимо иметь некий чек-лист того, что вам необходимо настроить на системе, для того чтобы это было во-первых единообразно с остальными вашими системами, а во-вторых чтобы в большом количестве настроек не упустить и не забыть что-либо.
Но если вам всё равно необходимо хотя бы однажды описать всю конфигурацию, то почему бы не сделать это сразу в эталонном конфигурационном файле и далее уже по необходимости туда вносить изменения, необходимые для конкретных систем? Если вы не один занимаетесь поддержкой этих систем, то можно дополнить эту схему при помощи Git репозитория, куда можно складывать конфиги под каждую систему и каждый из администраторов сможет вносить в них изменения, и при этом всем будет понятно когда и по какой причине в конфиг для конкретной системы вносились изменения (при условии, что всё это документируется при коммитах, конечно же).
Да и вспомнить через пару лет как была сконфигурирована система намного быстрее и нагляднее при помощи одного конфигурационного файла, нежели проводить инвентаризацию системы через GUI или консоль.
Но немного о самих модулях NetApp для Ansible. NetApp пожалуй активнее всего развивает их среди остальных стораджовых вендоров. И лишь Pure дышит им в затылок. Поддержка NetApp не ограничивается только системами под управлением ONTAP, также есть модули как для SolidFire, так и для E-series. Есть даже модули для поддержки 7-mode в старых версиях Ansible (были удалены в 2.11).

И так, расскажу, как на мой взгляд лучше построить этот процесс, а вы уже сможете применить его под себя, внеся необходимые правки. Но прежде чем переходить к написанию конфигурационного файла, надо всё-таки подготовить нашу рабочую станцию к работе. Как разворачивается сам Ansible я писал в одной из своих старых статей «Ansible знакомимся с системой на примерах». Дополнительно к этому нам понадобится модуль для работы с системами NetApp. Когда вы работаете с Ansible, крайне важным является использование самой свежей версии модулей. Очень часто проблемы с плейбуками возникают из-за того, что написаны они, например, для версии 2.8, а в версии 2.9 уже многое что изменилось и надо заглянуть в документацию на предмет изменений, которых обычно довольно много, в том числе и новые возможности в модулях. Поэтому ставить будем из Git.
yum install git -y git clone https://github.com/ansible/ansible.git ~/ansible-devel cd ~/ansible-devel git pull cd ~/ansible-devel/lib/ansible sudo yes|cp -aRv module_utils/netapp* /usr/lib/python2.7/site-packages/ansible/module_utils sudo yes|cp -aRv modules/storage/netapp/* /usr/lib/python2.7/site-packages/ansible/modules/storage/netapp/
Условно разделим на 2 этапа наше конфигурирование:
- Настройка параметров массива, которые не привязываются к SVM, а едины для всей системы
- Создание и настройка SVM
Начну с того, что первоначальную настройку я делаю всё-таки на самом массиве — это настройка менеджмента нод и создание кластера, после чего мы уже, собственно, сможем получить удалённый доступ к системе. И ещё одно действие, которое я предпочитаю всё-таки делать руками, привязка дисков в контроллерам и создание агрегатов. Во-первых потому что в модуле NetApp для Ansible нет поддержки работы с дисками, а создание аггрегатов вручную делается мной уже просто на автоматизме при конфигурировании дисков. Хотя никто не запрещает вам использовать для этого и Ansible, ведь это действительно просто. Начинать нужно с того, что мы скажем нашему плейбуку — где именно он будет запускаться и определим некоторые переменные.
---
- hosts: localhost
gather_facts: False
name: System setup
vars:
hostname: 192.168.1.130
username: admin
password: pass
Если вы уже имели дело с Ansible, то скорее всего заметите, что мы указываем нашему плейбуку, что запускаться он будет на localhost, хотя обычно мы указываем там имена хостов или имена групп хостов. Дело в том, что для работа Ansible с ONTAP (да на самом деле и с ElementOS) идёт не через привычный ssh, а посредствам http/https при помощи модулей, которые мы устанавливали ранее.
А теперь буквально в несколько строк мы создадим 2 агрегата
- name: Create Aggregates
na_ontap_aggregate:
state: present
service_state: online
name: "{{ item.aggr }}"
disk_count: "{{ item.disk_count }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
loop:
- { aggr: 'aggr1', disk_count: '13' }
- { aggr: 'aggr2', disk_count: '13' }
Есть ещё одна задача, которую необходимо выполнить на новой системе — создание VLAN’ов на портах. Если мы используем классическую двухконтроллерную систему, то мы должны как минимум на 4 портах массива настроить пару VLAN’ов. Конечно это не всегда так, их может как больше, так и меньше, или, если вы используете ONTAP Select, у вас может быть вообще один контроллер и один порт. Но я покажу общую концепцию, которую можно будет применить потом к любому количеству портов.
- name: Create VLANs
na_ontap_net_vlan:
state: present
vlanid: "{{ item.vlanid }}"
node: "{{ item.node }}"
parent_interface: "{{ item.parent_interface }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
loop:
- { node: 'korphome-01', vlanid: '13', parent_interface: 'e0a' }
- { node: 'korphome-01', vlanid: '14', parent_interface: 'e0a' }
- { node: 'korphome-01', vlanid: '15', parent_interface: 'e0a' }
- { node: 'korphome-01', vlanid: '16', parent_interface: 'e0a' }
Всё в принципе просто. На каждой из нод нашей системы на портах e0a мы создаём интерфейс с 13 VLAN ID, а на e0b с 14. В данном случае я использую loop и метод создания виртуального интерфейса выполнится 4 раза с заданными параметрами. Это не самая сложная схема, чуть более сложный вариант использования циклов я применю при создании вольюмов на агрегатах чуть позже.
Следующий этап — создание IPspaces и Broadcast Domains.
- name: Сreate broadcast domain
na_ontap_broadcast_domain:
state: present
name: ansible_domain
mtu: 1000
ipspace: Default
ports: ["korphome-01:e0a-13", "korphome-01:e0a-14"]
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
- name: Create ipspace
na_ontap_ipspace:
state: present
name: ansibleIpspace
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
И последним остаётся задать NTP сервер
- name: Create NTP server
na_ontap_ntp:
state: present
version: auto
server_name: "3.ru.pool.ntp.org"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
Теперь определив в первом конфигурационном файле все необходимые нам параметры (а вы, подправив их под свои нужды), можем запустить данный плейбук и получить первоначальные настройки на нашей системе.

Не удивляйтесь что у меня настройки немного расходятся с тем, что я предлагаю делать, просто эксперименты я провожу на ONTAP Select у которого всего один “контроллер” и всего один диск. Чтобы не собирать весь конфиг по тексту статьи, для удобства я выложу полный листинг обоих плейбуков в конце статьи. При помощи na_ontap_user вы возможно захотите добавить ещё и пользователей в систему с различными правами доступа.
С первым плейбуком и предварительной настройкой системы мы закончили, переходим ко второму этапу — создание и конфигурирование SVM. Это как раз одна из тех виртуальных сущностей, которая есть в системах ONTAP. Почему я решил их разделить на 2 части? Потому, что по моему опыту — создавать и модифицировать SVM приходится намного чаще, чем остальные настройки. Раз мы создаём отдельный плейбук, то ещё раз определим как он будет запускаться и с какими переменными, добавив туда сразу и имя нашего SVM.
---
- hosts: localhost
gather_facts: False
name: Create SVM
vars:
hostname: 192.168.1.130
username: admin
password: pass
vserver: AnsibleSVM
И первым делом, мы создаём саму сущностью SVM, которую будем уже дальше наполнять различными настройками.
- name: SVM Create
na_ontap_svm:
state: present
name: "{{ vserver }}"
root_volume: "{{ vserver }}_root"
root_volume_aggregate: aggr1
root_volume_security_style: unix
allowed_protocols: nfs,cifs,iscsi
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
Используется модуль na_ontap_svm, состояние указано в качестве present, т.е. мы его создаём. На самом деле, чтобы удалить какой-то элемент достаточно сменить present на absent, так что стоит быть внимательнее. Но по логике работы самого Ontap вы не сможете просто удалить SVM, предварительно нужно будет удалить всё его содержимое с данными (луны, вольюмы, шары) и некоторые связанные с ним настройки (igrop’ы, например), а уже потом удалять сам SVM. Но вернёмся к заданию создания SVM. Если вы работали с системами ONTAP, то большинство указанных параметров вам понятны. Имя SVM Create мы объявили в переменной в самом начале — AnsibleSVM, т.к. все наши настройки будут связаны именно с SVM, чтобы нам было достаточно только один раз его указать в конфигурационном файле для большей гибкости в далнейшем использовании этого конфига с другими системами. А вот последние 5 строк задачи создания SVM будут преследовать нас до самого конца. Как я уже говорил ранее, работа Ansible с ONTAP осуществляется посредством http/https и каждая задача — это отдельное обращение к массиву, для чего нам требуется каждый раз авторизовываться, говорить какой протокол мы используемся и что делать с сертификатом. Конечно это не совсем удобно и очень сильно раздувает конфигурационный файл.
Зададим настройки DNS
- name: Create DNS
na_ontap_dns:
state: present
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
domains: korphome.local
nameservers: 192.168.1.216
skip_validation: true
https: true
validate_certs: false
С применением loop, который мы использовали при создании VLAN’ов, мы создадим необходимые виртуальные интерфейсы.
- name: Create interface
na_ontap_interface:
state: absent
interface_name: "{{ item.interface_name }}"
home_port: "{{ item.home_port }}"
home_node: "{{ item.node }}"
role: data
protocols: "{{ item.protocols }}"
admin_status: up
firewall_policy: mgmt
address: "{{ item.address }}"
netmask: 255.255.255.0
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
loop:
- { node: 'korphome-01', interface_name: '{{ vserver }}_iscsi_1', protocols: 'iscsi', home_port: 'e0a', address: '192.168.1.165' }
- { node: 'korphome-01', interface_name: '{{ vserver }}_iscsi_2', protocols: 'iscsi', home_port: 'e0a', address: '192.168.1.166' }
- { node: 'korphome-01', interface_name: '{{ vserver }}_data_1', protocols: 'nfs,cifs', home_port: 'e0a', address: '192.168.1.167' }
- { node: 'korphome-01', interface_name: '{{ vserver }}_data_2', protocols: 'nfs,cifs', home_port: 'e0a', address: '192.168.1.168' }
Как я уже упоминал выше — моя конфигурация будет казаться немного странной. В данном случае у меня весь трафик идёт через один единственный порт, но т.к. мы готовим всё-таки универсальный скрипт для физической системы, я хочу показать как он должен выглядеть в идеальном случае.
Одним из протоколов, с которым мы будем работать, который мы указали при создании SVM, будет iSCSI, мы также создали для него 2 интерфейса, через которые будет ходить трафик и теперь нам необходимо создать на SVM сам сервис iSCSI и запустить его.
- name: Start iscsi service
na_ontap_iscsi:
state: absent
service_state: started
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
Следующим этапом станет создание группы инициаторов, которые будут работать с нашим массивом по iSCSI.
- name: Create igroup
na_ontap_igroup:
state: absent
name: ansibleIgroup
initiator_group_type: iscsi
ostype: vmware
initiator: iqn.1998-01.com.vmware:esxi6-68316bc6,iqn.1991-05.com.microsoft:veeamv10
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
Определяем произвольное имя группы хостов, задаём ostype и через запятую указываем iqn наших серверов. При создании SVM мы указали, что он будет работать ещё и с файловыми протоколами nfs,cifs и для них также необходимо сконфигурировать и запустить сервисы.
- name: Start nfs service
na_ontap_nfs:
state: absent
service_state: started
vserver: "{{ vserver }}"
nfsv3: disabled
nfsv4: disabled
nfsv41: enabled
tcp: disabled
udp: disabled
vstorage_state: disabled
nfsv4_id_domain: korphome.local
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
- name: Create ans start cifs service
na_ontap_cifs_server:
state: absent
cifs_server_name: ontap
workgroup: korphome
service_state: started
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
Для NFS нам необходимо указать по какой из версий протокола у нас клиенты будут получать доступ, в описании к na_ontap_nfs есть параметры, связанные с правами доступа, которые вам тоже могут понадобится. А для CIFS достаточно указать только workgroup.
Теперь нам осталось организовать луны и шары, на которых собственно и будут храниться наши данные. Но прежде чем переходить к их созданию, немного поговорим об именовании. Дело в том, что в зависимости от проекта, я именую луны и вольюмы по-разному. Где-то это просто порядковые номер vol1, vol2, vol3. А для некоторых проектов мне необходимо указывать какие-то более человеческие имена, типа sevr1_db_2. От этого варианты генериции конфига для Ansible будут немного отличаться. Я покажу оба варианта, а вы уже сможете взять тот вариант, который больше подходит для вас. И так, первый вариант — числовое именование.
- name: Volume Create
na_ontap_volume:
state: present
name: "vol_{{ item.1.name }}"
vserver: "{{ vserver }}"
aggregate_name: "{{ item.0.aggr }}"
size: 30
size_unit: gb
policy: default
percent_snapshot_space: 0
efficiency_policy: default
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
loop: "{{ lookup('subelements', aggrs, 'volumes', {'skip_missing': True}) }}"
vars:
aggrs:
- { name: "aggr1", volumes: [11,13,15,17] }
- { name: "aggr2", volumes: [12,14,16,18] }
Здесь мы используем итератор внутри loop. Данный конфиг создаст 4 вольюма vol11, vol13, vol15, vol17 на агрегате aggr1 и 4 вольюма с чётными числами на втором агрегате. Не забываем внести изменения в size и size_unit и поправить percent_snapshot_space и efficiency_policy под свои требования.
Создать луны под этот шаблон именования будет также просто
- name: Create LUN
na_ontap_lun:
state: present
name: "lun_{{ item }}"
flexvol_name: "vol_{{ item }}"
vserver: "{{ vserver }}"
size: 5
size_unit: gb
ostype: vmware
space_reserve: no
space_allocation: yes
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
with_sequence: start=11 end=18
with_sequence это такой же итератор, который создаст нам по одному луну на каждом из наших вольюмов. Не забываем внести изменения в size и size_unit и поправить percent_snapshot_space и efficiency_policy под свои требования. Изменяем ostype, если наши хосты не являются VMware и правим space_reserve и space_allocation, если хотите использовать другие параметры. Таким образом мы получим следующую структуру
aggr1/vol11/lun11
aggr2/vol12/lun12
aggr1/vol13/lun13
aggr2/vol14/lun14
aggr1/vol15/lun15
aggr2/vol16/lun16
aggr1/vol17/lun17
aggr2/vol18/lun18
Быстро и удобно, но не все отвечает требования задачи. Если мы хотим указывать какие-то конкретные имена вольюмов/лунов, то можно воспользоваться другим вариантом
- name: Volume Create
na_ontap_volume:
state: present
name: "vol_{{ item.1.name }}"
vserver: "{{ vserver }}"
aggregate_name: "{{ item.0.aggr }}"
size: 30
size_unit: gb
policy: default
percent_snapshot_space: 0
efficiency_policy: default
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
with_subelements:
- "{{ volumes }}"
- volume
vars:
volumes:
- aggr: aggr1
volume:
- name: server1_db1_vol
- name: server2_db1_vol
- aggr: aggr2
volume:
- name: server1_db2_vol
- name: server2_db2_vol
Также не забываем про size, size_unit, percent_snapshot_space и efficiency_policy. И по аналогии создадим луны
- name: Create LUN
na_ontap_lun:
state: present
name: "lun_{{ item }}"
flexvol_name: "vol_{{ item }}"
vserver: "{{ vserver }}"
size: 5
size_unit: mb
ostype: vmware
space_reserve: no
space_allocation: yes
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
with_subelements:
- "{{ volumes }}"
- lun
vars:
volumes:
- vol: server1_db1_vol
lun:
- name: server1_db1_lun
- vol: server2_db1_vol
lun:
- name: server2_db1_lun
- vol: server1_db2_vol
lun:
- name: server1_db2_lun
- vol: server2_db2_vol
lun:
- name: server2_db2_lun
Здесь тоже не забудьте про параметры: size и size_unit, percent_snapshot_space, efficiency_policy, ostype, space_reserve и space_allocation. Честно скажу, этот вариант мне не сильно нравится, но иногда приходится использовать и его. Проблема в том, что это сильно увеличивает конфиг и снижает его читабельность. При этом потом такую же конструкцию придётся использовать при мапинге, т.к. нам нужно будет указывать целиком путь /vol/vol_name/lun_name. Потому что с итератором это делать всё-таки намного проще
- name: Create LUN mapping
na_ontap_lun_map:
state: present
initiator_group_name: ansibleIgroup
lun_id: "{{ item }}"
path: "/vol/vol_{{ item }}/lun_{{ item }}"
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
with_sequence: start=11 end=18
Параметр lun_id в принципе можно не указывать, но удобнее, когда порядковый номер луна совпадает с Lun ID, который видно со стороны сервера. И главный параметр в этом конфиге — initiator_group_name, группа, которую мы создавали уже ранее и к которой мы мапим наши луны.
И последнее, что осталось нам сегодня сделать — создать CIFS и создать доступ по NFS.
- name: Create CIFS share
na_ontap_cifs:
state: present
share_name: Share
path: /
share_properties: browsable,oplocks
symlink_properties: read_only,enable
vserver: "{{ vserver }}"
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
https: true
validate_certs: false
Все share_properties описаны в документации к ONTAP vserver cifs share properties show, а параметры symlink_properties в Configuring UNIX symbolic link support on SMB shares.
Конечно в этой статья я описал далеко не все модули и даже не все возможности модулей, которые использовал для примеров. Но я и не ставил перед собой такой задачи, я лишь хотел показать, как можно удобно построить процесс настройки массивов под управлением ONTAP (в том числе и ONTAP Select). По сути, при помощи Ansible вы можете настроить практически всё тоже самое, что можете настроить из GUI (в CLI возможности конечно шире). Самое главное — сделать это будет удобнее и быстрее. Предварительно собираете необходимую для настройки информацию: ip-адреса для lif’ов, адреса dns, ntp, имена SVM и томов, быстро заполняете это в конфигурационном файле и за одну минуту производите настройку всей системы. Я считаю это отличным решением и потихоньку стараюсь внедрить этот подход у нас. Но а если у вас остались ещё вопросы, или что то не получается, можно написать мне или в канал Netapp.io в Slack.
Как и обещал, в конце полный листинги:
system_setup.yml
create_svm.yml

Один ответ к «NetApp + Ansible»