Repository: ansible/ansible-modules-extras

Issue:
zypper module: notify crashes because of changed dict
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### COMPONENT NAME

<!--- Name of the plugin/module/task -->

zypper
notify
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible 2.2.0 (devel acd69bcc77) last updated 2016/08/31 16:06:22 (GMT +200)
  lib/ansible/modules/core: (detached HEAD 5310bab12f) last updated 2016/08/31 16:06:30 (GMT +200)
  lib/ansible/modules/extras: (detached HEAD 2ef4a34eee) last updated 2016/08/31 16:06:30 (GMT +200)
  config file =
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

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

<!---
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.
-->

SLES 12
##### SUMMARY

<!--- Explain the problem briefly -->

The package module calls zypper with a list of packages/programs to install. The operation completes without errors. In my opinion, notify executes now and raises an error because package or zypper returned "changed" = {} instead of "changed" = "false".
##### STEPS TO REPRODUCE

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

The following will raise an exeption even if everything is fine and unchanged.

<!--- Paste example playbooks or commands between quotes below -->

```
#example code - apache2-utils is installed when apache is installed so both is fine
#from role/myrole/tasks/main.yml
- name: install apache and apache modules
  package: name={{ item }} state=latest
  with_items:
    - "apache2"
    - "apache2-utils"
  notify:
   - "restart apache"

#frome /role/myrole/handlers/main.yml
- name: restart apache
  service: name=apache2 state=restarted
```

<!--- You can also paste gist.github.com links for larger files -->
##### EXPECTED RESULTS

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

During the first run, when the packages aren't present, I expected that the handler is called. Instead => exception

During the second run, when the packages are present, I expectet that the handler isn't called. Instead => exception
##### ACTUAL RESULTS

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

<!--- Paste verbatim command output between quotes below -->

```
Running zypper
Using module file /home/****/ansible/lib/ansible/modules/extras/packaging/os/zypper.py
<node> ESTABLISH SSH CONNECTION FOR USER: None
<node> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r node '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279 `" && echo ansible-tmp-1472731543.66-70288465940279="` echo $HOME/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279 `" ) && sleep 0'"'"''
<node> PUT /tmp/tmpd7stK7 TO /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/zypper.py
<node> SSH: EXEC sftp -b - -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r '[node]'
<node> ESTABLISH SSH CONNECTION FOR USER: None
<node> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r node '/bin/sh -c '"'"'chmod u+x /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/ /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/zypper.py && sleep 0'"'"''
<node> ESTABLISH SSH CONNECTION FOR USER: None
<node> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r -tt node '/bin/sh -c '"'"'sudo -H -S  -p "[sudo via ansible, key=MYSECRET] password: " -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-MYSECRET; /usr/bin/python /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/zypper.py; rm -rf "/home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/" > /dev/null 2>&1'"'"'"'"'"'"'"'"' && sleep 0'"'"''
ok: [node] => (item=[u'apache2', u'apache2-utils']) => {
    "changed": {},
    "cmd": [
        "/usr/bin/zypper",
        "--quiet",
        "--non-interactive",
        "--xmlout",
        "install",
        "--type",
        "package",
        "--auto-agree-with-licenses",
        "--no-recommends",
        "--",
        "apache2-utils",
        "apache2"
    ],
    "invocation": {
        "module_args": {
            "disable_gpg_check": false,
            "disable_recommends": true,
            "force": false,
            "name": [
                "apache2",
                "apache2-utils"
            ],
            "oldpackage": false,
            "state": "latest",
            "type": "package",
            "update_cache": false
        }
    },
    "item": [
        "apache2",
        "apache2-utils"
    ],
    "name": [
        "apache2",
        "apache2-utils"
    ],
    "rc": 0,
    "state": "latest",
    "update_cache": false
}
ERROR! Unexpected Exception: unsupported operand type(s) for |=: 'bool' and 'dict'
the full traceback was:

Traceback (most recent call last):
  File "/home/****/ansible/bin/ansible-playbook", line 97, in <module>
    exit_code = cli.run()
  File "/home/****/ansible/lib/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/home/****/ansible/lib/ansible/executor/playbook_executor.py", line 147, in run
    result = self._tqm.run(play=play)
  File "/home/****/ansible/lib/ansible/executor/task_queue_manager.py", line 281, in run
    play_return = strategy.run(iterator, play_context)
  File "/home/****/ansible/lib/ansible/plugins/strategy/linear.py", line 269, in run
    results += self._wait_on_pending_results(iterator)
  File "/home/****/ansible/lib/ansible/plugins/strategy/__init__.py", line 514, in _wait_on_pending_results
    results = self._process_pending_results(iterator)
  File "/home/****/ansible/lib/ansible/plugins/strategy/__init__.py", line 370, in _process_pending_results
    if task_result.is_changed():
  File "/home/****/ansible/lib/ansible/executor/task_result.py", line 40, in is_changed
    return self._check_key('changed')
  File "/home/****/ansible/lib/ansible/executor/task_result.py", line 69, in _check_key
    flag |= res.get(key, False)
TypeError: unsupported operand type(s) for |=: 'bool' and 'dict'

AND WITHOUT -vvvv

TASK [apache-proxy : install apache and apache modules] ************************
ok: [sazvl0021.saz.bosch-si.com] => (item=[u'apache2', u'apache2-utils'])
ERROR! Unexpected Exception: unsupported operand type(s) for |=: 'bool' and 'dict'
```

zypper module: notify crashes because of changed dict
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### COMPONENT NAME

<!--- Name of the plugin/module/task -->

zypper
notify
##### ANSIBLE VERSION

<!--- Paste verbatim output from “ansible --version” between quotes below -->

```
ansible 2.2.0 (devel acd69bcc77) last updated 2016/08/31 16:06:22 (GMT +200)
  lib/ansible/modules/core: (detached HEAD 5310bab12f) last updated 2016/08/31 16:06:30 (GMT +200)
  lib/ansible/modules/extras: (detached HEAD 2ef4a34eee) last updated 2016/08/31 16:06:30 (GMT +200)
  config file =
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

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

<!---
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.
-->

SLES 12
##### SUMMARY

<!--- Explain the problem briefly -->

The package module calls zypper with a list of packages/programs to install. The operation completes without errors. In my opinion, notify executes now and raises an error because package or zypper returned "changed" = {} instead of "changed" = "false".
##### STEPS TO REPRODUCE

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

The following will raise an exeption even if everything is fine and unchanged.

<!--- Paste example playbooks or commands between quotes below -->

```
#example code - apache2-utils is installed when apache is installed so both is fine
#from role/myrole/tasks/main.yml
- name: install apache and apache modules
  package: name={{ item }} state=latest
  with_items:
    - "apache2"
    - "apache2-utils"
  notify:
   - "restart apache"

#frome /role/myrole/handlers/main.yml
- name: restart apache
  service: name=apache2 state=restarted
```

<!--- You can also paste gist.github.com links for larger files -->
##### EXPECTED RESULTS

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

During the first run, when the packages aren't present, I expected that the handler is called. Instead => exception

During the second run, when the packages are present, I expectet that the handler isn't called. Instead => exception
##### ACTUAL RESULTS

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

<!--- Paste verbatim command output between quotes below -->

