From ec7686d820b6b4bae0b23311bde02e8b431ce144 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 13:46:23 +0200 Subject: [PATCH 01/16] fix tuple indexerror when no accounts are found --- plugins/module_utils/user.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index 25b17346..62b7dad9 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -113,6 +113,9 @@ def get_existing_authentication(cursor, user, host): group by plugin, authentication_string limit 2""", {'user': user, 'host': host}) rows = cursor.fetchall() + if len(rows) == 0: + return None + # Mysql_info use a DictCursor so we must convert back to a list # otherwise we get KeyError 0 if isinstance(rows, dict): From 5477db90379360bc55fee63abb13a71093059442 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:11:01 +0200 Subject: [PATCH 02/16] Fix tests for update_password not executed --- tests/integration/targets/test_mysql_user/tasks/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/targets/test_mysql_user/tasks/main.yml b/tests/integration/targets/test_mysql_user/tasks/main.yml index 8ec0798c..e77c4436 100644 --- a/tests/integration/targets/test_mysql_user/tasks/main.yml +++ b/tests/integration/targets/test_mysql_user/tasks/main.yml @@ -295,3 +295,7 @@ - name: Mysql_user - test column case sensitive ansible.builtin.import_tasks: file: test_column_case_sensitive.yml + + - name: Mysql_user - test update_password + ansible.builtin.import_tasks: + file: test_update_password.yml From fa3c7b0c05d34ba43dcef2f3930c76f8ad522449 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:11:32 +0200 Subject: [PATCH 03/16] Add test for case where existing user have different password --- .../tasks/test_update_password.yml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml b/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml index 428c1ef7..3e6f42ab 100644 --- a/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml +++ b/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml @@ -127,3 +127,25 @@ update_password: on_create - username: test3 update_password: on_new_username + + # another new user, another new password and multiple existing users with + # varying passwords without providing a password + - name: update_password | Create account with on_new_username while omit password + community.mysql.mysql_user: + login_user: '{{ mysql_parameters.login_user }}' + login_password: '{{ mysql_parameters.login_password }}' + login_host: '{{ mysql_parameters.login_host }}' + login_port: '{{ mysql_parameters.login_port }}' + state: present + name: test3 + host: '10.10.10.10' + update_password: on_new_username + + - name: update_password | Assert create account with on_new_username while omit password produce empty auth string + ansible.builtin.command: >- + {{ mysql_command }} -BNe "SELECT user, host, plugin, authentication_string + FROM mysql.user where user='test3' and host='10.10.10.10'" + register: test3_info + changed_when: false + failed_when: + - "'test3\t10.10.10.10\tmysql_native_password\t' != test3_info.stdout" From c7218c71aa695954e5288595e68309209b83e4a9 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:12:15 +0200 Subject: [PATCH 04/16] lint to prevent warning about jinja templating in when clause --- .../tasks/utils/assert_user_password.yml | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml b/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml index d95e53b8..e6bd6953 100644 --- a/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml +++ b/tests/integration/targets/test_mysql_user/tasks/utils/assert_user_password.yml @@ -1,6 +1,6 @@ --- - name: Utils | Assert user password | Apply update_password to {{ username }} - mysql_user: + community.mysql.mysql_user: login_user: '{{ mysql_parameters.login_user }}' login_password: '{{ mysql_parameters.login_password }}' login_host: '{{ mysql_parameters.login_host }}' @@ -13,16 +13,17 @@ register: result - name: Utils | Assert user password | Assert a change occurred - assert: + ansible.builtin.assert: that: - - "result.changed | bool == {{ expect_change }} | bool" - - "result.password_changed == {{ expect_password_change }}" + - result.changed | bool == expect_change | bool + - result.password_changed == expect_password_change -- name: Utils | Assert user password | Query user {{ username }} - command: "{{ mysql_command }} -BNe \"SELECT plugin, authentication_string FROM mysql.user where user='{{ username }}' and host='{{ host }}'\"" +- name: Utils | Assert user password | Assert expect_hash is in user stdout for {{ username }} + ansible.builtin.command: >- + {{ mysql_command }} -BNe "SELECT plugin, authentication_string + FROM mysql.user where user='{{ username }}' and host='{{ host }}'" register: existing_user - -- name: Utils | Assert user password | Assert expect_hash is in user stdout - assert: - that: - - "'mysql_native_password\t{{ expect_password_hash }}' in existing_user.stdout_lines" + changed_when: false + failed_when: pattern not in existing_user.stdout_lines + vars: + pattern: "mysql_native_password\t{{ expect_password_hash }}" From 3f4af18cb910ab29557272f0a9c0617bf33580e1 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:15:28 +0200 Subject: [PATCH 05/16] Refactor get_existing_authentication to return a list of all row found Previously we were returning only the first row found. We need to be able to see if there is a difference in the existing passwords. --- plugins/module_utils/user.py | 53 ++++++++++++++++++++++++----------- plugins/modules/mysql_info.py | 2 +- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index 62b7dad9..8e52c9be 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -90,7 +90,11 @@ def get_grants(cursor, user, host): def get_existing_authentication(cursor, user, host): - # Return the plugin and auth_string if there is exactly one distinct existing plugin and auth_string. + """ Return a list of dict containing the plugin and auth_string for the + specified username. + If hostname is provided, return only the information about this particular + account. + """ cursor.execute("SELECT VERSION()") srv_type = cursor.fetchone() # Mysql_info use a DictCursor so we must convert back to a list @@ -114,27 +118,30 @@ def get_existing_authentication(cursor, user, host): rows = cursor.fetchall() if len(rows) == 0: - return None + return [] # Mysql_info use a DictCursor so we must convert back to a list # otherwise we get KeyError 0 if isinstance(rows, dict): rows = list(rows.values()) - # 'plugin_auth_string' contains the hash string. Must be removed in c.mysql 4.0 - # See https://github.com/ansible-collections/community.mysql/pull/629 - if isinstance(rows[0], tuple): - return {'plugin': rows[0][0], - 'plugin_auth_string': rows[0][1], - 'plugin_hash_string': rows[0][1]} + existing_auth_list = [] # 'plugin_auth_string' contains the hash string. Must be removed in c.mysql 4.0 # See https://github.com/ansible-collections/community.mysql/pull/629 - if isinstance(rows[0], dict): - return {'plugin': rows[0].get('plugin'), - 'plugin_auth_string': rows[0].get('auth'), - 'plugin_hash_string': rows[0].get('auth')} - return None + for r in rows: + if isinstance(r, tuple): + existing_auth_list.append({ + 'plugin': r[0], + 'plugin_auth_string': r[1], + 'plugin_hash_string': r[1]}) + elif isinstance(r, dict): + existing_auth_list.append({ + 'plugin': r.get('plugin'), + 'plugin_auth_string': r.get('auth'), + 'plugin_hash_string': r.get('auth')}) + + return existing_auth_list def user_add(cursor, user, host, host_all, password, encrypted, @@ -158,14 +165,26 @@ def user_add(cursor, user, host, host_all, password, encrypted, mogrify = do_not_mogrify_requires if old_user_mgmt else mogrify_requires + # This is for update_password: on_new_username used_existing_password = False if reuse_existing_password: existing_auth = get_existing_authentication(cursor, user, host) if existing_auth: - plugin = existing_auth['plugin'] - plugin_hash_string = existing_auth['plugin_hash_string'] - password = None - used_existing_password = True + pass_hashes = [p['plugin_hash_string'] for p in existing_auth] + # Use a set to check if all values are the same + if len(set(pass_hashes)) != 1: + module.warn("An account with the username %s has a different " + "password than the others existing accounts. Thus " + "on_new_username can't decide which password to " + "reuse so it will use your provided password " + "instead. If no password is provided, the account " + "will have an empty password!" % user) + used_existing_password = False + else: + plugin_hash_string = existing_auth[0]['plugin_hash_string'] + password = None + used_existing_password = True + plugin = existing_auth[0]['plugin'] # What if plugin differ? if password and encrypted: if impl.supports_identified_by_password(cursor): query_with_args = "CREATE USER %s@%s IDENTIFIED BY PASSWORD %s", (user, host, password) diff --git a/plugins/modules/mysql_info.py b/plugins/modules/mysql_info.py index c119b8df..acdad2f9 100644 --- a/plugins/modules/mysql_info.py +++ b/plugins/modules/mysql_info.py @@ -633,7 +633,7 @@ def __get_users_info(self): authentications = get_existing_authentication(self.cursor, user, host) if authentications: - output_dict.update(authentications) + output_dict.update(authentications[0]) # TODO password_option # TODO lock_option From f1f06d97a03ede120784a55b67249b4fc33a3611 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:17:20 +0200 Subject: [PATCH 06/16] Refactor host option to be optional This make it possible to use the same method from mysql_user to help update_password retrieve existing password for all account with the same username independently of their hostname. And from mysql_info to get the password of a specif user using WHERE user = '' AND host = '' --- plugins/module_utils/user.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index 8e52c9be..3ef15b0b 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -89,7 +89,7 @@ def get_grants(cursor, user, host): return grants.split(", ") -def get_existing_authentication(cursor, user, host): +def get_existing_authentication(cursor, user, host=None): """ Return a list of dict containing the plugin and auth_string for the specified username. If hostname is provided, return only the information about this particular @@ -105,16 +105,29 @@ def get_existing_authentication(cursor, user, host): if 'mariadb' in srv_type[0].lower(): # before MariaDB 10.2.19 and 10.3.11, "password" and "authentication_string" can differ # when using mysql_native_password - cursor.execute("""select plugin, auth from ( - select plugin, password as auth from mysql.user where user=%(user)s - and host=%(host)s - union select plugin, authentication_string as auth from mysql.user where user=%(user)s - and host=%(host)s) x group by plugin, auth limit 2 - """, {'user': user, 'host': host}) + if host: + cursor.execute("""select plugin, auth from ( + select plugin, password as auth from mysql.user where user=%(user)s + and host=%(host)s + union select plugin, authentication_string as auth from mysql.user where user=%(user)s + and host=%(host)s) x group by plugin, auth + """, {'user': user, 'host': host}) + else: + cursor.execute("""select plugin, auth from ( + select plugin, password as auth from mysql.user where user=%(user)s + union select plugin, authentication_string as auth from mysql.user where user=%(user)s + ) x group by plugin, auth + """, {'user': user}) else: - cursor.execute("""select plugin, authentication_string as auth - from mysql.user where user=%(user)s and host=%(host)s - group by plugin, authentication_string limit 2""", {'user': user, 'host': host}) + if host: + cursor.execute("""select plugin, authentication_string as auth + from mysql.user where user=%(user)s and host=%(host)s + group by plugin, authentication_string""", {'user': user, 'host': host}) + else: + cursor.execute("""select plugin, authentication_string as auth + from mysql.user where user=%(user)s + group by plugin, authentication_string""", {'user': user}) + rows = cursor.fetchall() if len(rows) == 0: @@ -168,7 +181,7 @@ def user_add(cursor, user, host, host_all, password, encrypted, # This is for update_password: on_new_username used_existing_password = False if reuse_existing_password: - existing_auth = get_existing_authentication(cursor, user, host) + existing_auth = get_existing_authentication(cursor, user) if existing_auth: pass_hashes = [p['plugin_hash_string'] for p in existing_auth] # Use a set to check if all values are the same From 2532f2a3845a3578f1398baaff24a183d1a941ac Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:27:16 +0200 Subject: [PATCH 07/16] Add change log fragment --- changelogs/fragments/lie_fix_mysql_user_on_new_username.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changelogs/fragments/lie_fix_mysql_user_on_new_username.yml diff --git a/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml b/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml new file mode 100644 index 00000000..cdf931df --- /dev/null +++ b/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml @@ -0,0 +1,6 @@ +--- + +bugfixes: + + - mysql_user - Fixed an IndexError in the update_password functionality introduced in PR https://github.com/ansible-collections/community.mysql/pull/580 and released in community.mysql 3.8.0. If you used this functionality, please avoid versions 3.8.0 to 3.9.0. + - mysql_user - Added a warning to update_password's on_new_username option if multiple accounts with the same username but different passwords exist. From a7a298d7f08a0ca381aad883bf626e0e94b4a71b Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 19:35:49 +0200 Subject: [PATCH 08/16] Add link to the PR in the change log --- changelogs/fragments/lie_fix_mysql_user_on_new_username.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml b/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml index cdf931df..7f13738b 100644 --- a/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml +++ b/changelogs/fragments/lie_fix_mysql_user_on_new_username.yml @@ -2,5 +2,5 @@ bugfixes: - - mysql_user - Fixed an IndexError in the update_password functionality introduced in PR https://github.com/ansible-collections/community.mysql/pull/580 and released in community.mysql 3.8.0. If you used this functionality, please avoid versions 3.8.0 to 3.9.0. - - mysql_user - Added a warning to update_password's on_new_username option if multiple accounts with the same username but different passwords exist. + - mysql_user - Fixed an IndexError in the update_password functionality introduced in PR https://github.com/ansible-collections/community.mysql/pull/580 and released in community.mysql 3.8.0. If you used this functionality, please avoid versions 3.8.0 to 3.9.0 (https://github.com/ansible-collections/community.mysql/pull/642). + - mysql_user - Added a warning to update_password's on_new_username option if multiple accounts with the same username but different passwords exist (https://github.com/ansible-collections/community.mysql/pull/642). From 0bcbaf8dc6cfa7eaa871ee6b5df8d5f54932b50e Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Thu, 6 Jun 2024 23:27:37 +0200 Subject: [PATCH 09/16] lint for ansible devel --- .../test_mysql_variables/tasks/issue-28.yml | 39 ++++++++++--------- .../tasks/mysql_variables.yml | 24 ++++++------ 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml b/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml index 10a91541..5bda205a 100644 --- a/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml +++ b/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml @@ -1,9 +1,12 @@ --- - name: set fact tls_enabled - command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\"" + ansible.builtin.command: + cmd: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\"" register: result -- set_fact: - tls_enabled: "{{ 'YES' in result.stdout | bool | default('false', true) }}" + +- name: Set tls_enabled fact + ansible.builtin.set_fact: + tls_enabled: "{{ 'YES' in result.stdout }}" - vars: mysql_parameters: &mysql_params @@ -16,21 +19,21 @@ # ============================================================ - name: get server certificate - copy: + ansible.builtin.copy: content: "{{ lookup('pipe', \"openssl s_client -starttls mysql -connect localhost:3307 -showcerts 2>/dev/null = 0.7.11 is required' in result.msg + ignore_errors: true + failed_when: + - result is failed or 'pymysql >= 0.7.11 is required' not in result.msg - name: Drop mysql user - mysql_user: + community.mysql.mysql_user: <<: *mysql_params name: '{{ user_name_1 }}' host_all: true diff --git a/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml b/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml index 2d2318e2..4a7fd000 100644 --- a/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml +++ b/tests/integration/targets/test_mysql_variables/tasks/mysql_variables.yml @@ -47,8 +47,8 @@ # Verify mysql_variable successfully updates a variable (issue:4568) # - set_fact: - set_name: 'delay_key_write' - set_value: 'ON' + set_name: 'delay_key_write' + set_value: 'ON' - name: set mysql variable mysql_variables: @@ -74,8 +74,8 @@ # Verify mysql_variable successfully updates a variable using single quotes # - set_fact: - set_name: 'wait_timeout' - set_value: '300' + set_name: 'wait_timeout' + set_value: '300' - name: set mysql variable to a temp value mysql_variables: @@ -105,8 +105,8 @@ # Verify mysql_variable successfully updates a variable using double quotes # - set_fact: - set_name: "wait_timeout" - set_value: "400" + set_name: "wait_timeout" + set_value: "400" - name: set mysql variable to a temp value mysql_variables: @@ -132,8 +132,8 @@ # Verify mysql_variable successfully updates a variable using no quotes # - set_fact: - set_name: wait_timeout - set_value: 500 + set_name: wait_timeout + set_value: 500 - name: set mysql variable to a temp value mysql_variables: @@ -251,8 +251,8 @@ # Verify mysql_variable works with the login_user and login_password parameters # - set_fact: - set_name: wait_timeout - set_value: 77 + set_name: wait_timeout + set_value: 77 - name: query mysql_variable using login_user and password_password mysql_variables: @@ -291,8 +291,8 @@ # Verify mysql_variable fails with an incorrect login_password parameter # - set_fact: - set_name: connect_timeout - set_value: 10 + set_name: connect_timeout + set_value: 10 - name: query mysql_variable using incorrect login_password mysql_variables: From b1fa90dc28251ce00def04d5dde4a186db1841b7 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Fri, 7 Jun 2024 17:49:47 +0200 Subject: [PATCH 10/16] Fix templating type error could not cconvert to bool with ansible devel --- tests/integration/targets/test_mysql_db/tasks/issue-28.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/test_mysql_db/tasks/issue-28.yml b/tests/integration/targets/test_mysql_db/tasks/issue-28.yml index 8cad28e6..5e4125f6 100644 --- a/tests/integration/targets/test_mysql_db/tasks/issue-28.yml +++ b/tests/integration/targets/test_mysql_db/tasks/issue-28.yml @@ -3,7 +3,7 @@ command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\"" register: result - set_fact: - tls_enabled: "{{ 'YES' in result.stdout | bool | default('false', true) }}" + tls_enabled: "{{ 'YES' in result.stdout }}" - vars: mysql_parameters: &mysql_params From a90e9048911b29197784a4bb3eeb54802c6ed081 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Mon, 10 Jun 2024 19:48:13 +0200 Subject: [PATCH 11/16] Revert changes made for ansible-devel that broke tests for Ansible 2.15 --- tests/integration/targets/test_mysql_db/tasks/issue-28.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/test_mysql_db/tasks/issue-28.yml b/tests/integration/targets/test_mysql_db/tasks/issue-28.yml index 5e4125f6..8cad28e6 100644 --- a/tests/integration/targets/test_mysql_db/tasks/issue-28.yml +++ b/tests/integration/targets/test_mysql_db/tasks/issue-28.yml @@ -3,7 +3,7 @@ command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\"" register: result - set_fact: - tls_enabled: "{{ 'YES' in result.stdout }}" + tls_enabled: "{{ 'YES' in result.stdout | bool | default('false', true) }}" - vars: mysql_parameters: &mysql_params From dfb3ef9714be9dd6226d458a069b50383aaad89c Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Mon, 10 Jun 2024 20:16:08 +0200 Subject: [PATCH 12/16] Revert changes made for ansible-devel that broke tests --- .../integration/targets/test_mysql_variables/tasks/issue-28.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml b/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml index 5bda205a..89d3d260 100644 --- a/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml +++ b/tests/integration/targets/test_mysql_variables/tasks/issue-28.yml @@ -6,7 +6,7 @@ - name: Set tls_enabled fact ansible.builtin.set_fact: - tls_enabled: "{{ 'YES' in result.stdout }}" + tls_enabled: "{{ 'YES' in result.stdout | bool | default('false', true) }}" - vars: mysql_parameters: &mysql_params From bd4f17d350cbdb9ec56fd7a415748ae20abd7888 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Wed, 19 Jun 2024 17:19:34 +0200 Subject: [PATCH 13/16] Cut unnecessary set, uniqueness is ensured by the group_by in the query --- plugins/module_utils/user.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index e8dfb66e..81bacdd5 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -189,9 +189,7 @@ def user_add(cursor, user, host, host_all, password, encrypted, if reuse_existing_password: existing_auth = get_existing_authentication(cursor, user) if existing_auth: - pass_hashes = [p['plugin_hash_string'] for p in existing_auth] - # Use a set to check if all values are the same - if len(set(pass_hashes)) != 1: + if len(existing_auth) != 1: module.warn("An account with the username %s has a different " "password than the others existing accounts. Thus " "on_new_username can't decide which password to " From 67f2e80ba362219c1754a0fc542f7b664edf0129 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Mon, 24 Jun 2024 11:29:03 +0200 Subject: [PATCH 14/16] Cut auth plugin from returned values when multiple existing auths exists Discussed here: https://github.com/ansible-collections/community.mysql/pull/642/files#r1649720519 --- plugins/module_utils/user.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index 81bacdd5..8e148484 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -201,7 +201,7 @@ def user_add(cursor, user, host, host_all, password, encrypted, plugin_hash_string = existing_auth[0]['plugin_hash_string'] password = None used_existing_password = True - plugin = existing_auth[0]['plugin'] # What if plugin differ? + plugin = existing_auth[0]['plugin'] # What if plugin differ? if password and encrypted: if impl.supports_identified_by_password(cursor): query_with_args = "CREATE USER %s@%s IDENTIFIED BY PASSWORD %s", (user, host, password) From 0eacc5ad4116c78f0eb6d4b11e1a18cd125a723e Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Mon, 24 Jun 2024 17:37:26 +0200 Subject: [PATCH 15/16] fix convertion of list(dict) to list(tuple) --- plugins/module_utils/user.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index 8e148484..bd716918 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -139,26 +139,20 @@ def get_existing_authentication(cursor, user, host=None): if len(rows) == 0: return [] - # Mysql_info use a DictCursor so we must convert back to a list - # otherwise we get KeyError 0 - if isinstance(rows, dict): - rows = list(rows.values()) + # Mysql_info use a DictCursor so we must convert list(dict) + # to list(tuple) otherwise we get KeyError 0 + if isinstance(rows[0], dict): + rows = [tuple(row.values()) for row in rows] existing_auth_list = [] # 'plugin_auth_string' contains the hash string. Must be removed in c.mysql 4.0 # See https://github.com/ansible-collections/community.mysql/pull/629 for r in rows: - if isinstance(r, tuple): - existing_auth_list.append({ - 'plugin': r[0], - 'plugin_auth_string': r[1], - 'plugin_hash_string': r[1]}) - elif isinstance(r, dict): - existing_auth_list.append({ - 'plugin': r.get('plugin'), - 'plugin_auth_string': r.get('auth'), - 'plugin_hash_string': r.get('auth')}) + existing_auth_list.append({ + 'plugin': r[0], + 'plugin_auth_string': r[1], + 'plugin_hash_string': r[1]}) return existing_auth_list From b651053b16887fac53feb3181a734f60aeafe439 Mon Sep 17 00:00:00 2001 From: Laurent Indermuehle Date: Mon, 24 Jun 2024 17:48:40 +0200 Subject: [PATCH 16/16] Fix test for empty password on MySQL 8+ --- .../targets/test_mysql_user/tasks/test_update_password.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml b/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml index 3e6f42ab..adaa7c72 100644 --- a/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml +++ b/tests/integration/targets/test_mysql_user/tasks/test_update_password.yml @@ -148,4 +148,8 @@ register: test3_info changed_when: false failed_when: + # MariaDB default plugin is mysql_native_password - "'test3\t10.10.10.10\tmysql_native_password\t' != test3_info.stdout" + + # MySQL 8+ default plugin is caching_sha2_password + - "'test3\t10.10.10.10\tcaching_sha2_password\t' != test3_info.stdout"