From 44bde4609778d8ae9038b983b85000cbe1e73b6f Mon Sep 17 00:00:00 2001
From: Jonathan Mainguy <jon@soh.re>
Date: Wed, 2 Dec 2015 23:24:23 -0500
Subject: [PATCH] Add ability to download deb from url

if :// in deb, will try to download from url.
---
 lib/ansible/modules/packaging/os/apt.py | 32 +++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 mode change 100755 => 100644 lib/ansible/modules/packaging/os/apt.py

diff --git a/lib/ansible/modules/packaging/os/apt.py b/lib/ansible/modules/packaging/os/apt.py
old mode 100755
new mode 100644
index fa0a86603e8..2220d2d9cf3
--- a/lib/ansible/modules/packaging/os/apt.py
+++ b/lib/ansible/modules/packaging/os/apt.py
@@ -92,6 +92,7 @@ options:
   deb:
      description:
        - Path to a .deb package on the remote machine.
+       - If :// in the path, ansible will attempt to download deb before installing. (Version added 2.1)
      required: false
      version_added: "1.6"
   autoremove:
@@ -144,6 +145,9 @@ EXAMPLES = '''
 
 # Install the build dependencies for package "foo"
 - apt: pkg=foo state=build-dep
+
+# Install a .deb package from the internet.
+- apt: deb=https://example.com/python-ppq_0.1-1_all.deb
 '''
 
 RETURN = '''
@@ -555,6 +559,31 @@ def upgrade(m, mode="yes", force=False, default_release=None,
         m.exit_json(changed=False, msg=out, stdout=out, stderr=err)
     m.exit_json(changed=True, msg=out, stdout=out, stderr=err)
 
+def download(module, deb):
+    tempdir = os.path.dirname(__file__)
+    package = os.path.join(tempdir, str(deb.rsplit('/', 1)[1]))
+    # When downloading a deb, how much of the deb to download before
+    # saving to a tempfile (64k)
+    BUFSIZE = 65536
+
+    try:
+        rsp, info = fetch_url(module, deb)
+        f = open(package, 'w')
+        # Read 1kb at a time to save on ram
+        while True:
+            data = rsp.read(BUFSIZE)
+
+            if data == "":
+                break # End of file, break while loop
+
+            f.write(data)
+        f.close()
+        deb = package
+    except Exception, e:
+        module.fail_json(msg="Failure downloading %s, %s" % (deb, e))
+
+    return deb
+
 def main():
     module = AnsibleModule(
         argument_spec = dict(
@@ -667,6 +696,8 @@ def main():
         if p['deb']:
             if p['state'] != 'present':
                 module.fail_json(msg="deb only supports state=present")
+            if '://' in p['deb']:
+                p['deb'] = download(module, p['deb'])
             install_deb(module, p['deb'], cache,
                         install_recommends=install_recommends,
                         force=force_yes, dpkg_options=p['dpkg_options'])
@@ -708,6 +739,7 @@ def main():
 
 # import module snippets
 from ansible.module_utils.basic import *
+from ansible.module_utils.urls import *
 
 if __name__ == "__main__":
     main()