ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
816 stars 1.5k forks source link

Cannot create a keycloak subgroup that belongs to a parent using community.general.keycloak_group #8366

Open vvanouytsel opened 4 months ago

vvanouytsel commented 4 months ago

Summary

The example below is shown in the documentation but is not working. The subgroup gets created but the error message is still thrown.

- name: Create a Keycloak group, authentication with credentials
  community.general.keycloak_group:
    name: my-new-kc-group
    realm: MyCustomRealm
    state: present
    auth_client_id: admin-cli
    auth_keycloak_url: https://auth.example.com/auth
    auth_realm: master
    auth_username: USERNAME
    auth_password: PASSWORD
  register: result_new_kcgrp
  delegate_to: localhost
- name: Create a Keycloak subgroup of a base group (using parent name)
  community.general.keycloak_group:
    name: my-new-kc-group-sub
    realm: MyCustomRealm
    state: present
    auth_client_id: admin-cli
    auth_keycloak_url: https://auth.example.com/auth
    auth_realm: master
    auth_username: USERNAME
    auth_password: PASSWORD
    parents:
      - name: my-new-kc-group
  register: result_new_kcgrp_sub
  delegate_to: localhost

The full play I used to test this:

---
- name: Create group and subgroup
  hosts: localhost
  become: true
  tasks:
  - name: Create a Keycloak realm
    community.general.keycloak_realm:
      realm: MyCustomRealm
      id: MyCustomRealm
      auth_client_id: admin-cli
      auth_keycloak_url: REDACTED
      auth_realm: master
      auth_username: REDACTED
      auth_password: REDACTED
    delegate_to: localhost

  - name: Create a Keycloak group, authentication with credentials
    community.general.keycloak_group:
      name: my-new-kc-group
      realm: MyCustomRealm
      auth_client_id: admin-cli
      auth_keycloak_url: REDACTED
      auth_realm: master
      auth_username: REDACTED
      auth_password: REDACTED
    delegate_to: localhost

  - name: Create a Keycloak subgroup of a base group (using parent name)
    community.general.keycloak_group:
      name: my-new-kc-group-sub
      realm: MyCustomRealm
      auth_client_id: admin-cli
      auth_keycloak_url: REDACTED
      auth_realm: master
      auth_username: REDACTED
      auth_password: REDACTED
      parents:
        - name: my-new-kc-group
    delegate_to: localhost

The result of the failing task using -vvv:

TASK [Create a Keycloak subgroup of a base group (using parent name)] ********************************************************************************************************************************************************************
task path: /opt/ansible/ansible-images/plays/keycloak-test.yml:28
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413 `" && echo ansible-tmp-1715760171.9674118-1354-226696054495413="` echo /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413 `" ) && sleep 0'
Using module file /root/.ansible/collections/ansible_collections/community/general/plugins/modules/keycloak_group.py
<localhost> PUT /root/.ansible/tmp/ansible-local-12728113mzjp/tmpbgcs4ffx TO /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/ /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python3 /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py", line 107, in <module>
    _ansiballz_main()
  File "/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py", line 99, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py", line 47, in invoke_module
    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.keycloak_group', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.keycloak_group', _modlib_path=modlib_path),
  File "/usr/lib64/python3.9/runpy.py", line 225, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib64/python3.9/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib64/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py", line 496, in <module>
  File "/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py", line 440, in main
TypeError: 'NoneType' object is not subscriptable
fatal: [localhost]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py\", line 107, in <module>\n    _ansiballz_main()\n  File \"/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py\", line 99, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py\", line 47, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.keycloak_group', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.keycloak_group', _modlib_path=modlib_path),\n  File \"/usr/lib64/python3.9/runpy.py\", line 225, in run_module\n    return _run_module_code(code, init_globals, run_name, mod_spec)\n  File \"/usr/lib64/python3.9/runpy.py\", line 97, in _run_module_code\n    _run_code(code, mod_globals, init_globals,\n  File \"/usr/lib64/python3.9/runpy.py\", line 87, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py\", line 496, in <module>\n  File \"/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py\", line 440, in main\nTypeError: 'NoneType' object is not subscriptable\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
    "rc": 1
}

If you run it again it will fail because the subgroup is already created. So the interesting part is that the subgroup does get created, but during creation it throws an error.

TASK [Create a Keycloak subgroup of a base group (using parent name)] ********************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Could not create subgroup my-new-kc-group-sub for parent group 817315f7-0a28-4ea6-b86b-596be399e792 in realm MyCustomRealm: HTTP Error 409: Conflict: {\"errorMessage\":\"Sibling group named 'my-new-kc-group-sub' already exists.\"}"}

Issue Type

Bug Report

Component Name

keycloak_group

Ansible Version

$ ansible --version
ansible [core 2.14.14]
  config file = /opt/ansible/ansible-images/ansible.cfg
  configured module search path = ['/opt/ansible/ansible-images/library']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.18 (main, Sep  7 2023, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general
# /root/.ansible/collections/ansible_collections
Collection        Version
----------------- -------
community.general 8.6.0  

Configuration

$ ansible-config dump --only-changed
CONFIG_FILE() = /opt/ansible/ansible-images/ansible.cfg
DEFAULT_FORKS(env: ANSIBLE_FORKS) = 10
DEFAULT_HOST_LIST(/opt/ansible/ansible-images/ansible.cfg) = ['/opt/ansible/ansible-images/inventory']
DEFAULT_LOAD_CALLBACK_PLUGINS(/opt/ansible/ansible-images/ansible.cfg) = True
DEFAULT_MANAGED_STR(/opt/ansible/ansible-images/ansible.cfg) = Managed by ansible: REDACTED
DEFAULT_MODULE_PATH(env: ANSIBLE_LIBRARY) = ['/opt/ansible/ansible-images/library']
DEFAULT_ROLES_PATH(/opt/ansible/ansible-images/ansible.cfg) = ['/opt/ansible/ansible-images/roles']
DEFAULT_STDOUT_CALLBACK(env: ANSIBLE_STDOUT_CALLBACK) = default
DEFAULT_TIMEOUT(/opt/ansible/ansible-images/ansible.cfg) = 30
DEPRECATION_WARNINGS(/opt/ansible/ansible-images/ansible.cfg) = False
HOST_KEY_CHECKING(/opt/ansible/ansible-images/ansible.cfg) = False
PERSISTENT_COMMAND_TIMEOUT(/opt/ansible/ansible-images/ansible.cfg) = 60
PERSISTENT_CONNECT_TIMEOUT(/opt/ansible/ansible-images/ansible.cfg) = 60
RETRY_FILES_ENABLED(/opt/ansible/ansible-images/ansible.cfg) = False

OS / Environment

NAME="AlmaLinux" VERSION="9.3 (Shamrock Pampas Cat)" ID="almalinux" ID_LIKE="rhel centos fedora" VERSION_ID="9.3" PLATFORM_ID="platform:el9" PRETTY_NAME="AlmaLinux 9.3 (Shamrock Pampas Cat)" ANSI_COLOR="0;34" LOGO="fedora-logo-icon" CPE_NAME="cpe:/o:almalinux:almalinux:9::baseos" HOME_URL="https://almalinux.org/" DOCUMENTATION_URL="https://wiki.almalinux.org/" BUG_REPORT_URL="https://bugs.almalinux.org/"

ALMALINUX_MANTISBT_PROJECT="AlmaLinux-9" ALMALINUX_MANTISBT_PROJECT_VERSION="9.3" REDHAT_SUPPORT_PRODUCT="AlmaLinux" REDHAT_SUPPORT_PRODUCT_VERSION="9.3"

Steps to Reproduce

---
- name: Create group and subgroup
  hosts: localhost
  become: true
  tasks:
  - name: Create a Keycloak realm
    community.general.keycloak_realm:
      realm: MyCustomRealm
      id: MyCustomRealm
      auth_client_id: admin-cli
      auth_keycloak_url: REDACTED
      auth_realm: master
      auth_username: REDACTED
      auth_password: REDACTED
    delegate_to: localhost

  - name: Create a Keycloak group, authentication with credentials
    community.general.keycloak_group:
      name: my-new-kc-group
      realm: MyCustomRealm
      auth_client_id: admin-cli
      auth_keycloak_url: REDACTED
      auth_realm: master
      auth_username: REDACTED
      auth_password: REDACTED
    delegate_to: localhost

  - name: Create a Keycloak subgroup of a base group (using parent name)
    community.general.keycloak_group:
      name: my-new-kc-group-sub
      realm: MyCustomRealm
      auth_client_id: admin-cli
      auth_keycloak_url: REDACTED
      auth_realm: master
      auth_username: REDACTED
      auth_password: REDACTED
      parents:
        - name: my-new-kc-group
    delegate_to: localhost

Expected Results

I expect the subgroup to be created without any errors. I also expect the next time that the play runs, it does not fail with the message that the subgroup already exists. I would expect the module to be idempotent.

Actual Results

The first time, when the subgroup does not yet exist:

TASK [Create a Keycloak subgroup of a base group (using parent name)] ********************************************************************************************************************************************************************
task path: /opt/ansible/ansible-images/plays/keycloak-test.yml:28
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413 `" && echo ansible-tmp-1715760171.9674118-1354-226696054495413="` echo /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413 `" ) && sleep 0'
Using module file /root/.ansible/collections/ansible_collections/community/general/plugins/modules/keycloak_group.py
<localhost> PUT /root/.ansible/tmp/ansible-local-12728113mzjp/tmpbgcs4ffx TO /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/ /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python3 /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py", line 107, in <module>
    _ansiballz_main()
  File "/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py", line 99, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py", line 47, in invoke_module
    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.keycloak_group', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.keycloak_group', _modlib_path=modlib_path),
  File "/usr/lib64/python3.9/runpy.py", line 225, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib64/python3.9/runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib64/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py", line 496, in <module>
  File "/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py", line 440, in main
