Примеры использования ADCM AIO Client

Содержание
ВНИМАНИЕ
На данный момент реализована альфа-версия ADCM AIO Client. При необходимости обратная совместимость с последующими версиями может быть нарушена. Релизу будет присваиваться статус "альфа" до тех пор, пока мажорная версия равна нулю (0.<minor>.<patch>). Список релизов ADCM AIO Client представлен в репозитории проекта на GitHub.

ADCM AIO Client предназначен для одновременного выполнения нескольких запросов без блокировки основного потока за счет асинхронной архитектуры.

Благодаря асинхронной обработке запросов ADCM AIO Client позволяет эффективнее управлять задачами, сокращая задержки и увеличивая пропускную способность. Реализованные расширенные механизмы обработки ошибок предназначены для корректного управления сбоями в асинхронной среде.

Объектная модель ADCM AIO Client отображает архитектуру ADCM и структуру его объектов, таких как кластеры, хосты, сервисы, компоненты, бандлы и др.

В этой статье приведены примеры использования ADCM AIO Client для управления объектами и конфигурациями ADCM.

Начало работы с ADCM AIO Client

Следуйте инструкциям ниже для настройки и использования ADCM AIO Client.

ВНИМАНИЕ
Перед установкой убедитесь, что Python не ниже 3.12.0 и pip доступны в вашей системе.
  1. Установите ADCM AIO Client, используя следующую команду:

    $ pip install adcm_aio_client
  2. Настройте соединение с ADCM. Ниже приведен пример получения списка кластеров для иллюстрации процедуры настройки соединения:

    import asyncio
    from adcm_aio_client import ADCMSession, Credentials
    
    # Учетные данные пользователя для подключения к веб-интерфейсу ADCM
    credentials = Credentials(username="<username>", password="<password>")
    
    # Настройка повторной отправки запроса
    kwargs = {"verify": False, "timeout": 10, "retry_interval": 1, "retry_attempts": 1}
    
    async def get_clusters():
    
        # Создание соединения с ADCM
        async with ADCMSession(url="http://<ip_address>:<port>", credentials=credentials, **kwargs) as client:
            # Получение кластеров
            clusters = await client.clusters.all()
    
    asyncio.run(get_clusters())

где:

  • timeout — время ожидания соединения с ADCM в секундах (значение по умолчанию — 600);

  • retry_interval — интервал времени между повторными попытками соединения с ADCM в секундах (значение по умолчанию — 3);

  • retry_attempts — количество повторных попыток соединения (значение по умолчанию — 1);

  • <username> — имя учетной записи пользователя;

  • <password> — пароль учетной записи пользователя;

  • <ip_address> — IP-адрес хоста, на котором развернут ADCM;

  • <port> — номер порта для соединения с ADCM.

Для установки HTTPS-соединения с ADCM (с использованием SSL-сертификата) должен быть передан параметр verify. Этот параметр определяет полный путь к файлу, включая имя файла, который содержит сертификат, подписанный центром сертификации (Certificate Authority, CA).

ПРИМЕЧАНИЕ
Убедитесь, что URL начинается с префикса https, а в качестве значения параметра <port> указан номер 8443.
import asyncio
from adcm_aio_client import ADCMSession, Credentials

credentials = Credentials(username="<username>", password="<password>")

verify = "/<file_path>/<certificate_file_name>.pem"

async def get_clusters():
    # Создание соединения с ADCM с использованием SSL
    async with ADCMSession(url="https://<ip_address>:8443", credentials=credentials, verify=verify) as client:
        # Получение кластеров
        clusters = await client.clusters.all()

asyncio.run(get_clusters())

Загрузка бандла

# Загрузка бандла с последующим принятием лицензионного соглашения
await client.bundles.create("https://downloads.arenadata.io/ADB/5.25.0_arenadata6/bundles/adcm_cluster_adb_v5.25.0_arenadata6_b1-1_enterprise.tgz", accept_license=True)

