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