From 44510448b07c16bbf7767076e2392f47dcb7e824 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Thu, 6 Sep 2018 11:26:58 -0400 Subject: [PATCH] prefer ansible_facts namespace and dict notation (#44980) * prefer ansible_facts namespace and dict notation * fixed mistranslation --- .../user_guide/playbooks_best_practices.rst | 12 +++-- .../rst/user_guide/playbooks_blocks.rst | 2 +- .../rst/user_guide/playbooks_conditionals.rst | 46 +++++++++---------- .../rst/user_guide/playbooks_reuse_roles.rst | 6 +-- .../rst/user_guide/playbooks_tests.rst | 10 ++-- .../rst/user_guide/playbooks_variables.rst | 30 +++++++----- 6 files changed, 57 insertions(+), 49 deletions(-) diff --git a/docs/docsite/rst/user_guide/playbooks_best_practices.rst b/docs/docsite/rst/user_guide/playbooks_best_practices.rst index 0d21a3372b..70a45e30ae 100644 --- a/docs/docsite/rst/user_guide/playbooks_best_practices.rst +++ b/docs/docsite/rst/user_guide/playbooks_best_practices.rst @@ -394,11 +394,12 @@ This makes a dynamic group of hosts matching certain criteria, even if that grou --- - # talk to all hosts just so we can learn about them - - hosts: all + - name: talk to all hosts just so we can learn about them + hosts: all tasks: - - group_by: - key: os_{{ ansible_distribution }} + - name: Classify hosts depending on their OS distribution + group_by: + key: os_{{ ansible_facts['distribution'] }} # now just on the CentOS hosts... @@ -426,7 +427,8 @@ Alternatively, if only variables are needed:: - hosts: all tasks: - - include_vars: "os_{{ ansible_distribution }}.yml" + - name: Set OS distribution dependant variables + include_vars: "os_{{ ansible_facts['distribution'] }}.yml" - debug: var: asdf diff --git a/docs/docsite/rst/user_guide/playbooks_blocks.rst b/docs/docsite/rst/user_guide/playbooks_blocks.rst index 8fa97ef8f4..51d34df2a8 100644 --- a/docs/docsite/rst/user_guide/playbooks_blocks.rst +++ b/docs/docsite/rst/user_guide/playbooks_blocks.rst @@ -25,7 +25,7 @@ Blocks allow for logical grouping of tasks and in play error handling. Most of w name: bar state: started enabled: True - when: ansible_distribution == 'CentOS' + when: ansible_facts['distribution'] == 'CentOS' become: true become_user: root diff --git a/docs/docsite/rst/user_guide/playbooks_conditionals.rst b/docs/docsite/rst/user_guide/playbooks_conditionals.rst index fc6efc3d39..72fb742bf5 100644 --- a/docs/docsite/rst/user_guide/playbooks_conditionals.rst +++ b/docs/docsite/rst/user_guide/playbooks_conditionals.rst @@ -28,17 +28,16 @@ It's actually pretty simple:: tasks: - name: "shut down Debian flavored systems" command: /sbin/shutdown -t now - when: ansible_os_family == "Debian" - # note that Ansible facts and vars like ansible_os_family can be used - # directly in conditionals without double curly braces + when: ansible_facts['os_family'] == "Debian" + # note that all variables can be directly in conditionals without double curly braces You can also use parentheses to group conditions:: tasks: - name: "shut down CentOS 6 and Debian 7 systems" command: /sbin/shutdown -t now - when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or - (ansible_distribution == "Debian" and ansible_distribution_major_version == "7") + when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or + (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7") Multiple conditions that all need to be true (a logical 'and') can also be specified as a list:: @@ -46,8 +45,8 @@ Multiple conditions that all need to be true (a logical 'and') can also be speci - name: "shut down CentOS 6 systems" command: /sbin/shutdown -t now when: - - ansible_distribution == "CentOS" - - ansible_distribution_major_version == "6" + - ansible_facts['distribution'] == "CentOS" + - ansible_facts['distribution_major_version'] == "6" A number of Jinja2 "tests" and "filters" can also be used in when statements, some of which are unique and provided by Ansible. Suppose we want to ignore the error of one statement and then @@ -72,17 +71,18 @@ decide to do something conditionally based on success or failure:: .. note:: both `success` and `succeeded` work (`fail`/`failed`, etc). -As a reminder, to see what facts are available on a particular system, you can do the following:: +To see what facts are available on a particular system, you can do the following in a playbook:: + + - debug: var=ansible_facts - ansible hostname.example.com -m setup Tip: Sometimes you'll get back a variable that's a string and you'll want to do a math operation comparison on it. You can do this like so:: tasks: - shell: echo "only on Red Hat 6, derivatives, and later" - when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6 + when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6 -.. note:: the above example requires the lsb_release package on the target host in order to return the ansible_lsb.major_release fact. +.. note:: the above example requires the lsb_release package on the target host in order to return the 'lsb major_release' fact. Variables defined in the playbooks or inventory can also be used. An example may be the execution of a task based on a variable's boolean value:: @@ -170,7 +170,7 @@ Or with a role:: - hosts: webservers roles: - role: debian_stock_config - when: ansible_os_family == 'Debian' + when: ansible_facts['os_family'] == 'Debian' You will note a lot of 'skipped' output by default in Ansible when using this approach on systems that don't match the criteria. In many cases the ``group_by`` module (see :doc:`modules`) can be a more streamlined way to accomplish the same thing; see @@ -224,13 +224,13 @@ but it is easily handled with a minimum of syntax in an Ansible Playbook:: remote_user: root vars_files: - "vars/common.yml" - - [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ] + - [ "vars/{{ ansible_facts['os_family'] }}.yml", "vars/os_defaults.yml" ] tasks: - name: make sure apache is started service: name={{ apache }} state=started .. note:: - The variable 'ansible_os_family' is being interpolated into + The variable "ansible_facts['os_family']" is being interpolated into the list of filenames being defined for vars_files. As a reminder, the various YAML files contain just keys and values:: @@ -267,7 +267,7 @@ The following example shows how to template out a configuration file that was ve loop: "{{ query('first_found', { 'files': myfiles, 'paths': mypaths}) }}" vars: myfiles: - - "{{ansible_distribution}}.conf" + - "{{ansible_facts['distribution']}}.conf" - default.conf mypaths: ['search_location_one/somedir/', '/opt/other_location/somedir/'] @@ -338,10 +338,10 @@ The following Facts are frequently used in Conditionals - see above for examples .. _ansible_distribution: -ansible_distribution --------------------- +ansible_facts['distribution'] +----------------------------- -Possible values:: +Possible values (sample, not complete list):: Alpine Altlinux @@ -366,17 +366,17 @@ Possible values:: .. _ansible_distribution_major_version: -ansible_distribution_major_version ----------------------------------- +ansible_facts['distribution_major_version'] +------------------------------------------- This will be the major version of the operating system. For example, the value will be `16` for Ubuntu 16.04. .. _ansible_os_family: -ansible_os_family ------------------ +ansible_facts['os_family'] +-------------------------- -Possible values:: +Possible values (sample, not complete list):: AIX Alpine diff --git a/docs/docsite/rst/user_guide/playbooks_reuse_roles.rst b/docs/docsite/rst/user_guide/playbooks_reuse_roles.rst index 404f563bc3..c143bc8798 100644 --- a/docs/docsite/rst/user_guide/playbooks_reuse_roles.rst +++ b/docs/docsite/rst/user_guide/playbooks_reuse_roles.rst @@ -46,9 +46,9 @@ Other YAML files may be included in certain directories. For example, it is comm # roles/example/tasks/main.yml - name: added in 2.4, previously you used 'include' import_tasks: redhat.yml - when: ansible_os_family|lower == 'redhat' + when: ansible_facts['os_family']|lower == 'redhat' - import_tasks: debian.yml - when: ansible_os_family|lower == 'debian' + when: ansible_facts['os_family']|lower == 'debian' # roles/example/tasks/redhat.yml - yum: @@ -163,7 +163,7 @@ You can conditionally import a role and execute it's tasks:: tasks: - include_role: name: some_role - when: "ansible_os_family == 'RedHat'" + when: "ansible_facts['os_family'] == 'RedHat'" diff --git a/docs/docsite/rst/user_guide/playbooks_tests.rst b/docs/docsite/rst/user_guide/playbooks_tests.rst index 83be5fe664..5163fc2067 100644 --- a/docs/docsite/rst/user_guide/playbooks_tests.rst +++ b/docs/docsite/rst/user_guide/playbooks_tests.rst @@ -43,7 +43,7 @@ To match strings against a substring or a regex, use the "match" or "search" fil url: "http://example.com/users/foo/resources/bar" tasks: - - debug: + - debug: msg: "matched pattern 1" when: url is match("http://example.com/users/.*/resources/.*") @@ -67,14 +67,14 @@ Version Comparison .. note:: In 2.5 ``version_compare`` was renamed to ``version`` -To compare a version number, such as checking if the ``ansible_distribution_version`` +To compare a version number, such as checking if the ``ansible_facts['distribution_version']`` version is greater than or equal to '12.04', you can use the ``version`` test. -The ``version`` test can also be used to evaluate the ``ansible_distribution_version``:: +The ``version`` test can also be used to evaluate the ``ansible_facts['distribution_version']``:: - {{ ansible_distribution_version is version('12.04', '>=') }} + {{ ansible_facts['distribution_version'] is version('12.04', '>=') }} -If ``ansible_distribution_version`` is greater than or equal to 12.04, this test returns True, otherwise False. +If ``ansible_facts['distribution_version']`` is greater than or equal to 12.04, this test returns True, otherwise False. The ``version`` test accepts the following operators:: diff --git a/docs/docsite/rst/user_guide/playbooks_variables.rst b/docs/docsite/rst/user_guide/playbooks_variables.rst index 4328e04765..c1433d0ed0 100644 --- a/docs/docsite/rst/user_guide/playbooks_variables.rst +++ b/docs/docsite/rst/user_guide/playbooks_variables.rst @@ -161,11 +161,17 @@ Information discovered from systems: Facts There are other places where variables can come from, but these are a type of variable that are discovered, not set by the user. -Facts are information derived from speaking with your remote systems. +Facts are information derived from speaking with your remote systems. You can find a complete set under the ``ansible_facts`` variable, +most facts are also 'injected' as top level variables preserving the ``ansible_`` prefix, but some are dropped due to conflicts. +This can be disabled via the :ref:INJECT_FACTS_AS_VARS setting. An example of this might be the IP address of the remote host, or what the operating system is. -To see what information is available, try the following:: +To see what information is available, try the following in a play:: + + - debug: var=ansible_facts + +To see the 'raw' information as gathered:: ansible hostname -m setup @@ -406,15 +412,15 @@ This will return a large amount of variable data, which may look like this, as t In the above the model of the first harddrive may be referenced in a template or playbook as:: - {{ ansible_devices.sda.model }} + {{ ansible_facts['devices']['sda']['model'] }} Similarly, the hostname as the system reports it is:: - {{ ansible_nodename }} + {{ ansible_facts['nodename'] }} and the unqualified hostname shows the string before the first period(.):: - {{ ansible_hostname }} + {{ ansible_facts['hostname'] }} Facts are frequently used in conditionals (see :doc:`playbooks_conditionals`) and also in templates. @@ -475,11 +481,11 @@ And you will see the following fact added:: And this data can be accessed in a ``template/playbook`` as:: - {{ ansible_local.preferences.general.asdf }} + {{ ansible_local['preferences']['general']['asdf'] }} The local namespace prevents any user supplied fact from overriding system facts or variables defined elsewhere in the playbook. -.. 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. +.. 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. .. _ConfigParser: https://docs.python.org/2/library/configparser.html .. _optionxform: https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.optionxform @@ -526,7 +532,7 @@ Fact Caching As shown elsewhere in the docs, it is possible for one server to reference variables about another, like so:: - {{ hostvars['asdf.example.com']['ansible_os_family'] }} + {{ hostvars['asdf.example.com']['ansible_facts']['os_family'] }} With "Fact Caching" disabled, in order to do this, Ansible must have already talked to 'asdf.example.com' in the current play, or another play up higher in the playbook. This is the default configuration of ansible. @@ -615,11 +621,11 @@ We already described facts a little higher up in the documentation. Some provided facts, like networking information, are made available as nested data structures. To access them a simple ``{{ foo }}`` is not sufficient, but it is still easy to do. Here's how we get an IP address:: - {{ ansible_eth0["ipv4"]["address"] }} + {{ ansible_facts["eth0"]["ipv4"]["address"] }} OR alternatively:: - {{ ansible_eth0.ipv4.address }} + {{ ansible_facts.eth0.ipv4.address }} Similarly, this is how we access the first element of an array:: @@ -641,7 +647,7 @@ or set of playbooks, you can still get the variables, but you will not be able t If your database server wants to use the value of a 'fact' from another node, or an inventory variable assigned to another node, it's easy to do so within a template or even an action line:: - {{ hostvars['test.example.com']['ansible_distribution'] }} + {{ hostvars['test.example.com']['ansible_facts']['distribution'] }} Additionally, ``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 @@ -666,7 +672,7 @@ A frequently used idiom is walking a group to find all IP addresses in that grou .. code-block:: jinja {% for host in groups['app_servers'] %} - {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }} + {{ hostvars[host]['ansible_facts']['eth0']['ipv4']['address'] }} {% endfor %} An example of this could include pointing a frontend proxy server to all of the app servers, setting up the correct firewall rules between servers, etc.