Создание хостпровайдера

# Определение загруженного бандла, на основе которого будет создан хостпровайдер
bundle = await client.bundles.get(name__eq="SSH Common")

# Создание хостпровайдера
hostprovider = await client.hostproviders.create(bundle=bundle, name="SSH")

Создание хостов

# Определение хостпровайдера
hostprovider=await client.hostproviders.get(name__eq="SSH")

# Создание хоста
host = await client.hosts.create(name="zar-adb-master", hostprovider=hostprovider))

Создание кластера

# Определение загруженного бандла, на основе которого будет создан кластер
bundle = await client.bundles.get(name__eq="ADB", version__eq="5.25.0_arenadata6_b1-1")

# Создание кластера
cluster = await client.clusters.create(bundle=bundle, name="Test_ADB_cluster")

Добавление сервисов

# Определение требуемого кластера и сервиса для добавления
cluster = await client.clusters.get(name__eq="Test_ADB_cluster")
service_name_conditions = Filter(attr="display_name", op="ieq", value="ADB")

# Добавление сервиса в кластер с последующим принятием лицензионного соглашения и установкой взаимозависимости сервисов
await cluster.services.add(service_name_conditions, accept_license=True, with_dependencies=False)

Добавление хостов в кластер

# Определение требуемого кластера и хоста для добавления
cluster = await client.clusters.get(name__eq = "Test_ADB_cluster")
host = await client.hosts.get(name__ieq = "zar-adb-master")

# Добавление хоста в кластер
added_host = await cluster.hosts.add(host=host)

Управление распределением компонентов между хостами кластера

ADCM AIO Client предоставляет метод mapping.add(component: Component | List[Component], host: Host| List[Host]) для распределения компонентов между хостами кластера.

ПРИМЕЧАНИЕ
До вызова метода mapping.save() изменения в распределении компонентов между хостами кластера будут сохранены локально.
"""
Локальное распределение компонентов между хостами кластера
"""
# Получение хостов и компонентов для распределения
components = await mapping.components.filter(display_name__iin=component_name_list)
hosts = await mapping.hosts.filter(name__iin=host_name_list)

# Передача полученных хостов и компонентов в качестве входных данных функции
await mapping.add(component=components, host=hosts)

# Распределение компонентов между хостами кластера
master_node = ["zar-adb-master"]
standby_node = ["zar-adb-standby"]
segment_node = ["zar-adb-segment1", "zar-adb-segment2"]

master_component = ["ADB Master"]
standby_component = ["ADB Standby"]
segment_component = ["ADB Segment"]

cluster = await client.clusters.get(name__eq="Test_ADB_cluster")
mapping = await cluster.mapping

await map_components_to_hosts(mapping, master_component, master_node)
await map_components_to_hosts(mapping, standby_component, standby_node)
await map_components_to_hosts(mapping, segment_component, segment_node)

# Сохранение распределения компонентов между хостами кластера
await mapping.save()

Также ADCM AIO Client позволяет управлять распределением компонентов между хостами кластера с помощью следующих методов:

  • mapping.all() — возвращает текущие сопоставленные пары.

  • mapping.empty() — сбрасывает локальные изменения в распределении компонентов, оставляя их пустыми.

  • mapping.refresh() — актуализирует текущие локальные изменения в распределении компонентов с учетом изменений на удаленном сервере. При возникновении конфликтов метод применяет одну из следующих стратегий:

    • apply_local_changes — локальные изменения имеют более высокий приоритет, чем изменения на удаленном сервере.

    • apply_remote_changes — изменения на удаленном сервере имеют более высокий приоритет, чем локальные изменения.

    Приведенный пример показывает использование метода mapping.refresh(). При возникновении конфликтов будут применены локальные изменения, так как strategy принимает значение apply_local_changes.

    cluster = await client.clusters.get(name__eq="Test_ADB_cluster")
    mapping = await cluster.mapping
    
    component_2 = await mapping.components.filter(display_name__eq="ADBM server")
    host_1 = await mapping.hosts.filter(name__eq="zar-adb-master")
    host_2 = await mapping.hosts.filter(name__eq="zar-adb-control")
    
    await mapping.refresh(strategy=apply_local_changes)
    
    await mapping.remove(component_2, host_1)
    await mapping.add(component_2, host_2)
    
    await mapping.save()

Управление конфигурацией объекта

ADCM AIO Client позволяет получить и изменить значение конфигурационного параметра объекта (хостпровайдера, кластера, сервиса и компонента) и ADCM.

Также при необходимости локальные изменения значений конфигурационных параметров могут быть сброшены с помощью метода config.reset().

Ниже приведены примеры настройки параметров кластера.

ПРИМЕЧАНИЕ
Обратите внимание на то, как указать путь к параметру конфигурации в дереве конфигурационных настроек.

Получение значения конфигурационного параметра

# Определение требуемого кластера
cluster = await client.clusters.get(name__eq="Test_ADB_cluster")

# Получение объекта, управляющего конфигурацией кластера
config = await cluster.config

# Получение значения конфигурационного параметра
parameter = config['Vault integration']['Address of the Vault server'].value

Изменение значения конфигурационного параметра

# Определение требуемого кластера
cluster = await client.clusters.get(name__eq="Test_ADB_cluster")

# Получение объекта, управляющего конфигурацией кластера
config = await cluster.config

# Получение конфигурационного параметра
parameter = config['Vault integration']['Address of the Vault server']

# Определение нового значения конфигурационного параметра
parameter.set('192.168.1.120')

# Сохранение новой конфигурации
await config.save()

Управление конфиг-группами объекта

ADCM AIO Client предоставляет методы, описанные ниже, для выполнения следующих операций над конфиг-группами:

Также ADCM AIO Client позволяет вызвать следующие методы для управления конфиг-группами объекта:

  • configuration.reset() — сбрасывает локальные изменения в конфигурации конфиг-группы.

  • config_group.hosts.remove(host: Host| List[Host] | Filter) — удаляет хосты из конфиг-группы.

  • config_group.delete() — удаляет конфиг-группу из кластера.

Создание конфиг-группы кластера

# Определение требуемого кластера
cluster = await client.clusters.get(name__eq="Test_ADH_cluster")

# Определение объекта, управляющего группой хостов кластера
config_group = cluster.config_host_groups

# Получение объектов хостов из списка хостов
hosts_for_add = await cluster.hosts.filter(name__iin=["zar-adh-segment1", "zar-adh-segment2"])

# Создание конфиг-группы
await config_group.create(name="config-group-1", hosts=hosts_for_add)

Получение списка конфиг-групп кластера

# Определение требуемого кластера
cluster = await client.clusters.get(name__eq="Test_ADH_cluster")

# Получение списка конфиг-групп
config_group_list = await cluster.config_host_groups.all()

Добавление хоста в конфиг-группу кластера

# Определение требуемого кластера
cluster = await client.clusters.get(name__eq="Test_ADH_cluster")

# Определение конфиг-группы для добавления хоста
config_group = await cluster.config_host_groups.get(name__eq="config-group-2")

# Получение добавляемого хоста
added_host = await cluster.hosts.filter(name__iin="zar-adh-master")

# Добавление хоста
host_add = await config_group.hosts.add(host=added_host)

Получение значения параметра конфиг-группы сервиса

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="Test_ADH_cluster")
service = await cluster.services.get(name__eq="hbase")

# Определение конфиг-группы сервиса
config_group = await service.config_host_groups.get(name__eq="service-group-1")

# Получение объекта, управляющего конфигурацией конфиг-группы
configuration = await config_group.config

parameter = configuration["hbase-site.xml"]["hbase.client.max.perregion.tasks"].value

Изменение значения параметра конфиг-группы сервиса

