Привет, Хабр.
В одном из наших недавних постов мы немного затронули тему автоматизации, которую мы активно продвигаем в наших продуктах. По различным каналам мы получили много положительных откликов и дополнительных вопросов о том, как можно использовать наши API для различных интеграций.
В рейтинге наиболее популярных «хотелок» – интеграция системы хранения данных с внешними отечественными или opensource продуктами: системы мониторинга, системы управления и планирования ёмкостей или сложные автоматизированные метрокластеры с классическим набором серверов приложений, СУБД и систем виртуализации. Решив, что краткого упоминания о REST API в системах хранения данных АЭРОДИСК явно недостаточно, в этой статье мы расскажем о том, как автоматизировать создание классических репликации, конфигурации метрокластера и управлять переключением сайтов с использованием REST API и Python. А послушать про это можно будет на вебинаре «ОколоИТ», который пройдёт 12 марта в 15:00 – регистрируйтесь по ссылке.
Немного матчасти
Прежде чем перейти к непосредственной разработке скриптов для автоматизированной настройки СХД через REST API, залезем под капот СХД АЭРОДИСК в части работы API.
При разработке API доступного конечному пользователю продукта, очень важно применять такие же принципы, как и при разработке качественного Front-End интерфейса, а именно учитывать пользовательский опыт и понимать, насколько удобно будет использовать тот или иной метод, рассчитывая на то, что использовать его будет скорее всего не команда разработки, а системный администратор заказчика. Немаловажным является качественное документирование API и возможных параметров при вызове методов. Для документирования REST API мы активно используем автодокументирование кода, написанного по спецификации OpenAPI с помощью известного пакета с открытым исходным кодом Swagger. Это позволяет одновременно получить качественный код, тест-кейсы под него и инструмент визуализации выполнения запросов (обычно в рамках обучения или отладки) с помощью Swagger UI. Естественно, это не отменяет необходимость написания технической документации для конечного пользователя с более подробным набором инструкций и примеров, но даже не имея под рукой никаких документов от вендора, можно довольно быстро разобраться с REST API, используя Swagger.
Приступим
Как знают администраторы СХД АЭРОДИСК, все управление нашим дисковым массивом выполняется через браузер: добавив в строке браузера “/api/docs/”, вы попадете как раз в управление СХД с помощью REST API и Swagger.

