|
@@ -0,0 +1,212 @@
|
|
|
+#!/usr/bin/python2.7 -tt
|
|
|
+# -*- coding: utf-8 -*-
|
|
|
+
|
|
|
+def update_package_db(module, paths):
|
|
|
+ cmd = "%s -S" % paths['install']
|
|
|
+ rc, sout, serr = module.run_command(cmd, check_rc=False)
|
|
|
+
|
|
|
+ if rc == 0:
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ module.fail_json(msg="could not update package db", rc=rc, stdout=sout, stderr=serr)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def query_package(module, paths, pkg):
|
|
|
+ '''
|
|
|
+ pkg: a package name
|
|
|
+ returns: (installed, available, latest) as booleans
|
|
|
+ '''
|
|
|
+ query_local = '%s -S %s | grep "^pkgver: "' % (paths['query'], pkg)
|
|
|
+ query_repo = '%s -RS %s | grep "^pkgver: "' % (paths['query'], pkg)
|
|
|
+
|
|
|
+ # query local installed packages
|
|
|
+ qlrc, qlsout, qlserr = module.run_command(query_local, use_unsafe_shell=True, check_rc=False)
|
|
|
+ if qlrc == 0:
|
|
|
+ # pkg installed
|
|
|
+ installed = True
|
|
|
+ else:
|
|
|
+ installed = False
|
|
|
+
|
|
|
+ # query repo conent
|
|
|
+ qrrc, qrsout, qrserr = module.run_command(query_repo, use_unsafe_shell=True, check_rc=False)
|
|
|
+ if qrrc == 0:
|
|
|
+ # pkg available
|
|
|
+ available = True
|
|
|
+ else:
|
|
|
+ available = False
|
|
|
+
|
|
|
+ if qlsout == qrsout:
|
|
|
+ # same pkgver
|
|
|
+ latest = True
|
|
|
+ else:
|
|
|
+ latest = False
|
|
|
+
|
|
|
+ #FIXME module.fail_json(msg='foo', ql=query_local, qlrc=qlrc, qlsout=qlsout, qlserr=qlserr, qr=query_repo, qrrc=qrrc, qrsout=qrsout, qrserr=qrserr)
|
|
|
+ return (installed, available, latest)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def get_changed_packages(module, paths, pkgs, desired_state):
|
|
|
+ '''
|
|
|
+ pkgs: list of packages
|
|
|
+ desired_state: desired state (present, latest, absent)
|
|
|
+ returns: list of packages to be changed
|
|
|
+ '''
|
|
|
+ to_be_changed = []
|
|
|
+ for pkg in pkgs:
|
|
|
+ (installed, available, latest) = query_package(module, paths, pkg)
|
|
|
+ #FIXME module.fail_json(msg='foo', installed=installed, available=available, latest=latest)
|
|
|
+ if desired_state == 'latest' and not latest:
|
|
|
+ to_be_changed.append(pkg)
|
|
|
+ elif desired_state == 'present' and not installed:
|
|
|
+ to_be_changed.append(pkg)
|
|
|
+ elif desired_state == 'absent' and installed:
|
|
|
+ to_be_changed.append(pkg)
|
|
|
+
|
|
|
+ return to_be_changed
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def check_packages(module, paths, pkgs, desired_state):
|
|
|
+ '''
|
|
|
+ pkgs: list of packages
|
|
|
+ desired_state: desired state (present, latest, absent)
|
|
|
+ retuns: n/a, exit module
|
|
|
+ '''
|
|
|
+ to_be_changed = get_changed_packages(module, paths, pkgs, desired_state)
|
|
|
+
|
|
|
+ if to_be_changed:
|
|
|
+ module.exit_json(changed=True, msg="%s package(s) not in state %s" % (
|
|
|
+ len(to_be_changed), state))
|
|
|
+ else:
|
|
|
+ module.exit_json(changed=False, msg="package(s) already in state %s" % state)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def upgrade(module, paths, check_mode):
|
|
|
+ '''
|
|
|
+ returns: (updates_available, updates_successful)
|
|
|
+ '''
|
|
|
+ # Check for updates
|
|
|
+ cmd = "%s -un" % paths['install']
|
|
|
+ rc, sout, serr = module.run_command(cmd, check_rc=False)
|
|
|
+
|
|
|
+ if sout:
|
|
|
+ # packages for upgrade available
|
|
|
+ if check_mode:
|
|
|
+ return (True, False)
|
|
|
+
|
|
|
+ # do upgrade
|
|
|
+ cmd = "%s -uy" % paths['install']
|
|
|
+ rc, sout, serr = module.run_command(cmd, check_rc=False)
|
|
|
+
|
|
|
+ if rc == 0:
|
|
|
+ return (True, True)
|
|
|
+ else:
|
|
|
+ module.fail_json(msg="could not upgrade packages", rc=rc, stdout=sout, stderr=serr)
|
|
|
+ else:
|
|
|
+ return (False, False)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def ensure_packages_state(module, paths, pkgs, desired_state):
|
|
|
+ '''
|
|
|
+ pkgs: list of packages
|
|
|
+ desired_state: desired state (present, latest, absent)
|
|
|
+ returns: list of packages to be changed
|
|
|
+ '''
|
|
|
+
|
|
|
+ # which packages must change state
|
|
|
+ pkgs2do = get_changed_packages(module, paths, pkgs, desired_state)
|
|
|
+
|
|
|
+ if not pkgs2do:
|
|
|
+ module.exit_json(msg='All packages in desired state')
|
|
|
+
|
|
|
+ if desired_state in ['present', 'latest']:
|
|
|
+ cmdtype = 'install'
|
|
|
+ elif desired_state == 'absent':
|
|
|
+ cmdtype = 'remove'
|
|
|
+
|
|
|
+ cmd = '%s -y %s' % (paths[cmdtype], ' '.join(pkgs2do))
|
|
|
+ rc, sout, serr = module.run_command(cmd, check_rc=False)
|
|
|
+
|
|
|
+ if rc == 0:
|
|
|
+ msg = '%s package' % len(pkgs2do)
|
|
|
+ msg += '%s ' % len(pkgs2do) == 1 and '' or 's'
|
|
|
+ if cmdtype == 'install':
|
|
|
+ msg += 'installed'
|
|
|
+ elif cmdtype == 'remove':
|
|
|
+ msg += 'removed'
|
|
|
+ module.exit_json(msg=msg, rc=rc, stdout=sout, stderr=serr)
|
|
|
+ else:
|
|
|
+ module.fail_json(msg="could not install/remove package(s)", rc=rc, stdout=sout, stderr=serr)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ module = AnsibleModule(
|
|
|
+ argument_spec = dict(
|
|
|
+ name = dict(aliases=['pkg', 'package'], type='list'),
|
|
|
+ state = dict(default='present', choices=['present', 'installed', "latest", 'absent', 'removed']),
|
|
|
+ force = dict(default=False, type='bool'),
|
|
|
+ upgrade = dict(default=False, type='bool'),
|
|
|
+ update_cache = dict(default=False, aliases=['update-cache'], type='bool')
|
|
|
+ ),
|
|
|
+ required_one_of = [['name', 'update_cache', 'upgrade']],
|
|
|
+ supports_check_mode = True)
|
|
|
+
|
|
|
+ paths = {}
|
|
|
+ paths['install'] = module.get_bin_path('xbps-install', True)
|
|
|
+ paths['remove'] = module.get_bin_path('xbps-remove', True)
|
|
|
+ paths['query'] = module.get_bin_path('xbps-query', True)
|
|
|
+
|
|
|
+ p = module.params
|
|
|
+
|
|
|
+ # normalize the state parameter
|
|
|
+ if p['state'] in ['present', 'installed']:
|
|
|
+ p['state'] = 'present'
|
|
|
+ elif p['state'] in ['absent', 'removed']:
|
|
|
+ p['state'] = 'absent'
|
|
|
+
|
|
|
+ # do update if package name is "*"
|
|
|
+ if p['name'] and p['name'][0] == '*' and p['state'] == 'latest':
|
|
|
+ p['update'] = True
|
|
|
+ p['name'] = []
|
|
|
+
|
|
|
+ # sync repo index
|
|
|
+ if p["update_cache"] and not module.check_mode:
|
|
|
+ update_package_db(module, paths) # FIXME
|
|
|
+ if not (p['name'] or p['upgrade']):
|
|
|
+ module.exit_json(changed=True, msg='Updated the package master lists')
|
|
|
+
|
|
|
+ if p['update_cache'] and module.check_mode and not (p['name'] or p['upgrade']):
|
|
|
+ module.exit_json(changed=True, msg='Would have updated the package cache')
|
|
|
+
|
|
|
+ # update/upgrade all installed packages
|
|
|
+ if p['upgrade']:
|
|
|
+ (upg_avail, upg_successful) = upgrade(module, paths, module.check_mode)
|
|
|
+ if not p['name']: # upgrade is last action
|
|
|
+ if upg_avail:
|
|
|
+ if upg_successful:
|
|
|
+ module.exit_json(changed=True, msg="all packages upgraded")
|
|
|
+ else:
|
|
|
+ if module.check_mode:
|
|
|
+ module.exit_json(msg="no packages upgraded in check mode")
|
|
|
+ # should never happen, "upgrade" function should exit module
|
|
|
+ module.fail_json(msg="could not upgrade packages", rc=rc, stdout=sout, stderr=serr)
|
|
|
+ else:
|
|
|
+ module.exit_json(msg="all packages uptodate")
|
|
|
+
|
|
|
+ if p['name']:
|
|
|
+ if module.check_mode:
|
|
|
+ check_packages(module, paths, p['name'], p['state']) # FIXME
|
|
|
+
|
|
|
+ ensure_packages_state(module, paths, p['name'], p['state']) # FIXME
|
|
|
+
|
|
|
+# import module snippets
|
|
|
+from ansible.module_utils.basic import *
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ main()
|
|
|
+
|