include role if variable is true - ansible

I want a role to be included in my Ansible playbook if a variable value is true and not executed if it is false. I thought this should work but the integration test gets run even if run_integration_test is false
- include_role:
name: integration_test
when: "{{ run_integration_test }}"
tags:
- configure_integration
- aws
What is the correct way to do this?

You have an indentation problem: when is a task option, not an argument to include_role. You need to write:
- include_role:
name: integration_test
when: run_integration_test
tags:
- configure_integration
- aws
Notice that when is aligned with tags in this example.
There's a trap here you might hit depending on how you're setting run_integration_test. You might try running something like this:
ansible-playbook -e run_integration_test=false ...
And you would be surprised that the task still runs. In the above command line, we're setting run_integration_test to the string value "false" rather than to boolean false, and a non-empty string evaluates to true. One way to deal with this is to write your when expression like this:
when: "run_integration_test|default(false)|bool"
This will (a) default to false if run_integration_test is unsent, and (b) will cast string values "true" and "false" to the correct boolean value using the bool filter.

Related

Ansible: How to check a value: key pair in the when condition

First of all, I have separated my playbooks in this way:
environtments/something/host_vars/host1.yml
roles/sshd/tasks/main.yml
The host's environment variable contains some value: key pairs, in this case:
specialinfo: 'blah'
And the role contains a block, which should be run when this 'specialinfo' value matches to blah:
- name: Check that specialvalue is blah
block:
- name: Do something
...
- name: Do something else
...
when: {{ specialinfo }} == 'blah'
Please help me to achive this, because I'm quite sure that the problem is inside the 'when' condition. If I need a copy (or something like that) inside a name, I can use {{ specialinfo }}
Please also notice that I can't use with_items here, because it can't be used inside the block element.
First of all, you can't use double curly braces in when because the condition itself needs to be a jinja expression. Change the condition to when: specialinfo == 'blah'.
Note that, when condition for block applies to all the tasks inside the block. This means that the same ... == 'blah' condition will be applied to both Do something and Do something else tasks. If you want to control when a particular task to be executed, use when for the task alone like so:
- debug: Do something
msg: is blah
when: specialinfo == 'blah'
- debug: Do something else
msg: is not blah
when: specialinfo != 'blah'

Check if arrays are defined and not empty in ansible

I have the following code
- set_fact:
MY_HOSTNAME: "SOME VALUE"
MY_SERVER: "00.00.00.00"
- name: Get MY server
set_fact:
MY_SERVER: "{{ groups[MY_HOSTNAME][0] }}"
when: groups[MY_HOSTNAME] is defined
In the above code, groups[MY_HOSTNAME] is an array. What is the best way to check that groups[MY_HOSTNAME] is defined and also that it is not empty
If it is either of that I want the value 00.00.00.00 to be assigned to MY_SERVER
I don't know if it's version specific, but I'm currently running ansible-2.3.2 on RHEL6 and I had to put quotes around the group name to get it to work for me:
when: groups["GROUP_NAME"] is defined and (groups["GROUP_NAME"]|length>0)
Edit: I couldn't add this as a comment to techraf's answer because I don't have enough reputation.
list | length filter returns the number of elements. If it is zero, the list is empty.
For a conditional value use if or ternary filter (example in this answer).
For a composite conditional (groups[MY_HOSTNAME]| default([])) | length.
You can first check if it is indeed a list and then check if it has more than one element:
when: (groups['MY_HOSTNAME'] is defined) and (groups['MY_HOSTNAME'] | type_debug == 'list') and (groups['MY_HOSTNAME'] | length > 0)
try this one (it checks if variable is defined and if it is a iterable like list)
when: (groups["GROUP_NAME"] is defined) and (groups["GROUP_NAME"] is iterable)

How do I check if variable defined in an Ansible playbook contains a string value?

