Создание RPC-модулей
1. Описание
RPC (Remote Procedure Call) — это протокол взаимодействия между клиентом и сервером, позволяющий вызывать процедуры или функции на удалённом сервере так, как если бы они выполнялись локально. Этот подход используется при разработке распределённых и масштабируемых приложений, где отдельные компоненты взаимодействуют между собой, находясь на разных серверах или в разных сетевых средах.
RPC-модуль — компонент, обеспечивающий взаимодействие между сервисом Cloudlink и внешним сервисом. Для этого он использует RPC-вызовы удалённых функций.
Внутри инфраструктуры Cloudlink RPC-модуль подключается к заданной очереди RabbitMQ внутри Kubernetes-кластера. После разработки и и развертывания модуль можно интегрировать с Конструктором Cloudlink и использовать внешний сервис в качестве узла в графе.
2. Предварительные условия
Для использования внешнего сервиса или приложения совместно с Kонструктором Cloudlink нужно:
-
Разработать rpc-модуль для интеграции с Конструктором Cloudlink.
-
Добавить разработанный модуль в качестве шаблона узла в Конструктор Cloudlink.
-
Создать граф для продукта.
3. Разработка RPC-модуля
Развёртывание RPC-модуля может выполняться двумя способами:
-
Внутри Kubernetes-кластера Cloudlink:
RPC-модуль размещается в том же кластере Kubernetes, где работают все необходимые сервисы.
-
Вне Kubernetes-кластера:
RPC-модуль разворачивается за пределами кластера. В этом случае необходимо обеспечить корректное подключение к RabbitMQ, State Service и другим сервисам внутри кластера.
В качестве Service 1,2,3 может выступать любой компонент инфраструктуры Cloudlink.
4. Реализация RPC-модулей
Для реализации RPC-модулей используется специальная библиотека, предназначенная для разработки и управления асинхронными RPC-взаимодействиями, включая инструменты для создание RPC-модулей, работы с задачами, API и управления состоянием.
Основные компоненты:
-
Adapter
-
Базовый класс для адаптеров.
-
Используется для инициализации, выбора и выполнения методов интерфейса.
-
Используется для интеграции с внешними сервисами.
-
-
BaseTaskReceiver
-
Класс для приема и обработки задач.
-
Используется для управления асинхронным циклом и сигналами завершения, а также для валидации входящих сообщений.
-
-
TaskReceiver
-
Расширяет BaseTaskReceiver, интегрируя пользовательские адаптеры.
-
Использует методы адаптера для выполнения задач.
-
-
RetryRequestByStatus
-
Декоратор для повторных попыток HTTP-запросов.
-
Используется для настройки задержек, таймаутов и обработки ошибок.
Пример использованияfrom app.adapter import NovaAdapter from app.settings import APP_NAME, TASK_EXECUTION_TIMEOUT from cld_rpc_utils.utils import TaskReceiver task_receiver = TaskReceiver(NovaAdapter, APP_NAME, TASK_EXECUTION_TIMEOUT) task_receiver.get_messages()
-
4.1. Процесс исполнения задачи с помощью библиотеки NovaAdapter
-
Получение сообщения из RabbitMQ
TaskReceiver прослушивает очередь RabbitMQ. При появлении нового сообщения (задачи) оно извлекается из очереди для дальнейшей обработки.
-
Обработка сообщения
TaskReceiver анализирует содержимое сообщения, чтобы определить тип задачи. На этом этапе разбираются входные данные и определяются необходимые действия.
-
Инициализация адаптера
TaskReceiver создаёт экземпляр адаптера (NovaAdapter) и передаёт ему входные данные и параметры логирования.
-
Выбор метода интерфейса
В NovaAdapter вызывается метод
obtain_interface_method(), который определяет, какой метод интерфейса использовать на основе входных данных. -
Выполнение задачи
Адаптер выполняет выбранный метод асинхронно. Это может включать взаимодействие с внешними сервисами, обработку данных и другие операции.
-
Логирование и обработка ошибок
Во время выполнения задачи адаптер собирает информацию о событиях и обрабатывает возможные ошибки.
-
Возвращение результата
Результат выполнения передаётся обратно в TaskReceiver. В зависимости от конфигурации, он может быть отправлен в очередь RabbitMQ или обработан другим способом.
-
Ожидание следующей задачи
После обработки текущего сообщения TaskReceiver продолжает прослушивание очереди RabbitMQ для получения новых задач.
4.2. Примеры использования библиотеки Nova Adapter
-
Создание адаптера
Адаптер должен наследоваться от базового класса Adapter. Инициализация адаптера включает базовую настройку и подготовку к работе с RPC-модулем.
Пример инициализации адаптера для Nova AdapterpythonCopy code # app/adapter.py from cld_rpc_utils import Adapter from typing import Union from logging import Logger, LoggerAdapter from cld_py_logging.log_extra import ExtraLogger class NovaAdapter(Adapter): def __init__(self, inputs: dict, logger: Union[Logger, LoggerAdapter, ExtraLogger]): super().__init__(inputs, logger) # Здесь можно инициализировать внутренние переменные и состояние # Инициализация и настройка для работы с Nova async def create_nova(self): # Логика создания Nova # Другие специфические методы -
Инициализация клиента
Клиент представляет собой компонент, который управляет взаимодействием с внешними сервисами или API. В этом контексте клиент используется для отправки запросов и получения данных от сервиса AWX.
Пример кода для AWX Client:# rpc-awx/aioawxclient/client.py import logging from aiohttp import ClientSession, TCPConnector from cld_rpc_utils import RetryRequestByStatus from aioawxclient import api from .exceptions import AWXException from .settings import * from .utils import response_handler class Client: _REQUIRED_HEADERS = {"Content-type": "application/json"} def __init__(self, url: str, port: int, usern ame: str, password: str, organization_name, api_version="v2", logger=logging): self.logger = logger self.api_version = api_version self.api_root = f"{url}:{port}" self.username = username self.password = password self.organization_name = organization_name # Другие начальные настройки async def __aenter__(self): # Инициализация асинхронной сессии и аутентификации # ... # Другие методы для взаимодействия с AWX APIКлиент можно интегрировать с адаптером через метод _init_client. Этот метод:
-
Устанавливает соединение с внешним сервисом (AWX).
-
Инициализирует все необходимые компоненты для работы клиента.
Пример интеграции:class MyCustomAdapter(Adapter): def _init_client(self): self.client = AWXClient( RPC_AWX_SETTINGS.awx_api_endpoint, RPC_AWX_SETTINGS.awx_api_port, RPC_AWX_SETTINGS.awx_username, RPC_AWX_SETTINGS.awx_password, RPC_AWX_SETTINGS.awx_organization, logger=self.logger, ) return self.client # Дополнительные настройки клиента, если необходимоВ этом примере MyCustomAdapter инициализирует клиент AWX в методе
_init_client. Такое разделение логики адаптера и клиента повышает читаемость и удобство поддержки кода.
-
-
Реализация специфических функций
Реализуйте методы для выполнения конкретных действий, например, создание, обновление или удаление кластера Nova.
Пример кода:async def create_nova(self): # Логика для создания Nova async def update_nova(self): # Логика для обновления Nova # ... другие методы ... -
Интеграция с TaskReceiver
Используйте TaskReceiver для приема и обработки задач. Инициализируйте его с вашим адаптером ( NovaAdapter ) и настройками приложения.
Пример кода ( rpc_nova.py ):# rpc_nova.py from app.adapter import NovaAdapter from cld_rpc_utils.utils import TaskReceiver from app.settings import APP_NAME, TASK_EXECUTION_TI MEOUT task_receiver = TaskReceiver(NovaAdapter, APP_NAME, TASK_EXECUTION_TIMEOUT) task_receiver.get_messages() -
Обработка задач
В TaskReceiver реализован метод get_messages() , который начинает прослушивание и обработку входящих сообщений.
-
Обработка и логирование
Добавьте подробное логирование в методах вашего адаптера для отслеживания хода выполнения задач и упрощения отладки.
Пример кода:async def create_nova(self): self.logger.info("Начало процесса создания Nova...") # Логика создания self.logger.info("Завершение процесса создания Nova...") -
Взаимодействие с внешними сервисами
Внедрите логику для взаимодействия с внешними сервисами, такими как базы данных, веб-сервисы или облачные провайдеры, внутри методов вашего адаптера.
Пример кода:async def create_nova(self): # Вызов внешнего сервиса или API external_service_result = await some_external_service_call() # Обработка результатов
5. Создание шаблона узла для RPC-модуля
RPC-модуль подключается к Конструктору Cloudlink через настроенный узел в Control Panel → раздел Шаблоны узлов. Этот узел обеспечивает связь с необходимой очередью RabbitMQ для обработки запросов.
| Подробнее о настройках Шаблонов узлов в Руководстве администратора Cloudlink. |
Модуль можно развернуть как внутри Kubernetes, так и в другой среде. При этом важно обеспечить доступ к:
-
очереди RabbitMQ
-
State Service
-
остальным сервисам, с которыми модуль должен взаимодействовать.
-
Перейдите в раздел Control Panel Конструктор → Шаблоны узлов и нажмите +.
-
Во вкладке Основное укажите следующие параметры:
-
Наименование
-
Код шаблона
-
Описание
-
Название очереди для старта задачи
-
Название очереди для отката
Очередь для отката может быть пустой, если данный функционал не используется. -
Время ожидания
-
Тип
Названия очереди для старта и отката задачи должны быть согласованы между разработчиком RPC-модуля и разработчиком продукта или графа. Для предварительного создания очереди, необходимо подключиться к RabbitMQ по ссылке https://rabbitmq.FQDN_Cloudlink/ и выполнить следующие действия:
-
Перейдите на вкладку Queues и найти пункт Add a new queue.
-
В качестве параметра Virtual host выберите корневой каталог
/. -
Выберите значение параметра Type из следующих вариантов:
-
Default for virtual host
-
Classic
-
Quorum
-
Stream
-
-
Введите название в поле Name. Оно должно совпадать с названием очереди в шаблоне узла.
-
Укажите длительность сохранения очереди в параметре Durability.
-
При необходимости указать дополнительные параметры в поле Arguments.
-
-
-
Во вкладке Параметры укажите входные и выходные параметры, которые нужны для работы вашего RPC-модуля.
Указанные параметры передаются в виде сообщения при обмене данными между RPC-модулем и приложением.
Активируйте при необходимости опции, разрешающие переопределение входных и выходных параметров, уровня логирования и приоритет.
-
Нажмите Добавить.
Созданный шаблон узла вы можете использовать в конструкторе графа.
6. Использование RPC-модуля в качестве узла в графе
-
Перейдите в раздел Конструктор → Графы.
-
Нажмите кнопку +.
-
В вкладке Общая информация введите следующие параметры:
-
Код графа — укажите уникальный символьный идентификатор продукта. Он может содержать только прописные латинские символы, цифры, нижнее подчеркивание,тире двоеточие и точку.
-
Наименование — дайте уникальное название создаваемому графу.
Код графа,наименование и автор необходимы для идентификации и управления графом в системе. -
Тип — укажите один из двух типов acting или creating.
-
Описание(опционально) — опишите отличительные особенности продукта.
-
Автор — укажите автора продукта.
-
При необходимости активируйте опции, которые включаются в случае некорректного проигрывания графа:
-
Переводить заказ в статус "Ошибка".
-
Блокировать заказ при ошибке.
-
-
-
Добавьте узлы графа:
-
Перейдите во вкладку Узлы и нажмите кнопку +.
-
На вкладке Основное укажите следующие параметры:
-
Название
-
Описание
-
Выберите Шаблон узла с RPC-модуля.
-
Перейдите на вкладку Параметры и введите данные:
-
В блок кода Static data.
-
В блоках кода Input и Output будут указаны входные и выходные переменные, которые были ранее указаны при создании Шаблона узла. При необходимости их можно отредактировать.
Данные, указанные в Static data можно использовать во всем графе. *
-
-
На вкладке Дополнительное заполните параметры, касающиеся запуска узла.
-
-
-
Нажмите Добавить, чтобы завершить создание узла.
Узел будет добавлен в граф.
-
Перейдите на вкладку графа Параметры заказа и задайте параметры:
-
В блоке Форма заказа опишите структуру в JSON-формате для определения структуры данных и параметров заказа:
Пример 1. Описание параметров в структуре JSONЗдесь создаётся новый объект с наименованием New app. Для него в форме заказа должны быть заданы следующие поля: vars, credentials, net_segment.
-
Поля vars и credentials имеют строковый тип.
-
Значения задаются по шаблону (
pattern):"^[a-zA-Z0-9-]*$(латинские буквы в верхнем и нижнем регистре, цифры от 0 до 9, символы-и). -
Ограничения по длине:
-
минимальное количество символов — 3 (
"minLength": 3), -
максимальное количество символов — 64 (
"maxLength": 64).
-
-
-
Параметр net_segment имеет тип object и позволяет выбирать значения из списка.
Для создания пользовательского интерфейса формы заказа используется UI-схема.
UI схемы позволяют визуально организовать поля ввода, кнопки и другие элементы интерфейса, обеспечивая интуитивно понятное и удобное взаимодействие для пользователя.
Пример 2. Переопределение виджетов и полей в интерфейсе UI-схемыДля полей vars и credentials свойство
ui:widgetзадаёт тип отображения элемента формы. В данном случае используется"ProductLabelWidget", который отображает поле как текстовую метку с названием продукта.Для поля net_segment свойство
ui:fieldопределяет интерфейс для работы со связанными объектами. Значение"DirectoryUiListField"в пользовательском интерфейсе будет выглядеть как поле со списком значений с доступными шаблонами на платформе. -
-
Перейдите на вкладку Детализация цены и выберите продукт для расчета стоимости и получите детализацию заказа.
-
-
Во вкладке Модификаторы выберите тип среды для исполнения графа:
-
dev
-
prod
-
test
-
-
Нажмите Сохранить, чтобы завершить создание графа.
