-
Notifications
You must be signed in to change notification settings - Fork 97
Description
SUMMARY
Granting ALL PRIVILEGES at a global level will always result in a change being detected. I came across this issue when trying to re-enable the user_password_update_test.yml
test for another change. This appears to be linked to the following change in MySQL 8.0:
In MySQL 8.0 compared to previous series, SHOW GRANTS no longer displays ALL PRIVILEGES in its global-privileges output because the meaning of ALL PRIVILEGES at the global level varies depending on which dynamic privileges are defined. Instead, SHOW GRANTS explictly lists each granted global privilege
(https://dev.mysql.com/doc/refman/8.0/en/show-grants.html)
So, because the expanded list of all privileges doesn't match "ALL PRIVILEGES", a change will always be made when applying *.*:ALL
. Privileges at the database and/or table level are unaffected (hopefully the more common use case).
This issue appears to be complicated by the fact that dynamic privileges are defined at runtime as per the docs. This isn't my area of expertise, but my understanding of the implication of this is that we cannot reliably hard-code dynamic privileges to check. SHOW PRIVILEGES
seems to get us the list of privileges that would be applied to a user with *.*:ALL
(in addition to GRANT
, PROXY
, and USAGE
).
I can think of a couple of options:
- This is the desired behavior. It can be added to the documentation and the test below can be added so the intent is clear. Possibly a warning?
- Build the list of privileges to check against using
SHOW PRIVILEGES
when priv is*.*:ALL
Like I mentioned, this isn't my area of expertise, so it is possible that hard-coding the privileges will really work, but purely based on the documentation it seems like it wouldn't.
ISSUE TYPE
- Bug Report
COMPONENT NAME
mysql_user
ANSIBLE VERSION
Development
CONFIGURATION
Development environment
OS / ENVIRONMENT
Development environment
STEPS TO REPRODUCE
The following test will fail and reproduce the issue:
- vars:
mysql_parameters: &mysql_params
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
block:
- name: Create a user with all privileges
mysql_user:
<<: *mysql_params
name: '{{ user_name_5 }}'
password: '{{ user_password_5 }}'
priv: '*.*:ALL'
state: present
register: result
- name: Assert that there was a change because the permissions did not exist previously
assert:
that:
- "result.changed == true"
- name: Test idempotency when nothing has changed and we're still granting ALL privileges
mysql_user:
<<: *mysql_params
name: '{{ user_name_5 }}'
password: '{{ user_password_5 }}'
priv: '*.*:ALL'
state: present
register: result
- name: Assert that there wasn't a change because the user already had ALL privileges
assert:
that:
- "result.changed == false"
##########
# Clean up
- name: Drop test user
mysql_user:
<<: *mysql_params
name: '{{ user_name_5 }}'
state: absent
EXPECTED RESULTS
The test above should pass because no change was made to the privileges.
ACTUAL RESULTS
TASK [test_mysql_user : Test idempotency when nothing has changed and we're still granting ALL privileges] ***
task path: /root/ansible_collections/community/mysql/tests/output/.tmp/integration/test_mysql_user-sw27zu6h-ÅÑŚÌβŁÈ/tests/integration/targets/test_mysql_user/tasks/test_grant_all_privileges.yml:33
<testhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<testhost> EXEC /bin/sh -c 'echo ~root && sleep 0'
<testhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp `"&& mkdir "` echo /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436 `" && echo ansible-tmp-1609109000.0398564-8365-196033537627436="` echo /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436 `" ) && sleep 0'
Using module file /root/ansible_collections/community/mysql/plugins/modules/mysql_user.py
<testhost> PUT /root/.ansible/tmp/ansible-local-101glv7bsmi/tmpd7a9ul1t TO /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436/AnsiballZ_mysql_user.py
<testhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436/ /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436/AnsiballZ_mysql_user.py && sleep 0'
<testhost> EXEC /bin/sh -c '/tmp/python-ypi9raas-ansible/python /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436/AnsiballZ_mysql_user.py && sleep 0'
<testhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1609109000.0398564-8365-196033537627436/ > /dev/null 2>&1 && sleep 0'
changed: [testhost] => {
"changed": true,
"invocation": {
"module_args": {
"append_privs": false,
"ca_cert": null,
"check_hostname": null,
"check_implicit_admin": false,
"client_cert": null,
"client_key": null,
"config_file": "/root/.my.cnf",
"connect_timeout": 30,
"encrypted": false,
"host": "localhost",
"host_all": false,
"login_host": "127.0.0.1",
"login_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"login_port": 3307,
"login_unix_socket": null,
"login_user": "root",
"name": "db_user5",
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"plugin": null,
"plugin_auth_string": null,
"plugin_hash_string": null,
"priv": "*.*:ALL",
"resource_limits": null,
"sql_log_bin": true,
"state": "present",
"tls_requires": null,
"update_password": "always",
"user": "db_user5"
}
},
"msg": "Privileges updated",
"user": "db_user5"
}
TASK [test_mysql_user : Assert that there wasn't a change because the user already had ALL privileges] ***
task path: /root/ansible_collections/community/mysql/tests/output/.tmp/integration/test_mysql_user-sw27zu6h-ÅÑŚÌβŁÈ/tests/integration/targets/test_mysql_user/tasks/test_grant_all_privileges.yml:42
fatal: [testhost]: FAILED! => {
"assertion": "result.changed == false",
"changed": false,
"evaluated_to": false,
"msg": "Assertion failed"
}