Названия разделов поделены согласно функциям дискового массива:
Authentication – авторизация пользователей, после авторизации будут доступны все остальные REST API запросы к СХД;
DDP – управление DDP группами, создание и удаление пулов, томов, снимков данных;
RDG – управление RDG группами, создание и удаление пулов, томов, снимков данных;
Disk – получение информации об установленных в СХД дисках;
Network – управление сетью, vlan, vip;
FC – управление Fibre Channel таргетами, группами, маппингами томов;
iSCSI – управление iSCSI таргетами, группами, маппингами томов;
Consistency group – управление группами консистентности;
Rrepl – управление удаленной репликацией и метрокластером, создание репликационных пар, управление переключением.
Авторизация
После авторизации пользователя становятся доступными все разделы по управлению СХД. При использовании Swagger UI возможно составить и отправить REST запрос, получить и проанализировать ответ СХД, а также использовать автоматически сгенерированный запрос curl, который уже можно использовать в своих скриптах.
Авторизация - обычно первая сложность, которую приходится побороть начинающему пользователю REST API. Для авторизации применяется endpoint http://IP_адрес/api/auth/token, куда c помощью POST запроса отправляются данные о пользователе и пароле. В ответе же в формате JSON приходит специальный токен, который можно использовать для авторизации при выполнении других команд. Токен действует в течение 1 часа, после этого времени необходимо его перегенерировать. Приведем пример получения токена авторизации с помощью curl:
curl -X 'POST' \
'http://192.168.11.30/api/auth/token' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=&username=admin&password=Bac12345&scope=&client_id=&client_secret='
Ответом на эту команду будет возвращен JSON c токеном (Response Body):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6NDkyMjczMzMzM30.Xe5poHQdIUJ_8yAlWfT_yHVVEgjhnmpLJa4NjmAN4pA",
"token_type": "bearer"
}
Далее можно использовать авторизационный токен, например, при получении информации о DDP пуле DDP1:
curl -X 'GET' \
'http://192.168.11.30/api/ddp/pool?name=DDP1' \
-H 'accept: application/json' \
-H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6NDkyMjczMzMzM30.Xe5poHQdIUJ_8yAlWfT_yHVVEgjhnmpLJa4NjmAN4pA'
Ответом на эту команду будет JSON c информацией о пуле DDP1:
[
{
"name": "DDP1",
"fullSize": 7681507065856,
"sizeAvailable": 7670761259008,
"dataDisksQty": 2,
"cacheDisksQty": 0,
"hotSpare": true,
"blockSize": 4194304,
"uuid": "wOCgyZ-oDio-HOLV-cR01-S7jj-TxZF-80G2ij",
"state": "UP",
"health": "ONLINE",
"lunQty": 0,
"alua": false,
"missingDisks": 0,
"disksInfo": [
{
"wwn": "35000c500a189620b",
"free": 3835380629504,
"diskType": "data"
},
{
"wwn": "35000c500a189625b",
"free": 3835380629504,
"diskType": "data"
}
],
"thinStorage": false
}
]
Метрокластер и репликация
Метрокластер – технология, позволяющая обеспечить доступность данных с помощью разнесения СХД на несколько площадок в пределах города или района и использовании репликации данных между ними. Основное отличие метрокластера от классической репликации – это автоматизация обработки отказов оборудования при обеспечении потребителей актуальными данными. Подробно о метрокластере и сценариях отказа мы рассказывали в одном из наших постов на Хабре и даже проводили демонстрацию на вебинаре «ОколоИТ». Здесь же поговорим о той подготовительной работе, которую необходимо провести при начальном развертывании метрокластера и как её можно автоматизировать с помощью REST API.
Подробные инструкции о настройке метрокластера приведены в руководстве администратора СХД, поэтому перечислим тут лишь основные необходимые шаги:
создание группы (RDG или DDP);
создание томов;
создание IP ресурсов для репликации и метрокластера;
создание репликационных связей;
создание маппингов томов;
управление переключением сайта (Primary/Secondary).
Естественно все шаги можно делать из GUI, но для двух массивов и, например, 20 томов это займет достаточно много времени даже у опытного системного администратора.
Приведем пример создания всей инфраструктуры метрокластера через REST API и Python. Ниже приведем шаги и листинги Python скриптов, при этом конфигурационные файлы и импортируемые модули приложим отдельными файлами.
Шаг 1 - создадим по два DDP пула на двух СХД (скрипт запускается два раза с разными настройками целевой СХД в конфигурационном файле config.conf):
import json
from pages_methods.base_methods import *
from pages_methods.DDP import *
ddp_post_create_pool = {
'name_pool': "DDP1",
'qty_disks': 4
'is_alua': 0,
'block_size': 4194304,
'is_hotspare': 0,
'max_recovery_rate': 50000}
name_pool = ddp_post_create_pool.get("name_pool")
qty_disks = ddp_post_create_pool.get("qty_disks")
is_alua = ddp_post_create_pool.get("is_alua")
block_size = ddp_post_create_pool.get("block_size")
is_hotspare = ddp_post_create_pool.get("is_hotspare")
max_recovery_rate = ddp_post_create_pool.get("max_recovery_rate")
disks = BaseApp.get_wwn_disks (4, "SSD")
print (disks)
Ddp_Methods.post_create_pool(name_pool, is_alua, block_size, is_hotspare, max_recovery_rate, qty_disks)
ddp_post_create_pool = {
'name_pool': "DDP2",
'qty_disks': 4,
'is_alua': 0,
'block_size': 4194304,
'is_hotspare': 0,
'max_recovery_rate': 50000}
name_pool = ddp_post_create_pool.get("name_pool")
qty_disks = ddp_post_create_pool.get("qty_disks")
is_alua = ddp_post_create_pool.get("is_alua")
block_size = ddp_post_create_pool.get("block_size")
is_hotspare = ddp_post_create_pool.get("is_hotspare")
max_recovery_rate = ddp_post_create_pool.get("max_recovery_rate")
disks = BaseApp.get_wwn_disks (4, "SSD")
print (disks)
Ddp_Methods.post_create_pool(name_pool, is_alua, block_size, is_hotspare, max_recovery_rate, qty_disks)
После выполнения скрипта можем видеть, что создались два пула на СХД1 и СХД2:

Шаг 2 - создадим по 22 тома на двух СХД:
for i in range (121,132): Ddp_Methods.post_create_lun("DDP2", "RAID-10", 300000000000, f'VOL{i}', "", 0, 0, 0)
for i in range (101,112): Ddp_Methods.post_create_lun("DDP1", "RAID-10", 300000000000, f'VOL{i}', "", 0, 0, 0)

Шаг 3 - создадим репликационные IP ресурсы (адреса) на каждой СХД:
СХД 1:
for i in range (101,112): Network_Methods.post_create_vip("ens11f1", "ens11f1", f'192.168.100.{i}', "255.255.255.0", "DDP1", "repl", None)
for i in range (121,132): Network_Methods.post_create_vip("ens11f1", "ens11f1", f'192.168.100.{i}', "255.255.255.0", "DDP2", "repl", None)

СХД2 – не забываем поменять адрес СХД в файле config:
for i in range (151,162): Network_Methods.post_create_vip("ens11f1", "ens11f1", f'192.168.100.{i}', "255.255.255.0", "DDP1", "repl", None)
for i in range (171,182): Network_Methods.post_create_vip("ens11f1", "ens11f1", f'192.168.100.{i}', "255.255.255.0", "DDP2", "repl", None)