```
Running zypper
Using module file /home/****/ansible/lib/ansible/modules/extras/packaging/os/zypper.py
<node> ESTABLISH SSH CONNECTION FOR USER: None
<node> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r node '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279 `" && echo ansible-tmp-1472731543.66-70288465940279="` echo $HOME/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279 `" ) && sleep 0'"'"''
<node> PUT /tmp/tmpd7stK7 TO /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/zypper.py
<node> SSH: EXEC sftp -b - -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r '[node]'
<node> ESTABLISH SSH CONNECTION FOR USER: None
<node> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r node '/bin/sh -c '"'"'chmod u+x /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/ /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/zypper.py && sleep 0'"'"''
<node> ESTABLISH SSH CONNECTION FOR USER: None
<node> SSH: EXEC ssh -vvv -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/****/.ansible/cp/ansible-ssh-%h-%p-%r -tt node '/bin/sh -c '"'"'sudo -H -S  -p "[sudo via ansible, key=MYSECRET] password: " -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-MYSECRET; /usr/bin/python /home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/zypper.py; rm -rf "/home/****/.ansible/tmp/ansible-tmp-1472731543.66-70288465940279/" > /dev/null 2>&1'"'"'"'"'"'"'"'"' && sleep 0'"'"''
ok: [node] => (item=[u'apache2', u'apache2-utils']) => {
    "changed": {},
    "cmd": [
        "/usr/bin/zypper",
        "--quiet",
        "--non-interactive",
        "--xmlout",
        "install",
        "--type",
        "package",
        "--auto-agree-with-licenses",
        "--no-recommends",
        "--",
        "apache2-utils",
        "apache2"
    ],
    "invocation": {
        "module_args": {
            "disable_gpg_check": false,
            "disable_recommends": true,
            "force": false,
            "name": [
                "apache2",
                "apache2-utils"
            ],
            "oldpackage": false,
            "state": "latest",
            "type": "package",
            "update_cache": false
        }
    },
    "item": [
        "apache2",
        "apache2-utils"
    ],
    "name": [
        "apache2",
        "apache2-utils"
    ],
    "rc": 0,
    "state": "latest",
    "update_cache": false
}
ERROR! Unexpected Exception: unsupported operand type(s) for |=: 'bool' and 'dict'
the full traceback was:

Traceback (most recent call last):
  File "/home/****/ansible/bin/ansible-playbook", line 97, in <module>
    exit_code = cli.run()
  File "/home/****/ansible/lib/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/home/****/ansible/lib/ansible/executor/playbook_executor.py", line 147, in run
    result = self._tqm.run(play=play)
  File "/home/****/ansible/lib/ansible/executor/task_queue_manager.py", line 281, in run
    play_return = strategy.run(iterator, play_context)
  File "/home/****/ansible/lib/ansible/plugins/strategy/linear.py", line 269, in run
    results += self._wait_on_pending_results(iterator)
  File "/home/****/ansible/lib/ansible/plugins/strategy/__init__.py", line 514, in _wait_on_pending_results
    results = self._process_pending_results(iterator)
  File "/home/****/ansible/lib/ansible/plugins/strategy/__init__.py", line 370, in _process_pending_results
    if task_result.is_changed():
  File "/home/****/ansible/lib/ansible/executor/task_result.py", line 40, in is_changed
    return self._check_key('changed')
  File "/home/****/ansible/lib/ansible/executor/task_result.py", line 69, in _check_key
    flag |= res.get(key, False)
TypeError: unsupported operand type(s) for |=: 'bool' and 'dict'

AND WITHOUT -vvvv

TASK [apache-proxy : install apache and apache modules] ************************
ok: [sazvl0021.saz.bosch-si.com] => (item=[u'apache2', u'apache2-utils'])
ERROR! Unexpected Exception: unsupported operand type(s) for |=: 'bool' and 'dict'
```



Discussion:
<!-- @Hoall: Thanks for filing this bug report! -->

@robinro ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->

<!-- @Hoall: Thanks for filing this bug report! -->

@robinro ping, this issue is waiting for your response.
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)

<!--- boilerplate: issue_bug_new --->


Resolving patch:
diff --git a/packaging/os/zypper.py b/packaging/os/zypper.py
--- a/packaging/os/zypper.py
+++ b/packaging/os/zypper.py
@@ -427,7 +427,7 @@ def main():
         elif state in ['installed', 'present', 'latest']:
             packages_changed, retvals = package_present(module, name, state == 'latest')
 
-    retvals['changed'] = retvals['rc'] == 0 and packages_changed
+    retvals['changed'] = retvals['rc'] == 0 and bool(packages_changed)
 
     if module._diff:
         set_diff(module, retvals, packages_changed)


Test patch: