ansible/ansible

Variable templating not working correctly when delegating

jimmymccrory opened this issue · 7 comments

SUMMARY

When looping through a list of variables and delegating to a templated host, only the first host's variables are templated correctly.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

lib/ansible/vars/manager.py

ANSIBLE VERSION
ansible 2.7.0
  config file = None
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /tmp/ants/local/lib/python2.7/site-packages/ansible
  executable location = /tmp/ants/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]
CONFIGURATION
OS / ENVIRONMENT

Ubuntu

STEPS TO REPRODUCE
[group1]
host1 some_var=1 some_other_var=a
host2 some_var=2 some_other_var=b

[group2]
localhost connection=local
---
- hosts: group1
  gather_facts: no
  tasks:
    - file:
        path: "/tmp/{{ item }}"
        state: "directory"
      with_items:
        - "{{ some_var }}"
        - "{{ some_other_var }}"
      delegate_to: "{{ groups['group2'][0] }}"

    - assert:
        that:
          - "'/tmp/1' is directory"
          - "'/tmp/a' is directory"
          - "'/tmp/2' is directory"
          - "'/tmp/b' is directory"
EXPECTED RESULTS

PLAY [group1] **********************************************************************************************************************************************************************************************************************

TASK [file] ************************************************************************************************************************************************************************************************************************
changed: [host1 -> localhost] => (item=1)
changed: [host2 -> localhost] => (item=2)
changed: [host1 -> localhost] => (item=a)
changed: [host2 -> localhost] => (item=b)

TASK [assert] **********************************************************************************************************************************************************************************************************************
ok: [host1] => {
    "changed": false,
    "msg": "All assertions passed"
}
ok: [host2] => {
    "changed": false,
    "msg": "All assertions passed"
}

PLAY RECAP *************************************************************************************************************************************************************************************************************************
host1                      : ok=2    changed=1    unreachable=0    failed=0
host2                      : ok=2    changed=1    unreachable=0    failed=0
ACTUAL RESULTS
ansible-playbook /tmp/play.yml -i /tmp/inventory
PLAY [group1] **********************************************************************************************************************************************************************************************************************

TASK [file] ************************************************************************************************************************************************************************************************************************
changed: [host2 -> localhost] => (item=1)
ok: [host1 -> localhost] => (item=1)
changed: [host2 -> localhost] => (item=a)
ok: [host1 -> localhost] => (item=a)

