/docsite/rst/playbooks_conditionals.rst

https://github.com/ajanthanm/ansible · ReStructuredText · 257 lines · 186 code · 71 blank · 0 comment · 0 complexity · 4b330c32f02665c8da032e257753e696 MD5 · raw file

  1. Conditionals
  2. ============
  3. .. contents:: Topics
  4. Often the result of a play may depend on the value of a variable, fact (something learned about the remote system),
  5. or previous task result. In some cases, the values of variables may depend on other variables.
  6. Further, additional groups can be created to manage hosts based on
  7. whether the hosts match other criteria. There are many options to control execution flow in Ansible.
  8. Let's dig into what they are.
  9. The When Statement
  10. ``````````````````
  11. Sometimes you will want to skip a particular step on a particular host. This could be something
  12. as simple as not installing a certain package if the operating system is a particular version,
  13. or it could be something like performing some cleanup steps if a filesystem is getting full.
  14. This is easy to do in Ansible, with the `when` clause, which contains a Jinja2 expression (see :doc:`playbooks_variables`).
  15. It's actually pretty simple::
  16. tasks:
  17. - name: "shutdown Debian flavored systems"
  18. command: /sbin/shutdown -t now
  19. when: ansible_os_family == "Debian"
  20. A number of Jinja2 "filters" can also be used in when statements, some of which are unique
  21. and provided by Ansible. Suppose we want to ignore the error of one statement and then
  22. decide to do something conditionally based on success or failure::
  23. tasks:
  24. - command: /bin/false
  25. register: result
  26. ignore_errors: True
  27. - command: /bin/something
  28. when: result|failed
  29. - command: /bin/something_else
  30. when: result|success
  31. - command: /bin/still/something_else
  32. when: result|skipped
  33. Note that was a little bit of foreshadowing on the 'register' statement. We'll get to it a bit later in this chapter.
  34. As a reminder, to see what facts are available on a particular system, you can do::
  35. ansible hostname.example.com -m setup
  36. 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::
  37. tasks:
  38. - shell: echo "only on Red Hat 6, derivatives, and later"
  39. when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
  40. .. note:: the above example requires the lsb_release package on the target host in order to return the ansible_lsb.major_release fact.
  41. 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::
  42. vars:
  43. epic: true
  44. Then a conditional execution might look like::
  45. tasks:
  46. - shell: echo "This certainly is epic!"
  47. when: epic
  48. or::
  49. tasks:
  50. - shell: echo "This certainly isn't epic!"
  51. when: not epic
  52. If a required variable has not been set, you can skip or fail using Jinja2's
  53. `defined` test. For example::
  54. tasks:
  55. - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
  56. when: foo is defined
  57. - fail: msg="Bailing out. this play requires 'bar'"
  58. when: bar is not defined
  59. This is especially useful in combination with the conditional import of vars
  60. files (see below).
  61. Note that when combining `when` with `with_items` (see :doc:`playbooks_loops`), be aware that the `when` statement is processed separately for each item. This is by design::
  62. tasks:
  63. - command: echo {{ item }}
  64. with_items: [ 0, 2, 4, 6, 8, 10 ]
  65. when: item > 5
  66. Loading in Custom Facts
  67. ```````````````````````
  68. It's also easy to provide your own facts if you want, which is covered in :doc:`developing_modules`. To run them, just
  69. make a call to your own custom fact gathering module at the top of your list of tasks, and variables returned
  70. there will be accessible to future tasks::
  71. tasks:
  72. - name: gather site specific fact data
  73. action: site_facts
  74. - command: /usr/bin/thingy
  75. when: my_custom_fact_just_retrieved_from_the_remote_system == '1234'
  76. Applying 'when' to roles and includes
  77. `````````````````````````````````````
  78. Note that if you have several tasks that all share the same conditional statement, you can affix the conditional
  79. to a task include statement as below. Note this does not work with playbook includes, just task includes. All the tasks
  80. get evaluated, but the conditional is applied to each and every task::
  81. - include: tasks/sometasks.yml
  82. when: "'reticulating splines' in output"
  83. Or with a role::
  84. - hosts: webservers
  85. roles:
  86. - { role: debian_stock_config, when: ansible_os_family == 'Debian' }
  87. You will note a lot of 'skipped' output by default in Ansible when using this approach on systems that don't match the criteria.
  88. Read up on the 'group_by' module in the :doc:`modules` docs for a more streamlined way to accomplish the same thing.
  89. Conditional Imports
  90. ```````````````````
  91. .. note:: This is an advanced topic that is infrequently used. You can probably skip this section.
  92. Sometimes you will want to do certain things differently in a playbook based on certain criteria.
  93. Having one playbook that works on multiple platforms and OS versions is a good example.
  94. As an example, the name of the Apache package may be different between CentOS and Debian,
  95. but it is easily handled with a minimum of syntax in an Ansible Playbook::
  96. ---
  97. - hosts: all
  98. remote_user: root
  99. vars_files:
  100. - "vars/common.yml"
  101. - [ "vars/{{ ansible_os_family }}.yml", "vars/os_defaults.yml" ]
  102. tasks:
  103. - name: make sure apache is running
  104. service: name={{ apache }} state=running
  105. .. note::
  106. The variable 'ansible_os_family' is being interpolated into
  107. the list of filenames being defined for vars_files.
  108. As a reminder, the various YAML files contain just keys and values::
  109. ---
  110. # for vars/CentOS.yml
  111. apache: httpd
  112. somethingelse: 42
  113. How does this work? If the operating system was 'CentOS', the first file Ansible would try to import
  114. would be 'vars/CentOS.yml', followed by '/vars/os_defaults.yml' if that file
  115. did not exist. If no files in the list were found, an error would be raised.
  116. On Debian, it would instead first look towards 'vars/Debian.yml' instead of 'vars/CentOS.yml', before
  117. falling back on 'vars/os_defaults.yml'. Pretty simple.
  118. To use this conditional import feature, you'll need facter or ohai installed prior to running the playbook, but
  119. you can of course push this out with Ansible if you like::
  120. # for facter
  121. ansible -m yum -a "pkg=facter ensure=installed"
  122. ansible -m yum -a "pkg=ruby-json ensure=installed"
  123. # for ohai
  124. ansible -m yum -a "pkg=ohai ensure=installed"
  125. Ansible's approach to configuration -- separating variables from tasks, keeps your playbooks
  126. from turning into arbitrary code with ugly nested ifs, conditionals, and so on - and results
  127. in more streamlined & auditable configuration rules -- especially because there are a
  128. minimum of decision points to track.
  129. Selecting Files And Templates Based On Variables
  130. ````````````````````````````````````````````````
  131. .. note:: This is an advanced topic that is infrequently used. You can probably skip this section.
  132. Sometimes a configuration file you want to copy, or a template you will use may depend on a variable.
  133. The following construct selects the first available file appropriate for the variables of a given host, which is often much cleaner than putting a lot of if conditionals in a template.
  134. The following example shows how to template out a configuration file that was very different between, say, CentOS and Debian::
  135. - name: template a file
  136. template: src={{ item }} dest=/etc/myapp/foo.conf
  137. with_first_found:
  138. - files:
  139. - {{ ansible_distribution }}.conf
  140. - default.conf
  141. paths:
  142. - search_location_one/somedir/
  143. - /opt/other_location/somedir/
  144. Register Variables
  145. ``````````````````
  146. Often in a playbook it may be useful to store the result of a given command in a variable and access
  147. it later. Use of the command module in this way can in many ways eliminate the need to write site specific facts, for
  148. instance, you could test for the existence of a particular program.
  149. The 'register' keyword decides what variable to save a result in. The resulting variables can be used in templates, action lines, or *when* statements. It looks like this (in an obviously trivial example)::
  150. - name: test play
  151. hosts: all
  152. tasks:
  153. - shell: cat /etc/motd
  154. register: motd_contents
  155. - shell: echo "motd contains the word hi"
  156. when: motd_contents.stdout.find('hi') != -1
  157. As shown previously, the registered variable's string contents are accessible with the 'stdout' value.
  158. The registered result can be used in the "with_items" of a task if it is converted into
  159. a list (or already is a list) as shown below. "stdout_lines" is already available on the object as
  160. well though you could also call "home_dirs.stdout.split()" if you wanted, and could split by other
  161. fields::
  162. - name: registered variable usage as a with_items list
  163. hosts: all
  164. tasks:
  165. - name: retrieve the list of home directories
  166. command: ls /home
  167. register: home_dirs
  168. - name: add home dirs to the backup spooler
  169. file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
  170. with_items: home_dirs.stdout_lines
  171. # same as with_items: home_dirs.stdout.split()
  172. .. seealso::
  173. :doc:`playbooks`
  174. An introduction to playbooks
  175. :doc:`playbooks_roles`
  176. Playbook organization by roles
  177. :doc:`playbooks_best_practices`
  178. Best practices in playbooks
  179. :doc:`playbooks_conditionals`
  180. Conditional statements in playbooks
  181. :doc:`playbooks_variables`
  182. All about variables
  183. `User Mailing List <http://groups.google.com/group/ansible-devel>`_
  184. Have a question? Stop by the google group!
  185. `irc.freenode.net <http://irc.freenode.net>`_
  186. #ansible IRC chat channel