Issue 1:
ISSUE TYPE

Bug Report

COMPONENT NAME

ansible-2.2.0.0

ANSIBLE VERSION

ansible-playbook 2.2.0.0
config file = /home/ansible/ansible/ansible.cfg
configured module search path = ['/usr/local/share/ansible/modules']

CONFIGURATION

[defaults]
inventory = /home/ansible/ansible/inventory/hosts
library = /usr/local/share/ansible/modules
forks = 20
roles_path = /home/ansible/ansible/roles
remote_user = ansible
log_path = /home/ansible/ansible/ansible.log
hash_behaviour = merge
private_role_vars = no
private_key_file = /home/ansible/.ssh/id_rsa
vault_password_file = /home/ansible/ansible/secrets/vault-password-file
ansible_managed = Ansible managed: {file} on {host}
action_plugins = /usr/local/share/ansible/plugins/action
callback_plugins = /usr/local/share/ansible/plugins/callback
connection_plugins = /usr/local/share/ansible/plugins/connection
lookup_plugins = /usr/local/share/ansible/plugins/lookup
vars_plugins = /usr/local/share/ansible/plugins/vars
filter_plugins = /usr/local/share/ansible/plugins/filter
test_plugins = /usr/local/share/ansible/plugins/test
strategy_plugins = /usr/local/share/ansible/plugins/strategy
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[accelerate]
[selinux]
[colors]
diff_remove = bright blue

OS / ENVIRONMENT

Controller: ansible-2.2.0.0

Controlled node: FreeBSD

SUMMARY

I have a role, ossec_hids_agent, which has a dependency on a subordinate role, ossec_hids_common. The subordinate role has a dynamic task include and loads tasks from ossec_hids_agent space. I believe this is incorrect, a child role should not run tasks defined in it's parent.

This behaviour changed in ansible-2.2.0.0

ansible-2.1.3.0 has what I consider the correct behaviour

STEPS TO REPRODUCE

roles/ossec_hids_agent/meta/main.yml:

dependencies:
- role: ossec_hids_common

roles/ossec_hids_common_tasks/config.yml (included from main.yml):

- name: Include OS-specific config tasks.
include: "{{ item }}"
with_first_found:
...
- "./includes/{{ ansible_distribution }}-config.yml"
...

ls roles/ossec_hids_agent/tasks/includes/:

FreeBSD-config.yml

ls roles/ossec_hids_common/tasks/includes/:

playbooks/test/ossec_hids.yml:

- hosts: ossec-agent
roles:
- role: ossec_hids_agent
tags: [ "ossec", "ossec-agent" ]

playbook command:

ansible-playbook playbooks/test/ossec_hids.yml -b -D -t ossec-agent

The intent is that on e.g. a FreeBSD node, if a file includes/FreeBSD-config.yml exists, it will be included and executed. I expect that ossec_hids_common will only include files defined in it's own role structure and not search through the parent's includes as well

EXPECTED RESULTS

The include in ossec_hids_common should be a noop

ACTUAL RESULTS

ansible-2.2.0.0:

TASK [ossec_hids_common : Include OS-specific config tasks.] *******************
included: /home/alan/gitwork/ansible/roles/role_ossec_hids_agent/tasks/includes/FreeBSD-config.yml for freebsd-9-3, freebsd-10-2, freebsd-10-3

Clearly, the child role is including files defined in it's parent.

ansible-2.1.3.0

TASK [ossec_hids_common : Include OS-specific config tasks.] *******************
TASK [ossec_hids_common : Enable ossec_hids_common services] *******************

With this version the operation is a noop

Issue 2:
ISSUE TYPE

Bug Report

COMPONENT NAME

roles

ANSIBLE VERSION

ansible 2.2.1.0
config file =
configured module search path = Default w/o overrides

CONFIGURATION

N/A

OS / ENVIRONMENT

N/A

SUMMARY

We include role3 from both role1 and role2 in meta/main.yml using dependencies: keyword. These roles both pass the same parameters (that is: none directly, only via extra arguments) to role3, but it's (wrongly) running twice, merely because the depending role has a condition on itself.

We have the condition because we want to run role2 only sometimes, so we put a when: on the role: in its dependency declaration. This seems to work fine as far as only including role2 when it should be. The condition is properly checked, and properly includes the role only if true.

However, including any condition at all results in the dependency running twice, even if the condition is always true (i.e. when: true). This is not a different parameter or value, so the role calls are 100% identical, and allow_duplicates is false, yet it runs twice.

STEPS TO REPRODUCE

$ tail test.yml roles/**/*.yml
==> test.yml <==
- hosts: all
gather_facts: false
roles:
- role1
- role2

==> roles/role1/meta/main.yml <==
dependencies:
- role: role3

==> roles/role1/tasks/main.yml <==
- set_fact: dummy

==> roles/role2/meta/main.yml <==
dependencies:
- role: role3
when: true

==> roles/role2/tasks/main.yml <==
- set_fact: dummy

==> roles/role3/tasks/main.yml <==
- set_fact: dummy

EXPECTED RESULTS

role3 should be run once only. it's run once until adding when: true to the dependency. then it runs twice, and that's a bug. the duplicate run check should be discerning whether a role with that name and paramaters has run already, without any knowledge of when it's supposed to run. only if it has.

ACTUAL RESULTS

$ ansible-playbook -c local -i localhost, test.yml

PLAY [all] *********************************************************************

TASK [role3 : set_fact] ********************************************************
ok: [localhost]

TASK [role1 : set_fact] ********************************************************
ok: [localhost]

TASK [role3 : set_fact] ********************************************************
ok: [localhost]

TASK [role2 : set_fact] ********************************************************
ok: [localhost]

PLAY RECAP *********************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0

now watch when removing the when: true condition on the role dependency:

$ sed -i /when:.true/d roles/role2/meta/main.yml

$ ansible-playbook -c local -i localhost, test.yml

PLAY [all] *********************************************************************

TASK [role3 : set_fact] ********************************************************
ok: [localhost]

TASK [role1 : set_fact] ********************************************************
ok: [localhost]

TASK [role2 : set_fact] ********************************************************
ok: [localhost]

PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0

The condition shouldn't matter, it's whether the role actually has been run or not already, and if it's the same role, and the same parameters. "when" is not a parameter, it's a control. Note that I tried altering become_user: instead of when: to see if that would also cause a second run, and that one works correctly: it only runs once (in that case, you might argue that it actually has a different parameter, but I don't see any way to argue that for when:).