Keycloak module cleanup and consistency (#3280)

* Consistent Modules - Rename updated_?? to desired_?? in all the keycloak modules.

* Consistent Modules - Rename the comments, and add whitespace so that all the modules are a lot more consistent between each other.

* Consistent Modules - Remove final elif where a final else doesn't exist.

This is to address the inconsistency between the other modules.

Whilst I can see it being more descriptive, there should be a final "else:" to cater if the values is neither 'absent' or 'present'.

* Consistent Modules - Use dict() instead of {} like most of the other keycloak modules.

* Consistent Modules - Update keycloak authentication so that the if ordering is consistent for no-item.

* Consistent Modules - Move the 'Filter and map' process to always occur before getting an existing item.

* Consistent Modules - Be consistent with how to initialse before_?? and set it to dict() if it is None.

* Consistent Modules - Add module.exit_?? in the locations as per the other modules.

* Consistent Modules - Represent result['diff'] using dict(before=.., after=...) as per all the other modules.

* Consistent Modules - Add / Move location of when result['end_state'] is getting defined.

* Consistent modules - Add result['changed'] = False where we do nothing and exit because item exists.

* Consistent Modules - Set the value result['changed'] to True earlier so it shows up when in checking mode only.

* Consistent Modules - test for equality with a dict to assert there was no realm in the first place as per the other modules.

* Consistent Modules - Address the spelling.

* Consistent Modules - keycloak_group - Remove result['group'] as result['end_state'] is the consistent value used in the other modules.

* Consistent Modules - Order the lines in the section, Do nothing and exit consistently.

* Consistent Modules - Add result['end_state'] and still add deprecated `flow` return value.

* Consistent Modules - Add missing return documentation for `msg`.

* Consistent Modules - Tweak whitespace in the RETURN variable.

* Consistent Modules - Add result['group'] in addition to deprecated result['group'] response.

* Consistent Modules - Add return property, 'contains' to address test errors.

* Consistent Modules - Rename updated_?? to desired_?? in new modules since initial PR.

* Consistent Modules - Rename the comments, and add whitespace so that all the (recently added) modules are a lot more consistent between each other.

* Consistent Modules - Make indentation consistent within the response document.

* Consistent Modules - Use B(DEPRECATED) in a seperate line in the description.

* Consistent Modules - Add a lot of full stops to sentences.

* Consistent Modules - Use C(...) and I(...) formatting methods.

* Consistent Modules - Use "on success" everywhere for end_state response documentation.

* Consistent Modules - Update the documents for RETURN.proposed, RETURN.existing, RETURN.end_state to be the same.

* Consistent Modules - Add fragment.

* Remove period after short_description.

* Update changelog fragment.

* Consistent Modules - PRFeedback - Remove `module.exit_json(**result)` within the `Delete` section of the if statement.

There's a exit_json(..) immediately after.

* Consistent Modules - PRFeedback - Use `if not x_repr` instead of `if x_repr == dict()`.

* keycloak_authentication - Add a sample of the output.

* Replace `dict()` with `{}` for all the keycloak modules.

* Add the requested deprecated notices

* Update changelogs/fragments/3280-keycloak-module-cleanup-and-consistency.yml

Co-authored-by: Pierre Dumuid <pierre@knowyourdata.com.au>
Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
Pierre Dumuid 2021-10-22 16:27:18 +10:30 committed by GitHub
commit 996dc617ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 593 additions and 346 deletions

View file

@ -182,7 +182,7 @@ options:
description:
- For one level, the search applies only for users in the DNs specified by User DNs.
For subtree, the search applies to the whole subtree. See LDAP documentation for
more details
more details.
default: '1'
type: str
choices:
@ -551,7 +551,7 @@ msg:
sample: "No changes required to user federation 164bb483-c613-482e-80fe-7f1431308799."
proposed:
description: Representation of proposed changes to user federation.
description: Representation of proposed user federation.
returned: always
type: dict
sample: {
@ -648,7 +648,7 @@ existing:
end_state:
description: Representation of user federation after module execution.
returned: always
returned: on success
type: dict
sample: {
"config": {
@ -668,7 +668,6 @@ end_state:
"providerId": "kerberos",
"providerType": "org.keycloak.storage.UserStorageProvider"
}
'''
from ansible_collections.community.general.plugins.module_utils.identity.keycloak.keycloak import KeycloakAPI, camel, \
@ -808,12 +807,12 @@ def main():
mapper['config'] = dict((k, [str(v).lower() if not isinstance(v, str) else v])
for k, v in mapper['config'].items() if mapper['config'][k] is not None)
# convert module parameters to client representation parameters (if they belong in there)
# Filter and map the parameters names that apply
comp_params = [x for x in module.params
if x not in list(keycloak_argument_spec().keys()) + ['state', 'realm', 'mappers'] and
module.params.get(x) is not None]
# does the user federation already exist?
# See if it already exists in Keycloak
if cid is None:
found = kc.get_components(urlencode(dict(type='org.keycloak.storage.UserStorageProvider', parent=realm, name=name)), realm)
if len(found) > 1:
@ -825,14 +824,14 @@ def main():
before_comp = kc.get_component(cid, realm)
if before_comp is None:
before_comp = dict()
before_comp = {}
# if user federation exists, get associated mappers
if cid is not None:
before_comp['mappers'] = sorted(kc.get_components(urlencode(dict(parent=cid)), realm), key=lambda x: x.get('name'))
# build a changeset
changeset = dict()
# Build a proposed changeset from parameters given to this module
changeset = {}
for param in comp_params:
new_param_value = module.params.get(param)
@ -851,11 +850,11 @@ def main():
if change.get('id') is None and change.get('name') is None:
module.fail_json(msg='Either `name` or `id` has to be specified on each mapper.')
if cid is None:
old_mapper = dict()
old_mapper = {}
elif change.get('id') is not None:
old_mapper = kc.get_component(change['id'], realm)
if old_mapper is None:
old_mapper = dict()
old_mapper = {}
else:
found = kc.get_components(urlencode(dict(parent=cid, name=change['name'])), realm)
if len(found) > 1:
@ -863,7 +862,7 @@ def main():
if len(found) == 1:
old_mapper = found[0]
else:
old_mapper = dict()
old_mapper = {}
new_mapper = old_mapper.copy()
new_mapper.update(change)
if new_mapper != old_mapper:
@ -871,37 +870,37 @@ def main():
changeset['mappers'] = list()
changeset['mappers'].append(new_mapper)
# prepare the new representation
updated_comp = before_comp.copy()
updated_comp.update(changeset)
# Prepare the desired values using the existing values (non-existence results in a dict that is save to use as a basis)
desired_comp = before_comp.copy()
desired_comp.update(changeset)
result['proposed'] = sanitize(changeset)
result['existing'] = sanitize(before_comp)
# if before_comp is none, the user federation doesn't exist.
if before_comp == dict():
# Cater for when it doesn't exist (an empty dict)
if not before_comp:
if state == 'absent':
# nothing to do.
# Do nothing and exit
if module._diff:
result['diff'] = dict(before='', after='')
result['changed'] = False
result['end_state'] = dict()
result['end_state'] = {}
result['msg'] = 'User federation does not exist; doing nothing.'
module.exit_json(**result)
# for 'present', create a new user federation.
# Process a creation
result['changed'] = True
if module._diff:
result['diff'] = dict(before='', after=sanitize(updated_comp))
result['diff'] = dict(before='', after=sanitize(desired_comp))
if module.check_mode:
module.exit_json(**result)
# do it for real!
updated_comp = updated_comp.copy()
updated_mappers = updated_comp.pop('mappers', [])
after_comp = kc.create_component(updated_comp, realm)
# create it
desired_comp = desired_comp.copy()
updated_mappers = desired_comp.pop('mappers', [])
after_comp = kc.create_component(desired_comp, realm)
for mapper in updated_mappers:
if mapper.get('id') is not None:
@ -919,26 +918,28 @@ def main():
else:
if state == 'present':
# Process an update
# no changes
if updated_comp == before_comp:
if desired_comp == before_comp:
result['changed'] = False
result['end_state'] = sanitize(updated_comp)
result['end_state'] = sanitize(desired_comp)
result['msg'] = "No changes required to user federation {id}.".format(id=cid)
module.exit_json(**result)
# update the existing role
# doing an update
result['changed'] = True
if module._diff:
result['diff'] = dict(before=sanitize(before_comp), after=sanitize(updated_comp))
result['diff'] = dict(before=sanitize(before_comp), after=sanitize(desired_comp))
if module.check_mode:
module.exit_json(**result)
# do the update
updated_comp = updated_comp.copy()
updated_mappers = updated_comp.pop('mappers', [])
kc.update_component(updated_comp, realm)
desired_comp = desired_comp.copy()
updated_mappers = desired_comp.pop('mappers', [])
kc.update_component(desired_comp, realm)
after_comp = kc.get_component(cid, realm)
for mapper in updated_mappers:
@ -946,7 +947,7 @@ def main():
kc.update_component(mapper, realm)
else:
if mapper.get('parentId') is None:
mapper['parentId'] = updated_comp['id']
mapper['parentId'] = desired_comp['id']
mapper = kc.create_component(mapper, realm)
after_comp['mappers'] = updated_mappers
@ -956,6 +957,7 @@ def main():
module.exit_json(**result)
elif state == 'absent':
# Process a deletion
result['changed'] = True
if module._diff:
@ -964,13 +966,12 @@ def main():
if module.check_mode:
module.exit_json(**result)
# delete for real
# delete it
kc.delete_component(cid, realm)
result['end_state'] = dict()
result['end_state'] = {}
result['msg'] = "User federation {id} has been deleted".format(id=cid)
module.exit_json(**result)
module.exit_json(**result)