Ansible переменная имеет противоречивые значения - PullRequest
4 голосов
/ 26 февраля 2020

Я играл с ansible последние пару дней и столкнулся с поведением, которое не имеет смысла для меня. Я могу воспроизвести это с помощью простой пьесы, которая выполняет две роли. Каждая роль устанавливает переменную, а затем импортирует цепочку других ролей. Другие роли ничего не делают, кроме как распечатывают значение переменной, а затем импортируют следующую роль в цепочке. Вывод, который я получаю:

$ ansible -playbook site.yml

"msg": "role_1a v1 = role_1a default"
"msg": "role_2 v1 = role_1a default"
"msg": "role_3 v1 = role_1a default"
"msg": "role_4 v1 = role_1b default" <=== expected role_1a default
"msg": "role_5 v1 = role_1b default" <=== expected role_1a default

"msg": "role_1b v1 = role_1b default"
"msg": "role_2 v1 = role_1b default"
"msg": "role_3 v1 = role_1a default" <=== expected role_1b default
"msg": "role_4 v1 = role_1b default"
"msg": "role_5 v1 = role_1b default"

Я прочитал раздел по переменным около двадцати раз сейчас, и единственное, что я вижу, это может иметь отношение к этому «Так как Ansible 2.7 переменные, определенные в переменных и значения по умолчанию для роли, выставляются во время синтаксического анализа playbook», что, я полагаю, может означать, что наследование переменных во время выполнения является грандиозным выстрелом.

# site.yml
- hosts: testserver
  roles:
    - role_1a
    - role_1b

# roles/role_1a/defaults/main.yml
v1: "role_1a default"

# roles/role_1a/tasks/main.yml
- debug: msg="role_1a v1 = {{ v1 }}"
- import_role: name=role_2

# roles/role_2/tasks/main.yml
- debug: msg="role_2 v1 = {{ v1 }}"
- import_role: name=role_3

# roles/role_3/tasks/main.yml
- debug: msg="role_3 v1 = {{ v1 }}"
- import_role: name=role_4

# roles/role_4/tasks/main.yml
- debug: msg="role_4 v1 = {{ v1 }}"
- import_role: name=role_5

# roles/role_5/tasks/main.yml
- debug: msg="role_5 v1 = {{ v1 }}"

# roles/role_1b/defaults/main.yml
v1: "role_1b default"

# roles/role_1b/tasks/main.yml
- debug: msg="role_1b v1 = {{ v1 }}"
- import_role: name=role_2

# hosts
[testing]
testserver

# /etc/ansible/ansible.cfg
[defaults]
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]

