mirror of
https://github.com/ansible-collections/community.mysql.git
synced 2025-04-09 04:00:32 -07:00
Add default database "mysql" to mysql_user (#266)
* Add default database "mysql" to mysql_user Since permissions are stored in the "mysql" database anyway this should not change the behaviour of the module. But replication / binlog filters which rely on the current database will be able to filter the statements correctly afterwards. Prior to this change they were not executed in any database context and could not be filtered in any way by the existing methods in MySQL. * Added changelog fragment * Update changelogs/fragments/266-default-database-for-mysql-user Thanks! Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * Update mysql_user.py Make the change a configureable boolean * Update 266-default-database-for-mysql-user update changelog fragment * Update 266-default-database-for-mysql-user it´s not a bugfix anymore * Update plugins/modules/mysql_user.py Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * Update plugins/modules/mysql_user.py Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * Update plugins/modules/mysql_user.py Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * Update plugins/modules/mysql_user.py Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * renamed new option to force_context enhanced description added tests * fixed changelog * Update plugins/modules/mysql_user.py Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * Update plugins/modules/mysql_user.py Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * added more tests * removed first test attempts again (from issue-28.yml) created new tests for testing with and without replication * added force_context: no testing * forgot to add the new part to main.yml * found a copy&paste issue * fix include naming * Made sure the tests work in local testing * MariaDB handles online replication filters differently * fix changelog * Update changelogs/fragments/266-default-database-for-mysql-user.yml Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> * Update changelogs/fragments/266-default-database-for-mysql-user.yml Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru> Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
This commit is contained in:
parent
9c575b4762
commit
f5e8fbb3f5
6 changed files with 358 additions and 0 deletions
changelogs/fragments
plugins/modules
tests/integration/targets
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- mysql_user - added the ``force_context`` boolean option to set the default database context for the queries to be the ``mysql`` database. This way replication/binlog filters can catch the statements (https://github.com/ansible-collections/community.mysql/issues/265).
|
|
@ -74,6 +74,19 @@ options:
|
|||
- Whether binary logging should be enabled or disabled for the connection.
|
||||
type: bool
|
||||
default: yes
|
||||
force_context:
|
||||
description:
|
||||
- Sets the С(mysql) system database as context for the executed statements (it will be used
|
||||
as a database to connect to). Useful if you use binlog / replication filters in MySQL as
|
||||
per default the statements can not be caught by a binlog / replication filter, they require
|
||||
a database to be set to work, otherwise the replication can break down.
|
||||
- See U(https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html#option_mysqld_binlog-ignore-db)
|
||||
for a description on how binlog filters work (filtering on the primary).
|
||||
- See U(https://dev.mysql.com/doc/refman/8.0/en/replication-options-replica.html#option_mysqld_replicate-ignore-db)
|
||||
for a description on how replication filters work (filtering on the replica).
|
||||
type: bool
|
||||
default: no
|
||||
version_added: '3.1.0'
|
||||
state:
|
||||
description:
|
||||
- Whether the user should exist.
|
||||
|
@ -341,6 +354,7 @@ def main():
|
|||
plugin_hash_string=dict(default=None, type='str'),
|
||||
plugin_auth_string=dict(default=None, type='str'),
|
||||
resource_limits=dict(type='dict'),
|
||||
force_context=dict(type='bool', default=False),
|
||||
)
|
||||
module = AnsibleModule(
|
||||
argument_spec=argument_spec,
|
||||
|
@ -366,6 +380,8 @@ def main():
|
|||
ssl_ca = module.params["ca_cert"]
|
||||
check_hostname = module.params["check_hostname"]
|
||||
db = ''
|
||||
if module.params["force_context"]:
|
||||
db = 'mysql'
|
||||
sql_log_bin = module.params["sql_log_bin"]
|
||||
plugin = module.params["plugin"]
|
||||
plugin_hash_string = module.params["plugin_hash_string"]
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
- name: alias mysql command to include default options
|
||||
set_fact:
|
||||
mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} --protocol=tcp"
|
||||
|
||||
- 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:
|
||||
|
||||
# start replica so it is available for testing
|
||||
|
||||
- name: Start replica
|
||||
mysql_replication:
|
||||
<<: *mysql_params
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
mode: startreplica
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.queries == ["START SLAVE"] or result.queries == ["START REPLICA"]
|
||||
|
||||
- name: Drop {{ user_name_1 }} if exists
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
state: absent
|
||||
ignore_errors: yes
|
||||
|
||||
# First test
|
||||
# check if user creation works with force_context and is replicated
|
||||
- name: create user with force_context
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: "{{ user_name_1 }}"
|
||||
password: "{{ user_password_1 }}"
|
||||
priv: '*.*:ALL,GRANT'
|
||||
force_context: yes
|
||||
|
||||
- name: attempt connection on replica1 with newly created user (expect success)
|
||||
mysql_replication:
|
||||
mode: getprimary
|
||||
login_user: '{{ user_name_1 }}'
|
||||
login_password: '{{ user_password_1 }}'
|
||||
login_host: 127.0.0.1
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is succeeded
|
||||
|
||||
- name: Drop user
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
state: absent
|
||||
force_context: yes
|
||||
|
||||
- name: attempt connection on replica with freshly removed user (expect failure)
|
||||
mysql_replication:
|
||||
mode: getprimary
|
||||
login_user: '{{ user_name_1 }}'
|
||||
login_password: '{{ user_password_1 }}'
|
||||
login_host: 127.0.0.1
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is failed
|
||||
|
||||
# Prepare replica1 for testing with a replication filter in place
|
||||
# Stop replication, create a filter and restart replication on replica1.
|
||||
- name: Stop replica
|
||||
mysql_replication:
|
||||
<<: *mysql_params
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
mode: stopreplica
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.queries == ["STOP SLAVE"] or result.queries == ["STOP REPLICA"]
|
||||
|
||||
- name: Create replication filter MySQL
|
||||
shell: "echo \"CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB = (mysql);\" | {{ mysql_command }} -P{{ mysql_replica1_port }}"
|
||||
when: install_type == 'mysql'
|
||||
|
||||
- name: Create replication filter MariaDB
|
||||
shell: "echo \"SET GLOBAL replicate_ignore_db = 'mysql';\" | {{ mysql_command }} -P{{ mysql_replica1_port }}"
|
||||
when: install_type == 'mariadb'
|
||||
|
||||
- name: Start replica
|
||||
mysql_replication:
|
||||
<<: *mysql_params
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
mode: startreplica
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.queries == ["START SLAVE"] or result.queries == ["START REPLICA"]
|
||||
|
||||
# Second test
|
||||
# Filter in place, ready to test if user creation is filtered with force_context
|
||||
- name: create user with force_context
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: "{{ user_name_1 }}"
|
||||
password: "{{ user_password_1 }}"
|
||||
priv: '*.*:ALL,GRANT'
|
||||
force_context: yes
|
||||
|
||||
- name: attempt connection on replica with newly created user (expect failure)
|
||||
mysql_replication:
|
||||
mode: getprimary
|
||||
login_user: '{{ user_name_1 }}'
|
||||
login_password: '{{ user_password_1 }}'
|
||||
login_host: 127.0.0.1
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is failed
|
||||
|
||||
- name: Drop user
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
state: absent
|
||||
force_context: yes
|
||||
|
||||
# restore normal replica1 operation
|
||||
# Stop replication and remove the filter
|
||||
- name: Stop replica
|
||||
mysql_replication:
|
||||
<<: *mysql_params
|
||||
login_port: '{{ mysql_replica1_port }}'
|
||||
mode: stopreplica
|
||||
register: result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
- result.queries == ["STOP SLAVE"] or result.queries == ["STOP REPLICA"]
|
||||
|
||||
- name: Remove replication filter MySQL
|
||||
shell: "echo \"CHANGE REPLICATION FILTER REPLICATE_IGNORE_DB = ();\" | {{ mysql_command }} -P{{ mysql_replica1_port }}"
|
||||
when: install_type == 'mysql'
|
||||
|
||||
- name: Remove replication filter MariaDB
|
||||
shell: "echo \"SET GLOBAL replicate_ignore_db = '';\" | {{ mysql_command }} -P{{ mysql_replica1_port }}"
|
||||
when: install_type == 'mariadb'
|
|
@ -9,6 +9,9 @@
|
|||
# Initial CI tests of mysql_replication module:
|
||||
- import_tasks: mysql_replication_initial.yml
|
||||
|
||||
# Tests of replication filters and force_context
|
||||
- include: issue-265.yml
|
||||
|
||||
# Tests of primary_delay parameter:
|
||||
- import_tasks: mysql_replication_primary_delay.yml
|
||||
|
||||
|
|
168
tests/integration/targets/test_mysql_user/tasks/issue-265.yml
Normal file
168
tests/integration/targets/test_mysql_user/tasks/issue-265.yml
Normal file
|
@ -0,0 +1,168 @@
|
|||
---
|
||||
- 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: Drop mysql user if exists
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
state: absent
|
||||
ignore_errors: yes
|
||||
|
||||
# Tests with force_context: yes
|
||||
# Test user creation
|
||||
- name: create mysql user {{user_name_1}}
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
password: '{{ user_password_1 }}'
|
||||
state: present
|
||||
force_context: yes
|
||||
register: result
|
||||
|
||||
- name: assert output message mysql user was created
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{user_name_1}}
|
||||
|
||||
# Test user removal
|
||||
- name: remove mysql user {{user_name_1}}
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{user_name_1}}'
|
||||
password: '{{user_password_1}}'
|
||||
state: absent
|
||||
force_context: yes
|
||||
register: result
|
||||
|
||||
- name: assert output message mysql user was removed
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
# Test blank user removal
|
||||
- name: create blank mysql user to be removed later
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: ""
|
||||
state: present
|
||||
force_context: yes
|
||||
password: 'KJFDY&D*Sfuydsgf'
|
||||
|
||||
- name: remove blank mysql user with hosts=all (expect changed)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
user: ""
|
||||
host_all: true
|
||||
state: absent
|
||||
force_context: yes
|
||||
register: result
|
||||
|
||||
- name: assert changed is true for removing all blank users
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- name: remove blank mysql user with hosts=all (expect ok)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
user: ""
|
||||
host_all: true
|
||||
force_context: yes
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: assert changed is true for removing all blank users
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
- include: assert_no_user.yml user_name={{user_name_1}}
|
||||
|
||||
# Tests with force_context: no
|
||||
# Test user creation
|
||||
- name: Drop mysql user if exists
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
state: absent
|
||||
ignore_errors: yes
|
||||
|
||||
# Tests with force_context: yes
|
||||
# Test user creation
|
||||
- name: create mysql user {{user_name_1}}
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{ user_name_1 }}'
|
||||
password: '{{ user_password_1 }}'
|
||||
state: present
|
||||
force_context: yes
|
||||
register: result
|
||||
|
||||
- name: assert output message mysql user was created
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- include: assert_user.yml user_name={{user_name_1}}
|
||||
|
||||
# Test user removal
|
||||
- name: remove mysql user {{user_name_1}}
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: '{{user_name_1}}'
|
||||
password: '{{user_password_1}}'
|
||||
state: absent
|
||||
force_context: no
|
||||
register: result
|
||||
|
||||
- name: assert output message mysql user was removed
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
# Test blank user removal
|
||||
- name: create blank mysql user to be removed later
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
name: ""
|
||||
state: present
|
||||
force_context: no
|
||||
password: 'KJFDY&D*Sfuydsgf'
|
||||
|
||||
- name: remove blank mysql user with hosts=all (expect changed)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
user: ""
|
||||
host_all: true
|
||||
state: absent
|
||||
force_context: no
|
||||
register: result
|
||||
|
||||
- name: assert changed is true for removing all blank users
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == true"
|
||||
|
||||
- name: remove blank mysql user with hosts=all (expect ok)
|
||||
mysql_user:
|
||||
<<: *mysql_params
|
||||
user: ""
|
||||
host_all: true
|
||||
force_context: no
|
||||
state: absent
|
||||
register: result
|
||||
|
||||
- name: assert changed is true for removing all blank users
|
||||
assert:
|
||||
that:
|
||||
- "result.changed == false"
|
||||
|
||||
- include: assert_no_user.yml user_name={{user_name_1}}
|
|
@ -284,3 +284,7 @@
|
|||
- import_tasks: issue-64560.yaml
|
||||
tags:
|
||||
- issue-64560
|
||||
|
||||
# Test that mysql_user still works with force_context enabled (database set to "mysql")
|
||||
# (https://github.com/ansible-collections/community.mysql/issues/265)
|
||||
- include: issue-265.yml
|
||||
|
|
Loading…
Add table
Reference in a new issue