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

@ -31,7 +31,7 @@ description:
options:
state:
description:
- State of the client template
- State of the client template.
- On C(present), the client template will be created (or updated if it exists already).
- On C(absent), the client template will be removed if it exists
choices: ['present', 'absent']
@ -51,12 +51,12 @@ options:
name:
description:
- Name of the client template
- Name of the client template.
type: str
description:
description:
- Description of the client template in Keycloak
- Description of the client template in Keycloak.
type: str
protocol:
@ -100,7 +100,7 @@ options:
protocol:
description:
- is either 'openid-connect' or 'saml', this specifies for which protocol this protocol mapper
- This is either C(openid-connect) or C(saml), this specifies for which protocol this protocol mapper.
is active.
choices: ['openid-connect', 'saml']
type: str
@ -143,7 +143,7 @@ options:
contents differ depending on the value of I(protocolMapper) and are not documented
other than by the source of the mappers and its parent class(es). An example is given
below. It is easiest to obtain valid config values by dumping an already-existing
protocol mapper configuration through check-mode in the "existing" field.
protocol mapper configuration through check-mode in the I(existing) field.
type: dict
attributes:
@ -163,7 +163,6 @@ notes:
extends_documentation_fragment:
- community.general.keycloak
author:
- Eike Frost (@eikef)
'''
@ -231,20 +230,21 @@ EXAMPLES = '''
RETURN = '''
msg:
description: Message as to what action was taken
returned: always
type: str
sample: "Client template testclient has been updated"
description: Message as to what action was taken.
returned: always
type: str
sample: "Client template testclient has been updated"
proposed:
description: client template representation of proposed changes to client template
description: Representation of proposed client template.
returned: always
type: dict
sample: {
name: "test01"
}
existing:
description: client template representation of existing client template (sample is truncated)
description: Representation of existing client template (sample is truncated).
returned: always
type: dict
sample: {
@ -254,9 +254,10 @@ existing:
"name": "test01",
"protocol": "saml"
}
end_state:
description: client template representation of client template after module execution (sample is truncated)
returned: always
description: Representation of client template after module execution (sample is truncated).
returned: on success
type: dict
sample: {
"description": "test01",
@ -302,6 +303,7 @@ def main():
full_scope_allowed=dict(type='bool'),
protocol_mappers=dict(type='list', elements='dict', options=protmapper_spec),
)
argument_spec.update(meta_args)
module = AnsibleModule(argument_spec=argument_spec,
@ -317,19 +319,20 @@ def main():
connection_header = get_token(module.params)
except KeycloakError as e:
module.fail_json(msg=str(e))
kc = KeycloakAPI(module, connection_header)
realm = module.params.get('realm')
state = module.params.get('state')
cid = module.params.get('id')
# convert module parameters to client representation parameters (if they belong in there)
# Filter and map the parameters names that apply to the client template
clientt_params = [x for x in module.params
if x not in ['state', 'auth_keycloak_url', 'auth_client_id', 'auth_realm',
'auth_client_secret', 'auth_username', 'auth_password',
'validate_certs', 'realm'] and module.params.get(x) is not None]
# See whether the client template already exists in Keycloak
# See if it already exists in Keycloak
if cid is None:
before_clientt = kc.get_client_template_by_name(module.params.get('name'), realm=realm)
if before_clientt is not None:
@ -338,12 +341,12 @@ def main():
before_clientt = kc.get_client_template_by_id(cid, realm=realm)
if before_clientt is None:
before_clientt = dict()
before_clientt = {}
result['existing'] = before_clientt
# Build a proposed changeset from parameters given to this module
changeset = dict()
changeset = {}
for clientt_param in clientt_params:
# lists in the Keycloak API are sorted
@ -355,78 +358,89 @@ def main():
pass
changeset[camel(clientt_param)] = new_param_value
# Whether creating or updating a client, take the before-state and merge the changeset into it
updated_clientt = before_clientt.copy()
updated_clientt.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_clientt = before_clientt.copy()
desired_clientt.update(changeset)
result['proposed'] = changeset
# If the client template does not exist yet, before_client is still empty
if before_clientt == dict():
# Cater for when it doesn't exist (an empty dict)
if not before_clientt:
if state == 'absent':
# do nothing and exit
# Do nothing and exit
if module._diff:
result['diff'] = dict(before='', after='')
result['changed'] = False
result['end_state'] = {}
result['msg'] = 'Client template does not exist, doing nothing.'
module.exit_json(**result)
# create new client template
# Process a creation
result['changed'] = True
if 'name' not in updated_clientt:
if 'name' not in desired_clientt:
module.fail_json(msg='name needs to be specified when creating a new client')
if module._diff:
result['diff'] = dict(before='', after=updated_clientt)
result['diff'] = dict(before='', after=desired_clientt)
if module.check_mode:
module.exit_json(**result)
kc.create_client_template(updated_clientt, realm=realm)
after_clientt = kc.get_client_template_by_name(updated_clientt['name'], realm=realm)
# create it
kc.create_client_template(desired_clientt, realm=realm)
after_clientt = kc.get_client_template_by_name(desired_clientt['name'], realm=realm)
result['end_state'] = after_clientt
result['msg'] = 'Client template %s has been created.' % updated_clientt['name']
result['msg'] = 'Client template %s has been created.' % desired_clientt['name']
module.exit_json(**result)
else:
if state == 'present':
# update existing client template
# Process an update
result['changed'] = True
if module.check_mode:
# We can only compare the current client template with the proposed updates we have
if module._diff:
result['diff'] = dict(before=before_clientt,
after=updated_clientt)
after=desired_clientt)
module.exit_json(**result)
kc.update_client_template(cid, updated_clientt, realm=realm)
# do the update
kc.update_client_template(cid, desired_clientt, realm=realm)
after_clientt = kc.get_client_template_by_id(cid, realm=realm)
if before_clientt == after_clientt:
result['changed'] = False
if module._diff:
result['diff'] = dict(before=before_clientt,
after=after_clientt)
result['end_state'] = after_clientt
result['msg'] = 'Client template %s has been updated.' % updated_clientt['name']
module.exit_json(**result)
else:
# Delete existing client
result['changed'] = True
if module._diff:
result['diff']['before'] = before_clientt
result['diff']['after'] = ''
result['diff'] = dict(before=before_clientt, after=after_clientt)
result['msg'] = 'Client template %s has been updated.' % desired_clientt['name']
module.exit_json(**result)
else:
# Process a deletion (because state was not 'present')
result['changed'] = True
if module._diff:
result['diff'] = dict(before=before_clientt, after='')
if module.check_mode:
module.exit_json(**result)
# delete it
kc.delete_client_template(cid, realm=realm)
result['proposed'] = dict()
result['end_state'] = dict()
result['proposed'] = {}
result['end_state'] = {}
result['msg'] = 'Client template %s has been deleted.' % before_clientt['name']
module.exit_json(**result)
module.exit_json(**result)