I want to validate that the input values passed to the variables as extra_args.
I want to run a pre-task that passes if the variable contains a string value, else fails if it contains anything else.
The values are passed to them as extra_args when executing the playbook.
I want to run a pre-task that passes if the variable contains a string value, else fails if it contains anything else.
This task fails if the variable is not a string object:
- fail:
when: variable is not string
But be aware that all values passed as extra-vars will be strings, because that's what they are -- anything you type on your keyboard is a valid string. As there is no type declaration, even if a variable contains a numerical value, it will be stored in a string object.
It is different to variable values defined in YAML which undergo type autodetection performed by YAML parser. For example if you type myvar: true in YAML, it will be considered Boolean object true, but if you pass the same value with --extra-vars "myvar:true", it will be a string object true.
You need to specify another condition.
Here are few filters and tests in ansible you may find it useful
http://docs.ansible.com/ansible/latest/playbooks_filters.html
http://docs.ansible.com/ansible/latest/playbooks_tests.html
for validation you might use it as follows:
tasks:
- fail: msg="Variable '{{ item }}' is not a string"
when: string | search("^[a-zA-Z]*$")
I prefer to use the 'assert' module for such cases like this.
- name: Test if the type of 'variable' is string
assert:
that:
- variable is defined
- variable is string
fail_msg: |
variable: {{ variable | d() | to_nice_json }}
seealso: type check examples: https://github.com/ssato/ansible-role-assertive-programming-examples/blob/master/tasks/pre_type_checks.yml
BTW, if you want to define variables with types you want using --extra-vars (-e) option, you need to prepare yaml files define these variables and let them loaded using '#' such like '-e #/path/to/the/yaml_file'.

Ansible - 'Undefined' at beginning and end of Key when map'ing a Attribute

When map'ing a attribute in a list of variables, Ansible is adding a 'Undefined' to the beginning and end of the key.
The variables:
vault_config_listener_params:
- address: "0.0.0.0:8200"
- tls_cert_file: "/etc/ssl/certs/wildcard.crt"
- tls_key_file: "/etc/ssl/certs/wildcard.key"
The debug task:
- debug: var=vault_config_listener_params|map(attribute="tls_cert_file")|list
The output:
ok: [id70118] => {
"vault_config_listener_params|map(attribute=\"tls_cert_file\")|list":
"[Undefined, u'/etc/ssl/certs/wildcard.crt', Undefined]"
}
The maping seems to have worked, as the key path has been extracted. But where are the 'Undefined' coming from?
PS: The variables needs to be a list, as they are looped it in another place with jinja2.
First of all, don't use debug's var when printing arbitrary expressions, use msg instead.
As for your question, map is quite dumb and doesn't do what you don't ask it to, so you actually need to select items with specified attributes defined first, and then get its values:
- debug:
msg: "{{ vault_config_listener_params | selectattr('tls_cert_file','defined') | map(attribute='tls_cert_file') | list }}"

Ansible, set_fact using if then else statement

I am trying to set a variable in Ansible with set_fact at runtime based upon another variable. If uses first value no matter what the actual value is. Here is my code example:
- name: Global_vars - get date info
set_fact:
jm_env: "{{lookup('env', 'Environment')}}"
l_env: "{% if '{{jm_env}}==Develop' %}d{% elif '{{jm_env}}==Staging'%}s{% else %}p{% endif %}"
l_env is d no matter what jm_env is set.
Firstly, dictionaries in YAML are not ordered (and the syntax used by Ansible here is a YAML dictionary), so you have no guarantee Ansible would first set jm_env before proceeding to l_env -- you need to split the assignment into two tasks.
Secondly, your test expressions are incorrect -- '{{jm_env}}==Develop' is a string because it is quoted; and testing if 'string' will always evaluate to true (this is the direct reason you always get d in the output).
Use:
- name: Set the jm_env
set_fact:
jm_env: "{{lookup('env', 'Environment')}}"
- name: Set the l_env
set_fact:
l_env: "{% if jm_env=='Develop' %}d{% elif jm_env=='Staging'%}s{% else %}p{% endif %}"
One of the simple way to set fact based condition example as follows:
- name: Set facts for delete operation results
set_fact:
tr_result: "{{ '{\"status\": \"SUCCESS\"}' if (op_result['output'] == 'Deleted') else '{\"status\" : \"FAILED\"}' }}"
Note: Assume op_result is a dict & already defined.
Code has been tested and working well.

Resources