1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-05-04 09:23:02 +00:00

[PR #11947/2becfe45 backport][stable-12] zypper_repository: allow state=absent when .repo URL/file is unreachable (#11970)

zypper_repository: allow `state=absent` when `.repo` URL/file is unreachable (#11947)

* fix(zypper_repository): allow state=absent when .repo URL/file is unreachable

When removing a repository by .repo URL, a download failure used to cause
an unconditional fail_json. Now, for state=absent, the module warns and
falls back to deriving the alias from the .repo filename basename.



* feat(changelog): add fragment for PR 11947



---------


(cherry picked from commit 2becfe45b5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
patchback[bot] 2026-05-02 10:04:22 +02:00 committed by GitHub
parent b6e41311fd
commit 3eadab1a01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 33 deletions

View file

@ -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).

View file

@ -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)