mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 02:54:26 +00:00
99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
"""Client-scope list convergence for keycloak_kcadm_update.
|
|
|
|
A client PUT ignores default/optionalClientScopes (sub-resources with their
|
|
own endpoints; verified against a live deploy) — these helpers converge them
|
|
explicitly: DELETE unassigns, bodyless PUT assigns, removals first so a scope
|
|
can move between the two lists.
|
|
|
|
``run_kcadm`` is injected by the calling module (it owns retry/CID-recovery
|
|
semantics); every helper takes it as its first argument.
|
|
"""
|
|
|
|
from ansible.module_utils.kcadm_json import json_from_noisy_stdout
|
|
|
|
|
|
def named_id_map(run_kcadm, module, cmd):
|
|
"""Run a kcadm list command and return a {name: id} map (empty on noise)."""
|
|
_rc, out, _err = run_kcadm(module, cmd, ignore_rc=True)
|
|
try:
|
|
data = json_from_noisy_stdout(out)
|
|
except ValueError:
|
|
data = []
|
|
return {
|
|
item["name"]: item["id"]
|
|
for item in data or []
|
|
if isinstance(item, dict) and item.get("name") and item.get("id")
|
|
}
|
|
|
|
|
|
def converge_client_scope_lists(
|
|
run_kcadm, module, object_id, desired, realm, kcadm_exec
|
|
):
|
|
"""Converge a client's default/optional client-scope lists to ``desired``."""
|
|
plans = []
|
|
for field, kind in (
|
|
("defaultClientScopes", "default-client-scopes"),
|
|
("optionalClientScopes", "optional-client-scopes"),
|
|
):
|
|
if field not in desired:
|
|
continue
|
|
wanted = {str(name) for name in (desired.get(field) or [])}
|
|
current = named_id_map(
|
|
run_kcadm,
|
|
module,
|
|
f"{kcadm_exec} get clients/{object_id}/{kind} -r {realm} --format json",
|
|
)
|
|
plans.append((kind, wanted, current))
|
|
|
|
changed = False
|
|
for kind, wanted, current in plans:
|
|
for name in sorted(set(current) - wanted):
|
|
rc, out, err = run_kcadm(
|
|
module,
|
|
f"{kcadm_exec} delete clients/{object_id}/{kind}/{current[name]} -r {realm}",
|
|
ignore_rc=True,
|
|
)
|
|
if rc != 0:
|
|
module.fail_json(
|
|
msg="Failed to unassign client scope",
|
|
scope=name,
|
|
scope_kind=kind,
|
|
rc=rc,
|
|
stdout=out,
|
|
stderr=err,
|
|
)
|
|
changed = True
|
|
|
|
catalog = None
|
|
for kind, wanted, current in plans:
|
|
for name in sorted(wanted - set(current)):
|
|
if catalog is None:
|
|
catalog = named_id_map(
|
|
run_kcadm,
|
|
module,
|
|
f"{kcadm_exec} get client-scopes -r {realm} --format json",
|
|
)
|
|
scope_id = catalog.get(name)
|
|
if not scope_id:
|
|
module.fail_json(
|
|
msg="Desired client scope does not exist in the realm",
|
|
scope=name,
|
|
scope_kind=kind,
|
|
)
|
|
rc, out, err = run_kcadm(
|
|
module,
|
|
f"{kcadm_exec} update clients/{object_id}/{kind}/{scope_id} -r {realm}",
|
|
ignore_rc=True,
|
|
)
|
|
if rc != 0:
|
|
module.fail_json(
|
|
msg="Failed to assign client scope",
|
|
scope=name,
|
|
scope_kind=kind,
|
|
rc=rc,
|
|
stdout=out,
|
|
stderr=err,
|
|
)
|
|
changed = True
|
|
return changed
|