1.. _playbooks_tests: 2 3***** 4Tests 5***** 6 7`Tests <http://jinja.pocoo.org/docs/dev/templates/#tests>`_ in Jinja are a way of evaluating template expressions and returning True or False. Jinja ships with many of these. See `builtin tests`_ in the official Jinja template documentation. 8 9The main difference between tests and filters are that Jinja tests are used for comparisons, whereas filters are used for data manipulation, and have different applications in jinja. Tests can also be used in list processing filters, like ``map()`` and ``select()`` to choose items in the list. 10 11Like all templating, tests always execute on the Ansible controller, **not** on the target of a task, as they test local data. 12 13In addition to those Jinja2 tests, Ansible supplies a few more and users can easily create their own. 14 15.. contents:: 16 :local: 17 18.. _test_syntax: 19 20Test syntax 21=========== 22 23`Test syntax <http://jinja.pocoo.org/docs/dev/templates/#tests>`_ varies from `filter syntax <http://jinja.pocoo.org/docs/dev/templates/#filters>`_ (``variable | filter``). Historically Ansible has registered tests as both jinja tests and jinja filters, allowing for them to be referenced using filter syntax. 24 25As of Ansible 2.5, using a jinja test as a filter will generate a warning. 26 27The syntax for using a jinja test is as follows:: 28 29 variable is test_name 30 31Such as:: 32 33 result is failed 34 35.. _testing_strings: 36 37Testing strings 38=============== 39 40To match strings against a substring or a regular expression, use the ``match``, ``search`` or ``regex`` tests:: 41 42 vars: 43 url: "http://example.com/users/foo/resources/bar" 44 45 tasks: 46 - debug: 47 msg: "matched pattern 1" 48 when: url is match("http://example.com/users/.*/resources/") 49 50 - debug: 51 msg: "matched pattern 2" 52 when: url is search("/users/.*/resources/.*") 53 54 - debug: 55 msg: "matched pattern 3" 56 when: url is search("/users/") 57 58 - debug: 59 msg: "matched pattern 4" 60 when: url is regex("example.com/\w+/foo") 61 62``match`` succeeds if it finds the pattern at the beginning of the string, while ``search`` succeeds if it finds the pattern anywhere within string. By default, ``regex`` works like ``search``, but ``regex`` can be configured to perform other tests as well, by passing the ``match_type`` keyword argument. In particular, ``match_type`` determines the ``re`` method that gets used to perform the search. The full list can be found in the relevant Python documentation `here <https://docs.python.org/3/library/re.html#regular-expression-objects>`_. 63 64All of the string tests also take optional ``ignorecase`` and ``multiline`` arguments. These correspond to ``re.I`` and ``re.M`` from Python's ``re`` library, respectively. 65 66.. _testing_vault: 67 68Vault 69===== 70 71.. versionadded:: 2.10 72 73You can test whether a variable is an inline single vault encrypted value using the ``vault_encrypted`` test. 74 75.. code-block:: yaml 76 77 vars: 78 variable: !vault | 79 $ANSIBLE_VAULT;1.2;AES256;dev 80 61323931353866666336306139373937316366366138656131323863373866376666353364373761 81 3539633234313836346435323766306164626134376564330a373530313635343535343133316133 82 36643666306434616266376434363239346433643238336464643566386135356334303736353136 83 6565633133366366360a326566323363363936613664616364623437336130623133343530333739 84 3039 85 86 tasks: 87 - debug: 88 msg: '{{ (variable is vault_encrypted) | ternary("Vault encrypted", "Not vault encrypted") }}' 89 90.. _testing_truthiness: 91 92Testing truthiness 93================== 94 95.. versionadded:: 2.10 96 97As of Ansible 2.10, you can now perform Python like truthy and falsy checks. 98 99.. code-block:: yaml 100 101 - debug: 102 msg: "Truthy" 103 when: value is truthy 104 vars: 105 value: "some string" 106 107 - debug: 108 msg: "Falsy" 109 when: value is falsy 110 vars: 111 value: "" 112 113Additionally, the ``truthy`` and ``falsy`` tests accept an optional parameter called ``convert_bool`` that will attempt 114to convert boolean indicators to actual booleans. 115 116.. code-block:: yaml 117 118 - debug: 119 msg: "Truthy" 120 when: value is truthy(convert_bool=True) 121 vars: 122 value: "yes" 123 124 - debug: 125 msg: "Falsy" 126 when: value is falsy(convert_bool=True) 127 vars: 128 value: "off" 129 130.. _testing_versions: 131 132Comparing versions 133================== 134 135.. versionadded:: 1.6 136 137.. note:: In 2.5 ``version_compare`` was renamed to ``version`` 138 139To compare a version number, such as checking if the ``ansible_facts['distribution_version']`` 140version is greater than or equal to '12.04', you can use the ``version`` test. 141 142The ``version`` test can also be used to evaluate the ``ansible_facts['distribution_version']``:: 143 144 {{ ansible_facts['distribution_version'] is version('12.04', '>=') }} 145 146If ``ansible_facts['distribution_version']`` is greater than or equal to 12.04, this test returns True, otherwise False. 147 148The ``version`` test accepts the following operators:: 149 150 <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne 151 152This test also accepts a 3rd parameter, ``strict`` which defines if strict version parsing as defined by ``distutils.version.StrictVersion`` should be used. The default is ``False`` (using ``distutils.version.LooseVersion``), ``True`` enables strict version parsing:: 153 154 {{ sample_version_var is version('1.0', operator='lt', strict=True) }} 155 156As of Ansible 2.11 the ``version`` test accepts a ``version_type`` parameter which is mutually exclusive with ``strict``, and accepts the following values:: 157 158 loose, strict, semver, semantic 159 160Using ``version_type`` to compare a semantic version would be achieved like the following:: 161 162 {{ sample_semver_var is version('2.0.0-rc.1+build.123', 'lt', version_type='semver') }} 163 164When using ``version`` in a playbook or role, don't use ``{{ }}`` as described in the `FAQ <https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#when-should-i-use-also-how-to-interpolate-variables-or-dynamic-variable-names>`_:: 165 166 vars: 167 my_version: 1.2.3 168 169 tasks: 170 - debug: 171 msg: "my_version is higher than 1.0.0" 172 when: my_version is version('1.0.0', '>') 173 174.. _math_tests: 175 176Set theory tests 177================ 178 179.. versionadded:: 2.1 180 181.. note:: In 2.5 ``issubset`` and ``issuperset`` were renamed to ``subset`` and ``superset`` 182 183To see if a list includes or is included by another list, you can use 'subset' and 'superset':: 184 185 vars: 186 a: [1,2,3,4,5] 187 b: [2,3] 188 tasks: 189 - debug: 190 msg: "A includes B" 191 when: a is superset(b) 192 193 - debug: 194 msg: "B is included in A" 195 when: b is subset(a) 196 197.. _contains_test: 198 199Testing if a list contains a value 200================================== 201 202.. versionadded:: 2.8 203 204Ansible includes a ``contains`` test which operates similarly, but in reverse of the Jinja2 provided ``in`` test. 205The ``contains`` test is designed to work with the ``select``, ``reject``, ``selectattr``, and ``rejectattr`` filters:: 206 207 vars: 208 lacp_groups: 209 - master: lacp0 210 network: 10.65.100.0/24 211 gateway: 10.65.100.1 212 dns4: 213 - 10.65.100.10 214 - 10.65.100.11 215 interfaces: 216 - em1 217 - em2 218 219 - master: lacp1 220 network: 10.65.120.0/24 221 gateway: 10.65.120.1 222 dns4: 223 - 10.65.100.10 224 - 10.65.100.11 225 interfaces: 226 - em3 227 - em4 228 229 tasks: 230 - debug: 231 msg: "{{ (lacp_groups|selectattr('interfaces', 'contains', 'em1')|first).master }}" 232 233.. versionadded:: 2.4 234 235Testing if a list value is True 236=============================== 237 238You can use `any` and `all` to check if any or all elements in a list are true or not:: 239 240 vars: 241 mylist: 242 - 1 243 - "{{ 3 == 3 }}" 244 - True 245 myotherlist: 246 - False 247 - True 248 tasks: 249 250 - debug: 251 msg: "all are true!" 252 when: mylist is all 253 254 - debug: 255 msg: "at least one is true" 256 when: myotherlist is any 257 258.. _path_tests: 259 260Testing paths 261============= 262 263.. note:: In 2.5 the following tests were renamed to remove the ``is_`` prefix 264 265The following tests can provide information about a path on the controller:: 266 267 - debug: 268 msg: "path is a directory" 269 when: mypath is directory 270 271 - debug: 272 msg: "path is a file" 273 when: mypath is file 274 275 - debug: 276 msg: "path is a symlink" 277 when: mypath is link 278 279 - debug: 280 msg: "path already exists" 281 when: mypath is exists 282 283 - debug: 284 msg: "path is {{ (mypath is abs)|ternary('absolute','relative')}}" 285 286 - debug: 287 msg: "path is the same file as path2" 288 when: mypath is same_file(path2) 289 290 - debug: 291 msg: "path is a mount" 292 when: mypath is mount 293 294 295Testing size formats 296==================== 297 298The ``human_readable`` and ``human_to_bytes`` functions let you test your 299playbooks to make sure you are using the right size format in your tasks, and that 300you provide Byte format to computers and human-readable format to people. 301 302Human readable 303-------------- 304 305Asserts whether the given string is human readable or not. 306 307For example:: 308 309 - name: "Human Readable" 310 assert: 311 that: 312 - '"1.00 Bytes" == 1|human_readable' 313 - '"1.00 bits" == 1|human_readable(isbits=True)' 314 - '"10.00 KB" == 10240|human_readable' 315 - '"97.66 MB" == 102400000|human_readable' 316 - '"0.10 GB" == 102400000|human_readable(unit="G")' 317 - '"0.10 Gb" == 102400000|human_readable(isbits=True, unit="G")' 318 319This would result in:: 320 321 { "changed": false, "msg": "All assertions passed" } 322 323Human to bytes 324-------------- 325 326Returns the given string in the Bytes format. 327 328For example:: 329 330 - name: "Human to Bytes" 331 assert: 332 that: 333 - "{{'0'|human_to_bytes}} == 0" 334 - "{{'0.1'|human_to_bytes}} == 0" 335 - "{{'0.9'|human_to_bytes}} == 1" 336 - "{{'1'|human_to_bytes}} == 1" 337 - "{{'10.00 KB'|human_to_bytes}} == 10240" 338 - "{{ '11 MB'|human_to_bytes}} == 11534336" 339 - "{{ '1.1 GB'|human_to_bytes}} == 1181116006" 340 - "{{'10.00 Kb'|human_to_bytes(isbits=True)}} == 10240" 341 342This would result in:: 343 344 { "changed": false, "msg": "All assertions passed" } 345 346 347.. _test_task_results: 348 349Testing task results 350==================== 351 352The following tasks are illustrative of the tests meant to check the status of tasks:: 353 354 tasks: 355 356 - shell: /usr/bin/foo 357 register: result 358 ignore_errors: True 359 360 - debug: 361 msg: "it failed" 362 when: result is failed 363 364 # in most cases you'll want a handler, but if you want to do something right now, this is nice 365 - debug: 366 msg: "it changed" 367 when: result is changed 368 369 - debug: 370 msg: "it succeeded in Ansible >= 2.1" 371 when: result is succeeded 372 373 - debug: 374 msg: "it succeeded" 375 when: result is success 376 377 - debug: 378 msg: "it was skipped" 379 when: result is skipped 380 381.. note:: From 2.1, you can also use success, failure, change, and skip so that the grammar matches, for those who need to be strict about it. 382 383 384.. _builtin tests: http://jinja.palletsprojects.com/templates/#builtin-tests 385 386.. seealso:: 387 388 :ref:`playbooks_intro` 389 An introduction to playbooks 390 :ref:`playbooks_conditionals` 391 Conditional statements in playbooks 392 :ref:`playbooks_variables` 393 All about variables 394 :ref:`playbooks_loops` 395 Looping in playbooks 396 :ref:`playbooks_reuse_roles` 397 Playbook organization by roles 398 :ref:`playbooks_best_practices` 399 Tips and tricks for playbooks 400 `User Mailing List <https://groups.google.com/group/ansible-devel>`_ 401 Have a question? Stop by the google group! 402 `irc.libera.chat <https://libera.chat/>`_ 403 #ansible IRC chat channel 404