Repository: ansible/ansible-modules-core

Issue:
Apt Module deb option failure
<!--- Verify first that your issue/request is not already reported in GitHub -->
##### ISSUE TYPE

<!--- Pick one below and delete the rest: -->
- Bug Report
##### ANSIBLE VERSION

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

```
ansible 2.1.0.0
  config file = /home/ubuntu/.ansible.cfg
  configured module search path = Default w/o overrides
```
##### CONFIGURATION

<!---
Default configuration
-->
##### OS / ENVIRONMENT

Both Host and Target are running Ubuntu 14.04 LTS 64bit
##### SUMMARY

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

After updating to Ansible 2.1.0.0 from 2.0.2.0 the deb option in Apt module is no longer working.
##### STEPS TO REPRODUCE

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

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

Running the following:

```
- name: Install Jenkins version
  apt: deb=http://pkg.jenkins-ci.org/debian/binary/jenkins_1.626_all.deb
```

I also manually downloaded the package, and attempted to run with the following:

```
- name: Install Jenkins version
  apt: deb=/tmp/jenkins_1.626_all.deb
```

Both yielded the same error.

Manually ssh'ing into the machine and running the following was successful:

```
sudo dpkg -i /tmp/jenkins_1.626_all.deb
```

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

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

Debian package to be installed.
##### ACTUAL RESULTS

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

Run with -vvvvvvv

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

```

TASK [jenkins : Install Jenkins version] ***************************************
task path: /tmp/operations/ansible/linux/roles/jenkins/tasks/debian.yml:7
<10.0.15.119> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<10.0.15.119> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<10.0.15.119> SSH: ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled: (-o)(StrictHostKeyChecking=no)
<10.0.15.119> SSH: ansible_password/ansible_ssh_pass not set: (-o)(KbdInteractiveAuthentication=no)(-o)(PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey)(-o)(PasswordAuthentication=no)
<10.0.15.119> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=ubuntu)
<10.0.15.119> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<10.0.15.119> SSH: PlayContext set ssh_common_args: ()
<10.0.15.119> SSH: PlayContext set ssh_extra_args: ()
<10.0.15.119> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/home/ubuntu/.ansible/cp/ansible-ssh-%h-%p-%r)
<10.0.15.119> SSH: EXEC ssh -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/home/ubuntu/.ansible/cp/ansible-ssh-%h-%p-%r 10.0.15.119 '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1464200759.5-271946676011887 `" && echo ansible-tmp-1464200759.5-271946676011887="` echo $HOME/.ansible/tmp/ansible-tmp-1464200759.5-271946676011887 `" ) && sleep 0'"'"''
<10.0.15.119> PUT /tmp/tmp7PkmRZ TO /home/ubuntu/.ansible/tmp/ansible-tmp-1464200759.5-271946676011887/apt
<10.0.15.119> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<10.0.15.119> SSH: ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled: (-o)(StrictHostKeyChecking=no)
<10.0.15.119> SSH: ansible_password/ansible_ssh_pass not set: (-o)(KbdInteractiveAuthentication=no)(-o)(PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey)(-o)(PasswordAuthentication=no)
<10.0.15.119> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=ubuntu)
<10.0.15.119> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<10.0.15.119> SSH: PlayContext set ssh_common_args: ()
<10.0.15.119> SSH: PlayContext set sftp_extra_args: ()
<10.0.15.119> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/home/ubuntu/.ansible/cp/ansible-ssh-%h-%p-%r)
<10.0.15.119> SSH: EXEC sftp -b - -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/home/ubuntu/.ansible/cp/ansible-ssh-%h-%p-%r '[10.0.15.119]'
<10.0.15.119> ESTABLISH SSH CONNECTION FOR USER: ubuntu
<10.0.15.119> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<10.0.15.119> SSH: ANSIBLE_HOST_KEY_CHECKING/host_key_checking disabled: (-o)(StrictHostKeyChecking=no)
<10.0.15.119> SSH: ansible_password/ansible_ssh_pass not set: (-o)(KbdInteractiveAuthentication=no)(-o)(PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey)(-o)(PasswordAuthentication=no)
<10.0.15.119> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=ubuntu)
<10.0.15.119> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<10.0.15.119> SSH: PlayContext set ssh_common_args: ()
<10.0.15.119> SSH: PlayContext set ssh_extra_args: ()
<10.0.15.119> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=/home/ubuntu/.ansible/cp/ansible-ssh-%h-%p-%r)
<10.0.15.119> SSH: EXEC ssh -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=ubuntu -o ConnectTimeout=10 -o ControlPath=/home/ubuntu/.ansible/cp/ansible-ssh-%h-%p-%r -tt 10.0.15.119 '/bin/sh -c '"'"'sudo -H -S -n -u root /bin/sh -c '"'"'"'"'"'"'"'"'echo BECOME-SUCCESS-dlcojcwhibdwafgkkphhfpcvsmwhcunw; LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 /usr/bin/python /home/ubuntu/.ansible/tmp/ansible-tmp-1464200759.5-271946676011887/apt; rm -rf "/home/ubuntu/.ansible/tmp/ansible-tmp-1464200759.5-271946676011887/" > /dev/null 2>&1'"'"'"'"'"'"'"'"' && sleep 0'"'"''
fatal: [10.0.15.119]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_name": "apt"}, "module_stderr": "OpenSSH_6.6.1, OpenSSL 1.0.1f 6 Jan 2014\r\ndebug1: Reading configuration data /etc/ssh/ssh_config\r\ndebug1: /etc/ssh/ssh_config line 19: Applying options for *\r\ndebug1: auto-mux: Trying existing master\r\ndebug2: fd 3 setting O_NONBLOCK\r\ndebug2: mux_client_hello_exchange: master version 4\r\ndebug3: mux_client_forwards: request forwardings: 0 local, 0 remote\r\ndebug3: mux_client_request_session: entering\r\ndebug3: mux_client_request_alive: entering\r\ndebug3: mux_client_request_alive: done pid = 4331\r\ndebug3: mux_client_request_session: session request sent\r\ndebug1: mux_client_request_session: master session id: 2\r\ndebug3: mux_client_read_packet: read header failed: Broken pipe\r\ndebug2: Received exit status from master 0\r\nShared connection to 10.0.15.119 closed.\r\n", "module_stdout": "\r\nTraceback (most recent call last):\r\n  File \"/tmp/ansible_6mapiy/ansible_module_apt.py\", line 842, in <module>\r\n    main()\r\n  File \"/tmp/ansible_6mapiy/ansible_module_apt.py\", line 798, in main\r\n    force=force_yes, dpkg_options=p['dpkg_options'])\r\n  File \"/tmp/ansible_6mapiy/ansible_module_apt.py\", line 538, in install_deb\r\n    diff[\"prepared\"] += '\\n\\n' + out\r\nKeyError: 'prepared'\r\n", "msg": "MODULE FAILURE", "parsed": false}

```



Discussion:
Same here, also happens with the following code:

``` yml
- name: Download Dropbox
  get_url:
    url=https://www.dropbox.com/download?dl=packages/ubuntu/dropbox_2015.10.28_amd64.deb
    dest=/tmp/dropbox.deb
- name: Install Dropbox
  apt: deb=/tmp/dropbox.deb
```

Error is:

```
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: KeyError: 'prepared'
fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_Klnlu8/ansible_module_apt.py\", line 842, in <module>\n    main()\n  File \"/tmp/ansible_Klnlu8/ansible_module_apt.py\", line 798, in main\n    force=force_yes, dpkg_options=p['dpkg_options'])\n  File \"/tmp/ansible_Klnlu8/ansible_module_apt.py\", line 538, in install_deb\n    diff[\"prepared\"] += '\\n\\n' + out\nKeyError: 'prepared'\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false}
```

I am also seeing this on Debian 7 (wheezy) i386.


Resolving patch:
diff --git a/packaging/os/apt.py b/packaging/os/apt.py
--- a/packaging/os/apt.py
+++ b/packaging/os/apt.py
@@ -535,7 +535,8 @@ def install_deb(m, debs, cache, force, install_recommends, allow_unauthenticated
             stdout = out
         if "diff" in retvals:
             diff = retvals["diff"]
-            diff["prepared"] += '\n\n' + out
+            if 'prepared' in diff:
+                diff['prepared'] += '\n\n' + out
         else:
             diff = out
         if "stderr" in retvals:


Test patch: