Zypper repo autoimport keys (#2132)

* zypper_repository add auto_import_keys options

* also give more output on failure (rc, stdout, stderr)

* be more specific in the doc for auto_import_keys

* add runrefresh option to zypper_repository

* this comes out of ansible/ansible-modules-extras#2411, where AnderEnder adds refresh to the zypper module
* adds a way to force zypper to refresh a repository
* can be used to refresh independently of auto_import_keys
* add option to run name=* runrefresh=yes
* name runrefresh to not break existing use to refresh (now alias to autorefresh)
* add version_added flag to autorefresh

* remove wrong version_added comment
This commit is contained in:
Robin Roth 2016-09-04 08:20:10 +02:00 committed by Matt Clay
parent 961c076e72
commit 6c9c4e7482

View file

@ -59,12 +59,13 @@ options:
required: false required: false
default: "no" default: "no"
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
refresh: autorefresh:
description: description:
- Enable autorefresh of the repository. - Enable autorefresh of the repository.
required: false required: false
default: "yes" default: "yes"
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
aliases: [ "refresh" ]
priority: priority:
description: description:
- Set priority of repository. Packages will always be installed - Set priority of repository. Packages will always be installed
@ -80,6 +81,26 @@ options:
default: "no" default: "no"
choices: [ "yes", "no" ] choices: [ "yes", "no" ]
version_added: "2.1" version_added: "2.1"
auto_import_keys:
description:
- Automatically import the gpg signing key of the new or changed repository.
- Has an effect only if state is I(present). Has no effect on existing (unchanged) repositories or in combination with I(absent).
- Implies runrefresh.
required: false
default: "no"
choices: ["yes", "no"]
version_added: "2.2"
runrefresh:
description:
- Refresh the package list of the given repository.
- Can be used with repo=* to refresh all repositories.
required: false
default: "no"
choices: ["yes", "no"]
version_added: "2.2"
requirements: requirements:
- "zypper >= 1.0 # included in openSuSE >= 11.1 or SuSE Linux Enterprise Server/Desktop >= 11.0" - "zypper >= 1.0 # included in openSuSE >= 11.1 or SuSE Linux Enterprise Server/Desktop >= 11.0"
''' '''
@ -93,6 +114,15 @@ EXAMPLES = '''
# Add python development repository # Add python development repository
- zypper_repository: repo=http://download.opensuse.org/repositories/devel:/languages:/python/SLE_11_SP3/devel:languages:python.repo - zypper_repository: repo=http://download.opensuse.org/repositories/devel:/languages:/python/SLE_11_SP3/devel:languages:python.repo
# Refresh all repos
- zypper_repository: repo=* runrefresh=yes
# Add a repo and add it's gpg key
- zypper_repository: repo=http://download.opensuse.org/repositories/systemsmanagement/openSUSE_Leap_42.1/ auto_import_keys=yes
# Force refresh of a repository
- zypper_repository: repo=http://my_internal_ci_repo/repo name=my_ci_repo state=present runrefresh=yes
''' '''
REPO_OPTS = ['alias', 'name', 'priority', 'enabled', 'autorefresh', 'gpgcheck'] REPO_OPTS = ['alias', 'name', 'priority', 'enabled', 'autorefresh', 'gpgcheck']
@ -121,14 +151,10 @@ def _parse_repos(module):
elif rc == 6: elif rc == 6:
return [] return []
else: else:
d = { 'zypper_exit_code': rc } module.fail_json(msg='Failed to execute "%s"' % " ".join(cmd), rc=rc, stdout=stdout, stderr=stderr)
if stderr:
d['stderr'] = stderr
if stdout:
d['stdout'] = stdout
module.fail_json(msg='Failed to execute "%s"' % " ".join(cmd), **d)
def _repo_changes(realrepo, repocmp): def _repo_changes(realrepo, repocmp):
"Check whether the 2 given repos have different settings."
for k in repocmp: for k in repocmp:
if repocmp[k] and k not in realrepo: if repocmp[k] and k not in realrepo:
return True return True
@ -144,6 +170,13 @@ def _repo_changes(realrepo, repocmp):
return False return False
def repo_exists(module, repodata, overwrite_multiple): def repo_exists(module, repodata, overwrite_multiple):
"""Check whether the repository already exists.
returns (exists, mod, old_repos)
exists: whether a matching (name, URL) repo exists
mod: whether there are changes compared to the existing repo
old_repos: list of matching repos
"""
existing_repos = _parse_repos(module) existing_repos = _parse_repos(module)
# look for repos that have matching alias or url to the one searched # look for repos that have matching alias or url to the one searched
@ -171,7 +204,8 @@ def repo_exists(module, repodata, overwrite_multiple):
module.fail_json(msg=errmsg) module.fail_json(msg=errmsg)
def modify_repo(module, repodata, old_repos, zypper_version, warnings): def addmodify_repo(module, repodata, old_repos, zypper_version, warnings):
"Adds the repo, removes old repos before, that would conflict."
repo = repodata['url'] repo = repodata['url']
cmd = ['/usr/bin/zypper', 'ar', '--check'] cmd = ['/usr/bin/zypper', 'ar', '--check']
if repodata['name']: if repodata['name']:
@ -212,24 +246,15 @@ def modify_repo(module, repodata, old_repos, zypper_version, warnings):
remove_repo(module, oldrepo['url']) remove_repo(module, oldrepo['url'])
rc, stdout, stderr = module.run_command(cmd, check_rc=False) rc, stdout, stderr = module.run_command(cmd, check_rc=False)
changed = rc == 0 return rc, stdout, stderr
if rc == 0:
changed = True
else:
if stderr:
module.fail_json(msg=stderr)
else:
module.fail_json(msg=stdout)
return changed
def remove_repo(module, repo): def remove_repo(module, repo):
"Removes the repo."
cmd = ['/usr/bin/zypper', 'rr', repo] cmd = ['/usr/bin/zypper', 'rr', repo]
rc, stdout, stderr = module.run_command(cmd, check_rc=True) rc, stdout, stderr = module.run_command(cmd, check_rc=True)
changed = rc == 0 return rc, stdout, stderr
return changed
def get_zypper_version(module): def get_zypper_version(module):
@ -238,14 +263,16 @@ def get_zypper_version(module):
return LooseVersion('1.0') return LooseVersion('1.0')
return LooseVersion(stdout.split()[1]) return LooseVersion(stdout.split()[1])
def runrefreshrepo(module, auto_import_keys=False, shortname=None):
"Forces zypper to refresh repo metadata."
cmd = ['/usr/bin/zypper', 'refresh', '--force']
if auto_import_keys:
cmd.append('--gpg-auto-import-keys')
if shortname is not None:
cmd.extend(['-r', shortname])
def fail_if_rc_is_null(module, rc, stdout, stderr): rc, stdout, stderr = module.run_command(cmd, check_rc=True)
if rc != 0: return rc, stdout, stderr
#module.fail_json(msg=stderr if stderr else stdout)
if stderr:
module.fail_json(msg=stderr)
else:
module.fail_json(msg=stdout)
def main(): def main():
@ -254,20 +281,25 @@ def main():
name=dict(required=False), name=dict(required=False),
repo=dict(required=False), repo=dict(required=False),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent'], default='present'),
runrefresh=dict(required=False, default='no', type='bool'),
description=dict(required=False), description=dict(required=False),
disable_gpg_check = dict(required=False, default=False, type='bool'), disable_gpg_check = dict(required=False, default=False, type='bool'),
refresh = dict(required=False, default=True, type='bool'), autorefresh = dict(required=False, default=True, type='bool', aliases=['refresh']),
priority = dict(required=False, type='int'), priority = dict(required=False, type='int'),
enabled = dict(required=False, default=True, type='bool'), enabled = dict(required=False, default=True, type='bool'),
overwrite_multiple = dict(required=False, default=False, type='bool'), overwrite_multiple = dict(required=False, default=False, type='bool'),
auto_import_keys = dict(required=False, default=False, type='bool'),
), ),
supports_check_mode=False, supports_check_mode=False,
required_one_of = [['state','runrefresh']],
) )
repo = module.params['repo'] repo = module.params['repo']
alias = module.params['name'] alias = module.params['name']
state = module.params['state'] state = module.params['state']
overwrite_multiple = module.params['overwrite_multiple'] overwrite_multiple = module.params['overwrite_multiple']
auto_import_keys = module.params['auto_import_keys']
runrefresh = module.params['runrefresh']
zypper_version = get_zypper_version(module) zypper_version = get_zypper_version(module)
warnings = [] # collect warning messages for final output warnings = [] # collect warning messages for final output
@ -287,7 +319,7 @@ def main():
repodata['gpgcheck'] = '0' repodata['gpgcheck'] = '0'
else: else:
repodata['gpgcheck'] = '1' repodata['gpgcheck'] = '1'
if module.params['refresh']: if module.params['autorefresh']:
repodata['autorefresh'] = '1' repodata['autorefresh'] = '1'
else: else:
repodata['autorefresh'] = '0' repodata['autorefresh'] = '0'
@ -296,6 +328,13 @@ def main():
module.exit_json(changed=False, repodata=repodata, state=state) module.exit_json(changed=False, repodata=repodata, state=state)
# Check run-time module parameters # Check run-time module parameters
if repo == '*' or alias == '*':
if runrefresh:
runrefreshrepo(module, auto_import_keys)
module.exit_json(changed=False, runrefresh=True)
else:
module.fail_json(msg='repo=* can only be used with the runrefresh option.')
if state == 'present' and not repo: if state == 'present' and not repo:
module.fail_json(msg='Module option state=present requires repo') module.fail_json(msg='Module option state=present requires repo')
if state == 'absent' and not repo and not alias: if state == 'absent' and not repo and not alias:
@ -310,18 +349,28 @@ def main():
exists, mod, old_repos = repo_exists(module, repodata, overwrite_multiple) exists, mod, old_repos = repo_exists(module, repodata, overwrite_multiple)
if repo:
shortname = repo
else:
shortname = alias
if state == 'present': if state == 'present':
if exists and not mod: if exists and not mod:
if runrefresh:
runrefreshrepo(module, auto_import_keys, shortname)
exit_unchanged() exit_unchanged()
changed = modify_repo(module, repodata, old_repos, zypper_version, warnings) rc, stdout, stderr = addmodify_repo(module, repodata, old_repos, zypper_version, warnings)
if rc == 0 and (runrefresh or auto_import_keys):
runrefreshrepo(module, auto_import_keys, shortname)
elif state == 'absent': elif state == 'absent':
if not exists: if not exists:
exit_unchanged() exit_unchanged()
if not repo: rc, stdout, stderr = remove_repo(module, shortname)
repo=alias
changed = remove_repo(module, repo)
module.exit_json(changed=changed, repodata=repodata, state=state, warnings=warnings) if rc == 0:
module.exit_json(changed=True, repodata=repodata, state=state, warnings=warnings)
else:
module.fail_json(msg="Zypper failed with rc %s" % rc, rc=rc, stdout=stdout, stderr=stderr, repodata=repodata, state=state, warnings=warnings)
# import module snippets # import module snippets
from ansible.module_utils.basic import * from ansible.module_utils.basic import *