Repository: ansible/ansible

Issue:
Passing dict variable defined in roles_defaults to role fails when dict merging is enabled
##### Issue Type:

<!--- Please pick one and delete the rest: -->
- Bug Report
##### Ansible Version:

```
ansible 2.0.1.0
  config file = /home/dag/home-made/ansible.testing/ansible.cfg
  configured module search path = Default w/o overrides
```
##### Ansible Configuration:

<!---
Please mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

``` ini
[defaults]
hash_behaviour = merge
```
##### Environment:

<!---
Please mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
-->

N/A
##### Summary:

<!--- Please explain the problem briefly -->

The issue we are having is quite similar to an issue we have had on v1.9.4 and older (see  #12915), related to hash_merge().

When we set a dict through _role/defaults_ and we also set the same dict through _role_params_, the merge fails with the error:

```
PLAY ***************************************************************************
ERROR! failed to combine variables, expected dicts but got a 'dict' and a 'AnsibleUnicode': 
{"public": true}
"{{ packages.foo_api }}"
```
##### Steps To Reproduce:

<!---
For bugs, please show exactly how to reproduce the problem. For new
features, show how the feature would be used.
-->

**ansible.cfg**

``` ini
[defaults]
hash_behaviour = merge
```

**group_vars/all**

``` yaml
packages:
  foo_api:
    name: api
    version: 1.2.3
    tomcat: 10
  foo_bar:
    name: bar
    version: 2.3.4
    tomcat: 11
```

**test70.yml**

``` yaml

---
- hosts: localhost
  gather_facts: no
  roles:
    - role: test70
      foo: '{{ packages.foo_api }}'
```

**roles/test70/defaults/main.yml**

``` yaml
foo:
  public: yes
```

**roles/test70/tasks/main.yml**

``` yaml

---
- name: '{{ foo.name }} : Test merging of vars'
  debug:
    var: foo
```
##### Expected Results:

<!--- What did you expect to happen when running the steps above? -->

I expect the following output:

```
PLAY ***************************************************************************

TASK [test70 : api : Test merging of vars] *************************************
ok: [localhost] => {
    "foo": {
        "name": "api", 
        "public": true,
        "tomcat": 10, 
        "version": "1.2.3"
    }
}

PLAY RECAP *********************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0   
```
##### Actual Results:

<!--- What actually happened? If possible run with high verbosity (-vvvv) -->

But I get:

```
ERROR! failed to combine variables, expected dicts but got a 'dict' and a 'AnsibleUnicode': 
{"public": true}
"{{ packages.foo_api }}"
```



Discussion:

Resolving patch:
diff --git a/lib/ansible/utils/vars.py b/lib/ansible/utils/vars.py
--- a/lib/ansible/utils/vars.py
+++ b/lib/ansible/utils/vars.py
@@ -86,7 +86,7 @@ def merge_hash(a, b):
     for k, v in iteritems(b):
         # if there's already such key in a
         # and that key contains a MutableMapping
-        if k in result and isinstance(result[k], MutableMapping):
+        if k in result and isinstance(result[k], MutableMapping) and isinstance(v, MutableMapping):
             # merge those dicts recursively
             result[k] = merge_hash(result[k], v)
         else:


Test patch: