ansible-collections / community.cassandra

Cassandra Ansible Collection
http://galaxy.ansible.com/community/cassandra
GNU General Public License v3.0
25 stars 17 forks source link

Role module - argument of type 'NoneType' is not iterable #281

Open jamesdehart opened 1 month ago

jamesdehart commented 1 month ago
SUMMARY

Using the community.cassandra.cassandra_role module to create the inital roles. Then in a later step I added some grants to this role. If ansible runs a 2nd time you will get argument of type 'NoneType' is not iterable.

ISSUE TYPE
COMPONENT NAME
ANSIBLE VERSION
ansible [core 2.16.6]
  config file = /Users/<user_name>/gitlab/devops/testing/ansible.cfg
  configured module search path = ['/Users/<user_name>//.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/<user_name>//.local/pipx/venvs/ansible/lib/python3.12/site-packages/ansible
  ansible collection location = /Users/<user_name>/.ansible/collections:/usr/share/ansible/collections
  executable location = /Users/<user_name>/.local/bin/ansible
  python version = 3.12.2 (main, Feb 22 2024, 16:59:04) [Clang 15.0.0 (clang-1500.1.0.2.5)] (/Users/<user_name>/.local/pipx/venvs/ansible/bin/python)
  jinja version = 3.1.3
  libyaml = True
COLLECTION VERSION
community.general 8.6.0 
CONFIGURATION

default configs.

OS / ENVIRONMENT
STEPS TO REPRODUCE

Given the following flow (Assuming the default super user is used) everything works the first time.


- name: DB Role | Create roles with login and passwords.
  community.cassandra.cassandra_role:
    name: "{{ item.role_name }}"
    password: "{{ item.role_password }}"
    state: present
    ssl: true
    super_user: false
    login: true
    login_host: 127.0.0.1
  loop:
    - { role_name: service_user, role_password: Password123 }

- name: DB Role | Create roles without login.
  community.cassandra.cassandra_role:
    name: "{{ item.role_name }}"
    password: "{{ item.role_password }}"
    state: present
    ssl: true
    super_user: false
    login: false
    login_host: 127.0.0.1
  loop:
    - { role_name: g_select_system_keyspace, role_password: '' }

- name: CQLSH Grants | SELECT
  community.cassandra.cassandra_cqlsh:
    execute: GRANT SELECT ON KEYSPACE system TO g_select_system_keyspace;
    ssl: true
    username: cassandra
    password: cassandra
    cqlsh_cmd: /usr/local/bin/cqlsh
    cqlsh_host: 127.0.0.1

- name: CQLSH Grants | Roles to login roles.
  community.cassandra.cassandra_cqlsh:
    execute: GRANT {{ item.service_role }} TO {{ item.login_role }};
    ssl: true
    username: cassandra
    password: cassandra
    cqlsh_cmd: /usr/local/bin/cqlsh
    cqlsh_host: 127.0.0.1
  loop:
    - { service_role: g_select_system_keyspace, login_role: service_user }
EXPECTED RESULTS

Not to error out.

ACTUAL RESULTS

The issue happens with the 2nd time running the apply. Seen below:

TASK [cassandra-db : DB Role | Create roles with login and passwords.] ********************************************************************************************************************************************************************
[WARNING]: Module did not set no_log for update_password
failed: [cassandra] (item={'role_name': 'service_user', 'role_password': 'Password123'}) => {"ansible_loop_var": "item", "changed": false, "item": {"role_name": "service_user", "role_password": "Password123"}, "msg": "argument of type 'NoneType' is not iterable", "role": "service_user"}

More details below. You can see roles is null and that causes issues

The full traceback is:
  File "/tmp/ansible_c_role_payload_dvlm7lrh/ansible_c_role_payload.zip/ansible/modules/cassandra_role.py", line 827, in main
  File "/tmp/ansible_c_role_payload_dvlm7lrh/ansible_c_role_payload.zip/ansible/modules/cassandra_role.py", line 446, in build_role_grants
[WARNING]: Module did not set no_log for update_password
failed: [cassandra] (item={'role_name': 'service_user', 'role_password': 'Password123'}) => {
    "ansible_loop_var": "item",
    "changed": false,
    "invocation": {
        "module_args": {
            "data_centres": null,
            "debug": false,
            "keyspace_permissions": null,
            "login": true,
            "login_host": [
                "127.0.0.1"
            ],
            "login_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "login_port": 9042,
            "login_user": "cassandra",
            "name": "service_user",
            "options": null,
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "roles": null,
            "ssl": true,
            "ssl_ca_certs": "/etc/cassandra/conf/certs/cassandra_client_cert.pem",
            "ssl_cert_reqs": "CERT_REQUIRED",
            "ssl_client_cert": "/etc/cassandra/conf/certs/cassandra_client_cert.pem",
            "ssl_client_key": "/etc/cassandra/conf/certs/cassandra_client_key.pem",
            "state": "present",
            "super_user": false,
            "update_password": false
        }
    },
    "item": {
        "role_name": "service_user",
        "role_password": "Password123"
    },
    "msg": "argument of type 'NoneType' is not iterable",
    "role": "service_user"
}

I think the issue is here -> https://github.com/ansible-collections/community.cassandra/blob/master/plugins/modules/cassandra_role.py#L437 where there is no null check for roles. I'm not sure if this is expected or not.

Since I'm working on adding support for the cert files to use two way auth I changed:

if current_roles is not None:

to

if current_roles is not None and roles is not None:

That seems to fix the issue with additional runs.

rhysmeister commented 1 month ago

Hello @jamesdehart,

In general I'd advise against managing objects outside the moudle that creates them. The module provides a "roles" parameter so I'd stick to using that to grant roles. That said the suggested fix is fine provided it doesn't break anything else.

Cheers,

Rnys