ПРИМЕЧАНИЕ
Метод configuration["<Path to parameter>"].sync() позволяет включить синхронизацию значения параметра конфиг-группы с конфигурацией объекта (Primary configuration). Чтобы выключить синхронизацию и изменить значение параметра, используйте метод configuration["<Path to parameter>"].desync().
# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="Test_ADH_cluster")
service = await cluster.services.get(name__eq="hbase")

# Определение конфиг-группы сервиса
config_group = await service.config_host_groups.get(name__eq="service-group-1")
configuration = await config_group.config

# Включение синхронизации значения параметра с конфигурацией объекта
configuration["hbase-site.xml"]["hbase.client.max.perregion.tasks"].desync()

# Определение нового значения параметра конфиг-группы
configuration["hbase-site.xml"]["hbase.client.max.perregion.tasks"].set(50)

# Сохранение новой конфигурации
await configuration.save()

Управление группами хостов для действий

ADCM AIO Client предоставляет методы, которые позволяют выполнять следующие операции над группами хостов:

Также ADCM AIO Client позволяет вызвать следующие методы для управления группами хостов:

  • action_host_group.hosts.remove() — удаляет хосты из группы хостов.

  • action_host_group.delete() — удаляет группу хостов из объекта ADCM.

Создание группы хостов для действий

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="Test ADQM cluster")
service = await cluster.services.get(name__eq="adqmdb")

# Определение объекта, управляющего группой хостов
action_group = service.action_host_groups

# Определение объектов хостов из списка хостов
hosts_for_add = await cluster.hosts.filter(name__iin=["dev-adqm-01.ru-central1.internal", "dev-adqm-04.ru-central1.internal"])

# Создание группы хостов для действий
action_group_create = await action_group.create(name="hosts_1-4", hosts=hosts_for_add)

Получение списка групп хостов

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="Test_ADQM_cluster")
service = await cluster.services.get(name__eq="adqmdb")

# Получение списка групп хостов
action_group_list = await service.action_host_groups.all()

Добавление хоста в группу хостов

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="Test ADQM cluster")
service = await cluster.services.get(name__eq="adqmdb")

# Определение группы хостов
action_host_group = await service.action_host_groups.get(name__eq="hosts_1-3")

# Получение добавляемых хостов
added_host = await cluster.hosts.filter(
    name__iin=["dev-adqm-02.ru-central1.internal", "dev-adqm-04.ru-central1.internal"])

# Добавление хостов
host_add = await action_host_group.hosts.add(host=added_host)

Запуск действия для группы хостов

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="Test_ADQM_cluster")
service = await cluster.services.get(name__eq="adqmdb")

# Определение группы хостов
action_host_group = await service.action_host_groups.get(name__eq="hosts_1-3")

# Определение действия
action = await action_host_group.actions.get(display_name__eq="Restart")

task = await action.run()

Импорт

ADCM AIO Client предоставляет метод cluster_import.add(*sources: Cluster | Service) для передачи определенных настроек сервиса в кластер.

# Определение кластера, в который будут импортированы настройки сервиса
cluster = await client.clusters.get(name__eq="Test_ADB_cluster")

# Получение объекта, управляющего импортом в кластере
cluster_import = await cluster.imports

# Определение кластера, содержащего импортируемые настройки сервиса
cluster_for_import = await client.clusters.get(name__eq="Monitoring")

# Получение импортируемых настроек сервиса
imported_service = await monitoring_cluster.services.get(name__eq="grafana")

# Импорт
imports = await cluster_import.add([imported_service])

Также ADCM AIO Client позволяет управлять импортом с помощью следующих методов:

  • cluster_import.remove(*sources: Cluster | Service) — удаляет импортированные настройки одного сервиса из кластера.

  • cluster_import.set() — удаляет импортированные настройки всех сервисов из кластера.

Выполнение действий для объектов

ADCM AIO Client предоставляет методы, которые позволяют выполнять действия для объектов, в том числе:

