From 08cc9269f80f06f2e379e4113608f081cf19841d Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Thu, 17 Sep 2020 12:11:53 +0200 Subject: [PATCH] external_usergroup: support non-LDAP groups (#959) * external_usergroup: support non-LDAP groups Fixes: #956 Obsoletes: #955 * include FreeIPA example * make invisible a boolean flag instead of a type * use lookup_entity instead of auto_lookup_entities * use module.run() --- .../956-external_usergroup-non-ldap.yaml | 4 +++ docs/developing.md | 2 +- plugins/module_utils/foreman_helper.py | 13 ++++---- plugins/modules/compute_resource.py | 32 +++++++++---------- plugins/modules/content_view.py | 2 +- plugins/modules/external_usergroup.py | 28 +++++++++++++--- plugins/modules/host.py | 2 +- plugins/modules/image.py | 4 +-- plugins/modules/provisioning_template.py | 2 +- tests/test_foreman_spec_helper.py | 6 ++-- 10 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 changelogs/fragments/956-external_usergroup-non-ldap.yaml diff --git a/changelogs/fragments/956-external_usergroup-non-ldap.yaml b/changelogs/fragments/956-external_usergroup-non-ldap.yaml new file mode 100644 index 0000000000..33fe70cd90 --- /dev/null +++ b/changelogs/fragments/956-external_usergroup-non-ldap.yaml @@ -0,0 +1,4 @@ +bugfixes: + - external_usergroup - support non-LDAP external groups (https://github.com/theforeman/foreman-ansible-modules/issues/956) +minor_changes: + - external_usergroup - rename the ``auth_source_ldap`` parameter to ``auth_source`` (``auth_source_ldap`` is still supported via an alias) diff --git a/docs/developing.md b/docs/developing.md index 1ceeec28c4..5b943c5bfc 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -59,7 +59,7 @@ This is usually combined with `flat_name=_ids`. If no flat_name is provi The module must handle the entities separately. See domain parameters in [`domain`](../plugins/modules/domain.py) for an example. The sub entities must be described by `foreman_spec=_spec`. -* `type='invisible'` The parameter is available to the API call, but it will be excluded from Ansible's `argument_spec`. +* `invisible=True` The parameter is available to the API call, but it will be excluded from Ansible's `argument_spec`. * `search_by='login'`: Used with `type='entity'` or `type='entity_list'`. Field used to search the sub entity. Defaults to value provided by `ENTITY_KEYS` or 'name' if no value found. * `search_operator='~'`: Used with `type='entity'` or `type='entity_list'`. Operator used to search the sub entity. Defaults to '='. For fuzzy search use '~'. * `resource_type='organizations'`: Used with `type='entity'` or `type='entity_list'`. Resource type used to build API resource PATH. Defaults to pluralized entity key. diff --git a/plugins/module_utils/foreman_helper.py b/plugins/module_utils/foreman_helper.py index 64d70a50c9..f6f62be2fd 100644 --- a/plugins/module_utils/foreman_helper.py +++ b/plugins/module_utils/foreman_helper.py @@ -42,7 +42,7 @@ PYYAML_IMP_ERR = traceback.format_exc() parameter_foreman_spec = dict( - id=dict(type='invisible'), + id=dict(invisible=True), name=dict(required=True), value=dict(type='raw', required=True), parameter_type=dict(default='string', choices=['string', 'boolean', 'integer', 'real', 'array', 'hash', 'yaml', 'json']), @@ -494,11 +494,8 @@ def find_resource(self, resource, search, params=None, failsafe=False, thin=None else: error_msg = "no" self.fail_json(msg="Found {0} results while searching for {1} with {2}".format(error_msg, resource, search)) - if result: - if thin: - result = {'id': result['id']} - else: - result = self.show_resource(resource, result['id'], params=params) + if result and not thin: + result = self.show_resource(resource, result['id'], params=params) return result def find_resource_by(self, resource, search_field, value, **kwargs): @@ -1124,6 +1121,7 @@ def _foreman_spec_helper(spec): 'failsafe', 'flat_name', 'foreman_spec', + 'invisible', 'resolve', 'resource_type', 'scope', @@ -1162,6 +1160,7 @@ def _foreman_spec_helper(spec): argument_value = {k: v for (k, v) in value.items() if k not in _FILTER_SPEC_KEYS} foreman_type = value.get('type') + ansible_invisible = value.get('invisible', False) flat_name = value.get('flat_name') if foreman_type == 'entity': @@ -1194,7 +1193,7 @@ def _foreman_spec_helper(spec): foreman_spec[key] = foreman_value - if foreman_type != 'invisible': + if not ansible_invisible: argument_spec[key] = argument_value return foreman_spec, argument_spec diff --git a/plugins/modules/compute_resource.py b/plugins/modules/compute_resource.py index e7f24357c3..a7bfc9d8cb 100644 --- a/plugins/modules/compute_resource.py +++ b/plugins/modules/compute_resource.py @@ -339,22 +339,22 @@ def main(): updated_name=dict(), description=dict(), provider=dict(choices=['vmware', 'libvirt', 'ovirt', 'proxmox', 'EC2', 'AzureRm', 'GCE']), - display_type=dict(type='invisible'), - datacenter=dict(type='invisible'), - url=dict(type='invisible'), - caching_enabled=dict(type='invisible'), - user=dict(type='invisible'), - password=dict(type='invisible'), - region=dict(type='invisible'), - tenant=dict(type='invisible'), - app_ident=dict(type='invisible'), - use_v4=dict(type='invisible'), - ovirt_quota=dict(type='invisible'), - project=dict(type='invisible'), - email=dict(type='invisible'), - key_path=dict(type='invisible'), - zone=dict(type='invisible'), - ssl_verify_peer=dict(type='invisible'), + display_type=dict(invisible=True), + datacenter=dict(invisible=True), + url=dict(invisible=True), + caching_enabled=dict(invisible=True), + user=dict(invisible=True), + password=dict(invisible=True), + region=dict(invisible=True), + tenant=dict(invisible=True), + app_ident=dict(invisible=True), + use_v4=dict(invisible=True), + ovirt_quota=dict(invisible=True), + project=dict(invisible=True), + email=dict(invisible=True), + key_path=dict(invisible=True), + zone=dict(invisible=True), + ssl_verify_peer=dict(invisible=True), ), argument_spec=dict( provider_params=dict(type='dict', options=dict( diff --git a/plugins/modules/content_view.py b/plugins/modules/content_view.py index 5cf7a826bc..8a82127c5e 100644 --- a/plugins/modules/content_view.py +++ b/plugins/modules/content_view.py @@ -143,7 +143,7 @@ cvc_foreman_spec = { - 'id': {'type': 'invisible'}, + 'id': {'invisible': True}, 'content_view': {'type': 'entity', 'required': True}, 'latest': {'type': 'bool', 'default': False}, 'content_view_version': {'type': 'entity', 'aliases': ['version']}, diff --git a/plugins/modules/external_usergroup.py b/plugins/modules/external_usergroup.py index b3e52ff61f..f33f244710 100644 --- a/plugins/modules/external_usergroup.py +++ b/plugins/modules/external_usergroup.py @@ -39,11 +39,13 @@ - Name of the linked usergroup required: true type: str - auth_source_ldap: + auth_source: description: - Name of the authentication source to be used for this group required: true type: str + aliases: + - auth_source_ldap extends_documentation_fragment: - theforeman.foreman.foreman - theforeman.foreman.foreman.entity_state @@ -53,7 +55,13 @@ - name: Create an external user group theforeman.foreman.external_usergroup: name: test - auth_source_ldap: "My LDAP server" + auth_source: "My LDAP server" + usergroup: "Internal Usergroup" + state: present +- name: Link a group from FreeIPA + theforeman.foreman.external_usergroup: + name: ipa_users + auth_source: "External" usergroup: "Internal Usergroup" state: present ''' @@ -82,7 +90,9 @@ def main(): foreman_spec=dict( name=dict(required=True), usergroup=dict(required=True), - auth_source_ldap=dict(required=True, type='entity', flat_name='auth_source_id', resource_type='auth_sources'), + auth_source=dict(required=True, aliases=['auth_source_ldap'], type='entity', flat_name='auth_source_id', resource_type='auth_sources'), + auth_source_ldap=dict(type='entity', invisible=True, flat_name='auth_source_id'), + auth_source_external=dict(type='entity', invisible=True, flat_name='auth_source_id'), ), ) @@ -97,8 +107,16 @@ def main(): entity = external_usergroup module.set_entity('entity', entity) - module.auto_lookup_entities() - module.ensure_entity('external_usergroups', module.foreman_params, entity, params) + + auth_source = module.lookup_entity('auth_source') + if auth_source.get('type') == 'AuthSourceExternal': + module.set_entity('auth_source_external', auth_source) + elif auth_source.get('type') == 'AuthSourceLdap': + module.set_entity('auth_source_ldap', auth_source) + else: + module.fail_json(msg="Unsupported authentication source type: {0}".format(auth_source.get('type'))) + + module.run(params=params) if __name__ == '__main__': diff --git a/plugins/modules/host.py b/plugins/modules/host.py index 4040275f74..c42d648a26 100644 --- a/plugins/modules/host.py +++ b/plugins/modules/host.py @@ -220,7 +220,7 @@ def main(): comment=dict(), owner=dict(type='entity', resource_type='users', flat_name='owner_id'), owner_group=dict(type='entity', resource_type='usergroups', flat_name='owner_id'), - owner_type=dict(type='invisible'), + owner_type=dict(invisible=True), provision_method=dict(choices=['build', 'image', 'bootdisk']), image=dict(type='entity', scope=['compute_resource']), compute_attributes=dict(type='dict'), diff --git a/plugins/modules/image.py b/plugins/modules/image.py index efe255c8d2..0e15cd6fe5 100644 --- a/plugins/modules/image.py +++ b/plugins/modules/image.py @@ -106,9 +106,9 @@ def main(): ), foreman_spec=dict( name=dict(required=True), - username=dict(type='invisible'), + username=dict(invisible=True), uuid=dict(required=True, aliases=['image_uuid']), - password=dict(type='invisible', no_log=True), + password=dict(invisible=True, no_log=True), compute_resource=dict(type='entity', required=True), architecture=dict(type='entity', required=True), operatingsystem=dict(type='entity', required=True), diff --git a/plugins/modules/provisioning_template.py b/plugins/modules/provisioning_template.py index 622ccb625f..5a257e5212 100644 --- a/plugins/modules/provisioning_template.py +++ b/plugins/modules/provisioning_template.py @@ -279,7 +279,7 @@ def main(): locked=dict(type='bool'), name=dict(), operatingsystems=dict(type='entity_list'), - snippet=dict(type='invisible'), + snippet=dict(invisible=True), ), mutually_exclusive=[ ['file_name', 'template'], diff --git a/tests/test_foreman_spec_helper.py b/tests/test_foreman_spec_helper.py index ae82195cc3..6c5ff47e20 100644 --- a/tests/test_foreman_spec_helper.py +++ b/tests/test_foreman_spec_helper.py @@ -20,7 +20,7 @@ def test_full_entity(): 'prices': {'type': 'nested_list', 'foreman_spec': { 'value': {'type': 'int'}, }}, - 'tenant': {'type': 'invisible'}, + 'tenant': {'invisible': True}, } foreman_spec, argument_spec = _foreman_spec_helper(spec) assert spec == { @@ -33,7 +33,7 @@ def test_full_entity(): 'prices': {'type': 'nested_list', 'foreman_spec': { 'value': {'type': 'int'}, }}, - 'tenant': {'type': 'invisible'}, + 'tenant': {'invisible': True}, } assert foreman_spec == { 'name': {}, @@ -46,7 +46,7 @@ def test_full_entity(): 'houses': {'type': 'entity_list', 'flat_name': 'house_ids', 'resource_type': 'houses'}, 'house_ids': {'type': 'list'}, 'prices': {'type': 'nested_list', 'ensure': False}, - 'tenant': {'type': 'invisible'}, + 'tenant': {}, } assert argument_spec == { 'name': {},