TASK [assert] **********************************************************************************************************************************************************************************************************************
fatal: [host1]: FAILED! => {
    "assertion": "'/tmp/2' is directory",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
fatal: [host2]: FAILED! => {
    "assertion": "'/tmp/2' is directory",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
	to retry, use: --limit @/tmp/play.retry

PLAY RECAP *************************************************************************************************************************************************************************************************************************
host1                      : ok=1    changed=0    unreachable=0    failed=1
host2                      : ok=1    changed=1    unreachable=0    failed=1
ansible-playbook /tmp/play.yml -i /tmp/inventory -vvvv
ansible-playbook 2.7.0
  config file = None
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /tmp/ansible27/local/lib/python2.7/site-packages/ansible
  executable location = /tmp/ansible27/bin/ansible-playbook
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]
No config file found; using defaults
setting up inventory plugins
Set default localhost to localhost
Parsed /tmp/inventory inventory source with ini plugin
Loading callback plugin default of type stdout, v2.0 from /tmp/ansible27/local/lib/python2.7/site-packages/ansible/plugins/callback/default.pyc

PLAYBOOK: play.yml *****************************************************************************************************************************************************************************************************************
1 plays in /tmp/play.yml

PLAY [group1] **********************************************************************************************************************************************************************************************************************
META: ran handlers

TASK [file] ************************************************************************************************************************************************************************************************************************
task path: /tmp/play.yml:5
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484 `" && echo ansible-tmp-1538925580.98-215028109547484="` echo /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484 `" ) && sleep 0'
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272 `" && echo ansible-tmp-1538925580.99-197840915774272="` echo /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272 `" ) && sleep 0'
Using module file /tmp/ansible27/local/lib/python2.7/site-packages/ansible/modules/files/file.py
Using module file /tmp/ansible27/local/lib/python2.7/site-packages/ansible/modules/files/file.py
<localhost> PUT /root/.ansible/tmp/ansible-local-29097PyqY1S/tmpAmGzBD TO /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484/AnsiballZ_file.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484/ /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484/AnsiballZ_file.py && sleep 0'
<localhost> PUT /root/.ansible/tmp/ansible-local-29097PyqY1S/tmp31OJ_0 TO /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272/AnsiballZ_file.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272/ /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1538925580.99-197840915774272/ > /dev/null 2>&1 && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1538925580.98-215028109547484/ > /dev/null 2>&1 && sleep 0'
changed: [host1 -> localhost] => (item=1) => {
    "changed": true,
    "diff": {
        "after": {
            "path": "/tmp/1",
            "state": "directory"
        },
        "before": {
            "path": "/tmp/1",
            "state": "absent"
        }
    },
    "gid": 0,
    "group": "root",
    "invocation": {
        "module_args": {
            "_diff_peek": null,
            "_original_basename": null,
            "access_time": null,
            "access_time_format": "%Y%m%d%H%M.%S",
            "attributes": null,
            "backup": null,
            "content": null,
            "delimiter": null,
            "directory_mode": null,
            "follow": true,
            "force": false,
            "group": null,
            "mode": null,
            "modification_time": null,
            "modification_time_format": "%Y%m%d%H%M.%S",
            "owner": null,
            "path": "/tmp/1",
            "recurse": false,
            "regexp": null,
            "remote_src": null,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": null,
            "state": "directory",
            "unsafe_writes": null
        }
    },
    "item": 1,
    "mode": "0755",
    "owner": "root",
    "path": "/tmp/1",
    "size": 4096,
    "state": "directory",
    "uid": 0
}
ok: [host2 -> localhost] => (item=1) => {
    "changed": false,
    "diff": {
        "after": {
            "path": "/tmp/1"
        },
        "before": {
            "path": "/tmp/1"
        }
    },
    "gid": 0,
    "group": "root",
    "invocation": {
        "module_args": {
            "_diff_peek": null,
            "_original_basename": null,
            "access_time": null,
            "access_time_format": "%Y%m%d%H%M.%S",
            "attributes": null,
            "backup": null,
            "content": null,
            "delimiter": null,
            "directory_mode": null,
            "follow": true,
            "force": false,
            "group": null,
            "mode": null,
            "modification_time": null,
            "modification_time_format": "%Y%m%d%H%M.%S",
            "owner": null,
            "path": "/tmp/1",
            "recurse": false,
            "regexp": null,
            "remote_src": null,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": null,
            "state": "directory",
            "unsafe_writes": null
        }
    },
    "item": 1,
    "mode": "0755",
    "owner": "root",
    "path": "/tmp/1",
    "size": 4096,
    "state": "directory",
    "uid": 0
}
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659 `" && echo ansible-tmp-1538925581.22-128641467257659="` echo /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659 `" ) && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869 `" && echo ansible-tmp-1538925581.22-257782839693869="` echo /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869 `" ) && sleep 0'
Using module file /tmp/ansible27/local/lib/python2.7/site-packages/ansible/modules/files/file.py
Using module file /tmp/ansible27/local/lib/python2.7/site-packages/ansible/modules/files/file.py
<localhost> PUT /root/.ansible/tmp/ansible-local-29097PyqY1S/tmpJOnbc9 TO /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659/AnsiballZ_file.py
<localhost> PUT /root/.ansible/tmp/ansible-local-29097PyqY1S/tmpm3ebfA TO /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869/AnsiballZ_file.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659/ /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869/ /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869/AnsiballZ_file.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1538925581.22-257782839693869/ > /dev/null 2>&1 && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1538925581.22-128641467257659/ > /dev/null 2>&1 && sleep 0'
changed: [host2 -> localhost] => (item=a) => {
    "changed": true,
    "diff": {
        "after": {
            "path": "/tmp/a",
            "state": "directory"
        },
        "before": {
            "path": "/tmp/a",
            "state": "absent"
        }
    },
    "gid": 0,
    "group": "root",
    "invocation": {
        "module_args": {
            "_diff_peek": null,
            "_original_basename": null,
            "access_time": null,
            "access_time_format": "%Y%m%d%H%M.%S",
            "attributes": null,
            "backup": null,
            "content": null,
            "delimiter": null,
            "directory_mode": null,
            "follow": true,
            "force": false,
            "group": null,
            "mode": null,
            "modification_time": null,
            "modification_time_format": "%Y%m%d%H%M.%S",
            "owner": null,
            "path": "/tmp/a",
            "recurse": false,
            "regexp": null,
            "remote_src": null,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": null,
            "state": "directory",
            "unsafe_writes": null
        }
    },
    "item": "a",
    "mode": "0755",
    "owner": "root",
    "path": "/tmp/a",
    "size": 4096,
    "state": "directory",
    "uid": 0
}
ok: [host1 -> localhost] => (item=a) => {
    "changed": false,
    "diff": {
        "after": {
            "path": "/tmp/a",
            "state": "directory"
        },
        "before": {
            "path": "/tmp/a",
            "state": "absent"
        }
    },
    "gid": 0,
    "group": "root",
    "invocation": {
        "module_args": {
            "_diff_peek": null,
            "_original_basename": null,
            "access_time": null,
            "access_time_format": "%Y%m%d%H%M.%S",
            "attributes": null,
            "backup": null,
            "content": null,
            "delimiter": null,
            "directory_mode": null,
            "follow": true,
            "force": false,
            "group": null,
            "mode": null,
            "modification_time": null,
            "modification_time_format": "%Y%m%d%H%M.%S",
            "owner": null,
            "path": "/tmp/a",
            "recurse": false,
            "regexp": null,
            "remote_src": null,
            "selevel": null,
            "serole": null,
            "setype": null,
            "seuser": null,
            "src": null,
            "state": "directory",
            "unsafe_writes": null
        }
    },
    "item": "a",
    "mode": "0755",
    "owner": "root",
    "path": "/tmp/a",
    "size": 4096,
    "state": "directory",
    "uid": 0
}

TASK [assert] **********************************************************************************************************************************************************************************************************************
task path: /tmp/play.yml:13
fatal: [host1]: FAILED! => {
    "assertion": "'/tmp/2' is directory",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
fatal: [host2]: FAILED! => {
    "assertion": "'/tmp/2' is directory",
    "changed": false,
    "evaluated_to": false,
    "msg": "Assertion failed"
}
	to retry, use: --limit @/tmp/play.retry

PLAY RECAP *************************************************************************************************************************************************************************************************************************
host1                      : ok=1    changed=1    unreachable=0    failed=1
host2                      : ok=1    changed=1    unreachable=0    failed=1

Files identified in the description:

If these files are inaccurate, please update the component name section of the description or use the !component bot command.

click here for bot help

Hello,

I think I have the same or related issue when switching from 2.6.5 to 2.7.0.
Here is an example.

Playbook:

- hosts: vms
  gather_facts: false

  tasks:

  - debug:
      var: item
    delegate_to: '{{ item.node }}'
    loop: '{{ mylist }}'

Inventory:

all:
  children:
    vms:
      hosts:
        target1:
          mylist: [{ node: "node1", vmid: 103 }]
        target2:
          mylist: [{ node: "node2", vmid: 104 }]
    cluster:
      hosts:
        node1:
        node2:

Result with 2.6.5 (correct) :

TASK [debug] ***********************************************************************
ok: [target2 -> node2] => (item={u'node': u'node2', u'vmid': 104}) => {
    "item": {
        "node": "node2", 
        "vmid": 104
    }
}
ok: [target1 -> node1] => (item={u'node': u'node1', u'vmid': 103}) => {
    "item": {
        "node": "node1", 
        "vmid": 103
    }
}

Result with 2.7.0 (broken) :

TASK [debug] ***********************************************************************
ok: [target2 -> node2] => (item={u'node': u'node2', u'vmid': 104}) => {
    "item": {
        "node": "node2", 
        "vmid": 104
    }
}
ok: [target1 -> node2] => (item={u'node': u'node2', u'vmid': 104}) => {
    "item": {
        "node": "node2", 
        "vmid": 104
    }
}

In 2.7.0 both items are the same although the variable looped-on is not the same on each host.

Regards,
Julien

I can confirm this issue.

I can also confirm. This is a real problem.

CODE

- debug:
    msg: "inventory_hostname = {{ inventory_hostname }}"

- debug:
    msg: "ansible_fqdn = {{ ansible_fqdn }}"

- debug:
    msg: "{{ item }}"
  with_items: "{{ hostvars[inventory_hostname]['ansible_local']['apache'] }}"

- debug:
    msg: "Source: {{ role_path }}/templates/service-templates/service_http.conf.j2"
  with_items: "{{ hostvars[inventory_hostname]['ansible_local']['apache'] }}"

- debug:
    msg: "Dest: /etc/icinga2/zones.d/{{ ansible_fqdn }}/service_{{ hostvars[inventory_hostname]['ansible_local']['apache'][item]['protocol'] }}_{{ hostvars[inventory_hostname]['ansible_local']['apache'][item]['servername'] }}.conf"
  with_items: "{{ hostvars[inventory_hostname]['ansible_local']['apache'] }}"

- name: Copy service check template for Apache HTTP
  template:
    src: "{{ role_path }}/templates/service-templates/service_http.conf.j2"
    dest: "/etc/icinga2/zones.d/{{ ansible_fqdn }}/service_{{ hostvars[inventory_hostname]['ansible_local']['apache'][item]['protocol'] }}_{{ hostvars[inventory_hostname]['ansible_local']['apache'][item]['servername'] }}.conf"
    owner: nagios
    group: nagios
    mode: 0644
  delegate_to: "{{ icinga2_server.uqdn }}"
  with_items: "{{ hostvars[inventory_hostname]['ansible_local']['apache'] }}"
  notify: check icinga2 config

OUTPUT

TASK [icinga2_config : debug] ******************************************************************************************************************************************************************
Wednesday 10 October 2018  12:21:22 +0200 (0:00:01.394)       0:10:35.940 ***** 
ok: [horst] => {
    "msg": "inventory_hostname = horst"
}
ok: [pythagoras] => {
    "msg": "inventory_hostname = pythagoras"
}
ok: [uwe] => {
    "msg": "inventory_hostname = uwe"
}
ok: [test03] => {
    "msg": "inventory_hostname = test03"
}
ok: [hiob] => {
    "msg": "inventory_hostname = hiob"
}
ok: [test02] => {
    "msg": "inventory_hostname = test02"
}
ok: [athena] => {
    "msg": "inventory_hostname = athena"
}
ok: [godzilla] => {
    "msg": "inventory_hostname = godzilla"
}
ok: [king] => {
    "msg": "inventory_hostname = king"
}
ok: [kong] => {
    "msg": "inventory_hostname = kong"
}
ok: [alien] => {
    "msg": "inventory_hostname = alien"
}
ok: [predator] => {
    "msg": "inventory_hostname = predator"
}
ok: [localhost] => {
    "msg": "inventory_hostname = localhost"
}

TASK [icinga2_config : debug] ******************************************************************************************************************************************************************
Wednesday 10 October 2018  12:21:24 +0200 (0:00:01.107)       0:10:37.048 ***** 
ok: [horst] => {
    "msg": "ansible_fqdn = horst.foo.de"
}
ok: [pythagoras] => {
    "msg": "ansible_fqdn = pythagoras.foo.de"
}
ok: [uwe] => {
    "msg": "ansible_fqdn = uwe.foo.de"
}
ok: [test03] => {
    "msg": "ansible_fqdn = test03.foo.de"
}
ok: [hiob] => {
    "msg": "ansible_fqdn = hiob.foo.de"
}
ok: [test02] => {
    "msg": "ansible_fqdn = test02.foo.de"
}
ok: [athena] => {
    "msg": "ansible_fqdn = athena.foo.de"
}
ok: [godzilla] => {
    "msg": "ansible_fqdn = godzilla.foo.de"
}
ok: [king] => {
    "msg": "ansible_fqdn = king.foo.de"
}
ok: [kong] => {
    "msg": "ansible_fqdn = kong.foo.de"
}
ok: [alien] => {
    "msg": "ansible_fqdn = alien.foo.de"
}
ok: [predator] => {
    "msg": "ansible_fqdn = predator.foo.de"
}
ok: [localhost] => {
    "msg": "ansible_fqdn = thales.foo.de"
}

TASK [icinga2_config : debug] ******************************************************************************************************************************************************************
Wednesday 10 October 2018  12:21:26 +0200 (0:00:01.385)       0:10:39.531 ***** 
ok: [horst] => (item=bcs-devel) => {
    "msg": "bcs-devel"
}
ok: [horst] => (item=bcs-devel_ssl) => {
    "msg": "bcs-devel_ssl"
}
ok: [pythagoras] => (item=bcs_ssl) => {
    "msg": "bcs_ssl"
}
ok: [pythagoras] => (item=bcs) => {
    "msg": "bcs"
}
ok: [uwe] => (item=bcs-beta_ssl) => {
    "msg": "bcs-beta_ssl"
}
ok: [uwe] => (item=bcs-beta) => {
    "msg": "bcs-beta"
}
ok: [athena] => (item=icinga2_ssl) => {
    "msg": "icinga2_ssl"
}
ok: [athena] => (item=icinga2) => {
    "msg": "icinga2"
}
ok: [localhost] => (item=seed) => {
    "msg": "seed"
}

TASK [icinga2_config : debug] ******************************************************************************************************************************************************************
Wednesday 10 October 2018  12:21:28 +0200 (0:00:01.498)       0:10:41.029 ***** 
ok: [horst] => (item=bcs-devel) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [horst] => (item=bcs-devel_ssl) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [pythagoras] => (item=bcs_ssl) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [pythagoras] => (item=bcs) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [uwe] => (item=bcs-beta_ssl) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [uwe] => (item=bcs-beta) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [athena] => (item=icinga2_ssl) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [athena] => (item=icinga2) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}
ok: [localhost] => (item=seed) => {
    "msg": "Source: /etc/ansible/roles/icinga2_config/templates/service-templates/service_http.conf.j2"
}

TASK [icinga2_config : debug] ******************************************************************************************************************************************************************
Wednesday 10 October 2018  12:21:29 +0200 (0:00:01.251)       0:10:42.280 ***** 
ok: [horst] => (item=bcs-devel) => {
    "msg": "Dest: /etc/icinga2/zones.d/horst.foo.de/service_http_bcs-devel.foo.de.conf"
}
ok: [pythagoras] => (item=bcs_ssl) => {
    "msg": "Dest: /etc/icinga2/zones.d/pythagoras.foo.de/service_https_bcs.foo.de.conf"
}
ok: [horst] => (item=bcs-devel_ssl) => {
    "msg": "Dest: /etc/icinga2/zones.d/horst.foo.de/service_https_bcs-devel.foo.de.conf"
}
ok: [uwe] => (item=bcs-beta_ssl) => {
    "msg": "Dest: /etc/icinga2/zones.d/uwe.foo.de/service_https_bcs-beta.foo.de.conf"
}
ok: [pythagoras] => (item=bcs) => {
    "msg": "Dest: /etc/icinga2/zones.d/pythagoras.foo.de/service_http_bcs.foo.de.conf"
}
ok: [uwe] => (item=bcs-beta) => {
    "msg": "Dest: /etc/icinga2/zones.d/uwe.foo.de/service_http_bcs-beta.foo.de.conf"
}
ok: [athena] => (item=icinga2_ssl) => {
    "msg": "Dest: /etc/icinga2/zones.d/athena.foo.de/service_https_athena.foo.de.conf"
}
ok: [athena] => (item=icinga2) => {
    "msg": "Dest: /etc/icinga2/zones.d/athena.foo.de/service_http_athena.foo.de.conf"
}
ok: [localhost] => (item=seed) => {
    "msg": "Dest: /etc/icinga2/zones.d/thales.foo.de/service_http_seed.foo.de.conf"
}

TASK [icinga2_config : Copy service check template for Apache HTTP] ****************************************************************************************************************************
Wednesday 10 October 2018  12:21:30 +0200 (0:00:01.482)       0:10:43.763 ***** 
fatal: [pythagoras]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute u'bcs-devel'\n\nThe error appears to have been in '/etc/ansible/roles/icinga2_config/tasks/create_client_config_apache.yml': line 30, 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: Copy service check template for Apache HTTP\n  ^ here\n"}
fatal: [uwe]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute u'bcs-devel'\n\nThe error appears to have been in '/etc/ansible/roles/icinga2_config/tasks/create_client_config_apache.yml': line 30, 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: Copy service check template for Apache HTTP\n  ^ here\n"}
fatal: [athena]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute u'bcs-devel'\n\nThe error appears to have been in '/etc/ansible/roles/icinga2_config/tasks/create_client_config_apache.yml': line 30, 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: Copy service check template for Apache HTTP\n  ^ here\n"}
ok: [horst -> athena] => (item=bcs-devel)
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute u'bcs-devel'\n\nThe error appears to have been in '/etc/ansible/roles/icinga2_config/tasks/create_client_config_apache.yml': line 30, 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: Copy service check template for Apache HTTP\n  ^ here\n"}
ok: [horst -> athena] => (item=bcs-devel_ssl)
ant31 commented

2.7 is unusable with any delegate_to field

We got a high number of reports due to this bug on https://github.com/kubernetes-incubator/kubespray/
The playbook doesn't fail, which is worse, the installation is 'corrupted' and more complex to clean-up / debug.

ant31 commented

have you checked with 2.7.1 ?
It seems to work now,
cc @jimmymccrory

Thanks @ant31, looks like 2.7.1 is working for me too.

This appears to be fix.
f1db898
#47207