В качестве примера можно рассмотреть процесс запуска действия Expand.

Получение списка действий

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__eq="ADB_cluster")
service = await cluster.services.get(name__eq="adb")

# Получение списка сервисных действий
actions = await service.actions.all()

Подготовка действия

Поскольку действие Expand выполняет расширение кластера путем назначения новых хостов компоненту, то подготовка действия к запуску включает следующие шаги:

  1. Определение параметров конфигурации объекта.

  2. Назначение новых хостов компоненту.

Также ADCM AIO Client позволяет запускать действия:

Определение параметров конфигурации

ПРИМЕЧАНИЕ
Методы для управления конфигурацией объекта также применимы для действий, содержащих конфигурационные параметры объекта.
# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__ieq="Test_ADB_cluster")
service = await cluster.services.get(name__eq="adb")

# Определение действия
expand_action = await cluster.actions.get(name__eq="Expand")

# Определение объекта действия, содержащего конфигурационные параметры
configuration = await expand_action.config

# Определение параметра и его нового значения
configuration["Reboot timeout, sec"].set(605)

Назначение новых хостов компоненту

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__ieq="Test_ADB_cluster")
service = await cluster.services.get(name__eq="adb")

# Определение действия
expand_action = await cluster.actions.get(name__eq="Expand")

# Получение хостов и компонентов для распределения
components = await service.components.filter(name__iin=["ADB Segment", "PXF"])
hosts = await cluster.hosts.get(name__eq="test-host")

# Определение объекта действия, включающего назначение новых хостов компоненту
mapping = await expand_action.mapping

# Внесение локальных изменений в распределении
await mapping.add(components, hosts)

Запись подробных логов

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__ieq="Test_ADB_cluster")
service = await cluster.services.get(name__eq="adb")

# Определение действия
expand_action = await cluster.actions.get(name__eq="Expand")

expand_action.verbose = True

Установка неблокирующего режима

# Определение требуемого кластера и сервиса
cluster = await client.clusters.get(name__ieq="Test_ADB_cluster")
service = await cluster.services.get(name__eq="adb")

# Определение действия
expand_action = await cluster.actions.get(name__eq="Expand")

expand_action.non_blocking = True

Запуск действия

Без блокировки текущего потока выполнения действия

job = await expand_action.run()

С блокировкой текущего потока выполнения действия

ПРИМЕЧАНИЕ
Вы можете использовать кастомное условие выхода из ожидания завершения задачи.
job = await expand_action.run()
await job.wait(exit_condition=default_exit_condition)

Получение статуса задачи

При выполнении действия ADCM запускает отдельную задачу (job). Чтобы отслеживать выполнение действия, получите информацию о статусе задачи с помощью метода job.get_status().

job_status = await job.get_status()

Работа с коллекциями объектов

ADCM AIO Client предоставляет методы, описанные ниже, для выполнения следующих операций:

  • all() — возвращает список всех объектов;

  • list() — возвращает пагинированный список объектов, удовлетворяющий параметрам запроса;

    Пример использования пагинации
    clusters = await client.clusters.list(query={"limit": 4, "offset": 10})

    где:

    • limit — максимальное количество объектов в списке;

    • offset — смещение, с которого начинается выборка объектов.

  • get() — возвращает один объект, удовлетворяющий указанным условиям;

  • filter() — возвращает список объектов, соответствующих указанным условиям.

Чтобы отфильтровать список объектов, используйте метод filter() с указанием параметров фильтрации и lookup-операторов, описанных ниже.

Lookup-операторы
Lookup-оператор Описание

eq

Оператор равенства

ieq

Оператор равенства (без учета регистра)

ne

Оператор неравенства

ine

Оператор неравенства (без учета регистра)

contains

Оператор поиска строк, содержащих заданную подстроку

icontains

Оператор поиска строк, содержащих заданную подстроку (без учета регистра)

in

