1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

mysql_db: add check_implicit_admin parameter (#486)

* mysql_db: add check_implicit_admin parameter

* add CI tests

* add changelog fragment

* fix
This commit is contained in:
Andrew Klychkov 2020-06-10 12:46:44 +03:00 committed by GitHub
parent 5552c6e94f
commit e47da0f512
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 21 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- mysql_db - add the ``check_implicit_admin`` parameter (https://github.com/ansible/ansible/issues/24418).

View file

@ -129,6 +129,12 @@ options:
- If this behavior is undesirable, use C(yes) to read only named option file. - If this behavior is undesirable, use C(yes) to read only named option file.
type: bool type: bool
default: no default: no
check_implicit_admin:
description:
- Check if mysql allows login as root/nopassword before trying supplied credentials.
- If success, passed I(login_user)/I(login_password) will be ignored.
type: bool
default: no
seealso: seealso:
- module: mysql_info - module: mysql_info
@ -259,6 +265,14 @@ EXAMPLES = r'''
name: foo name: foo
target: /tmp/dump.sql target: /tmp/dump.sql
dump_extra_args: --skip-triggers dump_extra_args: --skip-triggers
- name: Try to create database as root/nopassword first. If not allowed, pass the credentials
mysql_db:
check_implicit_admin: yes
login_user: bob
login_password: 123456
name: bobdata
state: present
''' '''
RETURN = r''' RETURN = r'''
@ -317,7 +331,8 @@ def db_dump(module, host, user, password, db_name, target, all_databases, port,
config_file, socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None, config_file, socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None,
single_transaction=None, quick=None, ignore_tables=None, hex_blob=None, single_transaction=None, quick=None, ignore_tables=None, hex_blob=None,
encoding=None, force=False, master_data=0, skip_lock_tables=False, encoding=None, force=False, master_data=0, skip_lock_tables=False,
dump_extra_args=None, unsafe_password=False, restrict_config_file=False): dump_extra_args=None, unsafe_password=False, restrict_config_file=False,
check_implicit_admin=False):
cmd = module.get_bin_path('mysqldump', True) cmd = module.get_bin_path('mysqldump', True)
# If defined, mysqldump demands --defaults-extra-file be the first option # If defined, mysqldump demands --defaults-extra-file be the first option
if config_file: if config_file:
@ -325,13 +340,19 @@ def db_dump(module, host, user, password, db_name, target, all_databases, port,
cmd += " --defaults-file=%s" % shlex_quote(config_file) cmd += " --defaults-file=%s" % shlex_quote(config_file)
else: else:
cmd += " --defaults-extra-file=%s" % shlex_quote(config_file) cmd += " --defaults-extra-file=%s" % shlex_quote(config_file)
if user is not None:
cmd += " --user=%s" % shlex_quote(user) if check_implicit_admin:
if password is not None: cmd += " --user=root --password=''"
if not unsafe_password: else:
cmd += " --password=%s" % shlex_quote(password) if user is not None:
else: cmd += " --user=%s" % shlex_quote(user)
cmd += " --password=%s" % password
if password is not None:
if not unsafe_password:
cmd += " --password=%s" % shlex_quote(password)
else:
cmd += " --password=%s" % password
if ssl_cert is not None: if ssl_cert is not None:
cmd += " --ssl-cert=%s" % shlex_quote(ssl_cert) cmd += " --ssl-cert=%s" % shlex_quote(ssl_cert)
if ssl_key is not None: if ssl_key is not None:
@ -390,7 +411,8 @@ def db_dump(module, host, user, password, db_name, target, all_databases, port,
def db_import(module, host, user, password, db_name, target, all_databases, port, config_file, def db_import(module, host, user, password, db_name, target, all_databases, port, config_file,
socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None, encoding=None, force=False, socket=None, ssl_cert=None, ssl_key=None, ssl_ca=None, encoding=None, force=False,
use_shell=False, unsafe_password=False, restrict_config_file=False): use_shell=False, unsafe_password=False, restrict_config_file=False,
check_implicit_admin=False):
if not os.path.exists(target): if not os.path.exists(target):
return module.fail_json(msg="target %s does not exist on the host" % target) return module.fail_json(msg="target %s does not exist on the host" % target)
@ -401,13 +423,19 @@ def db_import(module, host, user, password, db_name, target, all_databases, port
cmd.append("--defaults-file=%s" % shlex_quote(config_file)) cmd.append("--defaults-file=%s" % shlex_quote(config_file))
else: else:
cmd.append("--defaults-extra-file=%s" % shlex_quote(config_file)) cmd.append("--defaults-extra-file=%s" % shlex_quote(config_file))
if user:
cmd.append("--user=%s" % shlex_quote(user)) if check_implicit_admin:
if password: cmd += " --user=root --password=''"
if not unsafe_password: else:
cmd.append("--password=%s" % shlex_quote(password)) if user:
else: cmd.append("--user=%s" % shlex_quote(user))
cmd.append("--password=%s" % password)
if password:
if not unsafe_password:
cmd.append("--password=%s" % shlex_quote(password))
else:
cmd.append("--password=%s" % password)
if ssl_cert is not None: if ssl_cert is not None:
cmd.append("--ssl-cert=%s" % shlex_quote(ssl_cert)) cmd.append("--ssl-cert=%s" % shlex_quote(ssl_cert))
if ssl_key is not None: if ssl_key is not None:
@ -524,6 +552,7 @@ def main():
use_shell=dict(type='bool', default=False), use_shell=dict(type='bool', default=False),
unsafe_login_password=dict(type='bool', default=False), unsafe_login_password=dict(type='bool', default=False),
restrict_config_file=dict(type='bool', default=False), restrict_config_file=dict(type='bool', default=False),
check_implicit_admin=dict(type='bool', default=False),
), ),
supports_check_mode=True, supports_check_mode=True,
) )
@ -566,6 +595,7 @@ def main():
dump_extra_args = module.params["dump_extra_args"] dump_extra_args = module.params["dump_extra_args"]
use_shell = module.params["use_shell"] use_shell = module.params["use_shell"]
restrict_config_file = module.params["restrict_config_file"] restrict_config_file = module.params["restrict_config_file"]
check_implicit_admin = module.params['check_implicit_admin']
if len(db) > 1 and state == 'import': if len(db) > 1 and state == 'import':
module.fail_json(msg="Multiple databases are not supported with state=import") module.fail_json(msg="Multiple databases are not supported with state=import")
@ -581,8 +611,18 @@ def main():
if db == ['all']: if db == ['all']:
module.fail_json(msg="name is not allowed to equal 'all' unless state equals import, or dump.") module.fail_json(msg="name is not allowed to equal 'all' unless state equals import, or dump.")
try: try:
cursor, db_conn = mysql_connect(module, login_user, login_password, config_file, ssl_cert, ssl_key, ssl_ca, cursor = None
connect_timeout=connect_timeout) if check_implicit_admin:
try:
cursor, db_conn = mysql_connect(module, 'root', '', config_file, ssl_cert, ssl_key, ssl_ca,
connect_timeout=connect_timeout)
except Exception as e:
check_implicit_admin = False
pass
if not cursor:
cursor, db_conn = mysql_connect(module, login_user, login_password, config_file, ssl_cert, ssl_key, ssl_ca,
connect_timeout=connect_timeout)
except Exception as e: except Exception as e:
if os.path.exists(config_file): if os.path.exists(config_file):
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. " module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. "
@ -633,7 +673,8 @@ def main():
login_port, config_file, socket, ssl_cert, ssl_key, login_port, config_file, socket, ssl_cert, ssl_key,
ssl_ca, single_transaction, quick, ignore_tables, ssl_ca, single_transaction, quick, ignore_tables,
hex_blob, encoding, force, master_data, skip_lock_tables, hex_blob, encoding, force, master_data, skip_lock_tables,
dump_extra_args, unsafe_login_password, restrict_config_file) dump_extra_args, unsafe_login_password, restrict_config_file,
check_implicit_admin)
if rc != 0: if rc != 0:
module.fail_json(msg="%s" % stderr) module.fail_json(msg="%s" % stderr)
module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout, module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout,
@ -653,7 +694,7 @@ def main():
login_port, config_file, login_port, config_file,
socket, ssl_cert, ssl_key, ssl_ca, socket, ssl_cert, ssl_key, ssl_ca,
encoding, force, use_shell, unsafe_login_password, encoding, force, use_shell, unsafe_login_password,
restrict_config_file) restrict_config_file, check_implicit_admin)
if rc != 0: if rc != 0:
module.fail_json(msg="%s" % stderr) module.fail_json(msg="%s" % stderr)
module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout, module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout,

View file

@ -41,12 +41,14 @@
mysql_db: mysql_db:
name: '{{ db_name }}' name: '{{ db_name }}'
state: present state: present
check_implicit_admin: yes
login_unix_socket: '{{ mysql_socket }}' login_unix_socket: '{{ mysql_socket }}'
- name: create database - name: create database
mysql_db: mysql_db:
name: '{{ db_name2 }}' name: '{{ db_name2 }}'
state: present state: present
check_implicit_admin: no
login_unix_socket: '{{ mysql_socket }}' login_unix_socket: '{{ mysql_socket }}'
- name: state dump/import - create table department - name: state dump/import - create table department
@ -87,6 +89,7 @@
dump_extra_args: --skip-triggers dump_extra_args: --skip-triggers
config_file: '{{ config_file }}' config_file: '{{ config_file }}'
restrict_config_file: yes restrict_config_file: yes
check_implicit_admin: no
register: result register: result
- name: assert successful completion of dump operation - name: assert successful completion of dump operation
@ -104,12 +107,14 @@
state: dump state: dump
target: "{{ dump_file1 }}" target: "{{ dump_file1 }}"
login_unix_socket: '{{ mysql_socket }}' login_unix_socket: '{{ mysql_socket }}'
check_implicit_admin: yes
register: dump_result1 register: dump_result1
- name: assert successful completion of dump operation (with multiple databases in comma separated form) - name: assert successful completion of dump operation (with multiple databases in comma separated form)
assert: assert:
that: that:
- "dump_result1.changed == true" - dump_result1 is changed
- dump_result1.executed_commands[0] is search(" --user=root --password=''")
- name: state dump - dump file1 should exist - name: state dump - dump file1 should exist
file: name={{ dump_file1 }} state=file file: name={{ dump_file1 }} state=file