Однажды мне понадобилось проверить изменение одного параметра виртуальной машины. В коде это несколько строк, в лаборатории - свободный кластер, доступное хранилище, подходящий шаблон и надежда, что никто параллельно не запустит резервное копирование всего стенда. В такие моменты особенно хорошо понимаешь: инфраструктурная разработка умеет превращать маленькую задачу в огромную проблему на свою голову большое организационное мероприятие.
Я столкнулся с этим, когда занимался проектами, которые собирают сведения об инфраструктуре и управляют ею через API. Сначала хотел сделать небольшой инструмент для собственных тестов, чтобы реже зависеть от лабораторного Proxmox. В результате появились четыре проекта: симуляторы API Proxmox VE, OpenStack, VMware и oVirt.
Начиналось все с идеи возвращать заранее подготовленные ответы. Закончилось постоянным состоянием в PostgreSQL, фоновыми задачами, блокировками, импортом контрактов и довольно обстоятельным знакомством с тем, как инфраструктурные платформы общаются со своими клиентами.
Получился тот самый случай, когда «сейчас себе быстренько накожу вспомогательную утилитку» незаметно становится отдельным направлением разработки.
Почему разработка инфраструктурных сервисов упирается в стенд
Разработчика обычного приложения сегодня трудно удивить локальной базой данных или очередью сообщений в докере. Для многих проверок достаточно Docker Compose, а поведение приложения в Kubernetes можно отладить в Kind или Minikube (Да чего там, я даже писал себе веб-морду для быстрого поднятия локальных кубов для удобства нашей разработки - если нужно, пишите в комментариях, поделюсь репозиторием). Настоящее окружение все равно понадобится, но доступ к нему не определяет, сможешь ли ты сегодня написать очередную функцию.
С программами для управления виртуализацией ситуация сложнее. Если пишешь коннектор инвентаризации, провайдер Terraform или портал самообслуживания, приходится регулярно обращаться к платформе, которую эта программа обслуживает. Для простого чтения иногда хватает сохраненных ответов, но проверка создания, изменения и удаления ресурсов быстро приводит к необходимости иметь полноценный стенд.
У меня таких потребителей API было сразу несколько. Один проект собирал граф инфраструктуры: подключался к источникам данных, находил виртуальные машины, вычислительные узлы, сети, хранилища и связи между ними. Другой представлял собой портал динамической инфраструктуры, через который разработчики могли заказывать виртуальные машины, Kubernetes, PostgreSQL, Redis и другие сервисы.
В первом случае ошибка могла испортить модель зависимостей. Например, машина уже переехала на другой узел, а система продолжает показывать старую связь. Во втором пользователь мог получить успешно выполненную заявку, за которой почему-то не появилось никакого ресурса. Поэтому ограничиться проверкой «сервер вернул HTTP 200» было невозможно: требовалось проходить полноценные сценарии.
Однако перед каждой проверкой приходилось выяснять, кто сейчас пользуется лабораторией, осталось ли место, не менялась ли версия платформы и не выполняется ли операция, которая повлияет на результат. Причем не всегда было понятно, где искать причину сбоя: в собственном коде или в окружении.
Однажды я почти два часа разбирался, почему интеграционный тест стал выполняться в несколько раз медленнее. Проверил приложение, базу данных и сеть, а причиной оказалось резервное копирование чужих виртуальных машин на том же стенде. С точки зрения эксплуатации все происходило совершенно законно; с точки зрения разработки у меня появился незапланированный практикум по дисковой подсистеме.
После нескольких подобных историй захотелось вынести повседневную работу в отдельную лабораторию. Требование было простым: клиент должен обращаться к знакомому API, выполнять последовательность операций и получать согласованное состояние ресурсов. Реальные виртуальные машины для этого запускать необязательно, но последствия запросов должны сохраняться.
Красивый JSON выдержал ровно до второго запроса
Первый вариант выглядел очевидным: описать маршруты, подготовить ответы и поднять сервер на FastAPI. Такой подход обычно называют mock API - подставным интерфейсом, который возвращает данные для тестирования клиента. Для проверки разбора ответа или отображения таблицы ресурсов это вполне подходящий инструмент, поэтому начинать с него было разумно.
Проблема проявилась, когда вместо браузера подключился портал. Он отправлял запрос на создание виртуальной машины, получал идентификатор задачи, проверял ее завершение и запрашивал обновленный список ресурсов. Ответ на первый запрос выглядел убедительно, но созданной машины в списке не было: сервер продолжал отдавать ту же заготовку, что и до операции.
Клиенту недостаточно, чтобы каждый ответ по отдельности напоминал настоящий. Ему нужна связная история: если создание завершилось успешно, ресурс доступен для чтения; если параметры изменены, новое значение видно в конфигурации; если машина удалена, следующий запрос не должен возвращать ее как ни в чем не бывало. Именно на таких переходах проверяется значительная часть инфраструктурной автоматизации.
Я начал добавлять состояние в Python-словари. Сначала появились виртуальные машины, затем сети, диски, пользователи и задачи, а вместе с ними - вопросы о конкурентном доступе, связях между объектами и восстановлении после перезапуска. Довольно быстро выяснилось, что небольшой сервер с заготовками превращается в систему управления состоянием, только пока без подходящего хранилища и четких правил.
Здесь пришлось пересмотреть устройство проекта. В центре появилась модель инфраструктуры, а обработчики API стали вызывать операции над ней. Создание добавляет объект и связанные записи, изменение обновляет существующий ресурс, удаление учитывает зависимости, длительная операция получает собственную задачу. Ответ клиенту теперь формируется из результата работы этой модели.
Разница хорошо заметна на обычной проверке жизненного цикла. Вместо отдельных тестов «маршрут создания вернул строку» и «список машин содержит правильные поля» можно выполнить целый сценарий: создать машину, дождаться результата, изменить память, перечитать конфигурацию и удалить ресурс. Если на любом шаге состояние расходится с ожиданиями, тест показывает проблему в последовательности действий, которую действительно использует приложение.
При этом обычные заглушки никуда не исчезают и продолжают приносить пользу. Просто для моей задачи их уровня детализации оказалось недостаточно: нужно было проверять поведение клиента во времени, включая последствия его предыдущих действий.
Четыре платформы - четыре набора особенностей
После Proxmox я занялся другими системами, потому что собственным проектам требовалось работать с несколькими источниками. Повторно использовать удалось прежде всего архитектурный подход: хранение состояния, исполнение операций, учет задач и разделение ответственности. Поддержка каждой платформы при этом потребовала отдельной работы с ее интерфейсами и поведением.
Это существенная оговорка: одинаковое название операции еще не означает одинаковый контракт. Создать виртуальную машину в разных системах - не просто отправить один и тот же объект по другому адресу. Отличаются способы выбора образа, представление сетей и дисков, авторизация, формат ошибок и порядок наблюдаемых изменений.
| Платформа | На что приходится обращать внимание при симуляции |
|---|---|
| Proxmox VE | Иерархия ресурсов относительно узлов, формат ответов API, идентификаторы фоновых задач UPID и их состояния. |
| OpenStack | Взаимодействие нескольких сервисов: идентификация и каталог сервисов, вычисления, сети, образы и тома. |
| VMware | Различия между семействами API, работа с сессиями и объектной моделью, особенности REST и SOAP. |
| oVirt | Модель ресурсов Engine API, связанные объекты и представление операций в клиентском интерфейсе. |
Например, в OpenStack недостаточно правдоподобно ответить на запрос списка серверов. Клиент может сначала пройти авторизацию, получить каталог сервисов, выбрать адрес нужного API и только после этого обратиться к вычислительным ресурсам. Если симулятор игнорирует этот путь, ручной запрос через curl будет работать, а библиотека, ради которой все затевалось, остановится еще до получения списка машин.
Причем отдельные ресурсы должны оставаться согласованными между собой. Сервер ссылается на образ, сетевой порт принадлежит определенной сети, том имеет собственное состояние. Если каждый сервис возвращает независимо придуманные данные, клиент начинает находить объекты, связи между которыми существуют исключительно в воображении автора тестового стенда.
У VMware отдельного внимания потребовали REST и SOAP. Здесь одной автоматической регистрацией HTTP-маршрутов задача не решается: нужно учитывать способы представления объектов, вызова операций и обработки результатов. Общие внутренние механизмы помогают выполнять действия, но внешний слой обязан сохранять особенности интерфейса, которым пользуется конкретный клиент.
В результате получилось четыре репозитория, объединенных одной инженерной идеей. Общий подход облегчает разработку, однако не отменяет платформенную специфику. Если слишком рано объявить все системы одинаковыми, различия потом вернутся в виде ошибок совместимости - обычно в тот момент, когда уже очень хочется выпускать релиз.
Что можно получить из спецификации, а что придется написать
Вручную описывать сотни маршрутов неудобно, особенно когда рядом уже существует машиночитаемое описание API. В проектах я использовал контрактный подход: импортировал доступные описания интерфейсов, приводил их к внутреннему представлению и на этой основе регистрировал маршруты. Так меньше однотипного кода и проще отслеживать изменения между версиями.
При этом исходные материалы у платформ отличаются. Было бы неверно представлять дело так, будто каждый производитель выдает одинаково полный OpenAPI-файл, который остается только загрузить в генератор. Например, Proxmox описывает свой API с использованием JSON Schema, поэтому для общей обработки такие данные требуется преобразовать.
OpenAPI полезен как формат контракта HTTP API: он позволяет описывать операции, параметры и структуры данных. Но ни сам формат, ни генератор обработчиков не объяснят за разработчика, что должно произойти с дисками при клонировании машины или как вести себя при одновременном изменении одного ресурса. Синтаксис запроса и смысл операции приходится рассматривать отдельно.
Поэтому в архитектуре есть две связанные части. Первая отвечает за импорт, нормализацию и внешний интерфейс; вторая - за выполнение операций над состоянием инфраструктуры. Если в новой версии API появилось поле, обновление описания поможет принять и проверить его, но корректное влияние этого поля на поведение еще нужно реализовать.
Упрощенный пример регистрации маршрутов показывает только первую часть этой работы. Здесь create_handler создает обработчик, который связывает описание операции с соответствующей реализацией; сама логика управления ресурсами в этом цикле не возникает.
for endpoint in contract.endpoints:
app.add_api_route(
path=endpoint.path,
endpoint=create_handler(endpoint),
methods=endpoint.methods,
)
Самая неприятная ловушка такого подхода - принять автоматическую регистрацию маршрута за готовую функциональность. Обработчик может существовать, принимать запрос и возвращать подходящий тип данных, но не выполнять нужного сценария. Внешне API выглядит внушительно, а первая последовательность из нескольких операций показывает, что за фасадом пока идет ремонт.
Поэтому число маршрутов само по себе мало говорит о совместимости. Для разработки полезнее знать, какие цепочки действий проверены конкретным клиентом: авторизация, получение ресурсов, создание, ожидание задачи, изменение и удаление. Большая цифра в отчете о покрытии приятна, но портал ею виртуальную машину не создаст.
Разделение контракта и поведения особенно полезно при поддержке нескольких версий. Можно сравнить описания, увидеть измененные параметры и запустить клиент против нужного варианта интерфейса. Однако загрузка новой спецификации означает начало проверки: еще предстоит убедиться, что операции выполняются с правильными последствиями.
Зачем симулятору PostgreSQL
Хранение в памяти удобно, пока стенд живет в одном процессе и его не жалко потерять. У меня довольно быстро появились другие требования: сохранять подготовленную инфраструктуру, переживать обновление приложения и давать нескольким рабочим процессам согласованное представление о ресурсах. PostgreSQL закрыла эти задачи без необходимости изобретать собственное хранилище поверх словарей.
В базе находятся ресурсы, связи между ними, пользователи и задачи. Для доступа используется асинхронный стек на Python с asyncpg, а FastAPI принимает запросы и передает их сервисному слою. Такая организация позволяет отдельно разбирать ошибки интерфейса, ошибки исполнения операции и нарушения целостности данных.
Допустим, клиент создает машину с уже занятым идентификатором. Если проверять уникальность только в Python, два параллельных запроса могут одновременно увидеть свободное значение. Ограничение в базе дает окончательную защиту от такого конфликта, а сервисный слой переводит результат в ошибку, которую ожидает клиент соответствующей платформы.
Другой пример - одновременное изменение конфигурации. Один процесс прочитал параметры машины и собирается обновить память, а второй за это время уже изменил тот же объект. Если первый сохранит целиком устаревшее состояние, часть изменений второго процесса может потеряться.
Для таких ситуаций пригодились версии записей и оптимистические блокировки. Их смысл в том, чтобы при сохранении проверить: ресурс все еще находится в той версии, которую мы прочитали перед изменением. Если другой процесс успел его обновить, операция должна обработать конфликт, а не молча затереть чужой результат.
Постоянное состояние полезно и для отладки. Можно подготовить несколько узлов, сети, шаблоны и набор машин, затем возвращаться к этому окружению при работе над коннектором. После перезапуска приложения не приходится заново собирать весь виртуальный дата-центр только потому, что в обработчике исправлена одна строка.
Но для автоматических тестов сохранность нужно сочетать с явным восстановлением исходных данных. База, переживающая перезапуск, столь же успешно сохраняет мусор предыдущего прогона. Поэтому «данные не пропадают» и «каждый тест начинается с известного состояния» - две отдельные задачи.
Получается вполне практичный компромисс. Вместо одного легкого процесса нужно запускать еще и PostgreSQL, следить за схемой данных и миграциями. Взамен лаборатория перестает исчезать после каждого перезапуска, а целостность состояния можно обеспечивать средствами базы, которые для этого и предназначены.
Самая интересная работа начинается после HTTP-ответа
Проверить прием запроса относительно просто. Гораздо сложнее воспроизвести длительную операцию, за которой клиент наблюдает через API: создание, клонирование или другое действие, возвращающее идентификатор задачи. Здесь важен весь жизненный цикл - прием, выполнение, промежуточное состояние, успешное завершение либо ошибка.
Если всегда завершать такие операции мгновенно, значительная часть клиентской логики останется непроверенной. Приложение может неправильно опрашивать состояние, забывать об ограничении времени ожидания или считать любую остановившуюся задачу успешной. На удобном тестовом сервере все будет зеленым, а на настоящем стенде выяснится, что программа умеет ждать только результат, который уже готов.
Простой asyncio.sleep() внутри обработчика добавляет задержку, но сам по себе не решает проблему надежного исполнения. Нужно понимать, что произойдет при перезапуске процесса, где хранится состояние операции и кто завершит работу после того, как HTTP-запрос уже закончился. Иначе симулятор будет воспроизводить длительность, но терять саму задачу.
В проектах задачи хранятся в PostgreSQL, а выполняются фоновыми рабочими процессами. HTTP-обработчик регистрирует операцию и возвращает клиенту идентификатор в формате нужной платформы. После этого выполнение не зависит от продолжительности HTTP-запроса и может пережить перезапуск обслуживающего его процесса.
Для распределения задач используется FOR UPDATE SKIP LOCKED. Он позволяет выбирать доступные записи, пропуская те, которые уже заблокированы другой транзакцией; документация PostgreSQL прямо отмечает применимость такого механизма для таблиц, используемых как очередь несколькими потребителями.
Однако здесь легко переоценить возможности одного SQL-выражения. Блокировка строки действует в рамках транзакции, а право исполнять долгую задачу после ее завершения нужно закреплять отдельно. Для этого применяется аренда: рабочий процесс получает задачу на ограниченное время.
Захват должен одновременно выбрать запись и обновить сведения о владельце и сроке аренды. Ниже - иллюстрация принципа, а не точная схема таблиц конкретного репозитория.
WITH candidate AS (
SELECT id
FROM task_queue
WHERE status = 'queued'
OR (
status = 'running'
AND lease_until < NOW()
)
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED
)
UPDATE task_queue AS task
SET status = 'running',
worker_id = $1,
lease_until = NOW() + INTERVAL '30 seconds'
FROM candidate
WHERE task.id = candidate.id
RETURNING task.*;
Если исполнитель аварийно завершился, по истечении аренды задачу может подобрать другой процесс. Для длинной операции аренду нужно продлевать, а при фиксации результата проверять актуальность владения: старый исполнитель теоретически может ожить уже после передачи работы новому. Очередь на PostgreSQL избавляет от части инфраструктуры, но не освобождает от правил конкурентного исполнения.
Есть и еще одна тонкость: после сбоя операция не обязательно продолжится ровно с той инструкции, на которой остановилась. В зависимости от реализации она будет повторена, восстановлена по сохраненному этапу либо завершена ошибкой. Это поведение необходимо определить явно, иначе обещание «задачи переживают перезапуск» окажется слишком оптимистичным.
На практике именно такие детали превращают очередь из списка записей в пригодный для тестирования механизм. Добавить фонового исполнителя несложно; сделать так, чтобы его падение не оставляло ресурс в бессмысленном состоянии, уже заметно интереснее. Здесь тестовый проект начинает задавать вполне взрослые вопросы, хотя настоящую виртуальную машину он по-прежнему не запускает.
Повторный запрос не должен случайно удваивать инфраструктуру
Отдельный сценарий возникает, когда сервер принял запрос, но ответ потерялся по дороге. Клиент видит сетевую ошибку и повторяет создание, хотя первая операция уже могла попасть в очередь. Если считать каждое обращение новой независимой командой, результат легко расходится с намерением пользователя.
Для контролируемых сценариев в проектах предусмотрены ключи идемпотентности - идентификаторы, позволяющие связать повторное обращение с ранее принятой операцией. Регистрацию такого ключа, постановку задачи и связанные изменения состояния нужно согласовывать транзакционно. Иначе можно получить задачу без записи о повторе или запись о принятом запросе без самой работы.
При этом идемпотентность симулятора нельзя выдавать за универсальное свойство оригинального API. Если конкретная платформа не принимает такой ключ в выбранной операции, обычный клиент не начнет его передавать ради нашего удобства. Совместимое поведение должно учитывать реальные правила: где-то повтор обнаруживается по идентификатору ресурса, где-то возвращается конфликт, а где-то клиенту требуется дополнительная проверка состояния.
Для портала это особенно полезный тест. После потери ответа он должен разобраться с судьбой заявки, а не бесконечно повторять создание в надежде, что одна из попыток обязательно понравится серверу. Симулятор дает возможность отлаживать такую логику в управляемом окружении, где последствия каждого обращения можно проследить.
Причем повторное выполнение бывает нужно проверять на разных этапах. Запрос мог не дойти до сервера, задача могла создаться без доставки ответа, а сама операция могла успеть завершиться до повторного обращения. Для пользователя все три ситуации выглядят примерно одинаково - «что-то зависло», но действия клиента должны учитывать, что на стороне платформы произошло совершенно разное.
Как изменилась работа над коннекторами и порталом
Самая ощутимая польза появилась в ежедневной разработке. Для графа инфраструктуры я могу подготовить известный набор объектов, выполнить обход и проверить не только количество найденных машин, но и связи: к какому узлу относится ресурс, какая сеть используется, какое хранилище связано с диском. Затем изменить исходное состояние и посмотреть, корректно ли обновляется граф.
Важны здесь и исчезновения. Если машина удалена из источника, система инвентаризации должна убрать или соответствующим образом пометить ее у себя. Сохраненный ответ со списком ресурсов помогает проверить первоначальный импорт, а изменяемая модель позволяет пройти полный цикл синхронизации и обнаружить «призраков», которые иначе годами живут в отчетах.
Для портала самообслуживания набор проверок другой. Нужно пройти путь от выбора шаблона до получения результата, убедиться в правильной обработке ошибки задачи, проверить конфликт идентификатора и попытку изменить уже удаленный объект. Особенно интересно смотреть на интерфейс пользователя: иногда сервер давно сообщил о проблеме, а страница продолжает бодро показывать «Выполняется».
Такие сценарии удобно начинать с подготовленного профиля инфраструктуры. Один профиль нужен для обычной работы, другой - для проверки зависимостей, третий - для воспроизведения конкретной ошибки. Вместо ручной подготовки одних и тех же объектов можно один раз описать исходное окружение и возвращаться к нему при необходимости.
При этом одинаковые исходные данные еще не гарантируют одинаковый результат. Если в тесте остаются неконтролируемые задержки, случайность или общий ресурс, который меняют соседние проверки, нестабильность никуда не денется. Симулятор делает окружение управляемым, но дисциплину написания тестов за разработчика не обеспечивает.
В системе непрерывной интеграции это дает возможность создавать отдельное окружение для прогона. Вместо доступа к общей лаборатории тест получает собственные данные, выполняет сценарии и после завершения освобождает окружение. Падает проверка - разбираемся с конкретным набором входных данных, а не выясняем, кто в соседней команде только что удалил наш шаблон.
Для проектов вокруг Kubernetes такой стенд тоже полезен. Оператор, который заказывает внешние виртуальные машины, должен повторно сверять желаемое состояние с фактическим, переживать незавершенные операции и правильно реагировать на удаление ресурса. Проверять эту логику удобнее там, где можно воспроизвести нужную последовательность событий, а затем подтвердить ее на настоящей платформе.
Изменился и сам порядок работы. Раньше очередная функция начиналась с поиска подходящего стенда, теперь - с подготовки сценария и проверки клиентской логики. К настоящей системе я прихожу уже с более конкретными вопросами: совпадают ли ошибки, правильно ли обработаны переходные состояния, нет ли особенностей, которые не отражены в модели.
Почему я все равно оставил настоящий стенд
Самая опасная ошибка при работе с симулятором - начать считать его поведение доказательством правильности интеграции. Если и клиент, и тестовая модель написаны на основании одного неверного предположения, они прекрасно договорятся между собой. Настоящая платформа в этом соглашении не участвовала и вполне может иметь другое мнение.
Поэтому проверки на исходной системе остаются обязательными. На ней нужно подтверждать форматы ответов, авторизацию, переходы состояний и характер ошибок в используемых сценариях. Особенно внимательно стоит относиться к новым версиям: совпавшая структура данных еще не гарантирует прежнюю последовательность событий.
Есть задачи, для которых API-симулятор вообще не подходит. По нему нельзя измерить скорость дисков, проверить реальную миграцию памяти виртуальной машины, оценить поведение сети при отказе оборудования или подтвердить производительность хранилища. Успешная задача в модели говорит о работе сценария управления, а не о том, как физическая инфраструктура выдержит нагрузку.
Для себя я разделяю проверки по назначению. Основную логику клиента и повторяемые сценарии отлаживаю локально, совместимость подтверждаю на настоящей платформе, а производительность и отказоустойчивость исследую на подходящем стенде. Так лабораторный кластер остается важной частью процесса, но перестает быть обязательным условием для каждого изменения кода.
У подхода есть и собственная стоимость. Четыре проекта требуют сопровождения: нужно обновлять описания API, развивать поведение, разбирать расхождения и следить за тем, чтобы документация не обещала больше реализованного. Симулятор экономит время потребителям, только пока его собственной достоверности уделяется достаточно внимания.
Более того, здесь легко увлечься и начать воспроизводить детали, которые никому не нужны. Если конкретный потребитель только собирает инвентаризацию, ему вряд ли требуется глубокая модель всех вариантов клонирования. Поэтому развитие имеет смысл привязывать к реальным сценариям, иначе вспомогательная лаборатория начнет потреблять больше ресурсов, чем проекты, ради которых появилась.
Что потребуется для следующей платформы
Расширять список хочется, но теперь я осторожнее отношусь к формулировке «просто добавим еще один API». Хорошее машиночитаемое описание действительно сокращает ручную работу, однако не заменяет доступ к системе и понимание ее поведения. Отсутствие OpenAPI тоже не делает задачу невозможной: могут помочь другие формальные схемы, официальные библиотеки и документация, просто подготовка потребует больше усилий.
Начинать разумнее с конкретного потребителя. Какие операции выполняет его библиотека, как проходит авторизация, какие связанные ресурсы читаются и как клиент дожидается завершения задачи? Ответы позволяют выделить первый полезный сценарий, а затем расширять покрытие, не пытаясь с первого дня воспроизвести весь продукт.
Например, для коннектора инвентаризации первым результатом может стать корректная авторизация и согласованный набор узлов, машин, сетей и хранилищ. Для портала понадобятся уже операции изменения состояния и механизм задач. Для провайдера Terraform особенно важны повторное чтение, обнаружение внешних изменений и правильная обработка ситуации, когда ресурс исчез без участия самого провайдера.
Следом нужны проверенные примеры взаимодействия с настоящей платформой: успешные операции, ошибки, промежуточные состояния и результат повторного запроса. Без этого легко построить аккуратный интерфейс, который совпадает с документацией по форме, но расходится с поведением, на которое уже полагаются клиенты.
Именно поэтому качественный контракт API для меня перестал быть просто способом получить красивую страницу документации. Он помогает строить клиентские библиотеки, сравнивать версии и автоматизировать проверки. Но максимальную пользу дает вместе с описанными сценариями и возможностью подтвердить их на исходной системе.
Хотелось бы, чтобы производители инфраструктурных платформ относились к таким материалам как к полноценной части продукта. Чем легче стороннему разработчику понять и проверить интерфейс, тем проще вокруг системы появляются интеграции, инструменты автоматизации и те самые порталы, которые потом показывают на презентациях как развитую экосистему.
Где посмотреть проекты
Исходный код всех четырех симуляторов доступен на GitHub. Проекты выросли из моих задач, поэтому при выборе стенда для своей интеграции стоит начать с нужной версии API и проверки конкретного клиентского сценария.
- Proxmox API Simulator:
https://github.com/sergeyantropoff/proxmox-api-simulator
- OpenStack API Simulator:
https://github.com/sergeyantropoff/openstack-api-simulator
- VMware API Simulator:
https://github.com/sergeyantropoff/vmware-api-simulator
- oVirt API Simulator:
https://github.com/sergeyantropoff/ovirt-api-simulator
Особенно полезны сообщения о воспроизводимых расхождениях: какая версия платформы использовалась, что отправил клиент, какой ответ ожидался и что произошло в симуляторе. Такой отчет помогает улучшить совместимость гораздо быстрее, чем общее «у меня не работает», хотя последняя формулировка, конечно, давно стала международным протоколом технической поддержки.
Если знаете другие платформы с доступными описаниями API и готовы рассказать о сценариях, для которых нужен подобный стенд, напишите в комментариях. Идеи, исправления и звезды тоже приветствуются: приятно понимать, что инструмент помогает кому-то еще, кроме автора и его тестового портала.
Начиналась эта история с желания спокойно проверить несколько строк кода, не дожидаясь свободного гипервизора. Теперь для большей части такой работы я запускаю собственную лабораторию, а к настоящему стенду прихожу с уже отлаженным сценарием и конкретными вопросами. По-моему, это вполне достойный результат проекта, который изначально собирался сделать за несколько вечеров.