Оператор проверки совпадения указанного значения с одним из значений, разделенных запятыми, в формате list

iin

Оператор проверки совпадения указанного значения с одним из значений, разделенных запятыми, в формате list (без учета регистра)

exclude

Оператор для получения значений, которые не соответствуют заданным значениям, разделенным запятыми, в формате list

iexclude

Оператор для получения значений, которые не соответствуют заданным значениям, разделенным запятыми, в формате list (без учета регистра)

Обратите внимание, что разные объекты поддерживают разные параметры фильтрации.

  • Бандл

  • Кластер

  • Сервис

  • Компонент

  • Хостпровайдер

  • Хост

  • Действие

  • Задача

  • Конфиг-группа, группа хостов

  • name

  • display_name

  • version

  • edition

  • name

  • bundle

  • status

  • name

  • display_name

  • status

  • name

  • display_name

  • name

  • bundle

  • name

  • status

  • name

  • display_name

  • status

  • name

  • display_name

  • object

  • action

name

Параметры фильтрации bundle и action могут быть использованы только с lookup-операторами eq, ne, in и exclude.

clusters = await client.clusters.filter(name__iin=['monitoring', 'adb'])
clusters = await client.clusters.filter(name__icontains="test_adb_cluster")

Ошибки

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

Ошибки
Код ошибки Описание

WaitTimeoutError

Время ожидания выполнения превысило пороговое значение

ClientInitError

Не удалось подключиться к ADCM по указанному URL

NotSupportedVersionError

  1. Не удалось определить версию ADCM по указанному URL. Скорее всего, версия ADCM ниже, чем минимальная поддерживаемая версия ADCM.

  2. Версия ADCM не поддерживается.

NoCredentialsError

Не удалось найти учетные данные

AuthenticationError

Не удалось войти в ADCM по указанному URL. Возможная причина — неверные имя и пароль учетной записи

LoginError

Не удалось войти в ADCM по указанному URL

LogoutError

Не удалось выйти из ADCM по указанному URL

RetryRequestError

Не удалось выполнить запрос за указанный интервал времени

ResponseDataConversionError

  1. Неверный тип возвращаемых значений. Поддерживаемые типы: dict и list.

  2. Передаваемые данные имеют недопустимый формат JSON.

BadRequestError

Запрос не может быть обработан из-за ошибки на стороне пользователя

UnauthorizedError

Запрос не был выполнен из-за отсутствия аутентификации пользователя

PermissionDeniedError

У текущего пользователя недостаточно прав для выполнения запроса

NotFoundError

Объект не найден

ConflictError

Запрос не может быть выполнен из-за конфликта с текущим состоянием сервера

ServerError

Серверу не удалось обработать запрос

BadGatewayError

Сервер получил недействительный ответ от вышестоящего сервера при обработке запроса

ServiceUnavailableError

В данный момент сервер не готов обработать запрос из-за временной перегрузки или планового обслуживания

AccessorError

Неизвестная ошибка доступа

MultipleObjectsReturnedError

Найдено более одного объекта

ObjectDoesNotExistError

Не найдены объекты с заданным фильтром

OperationError

  1. Не удалось загрузить бандл по указанному URL.

  2. Возникла HTTP-ошибка.

HostNotInClusterError

Хост не добавлен в кластер или не обновлен

ConfigComparisonError

  1. Предыдущая версия файла спецификации schema.yaml не соответствует текущему файлу.

  2. Не удается обновить конфигурацию после обновления кластера: schema.yaml отличается для локального и удаленного серверов.

ConfigNoParameterError

Параметр с указанным названием отсутствует в дереве конфигурационных настроек

NoMappingInActionError

Выбранное действие не разрешает вносить изменения в маппинг

NoConfigInActionError

Выбранное действие не разрешает вносить изменения в конфигурационные параметры

InvalidFilterError

Неправильное использование метода filter(). Например, недопустимый формат встроенного фильтра или указание пустого списка объектов

Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней