Commit c4b5e460 by James Cammarata

Backporting apt_repository module from devel

parent f1f63829
......@@ -28,7 +28,7 @@ short_description: Add and remove APT repositores
description:
- Add or remove an APT repositories in Ubuntu and Debian.
notes:
- This module works on Debian and Ubuntu and requires C(python-apt) and C(python-pycurl) packages.
- This module works on Debian and Ubuntu and requires C(python-apt).
- This module supports Debian Squeeze (version 6) as well as its successors.
- This module treats Debian and Ubuntu distributions separately. So PPA could be installed only on Ubuntu machines.
options:
......@@ -43,15 +43,21 @@ options:
default: "present"
description:
- A source string state.
mode:
required: false
default: 0644
description:
- The octal mode for newly created files in sources.list.d
version_added: "1.6"
update_cache:
description:
- Run the equivalent of C(apt-get update) if has changed.
- Run the equivalent of C(apt-get update) when a change occurs. Cache updates are run after making changes.
required: false
default: "yes"
choices: [ "yes", "no" ]
author: Alexander Saltanov
version_added: "0.7"
requirements: [ python-apt, python-pycurl ]
requirements: [ python-apt ]
'''
EXAMPLES = '''
......@@ -70,10 +76,6 @@ apt_repository: repo='ppa:nginx/stable'
'''
import glob
try:
import json
except ImportError:
import simplejson as json
import os
import re
import tempfile
......@@ -87,22 +89,19 @@ try:
except ImportError:
HAVE_PYTHON_APT = False
try:
import pycurl
HAVE_PYCURL = True
except ImportError:
HAVE_PYCURL = False
VALID_SOURCE_TYPES = ('deb', 'deb-src')
def install_python_apt(module):
class CurlCallback:
def __init__(self):
self.contents = ''
def body_callback(self, buf):
self.contents = self.contents + buf
if not module.check_mode:
apt_get_path = module.get_bin_path('apt-get')
if apt_get_path:
rc, so, se = module.run_command('%s update && %s install python-apt -y -q' % (apt_get_path, apt_get_path))
if rc == 0:
global apt, apt_pkg
import apt
import apt_pkg
class InvalidSource(Exception):
pass
......@@ -140,12 +139,22 @@ class SourcesList(object):
def _suggest_filename(self, line):
def _cleanup_filename(s):
return '_'.join(re.sub('[^a-zA-Z0-9]', ' ', s).split())
def _strip_username_password(s):
if '@' in s:
s = s.split('@', 1)
s = s[-1]
return s
# Drop options and protocols.
line = re.sub('\[[^\]]+\]', '', line)
line = re.sub('\w+://', '', line)
# split line into valid keywords
parts = [part for part in line.split() if part not in VALID_SOURCE_TYPES]
# Drop usernames and passwords
parts[0] = _strip_username_password(parts[0])
return '%s.list' % _cleanup_filename(' '.join(parts[:1]))
def _parse(self, line, raise_if_invalid_or_disabled=False):
......@@ -214,7 +223,10 @@ class SourcesList(object):
if sources:
d, fn = os.path.split(filename)
fd, tmp_path = tempfile.mkstemp(prefix=".%s-" % fn, dir=d)
os.chmod(os.path.join(fd, tmp_path), 0644)
# allow the user to override the default mode
this_mode = module.params['mode']
module.set_mode_if_different(tmp_path, this_mode, False)
f = os.fdopen(fd, 'w')
for n, valid, enabled, source, comment in sources:
......@@ -290,29 +302,19 @@ class SourcesList(object):
class UbuntuSourcesList(SourcesList):
LP_API = 'https://launchpad.net/api/1.0/~%s/+archive/%s'
LP_API = 'https://launchpad.net/api/1.0/~%s/+archive/%s'
def __init__(self, add_ppa_signing_keys_callback=None):
def __init__(self, module, add_ppa_signing_keys_callback=None):
self.module = module
self.add_ppa_signing_keys_callback = add_ppa_signing_keys_callback
super(UbuntuSourcesList, self).__init__()
def _get_ppa_info(self, owner_name, ppa_name):
# we can not use urllib2 here as it does not do cert verification
lp_api = self.LP_API % (owner_name, ppa_name)
return self._get_ppa_info_curl(lp_api)
def _get_ppa_info_curl(self, lp_api):
callback = CurlCallback()
curl = pycurl.Curl()
curl.setopt(pycurl.SSL_VERIFYPEER, 1)
curl.setopt(pycurl.SSL_VERIFYHOST, 2)
curl.setopt(pycurl.WRITEFUNCTION, callback.body_callback)
curl.setopt(pycurl.URL, str(lp_api))
curl.setopt(pycurl.HTTPHEADER, ["Accept: application/json"])
curl.perform()
curl.close()
lp_page = callback.contents
return json.loads(lp_page)
headers = dict(Accept='application/json')
response, info = fetch_url(self.module, lp_api, headers=headers)
return json.load(response)
def _expand_ppa(self, path):
ppa = path.split(':')[1]
......@@ -363,16 +365,17 @@ def main():
argument_spec=dict(
repo=dict(required=True),
state=dict(choices=['present', 'absent'], default='present'),
mode=dict(required=False, default=0644),
update_cache = dict(aliases=['update-cache'], type='bool', default='yes'),
# this should not be needed, but exists as a failsafe
install_python_apt=dict(required=False, default="yes", type='bool'),
),
supports_check_mode=True,
)
if not HAVE_PYTHON_APT:
module.fail_json(msg='Could not import python modules: apt_pkg. Please install python-apt package.')
if not HAVE_PYCURL:
module.fail_json(msg='Could not import python modules: pycurl. Please install python-pycurl package.')
params = module.params
if params['install_python_apt'] and not HAVE_PYTHON_APT and not module.check_mode:
install_python_apt(module)
repo = module.params['repo']
state = module.params['state']
......@@ -380,7 +383,8 @@ def main():
sourceslist = None
if isinstance(distro, aptsources.distro.UbuntuDistribution):
sourceslist = UbuntuSourcesList(add_ppa_signing_keys_callback=get_add_ppa_signing_key_callback(module))
sourceslist = UbuntuSourcesList(module,
add_ppa_signing_keys_callback=get_add_ppa_signing_key_callback(module))
elif isinstance(distro, aptsources.distro.DebianDistribution) or \
isinstance(distro, aptsources.distro.Distribution):
sourceslist = SourcesList()
......@@ -413,5 +417,6 @@ def main():
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment