diff --git a/changelogs/fragments/11443-fix-keycloak-client-diff-for-null-attributes.yml b/changelogs/fragments/11443-fix-keycloak-client-diff-for-null-attributes.yml new file mode 100644 index 0000000000..a28a98e3f1 --- /dev/null +++ b/changelogs/fragments/11443-fix-keycloak-client-diff-for-null-attributes.yml @@ -0,0 +1,2 @@ +bugfixes: + - keycloak_client - fix idempotency bug caused by ``null`` client attribute value differences for non-existing client attributes (https://github.com/ansible-collections/community.general/issues/11443, https://github.com/ansible-collections/community.general/pull/11444). \ No newline at end of file diff --git a/plugins/modules/keycloak_client.py b/plugins/modules/keycloak_client.py index 0bdf3d853b..c05a595ac5 100644 --- a/plugins/modules/keycloak_client.py +++ b/plugins/modules/keycloak_client.py @@ -1319,7 +1319,11 @@ def main(): new_param_value = flow_binding_from_dict_to_model(new_param_value, realm, kc) elif client_param == "attributes" and "attributes" in before_client: attributes_copy = copy.deepcopy(before_client["attributes"]) - attributes_copy.update(new_param_value) + # Merge client attributes while excluding null-valued attributes that are not present in Keycloak's response. + # This ensures idempotency by treating absent attributes and null attributes as equivalent. + attributes_copy.update( + {key: value for key, value in new_param_value.items() if value is not None or key in attributes_copy} + ) new_param_value = attributes_copy elif client_param in ["clientScopesBehavior", "client_scopes_behavior"]: continue