$ ansible --version
ansible 2.9.3
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/joe/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.5 (default, Aug  7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
re

1 Ответ

0 голосов
/ 27 февраля 2020

Q: "Тот факт, что, очевидно, все остальные могут использовать переменные без проблем, я более склонен полагать, что есть некоторая фундаментальная концепция, которую я пропустил по пути."

A: К сожалению, не так. Очень вероятно, что это проблема Ansible. Есть десяток проблем с включением и импортом . Некоторые из них напоминают о проблеме, описанной здесь


Мне удалось воспроизвести отчетный результат , Игра
- hosts: localhost
  roles:
    - role_1a
    - role_1b

дает

    "msg": "role_1a v1 = role_1a default"
    "msg": "role_2 v1 = role_1a default"
    "msg": "role_3 v1 = role_1a default"
    "msg": "role_4 v1 = role_1b default"
    "msg": "role_5 v1 = role_1b default"
    "msg": "role_1b v1 = role_1b default"
    "msg": "role_2 v1 = role_1b default"
    "msg": "role_3 v1 = role_1a default"
    "msg": "role_4 v1 = role_1b default"
    "msg": "role_5 v1 = role_1b default"

Давайте удостоверимся, что порядок сообщений правильный. Измененные задачи (аналогично role_1a, 2,3,4)

# roles/role_1b/tasks/main.yml
- debug: msg="role_1b v1 = {{ v1 }}"
- import_role:
    name: role_2
  vars:
    root: "role_1b"

# roles/role_5/tasks/main.yml
- debug: msg="root = {{ root }} | role_5 v1 = {{ v1 }}"

дают

    "msg": "role_1a v1 = role_1a default"
    "msg": "root = role_1a | role_2 v1 = role_1a default"
    "msg": "root = role_1a | role_3 v1 = role_1a default"
    "msg": "root = role_1a | role_4 v1 = role_1b default"
    "msg": "root = role_1a | role_5 v1 = role_1b default"
    "msg": "role_1b v1 = role_1b default"
    "msg": "root = role_1b | role_2 v1 = role_1b default"
    "msg": "root = role_1b | role_3 v1 = role_1b default" <=== was: role_1a default
    "msg": "root = role_1b | role_4 v1 = role_1b default"
    "msg": "root = role_1b | role_5 v1 = role_1b default"

Это показывает, что порядок сообщений правильный. Но результат изменился. Теперь результат role_1b соответствует ожидаемому.


Q: "Пространство имен для избежания конфликтов. Что такое пространство имен?"

A: «Пространство имен» означает «определить переменную» или, в частности, «зарегистрировать переменную на хосте», т.е. поместить переменную в hostvars. Например,

# roles/role_1a/tasks/main.yml
- set_fact:
    v1: "{{ v1 }}"
- debug: msg="role_1a v1 = {{ v1 }}"
- import_role:
    name: role_2
  vars:
    root: "role_1a"

дает ожидаемый результат

    "msg": "role_1a v1 = role_1a default"
    "msg": "root = role_1a | role_2 v1 = role_1a default"
    "msg": "root = role_1a | role_3 v1 = role_1a default"
    "msg": "root = role_1a | role_4 v1 = role_1a default"
    "msg": "root = role_1a | role_5 v1 = role_1a default"
    "msg": "role_1b v1 = role_1a default"
    "msg": "root = role_1b | role_2 v1 = role_1a default"
    "msg": "root = role_1b | role_3 v1 = role_1a default"
    "msg": "root = role_1b | role_4 v1 = role_1a default"
    "msg": "root = role_1b | role_5 v1 = role_1a default"

, поскольку, как только переменная v1 была определена в области действия платежной книжки, нет необходимости искать значение по умолчанию. Следует отметить, что

- debug: msg="role_1a v1 = {{ v1 }}"

не определяет переменную v1. Этот оператор будет оценивать только переменную v1 по требованию. Цитата из Ansible Глоссарий :

Lazy Evaluation : В целом, Ansible оценивает любые переменные в содержимом playbook в последнюю возможную секунду, что означает, что если вы определяете структуру данных, то сама структура данных может определять значения переменных внутри нее, и все «просто работает» так, как вы ожидаете. Это также означает, что переменные строки могут включать другие переменные внутри этих строк.

Тот же результат должен быть достигнут с измененным порядком ролей, поскольку все роли импортированы.

- hosts: localhost
  roles:
    - role_1b
    - role_1a

дает

    "msg": "role_1b v1 = role_1b default" <=== expected role_1a default
    "msg": "root = role_1b | role_2 v1 = role_1b default" <=== expected role_1a default
    "msg": "root = role_1b | role_3 v1 = role_1b default" <=== expected role_1a default
    "msg": "root = role_1b | role_4 v1 = role_1a default"
    "msg": "root = role_1b | role_5 v1 = role_1a default"
    "msg": "role_1a v1 = role_1a default"
    "msg": "root = role_1a | role_2 v1 = role_1a default"
    "msg": "root = role_1a | role_3 v1 = role_1a default"
    "msg": "root = role_1a | role_4 v1 = role_1a default"
    "msg": "root = role_1a | role_5 v1 = role_1a default"

Это показывает, что «пространство имен», вероятно, необходимо во всех ролях. Например,

# roles/role_1b/tasks/main.yml
- set_fact:
    v1: "{{ v1 }}"
- debug: msg="role_1b v1 = {{ v1 }}"
- import_role:
    name: role_2
  vars:
    root: "role_1b"

решает проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...