I have my playbook as below:
---
- hosts: myser
tasks:
- name: Checking.
win_command: mycommand
register: win_command_result
- set_fact:
myvar={{win_command_result.stdout | regex_search('\\d+')}}
register: myvar_result
- debug:
var: myvar_result.ansible_facts.ple
- name: Checking Condition
win_command: ipconfig
register: ipconfig
when: myvar_result.ansible_facts.ple < 5000
- debug:
var: ipconfig
And below is output.
I am getting two different values per server but the task Checking Condition gets skipped. Based on the value, for one server it should skip and for another it should execute.
PLAY [myser]
*******************************************************
TASK [Gathering Facts]
**************************************************
ok: [ser1]
ok: [ser2]
TASK [Checking]
****************************
changed: [ser1]
changed: [ser2]
TASK [set_fact]
*********************************************************
ok: [ser1]
ok: [ser2]
TASK [debug]
************************************************************
ok: [ser1] => {
"myvar_result.ansible_facts.ple": "232"
}
ok: [ser2] => {
"myvar_result.ansible_facts.ple": "378416"
}
TASK [Checking Condition]
**********************************************
skipping: [ser1]
skipping: [ser2]
TASK [debug]
************************************************************
ok: [ser1] => {
"ipconfig": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
ok: [ser2] => {
"ipconfig": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
PLAY RECAP
**************************************************************
ser2 : ok=5 changed=1 unreachable=0 failed=0
ser1 : ok=5 changed=1 unreachable=0 failed=0
I want to use myvar_result.ansible_facts.ple in when condition. So idea here is if myvar_result.ansible_facts.ple crosses value of 5000 then execute "checking name"
Am I missing something here? How to get it work?
It is working properly, but you are comparing a string with an integer.
As you can see in your output:
"myvar_result.ansible_facts.ple": "232"
"myvar_result.ansible_facts.ple": "378416"
your values are strings (as is any command result passed in stdout, as well as the output of the regex_search filter).
Cast them to integer before doing the comparison in the conditional:
- name: Checking Condition
win_command: ipconfig
register: ipconfig
when: myvar_result.ansible_facts.ple|int < 5000
Related
I want to run a task only if at the previous task it contains a specific output.
E.g. I am checking if the status is "running". If yes, then run a command
My playbook:
- name: 'Backup'
hosts: localhost
tasks:
-
name: 'CHeck_Status'
shell: tool ha status |grep -i Status
register: service_status
-
debug:
var: service_status.stdout_lines
-
name: 'Run ls'
shell: ls -ltr
when: service_status.stdout_lines == "Status*running"
register: output
-
debug:
var: output
The output of the command is
PLAY [Backup] ******************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************
ok: [localhost]
TASK [CHeck_Status] *****************************************************************************************************************************************************
changed: [localhos]
TASK [debug] ***************************************************************************************************************************************************************
ok: [localhost] => {
"service_status.stdout_lines": [
"Status: running",
"Status: running"
]
}
TASK [Run ls] **************************************************************************************************************************************************************
skipping: [localhost]
TASK [debug] ***************************************************************************************************************************************************************
ok: [localhost] => {
"output": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
PLAY RECAP *****************************************************************************************************************************************************************
localhost : ok=4 changed=1 unreachable=0 failed=0
it always fails. Any help on how can I do the conditional for when?
Also if I try this conditional I get the below error:
The offending line appears to be:
shell: ls -ltr
when: service_status.stdout_lines == "'Status: running'"
^ here
Thank you
Test the item 'Status: running' is in the list, e.g.
- name: Run ls
shell: ls -ltr
register: output
when: "'Status: running' in service_status.stdout_lines"
If, during the execution of the playbook, we change the host file in host_vars (i.e. add a new variable), how then can we get this variable in hostvars in the current execution of the playbook? When you run it again, it appears in hostvars.
UPDATE 01:
Here's an example, it doesn't work (
The task Debug 3 should display test_1 instead of VARIABLE IS NOT DEFINED!
- name: Test
hosts: mon
tasks:
- name: Debug 1
debug:
var: hostvars.mon.test_1
- name: Add vars for host_vars
delegate_to: 127.0.0.1
blockinfile:
path: "{{ inventory_dir }}/host_vars/{{ inventory_hostname }}.yml"
marker: "# {mark}: {{ item.key }}"
block: |
{{ item.key }}: {{ item.value }}
with_dict:
- {test_1: "test_1"}
- name: Debug 2
debug:
var: hostvars.mon.test_1
- name: Clear facts
meta: clear_facts
- name: Refresh inventory
meta: refresh_inventory
- name: Setup
setup:
- name: Debug 3
debug:
var: hostvars.mon.test_1
Result:
PLAY [Test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [mon]
TASK [Debug 1] *****************************************************************
ok: [mon] => {
"hostvars.mon.test_1": "VARIABLE IS NOT DEFINED!"
}
TASK [Add vars for host_vars] **************************************************
changed: [mon -> 127.0.0.1] => (item={'key': 'test_1', 'value': 'test_1'})
TASK [Debug 2] *****************************************************************
ok: [mon] => {
"hostvars.mon.test_1": "VARIABLE IS NOT DEFINED!"
}
TASK [Setup] *******************************************************************
ok: [mon]
TASK [Debug 3] *****************************************************************
ok: [mon] => {
"hostvars.mon.test_1": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP *********************************************************************
mon : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
On restart:
PLAY [Test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [mon]
TASK [Debug 1] *****************************************************************
ok: [mon] => {
"hostvars.mon.test_1": "test_1"
}
TASK [Add vars for host_vars] **************************************************
ok: [mon -> 127.0.0.1] => (item={'key': 'test_1', 'value': 'test_1'})
TASK [Debug 2] *****************************************************************
ok: [mon] => {
"hostvars.mon.test_1": "test_1"
}
TASK [Setup] *******************************************************************
ok: [mon]
TASK [Debug 3] *****************************************************************
ok: [mon] => {
"hostvars.mon.test_1": "test_1"
}
PLAY RECAP *********************************************************************
mon : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Maybe there is a way to change hostvars manually in the process?
You can ask Ansible to reread inventory (including host_vars). Generally I'd say that changing inventory on-fly is a code smell, but there are few valid cases.
- name: Refreshing inventory, SO copypaste
meta: refresh_inventory
I have a string like this
"3000 Native active Po121, Po123"
I need to check if 3000 is present and active is present in this string. If not assert
I wanted to use when command and set_fact. Check if the variable present and assert. (which I haven't finished). Right now I am just printing a message. This is not the good to way to do it. If I can assert directly when 3000 and active not present, that would be great.
Also another question about when, if it matches first condition, it prints the debug message. It should match both right as its an and?
var:
vlan_output: "3000 Native active Po121, Po123"
item={vlan_id: 3000, state: present}
I tried like this
- name: Validate vlan for delete
debug: msg="VLAN FAILED "
when: item.state == "present" and "item.vlan_id not in vlan_output"
We can directly use the when condition if "3000" and "active" is present in the output
I believe the vlan_id would be a registered variable so the value can be accessed using vlan_id.stdout.
The below play works with when and assert module of ansible
for assertion +ve:
command -->
ansible-playbook tmp.yml --extra-vars "vlan_output='3000 active'"
playbook -->
---
- hosts: localhost
tasks:
- debug:
msg: "Strings Matched"
when: vlan_output | search("3000") and vlan_output | search("active")
- debug:
var: vlan_output
- assert:
that:
- "'3000' in vlan_output"
- "'active' in vlan_output"
output -->
ok: [localhost] => {
"msg": "Strings Matched"
}
TASK [debug] *****************************************************************************************************************************
ok: [localhost] => {
"vlan_output": "3000 active"
}
TASK [assert] ****************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY RECAP *******************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
for assertion -ve:
command -->
ansible-playbook tmp.yml --extra-vars "vlan_output='is'"
playbook -->
---
- hosts: localhost
tasks:
- debug:
msg: "Strings Matched"
when: vlan_output is not search("3000") and vlan_output is not search("active")
- debug:
var: vlan_output
- assert:
that:
- "'3000' not in vlan_output"
- "'active' not in vlan_output"
output -->
PLAY [localhost] *******************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [localhost]
TASK [debug] ***********************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Strings Matched"
}
TASK [debug] ***********************************************************************************************************************************************************
ok: [localhost] => {
"vlan_output": "is"
}
TASK [assert] **********************************************************************************************************************************************************
ok: [localhost] => {
"changed": false,
"msg": "All assertions passed"
}
PLAY RECAP *************************************************************************************************************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
There's a couple of issues here
Firstly, you should not quote "item.vlan_id not in vlan_output" - this is a string and will always evaluate to True.
Secondly, the not in test requires the operands to be type string (currently vlan_id is an integer).
You should see the behaviour you are looking for with these changes:
vars:
vlan_output: "3000 Native active Po121, Po123"
item:
vlan_id: "3000"
state: present
tasks:
- debug: msg="VLAN FAILED"
when: item.state == "present" and item.vlan_id not in vlan_output
I have two identical tasks in the same playbook:
when: var == "true"
when: var == "false"
Both tasks are using register: result, but first one fails and second one succeeds.
I tried using block: and not just when: and the behaviour is the same.
bug-when.yml
---
- hosts: localhost
tasks:
- name: when true
debug:
msg: "this is true"
register: result
when: var == "true"
- name: when false
debug:
msg: "this is false"
register: result
when: var == "false"
- name: print result
debug:
msg: "{{ result }}"
Example running it:
ansible-playbook bug-when.yml -e var=true
PLAY [localhost] ***************************************************************
TASK [setup] *******************************************************************
Thursday 09 May 2019 18:51:35 +0000 (0:00:02.018) 0:00:02.018 **********
ok: [localhost]
TASK [when true] ***************************************************************
Thursday 09 May 2019 18:51:35 +0000 (0:00:00.437) 0:00:02.456 **********
ok: [localhost] => {
"msg": "this is true"
}
TASK [when false] **************************************************************
Thursday 09 May 2019 18:51:35 +0000 (0:00:00.027) 0:00:02.483 **********
skipping: [localhost]
TASK [print result] ************************************************************
Thursday 09 May 2019 18:51:36 +0000 (0:00:00.023) 0:00:02.506 **********
ok: [localhost] => {
"msg": {
"changed": false,
"skip_reason": "Conditional check failed",
"skipped": true
}
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
Second example running it:
ansible-playbook bug-when.yml -e var=false
PLAY [localhost] ***************************************************************
TASK [setup] *******************************************************************
Thursday 09 May 2019 18:52:01 +0000 (0:00:02.019) 0:00:02.019 **********
ok: [localhost]
TASK [when true] ***************************************************************
Thursday 09 May 2019 18:52:01 +0000 (0:00:00.453) 0:00:02.472 **********
skipping: [localhost]
TASK [when false] **************************************************************
Thursday 09 May 2019 18:52:01 +0000 (0:00:00.024) 0:00:02.497 **********
ok: [localhost] => {
"msg": "this is false"
}
TASK [print result] ************************************************************
Thursday 09 May 2019 18:52:02 +0000 (0:00:00.028) 0:00:02.525 **********
ok: [localhost] => {
"msg": {
"changed": false,
"msg": "this is false"
}
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0
To expand upon what #b.enoit.be said:
When you have a task like this:
- name: some task
debug:
msg: this is an example
when: false
register: result
This will update result even if the task is skipped. This is what permits you, in a subsequent task, to see if this task was skipped or not:
- name: check if task was skipped
debug:
msg: previous task was skipped
when: result is skipped
Consider registering a different variable in each task, and then:
- name: when true
debug:
msg: "this is true"
register: result1
when: var == "true"
- name: when false
debug:
msg: "this is false"
register: result2
when: var == "false"
- name: print result
debug:
msg: "{{ result1.msg if result2 is skipped else result2.msg }}"
The behaviour you see here happens because the tasks are always registered, mostly because you can self reference a task register in itself, and this behaviour would fail if the tasks was not always registering itself.
So what you need to do is to have two different register handle and act upon the result and skipped attributes of them to display your message properly.
Here is the playbook:
---
- hosts: localhost
tasks:
- name: when true
debug:
msg: "this is true"
register: result_is_true
when: var == "true"
- name: when false
debug:
msg: "this is false"
register: result_is_false
when: var == "false"
- name: print result
debug:
msg: "{{ result_is_true if result_is_false is skipped else result_is_false }}"
Here is the run when var is true
$ ansible-playbook so.yml -e var=true
PLAY [localhost] *******************************************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************************************
ok: [host1]
TASK [when true] *******************************************************************************************************************************************************************************************
ok: [host1] => {
"msg": "this is true"
}
TASK [when false] ******************************************************************************************************************************************************************************************
skipping: [host1]
TASK [print result] ****************************************************************************************************************************************************************************************
ok: [host1] => {
"msg": {
"changed": false,
"failed": false,
"msg": "this is true"
}
}
PLAY RECAP *************************************************************************************************************************************************************************************************
host1 : ok=3 changed=0 unreachable=0 failed=0
And here is the result when var is false
$ ansible-playbook so.yml -e var=false
PLAY [localhost] *******************************************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************************************************
ok: [host1]
TASK [when true] *******************************************************************************************************************************************************************************************
skipping: [host1]
TASK [when false] ******************************************************************************************************************************************************************************************
ok: [host1] => {
"msg": "this is false"
}
TASK [print result] ****************************************************************************************************************************************************************************************
ok: [host1] => {
"msg": {
"changed": false,
"failed": false,
"msg": "this is false"
}
}
PLAY RECAP *************************************************************************************************************************************************************************************************
host1 : ok=3 changed=0 unreachable=0 failed=0
Needless to say: I would guess you simplified your issue for a MCVE, but your play can actually be as simple as
---
- hosts: localhost
tasks:
- name: print result
debug:
msg: "{{ 'this is true' if var == true else 'this is false' }}"
Which runs:
$ ansible-playbook so.yml -e var=false
PLAY [localhost] ***********************************************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************************************
ok: [host1]
TASK [print result] ********************************************************************************************************************************************************************************
ok: [host1] => {
"msg": "this is false"
}
PLAY RECAP *****************************************************************************************************************************************************************************************
host1 : ok=2 changed=0 unreachable=0 failed=0
$ ansible-playbook so.yml -e var=true
PLAY [localhost] ***********************************************************************************************************************************************************************************
TASK [Gathering Facts] *****************************************************************************************************************************************************************************
ok: [host1]
TASK [print result] ********************************************************************************************************************************************************************************
ok: [host1] => {
"msg": "this is true"
}
PLAY RECAP *****************************************************************************************************************************************************************************************
host1 : ok=2 changed=0 unreachable=0 failed=0
And for reference here is a jinja inline if-expression question: https://stackoverflow.com/a/14215034/2123530
Background information:
I need to dynamically set a variable on a set of hosts (web1) and then check the same on a different set of hosts. Once they match, I can perform further actions.
Code
My hosts file looks like this:
[web1]
web1.ttv.mydomain.com
[web1:vars]
primary_count=0
[web2]
web2.ttv.mydomain.com
[web2:vars]
secondary_count=0
[web]
web1
web2
And this is the playbook:
- hosts: web1
tasks:
- name: query primary servers
shell: psql -U widget widget -c 'SELECT COUNT(*) FROM test' -t
register: result
- set_fact: primary_count={{result.stdout}}
- hosts: web
tasks:
- name: retrieve variable from previous play
shell: echo hello
- debug: var=primary_count
This playbook produces the following results:
TASK [setup] *******************************************************************
ok: [web1.ttv.mydomain.com]
TASK [query primary servers] ****************************************************
changed: [web1.ttv.mydomain.com]
TASK [debug] *******************************************************************
ok: [web1.ttv.mydomain.com] => {
"primary_count": 0
}
TASK [set_fact] ****************************************************************
ok: [web1.ttv.mydomain.com]
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [web1.ttv.mydomain.com]
ok: [web2.ttv.mydomain.com]
TASK [retrieve variable from previous play] ************************************
changed: [web1.ttv.mydomain.com]
changed: [web2.ttv.mydomain.com]
TASK [debug] *******************************************************************
ok: [web2.ttv.mydomain.com] => {
"primary_count": "VARIABLE IS NOT DEFINED!"
}
ok: [web1.ttv.mydomain.com] => {
"primary_count": " 2"
}
Problem
Now I need a way to do the following in the second play:
run the same select statement on web2.ttv.mydomain.com
save the value to secondary_count variable
check if secondary_count matches the value of the "primary_count" on web1.mydomain.com. (Notice how right now, since I'm looping through more than just the web1 servers in play 2, I get an error about the "primary_count" not being defined on web2 servers.)
when the values match then restart various services on secondary
Questions:
How do I evaluate the "primary_count" variable on the web1 host with the matching web2 host name on? In the future my hosts file will look like this:
[web1]
web1.ttv.mydomain.com
web1.ttx.mydomain.com
[web2]
web2.ttv.mydomain.com
web2.ttx.mydomain.com
[web]
web1
web2
So I need to write some sort of an eval statement that does this:
(pseudocode)
while looping through ***ALL*** web servers
if primary_count on web1.ttv.mydomain.com matches secondary_count on web2.ttx.mydomain.com then
restart service x on web2.ttx.mydomain.com
else
wait a few seconds and repeat
end
end loop
I think the solution lies with my hosts / inventory file. Somehow I need this playbook to run on all web1 servers and all web2 servers... but I also need a way to associate web1.ttv with just web2.ttv and web1.ttx with just web2.ttx and so on.
I'm just learning ansible as I go along, so if this approach is entirely wrong, please let me know!
Thanks.
EDIT 1
On doing some research about group_vars, it looks like group_vars doesn't really help me because I still have the same problem. While looping through all web servers (play 2), the variables I set on web1 servers in play 1 are not visible from web2 servers.
EDIT 2:
- hosts: web1
tasks:
- name: query primary servers
shell: psql -U widget widget -c 'SELECT COUNT(*) FROM widget' -t
register: result
- local_action: shell echo {{ result.stdout }} > varacrossplay.txt
That fails on the local_action line with this error:
fatal: [web1.ttv.mydomain.com -> localhost]: FAILED! => {"changed": true, "cmd": "echo 2 > varacrossplay.txt", "delta": "0:00:00.001641", "end":
": "echo 2 > varacrossplay.txt", "_uses_shell": true, "chdir": null, "creates": null, "executable": null, "removes": null, "warn": true}, "mod
1: cannot create varacrossplay.txt: Permission denied", "stdout": "", "stdout_lines": [], "warnings": []}
Try with this example playbook:
[jenkins#batman ansible]$ cat testplaybook.yml
- hosts: web1
tasks:
- name: query primary servers
shell: echo "TEST"
register: result
- local_action: shell echo {{ result.stdout }} > varacrossplay.txt
- hosts: web
tasks:
- local_action: shell cat varacrossplay.txt
register: result
- set_fact: other_fact="{{ result.stdout }}"
- debug: var=other_fact
With my servers all works fine xD
[jenkins#batman ansible]$ ansible-playbook -i inventory testplaybook.yml
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [10.0.0.100]
TASK [query primary servers] ***************************************************
changed: [10.0.0.100]
TASK [command] *****************************************************************
changed: [10.0.0.100 -> localhost]
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [10.0.0.2]
ok: [10.0.0.1]
TASK [command] *****************************************************************
changed: [10.0.0.1 -> localhost]
changed: [10.0.0.2 -> localhost]
TASK [set_fact] ****************************************************************
ok: [10.0.0.1]
ok: [10.0.0.2]
TASK [debug] *******************************************************************
ok: [10.0.0.2] => {
"other_fact": "TEST"
}
ok: [10.0.0.1] => {
"other_fact": "TEST"
}
PLAY RECAP *********************************************************************
10.0.0.100 : ok=3 changed=2 unreachable=0 failed=0
10.0.0.1 : ok=4 changed=1 unreachable=0 failed=0
10.0.0.2 : ok=4 changed=1 unreachable=0 failed=0