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
This commit is contained in:
tdtrask 2017-05-24 12:28:41 -04:00 committed by ansibot
parent 37e5454839
commit 0d761e4568

View file

@ -32,11 +32,25 @@ description:
author: "Kevin Brebanov (@kbrebanov)" author: "Kevin Brebanov (@kbrebanov)"
version_added: "2.0" version_added: "2.0"
options: 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: name:
description: description:
- A package name, like C(foo), or mutliple packages, like C(foo, bar). - A package name, like C(foo), or mutliple packages, like C(foo, bar).
required: false required: false
default: null default: null
repository:
description:
- A package repository or multiple repositories
required: false
default: null
version_added: "2.4"
state: state:
description: description:
- Indicates the desired package(s) state. - Indicates the desired package(s) state.
@ -109,23 +123,54 @@ EXAMPLES = '''
- apk: - apk:
upgrade: yes 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 # Update repositories as a separate step
- apk: - apk:
update_cache: yes 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 re
# Import module snippets. # Import module snippets.
from ansible.module_utils.basic import AnsibleModule 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) cmd = "%s update" % (APK_PATH)
rc, stdout, stderr = module.run_command(cmd, check_rc=False) rc, stdout, stderr = module.run_command(cmd, check_rc=False)
if rc == 0: if rc != 0:
return True 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: else:
module.fail_json(msg="could not update package db") return True
def query_package(module, name): def query_package(module, name):
cmd = "%s -v info --installed %s" % (APK_PATH, name) cmd = "%s -v info --installed %s" % (APK_PATH, name)
@ -161,17 +206,20 @@ def get_dependencies(module, name):
else: else:
return [] return []
def upgrade_packages(module): def upgrade_packages(module, available):
if module.check_mode: if module.check_mode:
cmd = "%s upgrade --simulate" % (APK_PATH) cmd = "%s upgrade --simulate" % (APK_PATH)
else: else:
cmd = "%s upgrade" % (APK_PATH) cmd = "%s upgrade" % (APK_PATH)
if available:
cmd = "%s --available" % cmd
rc, stdout, stderr = module.run_command(cmd, check_rc=False) rc, stdout, stderr = module.run_command(cmd, check_rc=False)
packagelist = parse_for_packages(stdout)
if rc != 0: 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): if re.search(r'^OK', stdout):
module.exit_json(changed=False, msg="packages already upgraded") module.exit_json(changed=False, msg="packages already upgraded", stdout=stdout, stderr=stderr, packages=packagelist)
module.exit_json(changed=True, msg="upgraded packages") module.exit_json(changed=True, msg="upgraded packages", stdout=stdout, stderr=stderr, packages=packagelist)
def install_packages(module, names, state): def install_packages(module, names, state):
upgrade = False upgrade = False
@ -206,9 +254,10 @@ def install_packages(module, names, state):
else: else:
cmd = "%s add %s" % (APK_PATH, packages) cmd = "%s add %s" % (APK_PATH, packages)
rc, stdout, stderr = module.run_command(cmd, check_rc=False) rc, stdout, stderr = module.run_command(cmd, check_rc=False)
packagelist = parse_for_packages(stdout)
if rc != 0: if rc != 0:
module.fail_json(msg="failed to install %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)) module.exit_json(changed=True, msg="installed %s package(s)" % (packages), stdout=stdout, stderr=stderr, packages=packagelist)
def remove_packages(module, names): def remove_packages(module, names):
installed = [] installed = []
@ -223,9 +272,10 @@ def remove_packages(module, names):
else: else:
cmd = "%s del --purge %s" % (APK_PATH, names) cmd = "%s del --purge %s" % (APK_PATH, names)
rc, stdout, stderr = module.run_command(cmd, check_rc=False) rc, stdout, stderr = module.run_command(cmd, check_rc=False)
packagelist = parse_for_packages(stdout)
if rc != 0: if rc != 0:
module.fail_json(msg="failed to remove %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)) module.exit_json(changed=True, msg="removed %s package(s)" % (names), stdout=stdout, stderr=stderr, packages=packagelist)
# ========================================== # ==========================================
# Main control flow. # Main control flow.
@ -235,8 +285,10 @@ def main():
argument_spec=dict( argument_spec=dict(
state=dict(default='present', choices=['present', 'installed', 'absent', 'removed', 'latest']), state=dict(default='present', choices=['present', 'installed', 'absent', 'removed', 'latest']),
name=dict(type='list'), name=dict(type='list'),
repository=dict(type='list'),
update_cache=dict(default='no', type='bool'), update_cache=dict(default='no', type='bool'),
upgrade=dict(default='no', type='bool'), upgrade=dict(default='no', type='bool'),
available=dict(default='no', type='bool'),
), ),
required_one_of=[['name', 'update_cache', 'upgrade']], required_one_of=[['name', 'update_cache', 'upgrade']],
mutually_exclusive=[['name', 'upgrade']], mutually_exclusive=[['name', 'upgrade']],
@ -251,6 +303,11 @@ def main():
p = module.params 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 # normalize the state parameter
if p['state'] in ['present', 'installed']: if p['state'] in ['present', 'installed']:
p['state'] = 'present' p['state'] = 'present'
@ -258,12 +315,10 @@ def main():
p['state'] = 'absent' p['state'] = 'absent'
if p['update_cache']: if p['update_cache']:
update_package_db(module) update_package_db(module, not p['name'] and not p['upgrade'])
if not p['name']:
module.exit_json(changed=True, msg='updated repository indexes')
if p['upgrade']: if p['upgrade']:
upgrade_packages(module) upgrade_packages(module, p['available'])
if p['state'] in ['present', 'latest']: if p['state'] in ['present', 'latest']:
install_packages(module, p['name'], p['state']) install_packages(module, p['name'], p['state'])