Шаг 4 - создадим репликационные связи между томами для каждого из томов:
for i in range (101,112):
payload = {
"name": f'rpl1ddp{i}',
"protocol": "C",
"local_node": {
"pool_type": "DDP",
"pool_name": "DDP1",
"lun_name": f'VOL{i}',
"vip": f'192.168.100.{i}'
},
"remote_nodes": [
{
"pool_type": "DDP",
"pool_name": "DDP1",
"lun_name": f'VOL{i}',
"vip": f'192.168.100.{i+50}'
}
]}
print(payload)
url = f'{URL}/rrepl/node'
resp = requests.post(url, data=dumps(payload), headers=HEADERS)
print (resp.text)
for i in range (121,132):
payload = {
"name": f'rpl2ddp{i}',
"protocol": "C",
"local_node": {
"pool_type": "DDP",
"pool_name": "DDP2",
"lun_name": f'VOL{i}',
"vip": f'192.168.100.{i}'
},
"remote_nodes": [
{
"pool_type": "DDP",
"pool_name": "DDP2",
"lun_name": f'VOL{i}',
"vip": f'192.168.100.{i+50}'
}
]}
print(payload)
url = f'{URL}/rrepl/node'
resp = requests.post(url, data=dumps(payload), headers=HEADERS)
print (resp.text)

Шаг 5 - создадим VIP метрокластера (адреса для iSCSI порталов метрокластера).
Для большей наглядности сделаем это в графическом интерфейсе СХД. Естественно, можно сделать это через знакомый нам уже endpoint /api/network/vip.

Шаг 6 - сконфигурируем метрокластер и арбитр в интерфейсе.
Введем IP адреса арбитра и второй СХД:

Шаг 7 - подключим репликационные пары СХД1 к метрокластеру:
for i in range (101,112):
payload = {
"node_ip": f'192.168.100.{i}',
"name": f'rpl1ddp{i}',
"metro_ip": "192.168.11.23",
"metro_mask": 24
}
print(payload)
url = f'{URL}/rrepl/node~connect_metro'
resp = requests.post(url, data=dumps(payload), headers=HEADERS)
print (resp.text)
for i in range (121,132):
payload = {
"node_ip": f'192.168.100.{i}',
"name": f'rpl2ddp{i}',
"metro_ip": "192.168.11.24",
"metro_mask": 24
}
print(payload)
url = f'{URL}/rrepl/node~connect_metro'
resp = requests.post(url, data=dumps(payload), headers=HEADERS)
print (resp.text)

Для подключения СХД2 к метрокластеру, необходимо отключить VIP метрокластера на СХД1, сконфигурировать арбитр и связь со вторым СХД и, аналогично предыдущему шагу, выполнить скрипт подключения к метрокластеру каждой репликационной пары.
Шаг 8 - подключим репликационные пары СХД2 к метрокластеру:
for i in range (101,112):
payload = {
"node_ip": f'192.168.100.{i+50}',
"name": f'rpl1ddp{i}',
"metro_ip": "192.168.9.23",
"metro_mask": 24
}
print(payload)
url = f'{URL}/rrepl/node~connect_metro'
resp = requests.post(url, data=dumps(payload), headers=HEADERS)
print (resp.text)
for i in range (121,132):
payload = {
"node_ip": f'192.168.100.{i+50}',
"name": f'rpl2ddp{i}',
"metro_ip": "192.168.9.24",
"metro_mask": 24
}
print(payload)
url = f'{URL}/rrepl/node~connect_metro'
resp = requests.post(url, data=dumps(payload), headers=HEADERS)
print (resp.text)

Далее можно презентовать тома с каждого дискового массива для хостов и пользоваться отказоустойчивым сервисом по хранению данных.
При возникновении необходимости переключить направление репликации метрокластера можно воспользоваться графическим интерфейсом, либо также использовать REST API Post запрос /api/rrepl/node~set_primary
.
Подводим итоги
Как видно из примеров выше, начать пользоваться REST API для автоматизации рутинных задач системного администратора достаточно просто. Естественно, можно прикрутить работу с API в любое приложение, интегрировать управление с мобильного устройства, встроить необходимые алгоритмы в портал самообслуживания для частного облака или даже создать свою графическую оболочку для управления СХД, максимально адаптированную под решаемую задачу.
Если вас заинтересовали возможности API АЭРОДИСК и вы хотите попробовать использовать REST для управления СХД, все примеры для работы и документация доступна на нашем портале docs.aerodisk.ru.
Чтобы узнать больше про REST API записывайтесь на наш вебинар «ОколоИТ» 12 марта. На нём мы покажем, как пользоваться REST API, попробуем что-нибудь сломать и, естественно, починить в СХД АЭРОДИСК без перерыва сервиса с помощью технологий метрокластера ?
Мероприятие бесплатное, регистрация обязательна!