From 424b33d1f8ef69345cb3727211edce54dc0235c9 Mon Sep 17 00:00:00 2001 From: Maximilian Stinsky Date: Fri, 31 Mar 2023 09:24:54 +0200 Subject: [PATCH] Add MAX_STATEMENT_TIME to resource_limits --- ...-add-max_statement_time_resource-limit.yml | 2 + plugins/module_utils/user.py | 14 ++ plugins/modules/mysql_user.py | 2 +- .../tasks/test_resource_limits.yml | 147 ++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/523-add-max_statement_time_resource-limit.yml diff --git a/changelogs/fragments/523-add-max_statement_time_resource-limit.yml b/changelogs/fragments/523-add-max_statement_time_resource-limit.yml new file mode 100644 index 0000000..b42d63c --- /dev/null +++ b/changelogs/fragments/523-add-max_statement_time_resource-limit.yml @@ -0,0 +1,2 @@ +minor_changes: + - mysql_user - add ``MAX_STATEMENT_TIME`` support for mariadb to the ``resource_limits`` argument (https://github.com/ansible-collections/community.mysql/issues/211). diff --git a/plugins/module_utils/user.py b/plugins/module_utils/user.py index fc4c40e..7f3054d 100644 --- a/plugins/module_utils/user.py +++ b/plugins/module_utils/user.py @@ -808,6 +808,15 @@ def get_resource_limits(cursor, user, host): 'MAX_CONNECTIONS_PER_HOUR': res[2], 'MAX_USER_CONNECTIONS': res[3], } + + cursor.execute("SELECT VERSION()") + if 'mariadb' in cursor.fetchone()[0].lower(): + query = ('SELECT max_statement_time AS MAX_STATEMENT_TIME ' + 'FROM mysql.user WHERE User = %s AND Host = %s') + cursor.execute(query, (user, host)) + res_max_statement_time = cursor.fetchone() + current_limits['MAX_STATEMENT_TIME'] = res_max_statement_time[0] + return current_limits @@ -864,6 +873,11 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode): module.fail_json(msg="The server version does not match the requirements " "for resource_limits parameter. See module's documentation.") + cursor.execute("SELECT VERSION()") + if 'mariadb' not in cursor.fetchone()[0].lower(): + if 'MAX_STATEMENT_TIME' in resource_limits: + module.fail_json(msg="MAX_STATEMENT_TIME resource limit is only supported by MariaDB.") + current_limits = get_resource_limits(cursor, user, host) needs_to_change = match_resource_limits(module, current_limits, resource_limits) diff --git a/plugins/modules/mysql_user.py b/plugins/modules/mysql_user.py index e1808c8..e87fe12 100644 --- a/plugins/modules/mysql_user.py +++ b/plugins/modules/mysql_user.py @@ -145,7 +145,7 @@ options: description: - Limit the user for certain server resources. Provided since MySQL 5.6 / MariaDB 10.2. - "Available options are C(MAX_QUERIES_PER_HOUR: num), C(MAX_UPDATES_PER_HOUR: num), - C(MAX_CONNECTIONS_PER_HOUR: num), C(MAX_USER_CONNECTIONS: num)." + C(MAX_CONNECTIONS_PER_HOUR: num), C(MAX_USER_CONNECTIONS: num), C(MAX_STATEMENT_TIME: num) (supported only for MariaDB since collection version 3.7.0)." - Used when I(state=present), ignored otherwise. type: dict version_added: '0.1.0' diff --git a/tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml b/tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml index 7c2b97b..a390a4e 100644 --- a/tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml +++ b/tests/integration/targets/test_mysql_user/tasks/test_resource_limits.yml @@ -129,4 +129,151 @@ that: - result.rowcount[0] == 1 + - name: Resource limits | Drop mysql user {{ user_name_1 }} if exists + community.mysql.mysql_user: + <<: *mysql_params + name: '{{ user_name_1 }}' + host_all: true + state: absent + + - name: Resource limits | Create mysql user {{ user_name_1 }} with MAX_STATEMENT_TIME in check_mode + community.mysql.mysql_user: + <<: *mysql_params + name: '{{ user_name_1 }}' + password: '{{ user_password_1 }}' + state: present + resource_limits: + MAX_QUERIES_PER_HOUR: 10 + MAX_STATEMENT_TIME: 1 + check_mode: true + register: result + ignore_errors: true + + - name: Resource limits | Assert that create user with MAX_STATEMENT_TIME is changed for mariadb + ansible.builtin.assert: + that: + - result is changed + when: db_engine == 'mariadb' + + - name: Resource limits | Assert that create user with MAX_STATEMENT_TIME is failed for mysql + ansible.builtin.assert: + that: + - result is failed + when: db_engine == 'mysql' + + - name: Resource limits | Create mysql user {{ user_name_1 }} with MAX_STATEMENT_TIME in actual mode + community.mysql.mysql_user: + <<: *mysql_params + name: '{{ user_name_1 }}' + password: '{{ user_password_1 }}' + state: present + resource_limits: + MAX_QUERIES_PER_HOUR: 10 + MAX_STATEMENT_TIME: 1 + register: result + ignore_errors: true + + - name: Resource limits | Assert that create user with MAX_STATEMENT_TIME is changed for MariaDB + ansible.builtin.assert: + that: + - result is changed + when: db_engine == 'mariadb' + + - name: Resource limits | Assert that create user with MAX_STATEMENT_TIME is failed for MySQL + ansible.builtin.assert: + that: + - result is failed + when: db_engine == 'mysql' + + - name: Resource limits | Retrieve user with MAX_STATEMENT_TIME + community.mysql.mysql_query: + <<: *mysql_params + query: > + SELECT User FROM mysql.user + WHERE User = '{{ user_name_1 }}' + AND Host = 'localhost' + AND max_questions = 10 + AND max_statement_time = 1 + register: result + when: db_engine == 'mariadb' + + - name: Resource limits | Assert that rowcount is 1 with MAX_STATEMENT_TIME + ansible.builtin.assert: + that: + - result.rowcount[0] == 1 + when: db_engine == 'mariadb' + + - name: Resource limits | Try to set the same limits with MAX_STATEMENT_TIME again in check mode + community.mysql.mysql_user: + <<: *mysql_params + name: '{{ user_name_1 }}' + password: '{{ user_password_1 }}' + state: present + resource_limits: + MAX_QUERIES_PER_HOUR: 10 + MAX_STATEMENT_TIME: 1 + check_mode: true + register: result + when: db_engine == 'mariadb' + + - name: Resource limits | Assert that set same limits with MAX_STATEMENT_TIME again is not changed + ansible.builtin.assert: + that: + - result is not changed + when: db_engine == 'mariadb' + + - name: Resource limits | Try to set the same limits with MAX_STATEMENT_TIME again in actual mode + community.mysql.mysql_user: + <<: *mysql_params + name: '{{ user_name_1 }}' + password: '{{ user_password_1 }}' + state: present + resource_limits: + MAX_QUERIES_PER_HOUR: 10 + MAX_STATEMENT_TIME: 1 + register: result + when: db_engine == 'mariadb' + + - name: Resource limits | Assert that set same limits with MAX_STATEMENT_TIME again in actual mode is not changed + ansible.builtin.assert: + that: + - result is not changed + when: db_engine == 'mariadb' + + - name: Resource limits | Change limits with MAX_STATEMENT_TIME + community.mysql.mysql_user: + <<: *mysql_params + name: '{{ user_name_1 }}' + password: '{{ user_password_1 }}' + state: present + resource_limits: + MAX_QUERIES_PER_HOUR: 5 + MAX_STATEMENT_TIME: 2 + register: result + when: db_engine == 'mariadb' + + - name: Resource limits | Assert limits with MAX_STATEMENT_TIME changed + ansible.builtin.assert: + that: + - result is changed + when: db_engine == 'mariadb' + + - name: Resource limits | Get user limits with MAX_STATEMENT_TIME + community.mysql.mysql_query: + <<: *mysql_params + query: > + SELECT User FROM mysql.user + WHERE User = '{{ user_name_1 }}' + AND Host = 'localhost' + AND max_questions = 5 + AND max_statement_time = 2 + register: result + when: db_engine == 'mariadb' + + - name: Resource limits | Assert limit with MAX_STATEMENT_TIME row count + ansible.builtin.assert: + that: + - result.rowcount[0] == 1 + when: db_engine == 'mariadb' + when: (ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18') or (ansible_distribution == 'CentOS' and ansible_distribution_major_version >= '8')