Условия и циклы
Тема дорожной карты · SaltStack
Условия {% if %} и циклы {% for %} — управляющие конструкции Jinja, которые превращают SLS-файл из статичного списка состояний в генератор: один шаблон разворачивается в разный YAML в зависимости от миньона и данных. Условия обычно ветвятся по grains (дистрибутив, версия, роль машины) и pillar (включена ли фича, какое окружение), циклы — разворачивают списки и словари из pillar в наборы однотипных состояний: пользователи, виртуальные хосты, точки монтирования. Важно держать в голове масштаб: это не логика времени исполнения, а логика времени рендеринга. К моменту, когда Salt начинает применять состояния, всех if и for уже нет — остался только сгенерированный ими YAML.
Как это работает
Условие ветвит текст шаблона:
{% if grains['os_family'] == 'RedHat' %}
{% set svc = 'httpd' %}
{% elif grains['os_family'] == 'Debian' %}
{% set svc = 'apache2' %}
{% else %}
{% set svc = 'apache' %}
{% endif %}
Цикл по словарю из pillar генерирует состояния — ID каждого должен быть уникален, поэтому в него включают переменную цикла:
{% for site, cfg in salt['pillar.get']('vhosts', {}).items() %}
vhost_{{ site }}:
file.managed:
- name: /etc/nginx/conf.d/{{ site }}.conf
- source: salt://nginx/files/vhost.conf.jinja
- template: jinja
{% endfor %}
Дефисы в тегах — {%- if ... -%} — съедают пробелы и переводы строк вокруг тега; без них циклы оставляют в результате пустые строки. Обычно это безвредно для YAML, но затрудняет чтение вывода slsutil.renderer. Глобально поведение регулируется опциями jinja_trim_blocks и jinja_lstrip_blocks в конфигурации, но по умолчанию они выключены, и менять их для общих формул рискованно — шаблоны, написанные под другие настройки, начнут рендериться иначе.
Когда применять
Ветвление по grains['os_family'] — правильный уровень общности: семейство покрывает целую линейку дистрибутивов, тогда как проверка точного grains['os'] быстро превращается в лестницу из elif. Циклы по pillar — стандартный способ отдать управление данными: добавление нового виртуального хоста становится правкой pillar, а не SLS-файла. Проверка «есть ли данные» перед циклом не нужна, если использовать pillar.get с пустым дефолтом ({} или []) — цикл по пустой коллекции просто ничего не сгенерирует. А вот когда условия начинают определять десятки значений (пакет, сервис, путь, владелец — и всё по ОС), это признак, что пора переходить на паттерн map.jinja и держать данные словарём, а не веткой кода.
Типичные ошибки
Главная — дублирующиеся ID состояний в цикле: если ID не включает переменную итерации, каждая следующая итерация затирает предыдущую, и применяется только последняя — без ошибок, молча. Вторая — сравнение с неверным регистром или значением grain: grains['os'] возвращает, например, Ubuntu, а не ubuntu; при сомнении проверьте реальное значение через salt '*' grains.item os os_family. Третья — вложенные циклы и условия на три-четыре уровня: такой шаблон невозможно ревьюить, а ошибка отступа в глубине даёт YAML-ошибку со смещённым номером строки. Четвёртая — логика, зависящая от порядка итерации по словарю, когда конфиг собирается из фрагментов: делайте результат нечувствительным к порядку или сортируйте явно.
Связанные понятия
Полезные ресурсы
Проверить знания (2)
Загрузка вопросов…