Примеры процедур
Статья содержит готовые примеры процедур для задач администрирования кластера. Каждый пример включает:
-
Постановку задачи.
-
Подробное объяснение структуры.
-
Параметры запуска.
-
Рекомендации по использованию.
Используйте эти примеры как шаблоны для создания собственных процедур.
Отслеживание и восстановление состояния ВМ
Задача
Автоматически обнаруживать ВМ в некорректном состоянии и выполнять их перезагрузку в следующих случаях:
-
ВМ «зависает» и не отвечает.
-
Необходимо автоматическое восстановление сервисов.
-
Мониторинг критичных ВМ.
YAML-описание процедуры
vars:
value:
type: "number"
vcl:
type: "string"
visibility: "public"
vmname:
type: "string"
visibility: "public"
state:
type: "string"
visibility: "public"
steps:
save_value:
action:
apicall: "scheduler request show --name {{ vmname }} --vcluster {{ vcl }} --kind vm --metrics yes"
parse:
- filter: "metrics.libvirt_domain_info_vmstate[].value[] | [-1]"
op: "store"
var: "value"
log:
after: "{{ value }}"
reboot-on-error:
conditions:
- apicall: "scheduler request show --vcluster {{ vcl }} --name {{ vmname }} --metrics yes --kind vm"
expect:
- filter: "metrics.libvirt_domain_info_vmstate[].value[] | [-1]"
op: "!="
value: 1
attempts:
max: 1
interval: 15
on-error:
- error-type: AttemptsLimitReached
handler: _exit
action:
apicall: "scheduler request state --vcluster {{ vcl }} --name {{ vmname }} --kind vm --state {{ state }}"
wait-for-reboot:
conditions:
- apicall: "scheduler request show --vcluster {{ vcl }} --name {{ vmname }} --metrics yes --kind vm"
expect:
- filter: "metrics.libvirt_domain_info_vmstate[].value[] | [-1]"
op: "=="
value: 1
attempts:
max: 3
interval: 60
Подробное объяснение
Переменные vars:
value (number, private)— хранит последнее значение метрики состояния ВМ.vcl (string, public)— имя виртуального кластера.vmname (string, public)— имя виртуальной машины.state (string, public)— целевое состояние ВМ.
Шаг 1: save_value
Получить текущее состояние ВМ и сохранить в переменную.
Действие:
-
Выполняет команду
scheduler request showс параметрами:--name {{ vmname }}— имя ВМ;--vcluster {{ vcl }}— имя виртуального кластера;--kind vm— тип ресурса;--metrics yes— с метриками.
-
JMESPath выражение
Берет массив значений метрики
libvirt_domain_info_vmstate, выбирает последний элемент([-1]), сохраняет в переменнуюvalue. -
Логирует полученное значение.
Шаг 2: reboot-on-error
Проверить, что ВМ не в состоянии 1 (running), и если нет — перезагрузить.
Условия:
- Проверяет состояние ВМ той же командой, что в и в
save_value. - Ожидает последнее значение метрики ≠ 1.
- Попытки: максимум 1 попытка с интервалом 15 секунд.
- При ошибке: если достигнут лимит попыток происходит выход из процедуры
_exit.
Действие:
Выполняет перезагрузку ВМ
Шаг 3: wait-for-reboot
Дождаться успешной перезагрузки ВМ.
Условия:
- Проверяет состояние ВМ.
- Ожидает последнее значение метрики = 1 (
running). - Попытки: максимум 3 попытки с интервалом 60 секунд.
Как использовать
Возможны следующие варианты использования:
-
Запуск процедуры вручную
-
Планирование проверки каждые 5 минут
Фенсинг узлов кластера
Процедура состоит их двух частей:
Важно
Процедуры Фенсинг узлов кластера и Обработка конкретного узла предназначены только для пространства ВЦОД управления.
Не делегируйте их в пользовательские ВЦОД — это может привести к сбоям в работе сервисов
Задача
Автоматическое восстановление работоспособности кластера при отказе физических узлов:
- Обнаружение «упавших» узлов.
- Параллельный фенсинг всех проблемных узлов.
- Перераспределение ВМ на рабочие узлы.
Основная процедура Координация процесса
YAML-описание процедуры
config:
run-on-vip: true
vars:
exclude_current_node:
type: boolean
default: false
visibility: public
down_nodes:
type: array[string]
steps:
collect-down-nodes:
conditions:
# Выходим, если все узлы рабочие, и не требуется мигрировать vm
- apicall:
- "cluster nodes list"
- "scheduler labels list"
expect:
- filter: 'length(difference([0][?status==`DOWN`].uuid, [1]."system_drain_node=yes".nodes || `[]`))'
op: ">"
value: 0
attempts:
min: 2
max: 2
interval: 10
on-error:
- error-type: AttemptsLimitReached
handler: _exit
action:
apicall:
- "cluster nodes list"
- "scheduler labels list"
parse:
- filter: 'difference([0][?status==`DOWN`].uuid, [1]."system_drain_node=yes".nodes || `[]`)'
op: "store"
var: "down_nodes"
log: "Found down nodes: {{down_nodes}}"
process-down-nodes:
action:
apicall: 'checker procedure execute --name fence_node --vars ''{ "node": {{*down_nodes}}, "exclude_current_node": {{exclude_current_node}} }'' --json yes'
parse:
- filter: "@"
op: "push"
var: "@deps" # Добавляем подпроцедуру как зависимую для текущей процедуры
check-errors: # К этому шагу переходим только когда все подпроцедуры завершились
conditions:
- const: "{{@deps_status}}" # Читаем текущие статусы подпроцедур
expect:
- filter: "length([?task_status != `SUCCESS`])"
op: "=="
value: 0
attempts:
max: 1
log:
before: "{{*@deps_status | (task_status != `SUCCESS` && join(': ', ['Error', task_name || '', run_error || '', task_message || ''])) || ''}}"
Подробное объяснение
Конфигурация выполняется только на VIP-узле для гарантии доступности
Переменные:
exclude_current_node (boolean, public, default: false)— исключать ли текущий узел из доступных для миграции ВМ.down_nodes (array[string], private)— массив UUID "упавших" узлов.
Шаг 1: collect-down-nodes
Найти все узлы со статусом DOWN, которые не находятся на обслуживании.
Условия:
-
Выполняет две команды параллельно:
-
cluster nodes list— список всех узлов; -
scheduler labels list— список меток для поиска узлов на обслуживании. -
JMESPath выражение
- [
0][?status=='DOWN'].uuid— UUID всех узлов со статусомDOWN; [1]."system_drain_node=yes".nodes— узлы с меткой обслуживания;difference(...)— узлы в статусеDOWN, но не на обслуживании;length(...) > 0— проверка, что такие узлы есть.
- [
-
Попытки. Ровно 2 попытки с интервалом 10 секунд для того, чтобы убедиться, что узел действительно «упал».
- При ошибке, если после 2 попыток нет узлов для фенсинга, происходит выход из процедуры
_exit.
Действие:
- Повторно выполняет те же команды.
- Сохраняет найденные UUID узлов в переменную
down_nodes. - Логирует результат
"Found down nodes: [uuid1, uuid2, ...]".
Шаг 2: process-down-nodes
Запустить подпроцедуру фенсинга для каждого проблемного узла.
Действие:
-
Запускает подпроцедуру
fence_nodeдля всех узлов параллельно -
Распаковка массива
{{*down_nodes}}создаст параметр"node": [uuid1, uuid2]. - Параметр
--json yes— результат возвращается в машиночитаемом формате. - Сохранение в зависимости: результат
UUIDподзадачи добавляется в@deps. - Основная процедура будет ждать завершения всех подпроцедур.
Шаг 3: check-errors
Проверить результаты выполнения всех подпроцедур.
Условия:
- Использует встроенную переменную
{{@deps_status}}— статусы всех зависимостей. -
JMESPath выражение
Подсчитывает подпроцедуры со статусом
≠ SUCCESSи ожидает, что таких подпроцедур нет== 0. -
Логирование ошибок
"{{*@deps_status | (task_status != `SUCCESS` && join(': ', ['Error', task_name || '', run_error || '', task_message || ''])) || ''}}"Для каждой неудачной подпроцедуры формирует сообщение об ошибке в формате
"Error: <имя_задачи>: <ошибка>: <сообщение>".
Как использовать
Возможны следующие варианты использования:
-
Запустить с исключением текущего узла из доступных для миграции
-
Фенсинг по расписанию не рекомендован, тк является критичной операцией и может привести к нежелательным последствиям:
- если мониторинг узлов даст сбой, процедура может начать фенсить работоспособные узлы;
- фенсинг перезагружает узлы и мигрирует ВМ, что может нарушить работу сервисов.
Подпроцедура Обработка конкретного узла fence_node
Важно
Процедура Обработка конкретного узла предназначена только для пространства ВЦОД управления.
Не делегируйте ее в пользовательские ВЦОД — это может привести к сбоям в работе сервисов
YAML-описание процедуры
config:
run-on-vip: true
timeout: 600 # Максимум 10 мин на работу этой процедуры
vars:
# Задаем при запуске процедуры
node:
type: string
visibility: public
exclude_current_node:
type: boolean
visibility: public
steps:
restart-node:
action:
apicall: "commands ipmi power reset --node_uuid {{node}}"
exclude-node:
conditions:
- const: "{{exclude_current_node}}"
expect:
- filter: "@"
op: "=="
value: true
attempts:
max: 1
on-error:
- error-type: AttemptsLimitReached
handler: _continue
action:
apicall: "scheduler drain add --nodes {{node}}"
reschedule-vms:
action:
apicall: "scheduler request reschedule --node_uuid {{node}}"
parse:
- filter: "@"
op: "push"
var: "@deps"
reinclude-node:
conditions:
- const: "{{exclude_current_node}}"
expect:
- filter: "@"
op: "=="
value: true
attempts:
max: 1
on-error:
- error-type: AttemptsLimitReached
handler: _continue
action:
apicall: "scheduler drain del --nodes {{node}}"
check-errors:
conditions:
- const: "{{@deps_status}}"
expect:
- filter: "length([?task_status != `SUCCESS`])"
op: "=="
value: 0
attempts:
max: 1
log:
before: "{{*@deps_status | (task_status != `SUCCESS` && join(': ', ['Error', task_name || '', run_error || '', task_message || ''])) || ''}}"
Подробное объяснение
Конфигурация выполняется на VIP-узле с таймаутом 10 минут (600 с)
Переменные:
node (string, public)— UUID узла для фенсинга;exclude_current_node (boolean, public)— параметр из основной процедуры.
Шаг 1: restart-node
Выполнить hard reset узла через IPMI.
Действие:
-
Отправляет команду
-
Не ждёт завершения перезагрузки, только отправляет команду.
- Если команда не отправлена, процедура завершается с ошибкой.
Шаг 2: exclude-node
Если exclude_current_node == true, добавить метку drain на узел.
Условия:
- Проверяет значение
{{ exclude_current_node }}. - Ожидание:
значение = true. - При ошибке: если условие не выполняется, то пропуск шага
_continue.
Действие:
-
Выполняет команду
-
Добавляет метку
system_drain_node=yes. - Scheduler не будет размещать ВМ на этой узле.
Шаг 3: reschedule-vms
Запустить миграцию всех ВМ с проблемного узла.
Действие:
- Выполняет команду
- Отвязывает все ВМ от указанного узла.
- Scheduler автоматически перераспределяет их на другие узлы.
- Сохранение в зависимости: результат
UUID задачидобавляется в@deps.
Текущий шаг будет ждать завершения миграции ВМ.
Шаг 4: reinclude-node
Если ранее добавляли метку drain, необходимо удалить ее.
Условия и действие: Аналогично шагу exclude-node, но для удаления метки:
Шаг 5: check-errors
Проверить результат миграции ВМ.
Условия:
- Использует
{{@deps_status}}— статус задачи миграции ВМ. - Ожидание: все задачи миграции завершены успешно
SUCCESS. - Логирование: аналогично основной процедуре, формирует сообщения об ошибках.
Как использовать подпроцедуру отдельно
Ручной запуск фенсинга для конкретного узла кластера
checker procedure execute --name fence_node
--vars '{
"node": "uuid_current_node,
"exclude_current_node": true
}'
Термины и определения содержатся в статьях: