Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zypper_repository: extend module with possibility to modify repos #8795

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/fragments/8795-extend-zypper_repository.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- zypper_repository add action with choices add, modify and remove
(https://github.com/ansible-collections/community.general/pull/8795).
99 changes: 83 additions & 16 deletions plugins/modules/zypper_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

# Copyright (c) 2013, Matthias Vogelgesang <[email protected]>
# Copyright (c) 2014, Justin Lecher <[email protected]>
# Copyright (c) 2017, Christian Wittmer <[email protected]>
#
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later
Expand All @@ -15,9 +16,9 @@
---
module: zypper_repository
author: "Matthias Vogelgesang (@matze)"
short_description: Add and remove Zypper repositories
short_description: Add, modify and remove zypper repositories
description:
- Add or remove Zypper repositories on SUSE and openSUSE
- Add, modify or remove zypper repositories on SLE and openSUSE
extends_documentation_fragment:
- community.general.attributes
attributes:
Expand All @@ -32,13 +33,24 @@
type: str
repo:
description:
- URI of the repository or .repo file. Required when state=present.
- URI of the repository or .repo file. Required when O(state=present) and O(action=add).
type: str
state:
action:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that module options such as action are not a good idea (https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html#designing-module-interfaces), in particular if state is already present.

All your actions should already be doable with state. Modifying should be done with state=present and passing other parameters.

Copy link
Author

@computersalat computersalat Aug 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hear you, but state with [ "absent", "present" ] is only relevant when using add or remove, but it's irrelevant when using action with [ "modify" ]. When I modify a repo I expect it to be present.
Introducing action was IMHO the only possibility to add feature: modify.
If you have a better idea, I am open to hear ...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, state=present usually also means modify (except in certain situations, like it hasn't been implemented yet).

Please remove the action option and change the code so that with state=present it creates (if it doesn't exist yet) or modifies (if it does exist and is changed).

required: false
choices: [ "add", "modify", "remove" ]
default: "add"
description:
- A source string state.
- The action you want to perform. C(add, modify or remove)
- When wanting to C(add) a repo you can omit either O(action=add) or O(state=present) cause of their defaults.
- When wanting to C(modify) a repo then just use O(action=modify)
- When wanting to C(remove) a repo then just use one of O(state=absent) or O(action=remove)
- When using with C(modify) you should not run another task with C(add) before or afterwards cause of idempotency.
type: str
state:
choices: [ "absent", "present" ]
default: "present"
description:
- A source string state.
type: str
description:
description:
Expand Down Expand Up @@ -128,6 +140,20 @@
name: my_ci_repo
state: present
runrefresh: true

- name: "Modify (disable) repo (e.g. installed via template)"
community.general.zypper_repository:
action: modify
name: 15.5-update-sle
autorefresh: false
enabled: false

- name: "Modify (enable) repo (e.g. installed via template)"
community.general.zypper_repository:
action: modify
name: 15.6-update-sle
autorefresh: true
enabled: true
'''

import traceback
Expand Down Expand Up @@ -293,6 +319,36 @@ def addmodify_repo(module, repodata, old_repos, zypper_version, warnings):
return rc, stdout, stderr


def modify_repo(module, repodata, zypper_version, warnings):
"Modifys the repo like name, enable/disable, refresh/no-refresh, priority"
cmd = _get_cmd('modifyrepo')
if repodata['name']:
cmd.extend(['--name', repodata['name']])

# priority on addrepo available since 1.12.25
# https://github.com/openSUSE/zypper/blob/b9b3cb6db76c47dc4c47e26f6a4d2d4a0d12b06d/package/zypper.changes#L327-L336
if repodata['priority']:
if zypper_version >= LooseVersion('1.12.25'):
cmd.extend(['--priority', str(repodata['priority'])])
else:
warnings.append("Setting priority only available for zypper >= 1.12.25. Ignoring priority argument.")

if repodata['enabled'] == '1':
cmd.append('--enable')
else:
cmd.append('--disable')

if repodata['autorefresh'] == '1':
cmd.append('--refresh')
else:
cmd.append('--no-refresh')

cmd.append(repodata['alias'])

rc, stdout, stderr = module.run_command(cmd, check_rc=False)
return rc, stdout, stderr


def remove_repo(module, repo):
"Removes the repo."
cmd = _get_cmd(module, 'removerepo', repo)
Expand Down Expand Up @@ -325,6 +381,7 @@ def main():
module = AnsibleModule(
argument_spec=dict(
name=dict(required=False),
action=dict(choices=['add', 'modify', 'remove'], default='add'),
repo=dict(required=False),
state=dict(choices=['present', 'absent'], default='present'),
runrefresh=dict(required=False, default=False, type='bool'),
Expand All @@ -337,11 +394,12 @@ def main():
auto_import_keys=dict(required=False, default=False, type='bool'),
),
supports_check_mode=False,
required_one_of=[['state', 'runrefresh']],
required_one_of=[['action', 'state', 'runrefresh']],
)

repo = module.params['repo']
alias = module.params['name']
action = module.params['action']
state = module.params['state']
overwrite_multiple = module.params['overwrite_multiple']
auto_import_keys = module.params['auto_import_keys']
Expand Down Expand Up @@ -381,17 +439,19 @@ def exit_unchanged():
else:
module.fail_json(msg='repo=* can only be used with the runrefresh option.')

if state == 'present' and not repo:
module.fail_json(msg='Module option state=present requires repo')
if state == 'absent' and not repo and not alias:
module.fail_json(msg='Alias or repo parameter required when state=absent')
if state == 'present' and action == 'add' and not repo:
module.fail_json(msg='Missing option: \'repo\' (URI). Required when state=present and action=add')
if action == 'modify' and not alias:
module.fail_json(msg='Missing option: \'name\' (Alias). Required when action=modify')
if (state == 'absent' or action == 'remove') and not alias:
module.fail_json(msg='Missing option: \'name\' (Alias). Required when state=absent or action=remove')

if repo and repo.endswith('.repo'):
if alias:
module.fail_json(msg='Incompatible option: \'name\'. Do not use name when adding .repo files')
else:
if not alias and state == "present":
module.fail_json(msg='Name required when adding non-repo files.')
if not alias and state == 'present' and action == 'add':
module.fail_json(msg='Missing option: \'name\' (Alias). Required when adding non-repo files.')

# Download / Open and parse .repo file to ensure idempotency
if repo and repo.endswith('.repo'):
Expand Down Expand Up @@ -450,23 +510,30 @@ def exit_unchanged():
else:
shortname = repo

if state == 'present':
if action == 'add' and state == 'present':
if exists and not mod:
if runrefresh:
runrefreshrepo(module, auto_import_keys, shortname)
exit_unchanged()
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 action == 'modify' and state == 'present':
if exists and not mod:
exit_unchanged()
if not exists:
exit_unchanged()
rc, stdout, stderr = modify_repo(module, repodata, zypper_version, warnings)
elif action == 'remove' or state == 'absent':
if not exists:
exit_unchanged()
rc, stdout, stderr = remove_repo(module, shortname)

if rc == 0:
module.exit_json(changed=True, repodata=repodata, state=state, warnings=warnings)
module.exit_json(changed=True, repodata=repodata, action=action, 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)
module.fail_json(msg="zypper failed with rc %s" % rc, rc=rc, stdout=stdout, stderr=stderr, repodata=repodata, action=action, state=state,
warnings=warnings)


if __name__ == '__main__':
Expand Down
Loading