In this part we stop talking about the simple and the pleasant and start talking about the difficult. Variables in Ansible: scope, precedence, recursive interpolation. For those who read to the end, a little bonus: a simplified priority table to live with. Previous parts: 1 , 2 .
Usually, a story about variables in Ansible starts with something very simple, which gives the reader the illusion that variables in Ansible are like in any other programming language. Mutable or non-mutable, local and global. This is not true.
This is not true.
Ansible has a unique variable model (memory model?), Which must be learned from scratch. And we will start considering it from the place where the values ββare used (usually Ansible variables are considered from where they appear). Why? Because when telling in this direction, we have a directed graph, which is much easier to put in our heads.
Note - I said "values" because "variables" are just names to values. Variables have their own deep inner world, and about it in the second part.
Throughout this story, I will use the terms "appears" and / "is used". Appears - this is where the value was set. And "hits" - this is the place where the value begins to influence the work of Ansible, or rather, its side effects - on the real process of executing modules in the target system. While the variables are being moved from place to place in the section vars
, the values ββdo not "get" anywhere and do not affect the surrounding world in any way.
This is the first important thought that you need to remember in your head: as long as the value has not been used by something that affects the world around it, it can contain any syntax errors and references to non-existent variables, etc., and this will not confuse anyone. Why so - read on.
So where are the values ββused?
- .
- copy: src=foo.conf dest=/etc/foo.conf
.foo.conf
/etc/foo.conf
β . . , , , . , jinja, / , (, , , , ). - ( action plugin) 'template' lookup plugin' template. ( lookup plugin , , ).
- play. play ( play) play. , jinja2
gather_facts
, play. βhosts
,remote_user
. - , . ,
ansible_host
,ansbile_user
,ansible_extra_ssh_args
,ansible_transport
.. .
, :
- name: Do not do this
file: path=hello.txt state=touch
loop: '{{ groups.all }}'
vars:
ansible_host: '{{ hostvars[item].ansible_host }}'
. "" ( , ).
?
-
ansible_host
( ){{ hostvars[item].ansible_host }}
. . yaml, . -
loop
.{{ groups.all }}
. β jinja. , . loop , , item " ". -
hello.txt
touch
. jinja, . -
file
ansible_host
ssh β . ,ansible_host
Jinja, . , (.. loop). , jinja item, (.. item - ). , . ? . , .
β . , , - . set_fact
, ( ), .
. , ( best practice) IP- :
allow_access: '{{ ansible_default_ipv4.address }}'
, setup ( gathering_facts), allow_access Jinja , β , .
Jinja
β Jinja ( ). , , (), ( ). : - . . - , . , . , ( , ..). , Jinja , .
:
- debug:
msg: '{{ message }}'
vars:
foo: 'foo'
foobar: '{{ foo + "bar" }}'
message: 'This is {{ foobar }}'
, 'msg' 'debug' ( , action plugin, ), {{ message }}
. ({{
}}
) message. This is {{foobar }}
. This is {{ foo + "bar" }}
. This is foobar
. , .. . msg debug.
, , , .
WTF, " ".
- hosts: localhost
tasks:
- debug: msg={{foo}}
vars:
foo: ''{{ foo + 1 }}'
vars:
foo: 1
play, "" foo . play, . debug? msg . , {{ foo + 1 }}
, {{ foo + 1 }} + 1
.. , .
:
- hosts: localhost
tasks:
- set_fact:
foo: '{{ foo + 1 }}'
- debug: msg={{foo}}
vars:
foo: 1
""? ? set_fact
- foo. foo, . , , foo ( 1) , foo . , .
, , . .
.
- hosts: localhost
vars:
foo: '{{ bar * 2 }}'
tasks:
- debug: var=foo
loop: [1,2,3]
vars:
bar: '{{ item + 10 }}'
vars play ( ). WTF , .
? 1, 2, 3. :
foo
'{{ bar * 2 }}'
bar
'{{ item + 10 }}'
. , vars ( play, ), ( ) , . . , "", - .
debug. foo {{ bar *2 }}
, {{ (item + 10) * 2 }}
. item ( loop') 22, 24, 26.
β , , , , .. scope/precedence ( ), , .
:
- hosts: localhost
vars:
foo: '{{ bar }}'
tasks:
- debug: var=foo
vars:
bar: 'one value'
- debug: var=foo
vars:
bar: 'another value'
. , , bar . Mystery solved.
Jinja
, (, jinja) . jinja. {{ }}
, {% if True %} "" {%endif %}
. . yaml .
- foo_module:
username: <
{% for user in myusers %}
{% if user.lower() in good and user.upper() in other %}
{{ user }}
{% endif %}
{% endfor %}
'content' file
. :
- name: Configure sfcapd systemd service
become: true
copy:
content: |
[Unit]
Description=sflow capture service
[Service]
Type=simple
ExecStart=/usr/bin/sfcapd sfcapd -w -T{{ sflow_extensions }} -p {{ sflow_port }} -B {{ sflow_buffer_size }} -l {{ sflow_data_path }} -b {{ sflow_host }}
Restart=always
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/sfcapd.service
notify:
- restart sfcapd
? 100500 . , . template
, copy
content
. , .
. .
- (, prometheus Go), . yaml- .
Ansible : safe unsafe. safe- β , . unsafe .
:
- debug:
msg: !unsafe'{{ inventory_hostname }}'
" ", {{ inventory_hostname }}
.
, .
β , ? , , : . , , ( ).
, , -, PHP .
.
---
- hosts: localhost
gather_facts: false
tasks:
- name: Case1
debug: var=item
loop: '{{ [1,2,3,4] }}'
- name: Case2
debug: var=item
loop: '{{ foo + bar }}'
- name: Case3
debug: var=item
loop: ' {{ [9,10] }}'
vars:
foo: '[5,6'
bar: '7,8]'
Case1 Jinja . , jinja2 , . , yaml'.
Case2 ( β , ) β , , - , . PHP.
Case3 β , .
Case2 Case3 β , . , , . ( ) json. , ( json').
Ansible:
- name: Case6, space at the end
debug: var=item
loop: '{{ [15, 16] }} '
- name: Case7, space at the start
debug: var=item
loop: ' {{ [15, 16] }}'
Case6 , loop ( ), Case7 , . ? . .
β¦ . , , WTF' .
: , . 5 , , . ", ". , - β .
, : yaml, .
Scope ""
. -"", scope . :
- , inventory group_vars.
- play, play. ( , "play" β , ).
- task, .
- , . ( β ).
include_role
, include_role ( ), β include_role. , include .
Scope β scope scope:
---
- hosts: localhost
gather_facts: false
vars:
foo: 2
tasks:
- name: Case1
debug: var=foo
vars:
foo: 1
- name: Case2
debug: var=foo
play, foo=1, scope , foo scope play, foo 2. ( precedence ). "" "", ( ). "" β include_vars
, set_fact
, register
..
Variable precedence
. include_role
-"". , - scope, , . variable precedence ( β , ).
: , . , , http_port: 8088
, , http_port: 80
. -e
.. , , group_vars/
.
, , foo
inventory.yaml # [all:vars] foo=inventory
group_vars/all.yaml # foo: g_v_a
playbook.yaml
playbook.yaml
- debug: var=foo
?
β¦ , variable precedence , , group_vars .
host_group_vars
( ) host_group_vars. , group vars host vars. , . group_vars/all.yaml , . playbook, playbook.
, , group_vars . , variable precedence (playbook), group_vars .
. group_vars , . , . , , , .. .
group_vars/other, group_vars/all, host_vars .. , .
, , β .
. precedence WTF, : ( ), hostvars .
- role/defaults β . , . pre/post tasks.
- group_vars/all β all
- group_vars/other_groups
- host_vars
- gather_facts: true (host_facts)
- play
- block
- task
- set_fact/register.
set_fact
, (.. play). - -e .
, ( ). "". .
: group_vars/all
group_vars/other_group.yaml
.
,
, . include' (, , ), , import include', add_host
, .. set_fact . , . jinja, . group_host_vars () play. , , .
Keep it clean, keep it simple.