diff --git a/docs/docsite/rst/user_guide/playbooks_blocks.rst b/docs/docsite/rst/user_guide/playbooks_blocks.rst index 41ca7612e8b..dc5163126da 100644 --- a/docs/docsite/rst/user_guide/playbooks_blocks.rst +++ b/docs/docsite/rst/user_guide/playbooks_blocks.rst @@ -21,18 +21,20 @@ All tasks in a block inherit directives applied at the block level. Most of what tasks: - name: Install, configure, and start Apache block: - - name: install httpd and memcached - yum: + - name: Install httpd and memcached + ansible.builtin.yum: name: - httpd - memcached state: present - - name: apply the foo config template - template: + + - name: Apply the foo config template + ansible.builtin.template: src: templates/src.j2 dest: /etc/foo.conf - - name: start service bar and enable it - service: + + - name: Start service bar and enable it + ansible.builtin.service: name: bar state: started enabled: True @@ -62,14 +64,19 @@ Rescue blocks specify tasks to run when an earlier task in a block fails. This a tasks: - name: Handle the error block: - - debug: + - name: Print a message + ansible.builtin.debug: msg: 'I execute normally' - - name: i force a failure - command: /bin/false - - debug: + + - name: Force a failure + ansible.builtin.command: /bin/false + + - name: Never print this + ansible.builtin.debug: msg: 'I never execute, due to the above task failing, :-(' rescue: - - debug: + - name: Print when errors + ansible.builtin.debug: msg: 'I caught an error, can do stuff here to fix it, :-)' You can also add an ``always`` section to a block. Tasks in the ``always`` section run no matter what the task status of the previous block is. @@ -81,14 +88,19 @@ You can also add an ``always`` section to a block. Tasks in the ``always`` secti - name: Always do X block: - - debug: + - name: Print a message + ansible.builtin.debug: msg: 'I execute normally' - - name: i force a failure - command: /bin/false - - debug: + + - name: Force a failure + ansible.builtin.command: /bin/false + + - name: Never print this + ansible.builtin.debug: msg: 'I never execute :-(' always: - - debug: + - name: Always do this + ansible.builtin.debug: msg: "This always executes, :-)" Together, these elements offer complex error handling. @@ -99,26 +111,35 @@ Together, these elements offer complex error handling. - name: Attempt and graceful roll back demo block: - - debug: + - name: Print a message + ansible.builtin.debug: msg: 'I execute normally' - - name: i force a failure - command: /bin/false - - debug: + + - name: Force a failure + ansible.builtin.command: /bin/false + + - name: Never print this + ansible.builtin.debug: msg: 'I never execute, due to the above task failing, :-(' rescue: - - debug: + - name: Print when errors + ansible.builtin.debug: msg: 'I caught an error' - - name: i force a failure in middle of recovery! >:-) - command: /bin/false - - debug: + + - name: Force a failure in middle of recovery! >:-) + ansible.builtin.command: /bin/false + + - name: Never print this + ansible.builtin.debug: msg: 'I also never execute :-(' always: - - debug: + - name: Always do this + ansible.builtin.debug: msg: "This always executes" The tasks in the ``block`` execute normally. If any tasks in the block return ``failed``, the ``rescue`` section executes tasks to recover from the error. The ``always`` section runs regardless of the results of the ``block`` and ``rescue`` sections. -If an error occurs in the block and the rescue task succeeds, Ansible reverts the failed status of the original task for the run and continues to run the play as if the original task had succeeded. The rescued task is considered successful, and does not not trigger ``max_fail_percentage`` or ``any_errors_fatal`` configurations. However, Ansible still reports a failure in the playbook statistics. +If an error occurs in the block and the rescue task succeeds, Ansible reverts the failed status of the original task for the run and continues to run the play as if the original task had succeeded. The rescued task is considered successful, and does not trigger ``max_fail_percentage`` or ``any_errors_fatal`` configurations. However, Ansible still reports a failure in the playbook statistics. You can use blocks with ``flush_handlers`` in a rescue task to ensure that all handlers run even if an error occurs: @@ -129,17 +150,20 @@ You can use blocks with ``flush_handlers`` in a rescue task to ensure that all h tasks: - name: Attempt and graceful roll back demo block: - - debug: + - name: Print a message + ansible.builtin.debug: msg: 'I execute normally' changed_when: yes notify: run me even after an error - - command: /bin/false + + - name: Force a failure + ansible.builtin.command: /bin/false rescue: - - name: make sure all handlers run + - name: Make sure all handlers run meta: flush_handlers handlers: - - name: run me even after an error - debug: + - name: Run me even after an error + ansible.builtin.debug: msg: 'This handler runs even on error' diff --git a/docs/docsite/rst/user_guide/playbooks_conditionals.rst b/docs/docsite/rst/user_guide/playbooks_conditionals.rst index 0c5ce904ed3..76599cb30f3 100644 --- a/docs/docsite/rst/user_guide/playbooks_conditionals.rst +++ b/docs/docsite/rst/user_guide/playbooks_conditionals.rst @@ -26,7 +26,10 @@ The simplest conditional statement applies to a single task. Create the task, th tasks: - name: Configure SELinux to start mysql on any port - seboolean: name=mysql_connect_any state=true persistent=yes + ansible.posix.seboolean: + name: mysql_connect_any + state: true + persistent: yes when: ansible_selinux.status == "enabled" # all variables can be used directly in conditionals without double curly braces @@ -41,15 +44,17 @@ Often you want to execute or skip a task based on facts. Facts are attributes of See :ref:`commonly_used_facts` for a list of facts that frequently appear in conditional statements. Not all facts exist for all hosts. For example, the 'lsb_major_release' fact used in an example below only exists when the lsb_release package is installed on the target host. To see what facts are available on your systems, add a debug task to your playbook:: - - debug: var=ansible_facts + - name: Show facts available on the system + ansible.builtin.debug: + var: ansible_facts Here is a sample conditional based on a fact: .. code-block:: yaml tasks: - - name: shut down Debian flavored systems - command: /sbin/shutdown -t now + - name: Shut down Debian flavored systems + ansible.builtin.command: /sbin/shutdown -t now when: ansible_facts['os_family'] == "Debian" If you have multiple conditions, you can group them with parentheses: @@ -57,16 +62,16 @@ If you have multiple conditions, you can group them with parentheses: .. code-block:: yaml tasks: - - name: shut down CentOS 6 and Debian 7 systems - command: /sbin/shutdown -t now + - name: Shut down CentOS 6 and Debian 7 systems + ansible.builtin.command: /sbin/shutdown -t now when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7") You can use `logical operators `_ to combine conditions. When you have multiple conditions that all need to be true (that is, a logical ``and``), you can specify them as a list:: tasks: - - name: shut down CentOS 6 systems - command: /sbin/shutdown -t now + - name: Shut down CentOS 6 systems + ansible.builtin.command: /sbin/shutdown -t now when: - ansible_facts['distribution'] == "CentOS" - ansible_facts['distribution_major_version'] == "6" @@ -74,7 +79,7 @@ You can use `logical operators = 6 .. _conditionals_registered_vars: @@ -89,29 +94,31 @@ Often in a playbook you want to execute or skip a task based on the outcome of a You create the name of the registered variable using the ``register`` keyword. A registered variable always contains the status of the task that created it as well as any output that task generated. You can use registered variables in templates and action lines as well as in conditional ``when`` statements. You can access the string contents of the registered variable using ``variable.stdout``. For example:: - - name: test play + - name: Test play hosts: all tasks: - - shell: cat /etc/motd + - name: Register a variable + ansible.builtin.shell: cat /etc/motd register: motd_contents - - shell: echo "motd contains the word hi" + - name: Use the variable in conditional statement + ansible.builtin.shell: echo "motd contains the word hi" when: motd_contents.stdout.find('hi') != -1 You can use registered results in the loop of a task if the variable is a list. If the variable is not a list, you can convert it into a list, with either ``stdout_lines`` or with ``variable.stdout.split()``. You can also split the lines by other fields:: - - name: registered variable usage as a loop list + - name: Registered variable usage as a loop list hosts: all tasks: - - name: retrieve the list of home directories - command: ls /home + - name: Retrieve the list of home directories + ansible.builtin.command: ls /home register: home_dirs - - name: add home dirs to the backup spooler - file: + - name: Add home dirs to the backup spooler + ansible.builtin.file: path: /mnt/bkspool/{{ item }} src: /home/{{ item }} state: link @@ -127,12 +134,12 @@ The string content of a registered variable can be empty. If you want to run ano tasks: - - name: list contents of directory - command: ls mydir + - name: List contents of directory + ansible.builtin.command: ls mydir register: contents - - name: check contents for emptiness - debug: + - name: Check contents for emptiness + ansible.builtin.debug: msg: "Directory is empty" when: contents.stdout == "" @@ -141,17 +148,21 @@ Ansible always registers something in a registered variable for every host, even .. code-block:: yaml tasks: - - command: /bin/false + - name: Register a variable, ignore errors and continue + ansible.builtin.command: /bin/false register: result - ignore_errors: True + ignore_errors: true - - command: /bin/something + - name: Run only if the task that registered the "result" variable fails + ansible.builtin.command: /bin/something when: result is failed - - command: /bin/something_else + - name: Run only if the task that registered the "result" variable succeeds + ansible.builtin.command: /bin/something_else when: result is succeeded - - command: /bin/still/something_else + - name: Run only if the task that registered the "result" variable is skipped + ansible.builtin.command: /bin/still/something_else when: result is skipped .. note:: Older versions of Ansible used ``success`` and ``fail``, but ``succeeded`` and ``failed`` use the correct tense. All of these options are now valid. @@ -173,10 +184,12 @@ With the variables above, Ansible would run one of these tasks and skip the othe .. code-block:: yaml tasks: - - shell: echo "This certainly is epic!" + - name: Run the command if "epic" or "monumental" is true + ansible.builtin.shell: echo "This certainly is epic!" when: epic or monumental | bool - - shell: echo "This certainly isn't epic!" + - name: Run the command if "epic" is false + ansible.builtin.shell: echo "This certainly isn't epic!" when: not epic If a required variable has not been set, you can skip or fail using Jinja2's `defined` test. For example: @@ -184,10 +197,12 @@ If a required variable has not been set, you can skip or fail using Jinja2's `de .. code-block:: yaml tasks: - - shell: echo "I've got '{{ foo }}' and am not afraid to use it!" + - name: Run the command if "foo" is defined + ansible.builtin.shell: echo "I've got '{{ foo }}' and am not afraid to use it!" when: foo is defined - - fail: msg="Bailing out. this play requires 'bar'" + - name: Fail if "bar" is undefined + ansible.builtin.fail: msg="Bailing out. This play requires 'bar'" when: bar is undefined This is especially useful in combination with the conditional import of vars files (see below). @@ -203,7 +218,8 @@ If you combine a ``when`` statement with a :ref:`loop `, Ansibl .. code-block:: yaml tasks: - - command: echo {{ item }} + - name: Run with items greater than 5 + ansible.builtin.command: echo {{ item }} loop: [ 0, 2, 4, 6, 8, 10 ] when: item > 5 @@ -211,7 +227,8 @@ If you need to skip the whole task when the loop variable is undefined, use the .. code-block:: yaml - - command: echo {{ item }} + - name: Skip the whole task when a loop variable is undefined + ansible.builtin.command: echo {{ item }} loop: "{{ mylist|default([]) }}" when: item > 5 @@ -219,7 +236,8 @@ You can do the same thing when looping over a dict: .. code-block:: yaml - - command: echo {{ item.key }} + - name: The same as above using a dict + ansible.builtin.command: echo {{ item.key }} loop: "{{ query('dict', mydict|default({})) }}" when: item.value > 5 @@ -233,9 +251,11 @@ You can provide your own facts, as described in :ref:`developing_modules`. To r .. code-block:: yaml tasks: - - name: gather site specific fact data + - name: Gather site specific fact data action: site_facts - - command: /usr/bin/thingy + + - name: Use a custom fact + ansible.builtin.command: /usr/bin/thingy when: my_custom_fact_just_retrieved_from_the_remote_system == '1234' .. _when_with_reuse: @@ -258,19 +278,24 @@ When you add a conditional to an import statement, Ansible applies the condition when: x is not defined # other_tasks.yml - - set_fact: + - name: Set a variable + ansible.builtin.set_fact: x: foo - - debug: + + - name: Print a variable + ansible.builtin.debug: var: x Ansible expands this at execution time to the equivalent of:: - - set_fact: + - name: Set a variable if not defined + ansible.builtin.set_fact: x: foo when: x is not defined # this task sets a value for x - - debug: + - name: Do the task if "x" is not defined + ansible.builin.debug: var: x when: x is not defined # Ansible skips this task, because x is now defined @@ -293,22 +318,29 @@ When you use a conditional on an ``include_*`` statement, the condition is appli when: x is not defined # other_tasks.yml - - set_fact: + - name: Set a variable + ansible.builtin.set_fact: x: foo - - debug: + + - name: Print a variable + ansible.builtin.debug: var: x Ansible expands this at execution time to the equivalent of:: + # main.yml - include_tasks: other_tasks.yml when: x is not defined # if condition is met, Ansible includes other_tasks.yml - - set_fact: + # other_tasks.yml + - name: Set a variable + ansible.builtin.set_fact: x: foo # no condition applied to this task, Ansible sets the value of x to foo - - debug: + - name: Print a variable + ansible.builtin.debug: var: x # no condition applied to this task, Ansible prints the debug statement @@ -337,10 +369,11 @@ When you incorporate a role in your playbook statically with the ``roles`` keywo Selecting variables, files, or templates based on facts ------------------------------------------------------- -Sometimes the facts about a host determine the values you want to use for certain variables or even the file or template you want to select for that host. For example, the names of packages are different on CentOS and on Debian. The configuration files for common services are also different on different OS flavors and versions. To load different variables file, templates, or other files based on a fact about the hosts you are managing: +Sometimes the facts about a host determine the values you want to use for certain variables or even the file or template you want to select for that host. For example, the names of packages are different on CentOS and on Debian. The configuration files for common services are also different on different OS flavors and versions. To load different variables file, templates, or other files based on a fact about the hosts: - # Name your vars files, templates, or files to match the Ansible fact that differentiates them - # Select the correct vars file, template, or file for each host with a variable based on that Ansible fact + 1) name your vars files, templates, or files to match the Ansible fact that differentiates them + + 2) select the correct vars file, template, or file for each host with a variable based on that Ansible fact Ansible separates variables from tasks, keeping your playbooks from turning into arbitrary code with nested conditionals. This approach results in more streamlined and auditable configuration rules because there are fewer decision points to track. @@ -363,10 +396,12 @@ Then import those variables files based on the facts you gather on the hosts in - "vars/common.yml" - [ "vars/{{ ansible_facts['os_family'] }}.yml", "vars/os_defaults.yml" ] tasks: - - name: make sure apache is started - service: name={{ apache }} state=started + - name: Make sure apache is started + ansible.builtin.service: + name: '{{ apache }}' + state: started -Ansible gathers facts on the hosts in the webservers group, then interpolates the variable "ansible_facts['os_family']" into a list of filenames. If you have hosts with Red Hat operating systems ('CentOS', for example), Ansible looks for 'vars/RedHat.yml'. If that file does not exist, Ansible attempts to load 'vars/os_defaults.yml'. For Debian hosts, Ansible first looks for 'vars/Debian.yml', before falling back on 'vars/os_defaults.yml'. If no files in the list are found, Ansible raises an error. +Ansible gathers facts on the hosts in the webservers group, then interpolates the variable "ansible_facts['os_family']" into a list of filenames. If you have hosts with Red Hat operating systems (CentOS, for example), Ansible looks for 'vars/RedHat.yml'. If that file does not exist, Ansible attempts to load 'vars/os_defaults.yml'. For Debian hosts, Ansible first looks for 'vars/Debian.yml', before falling back on 'vars/os_defaults.yml'. If no files in the list are found, Ansible raises an error. Selecting files and templates based on facts ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -375,14 +410,14 @@ You can use the same approach when different OS flavors or versions require diff For example, you can template out a configuration file that is very different between, say, CentOS and Debian:: - - name: template a file - template: - src: "{{ item }}" - dest: /etc/myapp/foo.conf + - name: Template a file + ansible.builtin.template: + src: "{{ item }}" + dest: /etc/myapp/foo.conf loop: "{{ query('first_found', { 'files': myfiles, 'paths': mypaths}) }}" vars: myfiles: - - "{{ansible_facts['distribution']}}.conf" + - "{{ ansible_facts['distribution'] }}.conf" - default.conf mypaths: ['search_location_one/somedir/', '/opt/other_location/somedir/'] diff --git a/docs/docsite/rst/user_guide/playbooks_delegation.rst b/docs/docsite/rst/user_guide/playbooks_delegation.rst index 12d55d4ee0a..1042bafb455 100644 --- a/docs/docsite/rst/user_guide/playbooks_delegation.rst +++ b/docs/docsite/rst/user_guide/playbooks_delegation.rst @@ -18,39 +18,39 @@ Some tasks always execute on the controller. These tasks, including ``include``, Delegating tasks ---------------- -If you want to perform a task on one host with reference to other hosts, use the 'delegate_to' keyword on a task. This is ideal for managing nodes in a load balanced pool or for controlling outage windows. You can use delegation with the :ref:`serial ` keyword to control the number of hosts executing at one time:: +If you want to perform a task on one host with reference to other hosts, use the ``delegate_to`` keyword on a task. This is ideal for managing nodes in a load balanced pool or for controlling outage windows. You can use delegation with the :ref:`serial ` keyword to control the number of hosts executing at one time:: --- - hosts: webservers serial: 5 tasks: - - name: take out of load balancer pool - command: /usr/bin/take_out_of_pool {{ inventory_hostname }} + - name: Take out of load balancer pool + ansible.builtin.command: /usr/bin/take_out_of_pool {{ inventory_hostname }} delegate_to: 127.0.0.1 - - name: actual steps would go here - yum: + - name: Actual steps would go here + ansible.builtin.yum: name: acme-web-stack state: latest - - name: add back to load balancer pool - command: /usr/bin/add_back_to_pool {{ inventory_hostname }} + - name: Add back to load balancer pool + ansible.builtin.command: /usr/bin/add_back_to_pool {{ inventory_hostname }} delegate_to: 127.0.0.1 -The first and third tasks in this play run on 127.0.0.1, which is the machine running Ansible. There is also a shorthand syntax that you can use on a per-task basis: 'local_action'. Here is the same playbook as above, but using the shorthand syntax for delegating to 127.0.0.1:: +The first and third tasks in this play run on 127.0.0.1, which is the machine running Ansible. There is also a shorthand syntax that you can use on a per-task basis: ``local_action``. Here is the same playbook as above, but using the shorthand syntax for delegating to 127.0.0.1:: --- # ... tasks: - - name: take out of load balancer pool - local_action: command /usr/bin/take_out_of_pool {{ inventory_hostname }} + - name: Take out of load balancer pool + local_action: ansible.builtin.command /usr/bin/take_out_of_pool {{ inventory_hostname }} # ... - - name: add back to load balancer pool - local_action: command /usr/bin/add_back_to_pool {{ inventory_hostname }} + - name: Add back to load balancer pool + local_action: ansible.builtin.command /usr/bin/add_back_to_pool {{ inventory_hostname }} You can use a local action to call 'rsync' to recursively copy files to the managed servers:: @@ -58,11 +58,10 @@ You can use a local action to call 'rsync' to recursively copy files to the mana # ... tasks: - - name: recursively copy files from management server to target - local_action: command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/ + - name: Recursively copy files from management server to target + local_action: ansible.builtin.command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/ -Note that you must have passphrase-less SSH keys or an ssh-agent configured for this to work, otherwise rsync -will need to ask for a passphrase. +Note that you must have passphrase-less SSH keys or an ssh-agent configured for this to work, otherwise rsync asks for a passphrase. To specify more arguments, use the following syntax:: @@ -72,7 +71,7 @@ To specify more arguments, use the following syntax:: tasks: - name: Send summary mail local_action: - module: mail + module: community.general.mail subject: "Summary Mail" to: "{{ mail_recipient }}" body: "{{ mail_body }}" @@ -85,17 +84,17 @@ The `ansible_host` variable reflects the host a task is delegated to. Delegating facts ---------------- -Delegating Ansible tasks is like delegating tasks in the real world - your groceries belong to you, even if someone else delivers them to your home. Similarly, any facts gathered by a delegated task are assigned by default to the `inventory_hostname` (the current host), not to the host which produced the facts (the delegated to host). To assign gathered facts to the delegated host instead of the current host, set `delegate_facts` to `True`:: +Delegating Ansible tasks is like delegating tasks in the real world - your groceries belong to you, even if someone else delivers them to your home. Similarly, any facts gathered by a delegated task are assigned by default to the `inventory_hostname` (the current host), not to the host which produced the facts (the delegated to host). To assign gathered facts to the delegated host instead of the current host, set ``delegate_facts`` to ``true``:: --- - hosts: app_servers tasks: - - name: gather facts from db servers - setup: - delegate_to: "{{item}}" - delegate_facts: True - loop: "{{groups['dbservers']}}" + - name: Gather facts from db servers + ansible.builtin.setup: + delegate_to: "{{ item }}" + delegate_facts: true + loop: "{{ groups['dbservers'] }}" This task gathers facts for the machines in the dbservers group and assigns the facts to those machines, even though the play targets the app_servers group. This way you can lookup `hostvars['dbhost1']['ansible_default_ipv4']['address']` even though dbservers were not part of the play, or left out by using `--limit`. @@ -107,7 +106,7 @@ Local playbooks It may be useful to use a playbook locally on a remote host, rather than by connecting over SSH. This can be useful for assuring the configuration of a system by putting a playbook in a crontab. This may also be used to run a playbook inside an OS installer, such as an Anaconda kickstart. -To run an entire playbook locally, just set the "hosts:" line to "hosts: 127.0.0.1" and then run the playbook like so:: +To run an entire playbook locally, just set the ``hosts:`` line to ``hosts: 127.0.0.1`` and then run the playbook like so:: ansible-playbook playbook.yml --connection=local diff --git a/docs/docsite/rst/user_guide/playbooks_environment.rst b/docs/docsite/rst/user_guide/playbooks_environment.rst index 46e433561b2..7d97b95425d 100644 --- a/docs/docsite/rst/user_guide/playbooks_environment.rst +++ b/docs/docsite/rst/user_guide/playbooks_environment.rst @@ -23,7 +23,7 @@ You can set the environment directly at the task level:: tasks: - name: Install cobbler - package: + ansible.builtin.package: name: cobbler state: present environment: @@ -42,7 +42,7 @@ You can re-use environment settings by defining them as variables in your play a tasks: - name: Install cobbler - package: + ansible.builtin.package: name: cobbler state: present environment: "{{ proxy_env }}" @@ -94,19 +94,19 @@ Some language-specific version managers (such as rbenv and nvm) require you to s PATH: /var/local/nvm/versions/node/v4.2.1/bin:{{ ansible_env.PATH }} tasks: - - name: check for package.json - stat: + - name: Check for package.json + ansible.builtin.stat: path: '{{ node_app_dir }}/package.json' register: packagejson - - name: npm prune - command: npm prune + - name: Run npm prune + ansible.builtin.command: npm prune args: chdir: '{{ node_app_dir }}' when: packagejson.stat.exists - - name: npm install - npm: + - name: Run npm install + community.general.npm: path: '{{ node_app_dir }}' when: packagejson.stat.exists @@ -119,8 +119,8 @@ Some language-specific version managers (such as rbenv and nvm) require you to s You can also specify the environment at the task level:: --- - - name: install ruby 2.3.1 - command: rbenv install {{ rbenv_ruby_version }} + - name: Install ruby 2.3.1 + ansible.builtin.command: rbenv install {{ rbenv_ruby_version }} args: creates: '{{ rbenv_root }}/versions/{{ rbenv_ruby_version }}/bin/ruby' vars: diff --git a/docs/docsite/rst/user_guide/playbooks_error_handling.rst b/docs/docsite/rst/user_guide/playbooks_error_handling.rst index ecb68571c4a..c73067cc77d 100644 --- a/docs/docsite/rst/user_guide/playbooks_error_handling.rst +++ b/docs/docsite/rst/user_guide/playbooks_error_handling.rst @@ -16,36 +16,36 @@ Ignoring failed commands By default Ansible stops executing tasks on a host when a task fails on that host. You can use ``ignore_errors`` to continue on in spite of the failure:: - - name: this will not count as a failure - command: /bin/false + - name: Do not count this as a failure + ansible.builtin.command: /bin/false ignore_errors: yes -The ``ignore_errors`` directive only works when the task is able to run and returns a value of 'failed'. It will not make Ansible ignore undefined variable errors, connection failures, execution issues (for example, missing packages), or syntax errors. +The ``ignore_errors`` directive only works when the task is able to run and returns a value of 'failed'. It does not make Ansible ignore undefined variable errors, connection failures, execution issues (for example, missing packages), or syntax errors. Ignoring unreachable host errors ================================ .. versionadded:: 2.7 -You may ignore task failure due to the host instance being 'UNREACHABLE' with the ``ignore_unreachable`` keyword. Ansible ignores the task errors, but continues to execute future tasks against the unreachable host. For example, at the task level:: +You can ignore a task failure due to the host instance being 'UNREACHABLE' with the ``ignore_unreachable`` keyword. Ansible ignores the task errors, but continues to execute future tasks against the unreachable host. For example, at the task level:: - - name: this executes, fails, and the failure is ignored - command: /bin/true + - name: This executes, fails, and the failure is ignored + ansible.builtin.command: /bin/true ignore_unreachable: yes - - name: this executes, fails, and ends the play for this host - command: /bin/true + - name: This executes, fails, and ends the play for this host + ansible.builtin.command: /bin/true And at the playbook level:: - hosts: all ignore_unreachable: yes tasks: - - name: this executes, fails, and the failure is ignored - command: /bin/true + - name: This executes, fails, and the failure is ignored + ansible.builtin.command: /bin/true - - name: this executes, fails, and ends the play for this host - command: /bin/true + - name: This executes, fails, and ends the play for this host + ansible.builtin.command: /bin/true ignore_unreachable: no .. _resetting_unreachable: @@ -84,21 +84,21 @@ Ansible lets you define what "failure" means in each task using the ``failed_whe You may check for failure by searching for a word or phrase in the output of a command:: - name: Fail task when the command error output prints FAILED - command: /usr/bin/example-command -x -y -z + ansible.builtin.command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr" or based on the return code:: - name: Fail task when both files are identical - raw: diff foo/file1 bar/file2 + ansible.builtin.raw: diff foo/file1 bar/file2 register: diff_cmd failed_when: diff_cmd.rc == 0 or diff_cmd.rc >= 2 You can also combine multiple conditions for failure. This task will fail if both conditions are true:: - name: Check if a file exists in temp and fail task if it does - command: ls /tmp/this_should_not_be_here + ansible.builtin.command: ls /tmp/this_should_not_be_here register: result failed_when: - result.rc == 0 @@ -111,7 +111,7 @@ If you want the task to fail when only one condition is satisfied, change the `` If you have too many conditions to fit neatly into one line, you can split it into a multi-line yaml value with ``>``:: - name: example of many failed_when conditions with OR - shell: "./myBinary" + ansible.builtin.shell: "./myBinary" register: ret failed_when: > ("No such file or directory" in ret.stdout) or @@ -127,17 +127,19 @@ Ansible lets you define when a particular task has "changed" a remote node using tasks: - - shell: /usr/bin/billybass --mode="take me to the river" + - name: Report 'changed' when the return code is not equal to 2 + ansible.builtin.shell: /usr/bin/billybass --mode="take me to the river" register: bass_result changed_when: "bass_result.rc != 2" - # this will never report 'changed' status - - shell: wall 'beep' + - name: This will never report 'changed' status + ansible.builtin.shell: wall 'beep' changed_when: False You can also combine multiple conditions to override "changed" result:: - - command: /bin/fake_command + - name: Combine multiple conditions to override 'changed' result + ansible.builtin.command: /bin/fake_command register: result ignore_errors: True changed_when: @@ -149,11 +151,11 @@ See :ref:`controlling_what_defines_failure` for more conditional syntax examples Ensuring success for command and shell ====================================== -The :ref:`command ` and :ref:`shell ` modules care about return codes, so if you have a command whose successful exit code is not zero, you may wish to do this:: +The :ref:`command ` and :ref:`shell ` modules care about return codes, so if you have a command whose successful exit code is not zero, you can do this:: tasks: - - name: run this command and ignore the result - shell: /usr/bin/somecommand || /bin/true + - name: Run this command and ignore the result + ansible.builtin.shell: /usr/bin/somecommand || /bin/true Aborting a play on all hosts @@ -181,25 +183,26 @@ You can use this feature when all tasks must be 100% successful to continue play --- - hosts: load_balancers_dc_a - any_errors_fatal: True + any_errors_fatal: true tasks: - - name: 'shutting down datacenter [ A ]' - command: /usr/bin/disable-dc + - name: Shut down datacenter 'A' + ansible.builtin.command: /usr/bin/disable-dc - hosts: frontends_dc_a tasks: - - name: 'stopping service' - command: /usr/bin/stop-software - - name: 'updating software' - command: /usr/bin/upgrade-software + - name: Stop service + ansible.builtin.command: /usr/bin/stop-software + + - name: Update software + ansible.builtin.command: /usr/bin/upgrade-software - hosts: load_balancers_dc_a tasks: - - name: 'Starting datacenter [ A ]' - command: /usr/bin/enable-dc + - name: Start datacenter 'A' + ansible.builtin.command: /usr/bin/enable-dc In this example Ansible starts the software upgrade on the front ends only if all of the load balancers are successfully disabled. diff --git a/docs/docsite/rst/user_guide/playbooks_handlers.rst b/docs/docsite/rst/user_guide/playbooks_handlers.rst index d467f103fca..4650d5e78fe 100644 --- a/docs/docsite/rst/user_guide/playbooks_handlers.rst +++ b/docs/docsite/rst/user_guide/playbooks_handlers.rst @@ -14,49 +14,54 @@ Handler example This playbook, ``verify-apache.yml``, contains a single play with a handler:: --- - - name: verify apache installation + - name: Verify apache installation hosts: webservers vars: http_port: 80 max_clients: 200 remote_user: root tasks: - - name: ensure apache is at the latest version - yum: + - name: Ensure apache is at the latest version + ansible.builtin.yum: name: httpd state: latest - - name: write the apache config file - template: + + - name: Write the apache config file + ansible.builtin.template: src: /srv/httpd.j2 dest: /etc/httpd.conf notify: - - restart apache - - name: ensure apache is running - service: + - Restart apache + + - name: Ensure apache is running + ansible.builtin.service: name: httpd state: started + handlers: - - name: restart apache - service: + - name: Restart apache + ansible.builtin.service: name: httpd state: restarted In this example playbook, the second task notifies the handler. A single task can notify more than one handler:: - - name: template configuration file - template: + - name: Template configuration file + ansible.builtin.template: src: template.j2 dest: /etc/foo.conf notify: - - restart memcached - - restart apache + - Restart memcached + - Restart apache + handlers: - - name: restart memcached - service: + - name: Restart memcached + ansible.builtin.service: name: memcached state: restarted - - name: restart apache - service: + + - name: Restart apache + ansible.builtin.service: name: apache state: restarted @@ -68,9 +73,14 @@ By default, handlers run after all the tasks in a particular play have been comp If you need handlers to run before the end of the play, add a task to flush them using the :ref:`meta module `, which executes Ansible actions:: tasks: - - shell: some tasks go here - - meta: flush_handlers - - shell: some other tasks + - name: Some tasks go here + ansible.builtin.shell: ... + + - name: Flush handlers + meta: flush_handlers + + - name: Some other tasks + ansible.builtin.shell: ... The ``meta: flush_handlers`` task triggers any handlers that have been notified at that point in the play. @@ -80,8 +90,8 @@ Using variables with handlers You may want your Ansible handlers to use variables. For example, if the name of a service varies slightly by distribution, you want your output to show the exact name of the restarted service for each target machine. Avoid placing variables in the name of the handler. Since handler names are templated early on, Ansible may not have a value available for a handler name like this:: handlers: - # this handler name may cause your play to fail! - - name: restart "{{ web_service_name }}" + # This handler name may cause your play to fail! + - name: Restart "{{ web_service_name }}" If the variable used in the handler name is not available, the entire play fails. Changing that variable mid-play **will not** result in newly created handler. @@ -94,28 +104,29 @@ Instead, place variables in the task parameters of your handler. You can load th include_vars: "{{ ansible_facts.distribution }}.yml" handlers: - - name: restart web service - service: + - name: Restart web service + ansible.builtin.service: name: "{{ web_service_name | default('httpd') }}" state: restarted Handlers can also "listen" to generic topics, and tasks can notify those topics as follows:: handlers: - - name: restart memcached - service: + - name: Restart memcached + ansible.builtin.service: name: memcached state: restarted listen: "restart web services" - - name: restart apache - service: + + - name: Restart apache + ansible.builtin.service: name: apache state: restarted listen: "restart web services" tasks: - - name: restart everything - command: echo "this task will restart the web services" + - name: Restart everything + ansible.builtin.command: echo "this task will restart the web services" notify: "restart web services" This use makes it much easier to trigger multiple handlers. It also decouples handlers from their names, @@ -132,6 +143,6 @@ a shared source like Galaxy). When using handlers within roles, note that: -* handlers notified within ``pre_tasks``, ``tasks``, and ``post_tasks`` sections are automatically flushed in the end of section where they were notified. -* handlers notified within ``roles`` section are automatically flushed in the end of ``tasks`` section, but before any ``tasks`` handlers. +* handlers notified within ``pre_tasks``, ``tasks``, and ``post_tasks`` sections are automatically flushed at the end of section where they were notified. +* handlers notified within ``roles`` section are automatically flushed at the end of ``tasks`` section, but before any ``tasks`` handlers. * handlers are play scoped and as such can be used outside of the role they are defined in.