mysql_variables: add mode parameter (#63547)
* mysql_variables: add mode parameter * mysql_variables: add mode parameter, add changelog fragment * mysql_variables: add mode parameter, fix * mysql_variables: add mode parameter, fix * mysql_variables: add mode parameter, fix * mysql_variables: add mode parameter, fix sanity * mysql_variables: add mode parameter, remove warns * mysql_variables: add mode parameter, refactoring * mysql_variables: add mode parameter, fix logic
This commit is contained in:
parent
42b290b781
commit
73526b9d65
3 changed files with 179 additions and 19 deletions
|
@ -0,0 +1,2 @@
|
||||||
|
minor_changes:
|
||||||
|
- mysql_variables - add ``mode`` parameter (https://github.com/ansible/ansible/issues/60119).
|
|
@ -19,7 +19,7 @@ module: mysql_variables
|
||||||
short_description: Manage MySQL global variables
|
short_description: Manage MySQL global variables
|
||||||
description:
|
description:
|
||||||
- Query / Set MySQL variables.
|
- Query / Set MySQL variables.
|
||||||
version_added: 1.3
|
version_added: '1.3'
|
||||||
author:
|
author:
|
||||||
- Balazs Pocze (@banyek)
|
- Balazs Pocze (@banyek)
|
||||||
options:
|
options:
|
||||||
|
@ -32,6 +32,22 @@ options:
|
||||||
description:
|
description:
|
||||||
- If set, then sets variable value to this
|
- If set, then sets variable value to this
|
||||||
type: str
|
type: str
|
||||||
|
mode:
|
||||||
|
description:
|
||||||
|
- C(global) assigns C(value) to a global system variable which will be changed at runtime
|
||||||
|
but won't persist across server restarts.
|
||||||
|
- C(persist) assigns C(value) to a global system variable and persists it to
|
||||||
|
the mysqld-auto.cnf option file in the data directory
|
||||||
|
(the variable will survive service restarts).
|
||||||
|
- C(persist_only) persists C(value) to the mysqld-auto.cnf option file in the data directory
|
||||||
|
but without setting the global variable runtime value
|
||||||
|
(the value will be changed after the next service restart).
|
||||||
|
- Supported by MySQL 8.0 or later.
|
||||||
|
- For more information see U(https://dev.mysql.com/doc/refman/8.0/en/set-variable.html).
|
||||||
|
type: str
|
||||||
|
choices: ['global', 'persist', 'persist_only']
|
||||||
|
default: global
|
||||||
|
version_added: '2.10'
|
||||||
|
|
||||||
seealso:
|
seealso:
|
||||||
- module: mysql_info
|
- module: mysql_info
|
||||||
|
@ -48,10 +64,11 @@ EXAMPLES = r'''
|
||||||
mysql_variables:
|
mysql_variables:
|
||||||
variable: sync_binlog
|
variable: sync_binlog
|
||||||
|
|
||||||
- name: Set read_only variable to 1
|
- name: Set read_only variable to 1 persistently
|
||||||
mysql_variables:
|
mysql_variables:
|
||||||
variable: read_only
|
variable: read_only
|
||||||
value: 1
|
value: 1
|
||||||
|
mode: persist
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = r'''
|
RETURN = r'''
|
||||||
|
@ -75,6 +92,24 @@ from ansible.module_utils._text import to_native
|
||||||
executed_queries = []
|
executed_queries = []
|
||||||
|
|
||||||
|
|
||||||
|
def check_mysqld_auto(module, cursor, mysqlvar):
|
||||||
|
"""Check variable's value in mysqld-auto.cnf."""
|
||||||
|
query = ("SELECT VARIABLE_VALUE "
|
||||||
|
"FROM performance_schema.persisted_variables "
|
||||||
|
"WHERE VARIABLE_NAME = %s")
|
||||||
|
try:
|
||||||
|
cursor.execute(query, (mysqlvar,))
|
||||||
|
res = cursor.fetchone()
|
||||||
|
except Exception as e:
|
||||||
|
if "Table 'performance_schema.persisted_variables' doesn't exist" in str(e):
|
||||||
|
module.fail_json(msg='Server version must be 8.0 or greater.')
|
||||||
|
|
||||||
|
if res:
|
||||||
|
return res[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def typedvalue(value):
|
def typedvalue(value):
|
||||||
"""
|
"""
|
||||||
Convert value to number whenever possible, return same value
|
Convert value to number whenever possible, return same value
|
||||||
|
@ -110,7 +145,7 @@ def getvariable(cursor, mysqlvar):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def setvariable(cursor, mysqlvar, value):
|
def setvariable(cursor, mysqlvar, value, mode='global'):
|
||||||
""" Set a global mysql variable to a given value
|
""" Set a global mysql variable to a given value
|
||||||
|
|
||||||
The DB driver will handle quoting of the given value based on its
|
The DB driver will handle quoting of the given value based on its
|
||||||
|
@ -118,7 +153,13 @@ def setvariable(cursor, mysqlvar, value):
|
||||||
should be passed as numeric literals.
|
should be passed as numeric literals.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
query = "SET GLOBAL %s = " % mysql_quote_identifier(mysqlvar, 'vars')
|
if mode == 'persist':
|
||||||
|
query = "SET PERSIST %s = " % mysql_quote_identifier(mysqlvar, 'vars')
|
||||||
|
elif mode == 'global':
|
||||||
|
query = "SET GLOBAL %s = " % mysql_quote_identifier(mysqlvar, 'vars')
|
||||||
|
elif mode == 'persist_only':
|
||||||
|
query = "SET PERSIST_ONLY %s = " % mysql_quote_identifier(mysqlvar, 'vars')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursor.execute(query + "%s", (value,))
|
cursor.execute(query + "%s", (value,))
|
||||||
executed_queries.append(query + "%s" % value)
|
executed_queries.append(query + "%s" % value)
|
||||||
|
@ -126,6 +167,7 @@ def setvariable(cursor, mysqlvar, value):
|
||||||
result = True
|
result = True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
result = to_native(e)
|
result = to_native(e)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,6 +186,7 @@ def main():
|
||||||
ca_cert=dict(type='path', aliases=['ssl_ca']),
|
ca_cert=dict(type='path', aliases=['ssl_ca']),
|
||||||
connect_timeout=dict(type='int', default=30),
|
connect_timeout=dict(type='int', default=30),
|
||||||
config_file=dict(type='path', default='~/.my.cnf'),
|
config_file=dict(type='path', default='~/.my.cnf'),
|
||||||
|
mode=dict(type='str', choices=['global', 'persist', 'persist_only'], default='global'),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
user = module.params["login_user"]
|
user = module.params["login_user"]
|
||||||
|
@ -157,6 +200,8 @@ def main():
|
||||||
|
|
||||||
mysqlvar = module.params["variable"]
|
mysqlvar = module.params["variable"]
|
||||||
value = module.params["value"]
|
value = module.params["value"]
|
||||||
|
mode = module.params["mode"]
|
||||||
|
|
||||||
if mysqlvar is None:
|
if mysqlvar is None:
|
||||||
module.fail_json(msg="Cannot run without variable to operate with")
|
module.fail_json(msg="Cannot run without variable to operate with")
|
||||||
if match('^[0-9a-z_]+$', mysqlvar) is None:
|
if match('^[0-9a-z_]+$', mysqlvar) is None:
|
||||||
|
@ -177,27 +222,54 @@ def main():
|
||||||
else:
|
else:
|
||||||
module.fail_json(msg="unable to find %s. Exception message: %s" % (config_file, to_native(e)))
|
module.fail_json(msg="unable to find %s. Exception message: %s" % (config_file, to_native(e)))
|
||||||
|
|
||||||
|
mysqlvar_val = None
|
||||||
|
var_in_mysqld_auto_cnf = None
|
||||||
|
|
||||||
mysqlvar_val = getvariable(cursor, mysqlvar)
|
mysqlvar_val = getvariable(cursor, mysqlvar)
|
||||||
if mysqlvar_val is None:
|
if mysqlvar_val is None:
|
||||||
module.fail_json(msg="Variable not available \"%s\"" % mysqlvar, changed=False)
|
module.fail_json(msg="Variable not available \"%s\"" % mysqlvar, changed=False)
|
||||||
|
|
||||||
if value is None:
|
if value is None:
|
||||||
module.exit_json(msg=mysqlvar_val)
|
module.exit_json(msg=mysqlvar_val)
|
||||||
else:
|
|
||||||
# Type values before using them
|
|
||||||
value_wanted = typedvalue(value)
|
|
||||||
value_actual = typedvalue(mysqlvar_val)
|
|
||||||
if value_wanted == value_actual:
|
|
||||||
module.exit_json(msg="Variable already set to requested value", changed=False)
|
|
||||||
try:
|
|
||||||
result = setvariable(cursor, mysqlvar, value_wanted)
|
|
||||||
except SQLParseError as e:
|
|
||||||
result = to_native(e)
|
|
||||||
|
|
||||||
if result is True:
|
if mode in ('persist', 'persist_only'):
|
||||||
module.exit_json(msg="Variable change succeeded prev_value=%s" % value_actual,
|
var_in_mysqld_auto_cnf = check_mysqld_auto(module, cursor, mysqlvar)
|
||||||
changed=True, queries=executed_queries)
|
|
||||||
else:
|
if mode == 'persist_only':
|
||||||
module.fail_json(msg=result, changed=False)
|
if var_in_mysqld_auto_cnf is None:
|
||||||
|
mysqlvar_val = False
|
||||||
|
else:
|
||||||
|
mysqlvar_val = var_in_mysqld_auto_cnf
|
||||||
|
|
||||||
|
# Type values before using them
|
||||||
|
value_wanted = typedvalue(value)
|
||||||
|
value_actual = typedvalue(mysqlvar_val)
|
||||||
|
value_in_auto_cnf = None
|
||||||
|
if var_in_mysqld_auto_cnf is not None:
|
||||||
|
value_in_auto_cnf = typedvalue(var_in_mysqld_auto_cnf)
|
||||||
|
|
||||||
|
if value_wanted == value_actual and mode in ('global', 'persist'):
|
||||||
|
if mode == 'persist' and value_wanted == value_in_auto_cnf:
|
||||||
|
module.exit_json(msg="Variable is already set to requested value globally"
|
||||||
|
"and stored into mysqld-auto.cnf file.", changed=False)
|
||||||
|
|
||||||
|
elif mode == 'global':
|
||||||
|
module.exit_json(msg="Variable is already set to requested value.", changed=False)
|
||||||
|
|
||||||
|
if mode == 'persist_only' and value_wanted == value_in_auto_cnf:
|
||||||
|
module.exit_json(msg="Variable is already stored into mysqld-auto.cnf "
|
||||||
|
"with requested value.", changed=False)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = setvariable(cursor, mysqlvar, value_wanted, mode)
|
||||||
|
except SQLParseError as e:
|
||||||
|
result = to_native(e)
|
||||||
|
|
||||||
|
if result is True:
|
||||||
|
module.exit_json(msg="Variable change succeeded prev_value=%s" % value_actual,
|
||||||
|
changed=True, queries=executed_queries)
|
||||||
|
else:
|
||||||
|
module.fail_json(msg=result, changed=False)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -308,3 +308,89 @@
|
||||||
login_unix_socket: '{{ mysql_socket }}'
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
login_user: root
|
login_user: root
|
||||||
login_password: '{{ root_pass }}'
|
login_password: '{{ root_pass }}'
|
||||||
|
|
||||||
|
#=========================================
|
||||||
|
# Check mode 'persist' and 'persist_only':
|
||||||
|
#
|
||||||
|
- name: update mysql variable value (expect changed=true) in persist mode
|
||||||
|
mysql_variables:
|
||||||
|
variable: '{{ set_name }}'
|
||||||
|
value: '{{ set_value }}'
|
||||||
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
|
login_user: root
|
||||||
|
login_password: '{{ root_pass }}'
|
||||||
|
mode: persist
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result.queries == ["SET PERSIST `{{ set_name }}` = {{ set_value }}"]
|
||||||
|
|
||||||
|
- include: assert_var.yml changed=true output={{result}} var_name={{set_name}} var_value='{{set_value}}'
|
||||||
|
|
||||||
|
- name: try to update mysql variable value (expect changed=false) in persist mode again
|
||||||
|
mysql_variables:
|
||||||
|
variable: '{{ set_name }}'
|
||||||
|
value: '{{ set_value }}'
|
||||||
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
|
login_user: root
|
||||||
|
login_password: '{{ root_pass }}'
|
||||||
|
mode: persist
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- include: assert_var.yml changed=false output={{result}} var_name={{set_name}} var_value='{{set_value}}'
|
||||||
|
|
||||||
|
- name: set mysql variable to a temp value
|
||||||
|
mysql_variables:
|
||||||
|
variable: '{{ set_name }}'
|
||||||
|
value: '200'
|
||||||
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
|
login_user: root
|
||||||
|
login_password: '{{ root_pass }}'
|
||||||
|
mode: persist
|
||||||
|
|
||||||
|
- name: update mysql variable value (expect changed=true) in persist_only mode
|
||||||
|
mysql_variables:
|
||||||
|
variable: '{{ set_name }}'
|
||||||
|
value: '{{ set_value }}'
|
||||||
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
|
login_user: root
|
||||||
|
login_password: '{{ root_pass }}'
|
||||||
|
mode: persist_only
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.queries == ["SET PERSIST_ONLY `{{ set_name }}` = {{ set_value }}"]
|
||||||
|
|
||||||
|
- name: try to update mysql variable value (expect changed=false) in persist_only mode again
|
||||||
|
mysql_variables:
|
||||||
|
variable: '{{ set_name }}'
|
||||||
|
value: '{{ set_value }}'
|
||||||
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
|
login_user: root
|
||||||
|
login_password: '{{ root_pass }}'
|
||||||
|
mode: persist_only
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
set_name: max_connections
|
||||||
|
set_value: 105
|
||||||
|
def_val: 151
|
||||||
|
|
||||||
|
- name: update mysql variable value (expect changed=true) in persist_only mode
|
||||||
|
mysql_variables:
|
||||||
|
variable: '{{ set_name }}'
|
||||||
|
value: '{{ set_value }}'
|
||||||
|
login_unix_socket: '{{ mysql_socket }}'
|
||||||
|
login_user: root
|
||||||
|
login_password: '{{ root_pass }}'
|
||||||
|
mode: persist_only
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- include: assert_var.yml changed=true output={{result}} var_name={{set_name}} var_value='{{def_val}}'
|
||||||
|
|
Loading…
Reference in a new issue