1.. _playbooks_variables:
2
3***************
4Using Variables
5***************
6
7.. contents::
8   :local:
9
10While automation exists to make it easier to make things repeatable, all systems are not exactly alike; some may require configuration that is slightly different from others. In some instances, the observed behavior or state of one system might influence how you configure other systems. For example, you might need to find out the IP address of a system and use it as a configuration value on another system.
11
12Ansible uses *variables* to help deal with differences between systems.
13
14To understand variables you'll also want to read :ref:`playbooks_conditionals` and :ref:`playbooks_loops`.
15Useful things like the **group_by** module
16and the ``when`` conditional can also be used with variables, and to help manage differences between systems.
17
18The `ansible-examples github repository <https://github.com/ansible/ansible-examples>`_ contains many examples of how variables are used in Ansible.
19
20.. _valid_variable_names:
21
22Creating valid variable names
23=============================
24
25Before you start using variables, it's important to know what are valid variable names.
26
27Variable names should be letters, numbers, and underscores.  Variables should always start with a letter.
28
29``foo_port`` is a great variable.  ``foo5`` is fine too.
30
31``foo-port``, ``foo port``, ``foo.port`` and ``12`` are not valid variable names.
32
33YAML also supports dictionaries which map keys to values.  For instance::
34
35  foo:
36    field1: one
37    field2: two
38
39You can then reference a specific field in the dictionary using either bracket
40notation or dot notation::
41
42  foo['field1']
43  foo.field1
44
45These will both reference the same value ("one").  However, if you choose to
46use dot notation be aware that some keys can cause problems because they
47collide with attributes and methods of python dictionaries.  You should use
48bracket notation instead of dot notation if you use keys which start and end
49with two underscores (Those are reserved for special meanings in python) or
50are any of the known public attributes:
51
52``add``, ``append``, ``as_integer_ratio``, ``bit_length``, ``capitalize``, ``center``, ``clear``, ``conjugate``, ``copy``, ``count``, ``decode``, ``denominator``, ``difference``, ``difference_update``, ``discard``, ``encode``, ``endswith``, ``expandtabs``, ``extend``, ``find``, ``format``, ``fromhex``, ``fromkeys``, ``get``, ``has_key``, ``hex``, ``imag``, ``index``, ``insert``, ``intersection``, ``intersection_update``, ``isalnum``, ``isalpha``, ``isdecimal``, ``isdigit``, ``isdisjoint``, ``is_integer``, ``islower``, ``isnumeric``, ``isspace``, ``issubset``, ``issuperset``, ``istitle``, ``isupper``, ``items``, ``iteritems``, ``iterkeys``, ``itervalues``, ``join``, ``keys``, ``ljust``, ``lower``, ``lstrip``, ``numerator``, ``partition``, ``pop``, ``popitem``, ``real``, ``remove``, ``replace``, ``reverse``, ``rfind``, ``rindex``, ``rjust``, ``rpartition``, ``rsplit``, ``rstrip``, ``setdefault``, ``sort``, ``split``, ``splitlines``, ``startswith``, ``strip``, ``swapcase``, ``symmetric_difference``, ``symmetric_difference_update``, ``title``, ``translate``, ``union``, ``update``, ``upper``, ``values``, ``viewitems``, ``viewkeys``, ``viewvalues``, ``zfill``.
53
54.. _variables_in_inventory:
55
56Defining variables in inventory
57===============================
58
59Often you'll want to set variables for an individual host, or for a group of hosts in your inventory. For instance, machines in Boston
60may all use 'boston.ntp.example.com' as an NTP server. The :ref:`intro_inventory` page has details on setting :ref:`host_variables` and :ref:`group_variables` in inventory.
61
62.. _playbook_variables:
63
64Defining variables in a playbook
65================================
66
67You can define variables directly in a playbook::
68
69   - hosts: webservers
70     vars:
71       http_port: 80
72
73This can be nice as it's right there when you are reading the playbook.
74
75.. _included_variables:
76
77Defining variables in included files and roles
78==============================================
79
80As described in :ref:`playbooks_reuse_roles`, variables can also be included in the playbook via include files, which may or may
81not be part of an Ansible Role.  Usage of roles is preferred as it provides a nice organizational system.
82
83.. _about_jinja2:
84
85Using variables with Jinja2
86===========================
87
88Once you've defined variables, you can use them in your playbooks using the Jinja2 templating system.  Here's a simple Jinja2 template::
89
90    My amp goes to {{ max_amp_value }}
91
92This expression provides the most basic form of variable substitution.
93
94You can use the same syntax in playbooks. For example::
95
96    template: src=foo.cfg.j2 dest={{ remote_install_path }}/foo.cfg
97
98Here the variable defines the location of a file, which can vary from one system to another.
99
100Inside a template you automatically have access to all variables that are in scope for a host.  Actually
101it's more than that -- you can also read variables about other hosts.  We'll show how to do that in a bit.
102
103.. note:: ansible allows Jinja2 loops and conditionals in templates, but in playbooks, we do not use them.  Ansible
104   playbooks are pure machine-parseable YAML.  This is a rather important feature as it means it is possible to code-generate
105   pieces of files, or to have other ecosystem tools read Ansible files.  Not everyone will need this but it can unlock
106   possibilities.
107
108.. seealso::
109
110    :ref:`playbooks_templating`
111        More information about Jinja2 templating
112
113.. _jinja2_filters:
114
115Transforming variables with Jinja2 filters
116==========================================
117
118Jinja2 filters let you transform the value of a variable within a template expression. For example, the ``capitalize`` filter capitalizes any value passed to it; the ``to_yaml`` and ``to_json`` filters change the format of your variable values. Jinja2 includes many `built-in filters <http://jinja.pocoo.org/docs/templates/#builtin-filters>`_ and Ansible supplies :ref:`many more filters <playbooks_filters>`.
119
120.. _yaml_gotchas:
121
122Hey wait, a YAML gotcha
123=======================
124
125YAML syntax requires that if you start a value with ``{{ foo }}`` you quote the whole line, since it wants to be
126sure you aren't trying to start a YAML dictionary.  This is covered on the :ref:`yaml_syntax` documentation.
127
128This won't work::
129
130    - hosts: app_servers
131      vars:
132          app_path: {{ base_path }}/22
133
134Do it like this and you'll be fine::
135
136    - hosts: app_servers
137      vars:
138           app_path: "{{ base_path }}/22"
139
140.. _vars_and_facts:
141
142Variables discovered from systems: Facts
143========================================
144
145There are other places where variables can come from, but these are a type of variable that are discovered, not set by the user.
146
147Facts are information derived from speaking with your remote systems. You can find a complete set under the ``ansible_facts`` variable,
148most facts are also 'injected' as top level variables preserving the ``ansible_`` prefix, but some are dropped due to conflicts.
149This can be disabled via the :ref:`INJECT_FACTS_AS_VARS` setting.
150
151An example of this might be the IP address of the remote host, or what the operating system is.
152
153To see what information is available, try the following in a play::
154
155    - debug: var=ansible_facts
156
157To see the 'raw' information as gathered::
158
159    ansible hostname -m setup
160
161This will return a large amount of variable data, which may look like this on Ansible 2.7:
162
163.. code-block:: json
164
165    {
166        "ansible_all_ipv4_addresses": [
167            "REDACTED IP ADDRESS"
168        ],
169        "ansible_all_ipv6_addresses": [
170            "REDACTED IPV6 ADDRESS"
171        ],
172        "ansible_apparmor": {
173            "status": "disabled"
174        },
175        "ansible_architecture": "x86_64",
176        "ansible_bios_date": "11/28/2013",
177        "ansible_bios_version": "4.1.5",
178        "ansible_cmdline": {
179            "BOOT_IMAGE": "/boot/vmlinuz-3.10.0-862.14.4.el7.x86_64",
180            "console": "ttyS0,115200",
181            "no_timer_check": true,
182            "nofb": true,
183            "nomodeset": true,
184            "ro": true,
185            "root": "LABEL=cloudimg-rootfs",
186            "vga": "normal"
187        },
188        "ansible_date_time": {
189            "date": "2018-10-25",
190            "day": "25",
191            "epoch": "1540469324",
192            "hour": "12",
193            "iso8601": "2018-10-25T12:08:44Z",
194            "iso8601_basic": "20181025T120844109754",
195            "iso8601_basic_short": "20181025T120844",
196            "iso8601_micro": "2018-10-25T12:08:44.109968Z",
197            "minute": "08",
198            "month": "10",
199            "second": "44",
200            "time": "12:08:44",
201            "tz": "UTC",
202            "tz_offset": "+0000",
203            "weekday": "Thursday",
204            "weekday_number": "4",
205            "weeknumber": "43",
206            "year": "2018"
207        },
208        "ansible_default_ipv4": {
209            "address": "REDACTED",
210            "alias": "eth0",
211            "broadcast": "REDACTED",
212            "gateway": "REDACTED",
213            "interface": "eth0",
214            "macaddress": "REDACTED",
215            "mtu": 1500,
216            "netmask": "255.255.255.0",
217            "network": "REDACTED",
218            "type": "ether"
219        },
220        "ansible_default_ipv6": {},
221        "ansible_device_links": {
222            "ids": {},
223            "labels": {
224                "xvda1": [
225                    "cloudimg-rootfs"
226                ],
227                "xvdd": [
228                    "config-2"
229                ]
230            },
231            "masters": {},
232            "uuids": {
233                "xvda1": [
234                    "cac81d61-d0f8-4b47-84aa-b48798239164"
235                ],
236                "xvdd": [
237                    "2018-10-25-12-05-57-00"
238                ]
239            }
240        },
241        "ansible_devices": {
242            "xvda": {
243                "holders": [],
244                "host": "",
245                "links": {
246                    "ids": [],
247                    "labels": [],
248                    "masters": [],
249                    "uuids": []
250                },
251                "model": null,
252                "partitions": {
253                    "xvda1": {
254                        "holders": [],
255                        "links": {
256                            "ids": [],
257                            "labels": [
258                                "cloudimg-rootfs"
259                            ],
260                            "masters": [],
261                            "uuids": [
262                                "cac81d61-d0f8-4b47-84aa-b48798239164"
263                            ]
264                        },
265                        "sectors": "83883999",
266                        "sectorsize": 512,
267                        "size": "40.00 GB",
268                        "start": "2048",
269                        "uuid": "cac81d61-d0f8-4b47-84aa-b48798239164"
270                    }
271                },
272                "removable": "0",
273                "rotational": "0",
274                "sas_address": null,
275                "sas_device_handle": null,
276                "scheduler_mode": "deadline",
277                "sectors": "83886080",
278                "sectorsize": "512",
279                "size": "40.00 GB",
280                "support_discard": "0",
281                "vendor": null,
282                "virtual": 1
283            },
284            "xvdd": {
285                "holders": [],
286                "host": "",
287                "links": {
288                    "ids": [],
289                    "labels": [
290                        "config-2"
291                    ],
292                    "masters": [],
293                    "uuids": [
294                        "2018-10-25-12-05-57-00"
295                    ]
296                },
297                "model": null,
298                "partitions": {},
299                "removable": "0",
300                "rotational": "0",
301                "sas_address": null,
302                "sas_device_handle": null,
303                "scheduler_mode": "deadline",
304                "sectors": "131072",
305                "sectorsize": "512",
306                "size": "64.00 MB",
307                "support_discard": "0",
308                "vendor": null,
309                "virtual": 1
310            },
311            "xvde": {
312                "holders": [],
313                "host": "",
314                "links": {
315                    "ids": [],
316                    "labels": [],
317                    "masters": [],
318                    "uuids": []
319                },
320                "model": null,
321                "partitions": {
322                    "xvde1": {
323                        "holders": [],
324                        "links": {
325                            "ids": [],
326                            "labels": [],
327                            "masters": [],
328                            "uuids": []
329                        },
330                        "sectors": "167770112",
331                        "sectorsize": 512,
332                        "size": "80.00 GB",
333                        "start": "2048",
334                        "uuid": null
335                    }
336                },
337                "removable": "0",
338                "rotational": "0",
339                "sas_address": null,
340                "sas_device_handle": null,
341                "scheduler_mode": "deadline",
342                "sectors": "167772160",
343                "sectorsize": "512",
344                "size": "80.00 GB",
345                "support_discard": "0",
346                "vendor": null,
347                "virtual": 1
348            }
349        },
350        "ansible_distribution": "CentOS",
351        "ansible_distribution_file_parsed": true,
352        "ansible_distribution_file_path": "/etc/redhat-release",
353        "ansible_distribution_file_variety": "RedHat",
354        "ansible_distribution_major_version": "7",
355        "ansible_distribution_release": "Core",
356        "ansible_distribution_version": "7.5.1804",
357        "ansible_dns": {
358            "nameservers": [
359                "127.0.0.1"
360            ]
361        },
362        "ansible_domain": "",
363        "ansible_effective_group_id": 1000,
364        "ansible_effective_user_id": 1000,
365        "ansible_env": {
366            "HOME": "/home/zuul",
367            "LANG": "en_US.UTF-8",
368            "LESSOPEN": "||/usr/bin/lesspipe.sh %s",
369            "LOGNAME": "zuul",
370            "MAIL": "/var/mail/zuul",
371            "PATH": "/usr/local/bin:/usr/bin",
372            "PWD": "/home/zuul",
373            "SELINUX_LEVEL_REQUESTED": "",
374            "SELINUX_ROLE_REQUESTED": "",
375            "SELINUX_USE_CURRENT_RANGE": "",
376            "SHELL": "/bin/bash",
377            "SHLVL": "2",
378            "SSH_CLIENT": "REDACTED 55672 22",
379            "SSH_CONNECTION": "REDACTED 55672 REDACTED 22",
380            "USER": "zuul",
381            "XDG_RUNTIME_DIR": "/run/user/1000",
382            "XDG_SESSION_ID": "1",
383            "_": "/usr/bin/python2"
384        },
385        "ansible_eth0": {
386            "active": true,
387            "device": "eth0",
388            "ipv4": {
389                "address": "REDACTED",
390                "broadcast": "REDACTED",
391                "netmask": "255.255.255.0",
392                "network": "REDACTED"
393            },
394            "ipv6": [
395                {
396                    "address": "REDACTED",
397                    "prefix": "64",
398                    "scope": "link"
399                }
400            ],
401            "macaddress": "REDACTED",
402            "module": "xen_netfront",
403            "mtu": 1500,
404            "pciid": "vif-0",
405            "promisc": false,
406            "type": "ether"
407        },
408        "ansible_eth1": {
409            "active": true,
410            "device": "eth1",
411            "ipv4": {
412                "address": "REDACTED",
413                "broadcast": "REDACTED",
414                "netmask": "255.255.224.0",
415                "network": "REDACTED"
416            },
417            "ipv6": [
418                {
419                    "address": "REDACTED",
420                    "prefix": "64",
421                    "scope": "link"
422                }
423            ],
424            "macaddress": "REDACTED",
425            "module": "xen_netfront",
426            "mtu": 1500,
427            "pciid": "vif-1",
428            "promisc": false,
429            "type": "ether"
430        },
431        "ansible_fips": false,
432        "ansible_form_factor": "Other",
433        "ansible_fqdn": "centos-7-rax-dfw-0003427354",
434        "ansible_hostname": "centos-7-rax-dfw-0003427354",
435        "ansible_interfaces": [
436            "lo",
437            "eth1",
438            "eth0"
439        ],
440        "ansible_is_chroot": false,
441        "ansible_kernel": "3.10.0-862.14.4.el7.x86_64",
442        "ansible_lo": {
443            "active": true,
444            "device": "lo",
445            "ipv4": {
446                "address": "127.0.0.1",
447                "broadcast": "host",
448                "netmask": "255.0.0.0",
449                "network": "127.0.0.0"
450            },
451            "ipv6": [
452                {
453                    "address": "::1",
454                    "prefix": "128",
455                    "scope": "host"
456                }
457            ],
458            "mtu": 65536,
459            "promisc": false,
460            "type": "loopback"
461        },
462        "ansible_local": {},
463        "ansible_lsb": {
464            "codename": "Core",
465            "description": "CentOS Linux release 7.5.1804 (Core)",
466            "id": "CentOS",
467            "major_release": "7",
468            "release": "7.5.1804"
469        },
470        "ansible_machine": "x86_64",
471        "ansible_machine_id": "2db133253c984c82aef2fafcce6f2bed",
472        "ansible_memfree_mb": 7709,
473        "ansible_memory_mb": {
474            "nocache": {
475                "free": 7804,
476                "used": 173
477            },
478            "real": {
479                "free": 7709,
480                "total": 7977,
481                "used": 268
482            },
483            "swap": {
484                "cached": 0,
485                "free": 0,
486                "total": 0,
487                "used": 0
488            }
489        },
490        "ansible_memtotal_mb": 7977,
491        "ansible_mounts": [
492            {
493                "block_available": 7220998,
494                "block_size": 4096,
495                "block_total": 9817227,
496                "block_used": 2596229,
497                "device": "/dev/xvda1",
498                "fstype": "ext4",
499                "inode_available": 10052341,
500                "inode_total": 10419200,
501                "inode_used": 366859,
502                "mount": "/",
503                "options": "rw,seclabel,relatime,data=ordered",
504                "size_available": 29577207808,
505                "size_total": 40211361792,
506                "uuid": "cac81d61-d0f8-4b47-84aa-b48798239164"
507            },
508            {
509                "block_available": 0,
510                "block_size": 2048,
511                "block_total": 252,
512                "block_used": 252,
513                "device": "/dev/xvdd",
514                "fstype": "iso9660",
515                "inode_available": 0,
516                "inode_total": 0,
517                "inode_used": 0,
518                "mount": "/mnt/config",
519                "options": "ro,relatime,mode=0700",
520                "size_available": 0,
521                "size_total": 516096,
522                "uuid": "2018-10-25-12-05-57-00"
523            }
524        ],
525        "ansible_nodename": "centos-7-rax-dfw-0003427354",
526        "ansible_os_family": "RedHat",
527        "ansible_pkg_mgr": "yum",
528        "ansible_processor": [
529            "0",
530            "GenuineIntel",
531            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
532            "1",
533            "GenuineIntel",
534            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
535            "2",
536            "GenuineIntel",
537            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
538            "3",
539            "GenuineIntel",
540            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
541            "4",
542            "GenuineIntel",
543            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
544            "5",
545            "GenuineIntel",
546            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
547            "6",
548            "GenuineIntel",
549            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz",
550            "7",
551            "GenuineIntel",
552            "Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz"
553        ],
554        "ansible_processor_cores": 8,
555        "ansible_processor_count": 8,
556        "ansible_processor_threads_per_core": 1,
557        "ansible_processor_vcpus": 8,
558        "ansible_product_name": "HVM domU",
559        "ansible_product_serial": "REDACTED",
560        "ansible_product_uuid": "REDACTED",
561        "ansible_product_version": "4.1.5",
562        "ansible_python": {
563            "executable": "/usr/bin/python2",
564            "has_sslcontext": true,
565            "type": "CPython",
566            "version": {
567                "major": 2,
568                "micro": 5,
569                "minor": 7,
570                "releaselevel": "final",
571                "serial": 0
572            },
573            "version_info": [
574                2,
575                7,
576                5,
577                "final",
578                0
579            ]
580        },
581        "ansible_python_version": "2.7.5",
582        "ansible_real_group_id": 1000,
583        "ansible_real_user_id": 1000,
584        "ansible_selinux": {
585            "config_mode": "enforcing",
586            "mode": "enforcing",
587            "policyvers": 31,
588            "status": "enabled",
589            "type": "targeted"
590        },
591        "ansible_selinux_python_present": true,
592        "ansible_service_mgr": "systemd",
593        "ansible_ssh_host_key_ecdsa_public": "REDACTED KEY VALUE",
594        "ansible_ssh_host_key_ed25519_public": "REDACTED KEY VALUE",
595        "ansible_ssh_host_key_rsa_public": "REDACTED KEY VALUE",
596        "ansible_swapfree_mb": 0,
597        "ansible_swaptotal_mb": 0,
598        "ansible_system": "Linux",
599        "ansible_system_capabilities": [
600            ""
601        ],
602        "ansible_system_capabilities_enforced": "True",
603        "ansible_system_vendor": "Xen",
604        "ansible_uptime_seconds": 151,
605        "ansible_user_dir": "/home/zuul",
606        "ansible_user_gecos": "",
607        "ansible_user_gid": 1000,
608        "ansible_user_id": "zuul",
609        "ansible_user_shell": "/bin/bash",
610        "ansible_user_uid": 1000,
611        "ansible_userspace_architecture": "x86_64",
612        "ansible_userspace_bits": "64",
613        "ansible_virtualization_role": "guest",
614        "ansible_virtualization_type": "xen",
615        "gather_subset": [
616            "all"
617        ],
618        "module_setup": true
619    }
620
621In the above the model of the first disk may be referenced in a template or playbook as::
622
623    {{ ansible_facts['devices']['xvda']['model'] }}
624
625Similarly, the hostname as the system reports it is::
626
627    {{ ansible_facts['nodename'] }}
628
629Facts are frequently used in conditionals (see :ref:`playbooks_conditionals`) and also in templates.
630
631Facts can be also used to create dynamic groups of hosts that match particular criteria, see the :ref:`modules` documentation on **group_by** for details, as well as in generalized conditional statements as discussed in the :ref:`playbooks_conditionals` chapter.
632
633.. _disabling_facts:
634
635Disabling facts
636---------------
637
638If you know you don't need any fact data about your hosts, and know everything about your systems centrally, you
639can turn off fact gathering.  This has advantages in scaling Ansible in push mode with very large numbers of
640systems, mainly, or if you are using Ansible on experimental platforms.   In any play, just do this::
641
642    - hosts: whatever
643      gather_facts: no
644
645.. _local_facts:
646
647Local facts (facts.d)
648---------------------
649
650.. versionadded:: 1.3
651
652As discussed in the playbooks chapter, Ansible facts are a way of getting data about remote systems for use in playbook variables.
653
654Usually these are discovered automatically by the ``setup`` module in Ansible. Users can also write custom facts modules, as described in the API guide. However, what if you want to have a simple way to provide system or user provided data for use in Ansible variables, without writing a fact module?
655
656"Facts.d" is one mechanism for users to control some aspect of how their systems are managed.
657
658.. note:: Perhaps "local facts" is a bit of a misnomer, it means "locally supplied user values" as opposed to "centrally supplied user values", or what facts are -- "locally dynamically determined values".
659
660If a remotely managed system has an ``/usr/local/etc/ansible/facts.d`` directory, any files in this directory
661ending in ``.fact``, can be JSON, INI, or executable files returning JSON, and these can supply local facts in Ansible.
662An alternate directory can be specified using the ``fact_path`` play keyword.
663
664For example, assume ``/usr/local/etc/ansible/facts.d/preferences.fact`` contains::
665
666    [general]
667    asdf=1
668    bar=2
669
670This will produce a hash variable fact named ``general`` with ``asdf`` and ``bar`` as members.
671To validate this, run the following::
672
673    ansible <hostname> -m setup -a "filter=ansible_local"
674
675And you will see the following fact added::
676
677    "ansible_local": {
678            "preferences": {
679                "general": {
680                    "asdf" : "1",
681                    "bar"  : "2"
682                }
683            }
684     }
685
686And this data can be accessed in a ``template/playbook`` as::
687
688     {{ ansible_local['preferences']['general']['asdf'] }}
689
690The local namespace prevents any user supplied fact from overriding system facts or variables defined elsewhere in the playbook.
691
692.. note:: The key part in the key=value pairs will be converted into lowercase inside the ansible_local variable. Using the example above, if the ini file contained ``XYZ=3`` in the ``[general]`` section, then you should expect to access it as: ``{{ ansible_local['preferences']['general']['xyz'] }}`` and not ``{{ ansible_local['preferences']['general']['XYZ'] }}``. This is because Ansible uses Python's `ConfigParser`_ which passes all option names through the `optionxform`_ method and this method's default implementation converts option names to lower case.
693
694.. _ConfigParser: https://docs.python.org/2/library/configparser.html
695.. _optionxform: https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.optionxform
696
697If you have a playbook that is copying over a custom fact and then running it, making an explicit call to re-run the setup module
698can allow that fact to be used during that particular play.  Otherwise, it will be available in the next play that gathers fact information.
699Here is an example of what that might look like::
700
701  - hosts: webservers
702    tasks:
703      - name: create directory for ansible custom facts
704        file: state=directory recurse=yes path=/usr/local/etc/ansible/facts.d
705      - name: install custom ipmi fact
706        copy: src=ipmi.fact dest=/usr/local/etc/ansible/facts.d
707      - name: re-read facts after adding custom fact
708        setup: filter=ansible_local
709
710In this pattern however, you could also write a fact module as well, and may wish to consider this as an option.
711
712.. _ansible_version:
713
714Ansible version
715---------------
716
717.. versionadded:: 1.8
718
719To adapt playbook behavior to specific version of ansible, a variable ansible_version is available, with the following
720structure::
721
722    "ansible_version": {
723        "full": "2.0.0.2",
724        "major": 2,
725        "minor": 0,
726        "revision": 0,
727        "string": "2.0.0.2"
728    }
729
730.. _fact_caching:
731
732Caching Facts
733-------------
734
735.. versionadded:: 1.8
736
737As shown elsewhere in the docs, it is possible for one server to reference variables about another, like so::
738
739    {{ hostvars['asdf.example.com']['ansible_facts']['os_family'] }}
740
741With "Fact Caching" disabled, in order to do this, Ansible must have already talked to 'asdf.example.com' in the
742current play, or another play up higher in the playbook.  This is the default configuration of ansible.
743
744To avoid this, Ansible 1.8 allows the ability to save facts between playbook runs, but this feature must be manually
745enabled.  Why might this be useful?
746
747With a very large infrastructure with thousands of hosts, fact caching could be configured to run nightly. Configuration of a small set of servers could run ad-hoc or periodically throughout the day. With fact caching enabled, it would
748not be necessary to "hit" all servers to reference variables and information about them.
749
750With fact caching enabled, it is possible for machine in one group to reference variables about machines in the other group, despite the fact that they have not been communicated with in the current execution of /usr/bin/ansible-playbook.
751
752To benefit from cached facts, you will want to change the ``gathering`` setting to ``smart`` or ``explicit`` or set ``gather_facts`` to ``False`` in most plays.
753
754Currently, Ansible ships with two persistent cache plugins: redis and jsonfile.
755
756To configure fact caching using redis, enable it in ``ansible.cfg`` as follows::
757
758    [defaults]
759    gathering = smart
760    fact_caching = redis
761    fact_caching_timeout = 86400
762    # seconds
763
764To get redis up and running, perform the equivalent OS commands::
765
766    yum install redis
767    service redis start
768    pip install redis
769
770Note that the Python redis library should be installed from pip, the version packaged in EPEL is too old for use by Ansible.
771
772In current embodiments, this feature is in beta-level state and the Redis plugin does not support port or password configuration, this is expected to change in the near future.
773
774To configure fact caching using jsonfile, enable it in ``ansible.cfg`` as follows::
775
776    [defaults]
777    gathering = smart
778    fact_caching = jsonfile
779    fact_caching_connection = /path/to/cachedir
780    fact_caching_timeout = 86400
781    # seconds
782
783``fact_caching_connection`` is a local filesystem path to a writeable
784directory (ansible will attempt to create the directory if one does not exist).
785
786``fact_caching_timeout`` is the number of seconds to cache the recorded facts.
787
788.. _registered_variables:
789
790Registering variables
791=====================
792
793Another major use of variables is running a command and registering the result of that command as a variable. When you execute a task and save the return value in a variable for use in later tasks, you create a registered variable. There are more examples of this in the
794:ref:`playbooks_conditionals` chapter.
795
796For example::
797
798   - hosts: web_servers
799
800     tasks:
801
802        - shell: /usr/bin/foo
803          register: foo_result
804          ignore_errors: True
805
806        - shell: /usr/bin/bar
807          when: foo_result.rc == 5
808
809Results will vary from module to module. Each module's documentation includes a ``RETURN`` section describing that module's return values. To see the values for a particular task, run your playbook with ``-v``.
810
811Registered variables are similar to facts, with a few key differences. Like facts, registered variables are host-level variables. However, registered variables are only stored in memory. (Ansible facts are backed by whatever cache plugin you have configured.) Registered variables are only valid on the host for the rest of the current playbook run. Finally, registered variables and facts have different :ref:`precedence levels <ansible_variable_precedence>`.
812
813When you register a variable in a task with a loop, the registered variable contains a value for each item in the loop. The data structure placed in the variable during the loop will contain a ``results`` attribute, that is a list of all responses from the module. For a more in-depth example of how this works, see the :ref:`playbooks_loops` section on using register with a loop.
814
815.. note:: If a task fails or is skipped, the variable still is registered with a failure or skipped status, the only way to avoid registering a variable is using tags.
816
817.. _accessing_complex_variable_data:
818
819Accessing complex variable data
820===============================
821
822We already described facts a little higher up in the documentation.
823
824Some provided facts, like networking information, are made available as nested data structures.  To access
825them a simple ``{{ foo }}`` is not sufficient, but it is still easy to do.   Here's how we get an IP address::
826
827    {{ ansible_facts["eth0"]["ipv4"]["address"] }}
828
829OR alternatively::
830
831    {{ ansible_facts.eth0.ipv4.address }}
832
833Similarly, this is how we access the first element of an array::
834
835    {{ foo[0] }}
836
837.. _magic_variables_and_hostvars:
838
839Accessing information about other hosts with magic variables
840============================================================
841
842Whether or not you define any variables, you can access information about your hosts with the :ref:`special_variables` Ansible provides, including "magic" variables, facts, and connection variables. Magic variable names are reserved - do not set variables with these names. The variable ``environment`` is also reserved.
843
844The most commonly used magic variables are ``hostvars``, ``groups``, ``group_names``, and ``inventory_hostname``.
845
846``hostvars`` lets you access variables for another host, including facts that have been gathered about that host. You can access host variables at any point in a playbook. Even if you haven't connected to that host yet in any play in the playbook or set of playbooks, you can still get the variables, but you will not be able to see the facts.
847
848If your database server wants to use the value of a 'fact' from another node, or an inventory variable
849assigned to another node, it's easy to do so within a template or even an action line::
850
851    {{ hostvars['test.example.com']['ansible_facts']['distribution'] }}
852
853``groups`` is a list of all the groups (and hosts) in the inventory.  This can be used to enumerate all hosts within a group. For example:
854
855.. code-block:: jinja
856
857   {% for host in groups['app_servers'] %}
858      # something that applies to all app servers.
859   {% endfor %}
860
861A frequently used idiom is walking a group to find all IP addresses in that group.
862
863.. code-block:: jinja
864
865   {% for host in groups['app_servers'] %}
866      {{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }}
867   {% endfor %}
868
869You can use this idiom to point a frontend proxy server to all of the app servers, to set up the correct firewall rules between servers, etc.
870You need to make sure that the facts of those hosts have been populated before though, for example by running a play against them if the facts have not been cached recently (fact caching was added in Ansible 1.8).
871
872``group_names`` is a list (array) of all the groups the current host is in.  This can be used in templates using Jinja2 syntax to make template source files that vary based on the group membership (or role) of the host:
873
874.. code-block:: jinja
875
876   {% if 'webserver' in group_names %}
877      # some part of a configuration file that only applies to webservers
878   {% endif %}
879
880``inventory_hostname`` is the name of the hostname as configured in Ansible's inventory host file.  This can
881be useful when you've disabled fact-gathering, or you don't want to rely on the discovered hostname ``ansible_hostname``.  If you have a long FQDN, you can use ``inventory_hostname_short``, which contains the part up to the first
882period, without the rest of the domain.
883
884Other useful magic variables refer to the current play or playbook, including:
885
886.. versionadded:: 2.2
887
888``ansible_play_hosts`` is the full list of all hosts still active in the current play.
889
890.. versionadded:: 2.2
891
892``ansible_play_batch`` is available as a list of hostnames that are in scope for the current 'batch' of the play. The batch size is defined by ``serial``, when not set it is equivalent to the whole play (making it the same as ``ansible_play_hosts``).
893
894.. versionadded:: 2.3
895
896``ansible_playbook_python`` is the path to the python executable used to invoke the Ansible command line tool.
897
898These vars may be useful for filling out templates with multiple hostnames or for injecting the list into the rules for a load balancer.
899
900Also available, ``inventory_dir`` is the pathname of the directory holding Ansible's inventory host file, ``inventory_file`` is the pathname and the filename pointing to the Ansible's inventory host file.
901
902``playbook_dir`` contains the playbook base directory.
903
904We then have ``role_path`` which will return the current role's pathname (since 1.8). This will only work inside a role.
905
906And finally, ``ansible_check_mode`` (added in version 2.1), a boolean magic variable which will be set to ``True`` if you run Ansible with ``--check``.
907
908.. _variable_file_separation_details:
909
910Defining variables in files
911===========================
912
913It's a great idea to keep your playbooks under source control, but
914you may wish to make the playbook source public while keeping certain
915important variables private.  Similarly, sometimes you may just
916want to keep certain information in different files, away from
917the main playbook.
918
919You can do this by using an external variables file, or files, just like this::
920
921    ---
922
923    - hosts: all
924      remote_user: root
925      vars:
926        favcolor: blue
927      vars_files:
928        - /vars/external_vars.yml
929
930      tasks:
931
932      - name: this is just a placeholder
933        command: /bin/echo foo
934
935This removes the risk of sharing sensitive data with others when
936sharing your playbook source with them.
937
938The contents of each variables file is a simple YAML dictionary, like this::
939
940    ---
941    # in the above example, this would be vars/external_vars.yml
942    somevar: somevalue
943    password: magic
944
945.. note::
946   It's also possible to keep per-host and per-group variables in very
947   similar files, this is covered in :ref:`splitting_out_vars`.
948
949.. _passing_variables_on_the_command_line:
950
951Passing variables on the command line
952=====================================
953
954In addition to ``vars_prompt`` and ``vars_files``, it is possible to set variables at the
955command line using the ``--extra-vars`` (or ``-e``) argument.  Variables can be defined using
956a single quoted string (containing one or more variables) using one of the formats below
957
958key=value format::
959
960    ansible-playbook release.yml --extra-vars "version=1.23.45 other_variable=foo"
961
962.. note:: Values passed in using the ``key=value`` syntax are interpreted as strings.
963          Use the JSON format if you need to pass in anything that shouldn't be a string (Booleans, integers, floats, lists etc).
964
965JSON string format::
966
967    ansible-playbook release.yml --extra-vars '{"version":"1.23.45","other_variable":"foo"}'
968    ansible-playbook arcade.yml --extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'
969
970vars from a JSON or YAML file::
971
972    ansible-playbook release.yml --extra-vars "@some_file.json"
973
974This is useful for, among other things, setting the hosts group or the user for the playbook.
975
976Escaping quotes and other special characters:
977
978Ensure you're escaping quotes appropriately for both your markup (e.g. JSON), and for
979the shell you're operating in.::
980
981    ansible-playbook arcade.yml --extra-vars "{\"name\":\"Conan O\'Brien\"}"
982    ansible-playbook arcade.yml --extra-vars '{"name":"Conan O'\\\''Brien"}'
983    ansible-playbook script.yml --extra-vars "{\"dialog\":\"He said \\\"I just can\'t get enough of those single and double-quotes"\!"\\\"\"}"
984
985In these cases, it's probably best to use a JSON or YAML file containing the variable
986definitions.
987
988.. _ansible_variable_precedence:
989
990Variable precedence: Where should I put a variable?
991===================================================
992
993A lot of folks may ask about how variables override another.  Ultimately it's Ansible's philosophy that it's better
994you know where to put a variable, and then you have to think about it a lot less.
995
996Avoid defining the variable "x" in 47 places and then ask the question "which x gets used".
997Why?  Because that's not Ansible's Zen philosophy of doing things.
998
999There is only one Empire State Building. One Mona Lisa, etc.  Figure out where to define a variable, and don't make
1000it complicated.
1001
1002However, let's go ahead and get precedence out of the way!  It exists.  It's a real thing, and you might have
1003a use for it.
1004
1005If multiple variables of the same name are defined in different places, they get overwritten in a certain order.
1006
1007Here is the order of precedence from least to greatest (the last listed variables winning prioritization):
1008
1009  #. command line values (eg "-u user")
1010  #. role defaults [1]_
1011  #. inventory file or script group vars [2]_
1012  #. inventory group_vars/all [3]_
1013  #. playbook group_vars/all [3]_
1014  #. inventory group_vars/* [3]_
1015  #. playbook group_vars/* [3]_
1016  #. inventory file or script host vars [2]_
1017  #. inventory host_vars/* [3]_
1018  #. playbook host_vars/* [3]_
1019  #. host facts / cached set_facts [4]_
1020  #. play vars
1021  #. play vars_prompt
1022  #. play vars_files
1023  #. role vars (defined in role/vars/main.yml)
1024  #. block vars (only for tasks in block)
1025  #. task vars (only for the task)
1026  #. include_vars
1027  #. set_facts / registered vars
1028  #. role (and include_role) params
1029  #. include params
1030  #. extra vars (always win precedence)
1031
1032Basically, anything that goes into "role defaults" (the defaults folder inside the role) is the most malleable and easily overridden. Anything in the vars directory of the role overrides previous versions of that variable in namespace.  The idea here to follow is that the more explicit you get in scope, the more precedence it takes with command line ``-e`` extra vars always winning.  Host and/or inventory variables can win over role defaults, but not explicit includes like the vars directory or an ``include_vars`` task.
1033
1034.. rubric:: Footnotes
1035
1036.. [1] Tasks in each role will see their own role's defaults. Tasks defined outside of a role will see the last role's defaults.
1037.. [2] Variables defined in inventory file or provided by dynamic inventory.
1038.. [3] Includes vars added by 'vars plugins' as well as host_vars and group_vars which are added by the default vars plugin shipped with Ansible.
1039.. [4] When created with set_facts's cacheable option, variables will have the high precedence in the play,
1040       but will be the same as a host facts precedence when they come from the cache.
1041
1042.. note:: Within any section, redefining a var will overwrite the previous instance.
1043          If multiple groups have the same variable, the last one loaded wins.
1044          If you define a variable twice in a play's ``vars:`` section, the second one wins.
1045.. note:: The previous describes the default config ``hash_behaviour=replace``, switch to ``merge`` to only partially overwrite.
1046.. note:: Group loading follows parent/child relationships. Groups of the same 'parent/child' level are then merged following alphabetical order.
1047          This last one can be superseded by the user via ``ansible_group_priority``, which defaults to ``1`` for all groups.
1048          This variable, ``ansible_group_priority``, can only be set in the inventory source and not in group_vars/ as the variable is used in the loading of group_vars/.
1049
1050Another important thing to consider (for all versions) is that connection variables override config, command line and play/role/task specific options and keywords. See :ref:`general_precedence_rules` for more details. For example, if your inventory specifies ``ansible_user: ramon`` and you run::
1051
1052    ansible -u lola myhost
1053
1054This will still connect as ``ramon`` because the value from the variable takes priority (in this case, the variable came from the inventory, but the same would be true no matter where the variable was defined).
1055
1056For plays/tasks this is also true for ``remote_user``. Assuming the same inventory config, the following play::
1057
1058 - hosts: myhost
1059   tasks:
1060    - command: I'll connect as ramon still
1061      remote_user: lola
1062
1063will have the value of ``remote_user`` overwritten by ``ansible_user`` in the inventory.
1064
1065This is done so host-specific settings can override the general settings. These variables are normally defined per host or group in inventory,
1066but they behave like other variables.
1067
1068If you want to override the remote user globally (even over inventory) you can use extra vars. For instance, if you run::
1069
1070    ansible... -e "ansible_user=maria" -u lola
1071
1072the ``lola`` value is still ignored, but ``ansible_user=maria`` takes precedence over all other places where ``ansible_user`` (or ``remote_user``) might be set.
1073
1074A connection-specific version of a variable takes precedence over more generic
1075versions.  For example, ``ansible_ssh_user`` specified as a group_var would have
1076a higher precedence than ``ansible_user`` specified as a host_var.
1077
1078You can also override as a normal variable in a play::
1079
1080    - hosts: all
1081      vars:
1082        ansible_user: lola
1083      tasks:
1084        - command: I'll connect as lola!
1085
1086.. _variable_scopes:
1087
1088Scoping variables
1089-----------------
1090
1091You can decide where to set a variable based on the scope you want that value to have. Ansible has three main scopes:
1092
1093 * Global: this is set by config, environment variables and the command line
1094 * Play: each play and contained structures, vars entries (vars; vars_files; vars_prompt), role defaults and vars.
1095 * Host: variables directly associated to a host, like inventory, include_vars, facts or registered task outputs
1096
1097.. _variable_examples:
1098
1099Examples of where to set a variable
1100-----------------------------------
1101
1102 Let's show some examples and where you would choose to put what based on the kind of control you might want over values.
1103
1104First off, group variables are powerful.
1105
1106Site-wide defaults should be defined as a ``group_vars/all`` setting.  Group variables are generally placed alongside
1107your inventory file.  They can also be returned by a dynamic inventory script (see :ref:`intro_dynamic_inventory`) or defined
1108in things like :ref:`ansible_tower` from the UI or API::
1109
1110    ---
1111    # file: /usr/local/etc/ansible/group_vars/all
1112    # this is the site wide default
1113    ntp_server: default-time.example.com
1114
1115Regional information might be defined in a ``group_vars/region`` variable.  If this group is a child of the ``all`` group (which it is, because all groups are), it will override the group that is higher up and more general::
1116
1117    ---
1118    # file: /usr/local/etc/ansible/group_vars/boston
1119    ntp_server: boston-time.example.com
1120
1121If for some crazy reason we wanted to tell just a specific host to use a specific NTP server, it would then override the group variable!::
1122
1123    ---
1124    # file: /usr/local/etc/ansible/host_vars/xyz.boston.example.com
1125    ntp_server: override.example.com
1126
1127So that covers inventory and what you would normally set there.  It's a great place for things that deal with geography or behavior.  Since groups are frequently the entity that maps roles onto hosts, it is sometimes a shortcut to set variables on the group instead of defining them on a role.  You could go either way.
1128
1129Remember:  Child groups override parent groups, and hosts always override their groups.
1130
1131Next up: learning about role variable precedence.
1132
1133We'll pretty much assume you are using roles at this point.  You should be using roles for sure.  Roles are great.  You are using
1134roles aren't you?  Hint hint.
1135
1136If you are writing a redistributable role with reasonable defaults, put those in the ``roles/x/defaults/main.yml`` file.  This means
1137the role will bring along a default value but ANYTHING in Ansible will override it.
1138See :ref:`playbooks_reuse_roles` for more info about this::
1139
1140    ---
1141    # file: roles/x/defaults/main.yml
1142    # if not overridden in inventory or as a parameter, this is the value that will be used
1143    http_port: 80
1144
1145If you are writing a role and want to ensure the value in the role is absolutely used in that role, and is not going to be overridden
1146by inventory, you should put it in ``roles/x/vars/main.yml`` like so, and inventory values cannot override it.  ``-e`` however, still will::
1147
1148    ---
1149    # file: roles/x/vars/main.yml
1150    # this will absolutely be used in this role
1151    http_port: 80
1152
1153This is one way to plug in constants about the role that are always true.  If you are not sharing your role with others,
1154app specific behaviors like ports is fine to put in here.  But if you are sharing roles with others, putting variables in here might
1155be bad. Nobody will be able to override them with inventory, but they still can by passing a parameter to the role.
1156
1157Parameterized roles are useful.
1158
1159If you are using a role and want to override a default, pass it as a parameter to the role like so::
1160
1161    roles:
1162       - role: apache
1163         vars:
1164            http_port: 8080
1165
1166This makes it clear to the playbook reader that you've made a conscious choice to override some default in the role, or pass in some
1167configuration that the role can't assume by itself.  It also allows you to pass something site-specific that isn't really part of the
1168role you are sharing with others.
1169
1170This can often be used for things that might apply to some hosts multiple times. For example::
1171
1172    roles:
1173       - role: app_user
1174         vars:
1175            myname: Ian
1176       - role: app_user
1177         vars:
1178           myname: Terry
1179       - role: app_user
1180         vars:
1181           myname: Graham
1182       - role: app_user
1183         vars:
1184           myname: John
1185
1186In this example, the same role was invoked multiple times.  It's quite likely there was
1187no default for ``name`` supplied at all.  Ansible can warn you when variables aren't defined -- it's the default behavior in fact.
1188
1189There are a few other things that go on with roles.
1190
1191Generally speaking, variables set in one role are available to others.  This means if you have a ``roles/common/vars/main.yml`` you
1192can set variables in there and make use of them in other roles and elsewhere in your playbook::
1193
1194     roles:
1195        - role: common_settings
1196        - role: something
1197          vars:
1198            foo: 12
1199        - role: something_else
1200
1201.. note:: There are some protections in place to avoid the need to namespace variables.
1202          In the above, variables defined in common_settings are most definitely available to 'something' and 'something_else' tasks, but if
1203          "something's" guaranteed to have foo set at 12, even if somewhere deep in common settings it set foo to 20.
1204
1205So, that's precedence, explained in a more direct way.  Don't worry about precedence, just think about if your role is defining a
1206variable that is a default, or a "live" variable you definitely want to use.  Inventory lies in precedence right in the middle, and
1207if you want to forcibly override something, use ``-e``.
1208
1209If you found that a little hard to understand, take a look at the `ansible-examples <https://github.com/ansible/ansible-examples>`_ repo on GitHub for a bit more about how all of these things can work together.
1210
1211Using advanced variable syntax
1212==============================
1213
1214For information about advanced YAML syntax used to declare variables and have more control over the data placed in YAML files used by Ansible, see :ref:`playbooks_advanced_syntax`.
1215
1216.. seealso::
1217
1218   :ref:`about_playbooks`
1219       An introduction to playbooks
1220   :ref:`playbooks_conditionals`
1221       Conditional statements in playbooks
1222   :ref:`playbooks_filters`
1223       Jinja2 filters and their uses
1224   :ref:`playbooks_loops`
1225       Looping in playbooks
1226   :ref:`playbooks_reuse_roles`
1227       Playbook organization by roles
1228   :ref:`playbooks_best_practices`
1229       Best practices in playbooks
1230   :ref:`special_variables`
1231       List of special variables
1232   `User Mailing List <https://groups.google.com/group/ansible-devel>`_
1233       Have a question?  Stop by the google group!
1234   `irc.libera.chat <https://libera.chat/>`_
1235       #ansible IRC chat channel
1236