Ansible set_facts based on OS version not working - ansible

I want to set the patch based on the OS version. came up with this playbook in Ansible version 2.8. but its giving The task includes an option with an undefined variable. error message in the debug line.
---
- hosts: all
gather_facts: yes
vars:
patch_name_8: 'centos8-updates'
patch_name_7: 'centos7-updates'
tasks:
- name: Set fact for CentOS 7
set_fact:
install_patch_name: "{{ patch_name_7 }}"
when: ansible_distribution_major_version == 7
- name: Set fact for CentOS 8
set_fact:
install_patch_name: "{{ patch_name_8 }}"
when: ansible_distribution_major_version == 8
- name: patch name display
debug:
msg: "install {{ install_patch_name }}"
How to set the install_patch_name variable value based on the OS version?
adding the error message:
TASK [patch name display] ************************************************************************************************************
fatal: [host01]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'install_patch_name' is undefined\n\nThe error appears to be in 't.yaml': line 23, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n
- name: patch name display\n ^ here\n"}
thanks

TLDR;
Use
when: ansible_distribution_major_version == "8"
or
when: ansible_distribution_major_version | int == 8
Explanation
Note: all following examples have been played against a centos:8 docker image.
The fact your are looking after is returned as a string :
[root#f6408271fc8c ~]# ansible localhost -m setup -a filter=ansible_distribution_major_version
localhost | SUCCESS => {
"ansible_facts": {
"ansible_distribution_major_version": "8"
},
"changed": false
}
Variables keep their types when using comparison and need to be correctly casted if need be, as demonstrated by the following playbook.
---
- hosts: localhost
tasks:
- name: default compare
debug:
msg: Comparison is true
when: ansible_distribution_major_version == 8
- name: compare as strings
debug:
msg: Comparison is true
when: ansible_distribution_major_version == "8"
- name: compare as ints
debug:
msg: Comparison is true
when: ansible_distribution_major_version | int == 8
Which gives
[root#f6408271fc8c ~]# ansible-playbook play.yml
PLAY [localhost] **************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [default compare] ********************************************************************************************************************************************************************************************
skipping: [localhost]
TASK [compare as strings] *****************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Comparison is true"
}
TASK [compare as ints] ********************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Comparison is true"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0

Related

How to use custom fact in Ansible dynamically to evaluate conditional statement

I'm trying to evaluate the condition
hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']
The external_ip is set on the host_variable . I have set the ipify_ip on the custom facts and trying to evaluate this condition
when: hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']
I have tried this option also but it failed there too
when: hostvars[inventory_hostname].external_ip == {{ ipify_ip }}
Here is the complete playbook file
- name: Get public ip for the host
ipify_facts:
api_url: https://api.ipify.org/
timeout: 20
tags: always
- name: Set fact
set_fact:
ipify_ip: "{{ ipify_public_ip }}"
tags: always
- name: ipify_ip External IP
debug:
var: ipify_ip
tags: always
- name: is extrnal_ip in hostvars is same with ipify_ip
debug:
var=hostvars[inventory_hostname].external_ip
when: hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']
tags: always
The error
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']' failed. The error was: error while evaluating conditional (hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']): 'dict object' has no attribute 'ipify_ip'\n\nThe error appears to be in '/home/anish/playbook/prereqs.yml': line 29, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: extrnal_ip on hostvars\n ^ here\n"}
What is the right way to do this ??
Simply use the variables. For example, given the inventory
shell> cat hosts
host01 external_ip=1.2.3.4
and the playbook
shell> cat playbook.yml
- hosts: host01
tasks:
- set_fact:
ipify_ip: 1.2.3.4
- debug:
var: ipify_ip
- debug:
var: external_ip
- debug:
msg: "{{ external_ip }} is equal to {{ ipify_ip }}"
when: external_ip == ipify_ip
gives
shell> ansible-playbook -i hosts playbook.yml
PLAY [host01] *******************************
TASK [set_fact] *****************************
ok: [host01]
TASK [debug] ********************************
ok: [host01] =>
ipify_ip: 1.2.3.4
TASK [debug] ********************************
ok: [host01] =>
external_ip: 1.2.3.4
TASK [debug] ********************************
ok: [host01] =>
msg: 1.2.3.4 is equal to 1.2.3.4
PLAY RECAP **********************************
host01: ok=4 changed=0 unreachable=0 failed=0 ...

Ansible loop giving warning found a duplicate dict key (when). Using last defined value only

I am trying to iterate over an array and assign the value to variables hooks_enabled, workflow_artifact_id, workflow_version, one by one in every iteration and perform a specific task (currently debug, later change to Helm install command).
Code:
---
- name: Executing Ansible Playbook
hosts: localhost
become: yes
become_user: someuser
pre_tasks:
- include_vars: global_vars.yaml
- name: Print some debug information
set_fact:
all_vars: |
Content of vars
--------------------------------
{{ vars | to_nice_json }}
tasks:
- name: Iterate over an array
set_fact:
hooks_enabled: '{{ array_item1_hooks_enabled }}'
workflow_artifact_id: '{{ array_item1_workflow_artifact_id }}'
workflow_version: '{{ array_item1_workflow_version }}'
when: "item == 'array_item1'"
set_fact:
hooks_enabled: '{{ array_item2_hooks_enabled }}'
workflow_artifact_id: '{{ array_item2_workflow_artifact_id }}'
workflow_version: '{{ array_item2_workflow_version }}'
when: "item == 'array_item2'"
with_items: "{{ array}}"
# Change debug with helm install command
- debug:
msg: " id= '{{ workflow_artifact_id }}'"
The issue I am facing is, only the last when is considered and others are skipped
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
[WARNING]: While constructing a mapping from /c/ansible-test/second.yaml, line 16, column 7, found a duplicate dict key (set_fact). Using last defined value only.
[WARNING]: While constructing a mapping from /c/ansible-test/second.yaml, line 16, column 7, found a duplicate dict key (when). Using last defined value only.
PLAY [Executing Ansible Playbook] *********************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [include_vars] ***********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [Print some debug information] *******************************************************************************************************************************************************************************
ok: [localhost]
TASK [Iterate over an array] **************************************************************************************************************************************************************************************
skipping: [localhost] => (item=array_item1)
ok: [localhost] => (item=array_item2)
skipping: [localhost] => (item=array_item3)
skipping: [localhost] => (item=array_item4)
skipping: [localhost] => (item=array_item5)
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": " id= 'algorithm-Workflow'"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=5 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
How do I modify the block to enable all the when statement execute and later use helm install command to take the variables one by one.
I would go with a dynamic variable construction using the vars lookup.
Something along the lines of:
- set_fact:
hooks_enabled: "{{ lookup('vars', item ~ '_hooks_enabled') }}"
workflow_artifact_id: "{{ lookup('vars', item ~ '_workflow_artifact_id') }}"
workflow_version: "{{ lookup('vars', item ~ '_workflow_version') }}"
when: "item in ['array_item1', 'array_item2']"
with_items: "{{ array }}"

How to access status in ansible_facts.services?

I am trying to Stop and/or Disable a systemd service if it is running and/or enabled on the remote host.
Contents of tasks/main.yml:
---
- name: Populate service facts
service_facts:
- name: Display selected service
debug:
var: ansible_facts.services[serviceToDisplay]
loop: "{{ disable_services }}"
loop_control:
loop_var: serviceToDisplay
vars:
disable_services:
- cups.service
- cups
- name: Stop and Disable service if it is running or enabled
systemd:
name: cups.service
enabled: false
state: stopped
when:
- "serviceToDisable is defined"
- "serviceToDisable.status == 'enabled'"
loop: "{{ disable_services }}"
loop_control:
loop_var: serviceToDisable
vars:
disable_services:
- cups.service
- cups
become: true
...
Results:
PLAY [configServerGroup] *************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [radicale.jlhimpel.net]
TASK [example : Populate service facts] **********************************************************************************************************************
ok: [radicale.jlhimpel.net]
TASK [example : Display selected service] ********************************************************************************************************************
ok: [radicale.jlhimpel.net] => (item=cups.service) => {
"ansible_facts.services[serviceToDisplay]": {
"name": "cups.service",
"source": "systemd",
"state": "running",
"status": "enabled"
},
"ansible_loop_var": "serviceToDisplay",
"serviceToDisplay": "cups.service"
}
ok: [radicale.jlhimpel.net] => (item=cups) => {
"ansible_facts.services[serviceToDisplay]": {
"name": "cups",
"source": "sysv",
"state": "running"
},
"ansible_loop_var": "serviceToDisplay",
"serviceToDisplay": "cups"
}
TASK [example : Stop and Disable service if it is running or enabled] ****************************************************************************************
fatal: [radicale.jlhimpel.net]: FAILED! => {"msg": "The conditional check 'serviceToDisable.status == 'enabled'' failed. The error was: error while evaluating conditional (serviceToDisable.status == 'enabled'): 'str object' has no attribute 'status'\n\nThe error appears to be in '/home/jwhimpel/ansible/roles/example/tasks/main.yml': line 16, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Stop and Disable service if it is running or enabled\n ^ here\n"}
PLAY RECAP ***************************************************************************************************************************************************
radicale.jlhimpel.net : ok=3 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Ansible version: 2.9.14-1.fc32 on Fedora
How should I go about checking if the status == enabled or the state == running?
Note: The service may optionally not be present in ansible_facts.service. It may also optionally not be running and/or not enabled. I am attempting to make the tasks idempotent.
Thanks
Your second task should be as below, please notice the name clause and the when section:
- name: Stop and Disable service if it is running or enabled
systemd:
name: "{{ ansible_facts.services[serviceToDisable]['name'] }}"
enabled: false
state: stopped
when:
- serviceToDisable is defined
- ansible_facts.services[serviceToDisable]['status'] == 'enabled'
loop: "{{ disable_services }}"
loop_control:
loop_var: serviceToDisable
vars:
disable_services:
- cups.service
- cups
become: true
Not sure why you have defined two times the same service (cups.service and cups), but I guess you have your good reasons.

Or condition is not working with set_facts in my playbook

I created one playbook to run the tasks based on the test case so I have created like below
Here when I pass the ansible-playbook playbook.yml -e stage=1, it's skipping all the tasks, and when I debug the test_case* values I could see both are in a false state, So can some help me to work this code.
---
- name: test
hosts: localhost
tasks:
- name: setting the level
set_fact:
test_case_1: "{{ stage == 1 }}"
test_case_2: "{{ stage == 1 or stage == 2 }}"
- name: "running ls command"
shell: "ls -l"
register: testing
when:
- test_case_1 == true
- debug:
msg: "{{ testing.stdout_lines }}"
when:
- test_case_1 == true
- name: "kickoff"
shell: "df -Th"
register: kick
when:
- test_case_2 == true
- name: "printing kickoff"
debug:
msg: "{{ kick.stdout_lines }}"
when:
- test_case_2 == true
Below is the error results which I am getting
[root#server ~]# ansible-playbook playbook.yml -e stage=1
PLAY [test] ***********************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************
ok: [localhost]
TASK [setting the level] **********************************************************************************************
ok: [localhost]
TASK [running ls command] *********************************************************************************************
skipping: [localhost]
TASK [debug] **********************************************************************************************************
skipping: [localhost]
TASK [kickoff] ********************************************************************************************************
skipping: [localhost]
TASK [printing kickoff] ***********************************************************************************************
skipping: [localhost]
PLAY RECAP ************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=4 rescued=0 ignored=0
[root#server ~]#
expected results should be, it should execute all the tasks from the play.
Your problem is that you are performing an integer comparison (stage == 1), but when you provide a value on the command line via -e stage=1, you are setting a string value.
You probably want to case the value of stage to an integer using the int filter.
---
- name: test
hosts: localhost
tasks:
- name: setting the level
set_fact:
test_case_1: "{{ stage|int == 1 }}"
test_case_2: "{{ stage|int == 1 or stage|int == 2 }}"
With this change, things seem to work as expected.
Unrelated to your question, but you could rewrite the second test like this:
{{ stage|int in [1, 2] }}
That simplifies things a bit.

Ansible error: The task includes an option with an undefined variable

Below is how my complete helpA.yml playbook looks like:
- hosts: localhost
tasks:
- name: "Construct File Path {{ inventory_hostname }} before Deployment."
tags: validate
include_vars:
file: "{{ item }}"
with_fileglob:
- "vars/{{ Layer }}_*.yaml"
- name: "set_fact"
tags: validate
set_fact:
fpath_APP: "{{ fpath_APP + [ BASEPATH ~ '/' ~ vars[item.split('.')[1]] ~ '/' ~ item | basename ] }}"
when: Layer == 'APP'
with_items:
- "{{ Source_Filenames.split(',') }}"
vars:
fpath_APP: []
- debug: var=fpath_{{ Layer }}
I'm getting the below syntax error running the yml.
$ ansible-playbook /app/helpA.yml --tags validate -e
"Source_Filenames=/tmp/logs/filename1.src,/tmp/logs/33211.sql,/app/Jenkins/file1.mrt
Layer=APP" [WARNING]: provided hosts list is empty, only localhost is
available. Note that the implicit localhost does not match 'all'
PLAY [localhost]
TASK [Construct File Path localhost before Deployment.]
************************************************************************************************* ok: [localhost] => (item=/app/vars/APP_BASE_vars.yaml)
TASK [set_fact]
*************************************************************************************************************************************************************** fatal: [localhost]: FAILED! => {"msg": "The task includes an option
with an undefined variable. The error was: 'dict object' has no
attribute u'src'\n\nThe error appears to be in '/app/helpA.yml': line
12, column 6, but may\nbe elsewhere in the file depending on the exact
syntax problem.\n\nThe offending line appears to be:\n\n\n - name:
\"set_fact\"\n ^ here\n"}
PLAY RECAP
******************************************************************************************************************************************************************** localhost : ok=1 changed=0 unreachable=0
failed=1 skipped=0 rescued=0 ignored=0
I'm on the latest version on of ansible and python 2.7.5

Resources