#!/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 or serr: module.fail_json(msg="could not update package db", rc=rc, stdout=sout, stderr=serr) else: return True 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') additional_options = [] if desired_state in ['present', 'latest']: cmdtype = 'install' elif desired_state == 'absent': cmdtype = 'remove' if module.params['recurse']: additional_options.append('-R') cmd = '%s %s -y %s' % (paths[cmdtype], ' '.join(additional_options), ' '.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'), recurse = 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()