From 8d6192d61e15c134b8ec1747358d66f907487291 Mon Sep 17 00:00:00 2001 From: Netmonk Date: Wed, 27 Nov 2019 11:41:55 +0100 Subject: [PATCH] =?UTF-8?q?adding=20encoding=20dump/import=20support=20for?= =?UTF-8?q?=20the=20mysql=5Fdb=20module,=20with=20upd=E2=80=A6=20(#65228)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adding encoding dump/import support for the mysql_db module, with updated documentation, and full test suite * fixing lint issue test #3 * fixing lint issue test #1 * fixing lint issue test #1 second time * Improving Test to be re-entrant * improving test to not fail on centos/6 * Update test/integration/targets/mysql_db/tasks/encoding_dump_import.yml Comminting suggestion Co-Authored-By: Benjamin MALYNOVYTCH * Update test/integration/targets/mysql_db/tasks/encoding_dump_import.yml comminting suggestion Co-Authored-By: Benjamin MALYNOVYTCH * adding comment Adding comment to explain test strategy * Update test/integration/targets/mysql_db/tasks/encoding_dump_import.yml Co-Authored-By: Benjamin MALYNOVYTCH * Update test/integration/targets/mysql_db/tasks/encoding_dump_import.yml Co-Authored-By: Benjamin MALYNOVYTCH * Update test/integration/targets/mysql_db/tasks/encoding_dump_import.yml accepted Co-Authored-By: Andrey Klychkov * Update test/integration/targets/mysql_db/tasks/encoding_dump_import.yml Co-Authored-By: Andrey Klychkov * Update encoding_dump_import.yml * Fixing typoo --- .../modules/database/mysql/mysql_db.py | 27 +++++-- .../targets/mysql_db/defaults/main.yml | 2 + .../mysql_db/tasks/encoding_dump_import.yml | 78 +++++++++++++++++++ .../targets/mysql_db/tasks/main.yml | 8 +- 4 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 test/integration/targets/mysql_db/tasks/encoding_dump_import.yml diff --git a/lib/ansible/modules/database/mysql/mysql_db.py b/lib/ansible/modules/database/mysql/mysql_db.py index 457dcdf36e..ed37b711da 100644 --- a/lib/ansible/modules/database/mysql/mysql_db.py +++ b/lib/ansible/modules/database/mysql/mysql_db.py @@ -40,7 +40,7 @@ options: - Collation mode (sorting). This only applies to new table/databases and does not update existing ones, this is a limitation of MySQL. encoding: description: - - Encoding mode to use, examples include C(utf8) or C(latin1_swedish_ci) + - Encoding mode to use, examples include C(utf8) or C(latin1_swedish_ci), at creation of database, dump or importation of sql script target: description: - Location, on the remote host, of the dump file to read from or write to. Uncompressed SQL @@ -125,10 +125,20 @@ EXAMPLES = r''' name: all target: /tmp/dump.sql -- name: Import file.sql similar to mysql -u -p < hostname.sql +# Import of sql script with encoding option +- name: Import dump.sql with specific latin1 encoding, similar to mysql -u --default-character-set=latin1 -p < dump.sql mysql_db: state: import name: all + encoding: latin1 + target: /tmp/dump.sql + +# Dump of database with encoding option +- name: Dump of Databse with specific latin1 encoding, similar to mysqldump -u --default-character-set=latin1 -p + mysql_db: + state: dump + name: db_1 + encoding: latin1 target: /tmp/dump.sql - name: Delete database with name 'bobdata' @@ -191,7 +201,7 @@ def db_delete(cursor, db): 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, - single_transaction=None, quick=None, ignore_tables=None, hex_blob=None): + single_transaction=None, quick=None, ignore_tables=None, hex_blob=None, encoding=None): cmd = module.get_bin_path('mysqldump', True) # If defined, mysqldump demands --defaults-extra-file be the first option if config_file: @@ -214,6 +224,8 @@ def db_dump(module, host, user, password, db_name, target, all_databases, port, cmd += " --all-databases" else: cmd += " --databases {0} --skip-lock-tables".format(' '.join(db_name)) + if (encoding is not None) and (encoding != ""): + cmd += " --default-character-set=%s" % shlex_quote(encoding) if single_transaction: cmd += " --single-transaction=true" if quick: @@ -241,7 +253,8 @@ def db_dump(module, host, user, password, db_name, target, all_databases, port, return rc, stdout, stderr -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): +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): if not os.path.exists(target): return module.fail_json(msg="target %s does not exist on the host" % target) @@ -264,6 +277,8 @@ def db_import(module, host, user, password, db_name, target, all_databases, port else: cmd.append("--host=%s" % shlex_quote(host)) cmd.append("--port=%i" % port) + if (encoding is not None) and (encoding != ""): + cmd.append("--default-character-set=%s" % shlex_quote(encoding)) if not all_databases: cmd.append("--one-database") cmd.append(shlex_quote(''.join(db_name))) @@ -436,7 +451,7 @@ def main(): rc, stdout, stderr = db_dump(module, login_host, login_user, login_password, db, target, all_databases, login_port, config_file, socket, ssl_cert, ssl_key, - ssl_ca, single_transaction, quick, ignore_tables, hex_blob) + ssl_ca, single_transaction, quick, ignore_tables, hex_blob, encoding) if rc != 0: module.fail_json(msg="%s" % stderr) module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout) @@ -453,7 +468,7 @@ def main(): login_password, db, target, all_databases, login_port, config_file, - socket, ssl_cert, ssl_key, ssl_ca) + socket, ssl_cert, ssl_key, ssl_ca, encoding) if rc != 0: module.fail_json(msg="%s" % stderr) module.exit_json(changed=True, db=db_name, db_list=db, msg=stdout) diff --git a/test/integration/targets/mysql_db/defaults/main.yml b/test/integration/targets/mysql_db/defaults/main.yml index 1b9d338439..764064bcd6 100644 --- a/test/integration/targets/mysql_db/defaults/main.yml +++ b/test/integration/targets/mysql_db/defaults/main.yml @@ -6,3 +6,5 @@ db_user1: 'datauser1' db_user2: 'datauser2' tmp_dir: '/tmp' +db_latin1_name: 'db_latin1' +file4: 'latin1_file' diff --git a/test/integration/targets/mysql_db/tasks/encoding_dump_import.yml b/test/integration/targets/mysql_db/tasks/encoding_dump_import.yml new file mode 100644 index 0000000000..a1bacd1862 --- /dev/null +++ b/test/integration/targets/mysql_db/tasks/encoding_dump_import.yml @@ -0,0 +1,78 @@ +--- + +- set_fact: + latin1_file1="{{tmp_dir}}/{{file}}" + +- name: Deleting Latin1 encoded Database + mysql_db: + name: '{{ db_latin1_name }}' + state: absent + login_unix_socket: '{{ mysql_socket }}' + +- name: create Latin1 encoded database + mysql_db: + name: '{{ db_latin1_name }}' + state: present + encoding: latin1 + login_unix_socket: '{{ mysql_socket }}' + +- name: create a table in Latin1 database + command: mysql {{ db_latin1_name }} -e 'create table testlatin1(id int, name varchar(100));' + + +# Inserting a string in latin1 into table, , this string be tested later, +# so report any change of content in the test too +- name: inserting data into Latin1 database + command: mysql {{ db_latin1_name }} -e "insert into testlatin1 value(47,'Amédée Bôlüt');" + +- name: selecting table + command: mysql {{ db_latin1_name }} -e "select * from testlatin1;" + register: output + +- name: Dumping a table in Latin1 database + mysql_db: + name: "{{ db_latin1_name }}" + encoding: latin1 + target: "{{ latin1_file1 }}" + state: dump + login_unix_socket: '{{ mysql_socket }}' + register: dump_result + +- assert: + that: + - result is changed + +- name: state dump - file name should exist + file: name={{ latin1_file1 }} state=file + +- name: od the file and check of latin1 encoded string is present + shell: grep -a 47 {{ latin1_file1 }} | od -c |grep "A m 351 d 351 e B 364\|A m 303 251 d 303 251 e B 303" + +- name: Dropping {{ db_latin1_name }} database + mysql_db: + name: '{{ db_latin1_name }}' + state: absent + login_unix_socket: '{{ mysql_socket }}' + +- name: Importing the latin1 mysql script + mysql_db: + state: import + encoding: latin1 + name: '{{ db_latin1_name }}' + target: "{{ latin1_file1 }}" + login_unix_socket: '{{ mysql_socket }}' + +- assert: + that: + - result is changed + +- name: check encoding of table + shell: mysql {{ db_latin1_name }} -e "SHOW FULL COLUMNS FROM testlatin1;" + register: output + failed_when: '"latin1_swedish_ci" not in output.stdout' + +- name: remove database + mysql_db: + name: '{{ db_latin1_name }}' + state: absent + login_unix_socket: '{{ mysql_socket }}' diff --git a/test/integration/targets/mysql_db/tasks/main.yml b/test/integration/targets/mysql_db/tasks/main.yml index cd8548a355..bb875a5cfa 100644 --- a/test/integration/targets/mysql_db/tasks/main.yml +++ b/test/integration/targets/mysql_db/tasks/main.yml @@ -238,10 +238,12 @@ assert: { that: "'{{ db_user1 }}' not in result.stdout" } # ============================================================ -- include: state_dump_import.yml format_type=sql file=dbdata.sql format_msg_type=ASCII file2=dump2.sql file3=dump3.sql +- include: state_dump_import.yml format_type=sql file=dbdata.sql format_msg_type=ASCII file2=dump2.sql file3=dump3.sql file4=dump4.sql -- include: state_dump_import.yml format_type=gz file=dbdata.gz format_msg_type=gzip file2=dump2.gz file3=dump3.gz +- include: state_dump_import.yml format_type=gz file=dbdata.gz format_msg_type=gzip file2=dump2.gz file3=dump3.gz file4=dump4.gz -- include: state_dump_import.yml format_type=bz2 file=dbdata.bz2 format_msg_type=bzip2 file2=dump2.bz2 file3=dump3.bz2 +- include: state_dump_import.yml format_type=bz2 file=dbdata.bz2 format_msg_type=bzip2 file2=dump2.bz2 file3=dump3.bz2 file4=dump4.bz2 - include: multi_db_create_delete.yml + +- include: encoding_dump_import.yml file=latin1.sql format_msg_type=ASCII