having an ansible playbook that will run on all hosts including Debian based & RedHat based servers this will install mariadb on RHEL based servers only doing some configuration changes, start the service once the service started handlers are used to change the root password but the problem is handlers seems to be applied on all the hosts instead of RHEL based servers only, when statement is not working with handlers, check the following code:
---
- name: "Install & Configure MariaDB server on RHEL8"
hosts: all
vars:
required_distribution: "RedHat"
required_version: "8"
my_packages:
- mariadb-server
- python3-PyMySQL
tasks:
- name: "check & install MariaDB on RHEL 8 only"
yum:
name: "{{ item }}"
state: present
loop: "{{ my_packages }}"
when: "ansible_distribution == required_distribution and ansible_distribution_major_version == required_version"
- name: "start & enable MariaDb service"
service:
name: mariadb
state: started
enabled: true
when: "ansible_distribution == required_distribution and ansible_distribution_major_version == required_version"
notify:
- root_password
handlers:
- name: root_password
mysql_user:
name: root
password: password
when: "ansible_distribution == required_distribution and ansible_distribution_major_version == required_version"
getting this warning:
RUNNING HANDLER [root_password] ****************************************************************************************************************************************************
task path: /home/student/labs/lab6/lab6.yaml:29
[WARNING]: Module did not set no_log for update_********
changed: [server-b] => {"changed": true, "msg": "Password updated (new style)", "user": "root"}
changed: [server-a] => {"changed": true, "msg": "Password updated (new style)", "user": "root"}
changed: [server-d] => {"changed": true, "msg": "Password updated (new style)", "user": "root"}
changed: [server-c] => {"changed": true, "msg": "Password updated (new style)", "user": "root"}
META: ran handlers
META: ran handlers
what I am considering here is the handler is also applying on ubuntu-a server & giving me "[WARNING]: Module did not set no_log for update_**"
if this warning is not coming from ubuntu-a server then how to remove this and what's the issue in my playbook, is this only applied on RHEL based servers on handlers as well?
I am also looking for some effective way of writing the playbook so that each time I don't have to write when block to filter out my managed hosts it must be checked once (may be at play level) and will apply on all tasks
CodePudding user response:
Given the inventory
shell> cat hosts
host_A
host_B
[test_ubuntu]
host_A ansible_host=10.1.0.184
[test_ubuntu:vars]
ansible_connection=ssh
ansible_user=admin
ansible_become=yes
ansible_become_user=root
ansible_become_method=sudo
ansible_python_interpreter=/usr/bin/python3.9
[test_centos]
host_B ansible_host=10.1.0.74
[test_centos:vars]
ansible_connection=ssh
ansible_user=admin
ansible_become=yes
ansible_become_user=root
ansible_become_method=sudo
ansible_python_interpreter=/bin/python3.6
Q: "Effective way of writing the playbook to filter out my managed hosts."
A: Use inventory plugin constructed. See
shell> ansible-doc -t inventory ansible.builtin.constructed
- Cache the facts. Configure cache, e.g.
shell> cat ansible.cfg
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_cache
fact_caching_prefix = ansible_facts_
fact_caching_timeout = 86400
...
and run the playbook
shell> cat pb2.yml
- hosts: all
tasks:
- debug:
msg: Completed.
This will create the cache
shell> tree /tmp/ansible_cache/
/tmp/ansible_cache/
├── ansible_facts_host_A
└── ansible_facts_host_B
- Create the inventory
shell> tree inventory/
inventory/
├── 01-hosts
└── 02-constructed.yml
0 directories, 2 files
shell> cat inventory/01-hosts
host_A
host_B
[test_ubuntu]
host_A ansible_host=10.1.0.184
[test_ubuntu:vars]
ansible_connection=ssh
ansible_user=admin
ansible_become=yes
ansible_become_user=root
ansible_become_method=sudo
ansible_python_interpreter=/usr/bin/python3.9
[test_centos]
host_B ansible_host=10.1.0.74
[test_centos:vars]
ansible_connection=ssh
ansible_user=admin
ansible_become=yes
ansible_become_user=root
ansible_become_method=sudo
ansible_python_interpreter=/bin/python3.6
shell> cat inventory/02-constructed.yml
plugin: ansible.builtin.constructed
strict: true
groups:
centos_8: ansible_distribution == 'CentOS' and ansible_distribution_major_version == '8'
ubuntu_20: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version == '20'
Test the inventory
shell> ansible-inventory -i inventory --graph
@all:
|--@centos_8:
| |--host_B
|--@test_centos:
| |--host_B
|--@test_ubuntu:
| |--host_A
|--@ubuntu_20:
| |--host_A
|--@ungrouped:
You can see that the plugin constructed created groups centos_8 and ubuntu_20.
- Use the groups in a play. For example,
shell> cat pb3.yml
- hosts: centos_8
tasks:
- setup:
gather_subset: distribution
- debug:
msg: |
ansible_distribution: {{ ansible_distribution }}
ansible_distribution_major_version: {{ ansible_distribution_major_version }}
- debug:
msg: Trigger handler
changed_when: true
notify: root_password
handlers:
- name: root_password
debug:
msg: Change root password
gives
shell> ansible-playbook -i inventory pb3.yml
PLAY [centos_8] ******************************************************************************
TASK [setup] *********************************************************************************
ok: [host_B]
TASK [debug] *********************************************************************************
ok: [host_B] =>
msg: |-
ansible_distribution: CentOS
ansible_distribution_major_version: 8
TASK [debug] *********************************************************************************
changed: [host_B] =>
msg: Trigger handler
RUNNING HANDLER [root_password] **************************************************************
ok: [host_B] =>
msg: Change root password
PLAY RECAP ***********************************************************************************
host_B: ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Q: "The handler is also applying on Ubuntu."
A: In your code, there is no reason for this. For example, given the data
required_distribution: "CentOS"
required_version: "8"
the tasks
- setup:
gather_subset: distribution
- debug:
msg: |
ansible_distribution: {{ ansible_distribution }}
ansible_distribution_major_version: {{ ansible_distribution_major_version }}
give
ok: [host_A] =>
msg: |-
ansible_distribution: Ubuntu
ansible_distribution_major_version: 20
ok: [host_B] =>
msg: |-
ansible_distribution: CentOS
ansible_distribution_major_version: 8
Your condition works as expected
- debug:
msg: |
ansible_distribution is {{ required_distribution }} and
ansible_distribution_major_version is {{ required_version }}
when: "ansible_distribution == required_distribution and ansible_distribution_major_version == required_version"
gives
skipping: [host_A]
ok: [host_B] =>
msg: |-
ansible_distribution is CentOS and
ansible_distribution_major_version is 8
You don't have to quote the condition
when: ansible_distribution == required_distribution and ansible_distribution_major_version == required_version
You can format it
when: ansible_distribution == required_distribution and
ansible_distribution_major_version == required_version
, or even better
when:
- ansible_distribution == required_distribution
- ansible_distribution_major_version == required_version
All options give the same result.
Test the handler. There is no reason to put the condition into the handler when the condition is in the task that will trigger it
handlers:
- name: root_password
debug:
msg: Change root password
The task below will trigger the handler for required_distribution and required_version only
- debug:
msg: Trigger handler
changed_when: true
notify: root_password
when:
- ansible_distribution == required_distribution
- ansible_distribution_major_version == required_version
gives
TASK [debug] *********************************************************************************
skipping: [host_A]
changed: [host_B] =>
msg: Trigger handler
RUNNING HANDLER [root_password] **************************************************************
ok: [host_B] =>
msg: Change root password
PLAY RECAP ***********************************************************************************
- Example of a complete playbook for testing
- hosts: all
gather_facts: false
vars:
required_distribution: "CentOS"
required_version: "8"
tasks:
- setup:
gather_subset: distribution
- debug:
msg: |
ansible_distribution: {{ ansible_distribution }}
ansible_distribution_major_version: {{ ansible_distribution_major_version }}
- debug:
msg: |
ansible_distribution is {{ required_distribution }} and
ansible_distribution_major_version is {{ required_version }}
when: "ansible_distribution == required_distribution and ansible_distribution_major_version == required_version"
- debug:
msg: |
ansible_distribution is {{ required_distribution }} and
ansible_distribution_major_version is {{ required_version }}
when: ansible_distribution == required_distribution and ansible_distribution_major_version == required_version
- debug:
msg: |
ansible_distribution is {{ required_distribution }} and
ansible_distribution_major_version is {{ required_version }}
when: ansible_distribution == required_distribution and
ansible_distribution_major_version == required_version
- debug:
msg: |
ansible_distribution is {{ required_distribution }} and
ansible_distribution_major_version is {{ required_version }}
when:
- ansible_distribution == required_distribution
- ansible_distribution_major_version == required_version
- debug:
msg: Trigger handler
changed_when: true
notify: root_password
when:
- ansible_distribution == required_distribution
- ansible_distribution_major_version == required_version
handlers:
- name: root_password
debug:
msg: Change root password
- The tree of this project
shell> tree .
.
├── ansible.cfg
├── hosts
├── inventory
│ ├── 01-hosts
│ └── 02-constructed.yml
├── pb2.yml
├── pb3.yml
└── pb.yml
1 directory, 7 files
CodePudding user response:
I don't think that message indicates the handler is running on Ubuntu, but it's hard to say without seeing your inventory and other more info.
Anyways, if you want to only apply when "when" once (good impulse, you have two options:
Put all of your tasks in a "block" and apply the when to the block. You shouldn't even need then when on the handler if all of the tasks are skipped using the same when.
If what you really want is to bail on the play altogether on non RedHat 8 hosts, you could use end_host like this, as the first task in your play.
# Example showing how to end the play for specific targets
- name: End the play for hosts are not the desired versions
ansible.builtin.meta: end_host
when: ansible_distribution != required_distribution or ansible_distribution_major_version != required_version