Документация Метки раннеров и таргетинг

Метки раннеров и таргетинг

Раннер может нести произвольные метки — короткие теги вроде
linux, gpu, prod, staging, region-eu. При запуске нагрузочного
теста, фаззинга, хаос-эксперимента или test plan Mockarty маршрутизирует
задачу только на те раннеры, чьи метки удовлетворяют требованию.

Способов указать требование два:

Режим Когда выбирать Что пишете
Простой (чипы) Каждому раннеру нужны все перечисленные метки. Самый частый случай. linux, gpu, prod (по одному чипу, неявный AND)
Расширенный (DSL) Нужен OR, NOT, регекс или скобки. `linux & (gpu

В UI у пикера есть переключатель Простой / Расширенный справа от
поля с чипами. При переходе из Простого в Расширенный выражение
предзаполняется конкатенацией чипов через &. Обратное переключение
доступно, только когда выражение — чистое AND из литеральных атомов.

Задаём метки раннеру

Откройте Админ → Интеграции, нажмите Изменить метки
рядом с раннером и добавьте чипы. Метка — 1–64 символа из набора
a-z, 0-9, ., -, _. Заглавные буквы автоматически приводятся
к нижнему регистру.

Для эфемерных раннеров метки можно передать через переменную окружения
RUNNER_LABELS=linux,gpu,ci при запуске процесса.

Простой режим (чипы)

Добавьте один или несколько чипов. Раннер подходит только тогда, когда
его набор меток является надмножеством вашего списка чипов:

Чипы Подходят
linux любой раннер с меткой linux
linux, gpu только раннеры, у которых есть обе метки

Порядок не важен. Каждый добавленный чип сужает выбор, но никогда не
расширяет.

Расширенный режим (label DSL)

Переключитесь на Расширенный и впишите выражение. Грамматика:

expr     := orExpr
orExpr   := andExpr ('|' andExpr)*
andExpr  := notExpr ('&' notExpr)*
notExpr  := '!' notExpr | atom
atom     := литерал | регекс | '(' expr ')'
литерал  := [a-z0-9._-]{1,64}
регекс   := '/' pattern '/' flags?
flags    := 'i'
  • & — AND (обе стороны должны совпасть)
  • | — OR (достаточно одной стороны)
  • ! — NOT (сторона не должна совпасть)
  • (...) — группировка, переопределяет приоритет
  • /.../ — регулярное выражение по набору меток; совпадение, если
    хотя бы одна метка матчит паттерн. Разрешён только флаг i
    (case-insensitive).

Приоритет (от высшего к низшему): !, &, |. То есть
linux & gpu | tpu парсится как (linux & gpu) | tpu. Когда не
уверены — используйте скобки.

Примеры

linux & gpu                       эквивалент Простого [linux, gpu]
linux & (gpu | tpu)               Linux + любой ускоритель
linux & !staging                  Linux, но не staging-флот
/^perf-.*/i & ci                  любой раннер "perf-…", который ещё и "ci"
(prod | staging) & region-eu      только ЕС, prod или staging
!arm64                            любой не-ARM раннер

Лимиты

Парсер защищается жёсткими ограничениями — некорректное выражение не
может заставить диспетчер делать неограниченную работу:

Лимит Значение
Максимальная длина выражения 1024 байта
Максимальная глубина вложенности 16
Максимум литералов + регексов 64
Максимум регексов 8
Максимальная длина паттерна регекса 256 байт
Разрешённые флаги регекса только i

При превышении лимита badge под полем покажет точный байтовый офсет и
правило, которое нарушено.

Live-валидация

По мере набора Mockarty шлёт запрос на POST /api/v1/runner-labels/validate
и показывает один из вариантов:

  • подходит раннеров онлайн: N — зелёный, выражение корректно и
    N онлайн-раннеров под него подходят. Под пикером отображается
    превью первых 5 имён.
  • подходит раннеров онлайн: 0 — янтарный, парсится, но сейчас
    никто не совпадает. Задача встанет в очередь и подождёт подходящего
    раннера.
  • Некорректное выражение, байт N: <причина> — красный. Исправьте
    синтаксис; диспетчер откажется принимать выражение с ошибкой.

Валидация дебаунсится на 300 мс, чтобы быстрый ввод не спамил сервер.

Где применяются метки

Таргетинг работает одинаково везде, где задача уходит на раннер:

Поверхность Поле в payload
POST /api/v1/perf/run requiredRunnerLabels[] или runnerLabelExpr
POST /api/v1/fuzzing/run requiredRunnerLabels[] или runnerLabelExpr
Test Plan item runnerLabels[] (на каждый item)
Функциональный запуск API tester requiredRunnerLabels[] или runnerLabelExpr
Запуск Test Case / UI-теста наследуется от TCM-конфигурации запуска (см. ниже)

requiredRunnerLabels и runnerLabelExpr в UI взаимоисключающие —
пикер посылает одно из двух в зависимости от режима. Если оба попадут
в диспетчер, они комбинируются через AND (выражение всегда сужает
набор чипов, не расширяет).

Маршрутизация запусков Test Case (и UI-тестов) через конфигурацию

У запуска Test Case нет собственного пикера меток — вместо этого он
наследует runner-селектор от TCM-конфигурации, против которой
запущен. Так селектор остаётся переиспользуемым: «конфигурация EU smoke
всегда гоняется на флоте region-eu» объявляется один раз на
конфигурации, и каждый запуск с ней маршрутизируется одинаково. Каждый
шаг с внешним раннером, который порождает запуск — UI-тест (browser
runner)
, нагрузочный, API-тест, фаззинг — наследует тот же селектор.

Конфигурация объявляет селектор двумя опциональными полями:

Поле Тип Значение
runnerLabels массив строк Чипы простого режима — раннер должен нести все (надмножество, неявный AND).
runnerLabelExpr строка DSL расширенного режима (та же грамматика, что выше). Комбинируется с runnerLabels через AND.

Поля задаются на конфигурации через API конфигураций, например:

# Создать конфигурацию, привязанную к EU GPU-флоту
curl -X POST "$MOCKARTY/api/v1/namespaces/$NS/tcm/configurations" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{
        "name": "EU smoke",
        "isDefault": true,
        "params": { "runnerLabels": ["region-eu", "gpu"] }
      }'

При старте запуска кейса выберите конфигурацию опциональным полем
configurationId:

curl -X POST "$MOCKARTY/api/v1/namespaces/$NS/test-cases/$CASE_ID/run" \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{ "mode": "semi_automatic", "configurationId": "'$CONFIG_ID'" }'
  • Явный configurationId — запуск использует селектор этой
    конфигурации. Неизвестный id (или из другого namespace) отклоняется с
    400 / 404, чтобы опечатка не привела к запуску без селектора.
  • Без configurationId — запуск откатывается к конфигурации
    кейса по умолчанию
    (помеченной default). Если у кейса нет
    default-конфигурации, запуск идёт без селектора (матчинг только по
    namespace + capability, как и раньше).

Если конфигурация не объявляет селектор, запуск идёт без селектора.
Запуск, чей селектор не матчит ни одного онлайн-раннера, встаёт в
очередь и ждёт появления подходящего раннера (UI-тесты дополнительно
требуют раннер с capability ui-test — см. «Запись UI-тестов»).

Простой или Расширенный — что выбрать?

Простой подходит, когда:

  • правило формулируется как «у каждого раннера должны быть эти теги»;
  • набор тегов короткий (1–4);
  • OR / NOT / регекс не нужны.

Расширенный оправдан, когда:

  • у раннеров есть пулы, которые удобно адресовать по шаблону имени
    (/^perf-.*/i);
  • нужно OR («любой раннер с gpu ИЛИ tpu»);
  • нужно NOT («всё, кроме staging»);
  • правила вложенные.

Простой режим быстрее писать и читать с разбегу; Расширенный строго
выразительнее, но требует внимания при чтении. Для CI-раннбука
выражение естественно живёт в версионируемом конфиге; для разовых
запусков обычно хватает Простого.

Хорошие практики

  • Думайте о метках как о Kubernetes node labels — описывайте,
    что раннер из себя представляет, а не что нужно задаче
    (gpu ✓, ml-training-job ✗).
  • Держите словарь меток компактным. Чип-пикер автодополняет из
    существующего словаря; «джунгли тегов» становится тяжело навигировать.
  • Договоритесь о стабильной схеме: region-eu, region-us,
    os-linux, arch-amd64. Точка/дефис хорошо читаются в выражениях.
  • Регекс — крайний случай, когда литеральным набором действительно
    нельзя описать когорту. Это самый медленный путь оценки.
  • Для конкретного железа (например, модель GPU) лучше отдельный
    литерал (gpu-a100), а не регекс (/^gpu-a100.*/).