TypeError: 'NoneType' object is not subscriptable
fatal: [localhost]: FAILED! => {
    "changed": false,
    "module_stderr": "Traceback (most recent call last):\n  File \"/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py\", line 107, in <module>\n    _ansiballz_main()\n  File \"/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py\", line 99, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/root/.ansible/tmp/ansible-tmp-1715760171.9674118-1354-226696054495413/AnsiballZ_keycloak_group.py\", line 47, in invoke_module\n    runpy.run_module(mod_name='ansible_collections.community.general.plugins.modules.keycloak_group', init_globals=dict(_module_fqn='ansible_collections.community.general.plugins.modules.keycloak_group', _modlib_path=modlib_path),\n  File \"/usr/lib64/python3.9/runpy.py\", line 225, in run_module\n    return _run_module_code(code, init_globals, run_name, mod_spec)\n  File \"/usr/lib64/python3.9/runpy.py\", line 97, in _run_module_code\n    _run_code(code, mod_globals, init_globals,\n  File \"/usr/lib64/python3.9/runpy.py\", line 87, in _run_code\n    exec(code, run_globals)\n  File \"/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py\", line 496, in <module>\n  File \"/tmp/ansible_community.general.keycloak_group_payload__jftkg3a/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/modules/keycloak_group.py\", line 440, in main\nTypeError: 'NoneType' object is not subscriptable\n",
    "module_stdout": "",
    "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
    "rc": 1
}

The second time when the subgroup exists (even though the task fails):

