From 0d761e4568fd2cf393114b648dac657afa0d3400 Mon Sep 17 00:00:00 2001 From: tdtrask Date: Wed, 24 May 2017 12:28:41 -0400 Subject: [PATCH] Add apk available and repository (#24146) * apk: Allow update and upgrade in same task * apk: Add repository option * apk: Add available option * apk: Add stdout and stderr output where possible * apk: Add packages return with list of changed packages --- lib/ansible/modules/packaging/os/apk.py | 87 ++++++++++++++++++++----- 1 file changed, 71 insertions(+), 16 deletions(-) diff --git a/lib/ansible/modules/packaging/os/apk.py b/lib/ansible/modules/packaging/os/apk.py index f4fb035541..f9f8e06079 100644 --- a/lib/ansible/modules/packaging/os/apk.py +++ b/lib/ansible/modules/packaging/os/apk.py @@ -32,11 +32,25 @@ description: author: "Kevin Brebanov (@kbrebanov)" version_added: "2.0" options: + available: + description: + - During upgrade, reset versioned world dependencies and change logic to prefer replacing or downgrading packages (instead of holding them) + if the currently installed package is no longer available from any repository. + required: false + default: no + choices: [ "yes", "no" ] + version_added: "2.4" name: description: - A package name, like C(foo), or mutliple packages, like C(foo, bar). required: false default: null + repository: + description: + - A package repository or multiple repositories + required: false + default: null + version_added: "2.4" state: description: - Indicates the desired package(s) state. @@ -109,23 +123,54 @@ EXAMPLES = ''' - apk: upgrade: yes +# Upgrade / replace / downgrade / uninstall all installed packages to the latest versions available +- apk: + available: yes + upgrade: yes + # Update repositories as a separate step - apk: update_cache: yes + +# Install package from a specific repository +- apk: + name: foo + state: latest + update_cache: yes + repository: http://dl-3.alpinelinux.org/alpine/edge/main ''' +RETURN = ''' +packages: + description: a list of packages that have been changed + returned: when packages have changed + type: list + sample: ['package', 'other-package'] +''' import re # Import module snippets. from ansible.module_utils.basic import AnsibleModule -def update_package_db(module): +def parse_for_packages(stdout): + packages = [] + data = stdout.split('\n') + regex = re.compile('^\(\d+/\d+\)\s+\S+\s+(\S+)') + for l in data: + p = regex.search(l) + if p: + packages.append(p.group(1)) + return packages + +def update_package_db(module, exit): cmd = "%s update" % (APK_PATH) rc, stdout, stderr = module.run_command(cmd, check_rc=False) - if rc == 0: - return True + if rc != 0: + module.fail_json(msg="could not update package db", stdout=stdout, stderr=stderr) + elif exit: + module.exit_json(changed=True, msg='updated repository indexes', stdout=stdout, stderr=stderr) else: - module.fail_json(msg="could not update package db") + return True def query_package(module, name): cmd = "%s -v info --installed %s" % (APK_PATH, name) @@ -161,17 +206,20 @@ def get_dependencies(module, name): else: return [] -def upgrade_packages(module): +def upgrade_packages(module, available): if module.check_mode: cmd = "%s upgrade --simulate" % (APK_PATH) else: cmd = "%s upgrade" % (APK_PATH) + if available: + cmd = "%s --available" % cmd rc, stdout, stderr = module.run_command(cmd, check_rc=False) + packagelist = parse_for_packages(stdout) if rc != 0: - module.fail_json(msg="failed to upgrade packages") + module.fail_json(msg="failed to upgrade packages", stdout=stdout, stderr=stderr, packages=packagelist) if re.search(r'^OK', stdout): - module.exit_json(changed=False, msg="packages already upgraded") - module.exit_json(changed=True, msg="upgraded packages") + module.exit_json(changed=False, msg="packages already upgraded", stdout=stdout, stderr=stderr, packages=packagelist) + module.exit_json(changed=True, msg="upgraded packages", stdout=stdout, stderr=stderr, packages=packagelist) def install_packages(module, names, state): upgrade = False @@ -206,9 +254,10 @@ def install_packages(module, names, state): else: cmd = "%s add %s" % (APK_PATH, packages) rc, stdout, stderr = module.run_command(cmd, check_rc=False) + packagelist = parse_for_packages(stdout) if rc != 0: - module.fail_json(msg="failed to install %s" % (packages)) - module.exit_json(changed=True, msg="installed %s package(s)" % (packages)) + module.fail_json(msg="failed to install %s" % (packages), stdout=stdout, stderr=stderr, packages=packagelist) + module.exit_json(changed=True, msg="installed %s package(s)" % (packages), stdout=stdout, stderr=stderr, packages=packagelist) def remove_packages(module, names): installed = [] @@ -223,9 +272,10 @@ def remove_packages(module, names): else: cmd = "%s del --purge %s" % (APK_PATH, names) rc, stdout, stderr = module.run_command(cmd, check_rc=False) + packagelist = parse_for_packages(stdout) if rc != 0: - module.fail_json(msg="failed to remove %s package(s)" % (names)) - module.exit_json(changed=True, msg="removed %s package(s)" % (names)) + module.fail_json(msg="failed to remove %s package(s)" % (names), stdout=stdout, stderr=stderr, packages=packagelist) + module.exit_json(changed=True, msg="removed %s package(s)" % (names), stdout=stdout, stderr=stderr, packages=packagelist) # ========================================== # Main control flow. @@ -235,8 +285,10 @@ def main(): argument_spec=dict( state=dict(default='present', choices=['present', 'installed', 'absent', 'removed', 'latest']), name=dict(type='list'), + repository=dict(type='list'), update_cache=dict(default='no', type='bool'), upgrade=dict(default='no', type='bool'), + available=dict(default='no', type='bool'), ), required_one_of=[['name', 'update_cache', 'upgrade']], mutually_exclusive=[['name', 'upgrade']], @@ -251,6 +303,11 @@ def main(): p = module.params + # add repositories to the APK_PATH + if p['repository']: + for r in p['repository']: + APK_PATH = "%s --repository %s" % (APK_PATH, r) + # normalize the state parameter if p['state'] in ['present', 'installed']: p['state'] = 'present' @@ -258,12 +315,10 @@ def main(): p['state'] = 'absent' if p['update_cache']: - update_package_db(module) - if not p['name']: - module.exit_json(changed=True, msg='updated repository indexes') + update_package_db(module, not p['name'] and not p['upgrade']) if p['upgrade']: - upgrade_packages(module) + upgrade_packages(module, p['available']) if p['state'] in ['present', 'latest']: install_packages(module, p['name'], p['state'])