Сообщение об ошибке
1.6.10 и 1.7
Mac OSX 10.9.4
Я нашел странную ошибку с нестандартными плейбуками (или, может быть, с моим кодом/настройкой). Когда я использую сборник задач с включением, переданные переменные нельзя использовать в «имени» модуля.
name:
включите переменную.Вот пример проблемы:
task_runner.yml
---
- name: Disable {{ host }}
hosts: all
gather_facts: no # for debug purposes
tasks:
- name: Run task
include: tasks.yml
vars:
host: "{{ host }}"
Задачи.yml
- name: "ping {{ host }} twice"
shell: ping -c 2 {{ host }}
Следует отметить, что если я изменю name: "ping {{ host }} twice"
на name: "ping host twice"
, я не получу ошибку (которую я получаю в разделе «Фактические результаты» ниже).
Нет сообщения об ошибке.
Вот рабочий пример, впервые выполненный в одном плейбуке:
task_playbook.yml
---
- name: Disable {{ host }}
hosts: all
gather_facts: no # for debug purposes
tasks:
- name: ping {{ host }} twice
shell: ping -c 2 {{ host }}
Вот как это работает:
(venv) isingh$ ansible-playbook -c local task_playbook.yml -i hosts --extra-vars host=google.com
PLAY [Disable google.com] *****************************************************
TASK: [ping google.com twice] *************************************************
changed: [fionn]
PLAY RECAP ********************************************************************
fionn : ok=1 changed=1 unreachable=0 failed=0
(venv) isingh$ ansible-playbook -c local tasks_runner.yml -i hosts --extra-vars host=google.com
PLAY [Disable google.com] *****************************************************
ERROR: recursive loop detected in template string: {{host}}
Спасибо.
Привет!
Похоже, это работает именно так, как было задумано для меня, потому что вы определяете переменную с именем host, значением которой является host.
vars:
host: "{{ host }}"
Я бы рекомендовал _НЕ_ этого делать.
Это что-то вроде "Доктор, у меня болит рука, когда я это делаю", если перевести эту шутку :)
Я собираюсь закрыть этот вопрос, так как он работает, как задумано, но не стесняйтесь заходить на ansible-project, если вы хотите продолжить обсуждение. Мы открыты для этого.
Я сталкиваюсь с той же ошибкой, хотя и с другой конфигурацией. Этого достаточно, чтобы воспроизвести его в плейбуке:
vars:
app:
user: rails
home: "/home/{{ app.user }}"
Если я сравню переменные с app_user
и app_home
, все будет замечательно, но я подумал, что было бы неплохо сохранить иерархию, особенно когда у меня много переменных с префиксом app
. Использование анзибл 1.8.3.
Я в той же лодке, что и Томник. Хотя, если подумать, это имеет смысл. Мы пытаемся сослаться на переменную до того, как она была назначена.
Попробуйте то же самое в питоне:
>>> app = {"user": "rails", "home": "/home/" + app['user']}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'app' is not defined
Это позор, потому что это делает хорошие аккуратные конфиги.
Мой обходной путь - определить повторно используемые переменные отдельно, т.е. в вашем случае:
app_user: "rails"
app:
user: "{{ app_user }}"
home: /home/{{ app_user }}
Немного некрасиво, но пока это компромисс, с которым я согласен.
Имея нечто подобное после перехода с 1.6.X на 1.8.4. Раньше это работало для нас, теперь мы сталкиваемся с проблемой рекурсии.
У нас есть плейбук следующим образом:
- role: rsyslog
tags: ['rsyslog']
rsyslog:
reception:
tcp:
enabled: True
transmission:
tcp:
enabled: True
hosts: "{{rsyslog.producers}}"
Затем в group_vars для конкретной среды мы определяем rsyslog:
rsyslog:
producers: "{% set hosts = ['localhost:5544'] %}{% for host in groups['logmaster'] %}{% do hosts.append(host + ':5140') %}{% endfor %}
После запуска роли rsyslog мы получаем ошибку:
=> в строке шаблона обнаружен рекурсивный цикл: {{rsyslog.producers}}
Я очень надеюсь, что это была не ошибка, которую исправили и теперь мы не можем ею воспользоваться. Моя интуиция чувствует, что это изменение порядка в том, как создаются переменные. Обратите внимание, что мы принудительно объединили hash_behaviour в нашей конфигурации ansible.
Любые мысли или предложения будут приветствоваться, прежде чем я углублюсь или переработаю то, как мы определяем вещи.
та же проблема :-1:
Та же проблема, которую удалось обойти, просто переместив и переименовав «конфликтующую» переменную.
То же самое здесь ... потому что вы вслух передаете «переменные» в качестве дополнительных аргументов, бывают случаи, когда мне нужно использовать переданное значение, иначе используйте значение по умолчанию.
ansible-playbook playbook.yml -e "my_var=1"
# playbook.yml
vars:
my_var: "{{ my_var | default(my_default_var) }}"
Только что столкнулся с тем, что сделал @thom-nic. Я не совсем уверен, почему это приводит к ошибке. Глядя на это, похоже, что-то, что должно работать отлично.
Ага. когда я вставляю зависимости ролей, это происходит.
Та же проблема здесь. Хотел использовать более приятный формат так плохо
Программное обеспечение может решить все виды проблем, и, конечно же, это тоже можно решить. Однако формат словаря, вызывающего сам себя во время его определения, находится в его собственном домене. Год назад кто-то задал этот вопрос, где предлагается формат, это может быть способ сделать это:
Я также сталкиваюсь с той же ошибкой. Может кто-нибудь сказать мне, как мне это сделать. Я использую приведенную ниже переменную и получаю ошибку рекурсивного цикла.
maxHeapSizeAnsi: "{{(hostvars[inventory_hostname]['ansible_memtotal_mb'] * 3 / 4)|int}}"
Я тоже в него попадаю. Это будет исправлено? Должен ли он быть вновь открыт?
+1
+1
+1
+1
+1
+1
+1
Кажется глупым, но понятно, почему это не должно работать из-за того, что словарь пытается рекурсивно запросить у себя ключ, когда сам словарь еще не полностью инициализирован.
Вот как мне удалось обойти это с ролью:
Это то, что я пытался сделать заранее, чтобы иметь только одно место для изменения версии.
application:
params:
state: present
version: "0.6.3"
download_url: "https://releases.hashicorp.com/consul/{{ consul.params.version }}/consul_{{ consul.params.version }}_linux_amd64.zip"
agent:
...
Я решил использовать папку по умолчанию и запихнуть туда случайные вещи, так как сохранение плоского состояния vars заставляет их сначала инициализироваться. Затем я мог бы втянуть их в свою «красивую» структуру в vars/main.yml.
.
|-roles
|---Application
|-----defaults
|-------main.yml
|-----files
|-----handlers
|-----meta
|-----tasks
|-----templates
|-----vars
|-------main.yml
В defaults/main.yml у меня есть:
_version: "0.6.3"
_download_url: "https://releases.hashicorp.com/consul/{{ _version }}/consul_{{ _version }}_linux_amd64.zip"
В defaults/vars.yml у меня есть:
consul:
params:
state: present
version: "{{ _version }}"
download_url: "{{ _download_url }}"
is_agent: false
agent:
...
Таким образом, переменные по-прежнему могут быть изменены выше, но также позволяет единый источник, из которого можно изменить «переменные по умолчанию»;)
После тестирования я изменил переменные по умолчанию, чтобы они имели подчеркивание из-за того, что они обозначались таким образом (согласно соглашению) как «частные». Кроме того, таким образом вы точно знаете, из какого файла считываются переменные. хе.
+1
+1
Я хотел бы иметь возможность использовать такую конфигурацию:
myapp:
version: 1.6.3
download_url: http://example.org/download/myapp-{{ myapp.version }}.tgz
Я бы рекомендовал НЕ делать этого.
Это что-то вроде "Доктор, у меня болит рука, когда я это делаю", если перевести эту шутку :)
@mpdehaan , представьте, что я только что установил другой модуль от ansible galaxy взамен того, который я использовал раньше. Представьте, что он установил переменную по умолчанию с именем, скажем, mysql_version
. Представьте, что у меня есть переменная с точно таким же именем в моем модуле, которая имеет метазависимость от модуля, который я только что установил.
Я не хочу менять имя переменной внутри моего модуля. Поскольку это само по себе мнемоника, и все переменные названы по одному и тому же правилу, то есть service_name_version
, и я не хочу создавать свою команду с чем-то вроде mysql_version_another_stupid_name_because_ansible_cannot_do_that_properly
. Специальное имя переменной — еще один нюанс, который член команды должен помнить, а значит, больше шансов на ошибку. И я не могу принести это из инвентаря, так как модуль должен быть общим.
Что бы вы посоветовали для этого довольно распространенного варианта использования?
+1
+1
Отсутствие этого мешает иметь красивую, чистую иерархию переменных, поскольку мы должны делать это старомодным способом с префиксами. Учитывать:
mysql:
version: 5.5
install_path: "/var/lib/mysql/{{ mysql.version }}"
user: mysql
group: mysql
против
mysql_version: 5.5
mysql_install_path: "/var/lib/mysql/{{ mysql_version }}"
mysql_user: mysql
mysql_group: mysql
Хотя это всего лишь пример, а не реальный случай (по крайней мере, для меня), он показывает, в чем проблема. ИМО, последнее определение просто противно. Первый применяет своего рода DRY'ing.
+1
Хотя, если подумать, это имеет смысл. Мы пытаемся сослаться на переменную до того, как она была назначена.
Эта функция на самом деле четко определена с точки зрения значения ровно одной вещи. Синтаксис и семантика (с точки зрения логики) хорошо определены для такого рода «обратной ссылки».
Проблема здесь действительно относится только к тому, как будет выглядеть реализация.
Предположение здесь отчасти неверно. Потому что здесь мы обрабатываем два синтаксиса. YAML и доступные переменные. Нужно знать, что недоступное понятие переменных {{ some_var_name_here }}
не имеет смысла в YAML (см. раздел 2 этого). На самом деле он сам является доступным, что придает смысл этой строке. И, таким образом, ansible свободен в том, как реализовать парсер для обработки этого. Давайте рассмотрим быстрый пример, учитывая следующий документ настроек YAML:
1. hash_map:
2. version: ab
3. path: "/somepath/{{hash_map.version}}"
Когда определена переменная hash_map
? Уже на _строке 1_ или только после _строки 3_?
Посмотрим, как это решение повлияет на реализацию.
Обратите внимание: эти примеры действительно упрощены, на самом деле все это будет обрабатываться синтаксическим анализатором по-другому.
Реализация №1 подразумевает, что структура данных определяется только после _строки 3_ в приведенном выше примере:
variables = {}
variables["hash_map"] = {"version": "ab", "path": "/somepath/{{hash_map.version}}" }
# We cannot do this!!!
variables["hash_map"] = {"version": "ab", "path": "/somepath/%s" % variables["hash_map"]["version"] }
Реализация № 2 подразумевает, что _строки 1_ выше вполне достаточно для размещения структуры данных.
variables = {}
variables["hash_map"] = {}
variables["hash_map"]["version"] = "ab"
# This is totally possible
variables["hash_map"]["path"] = "/somepath/%s" % variables["hash_map"]["version"]
Оба представляют одно и то же, но, как вы можете видеть, последний немного мощнее.
Давайте посмотрим, чего мы можем добиться с помощью простого YAML.
Стандарт YAML описывает семантику YAML как корневой ориентированный граф. Узлы описаны в разделе 3.2.1.1.
В соответствии со _стандартом_ значения также представлены в виде узлов. Но — и вот в чем дело — насколько мне известно, не существует типа узла, который мог бы семантически правильно (как мы этого хотим) представить описанную выше функцию как один узел . Единственным реальным вариантом здесь будет использование узла sequence
(он же список в YAML).
Приведенный выше пример YAML будет представлен следующим графиком в соответствии с моим пониманием стандарта:
Поскольку мы хотим придать значение {{hash_map.version}}
, нам придется использовать anchor
и псевдонимы узлов, подобные этому:
Примечание. Эта функция описана в разделе 6.2.9. Раздел
1. hash_map:
2. version: &anchor "ab" #setting the anchor
3. path:
4. - "/somepath/"
5. - *anchor # referring to the anchor, yields ab
Проверьте это с помощью онлайн-парсера YAML.
получается следующий график:
Выше мы видим, что мы не можем объединить эти два узла. Таким образом, невозможно реализовать эту функцию, используя только синтаксис YAML.
Но мы также можем видеть, что {{ some_var_name_here }}
— это всего лишь анзиблируемая нотация, которая не имеет значения в YAML. Таким образом, мы вольны определять семантику этого по своему усмотрению!
YAML - это язык разметки (несмотря на то, что может предполагать его аббревиатура), и язык разметки просто отвечает на вопрос "что", а не "как". И поскольку совершенно ясно, что означает ссылка, реализовать эту функцию вполне возможно.
Имейте в виду, что эта функция не соответствует текущему стандарту YAML v.1.2 (последняя версия согласно Википедии ), но это не соответствует нашему понятию переменных
{{ some_var_name_here }}
.
РЕДАКТИРОВАНИЕ:
Ну и какой вывод? Поскольку {{ some_var_name_here }} - это просто неизменяемая нотация, и ее семантика может быть изменена для обработки "отложенного разрешения", планируете ли вы реализовать что-то подобное (например, привязку замыкания, например, в groovy)? Вопрос все еще закрыт.
Я бы очень хотел реализовать эту функцию! Хотя это не так просто. Поскольку эта функция имеет большее влияние, мне потребуется некоторое время, если я сделаю это самостоятельно. Желательно, чтобы был один или два других участника, готовых помочь, и в этом случае все ускорится.
Для меня такое поведение было действительно неожиданным и странным. Есть много возможных сценариев, когда с текущим поведением не очень приятно работать:
~~~
Это потенциально происходит каждый раз, когда вы передаете данные из одной роли/задачи в другую. Особенно с внешними ролями (Galaxy) это может быть основным PITA. Обходной путь установки промежуточного факта или использования промежуточной фиктивной задачи довольно уродлив:
~~~
Это очень неожиданное поведение. Любой приличный язык позволяет вам установить ключ dict, равный переменной с таким же именем. В питоне, например:
{'host': host}
Было бы настоящей проблемой, если бы нужно было изменить имя переменной только для того, чтобы передать его дальше:
{'host': _host}
В настоящее время лучшим обходным решением, которое я нашел, является префикс переменных с именем роли. например:
nginx_domain: '{{ myapp_domain }}'
Это работает, но это довольно хлопотно, тебе не кажется?
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
+1
Это ошибка реализации YAML.
+1
+1
+1
+1
+1
Я также попал в это. Не могли бы вы подумать о повторном открытии этого?
@everybody , я имею в виду буквально всех :-).
Это поразило меня раньше, единственное, что вы можете сделать, это реструктурировать свои переменные. Обратите внимание, что вы не можете ссылаться на переменную, которая еще не определена (см. приоритет переменных в документах ansible. Также обратите внимание, что если вы ссылаетесь на переменную, которую вы определяете позже в файле, вы получите сообщение об ошибке.).
Настоящая «проблема» не в Ansible, а в Jinja2. Если вы думаете, что можете это исправить, будьте моим гостем. Однако я не думаю, что это легко исправить, если не невозможно в рамках текущей архитектуры/проекта jinja2.
Когда у вас есть что-то подобное (например, @rqelibari ):
hash_map:
version: ab
path: "/somepath/{{hash_map.version}}"
А также хочет чистый и красивый файл с переменными и / или каталог. Рассмотрим другую архитектуру, вы можете добавить переменные в другие файлы, вы не ограничены файлом main.yml или файлом all.yml. Ansible гибок, поэтому, если вы сообразительны, двигайтесь и играйте с ним :-D.
Например, вы можете создать файл в каталоге all группы group_vars с именем hash_map и создать в этом файле нужные вам переменные.
Да, было бы неплохо, если бы можно было сослаться на отмеченный вами ключ в том же хранилище ключей, в настоящее время это невозможно. Я не вижу, чтобы это произошло в ближайшие несколько месяцев...
Обходите это, проявляйте творческий подход и не делайте беспорядок в своих скриптах. Лично мне хотелось, чтобы все настраивалось с помощью ansible-variables. Единственной наградой, которую я получил, была неуправляемая пьеса и нечеткая структура переменных :-).
Хорошо, не добавляйте +1 к этому в ansible, но исправьте это в проекте jinja2.
Эта проблема является прямым результатом использования ansibles парсера yaml.
функция интерполяции вместо загрузки объекта yaml и выполнения второго
проход для интерполяции. Это не просто ошибка jinja, это
ошибка реализации в ansible. Пожалуйста, осмотрите. Загрузка как необработанная строка и
затем обработка инициализированных членов объекта во втором проходе должна исправить
это.
+1
+1
+1
+1
Самый полезный комментарий
Я сталкиваюсь с той же ошибкой, хотя и с другой конфигурацией. Этого достаточно, чтобы воспроизвести его в плейбуке:
Если я сравню переменные с
app_user
иapp_home
, все будет замечательно, но я подумал, что было бы неплохо сохранить иерархию, особенно когда у меня много переменных с префиксомapp
. Использование анзибл 1.8.3.