TASK [Create a Keycloak subgroup of a base group (using parent name)] ********************************************************************************************************************************************************************
task path: /opt/ansible/ansible-images/plays/keycloak-test.yml:28
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921 `" && echo ansible-tmp-1715760496.1611168-1658-7800122281921="` echo /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921 `" ) && sleep 0'
Using module file /root/.ansible/collections/ansible_collections/community/general/plugins/modules/keycloak_group.py
<localhost> PUT /root/.ansible/tmp/ansible-local-1576qb7eg5aj/tmpucpndqhq TO /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921/AnsiballZ_keycloak_group.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921/ /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921/AnsiballZ_keycloak_group.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python3 /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921/AnsiballZ_keycloak_group.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1715760496.1611168-1658-7800122281921/ > /dev/null 2>&1 && sleep 0'
The full traceback is:
  File "/tmp/ansible_community.general.keycloak_group_payload_h90t8_dr/ansible_community.general.keycloak_group_payload.zip/ansible_collections/community/general/plugins/module_utils/identity/keycloak/keycloak.py", line 1637, in create_subgroup
    return open_url(url, method='POST', http_agent=self.http_agent, headers=self.restheaders, timeout=self.connection_timeout,
  File "/tmp/ansible_community.general.keycloak_group_payload_h90t8_dr/ansible_community.general.keycloak_group_payload.zip/ansible/module_utils/urls.py", line 1665, in open_url
    return Request().open(method, url, data=data, headers=headers, use_proxy=use_proxy,
  File "/tmp/ansible_community.general.keycloak_group_payload_h90t8_dr/ansible_community.general.keycloak_group_payload.zip/ansible/module_utils/urls.py", line 1557, in open
    r = urllib_request.urlopen(request, None, timeout)
  File "/usr/lib64/python3.9/urllib/request.py", line 214, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib64/python3.9/urllib/request.py", line 523, in open
    response = meth(req, response)
  File "/usr/lib64/python3.9/urllib/request.py", line 632, in http_response
    response = self.parent.error(
  File "/usr/lib64/python3.9/urllib/request.py", line 561, in error
    return self._call_chain(*args)
  File "/usr/lib64/python3.9/urllib/request.py", line 494, in _call_chain
    result = func(*args)
  File "/usr/lib64/python3.9/urllib/request.py", line 641, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
fatal: [localhost]: FAILED! => {
    "changed": false,
    "invocation": {
        "module_args": {
            "attributes": null,
            "auth_client_id": "admin-cli",
            "auth_client_secret": null,
            "auth_keycloak_url": "REDACTED",
            "auth_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "auth_realm": "master",
            "auth_username": "REDACTED",
            "connection_timeout": 10,
            "http_agent": "Ansible",
            "id": null,
            "name": "my-new-kc-group-sub",
            "parents": [
                {
                    "id": null,
                    "name": "my-new-kc-group"
                }
            ],
            "realm": "MyCustomRealm",
            "state": "present",
            "token": null,
            "validate_certs": true
        }
    },
    "msg": "Could not create subgroup my-new-kc-group-sub for parent group 817315f7-0a28-4ea6-b86b-596be399e792 in realm MyCustomRealm: HTTP Error 409: Conflict: {\"errorMessage\":\"Sibling group named 'my-new-kc-group-sub' already exists.\"}"
}

Code of Conduct

ansibullbot commented 4 months ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 4 months ago

cc @adamgoossens @eikef @mattock @ndclt click here for bot help

digitalfox commented 4 months ago

I encounter the same issue. And it works with keycloak 22.X. The issue trigger on keycloak 23.X and 24.X

digitalfox commented 4 months ago

Looks like it is related to a change in keycloak sub group representation since KC 23 : https://www.keycloak.org/docs/23.0.0/upgrading/index.html#grouprepresentation-changes

ansible module should now call expliciterly the children API to get information, as stated in this report: https://github.com/keycloak/keycloak/issues/25053#issuecomment-1892193969

ansibullbot commented 2 months ago

cc @thomasbach-dev click here for bot help