diff --git a/changelogs/fragments/11947-zypper-repository-remove-broken.yml b/changelogs/fragments/11947-zypper-repository-remove-broken.yml new file mode 100644 index 0000000000..58078a3a9e --- /dev/null +++ b/changelogs/fragments/11947-zypper-repository-remove-broken.yml @@ -0,0 +1,2 @@ +bugfixes: + - zypper_repository - allow unreachable ``.repo`` URLs and missing local paths when using ``state=absent`` (https://github.com/ansible-collections/community.general/issues/5769, https://github.com/ansible-collections/community.general/pull/11947). diff --git a/plugins/modules/zypper_repository.py b/plugins/modules/zypper_repository.py index fce241d60a..f925292574 100644 --- a/plugins/modules/zypper_repository.py +++ b/plugins/modules/zypper_repository.py @@ -394,53 +394,69 @@ def main(): # Download / Open and parse .repo file to ensure idempotency if repo and repo.endswith(".repo"): + repofile_text = None if repo.startswith(("http://", "https://")): response, info = fetch_url(module=module, url=repo, force=True) if not response or info["status"] != 200: - module.fail_json(msg="Error downloading .repo file from provided URL") - repofile_text = to_text(response.read(), errors="surrogate_or_strict") + if state == "absent": + # Fall back to alias derived from URL filename (convention: section == basename) + module.warn( + f"Could not download .repo file from '{repo}'; will try to identify repository by alias" + ) + alias = alias or repo.rsplit("/", 1)[-1][:-5] + repodata["alias"] = alias + else: + module.fail_json(msg="Error downloading .repo file from provided URL") + else: + repofile_text = to_text(response.read(), errors="surrogate_or_strict") else: try: with open(repo, encoding="utf-8") as file: repofile_text = file.read() except OSError: - module.fail_json(msg="Error opening .repo file from provided path") + if state == "absent": + module.warn(f"Could not open .repo file at '{repo}'; will try to identify repository by alias") + alias = alias or repo.rsplit("/", 1)[-1][:-5] + repodata["alias"] = alias + else: + module.fail_json(msg="Error opening .repo file from provided path") - repofile = configparser.ConfigParser() - try: - repofile.read_file(StringIO(repofile_text)) - except configparser.Error: - module.fail_json(msg="Invalid format, .repo file could not be parsed") + if repofile_text is not None: + repofile = configparser.ConfigParser() + try: + repofile.read_file(StringIO(repofile_text)) + except configparser.Error: + module.fail_json(msg="Invalid format, .repo file could not be parsed") - # No support for .repo file with zero or more than one repository - if len(repofile.sections()) != 1: - err = f"Invalid format, .repo file contains {len(repofile.sections())} repositories, expected 1" - module.fail_json(msg=err) + # No support for .repo file with zero or more than one repository + if len(repofile.sections()) != 1: + err = f"Invalid format, .repo file contains {len(repofile.sections())} repositories, expected 1" + module.fail_json(msg=err) - section = repofile.sections()[0] - repofile_items = dict(repofile.items(section)) - # Only proceed if at least baseurl is available - if "baseurl" not in repofile_items: - module.fail_json(msg="No baseurl found in .repo file") + section = repofile.sections()[0] + repofile_items = dict(repofile.items(section)) + # Only proceed if at least baseurl is available + if "baseurl" not in repofile_items: + module.fail_json(msg="No baseurl found in .repo file") - # Set alias (name) and url based on values from .repo file - alias = section - repodata["alias"] = section - repodata["url"] = repofile_items["baseurl"] + # Set alias (name) and url based on values from .repo file + alias = section + repodata["alias"] = section + repodata["url"] = repofile_items["baseurl"] - # If gpgkey is part of the .repo file, auto import key - if "gpgkey" in repofile_items: - auto_import_keys = True + # If gpgkey is part of the .repo file, auto import key + if "gpgkey" in repofile_items: + auto_import_keys = True - # Map additional values, if available - if "name" in repofile_items: - repodata["name"] = repofile_items["name"] - if "enabled" in repofile_items: - repodata["enabled"] = repofile_items["enabled"] - if "autorefresh" in repofile_items: - repodata["autorefresh"] = repofile_items["autorefresh"] - if "gpgcheck" in repofile_items: - repodata["gpgcheck"] = repofile_items["gpgcheck"] + # Map additional values, if available + if "name" in repofile_items: + repodata["name"] = repofile_items["name"] + if "enabled" in repofile_items: + repodata["enabled"] = repofile_items["enabled"] + if "autorefresh" in repofile_items: + repodata["autorefresh"] = repofile_items["autorefresh"] + if "gpgcheck" in repofile_items: + repodata["gpgcheck"] = repofile_items["gpgcheck"] exists, mod, old_repos = repo_exists(module, repodata, overwrite_multiple)