Setup
I have several roles which declare role dependencies and sometimes use handlers from roles they depend on. A simplified version of my setup looks like this (This is the output of head inventory **/*.yml and it shows all path names and the full contents of the files):
==> inventory <==
[app]
server1 ansible_host=192.168.2.113
[db]
server2 ansible_host=192.168.2.153
==> playbook.yml <==
- hosts: all
roles:
- { role: app, when: "inventory_hostname in groups['app']" }
- { role: db, when: "inventory_hostname in groups['db']" }
==> roles/app/handlers/main.yml <==
- name: app handler
command: echo app handler
==> roles/app/meta/main.yml <==
dependencies: [base]
==> roles/app/tasks/main.yml <==
- command: /bin/true
notify: [app handler, base handler]
==> roles/base/handlers/main.yml <==
- name: base handler
command: echo base handler
==> roles/base/tasks/main.yml <==
- command: /bin/true
==> roles/db/handlers/main.yml <==
- name: db handler
command: echo db handler
==> roles/db/meta/main.yml <==
dependencies: [base]
==> roles/db/tasks/main.yml <==
- command: /bin/true
notify: [db handler, base handler]
Now I run ansible-playbook -i inventory playbook.yml which results in
PLAY [all] **********************************************************************
TASK [Gathering Facts] **********************************************************
ok: [server1]
ok: [server2]
TASK [base : command] ***********************************************************
skipping: [server2]
changed: [server1]
TASK [app : command] ************************************************************
skipping: [server2]
changed: [server1]
TASK [base : command] ***********************************************************
changed: [server2]
TASK [db : command] *************************************************************
skipping: [server1]
changed: [server2]
RUNNING HANDLER [base : base handler] *******************************************
skipping: [server2]
changed: [server1]
RUNNING HANDLER [app : app handler] *********************************************
changed: [server1]
RUNNING HANDLER [db : db handler] ***********************************************
changed: [server2]
PLAY RECAP **********************************************************************
server1 : ok=5 changed=4 unreachable=0 failed=0
server2 : ok=4 changed=3 unreachable=0 failed=0
Problem
My problem is that I expected both servers to execute the base handler. But apparently it is skipped on server2. If I add -v to the ansible command I get the unhelpful comment that skipping: [server2] => {"changed": false, "skip_reason": "Conditional result was False"}.
What also puzzles me is that the base role seems to be included twice and each server skips one or the other inclusion of the role respectively.
Question
Is there any way I can ensure that the handlers are fired correctly?
EDIT
Is it a bug that the handler is not fired or is that behavior documented somewhere?
/EDIT
minor questions
Is there any way to declare dependencies in a way that does not yield many inclusions which are only picked up by one server and ignored by all others although the others will include the same role through their own dependencies at some other point? This results in a lot of skipped tasks when I have some more servers and roles. (after reading the docs on role inclusion I suspect not)
Is there some other way to handle role dependencies and handlers with ansible? I came up with this setup after reading https://medium.com/#ibrahimgunduz34/parallel-playbook-execution-in-ansible-30799ccda4e0
Sidenote
I would like to avoid the group_by technique described in the docs, or more generally executing each role in their own playbook for the correct subset of the servers only, because I have a lot of servers and I want to speed up the run of the playbook by using strategy: free.
Related
My molecule invocation looks like this:
molecule test -s default 2>&1 test.log
Unfortunately, the command doesn't test the scenario:
INFO default scenario test matrix: dependency, lint, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy
INFO Performing prerun...
INFO Added ANSIBLE_LIBRARY=/Users/oschlueter/.cache/ansible-compat/e0666c/modules:/Users/oschlueter/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
INFO Added ANSIBLE_COLLECTIONS_PATH=/Users/oschlueter/.cache/ansible-compat/e0666c/collections:/Users/oschlueter/.ansible/collections:/usr/share/ansible/collections
INFO Added ANSIBLE_ROLES_PATH=/Users/oschlueter/.cache/ansible-compat/e0666c/roles:/Users/oschlueter/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
INFO Using /Users/oschlueter/.ansible/roles/company.python symlink to current repository in order to enable Ansible to find the role using its expected full name.
INFO Running default > dependency
WARNING Skipping, missing the requirements file.
WARNING Skipping, missing the requirements file.
INFO Running default > lint
COMMAND: set -e
yamllint .
ansible-lint
Loading custom .yamllint config file, this extends our internal yamllint config.
INFO Running default > cleanup
WARNING Skipping, cleanup playbook not configured.
INFO Running default > destroy
INFO Sanity checks: 'docker'
PLAY [Destroy] *****************************************************************
TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)
TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item=instance)
TASK [Delete docker networks(s)] ***********************************************
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
INFO Running default > syntax
ERROR! the playbook: test.log could not be found
CRITICAL Ansible return code was 1, command was: ['ansible-playbook', '--inventory', '/Users/oschlueter/.cache/molecule/python-venv/default/inventory', '--skip-tags', 'molecule-notest,notest', '--syntax-check', 'test.log', '/Users/oschlueter/git/ansible/roles/python-venv/molecule/default/converge.yml']
WARNING An error occurred during the test sequence action: 'syntax'. Cleaning up.
INFO Running default > cleanup
WARNING Skipping, cleanup playbook not configured.
INFO Running default > destroy
PLAY [Destroy] *****************************************************************
TASK [Destroy molecule instance(s)] ********************************************
changed: [localhost] => (item=instance)
TASK [Wait for instance(s) deletion to complete] *******************************
FAILED - RETRYING: Wait for instance(s) deletion to complete (300 retries left).
ok: [localhost] => (item=instance)
TASK [Delete docker networks(s)] ***********************************************
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
It seems that molecule includes the target of my redirect into its ansible invocation for some reason.
I have a rather large playbook that contains tasks to install and configure a new application, with a bunch of tasks that are relevant only to the initial install and configuration, and a bunch of tasks that are only relevant for subsequent runs.
What I would like to do is conditionally include the tasks for the initial install and configuration, and run those only when an initial-install tag is passed.
For example:
# main.yml
- include: initial_install.yml
when: tag 'initial-install' specified
- include: initial_configuration.yml
when: tag 'initial-install' specified
- include: configure.yml
This is a simplified example, but if I can figure this out, I should be able to organize my task list into a format that doesn't run the unnecessary tasks unless the playbook is being ran for an initial installation, with the initial-install tag.
There is indeed a full tagging mechanism build for you in Ansible already.
You can either run only tasks with one or more tag(s):
ansible-playbook play.yml --tags "some,tags,here"
Where the tags specified is a comma separated list of all the tags you want to run.
Or specify tag(s) you want to skip
ansible-playbook play.yml --skip-tags "some,tags,here"
And you just specify your tags as a list on any task you need them:
- include: initial_install.yml
tags: initial-install
- include: initial_configuration.yml
tags: initial-install
- include: configure.yml
tags:
- setup
- reconfiguration
- else
In your case, mind that
Adding tags: to a play, or to statically imported tasks and roles, adds those tags to all of the contained tasks.
Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html#tag-inheritance
There is also a set of special tags:
always, is always run, unless specifically skipped via --skip-tags always
never, is never run, unless another tag of that task is specifically requested
And a set of special keywords
tagged, if you want to target all tagged tasks in --tags or --skip-tags
untagged, if you want to target all untagged tasks in --tags or --skip-tags
all, if you want to target all tasks in --tags or --skip-tags
Those can be used in your case:
- include: initial_install.yml
tags:
- initial-install
- never
- include: initial_configuration.yml
tags:
- initial-install
- never
- include: configure.yml
tags:
- setup
- reconfiguration
- else
Running this example via plain
ansible-playbook play.yml
won't run the two first task, but will run the last one.
Running it with
ansible-playbook play.yml --tags "initial-install,all"
will run all three tasks.
Given the playbook:
- hosts: all
gather_facts: no
tasks:
- debug:
msg: initial_install.yml
tags:
- initial-install
- never
- debug:
msg: initial_configuration.yml
tags:
- initial-install
- never
- debug:
msg: configure.yml
tags:
- setup
- reconfiguration
- else
This gives those outputs:
$ ansible-playbook play.yml
PLAY [all] **********************************************************************************************************************
TASK [debug] ********************************************************************************************************************
ok: [localhost] => {
"msg": "configure.yml"
}
PLAY RECAP **********************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$ ansible-playbook play.yml --tags "initial-install,all"
PLAY [all] **********************************************************************************************************************
TASK [debug] ********************************************************************************************************************
ok: [localhost] => {
"msg": "initial_install.yml"
}
TASK [debug] ********************************************************************************************************************
ok: [localhost] => {
"msg": "initial_configuration.yml"
}
TASK [debug] ********************************************************************************************************************
ok: [localhost] => {
"msg": "configure.yml"
}
PLAY RECAP **********************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
---
- hosts: all
become_user: ansible
become: yes
become_method: sudo
tasks:
- name: Restart the sshd service
service: name=sshd state=restarted
### sudoers file entry for user on host ####
ansible ALL=(ALL) NOPASSWD:ALL
PLAY [all] ***************************************************************************
TASK [Gathering Facts] ***************************************************************
ok: [host2.domain.local]
ok: [host1.domain.local]
TASK [Restart the ssh service] *******************************************************
fatal: [host2.domain.local]: FAILED! => {"changed": false, "msg": "Unable to restart service sshd: Failed to restart sshd.service: Interactive authentication required.\n"}
fatal: [host1.domain.local]: FAILED! => {"changed": false, "msg": "Unable to restart service sshd: Failed to restart sshd.service: Interactive authentication required.\n"}
to retry, use: --limit #/root/1stplay.retry
PLAY RECAP ***************************************************************************
host1.domain.local : ok=1 changed=0 unreachable=0 failed=1
host2.domain.local : ok=1 changed=0 unreachable=0 failed=1
Lose the line:
become_user: ansible
Presumably you are logging into the target machine as ansible and want to become root, not ansible? If you do not specify the become_user root is used by default.
- hosts: Ebonding
become: yes
become_method: sudo
tasks
- name: Clearing cache of Server4
file: path=/weblogic/bea/user_projects/domains/tmp state=absent
become: yes
become_user: wls10
Ansible version 2.0.0.0 run the above playbook successfully::
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [ggnqinfa2]
TASK [Clearing cache of Server4] ***********************************************
ok: [ggnqinfa2]
PLAY RECAP *********************************************************************
ggnqinfa2 : ok=2 changed=0 unreachable=0 failed=0
But latest version of ansible 2.5.0rc2 encountered below error::
PLAY [Ebonding] *****************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************
ok: [ggnqinfa2]
TASK [Clearing cache of Server4] ************************************************************************************************************************************
fatal: [ggnqinfa2]: FAILED! => {"msg": "Failed to set permissions on the temporary files Ansible needs to create when becoming an unprivileged user (rc: 2, err: chown: /var/tmp/ansible-tmp-1520704924.34-191458796685785/: Not owner\nchown: /var/tmp/ansible-tmp-1520704924.34-191458796685785/file.py: Not owner\n}). For information on working around this, see https://docs.ansible.com/ansible/become.html#becoming-an-unprivileged-user"}
PLAY RECAP **********************************************************************************************************************************************************
ggnqinfa2 : ok=1 changed=0 unreachable=0 failed=1
How can i run this playbook by latest version of ansible successfully?
Chances are the user you're using (wls10) does not have write access to the remote temporary directory /var/tmp.
This can be overridden using ansible.cfg and set via remote_tmp to a directory you have write-access to -- or, a "normal temp directory" (like /tmp) that has the sticky bit set.
For more info, see
http://docs.ansible.com/ansible/latest/intro_configuration.html#remote-tmp
Senario:
1. I need to run two plays in a single playbook.
2. The second play should run after the first play.
3. The first play create few instance and update the inventory file by making new group.
4. Second play uses the updated group and install few packages.
Problem: If I am running both plays separately it is success.
But, i need them in same scripts.
The problem i think is both play executing in parallel.
And thanks in advance.
---
- name: ec2
hosts: localhost
connection: local
roles:
- launchEc2
- hosts: ansible
gather_facts: Fasle
become: yes
roles:
- python
OUTPUT:
PLAY [ec2] *********************************************************************
TASK [setup] *******************************************************************
ok: [127.0.0.1]
TASK [launchEc2 : include_vars] ************************************************
ok: [127.0.0.1]
TASK [launchEc2 : Launch new ec2 instance] *************************************
changed: [127.0.0.1]
TASK [launchEc2 : Add ec2 ip to the hostgroup] *********************************
changed: [127.0.0.1] => (item={.....})
TASK [launchEc2 : wait for SSh to come up] *************************************
ok: [127.0.0.1] => (item={.....})
PLAY [ansible] *****************************************************************
TASK [python : install python] *************************************************
skipping: [34.203.228.19]
PLAY RECAP *********************************************************************
127.0.0.1 : ok=5 changed=2 unreachable=0 failed=0
34.203.228.19 : ok=0 changed=0 unreachable=0 failed=0
Ansible loads inventory before processing playbook.
In your case the second play has the same inventory as it was before modification in the first play.
Generally when you provision cloud hosts you may want to use add_host to dynamically add new hosts to in memory inventory, so they are available to subsequent plays.
You may also try to call meta: refresh_inventory after your inventory modification, but I'm not sure wether it work with updating static inventory.