Compare commits

...

91 commits
main ... 2.4.2

Author SHA1 Message Date
Andrew Klychkov
6e2310d356
Release 2.4.2 commit (#607) 2024-01-22 11:12:34 +01:00
Andrew Klychkov
b894d28957
Version 2.*.* is EOL (#606) 2024-01-22 11:06:33 +01:00
Laurent Indermühle
368c9b4b65
[PR #599/81ab18d backport][stable-2] chore[CI]: fix conditional statements should not include jinja 2 templating (#601)
* chore: fix conditional statements should not include jinja 2 templating (#599)

Thanks to @tompal3 for your contribution

(cherry picked from commit 81ab18d56c)

* fix query for stable-2
2023-11-30 16:41:34 +01:00
patchback[bot]
534a6fa1bc
Document MySQL and MariaDB don't store roles with same manner (#584) (#585)
(cherry picked from commit 0dbedf57cb)

Co-authored-by: Laurent Indermühle <laurent.indermuehle@epfl.ch>
2023-10-27 14:08:30 +02:00
Laurent Indermühle
37b105c526
cut ansible devel from the test matrix (#587) 2023-10-27 13:21:35 +02:00
patchback[bot]
57d9ba03eb
README: Define project's mission statement (#561) (#562)
* README: Define project's mission statement

* Add suggestion

(cherry picked from commit 94392826e1)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2023-07-20 12:30:42 +02:00
patchback[bot]
89d1637c32
Doc Attributes (#555) (#557)
* Added Attributes section

* Added Attributes section

(cherry picked from commit b79fd94d51)

Co-authored-by: Pavel Rabel <128324708+elpavel@users.noreply.github.com>
2023-05-29 11:02:20 +02:00
Laurent Indermühle
bbbd38855b
[stable-2] Revert announcement of EOL (#545)
* docs: revert announcement of EOL for stable-2

stable-2 is still support until 2023-12-01. My bad.
2023-05-17 14:15:00 +02:00
patchback[bot]
aa16129737
MAINTAINERS: add new maintainer (#548) (#550)
(cherry picked from commit bd90ce7cc6)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2023-05-10 15:25:46 +02:00
Laurent Indermühle
fbb22a62f6
Release 2.4.1 commit (#542)
* Release 2.4.1 commit
2023-05-05 12:50:24 +02:00
patchback[bot]
9670218a6a
Fix the Makefile for integration tests not using the Python Venv (#532) (#534)
* Fix venv not being used by keeping the same shell

Also fix "-set -x" command not found.

* Fix missing option in the command usage documentation

* Document connector-version relationship

* Fix missing option in the command usage documentation

* Rephrase commands descriptions

* Document that you need to kill the ansible-test container yourself

(cherry picked from commit 426084a131)

Co-authored-by: Laurent Indermühle <laurent.indermuehle@pm.me>
2023-04-27 13:30:38 +02:00
patchback[bot]
095df1e8af
Added formatting behaviour to documentation (#516) (#524)
* Added formatting behaviour to documentation

* Update plugins/modules/mysql_query.py

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

---------

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 754387c7e5)

Co-authored-by: IBims1NicerTobi <54948543+IBims1NicerTobi@users.noreply.github.com>
2023-03-31 20:25:05 +02:00
patchback[bot]
423a2272aa
Add filter to prevent rebuild container on push on stable-(1|2) (#522) (#526)
(cherry picked from commit 21e42b5777)

Co-authored-by: Laurent Indermühle <laurent.indermuehle@pm.me>
2023-03-31 17:52:56 +02:00
Laurent Indermühle
c30a2e5c99
[PR #514/e2aa655 backport][stable-2] Fix issues and documentation with integration tests after merge of #490 (#521)
* Fix issues and documentation with integration tests after merge of #490. (#514)

* Fix explanation about containers images
* Add definitive URI to the containers images
* Document that new images must be set as public
* Document makefile options possible values
* Document that any mysql and mariadb tag can be use
* Add computation of docker_image path
* Refactor pre-command to separate commands for cleaner GHA output
* Refactor to use GHA test matrix
* Cut docker_image from documentation since it's now automatic
* Document how to use run_all_test.py to display the test matrix

(cherry picked from commit e2aa655762)

* Add changelog fragment
2023-03-30 08:29:21 +02:00
Laurent Indermühle
530e6c3d9c
[PR #490/6970aef backport][stable-2] Integrations tests : Use containers (#519)
* Integrations tests : Use containers for more control and verify that versions match expectation (#490)

* Add healthcheck to MariaDB before starting the tests
This prevent the first test to fail because the db isn't ready yet.

* Add % instead of the default 'localhost' since we use remote connection

Previously, everything was on localhost. Now ansible-test is in a
venv and the db is in a container. The db see the IP address from the
podman host (10.88.0.2)

* Add mysql_client to the controller

* Prepare controller with Podman/Docker Network

We use the Podman/Docker network gateway address to communicate between
container. I haven't tested Docker. I would have preferred to use a pod
but only Podman support it and ansible-test only support the
--docker-network option.

* Generalize mysql and mariadb version based on container name

This way we can split db_engine and db_version and simplify tests.
Also this is mandatory to use the matrix.db_engine_version as the
image name for our services containers.

* Fix replication due to usage of gateway_addr instead of localhost

* Refactor setup_mysql into setup_controller

* Fix server_id in GHA

GHA lack a way to pass option to docker's command. Also server_id is
not read as a environment variable. So I'm forced to use a config file.

* Refactor test_mysql_user to work with other host than localhost

* Refactor way tests info are passed from sed to file with lookup

The idea is to avoid modifying test targets from the workflow to prevent
ansible-test to think every tests needs to be run.

* Refactor test to use the db_version from setup_controller

* Add temporary files to .gitignore

* Add back docker healthcheck on services

I saw in the GHA logs that it perform an healtcheck ! So I hope this
will work.

* Refactor the way server_id is set for replicas

The simple way is to add '--server-id 2' after the name of the image of
the container. But GHA doesn't let us do that. The idea of mount a file
from our repo doesn't work because the repo is check out later in the
workflow and I failed to find a pre-job hook. Then I realized that this
MySQL option is dynamic! So we will set that in the test target!

* Add IF NOT EXISTS to prevent misleading error on retry

* Cut python 3.11 not supported by ansible-test yet

* Add option to run only a single target

* Disable replication with channel tests entirely for MySQL 5.7

* Activate Mysql 8 and Mariadb into GitHub Action Workflow

* Document run_all_tests.py

* Fix replication settings

sh don't know 'echo -e', so we use bash instead.
Also, we need to wait for the container to be healthy before trying to
restart it. Otherwise that could corrupt it.

* Add more descriptive tests names

* Use mysql_host var name instead of gateway_addr in tests

* Refactor user@<gateway ip addr> into user@%

* Workaround for plugin role that fails with any MariaDB versions

* Ensure replicas are healthy before rebooting them

* Add a virtualenv for ansible-test used locally

* Cut column-statistics disabling

Thanks to our test-container, we now use the correspond mysql-client.
So to test mysql 5.7 we use mysql-client-5.7 and to test mysql 8 we
use mysql-client-8.

* Fix test matrix

Python version should be quoted, otherwise 3.10 become 3.1
We can skip 2.14 and devel with Python3.8
We can skip devel with Python 3.9
We can skip MariaDB 10.4 with mysql-client-10.6
Add tests for MariaDB 10.6, 10.7 and 10.8

* Fix queries for roles

* Add filter for issues resolved in newer version of mysqlclient

* Add names to tests

* Cut tests for incompatible MySQL 8 and pymysql 0.7.11

* Fix assertion for older mysqlclient than 2.0.1 with mysql (mariadb ok)

* Change docker-image workflow to work on all images using matrix

* Add support for version of mysqlclient

* Fix verify database version

Sometimes, version_full contains trailing information (-log). To prevent
issues it's best to concatenate major and minor version.

* Cut filter for tests now that the right connector is used

* Add clean up in "always" phase of the block

Because our tests use --retry-on-error, and the first thing the test
does is to try to create the database. We must cleanup otherwise if
there is a retry, it will throw a misleading "database already exists"
error.

* Disable tests using pymysql 1.0.2

Many tests are failing but this must be fixed in the plugins in a future
PR.

* Cut test MySQL 8 with incompatible pymysql 0.7.11

It fails to connect with error about cryptography unsupported

* Fix missing cffi package to connect to MySQL 8 using Python 3.9

* Split Docker image workflow to rebuild only changed Dockerfile

My goal is not to save the planet but to make it work. Currently
docker/setup-buildx-action@v2 often fails. You have to rerun the
workflow multiple times until it succeed. When you do that with the
matrix with 15 containers, you never get to the point where they all
built successfully. Having separate workflows makes rerun the failing
build easier.

* Add option to let containers alive at end of testing

* Migrate tests documentations in their own file

* Document usage of continue_on_errors

* Add support for systems with unsupported python set as default

* Add create podman network for system missing it.

We saw that on a Fedora 33 with Podman 3.3.1, an old system. I didn't
find in which release the default network changed and maybe it's
defined in the Linux distribution. So in doubt I always attempt to
create the network.

* Add full path to image to prevent podman asking which registry to use

* Add options to enforce recreate containers even if already exists

* Add deletion of anonymous volumes associated with the container

* Change shebang from python to python3 to avoid confusion with python2

This script is a python3 script.

* Add disk and RAM requirements

* Cut the 3 from python command to follow shebang recommendations

https://docs.ansible.com/ansible-core/devel/dev_guide/testing/sanity/shebang.html

* Reformat file path

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@futurice.com>

* Move utility task files in their own folder

* Add called workflow file in the GHA hooks

Without this, the containers are not rebuilt when you modify the file
built-docker-image.yml.

* Rollback to github.repository in container image name

This time I think I understood. We publish in the
github.repository_owner's namespace. In my case it's laurent-indermuehle
and in case of upstream it's ansible-collections. A proof of that:
https://github.com/orgs/ansible-collections/packages <- here there is
one attempt I did in february to push my branch to the upstream.
So, our tests containers will be visible to the whole community, not
just community.mysql.

---------

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@futurice.com>
(cherry picked from commit 6970aef8f6)

* Add changelog fragment

* Disable tests that doesn't work on stable-1

It's shameful to disable tests, but they didn't makes much sense
anyway.

* Fix error message being different on stable-1 than v3

* Disable tests against MariaDB 10.5 and 10.6

Does version have never been tested on stable-1 and many tests fails.
2023-03-29 08:56:52 +02:00
patchback[bot]
b02c5b411a
[PR #508/9b8455c2 backport][stable-2] Fix sanity (#509)
* Fix sanity (#508)

* Fix sanity

* Remove as unnecessary

(cherry picked from commit 9b8455c2e6)

* Update tests/unit/plugins/module_utils/test_mysql_user.py

---------

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2023-02-14 14:33:36 +01:00
Markus Bergholz
1243d85f65
prepare community.mysql 2.4.0 (#506)
* prepare 2.3.11

* 2.4.0
2023-02-08 10:34:31 +01:00
patchback[bot]
ff94dcdf0f
[PR #497/a5f3296d backport][stable-2] mysql_info - Add connector_name and connector_version to returned value (#499)
* mysql_info - Add connector_name and connector_version to returned value (#497)

* Add methods to retrieve connector name and version
* Document that mysqlclient is also named MySQLdb
* Document version_added
* Add connector name and version in the returned block
* Cut condition to display any name that is return

In case of MySQLdb is renamed in mysqlclient. In that case, the
integration tests will catch this the day we update the connector
version.

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit a5f3296d73)

* Cut fragment not relevant to the collection usage

* Update version_added for stable-2

---------

Co-authored-by: Laurent Indermühle <laurent.indermuehle@pm.me>
2023-02-01 09:49:13 +01:00
patchback[bot]
b16e57ddbc
README: improve Matrix badge (#494) (#496)
* README: improve Matrix badge

* Add text

(cherry picked from commit 3229ce4e55)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2023-01-26 09:46:19 +01:00
Andrew Klychkov
c9dc6cd4eb
491-CI-fix-tarball-download (#491) (#492)
* Fix mariadb test setup

* Update mysql src URL

* Add changelog fragment

* Update 491_fix_download_url.yaml

Sanity test failed because minor_changes in not an element of a list.

* Fix casing

Co-authored-by: Laurent Indermühle <laurent.indermuehle@pm.me>
(cherry picked from commit 00fa058a18)

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@futurice.com>
2023-01-25 10:57:28 +01:00
patchback[bot]
090cab98a4
README: update Matrix badge (#485) (#486)
(cherry picked from commit 4ad71775a6)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2023-01-16 13:26:39 +01:00
Andrew Klychkov
e4fc4bdf06
Docs: change yes/no to true/false (#480) (#481)
(cherry picked from commit 3ff1fad5f3)
2023-01-03 12:56:27 +01:00
patchback[bot]
335ce76f82
CI: add PR change detection (#473) (#476)
(cherry picked from commit eade7ec1f0)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-12-09 16:48:12 +01:00
patchback[bot]
2b6adcd58a
Add fixed version of Ubuntu (#470) (#472)
This is because ubuntu-latest link to ubuntu-22.04 which includes
cgroup-v2. I thinks our tests fails because of that. See
https://github.com/ansible-collections/news-for-maintainers/issues/28
for more information.

(cherry picked from commit 4dac66382a)

Co-authored-by: Laurent Indermühle <laurent.indermuehle@pm.me>
2022-12-07 16:46:14 +01:00
Laurent Indermühle
8949c68929
Backport/stable 2/pr 452 (#463)
* Sync GHA workflow w/ the collection template (#452)

* Sync GHA workflow w/ the collection template

* Drop the trailing pre-cmd semicolon

* Recover missing `-e` flag of `sed`

* Use relative paths for version configs

* Unquote `env.connector_version_file`

* Use string formatting to fix the substitution problem

(cherry picked from commit 8107530744)

* Backport mysql_version_parts variable assignation

(cherry picked from commit 79046a88cb)

* Add changelog fragment

* Backport flags and variables to differentiate MariaDB from MySQL setup

* Backport issue-28 check for tls support

* Backport tls_requirements simplified and deduplified tests

Co-authored-by: Sviatoslav Sydorenko <wk.cvs.github@sydorenko.org.ua>
2022-11-10 14:57:58 +01:00
patchback[bot]
1f42f39d92
README: Add matrix room + badge (#459) (#461)
* README: Add matrix room + badge

* improve

(cherry picked from commit 09e02320fd)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-11-01 13:28:02 +01:00
patchback[bot]
826e9c7c89
* add socket option suggestion in documentation (#437) (#455)
* * add `socket` option suggestion in documentation

* white space fix

* * move first two at the end

(cherry picked from commit b9a6ec4f7d)

Co-authored-by: Gabriel PREDA <eRadical@users.noreply.github.com>
2022-10-04 14:35:05 +02:00
patchback[bot]
d8a1284e3d
CI: add stable-2.14 to test matrix (#449) (#450)
(cherry picked from commit b8e2c02e89)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-09-23 07:06:07 +02:00
patchback[bot]
b5a0b3aa62
Fix: devel requires python 3.9 in roles CI (#444) (#448)
* Fix: devel requires python 3.9

Package 'ansible-core' requires a different Python: 3.8.13 not in '>=3.9'

* Exclude older version of Ansible when testing Python 3.9

(cherry picked from commit 2cd29207f3)

Co-authored-by: R.Sicart <roger.sicart@gmail.com>
2022-09-16 16:15:40 +02:00
patchback[bot]
b4f03b01ef
Combine REVIEW_CHECKLIST.md and CONTRIBUTING.md and fix links (#432) (#439)
(cherry picked from commit ea73d408c3)

Co-authored-by: Maxwell G <9920591+gotmax23@users.noreply.github.com>
2022-09-06 09:48:43 +02:00
Laurent Indermühle
58b850f217
[PR #427/0a68bb27 backport][stable-2] CI is changed (#429)
* Is changed (#427)

* Refactor tests to use "is" and "is not" changed

* Refactor tests to use is succeeded or is failed

* Reformat indentation

* Add filter "bool" to prevent issues

(cherry picked from commit 0a68bb270f)

* Fix error message verification

I don't know why this works on main, but in stable-1, the error message
is "invalid privileges string: Invalid privileges specified:
frozenset({'INVALID'})"

* Add filter for test that won't work with mariadb

* Add test databases cleanup

* Backport small diff from main
2022-08-29 10:20:13 +02:00
patchback[bot]
4aa166ec13
Docs: add info how to cope with a protocol-related connection error using login_unix_socket argument (#420) (#430)
(cherry picked from commit f1d63e3fc8)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-08-26 13:08:42 +02:00
Laurent Indermühle
8968f51533
Port stable 1 ci changes (#423) (#424)
* Add changes from stable-1 integrations tests (PR 418)

* Refactor to use connectors' info declared in setup_mysql

* Fix 2nd replication stop marked changed by mysqlclient

(cherry picked from commit 61586ae4cc)
2022-08-17 11:30:34 +02:00
patchback[bot]
13a8a4ebff
MAINTAINERS file: add a new maintainer (#419) (#421)
(cherry picked from commit 057f817111)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-08-13 21:37:22 +02:00
patchback[bot]
912995da76
Fix ci python requirements (#416) (#417)
* Add matrix for python and ansible-core versions for sanity tests

* Add python 3.9 to integrations tests

* Add python 3.9 to unit tests

* Reformat sort by python version first

(cherry picked from commit 97318559e5)

Co-authored-by: Laurent Indermühle <laurent.indermuehle@pm.me>
2022-08-09 08:17:00 +02:00
Laurent Indermühle
98d4828e44
Update galaxy.yml to the next expected version (#413) 2022-08-03 10:30:06 +02:00
Laurent Indermühle
b642aedc25
Release 2.3.9 commit (#411) 2022-08-02 10:24:25 +02:00
patchback[bot]
a444d0a356
README: update MariaDB versions we test against (#404) (#405)
(cherry picked from commit 6f87620d9b)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-06-24 15:07:20 +02:00
patchback[bot]
cac58cfa49
Note added regarding the default config file, ~/.my.cnf (#400) (#401)
* Note added for https://github.com/ansible-collections/community.mysql/issues/394

* Update config file notes as discussed

* Update plugins/doc_fragments/mysql.py

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 0df46e0e67)

Co-authored-by: Chris Croome <chris@webarchitects.co.uk>
2022-06-17 08:27:08 +02:00
patchback[bot]
404ffbb3b1
Update licensing information (#390) (#391)
(cherry picked from commit 2a3f8f6506)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-06-03 16:28:20 +02:00
Andrew Klychkov
71c7275fef
Release 2.3.8 commit (#388) 2022-06-02 08:18:36 +02:00
patchback[bot]
9ca52b3aa5
Changed += to append because cmd is a list (#377) (#385)
Using += on a list cause some problems druing creation of mysql command:
/usr/bin/mysql   - - u s e r = r o o t   - - p a s s w o r d = ' ' --socket=/run/mysqld/mysqld.sock

(cherry picked from commit 2e9d50f274)

Co-authored-by: Maciej <moledzki@users.noreply.github.com>
2022-06-01 07:57:56 +02:00
Andrew Klychkov
0a40c13aa8
mysql_user: prevent password getting set for existing users on on_cre… (#342) (#382)
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 51a38840d9)

Co-authored-by: hubiongithub <79990207+hubiongithub@users.noreply.github.com>
2022-05-31 14:32:23 +02:00
patchback[bot]
0011798382
mysql_query: fix false change reports when IF NOT EXISTS clause is used (#322) (#374)
* mysql_query: fix false change reports when IF NOT EXISTS clause is used

* Fix

* Fix doc, add fragment

* Improve doc

(cherry picked from commit 647461010d)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-05-25 19:58:15 +02:00
Andrew Klychkov
46dc308e28
mysql_role - don't add members to a role when creating the role and detach_members true is set (#372)
Co-authored-by: betanummeric <40263343+betanummeric@users.noreply.github.com>
2022-05-25 16:22:39 +02:00
patchback[bot]
e34cfba109
mysql_role: fix and simplify role member detection (#368) (#371)
* mysql_role: fix and simplify role membership detection

* add changelog fragment

* Update changelogs/fragments/368-mysql_role-fix-member-detection.yml

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

Co-authored-by: Felix Hamme <felix.hamme@ionos.com>
Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 07a72865f7)

Co-authored-by: betanummeric <40263343+betanummeric@users.noreply.github.com>
2022-05-25 14:36:08 +02:00
Andrew Klychkov
c02e46e7b0
Release 2.3.7 commit (#362) 2022-05-17 12:15:07 +02:00
Felix Fontein
cf1c95b64d
Add PSF-license.txt file (#356) (#360)
* Add PSF-license.txt file.

* Update with actual CPython 3.9.5 license.

(cherry picked from commit b2e476cb1a)
2022-05-17 08:24:28 +02:00
Andrew Klychkov
65b1773ed0
Release 2.3.6 commit (#354) 2022-05-13 09:16:09 +02:00
Andrew Klychkov
f854fc96db
Drop support for Ansible 2.9 and ansible-base 2.10 (#343) (#348)
* Drop support for Ansible 2.9 and ansible-base 2.10

* Improve README

(cherry picked from commit eff87f952b)
2022-05-12 14:31:07 +02:00
Andrew Klychkov
cc78846f22
mysql_user: fix parsing privs when a user has roles assigned to it (#345) 2022-05-12 14:20:44 +02:00
patchback[bot]
65eb142960
Move CHANGELOG.rst at top level (#349) (#350)
(cherry picked from commit f57ed38beb)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-05-12 11:55:02 +02:00
patchback[bot]
d61d442861
mysql_user: added flush privileges to write dynamic privs into db (#338) (#339)
* added flush privileges to write dynamic privs into db
Fixes https://github.com/ansible-collections/community.mysql/issues/120

* added changelog fragment

* Update changelogs/fragments/338-mysql_user_fix_missing_dynamic_privileges.yml

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>

Co-authored-by: Andrew Klychkov <aaklychkov@mail.ru>
(cherry picked from commit 1dcc5ec086)

Co-authored-by: bigo8525 <53953606+bigo8525@users.noreply.github.com>
2022-04-29 16:29:33 +02:00
patchback[bot]
d38813d418
mysql_role: remove redundant connection closing (fixes #329) (#330) (#332)
* mysql_role: remove redundant connection closing (fixes #329)

* add changelog fragment for pull request #330

Co-authored-by: Felix Hamme <felix.hamme@ionos.com>
(cherry picked from commit 641894e6e8)

Co-authored-by: betanummeric <40263343+betanummeric@users.noreply.github.com>
2022-04-05 11:31:38 +02:00
Andrew Klychkov
9857a16cb5
CI: add testing against ansible-core 2.13 (#327)
Co-authored-by: R.Sicart <roger.sicart@gmail.com>
2022-04-03 08:10:35 +02:00
Andrew Klychkov
2de30ed7cb
[stable-2] Backports (#324)
* Clarified error message about missing python modules (#279)

* Clarified error message about missing python modules, and tweak documentation to suggest overriding interpreter.

* Mention mysqlclient as another option

* Correct mysqlclient suggestions from python2 to python3

Co-authored-by: Matthew Exon <git.mexon@spamgourmet.com>
(cherry picked from commit 82baf7508c)

* Copy ignore-2.13.txt to ignore-2.14.txt (#323)

* Copy ignore-2.13.txt to ignore-2.14.txt

* Fix sanity

(cherry picked from commit c16b2428e8)

Co-authored-by: Matthew Exon <github2.mexon@neverbox.com>
2022-04-02 17:33:46 +02:00
patchback[bot]
74ab876064
mysql_user: clarify behavior of priv parameter (#319) (#321)
(cherry picked from commit 5afae459dc)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-03-25 14:14:44 +01:00
patchback[bot]
203338024f
Fix roles CI (#316) (#317)
(cherry picked from commit e6e661b87f)

Co-authored-by: Andrew Klychkov <aklychko@redhat.com>
2022-03-24 06:54:56 +01:00
patchback[bot]
82cde26b11
Setup patchback bot config file (resolves #310) (#311) (#312)
(cherry picked from commit 55458f5b0b)

Co-authored-by: R.Sicart <roger.sicart@gmail.com>
2022-03-17 09:51:14 +01:00
Andrew Klychkov
66c340e951
Add IF EXISTS clause to DROP USER statement (#307) (#308)
* Add IF EXISTS clause to DROP USER statement

* Add a changelog fragment

* Fix exception

(cherry picked from commit 3a452faeb0)
2022-03-15 15:30:23 +01:00
Andrew Klychkov
fecc9866e3
Release 2.3.5 commit (#303) 2022-03-14 15:17:21 +01:00
Andrew Klychkov
95c649cce2
Fix the collection to work with mysqlclient connector (#301) 2022-03-14 14:41:38 +01:00
Andrew Klychkov
a516c1a6ad
Update requirements (#300) 2022-03-14 12:01:18 +01:00
Andrew Klychkov
fc16243349
Fix role integration tests for mariadb (#299)
Co-authored-by: R.Sicart <roger.sicart@gmail.com>
2022-03-14 11:47:28 +01:00
Andrew Klychkov
cb960ef182
Enable and fix integration tests for devel (#297) 2022-03-14 11:13:17 +01:00
Andrew Klychkov
d7c6bddefa
Release 2.3.4 commit (#288) 2022-02-16 11:24:17 +01:00
Andrew Klychkov
8b2c418538
[stable-2] Backport from main to stable-2 (#287)
* Update CONTRIBUTORS file (#278)

(cherry picked from commit cbdf51234a)

* Honor the set_default_role_all parameter (#282)

The set_default_role_all parameter is documented, but does nothing. This PR fixes this.

(cherry picked from commit f547b66d35)

* Add a changelog fragment to PR 282 (#283)

(cherry picked from commit 952e1666d8)

Co-authored-by: Benoit Garret <benoit.garret_github@gadz.org>
2022-02-16 11:11:55 +01:00
Andrew Klychkov
9d9ea46603
Release 2.3.3 commit (#276) 2022-01-18 11:04:04 +01:00
Andrew Klychkov
9c76f1a566
[stable-2] Use vendored version of distutils.version (#269) (#273)
* Prepare for distutils.version being removed in Python 3.12 (#267)

* Prepare for distutils.version being removed in Python 3.12

* Update plugins/module_utils/version.py

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit d9e12b85ad)

* Use vendored version of distutils.version (#269)

* Use vendored version of distutils.version

* Correct fragment

* Update plugins/module_utils/version.py

Co-authored-by: Felix Fontein <felix@fontein.de>

Co-authored-by: Felix Fontein <felix@fontein.de>
(cherry picked from commit 9c575b4762)
2022-01-18 10:39:22 +01:00
Andrew Klychkov
a2c0bf4f0a
Release 2.3.2 commit (#253) 2021-11-29 15:52:22 +01:00
Andrew Klychkov
7aab5cc04f
Backport of PRs to stable-2 (#251)
* Allow the "%" character in database name (#227)

The naming rules for MySQL/MariaDB identifiers, when quoted, allow the
`%` character.

However, currently, the use of the `%` character in database names
results in mismatch or missing databases.

- Rewrite query to identify the databases in the catalog using
  `information_schema` instead of `SHOW DATABASES LIKE`
- Escape the `%` character in `CREATE DATABASE` query.

Signed-off-by: Nicolas Payart <npayart@gmail.com>
(cherry picked from commit 6b12435b2b)

* mysql_db: Fix assert in tests suite (#239)

Signed-off-by: Nicolas Payart <npayart@gmail.com>
(cherry picked from commit 5522e45284)

* mysql_db: Improve tests (#240)

- Define variables "db_names" and "db_formats" in defaults
- Use of the "vars" option in includes instead of default parameters
  that might be overridden by a previous task
- Use of the "loop" option in includes instead of duplicating include
  tasks
- Use a nested loop on db_names and db_formats in state_dump_import test

Signed-off-by: Nicolas Payart <npayart@gmail.com>
(cherry picked from commit e4de13aabe)

* MAINTAINERS file: Add new maintainer (#248)

(cherry picked from commit d411a8e216)

Co-authored-by: Nicolas PAYART <koleo@users.noreply.github.com>
2021-11-29 11:50:08 +01:00
Andrew Klychkov
1cb39cce0a
Release 2.3.1 commit (#236) 2021-10-19 12:41:22 +02:00
Andrew Klychkov
55a8ecd64e
[stable-2] Backport stable 2 5 (#235)
* Copy ignore-2.12.txt to ignore-2.13.txt (#225)

(cherry picked from commit 4f205ef540)

* CI matrix update (#226)

* CI matrix update

* Fix test_mysql_user

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

(cherry picked from commit fc984b28aa)

* integration tests: remove superfluous debug task (#228)

* integration tests: remove superfluous debug task

* Turn off integration tests against devel

(cherry picked from commit f47d4635f1)

* mysql_user: fix broken compatibility for priviledge aliases (#233)

* mysql_user: fix broken compatibility for priviledge aliases

* add changelog fragment

* fix changelog fragment

* Improve formatting

(cherry picked from commit bb3e9fd3fa)
2021-10-19 12:20:30 +02:00
Andrew Klychkov
a6bacefc41
Release 2.3.0 commit (#220) 2021-09-23 13:39:01 +02:00
Andrew Klychkov
c5676ff0c9
[stable-2] Backport stable 2 4 (#219)
* Fix wrong impl for mysql (#210)

If 'mariadb' in version info, the db instance should be mariadb(reverse in code) rather than mysql.

(cherry picked from commit 663590689f)

* Update README.md (#216)

(cherry picked from commit 4de0e25ea0)

* mysql_user: replace VALID_PRIVS by get_valid_privs() function (#217)

* mysql_user: replace VALID_PRIVS by get_valid_privs() function

* Add EXTRA_PRIVS in case we need to add more privs in the future

* Add changelog fragment

(cherry picked from commit 0ce1fa1634)

Co-authored-by: int32bit <krystism@gmail.com>
Co-authored-by: R.Sicart <roger.sicart@gmail.com>
2021-09-23 12:51:32 +02:00
Andrew Klychkov
0c462c84ff
Release 2.2.0 commit (#218) 2021-09-23 11:32:06 +02:00
Andrew Klychkov
77bd3bfa2e
[stable-2] mysql_info: fix TypeError failure when there are databases that do not contain tables (#205) (#208)
* mysql_info: fix TypeError failure when there are databases that do not contain tables (#205)

* mysql_info: fix TypeError failure when there are databases that do not contain tables

* Add changelog fragment

(cherry picked from commit a1f419d541)

* Fix sanity errors (#206)

(cherry picked from commit 8a17e43eae)
2021-08-20 09:50:41 +02:00
Andrew Klychkov
2508c420ce
Update galaxy.yml after release (#202) 2021-08-11 11:12:34 +02:00
Andrew Klychkov
04c0f9f049
Release 2.2.0-a1 commit (#201) 2021-08-11 10:20:05 +02:00
Andrew Klychkov
a8e2c5290b
mysql_role: new module (#189) (#200)
* mysql_role: new module

* fixes

* fixes

* Add the role class

* Check if role exists

* role.add()

* role.__get_members

* tmp

* tmp

* Change tests

* Fix

* Fix

* add_members()

* get_privs()

* tmp

* __extract_grants() filler version

* Before big work

* tmp

* drop()

* tmp

* tmp

* Big changes

* Fix

* append_members, detach_members, append_privs

* tmp

* admin option

* Add tests

* Add tests

* Fix tests

* Remove debug warning

* Fix tests

* Add documentation

* Fix MariaDB case

* Fix MariaDB

* Fix MariaDB

* Fix MariaDB

* Fix MariaDB

* Fix MariaDB

* Fix

* Fix

* Remove debug warning

* Add try-except block

* tmp

* tmp

* tmp

* Fix

* Add err handling

* Add user check

* Check admin in db

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Fix

* Add mutually exclusive options

* Small refactoring, documenting

* Documenting, refactoring

* Change docs

* Refactoring

* Refactoring

* Refactoring

* Add unit tests

* Update README.md

(cherry picked from commit ce2b269f84)
2021-08-11 09:46:50 +02:00
Andrew Klychkov
fa62fd30d8
Release 2.1.1 commit (#199) 2021-08-11 08:47:16 +02:00
Andrew Klychkov
0c261b76d6
mysql_query: correctly reflect changed status in replace statements (#193) (#195)
* mysql_query: correctly reflect changed status in replace statements.

* Fix the wrong indent.

(cherry picked from commit 9055bb4c8c)

Co-authored-by: Tong He <68936428+unnecessary-username@users.noreply.github.com>
2021-08-10 14:25:29 +02:00
Andrew Klychkov
5d7451aed6
[stable-2] Doc PRs backport (#194)
* Update README.md (#183)

* Update README.md

* Change IRC ref

(cherry picked from commit 69012a2eb9)

* README: fix link (#184)

(cherry picked from commit 8ab6ea7714)

* README: fix the channel name (#185)

(cherry picked from commit cd759924fd)

* CONTRIBUTING.md: replace the content with a link to Ansible contributing guidelines (#187)

(cherry picked from commit 56a214885a)

* Update README (#186)

* Update README

* Fix

* Fix

* Fix

* Fix

* Add Libera.Chat link

(cherry picked from commit adb201a795)

* fix typo (#190)

"optoin" -> "option"

(cherry picked from commit 596ba0cedb)

* Update README.md (#191)

* Update README.md

* Update README.md

(cherry picked from commit 6f02cb266a)

* Add MAINTAINING.md, update README.md (#192)

(cherry picked from commit 0fabb2b77a)

Co-authored-by: Baptiste Mille-Mathias <baptiste.millemathias@gmail.com>
2021-08-10 14:15:49 +02:00
Andrew Klychkov
2e748efb02
[stable-2] Backport of all the doc PRs merged to main since the last backporting (#182)
* Add CONTRIBUTORS file (#166)

(cherry picked from commit ac927fdb08)

* Add documentation for privs with functions and procedures (#169)

(cherry picked from commit 6bce48e771)

* Update README.md (#168)

* Update README.md

* Fix

* Add MAINTAINERS file

(cherry picked from commit 479edd81d1)

* Improve wording in README (#170)

* Improve wording in README

* Update README.md

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>
(cherry picked from commit c909aa2182)

* Update REVIEW_CHECKLIST.md (#171)

(cherry picked from commit 2236110bae)

* README: add a note how people can complain (#172)

* README: add a note how people can complain

* Change

* Improve

* Update README.md

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>
(cherry picked from commit be4e84a92a)

* README: fix typos (#174)

(cherry picked from commit 2a80c301a6)

* README.md: Add link to IRC (#175)

(cherry picked from commit 3335a95ba5)

* README.md, CONTRIBUTING.md: add links to the Maintainer guidelines (#179)

(cherry picked from commit 8fad3f85b8)

* Update README (#181)

(cherry picked from commit 6d9288d19b)

Co-authored-by: Alexander Skiba <ghostlyrics@gmail.com>
2021-06-09 10:38:17 +02:00
Andrew Klychkov
a68c83f7b5
Update next expected release version in galaxy.yml (#158) 2021-04-23 16:07:29 +02:00
Andrew Klychkov
b32380a9e1
Release 2.1.0 commit (#157) 2021-04-23 15:11:57 +02:00
Andrew Klychkov
34a300d5f0
mysql: revert changes made in PR 116 (#153) (#155)
* mysql: revert changes made in PR 116

* Add changelog fragment

* Fix CI

* Fix CI

* Fix CI

* Update CI

* Fix CI

(cherry picked from commit 738343d64c)
2021-04-23 14:08:36 +02:00
Andrew Klychkov
d9651f37d3
mysql_replication: Add aliases to "master" options, add alternatives to "master" state options, add announcement (#150) (#152)
* mysql_replication: Add aliases, add alternatives for the state option, announce major changes

* Change tests

* Add changelog fragment

* Fix changelog

* Update plugins/modules/mysql_replication.py

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>

* Update plugins/modules/mysql_replication.py

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>

Co-authored-by: Jorge Rodriguez (A.K.A. Tiriel) <jorge.rodriguez@tiriel.eu>
(cherry picked from commit c8f9b1cd3f)
2021-04-23 07:31:02 +02:00
Andrew Klychkov
da7e73ef6e
mysql_replication: add deprecation warning about future replacement of Is_Slave and Is_Master return values, add alternatives (#147) (#149)
* mysql_replication: add deprecation warning about future replacement of Is_Slave and Is_Master return values, add alternatives

* Add changelog fragment

(cherry picked from commit 853db5a2a4)
2021-04-16 07:23:53 +02:00
Andrew Klychkov
5fbac22486 Update collection version to the next expected in galaxy.yml 2021-04-15 10:48:56 +02:00
Andrew Klychkov
900899740b Release 2.0.0 commit 2021-04-15 10:21:17 +02:00
165 changed files with 9677 additions and 3455 deletions

5
.github/patchback.yml vendored Normal file
View file

@ -0,0 +1,5 @@
---
backport_branch_prefix: patchback/backports/
backport_label_prefix: backport-
target_branch_prefix: stable-
...

View file

@ -1,3 +1,4 @@
---
name: Plugins CI
on:
push:
@ -14,98 +15,306 @@ on:
- cron: '0 6 * * *'
env:
mysql_version_file: "./ansible_collections/community/mysql/tests/integration/targets/setup_mysql/defaults/main.yml"
connector_version_file: "./ansible_collections/community/mysql/tests/integration/targets/setup_mysql/vars/main.yml"
jobs:
sanity:
name: "Sanity (Python: ${{ matrix.python }}, Ansible: ${{ matrix.ansible }})"
runs-on: ubuntu-latest
name: "Sanity (Ansible: ${{ matrix.ansible }})"
runs-on: ubuntu-20.04
strategy:
matrix:
ansible:
- stable-2.9
- stable-2.10
- stable-2.11
- devel
- stable-2.12
- stable-2.13
- stable-2.14
steps:
- name: Check out code
uses: actions/checkout@v2
- name: Perform sanity testing
uses: ansible-community/ansible-test-gh-action@release/v1
with:
path: ansible_collections/community/mysql
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install ansible-base (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Run sanity tests
run: ansible-test sanity --docker -v --color
working-directory: ./ansible_collections/community/mysql
ansible-core-version: ${{ matrix.ansible }}
testing-type: sanity
pull-request-change-detection: true
integration:
name: "Integration (Python: ${{ matrix.python }}, Ansible: ${{ matrix.ansible }}, MySQL: ${{ matrix.mysql }}, Connector: ${{ matrix.connector }})"
runs-on: ubuntu-latest
name: "Integration (Python: ${{ matrix.python }}, Ansible: ${{ matrix.ansible }}, DB: ${{ matrix.db_engine_name }} ${{ matrix.db_engine_version }}, connector: ${{ matrix.connector_name }} ${{ matrix.connector_version }})"
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
mysql:
- 5.7.31
- 8.0.22
ansible:
- stable-2.9
- stable-2.10
- stable-2.11
- devel
- stable-2.12
- stable-2.13
- stable-2.14
db_engine_name:
- mysql
- mariadb
db_engine_version:
- 5.7.40
- 8.0.31
- 10.4.27
- 10.5.18
- 10.6.11
python:
- 3.6
connector:
- pymysql==0.7.10
- pymysql==0.9.3
- mysqlclient==2.0.1
- '3.8'
- '3.9'
- '3.10'
connector_name:
- pymysql
- mysqlclient
connector_version:
- 0.7.11
- 0.9.3
# Before we can activate test with pymysql 1.0.2 we should debug the
# following plugins:
#
# mysql_query:
# test "Assert that create table IF NOT EXISTS is not changed with pymysql" failed
#
# mysql_replication:
# test "Assert that startreplica is not changed" failed
# - 1.0.2
- 2.0.1
- 2.0.3
- 2.1.1
exclude:
- mysql: 8.0.22
connector: pymysql==0.7.10
- db_engine_name: mysql
db_engine_version: 10.4.27
- db_engine_name: mysql
db_engine_version: 10.5.18
- db_engine_name: mysql
db_engine_version: 10.6.11
- db_engine_name: mariadb
db_engine_version: 5.7.40
- db_engine_name: mariadb
db_engine_version: 8.0.31
- connector_name: pymysql
connector_version: 2.0.1
- connector_name: pymysql
connector_version: 2.0.3
- connector_name: pymysql
connector_version: 2.1.1
- connector_name: mysqlclient
connector_version: 0.7.11
- connector_name: mysqlclient
connector_version: 0.9.3
- connector_name: mysqlclient
connector_version: 1.0.2
- db_engine_name: mariadb
connector_version: 0.7.11
- db_engine_version: 5.7.40
python: '3.9'
- db_engine_version: 5.7.40
python: '3.10'
- db_engine_version: 5.7.40
ansible: stable-2.13
- db_engine_version: 5.7.40
ansible: stable-2.14
- db_engine_version: 8.0.31
python: '3.8'
- db_engine_version: 8.0.31
python: '3.8'
- db_engine_version: 10.4.27
python: '3.10'
- db_engine_version: 10.6.11
python: '3.8'
- db_engine_version: 10.6.11
python: '3.9'
- python: '3.8'
connector_version: 2.0.3
- python: '3.8'
connector_version: 2.1.1
- python: '3.9'
connector_version: 0.7.11
- python: '3.9'
connector_version: 2.0.1
- python: '3.9'
connector_version: 2.1.1
- python: '3.10'
connector_version: 0.7.11
- python: '3.10'
connector_version: 0.9.3
- python: '3.10'
connector_version: 2.0.1
- python: '3.10'
connector_version: 2.0.3
- python: '3.8'
ansible: stable-2.13
- python: '3.8'
ansible: stable-2.14
- python: '3.9'
ansible: stable-2.12
- python: '3.10'
ansible: stable-2.12
services:
db_primary:
image: docker.io/library/${{ matrix.db_engine_name }}:${{ matrix.db_engine_version }}
env:
MARIADB_ROOT_PASSWORD: msandbox
MYSQL_ROOT_PASSWORD: msandbox
ports:
- 3307:3306
# We write our own health-cmd because the mariadb container does not
# provide a healthcheck
options: >-
--health-cmd "mysqladmin ping -P 3306 -pmsandbox |grep alive || exit 1"
--health-start-period 10s
--health-interval 10s
--health-timeout 5s
--health-retries 6
db_replica1:
image: docker.io/library/${{ matrix.db_engine_name }}:${{ matrix.db_engine_version }}
env:
MARIADB_ROOT_PASSWORD: msandbox
MYSQL_ROOT_PASSWORD: msandbox
ports:
- 3308:3306
options: >-
--health-cmd "mysqladmin ping -P 3306 -pmsandbox |grep alive || exit 1"
--health-start-period 10s
--health-interval 10s
--health-timeout 5s
--health-retries 6
db_replica2:
image: docker.io/library/${{ matrix.db_engine_name }}:${{ matrix.db_engine_version }}
env:
MARIADB_ROOT_PASSWORD: msandbox
MYSQL_ROOT_PASSWORD: msandbox
ports:
- 3309:3306
options: >-
--health-cmd "mysqladmin ping -P 3306 -pmsandbox |grep alive || exit 1"
--health-start-period 10s
--health-interval 10s
--health-timeout 5s
--health-retries 6
steps:
- name: Check out code
uses: actions/checkout@v2
# No need to check for service health. GitHub Action took care of it.
- name: Restart MySQL server with settings for replication
run: |
docker exec ${{ job.services.db_primary.id }} bash -c 'echo -e [mysqld]\\nserver-id=1\\nlog-bin=/var/lib/mysql/primary-bin > /etc/mysql/conf.d/replication.cnf'
docker exec ${{ job.services.db_replica1.id }} bash -c 'echo -e [mysqld]\\nserver-id=2\\nlog-bin=/var/lib/mysql/replica1-bin > /etc/mysql/conf.d/replication.cnf'
docker exec ${{ job.services.db_replica2.id }} bash -c 'echo -e [mysqld]\\nserver-id=3\\nlog-bin=/var/lib/mysql/replica2-bin > /etc/mysql/conf.d/replication.cnf'
docker restart -t 30 ${{ job.services.db_primary.id }}
docker restart -t 30 ${{ job.services.db_replica1.id }}
docker restart -t 30 ${{ job.services.db_replica2.id }}
- name: Wait for the primary to be healthy
run: >
while ! /usr/bin/docker inspect
--format="{{if .Config.Healthcheck}}{{print .State.Health.Status}}{{end}}"
${{ job.services.db_primary.id }}
| grep healthy && [[ "$SECONDS" -lt 120 ]]; do sleep 1; done
- name: Compute docker_image - Set python_version_flat
run: >
echo "python_version_flat=$(echo ${{ matrix.python }}
| tr -d '.')" >> $GITHUB_ENV
- name: Compute docker_image - Set connector_version_flat
run: >
echo "connector_version_flat=$(echo ${{ matrix.connector_version }}
|tr -d .)" >> $GITHUB_ENV
- name: Compute docker_image - Set db_engine_version_flat
run: >
echo "db_engine_version_flat=$(echo ${{ matrix.db_engine_version }}
| awk -F '.' '{print $1 $2}')" >> $GITHUB_ENV
- name: Compute docker_image - Set db_client
run: >
if [[ ${{ env.db_engine_version_flat }} == 57 ]]; then
echo "db_client=my57" >> $GITHUB_ENV;
else
echo "db_client=$(echo ${{ matrix.db_engine_name }})" >> $GITHUB_ENV;
fi
- name: Set docker_image
run: >
docker_image_multiline=("
ghcr.io/ansible-collections/community.mysql\
/test-container-${{ env.db_client }}\
-py${{ env.python_version_flat }}\
-${{ matrix.connector_name }}${{ env.connector_version_flat }}\
:latest")
echo "docker_image=$(printf '%s' $docker_image_multiline)"
>> $GITHUB_ENV
- name: >-
Perform integration testing against
Ansible version ${{ matrix.ansible }}
under Python ${{ matrix.python }}
uses: ansible-community/ansible-test-gh-action@release/v1
with:
path: ansible_collections/community/mysql
ansible-core-version: ${{ matrix.ansible }}
pre-test-cmd: >-
echo Setting db_engine_name to "${{ matrix.db_engine_name }}"...;
echo -n "${{ matrix.db_engine_name }}"
> tests/integration/db_engine_name;
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
echo Setting db_engine_version to \
"${{ matrix.db_engine_version }}"...;
echo -n "${{ matrix.db_engine_version }}"
> tests/integration/db_engine_version;
- name: Install ansible-base (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
echo Setting Connector name to "${{ matrix.connector_name }}"...;
echo -n "${{ matrix.connector_name }}"
> tests/integration/connector_name;
- name: Set MySQL version (${{ matrix.mysql }})
run: "sed -i 's/^mysql_version:.*/mysql_version: \"${{ matrix.mysql }}\"/g' ${{ env.mysql_version_file }}"
echo Setting Connector name to "${{ matrix.connector_version }}"...;
echo -n "${{ matrix.connector_version }}"
> tests/integration/connector_version;
- name: Set Connector version (${{ matrix.connector }})
run: "sed -i 's/^python_packages:.*/python_packages: [${{ matrix.connector }}]/' ${{ env.connector_version_file }}"
echo Setting Python version to "${{ matrix.python }}"...;
echo -n "${{ matrix.python }}"
> tests/integration/python;
- name: Run integration tests
run: ansible-test integration --docker -v --color --retry-on-error --continue-on-error --python ${{ matrix.python }} --diff --coverage
working-directory: ./ansible_collections/community/mysql
- name: Generate coverage report.
run: ansible-test coverage xml -v --requirements --group-by command --group-by version
working-directory: ./ansible_collections/community/mysql
- uses: codecov/codecov-action@v1
with:
fail_ci_if_error: false
echo Setting Ansible version to "${{ matrix.ansible }}"...;
echo -n "${{ matrix.ansible }}"
> tests/integration/ansible
docker-image: ${{ env.docker_image }}
target-python-version: ${{ matrix.python }}
testing-type: integration
units:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
name: Units (Ⓐ${{ matrix.ansible }})
strategy:
# As soon as the first unit test fails,
@ -113,36 +322,27 @@ jobs:
fail-fast: true
matrix:
ansible:
- stable-2.9
- stable-2.10
- stable-2.11
- devel
- stable-2.12
- stable-2.13
- stable-2.14
python:
- 3.8
- 3.9
exclude:
- python: '3.8'
ansible: stable-2.13
- python: '3.8'
ansible: stable-2.14
- python: '3.9'
ansible: stable-2.12
steps:
- name: Check out code
uses: actions/checkout@v2
- name: >-
Perform unit testing against
Ansible version ${{ matrix.ansible }}
uses: ansible-community/ansible-test-gh-action@release/v1
with:
path: ./ansible_collections/community/mysql
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8
- name: Install ansible-base (${{matrix.ansible}})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
# Run the unit tests
- name: Run unit test
run: ansible-test units -v --color --docker --coverage
working-directory: ./ansible_collections/community/mysql
# ansible-test support producing code coverage date
- name: Generate coverage report
run: ansible-test coverage xml -v --requirements --group-by command --group-by version
working-directory: ./ansible_collections/community/mysql
# See the reports at https://codecov.io/gh/GITHUBORG/REPONAME
- uses: codecov/codecov-action@v1
with:
fail_ci_if_error: false
ansible-core-version: ${{ matrix.ansible }}
target-python-version: ${{ matrix.python }}
testing-type: units
pull-request-change-detection: true

View file

@ -1,3 +1,4 @@
---
name: Roles CI
on:
push:
@ -14,7 +15,7 @@ on:
jobs:
molecule:
name: "Molecule (Python: ${{ matrix.python }}, Ansible: ${{ matrix.ansible }}, MySQL: ${{ matrix.mysql }})"
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
env:
PY_COLORS: 1
ANSIBLE_FORCE_COLOR: 1
@ -23,14 +24,26 @@ jobs:
mysql:
- 2.0.12
ansible:
- stable-2.9
### it looks like there's errors for 2.10+ with ansible-lint (https://github.com/ansible/ansible-lint/pull/878)
### and molecule (_maybe_ relating to https://github.com/ansible-community/molecule/pull/2547)
# - stable-2.10
# - devel
- stable-2.11
- stable-2.12
- stable-2.13
python:
- 2.7
- 3.6
- 3.8
- 3.9
exclude:
- python: 3.6
ansible: stable-2.12
- python: 3.6
ansible: stable-2.13
- python: 3.8
ansible: stable-2.11
- python: 3.8
ansible: stable-2.13
- python: 3.9
ansible: stable-2.11
- python: 3.9
ansible: stable-2.12
steps:
@ -44,7 +57,7 @@ jobs:
with:
python-version: ${{ matrix.python }}
- name: Install ansible-base (${{ matrix.ansible }})
- name: Install ansible-core (${{ matrix.ansible }})
run: pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check
- name: Install molecule and related dependencies

View file

@ -0,0 +1,67 @@
---
name: Build Docker Image for ansible-test
on:
workflow_call:
inputs:
registry:
required: true
type: string
image_name:
required: true
type: string
context:
required: true
type: string
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
# Requirement to use 'context' in docker/build-push-action@v3
- name: Checkout repository
uses: actions/checkout@v3
# https://github.com/docker/login-action
- name: Log into registry ${{ inputs.registry }}
uses: docker/login-action@v2
with:
registry: ${{ inputs.registry }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# https://github.com/docker/metadata-action
- name: Extract Docker metadata (tags, labels)
id: meta
uses: docker/metadata-action@v4
with:
images:
"${{ inputs.registry }}\
/${{ github.repository }}\
/${{ inputs.image_name }}"
tags: latest
# Setting up Docker Buildx with docker-container driver is required
# at the moment to be able to use a subdirectory with Git context
#
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# https://github.com/docker/build-push-action
- name: Build and push Docker image with Buildx
id: build-and-push
uses: docker/build-push-action@v3
with:
context: ${{ inputs.context }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mariadb-py310-mysqlclient211
on:
push:
paths:
- 'test-containers/mariadb-py310-mysqlclient211/**'
- '.github/workflows/docker-image-mariadb-py310-mysqlclient211.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mariadb-py310-mysqlclient211
context: test-containers/mariadb-py310-mysqlclient211

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mariadb-py310-pymysql102
on:
push:
paths:
- 'test-containers/mariadb-py310-pymysql102/**'
- '.github/workflows/docker-image-mariadb-py310-pymysql102.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mariadb-py310-pymysql102
context: test-containers/mariadb-py310-pymysql102

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mariadb-py38-mysqlclient201
on:
push:
paths:
- 'test-containers/mariadb-py38-mysqlclient201/**'
- '.github/workflows/docker-image-mariadb-py38-mysqlclient201.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mariadb-py38-mysqlclient201
context: test-containers/mariadb-py38-mysqlclient201

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mariadb-py38-pymysql093
on:
push:
paths:
- 'test-containers/mariadb-py38-pymysql093/**'
- '.github/workflows/docker-image-mariadb-py38-pymysql093.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mariadb-py38-pymysql093
context: test-containers/mariadb-py38-pymysql093

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mariadb-py39-mysqlclient203
on:
push:
paths:
- 'test-containers/mariadb-py39-mysqlclient203/**'
- '.github/workflows/docker-image-mariadb-py39-mysqlclient203.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mariadb-py39-mysqlclient203
context: test-containers/mariadb-py39-mysqlclient203

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mariadb-py39-pymysql093
on:
push:
paths:
- 'test-containers/mariadb-py39-pymysql093/**'
- '.github/workflows/docker-image-mariadb-py39-pymysql093.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mariadb-py39-pymysql093
context: test-containers/mariadb-py39-pymysql093

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI my57-py38-mysqlclient201
on:
push:
paths:
- 'test-containers/my57-py38-mysqlclient201/**'
- '.github/workflows/docker-image-my57-py38-mysqlclient201.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-my57-py38-mysqlclient201
context: test-containers/my57-py38-mysqlclient201

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI my57-py38-pymysql0711
on:
push:
paths:
- 'test-containers/my57-py38-pymysql0711/**'
- '.github/workflows/docker-image-my57-py38-pymysql0711.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-my57-py38-pymysql0711
context: test-containers/my57-py38-pymysql0711

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI my57-py38-pymysql093
on:
push:
paths:
- 'test-containers/my57-py38-pymysql093/**'
- '.github/workflows/docker-image-my57-py38-pymysql093.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-my57-py38-pymysql093
context: test-containers/my57-py38-pymysql093

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mysql-py310-mysqlclient211
on:
push:
paths:
- 'test-containers/mysql-py310-mysqlclient211/**'
- '.github/workflows/docker-image-mysql-py310-mysqlclient211.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mysql-py310-mysqlclient211
context: test-containers/mysql-py310-mysqlclient211

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mysql-py310-pymysql102
on:
push:
paths:
- 'test-containers/mysql-py310-pymysql102/**'
- '.github/workflows/docker-image-mysql-py310-pymysql102.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mysql-py310-pymysql102
context: test-containers/mysql-py310-pymysql102

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mysql-py38-mysqlclient201
on:
push:
paths:
- 'test-containers/mysql-py38-mysqlclient201/**'
- '.github/workflows/docker-image-mysql-py38-mysqlclient201.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mysql-py38-mysqlclient201
context: test-containers/mysql-py38-mysqlclient201

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mysql-py38-pymysql093
on:
push:
paths:
- 'test-containers/mysql-py38-pymysql093/**'
- '.github/workflows/docker-image-mysql-py38-pymysql093.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mysql-py38-pymysql093
context: test-containers/mysql-py38-pymysql093

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mysql-py39-mysqlclient203
on:
push:
paths:
- 'test-containers/mysql-py39-mysqlclient203/**'
- '.github/workflows/docker-image-mysql-py39-mysqlclient203.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mysql-py39-mysqlclient203
context: test-containers/mysql-py39-mysqlclient203

View file

@ -0,0 +1,21 @@
---
name: Docker Image CI mysql-py39-pymysql093
on:
push:
paths:
- 'test-containers/mysql-py39-pymysql093/*'
- '.github/workflows/docker-image-mysql-py39-pymysql093.yml'
- '.github/workflows/build-docker-image.yml'
branches-ignore:
- stable-*
jobs:
call-workflow-passing-data:
uses: ./.github/workflows/build-docker-image.yml
secrets: inherit
with:
registry: ghcr.io
image_name: test-container-mysql-py39-pymysql093
context: test-containers/mysql-py39-pymysql093

5
.gitignore vendored
View file

@ -1,5 +1,7 @@
/tests/output/
/tests/integration/inventory
/changelogs/.plugin-cache.yaml
*.swp
# Byte-compiled / optimized / DLL files
__pycache__/
@ -133,3 +135,6 @@ dmypy.json
# MacOS
.DS_Store
# IntelliJ IDEA or PyCharm
.idea/

489
CHANGELOG.rst Normal file
View file

@ -0,0 +1,489 @@
========================================
Community MySQL Collection Release Notes
========================================
.. contents:: Topics
v2.4.2
======
Release Summary
---------------
Maintenance release of ``community.mysql`` to inform users that the collection version 2 is EOL. There were no functional changes made in this release.
Major Changes
-------------
- Collection version 2.*.* is EOL, no more bugfixes will be backported. Please consider upgrading to the latest version.
v2.4.1
======
Release Summary
---------------
Maintenance release of ``community.mysql`` major version 2. Only contains changes to the CI. There is no functional difference between 2.4.0 and 2.4.1.
v2.4.0
======
Release Summary
---------------
This is a bugfix release of the ``community.mysql`` collection.
This changelog contains all changes to the modules and plugins in this collection
that have been made after the previous release.
Minor Changes
-------------
- mysql_info - add ``connector_name`` and ``connector_version`` to returned values (https://github.com/ansible-collections/community.mysql/pull/497).
v2.3.9
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.8.
Bugfixes
--------
- Include ``simplified_bsd.txt`` license file for various module utils.
v2.3.8
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.7.
Bugfixes
--------
- mysql_query - fix false change reports when ``IF EXISTS/IF NOT EXISTS`` clause is used (https://github.com/ansible-collections/community.mysql/issues/268).
- mysql_role - don't add members to a role when creating the role and ``detach_members: true`` is set (https://github.com/ansible-collections/community.mysql/pull/367).
- mysql_role - in some cases (when "SHOW GRANTS" did not use backticks for quotes), no unwanted members were detached from the role (and redundant "GRANT" statements were executed for wanted members). This is fixed by querying the existing role members from the mysql.role_edges (MySQL) or mysql.roles_mapping (MariaDB) tables instead of parsing the "SHOW GRANTS" output (https://github.com/ansible-collections/community.mysql/pull/368).
- mysql_user - fix logic when ``update_password`` is set to ``on_create`` for users using ``plugin*`` arguments (https://github.com/ansible-collections/community.mysql/issues/334). The ``on_create`` sets ``password`` to None for old mysql_native_authentication but not for authentiation methods which uses the ``plugin*`` arguments. This PR changes this so ``on_create`` also exchange ``plugin``, ``plugin_hash_string``, ``plugin_auth_string`` to None in the list of arguments to change
v2.3.7
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.6.
Bugfixes
--------
- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``.
v2.3.6
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.5.
Major Changes
-------------
- The community.mysql collection no longer supports ``Ansible 2.9`` and ``ansible-base 2.10``. While we take no active measures to prevent usage and there are no plans to introduce incompatible code to the modules, we will stop testing against ``Ansible 2.9`` and ``ansible-base 2.10``. Both will very soon be End of Life and if you are still using them, you should consider upgrading to the ``latest Ansible / ansible-core 2.11 or later`` as soon as possible (https://github.com/ansible-collections/community.mysql/pull/343).
Bugfixes
--------
- mysql_role - remove redundant connection closing (https://github.com/ansible-collections/community.mysql/pull/330).
- mysql_user - fix missing dynamic privileges after revoke and grant privileges to user (https://github.com/ansible-collections/community.mysql/issues/120).
- mysql_user - fix parsing privs when a user has roles assigned (https://github.com/ansible-collections/community.mysql/issues/231).
- mysql_user - fix the possibility for a race condition that breaks certain (circular) replication configurations when ``DROP USER`` is executed on multiple nodes in the replica set. Adding ``IF EXISTS`` avoids the need to use ``sql_log_bin: no`` making the statement always replication safe (https://github.com/ansible-collections/community.mysql/pull/287).
v2.3.5
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection. This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 2.3.4.
Bugfixes
--------
- Collection core functions - fixes related to the mysqlclient Python connector (https://github.com/ansible-collections/community.mysql/issues/292).
v2.3.4
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection. This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 2.3.3.
Bugfixes
--------
- mysql_role - make the ``set_default_role_all`` parameter actually working (https://github.com/ansible-collections/community.mysql/pull/282).
v2.3.3
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection. This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 2.3.2.
Bugfixes
--------
- Collection core functions - use vendored version of ``distutils.version`` instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.mysql/pull/269).
v2.3.2
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.1.
Bugfixes
--------
- mysql_db - Fix mismatch when database name contains a ``%`` character (https://github.com/ansible-collections/community.mysql/pull/227).
v2.3.1
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.0.
Bugfixes
--------
- mysql_user - Fix crash reporting ``Invalid privileges specified`` when passing privileges that became aliases (https://github.com/ansible-collections/community.mysql/issues/232).
v2.3.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.2.0.
Minor Changes
-------------
- mysql_user - replace VALID_PRIVS constant by get_valid_privs() function (https://github.com/ansible-collections/community.mysql/pull/217).
Bugfixes
--------
- mysql_info - fix TypeError failure when there are databases that do not contain tables (https://github.com/ansible-collections/community.mysql/issues/204).
v2.2.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.1.1
New Modules
-----------
- mysql_role - Adds, removes, or updates a MySQL role
v2.1.1
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.1.0.
Minor Changes
-------------
- mysql_query - correctly reflect changed status in replace statements (https://github.com/ansible-collections/community.mysql/pull/193).
v2.1.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.0.0.
Major Changes
-------------
- mysql_replication - add deprecation warning that the ``Is_Slave`` and ``Is_Master`` return values will be replaced with ``Is_Primary`` and ``Is_Replica`` in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/pull/147).
- mysql_replication - the choices of the ``state`` option containing ``master`` will be finally replaced with the alternative ``primary`` choices in ``community.mysql`` 3.0.0, add deprecation warnings (https://github.com/ansible-collections/community.mysql/pull/150).
Minor Changes
-------------
- mysql_replication - add alternative (``primary``) choices to the ``state`` option choices containing ``master`` (https://github.com/ansible-collections/community.mysql/pull/150).
- mysql_replication - add the ``Is_Primary`` and ``Is_Replica`` alternatives to the ``Is_Slave`` and ``Is_Master`` return values as a preparation for replacement in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/pull/147).
- mysql_replication - change ``master_`` options to ``primary_`` options, add aliases to keep compatibility (https://github.com/ansible-collections/community.mysql/pull/150).
Bugfixes
--------
- mysql - revert changes of connector arguments made in pull request 116 causing the invalid keyword argument error (https://github.com/ansible-collections/community.mysql/pull/116).
v2.0.0
======
Release Summary
---------------
This is release 2.0.0 of the ``community.mysql`` collection, released on 2021-04-15.
Major Changes
-------------
- mysql_replication - the return value ``Is_Slave`` and ``Is_Master`` will be replaced with ``Is_Replica`` and ``Is_Primary`` in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/145).
- mysql_replication - the word ``master`` in messages returned by the module will be replaced with ``primary`` in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/145).
- mysql_replication - the word ``slave`` in messages returned by the module replaced with ``replica`` (https://github.com/ansible-collections/community.mysql/issues/98).
- mysql_user - the ``REQUIRESSL`` is an alias for the ``ssl`` key in the ``tls_requires`` option in ``community.mysql`` 2.0.0 and support will be dropped altogether in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/121).
Minor Changes
-------------
- mysql module utils - change deprecated connection parameters ``passwd`` and ``db`` to ``password`` and ``database`` (https://github.com/ansible-collections/community.mysql/pull/116).
- mysql_collection - introduce codebabse split to handle divergences between MySQL and MariaDB (https://github.com/ansible-collections/community.mysql/pull/103).
- mysql_info - add `version.full` and `version.suffix` return values (https://github.com/ansible-collections/community.mysql/issues/114).
- mysql_user - deprecate the ``REQUIRESSL`` privilege (https://github.com/ansible-collections/community.mysql/issues/101).
Bugfixes
--------
- mysql_user - add support for ``REPLICA MONITOR`` privilege (https://github.com/ansible-collections/community.mysql/issues/105).
v1.3.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 1.2.0.
Major Changes
-------------
- mysql_replication - the mode options values ``getslave``, ``startslave``, ``stopslave``, ``resetslave``, ``resetslaveall` and the master_use_gtid option ``slave_pos`` are deprecated (see the alternative values) and will be removed in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/pull/97).
- mysql_replication - the word ``SLAVE`` in messages returned by the module will be changed to ``REPLICA`` in ``community.mysql`` 2.0.0 (https://github.com/ansible-collections/community.mysql/issues/98).
Minor Changes
-------------
- mysql_replication - deprecate offending terminology, add alternative choices to the ``mode`` option (https://github.com/ansible-collections/community.mysql/issues/78).
Bugfixes
--------
- mysql_user - fix handling of INSERT, UPDATE, REFERENCES on columns (https://github.com/ansible-collections/community.mysql/issues/106).
- mysql_user - the module is not idempotent when SELECT on columns granted (https://github.com/ansible-collections/community.mysql/issues/99).
v1.2.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 1.1.2.
Minor Changes
-------------
- mysql_user - refactor to reduce cursor.execute() calls in preparation for adding query logging (https://github.com/ansible-collections/community.mysql/pull/76).
Bugfixes
--------
- mysql_user - add ``SHOW_ROUTINE`` privilege support (https://github.com/ansible-collections/community.mysql/issues/86).
- mysql_user - fixed creating user with encrypted password in MySQL 8.0 (https://github.com/ansible-collections/community.mysql/pull/79).
v1.1.2
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 1.1.1.
Minor Changes
-------------
- mysql_query - simple refactoring of query type check (https://github.com/ansible-collections/community.mysql/pull/58).
- mysql_user - simple refactoring of priv type check (https://github.com/ansible-collections/community.mysql/pull/58).
Bugfixes
--------
- mysql_db - fix false warning related to ``unsafe_login_password`` option (https://github.com/ansible-collections/community.mysql/issues/33).
- mysql_replication - fix crashes of mariadb >= 10.5.1 and mysql >= 8.0.22 caused by using deprecated terminology (https://github.com/ansible-collections/community.mysql/issues/70).
- mysql_user - fixed change detection when using append_privs (https://github.com/ansible-collections/community.mysql/pull/72).
v1.1.1
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 1.1.0.
Bugfixes
--------
- mysql_query - fix failing when single-row query contains commas (https://github.com/ansible-collections/community.mysql/issues/51).
v1.1.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 1.0.2.
Minor Changes
-------------
- mysql modules - add the ``check_hostname`` option (https://github.com/ansible-collections/community.mysql/issues/28).
- mysql modules - patch the ``Connection`` class to add a destructor that ensures connections to the server are explicitly closed (https://github.com/ansible-collections/community.mysql/pull/44).
Bugfixes
--------
- mysql modules - fix crash when ``!includedir`` option is in config file (https://github.com/ansible-collections/community.mysql/issues/46).
v1.0.2
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 1.0.1.
Bugfixes
--------
- mysql_user - fix module's crash when modifying a user with ``host_all`` (https://github.com/ansible-collections/community.mysql/issues/39).
v1.0.1
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 1.0.0.
Bugfixes
--------
- mysql_db - fix false warning related to ``unsafe_login_password`` option (https://github.com/ansible-collections/community.mysql/issues/33).
- mysql_user - added tests to verify that TLS requirements are removed with an empty ``tls_requires`` option (https://github.com/ansible-collections/community.mysql/issues/20).
- mysql_user - correct procedure to check existing TLS requirements (https://github.com/ansible-collections/community.mysql/pull/26).
- mysql_user - minor syntax fixes (https://github.com/ansible-collections/community.mysql/pull/26).
v1.0.0
======
Release Summary
---------------
This is the first proper release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2.9.0.
Minor Changes
-------------
- mysql_db - add ``master_data`` parameter (https://github.com/ansible/ansible/pull/66048).
- mysql_db - add ``skip_lock_tables`` option (https://github.com/ansible/ansible/pull/66688).
- mysql_db - add the ``check_implicit_admin`` parameter (https://github.com/ansible/ansible/issues/24418).
- mysql_db - add the ``dump_extra_args`` parameter (https://github.com/ansible/ansible/pull/67747).
- mysql_db - add the ``executed_commands`` returned value (https://github.com/ansible/ansible/pull/65498).
- mysql_db - add the ``force`` parameter (https://github.com/ansible/ansible/pull/65547).
- mysql_db - add the ``restrict_config_file`` parameter (https://github.com/ansible/ansible/issues/34488).
- mysql_db - add the ``unsafe_login_password`` parameter (https://github.com/ansible/ansible/issues/63955).
- mysql_db - add the ``use_shell`` parameter (https://github.com/ansible/ansible/issues/20196).
- mysql_info - add ``exclude_fields`` parameter (https://github.com/ansible/ansible/issues/63319).
- mysql_info - add ``global_status`` filter parameter option and return (https://github.com/ansible/ansible/pull/63189).
- mysql_info - add ``return_empty_dbs`` parameter to list empty databases (https://github.com/ansible/ansible/issues/65727).
- mysql_replication - add ``channel`` parameter (https://github.com/ansible/ansible/issues/29311).
- mysql_replication - add ``connection_name`` parameter (https://github.com/ansible/ansible/issues/46243).
- mysql_replication - add ``fail_on_error`` parameter (https://github.com/ansible/ansible/pull/66252).
- mysql_replication - add ``master_delay`` parameter (https://github.com/ansible/ansible/issues/51326).
- mysql_replication - add ``master_use_gtid`` parameter (https://github.com/ansible/ansible/pull/62648).
- mysql_replication - add ``queries`` return value (https://github.com/ansible/ansible/pull/63036).
- mysql_replication - add support of ``resetmaster`` choice to ``mode`` parameter (https://github.com/ansible/ansible/issues/42870).
- mysql_user - ``priv`` parameter can be string or dictionary (https://github.com/ansible/ansible/issues/57533).
- mysql_user - add TLS REQUIRES parameters (https://github.com/ansible-collections/community.mysql/pull/9).
- mysql_user - add ``plugin_auth_string`` parameter (https://github.com/ansible/ansible/pull/44267).
- mysql_user - add ``plugin_hash_string`` parameter (https://github.com/ansible/ansible/pull/44267).
- mysql_user - add ``plugin`` parameter (https://github.com/ansible/ansible/pull/44267).
- mysql_user - add the resource_limits parameter (https://github.com/ansible-collections/community.general/issues/133).
- mysql_variables - add ``mode`` parameter (https://github.com/ansible/ansible/issues/60119).
Bugfixes
--------
- mysql - dont mask ``mysql_connect`` function errors from modules (https://github.com/ansible/ansible/issues/64560).
- mysql_db - fix Broken pipe error appearance when state is import and the target file is compressed (https://github.com/ansible/ansible/issues/20196).
- mysql_db - fix bug in the ``db_import`` function introduced by https://github.com/ansible/ansible/pull/56721 (https://github.com/ansible/ansible/issues/65351).
- mysql_info - add parameter for __collect to get only what are wanted (https://github.com/ansible-collections/community.general/pull/136).
- mysql_replication - allow to pass empty values to parameters (https://github.com/ansible/ansible/issues/23976).
- mysql_user - Fix idempotence when long grant lists are used (https://github.com/ansible/ansible/issues/68044)
- mysql_user - Remove false positive ``no_log`` warning for ``update_password`` option
- mysql_user - add ``INVOKE LAMBDA`` privilege support (https://github.com/ansible-collections/community.general/issues/283).
- mysql_user - add missed privileges to support (https://github.com/ansible-collections/community.general/issues/617).
- mysql_user - fix ``host_all`` arguments conversion string formatting error (https://github.com/ansible/ansible/issues/29644).
- mysql_user - fix overriding password to the same (https://github.com/ansible-collections/community.general/issues/543).
- mysql_user - fix support privileges with underscore (https://github.com/ansible/ansible/issues/66974).
- mysql_user - fix the error No database selected (https://github.com/ansible/ansible/issues/68070).
- mysql_user - make sure current_pass_hash is a string before using it in comparison (https://github.com/ansible/ansible/issues/60567).
- mysql_variable - fix the module doesn't support variables name with dot (https://github.com/ansible/ansible/issues/54239).

View file

@ -1,200 +1,5 @@
# Contributing
We follow [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our contributions and interactions within this repository.
Refer to the [Ansible Contributing guidelines](https://docs.ansible.com/ansible/devel/community/index.html) to learn how to contribute to this collection.
If you are a committer, also refer to the [Ansible committer guidelines](https://docs.ansible.com/ansible/devel/community/committer_guidelines.html).
## Issue tracker
Whether you are looking for an opportunity to contribute or you found a bug and already know how to solve it, please go to the [issue tracker](https://github.com/ansible-collections/community.mysql/issues).
There you can find feature ideas to implement, reports about bugs to solve, or submit an issue to discuss your idea before implementing it which can help choose a right direction at the beginning of your work and potentially save a lot of time and effort.
Also somebody may already have started discussing or working on implementing the same or a similar idea,
so you can cooperate to create a better solution together.
## Open pull requests
Look through currently [open pull requests](https://github.com/ansible-collections/community.mysql/pulls).
You can help by reviewing them. Reviews help move pull requests to merge state. Some good pull requests cannot be merged only due to a lack of reviews. And it is always worth saying that good reviews are often more valuable than pull requests themselves. For more information how to provide a good review, refer to the [review checklist](REVIEW_CHECKLIST.md).
Also, consider taking up a valuable, reviewed, but abandoned pull request which you could politely ask the original authors to complete yourself.
## Discussions
For open questions, broad suggestions, and other comments that will not typically fit in the scope of an issue or pull request, [discussions](https://github.com/ansible-collections/community.mysql/discussions) are available. That section provides a place to have a more open and informal conversation about any and all things related to this collection, included but not limited to future development plans, functionality explanations and feature proposals that are not yet fleshed out enough for an issue of their own.
## Looking for an idea to implement
First, see the paragraphs above.
If you came up with a new feature, it is always worth creating an issue
before starting to write code to discuss the idea with the community first.
If you are going to implement the feature yourself, say it in the issue explicitly to avoid working in parallel with somebody else.
## Step-by-step guide how to get into development quickly
We assume that you use Linux as a work environment (you can use a virtual machine as well) and have `git` installed.
1. If possible, make sure that you have installed and started `docker`. While you can also run tests without docker, this makes it a lot easier since you do not have to install the precise requirements, and tests are running properly isolated and in the exact same environments as in CI. You often can also use `podman` with the `docker` executable shim, so if you have that you probably do not need to install `docker`.
2. Clone the [ansible-core](https://github.com/ansible/ansible) repository:
```bash
git clone https://github.com/ansible/ansible.git
```
Instead of installing ansible-core from source, you can also work with an already existing installation of Ansible, ansible-base or ansible-core. Simply skip steps 2 and 3 in that case.
3. Go to the cloned repository and prepare the environment:
```bash
cd ansible && source hacking/env-setup
pip install -r requirements.txt
cd ~
```
4. Create the following directories in your home directory:
```bash
mkdir -p ~/ansible_collections/community/mysql
```
5. Fork the `community.mysql` repository through the GitHub web interface.
6. Clone the forked repository from your profile to the created path:
```bash
git clone https://github.com/YOURACC/community.mysql.git ~/ansible_collections/community/mysql
```
If you prefer to use the SSH protocol:
```bash
git clone git@github.com:YOURACC/community.mysql.git ~/ansible_collections/community/mysql
```
7. Go to your new cloned repository.
```bash
cd ~/ansible_collections/community/mysql
```
8. Be sure you are in the main branch:
```bash
git status
```
9. Show remotes. There should be the `origin` repository only:
```bash
git remote -v
```
10. Add the `upstream` repository:
```bash
git remote add upstream https://github.com/ansible-collections/community.mysql.git
```
11. Update your local `main` branch:
```bash
git fetch upstream
git rebase upstream/main
```
12. Create a branch for your changes:
```bash
git checkout -b name_of_my_branch
```
13. We recommend you start with writing integration tests if applicable.
Note: If there are any difficulties with writing the tests or you are not sure if the case can be covered, feel free to skip this step.
If needed, other contributors can help you with it later.
All integration tests are stored in `tests/integration/targets` subdirectories.
Go to the subdirectory containing the name of module you are going to change.
For example, if you are fixing the `mysql_user` module, its tests are in `tests/integration/targets/test_mysql_user/tasks`.
The `main.yml` file holds test tasks and includes other test files.
Look for a suitable test file to integrate your tests or create and include a dedicated test file.
You can use one of the existing test files as a draft.
When fixing a bug, write a task which reproduces the bug from the issue.
Put the reported case in the tests, then run integration tests with the following command:
```bash
ansible-test integration test_mysql_user --docker -vvv
```
If the tests do not want to run, first, check you complete step 3 of this guide.
If the tests ran successfully, there are usually two possible outcomes:
a) If the bug has not appeared and the tests have passed successfully, ask the reporter to provide more details. The bug can be not a bug actually or can relate to a particular software version used or specifics of local environment configuration.
b) The bug has appeared and the tests has failed as expected showing the reported symptoms.
14. Fix the bug.
15. Run `flake8` against a changed file. If it is `plugins/modules/mysql_user.py`:
```bash
flake8 plugins/modules/mysql_user.py
```
It is worth installing and running `flake8` against the changed file(s) first.
It shows unused imports, which is not shown by sanity tests (see the next step), as well as other common issues.
Optionally, you can use the `--max-line-length=160` command-line argument.
16. Run sanity tests:
```bash
ansible-test sanity plugins/modules/mysql_user.py --docker
```
If they failed, look at the output carefully - it is usually very informative and helps to identify a problem line quickly.
Sanity failings usually relate to wrong code and documentation formatting.
17. Run integration tests:
```bash
ansible-test integration test_mysql_user --docker -vvv
```
There are two possible outcomes:
a) They have failed. Look at the output of the command.
Fix the problem place in the code and run again.
Repeat the cycle until the tests pass.
b) They have passed. Remember they failed originally? Our congratulations! You have fixed the bug.
18. Commit your changes with an informative but short commit message:
```bash
git add /path/to/changed/file
git commit -m "mysql_user: fix crash when ..."
```
19. Push the branch to the `origin` (your fork):
```bash
git push origin name_of_my_branch
```
20. Go to the `upstream` (http://github.com/ansible-collections/community.mysql).
21. Go to `Pull requests` tab and create a pull request.
GitHub is tracking your fork, so it should see the new branch in it and automatically offer
to create a pull request. Sometimes GitHub does not do it and you should click the `New pull request` button yourself.
Then choose `compare across forks` under the `Compare changes` title.
Choose your repository and the new branch you pushed in the right drop-down list.
Confirm. Fill out the pull request template with all information you want to mention.
Put "Fixes + link to the issue" in the pull request's description.
Put "[WIP] + short description" in the pull request's title. It's often a good idea to mention the name of the module/plugin you are modifying at the beginning of the description.
Click `Create pull request`.
22. Add a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#changelogs) to the `changelog/fragments` directory. It will be published in release notes, so users will know about the fix.
Commit and push it:
```bash
git add changelog/fragments/myfragment.yml
git commit -m "Add changelog fragment"
git push origin name_of_my_branch
```
23. The CI tests will run automatically on Red Hat infrastructure after every commit.
You will see the CI status in the bottom of your pull request.
If they are green, remove "[WIP]" from the title. Mention the issue reporter in a comment and let contributors know that the pull request is "Ready for review".
24. Wait for reviews. You can also ask for review on IRC in the #ansible-community channel.
25. If the pull request looks good to the community, committers will merge it.
For details, refer to the [Ansible developer guide](https://docs.ansible.com/ansible/latest/dev_guide/index.html).
If you find any inconsistencies or places in this document which can be improved, feel free to raise an issue or pull request to fix it.
Refer to the [review checklist](https://docs.ansible.com/ansible/devel/community/collection_contributors/collection_reviewing.html) when triaging issues or reviewing PRs.

283
CONTRIBUTORS Normal file
View file

@ -0,0 +1,283 @@
116davinder
20
28
29
4
4n70w4
abadger
abondis
acozine
adamchainz
adq
Akasurde
Alexander198961
alustenberg
aminvakil
amitk79
amree
Andersson007
andrewhowdencom
ansibot
anthonyxpalermo
antonioribeiro
apollo13
aquach
arcmop
asad-at-srt
AshDevilRed
aurimasl
axelll
axisK
azielke
baldpale
banyek
BarbzYHOOL
Berbe
bjne
bmalynovytch
bmildren
bmillemathias
boreal321
brutus
burner1024
calfonso
candeira
caphrim007
cdalbergue
checkphi
chrismeyersfsu
ChristopherGAndrews
cmodijk
codeaken
codebymikey
coreylane
CormacBracken
cosmix
cptMikky
crashes
dagwieers
damianmoore
Davidffry
denisemauldin
diclophis
d-lee
d-rupp
dmp1ce
dnelson
dramaley
drybjed
drzraf
DSpeichert
dungdm93
dwagelaar
dylanjbarth
einarc
E-M
eowin
Ernest0x
esamattis
Everspace
F21
faitno
felixfontein
flatrocks
fourjay
fraff
g00fy-
geerlingguy
georgeOsdDev
ghjm
ghost
giacmir
giorgio-v
gkoller
gottwald
gstorme
gundalow
hansbaer
hchargois
hluaces
hwali
hyperfocus1338
igormukhingmailcom
imjoseangel
infigoKriti
int32bit
ipergenitsa
iredmail
ivandigiusto
jadbaz
jaikdean
jamescassell
janosmiko
jarnold-timeout
JaSafieddine
jb-2197
jborean93
jctanner
jean-christophe-manciot
Jean-Daniel
jgornick
jhagg
jhoekx
jirib
jkleckner
jkordish
jlaska
Jmainguy
jochu
JoelFeiner
johnavp1989
jonatasbaldin
Jorge-Rodriguez
jpjaatin
jpmens
JSafieddine
jsmartin
juergenhoetzel
jw34
kalaisubbiah
kenichi-ogawa-1988
kkeane
klingac
koleo
kotso
kuntalFreshBooks
kurtdavis
larsks
laurent-indermuehle
ldesgrange
leeadh
LeonB
leucos
loomsen
lorin
lowwalker
lperezs
makmanalp
manuelmorena
MarcinOrlowski
markdorison
markotitel
marktheunissen
markuman
mattclay
matt-horwood-mayden
mavimo
maxamillion
maxbube
mcgoldrickm
meanstrong
meersjo
megamisan
michaeldg
michalmedvecky
MikeiLL
milky-milk
milosz
mistaka0s
mklassen
mkrizek
mmoya
mohag
mohsenSy
mpdehaan
MRwangyd
mverwijs
mvgrimes
mysqlbox
netmonk
nhojpatrick
nicolas-g
NielsH
nitinkansal1984
nitzmahone
Ompragash
on
order
organman91
p53
pakal
paulbadcock
pennycoders
petoju
petracvv
pgrenaud
philfry
pileofrogs
pkaramol
platypus-geek
plumbeo
pratikgadiya12
pshanbhag
r0bj
rajsshah86
reduzent
relrod
resmo
ricco24
richlv
riupie
rndmh3ro
robertdebock
robpblake
rokka-n
Roxyrob
roysmith
rsicart
rthouvenin
ruudk
samccann
samdoran
sayap
scottbrown
seanorama
sedrubal
sergey-trukhin
Shaps
shrikeh
sivel
skalfyfan
skoriy88
sperantus
spoyd
steverweber
steveteahan
stijnopheide
stintel
stoned
strixBE
SWADESNA
tapologo
tarunm97
tejatsk14
tersmitten
the
the02
thomasliddledba
time-palominodb
timorunge
Tomasthanes
tomdymond
Tronde
tuhoanganh
tvlooy
tyll
UncertaintyP
unnecessary-username
vamshi8
vanne
vdboor
vmahadev
v-zhuravlev
webmat
wedi
whysthatso
willthames
windowsansiblernew
wrosario
xiata
Xyon
yangchao0512
ziegenberg
Zverik

6
MAINTAINERS Normal file
View file

@ -0,0 +1,6 @@
betanummeric
bmalynovytch
Jorge-Rodriguez
rsicart
laurent-indermuehle
Andersson007 (andersson007_ in #ansible-community IRC/Matrix)

3
MAINTAINING.md Normal file
View file

@ -0,0 +1,3 @@
# Maintaining this collection
Refer to the [Maintainer guidelines](https://github.com/ansible/community-docs/blob/main/maintaining.rst).

112
Makefile Normal file
View file

@ -0,0 +1,112 @@
SHELL := /bin/bash
# To tell ansible-test and Make to not kill the containers on failure or
# end of tests. Disabled by default.
ifdef keep_containers_alive
_keep_containers_alive = --docker-terminate never
endif
# This match what GitHub Action will do. Disabled by default.
ifdef continue_on_errors
_continue_on_errors = --retry-on-error --continue-on-error
endif
db_ver_tuple := $(subst ., , $(db_engine_version))
db_engine_version_flat := $(word 1, $(db_ver_tuple))$(word 2, $(db_ver_tuple))
con_ver_tuple := $(subst ., , $(connector_version))
connector_version_flat := $(word 1, $(con_ver_tuple))$(word 2, $(con_ver_tuple))$(word 3, $(con_ver_tuple))
py_ver_tuple := $(subst ., , $(python))
python_version_flat := $(word 1, $(py_ver_tuple))$(word 2, $(py_ver_tuple))
ifeq ($(db_engine_version_flat), 57)
db_client := my57
else
db_client := $(db_engine_name)
endif
.PHONY: test-integration
test-integration:
@echo -n $(db_engine_name) > tests/integration/db_engine_name
@echo -n $(db_engine_version) > tests/integration/db_engine_version
@echo -n $(connector_name) > tests/integration/connector_name
@echo -n $(connector_version) > tests/integration/connector_version
@echo -n $(python) > tests/integration/python
@echo -n $(ansible) > tests/integration/ansible
# Create podman network for systems missing it. Error can be ignored
podman network create podman || true
podman run \
--detach \
--replace \
--name primary \
--env MARIADB_ROOT_PASSWORD=msandbox \
--env MYSQL_ROOT_PASSWORD=msandbox \
--network podman \
--publish 3307:3306 \
--health-cmd 'mysqladmin ping -P 3306 -pmsandbox | grep alive || exit 1' \
docker.io/library/$(db_engine_name):$(db_engine_version) \
mysqld
podman run \
--detach \
--replace \
--name replica1 \
--env MARIADB_ROOT_PASSWORD=msandbox \
--env MYSQL_ROOT_PASSWORD=msandbox \
--network podman \
--publish 3308:3306 \
--health-cmd 'mysqladmin ping -P 3306 -pmsandbox | grep alive || exit 1' \
docker.io/library/$(db_engine_name):$(db_engine_version) \
mysqld
podman run \
--detach \
--replace \
--name replica2 \
--env MARIADB_ROOT_PASSWORD=msandbox \
--env MYSQL_ROOT_PASSWORD=msandbox \
--network podman \
--publish 3309:3306 \
--health-cmd 'mysqladmin ping -P 3306 -pmsandbox | grep alive || exit 1' \
docker.io/library/$(db_engine_name):$(db_engine_version) \
mysqld
# Setup replication and restart containers
podman exec primary bash -c 'echo -e [mysqld]\\nserver-id=1\\nlog-bin=/var/lib/mysql/primary-bin > /etc/mysql/conf.d/replication.cnf'
podman exec replica1 bash -c 'echo -e [mysqld]\\nserver-id=2\\nlog-bin=/var/lib/mysql/replica1-bin > /etc/mysql/conf.d/replication.cnf'
podman exec replica2 bash -c 'echo -e [mysqld]\\nserver-id=3\\nlog-bin=/var/lib/mysql/replica2-bin > /etc/mysql/conf.d/replication.cnf'
# Don't restart a container unless it is healthy
while ! podman healthcheck run primary && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
podman restart -t 30 primary
while ! podman healthcheck run replica1 && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
podman restart -t 30 replica1
while ! podman healthcheck run replica2 && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
podman restart -t 30 replica2
while ! podman healthcheck run primary && [[ "$$SECONDS" -lt 120 ]]; do sleep 1; done
mkdir -p .venv/$(ansible)
python$(local_python_version) -m venv .venv/$(ansible)
# Start venv (use `; \` to keep the same shell)
source .venv/$(ansible)/bin/activate; \
python$(local_python_version) -m ensurepip; \
python$(local_python_version) -m pip install --disable-pip-version-check \
https://github.com/ansible/ansible/archive/$(ansible).tar.gz; \
set -x; \
ansible-test integration $(target) -v --color --coverage --diff \
--docker ghcr.io/ansible-collections/community.mysql/test-container\
-$(db_client)-py$(python_version_flat)-$(connector_name)$(connector_version_flat):latest \
--docker-network podman $(_continue_on_errors) $(_keep_containers_alive) --python $(python); \
set +x
# End of venv
rm tests/integration/db_engine_name
rm tests/integration/db_engine_version
rm tests/integration/connector_name
rm tests/integration/connector_version
rm tests/integration/python
rm tests/integration/ansible
ifndef keep_containers_alive
podman stop --time 0 --ignore primary replica1 replica2
podman rm --ignore --volumes primary replica1 replica2
endif

48
PSF-license.txt Normal file
View file

@ -0,0 +1,48 @@
PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
--------------------------------------------
1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using this software ("Python") in source or binary form and
its associated documentation.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python alone or in any derivative version,
provided, however, that PSF's License Agreement and PSF's notice of copyright,
i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Python Software Foundation;
All Rights Reserved" are retained in Python alone or in any derivative version
prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on
or incorporates Python or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python.
4. PSF is making Python available to Licensee on an "AS IS"
basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee. This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.
8. By copying, installing or otherwise using Python, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.

116
README.md
View file

@ -1,5 +1,58 @@
# MySQL collection for Ansible
[![Plugins CI](https://github.com/ansible-collections/community.mysql/workflows/Plugins%20CI/badge.svg?event=push)](https://github.com/ansible-collections/community.mysql/actions?query=workflow%3A"Plugins+CI") [![Roles CI](https://github.com/ansible-collections/community.mysql/workflows/Roles%20CI/badge.svg?event=push)](https://github.com/ansible-collections/community.mysql/actions?query=workflow%3A"Roles+CI") [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.mysql)](https://codecov.io/gh/ansible-collections/community.mysql)
[![Plugins CI](https://github.com/ansible-collections/community.mysql/workflows/Plugins%20CI/badge.svg?event=push)](https://github.com/ansible-collections/community.mysql/actions?query=workflow%3A"Plugins+CI") [![Roles CI](https://github.com/ansible-collections/community.mysql/workflows/Roles%20CI/badge.svg?event=push)](https://github.com/ansible-collections/community.mysql/actions?query=workflow%3A"Roles+CI") [![Codecov](https://img.shields.io/codecov/c/github/ansible-collections/community.mysql)](https://codecov.io/gh/ansible-collections/community.mysql) [![Discuss on Matrix at #mysql:ansible.com](https://img.shields.io/matrix/mysql:ansible.com.svg?server_fqdn=ansible-accounts.ems.host&label=Discuss%20on%20Matrix%20at%20%23mysql:ansible.com&logo=matrix)](https://matrix.to/#/#mysql:ansible.com)
This collection is a part of the Ansible package.
## Our mission
The Ansible `community.mysql` collection goals are to produce and maintain simple,
flexible, and powerful open-source software for automating MySQL and MariaDB related tasks
providing good documentation for easy deployment and use.
## Code of Conduct
We follow the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our interactions within this project.
If you encounter abusive behavior violating the [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html), please refer to the [policy violations](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html#policy-violations) section of the Code of Conduct for information on how to raise a complaint.
## Contributing
The content of this collection is made by [people](https://github.com/ansible-collections/community.mysql/blob/main/CONTRIBUTORS) just like you, a community of individuals collaborating on making the world better through developing automation software.
We are actively accepting new contributors.
Any kind of contribution is very welcome.
You don't know how to start? Refer to our [contribution guide](https://github.com/ansible-collections/community.mysql/blob/main/CONTRIBUTING.md) or ask us in the [#mysql:ansible.com room](https://matrix.to/#/#mysql:ansible.com) on [Matrix](https://docs.ansible.com/ansible/devel/community/communication.html#ansible-community-on-matrix)!
## Collection maintenance
The current maintainers (contributors with `write` or higher access) are listed in the [MAINTAINERS](https://github.com/ansible-collections/community.mysql/blob/main/MAINTAINERS) file. If you have questions or need help, feel free to mention them in the proposals.
To learn how to maintain / become a maintainer of this collection, refer to the [Maintainer guidelines](https://github.com/ansible-collections/community.mysql/blob/main/MAINTAINING.md).
It is necessary for maintainers of this collection to be subscribed to:
* The collection itself (the `Watch` button -> `All Activity` in the upper right corner of the repository's homepage).
* The "Changes Impacting Collection Contributors and Maintainers" [issue](https://github.com/ansible-collections/overview/issues/45).
They also should be subscribed to Ansible's [The Bullhorn newsletter](https://docs.ansible.com/ansible/devel/community/communication.html#the-bullhorn).
## Communication
We announce releases and important changes through Ansible's [The Bullhorn newsletter](https://eepurl.com/gZmiEP). Be sure you are subscribed.
Join us on Matrix in the `#mysql:ansible.com` [room](https://matrix.to/#/#mysql:ansible.com), the `#users:ansible.com` [room](https://matrix.to/#/#users:ansible.com) (general use questions and support), `#ansible-community:ansible.com` [room](https://matrix.to/#/#community:ansible.com) (community and collection development questions), and other Matrix rooms or corresponding bridged Libera.Chat channels. See the [Ansible Communication Guide](https://docs.ansible.com/ansible/devel/community/communication.html) for details.
We take part in the global quarterly [Ansible Contributor Summit](https://github.com/ansible/community/wiki/Contributor-Summit) virtually or in-person. Track [The Bullhorn newsletter](https://eepurl.com/gZmiEP) and join us.
For more information about communication, refer to the [Ansible Communication guide](https://docs.ansible.com/ansible/devel/community/communication.html).
## Governance
The process of decision making in this collection is based on discussing and finding consensus among participants.
Every voice is important and every idea is valuable. If you have something on your mind, create an issue or dedicated discussion and let's discuss it!
## Included content
@ -8,19 +61,52 @@
- [mysql_info](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_info_module.html)
- [mysql_query](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_query_module.html)
- [mysql_replication](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_replication_module.html)
- [mysql_role](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_role_module.html)
- [mysql_user](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_user_module.html)
- [mysql_variables](https://docs.ansible.com/ansible/latest/collections/community/mysql/mysql_variables_module.html)
## Tested with Ansible
## Releases Support Timeline
- 2.9
- 2.10
- 2.11
- devel
We maintain each major release (1.x.y, 2.x.y, ...) for two years after the next major version is released.
Here is the table for the support timeline:
- 1.x.y: released 2020-08-17, EOL
- 2.x.y: released 2021-04-15, EOL
## Tested with
### ansible-core
- 2.12
- 2.13
- 2.14
### Databases
For MariaDB, only Long Term releases are tested.
- mysql 5.7.40
- mysql 8.0.31
- mariadb:10.3.34 (only collection version <= 3.5.1)
- mariadb:10.4.24 (only collection version >= 3.5.2)
- mariadb:10.5.18 (only collection version >= 3.5.2)
- mariadb:10.6.11 (only collection version >= 3.5.2)
- mariadb:10.11.?? (waiting for release)
### Database connectors
- pymysql 0.7.11 (Only tested with MySQL 5.7)
- pymysql 0.9.3
- pymysql 1.0.2 (only collection version >= ???) !!! Unsuported until future release !!!
- mysqlclient 2.0.1
- mysqlclient 2.0.3 (only collection version >= 3.5.2)
- mysqlclient 2.1.1 (only collection version >= 3.5.2)
## External requirements
The MySQL modules rely on a MySQL connector. The list of supported drivers is below:
The MySQL modules rely on a MySQL connector. The list of supported drivers is below:
- [PyMySQL](https://github.com/PyMySQL/PyMySQL)
- [MySQLdb](https://github.com/PyMySQL/mysqlclient-python)
@ -44,12 +130,20 @@ collections:
- name: community.mysql
```
Note that if you install the collection from Ansible Galaxy, it will not be upgraded automatically if you upgrade the Ansible package. To upgrade the collection to the latest available version, run the following command:
```bash
ansible-galaxy collection install community.mysql --upgrade
```
You can also install a specific version of the collection, for example, if you need to downgrade when something is broken in the latest version (please report an issue in this repository). Use the following syntax:
```bash
ansible-galaxy collection install community.mysql:==2.0.0
```
See [Ansible Using collections](https://docs.ansible.com/ansible/latest/user_guide/collections_using.html) for more details.
## Contributing
See the [contribution guide](CONTRIBUTING.md).
## Licensing
<!-- Include the appropriate license information here and a pointer to the full licensing details. If the collection contains modules migrated from the ansible/ansible repo, you must use the same license that existed in the ansible/ansible repo. See the GNU license example below. -->

View file

@ -1,38 +0,0 @@
# Review Checklist
When reviewing, keep in mind that we follow [Ansible Code of Conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html) in all our contributions and interactions within this repository.
If you are a committer, also refer to the [Ansible committer guidelines](https://docs.ansible.com/ansible/devel/community/committer_guidelines.html).
**General tips**
- Try to create a culture of collaboration when reviewing
- Welcome the author and thank them for the pull request
- When suggesting changes, try to use questions, not statements
- When suggesting mandatory changes, do it as politely as possible providing documentation references
- If your suggestion is optional or a matter of personal preferences, please say it explicitly
- When asking for adding tests or for complex code refactoring, say that the author is welcome to ask for clarifications and help if they need
- If somebody suggests a good idea, mention it or put a thumbs up
- After merging, thank the author and reviewers for their time and effort
**Standards and documentation**
- [ ] if the pull request is not a documentation fix, it must include a [changelog fragment](https://docs.ansible.com/ansible/devel/community/development_process.html#creating-a-changelog-fragment) - please check the format carefully
- [ ] if new files are added with the pull request, they follow the [licensing rules](https://github.com/ansible-collections/overview/blob/main/collection_requirements.rst#licensing)
- [ ] the changes follow the [Ansible documentation standards](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_documenting.html) and the [style guide](https://docs.ansible.com/ansible/devel/dev_guide/style_guide/index.html#style-guide)
- [ ] the changes follow the [development conventions](https://docs.ansible.com/ansible/devel/dev_guide/developing_modules_best_practices.html)
- [ ] if a new plugin is added, it is one of the [allowed plugin types](https://github.com/ansible-collections/overview/blob/main/collection_requirements.rst#modules-plugins)
- [ ] documentation, examples, and return sections use FQCNs for the `M(..)` [format macros](https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_documenting.html#linking-and-other-format-macros-within-module-documentation) when referring to modules
- [ ] modules and plugins from ansible-core use `ansible.builtin.` as a FQCN prefix when mentioned
- [ ] when a new option, module, plugin, or return value is added, the corresponding documentation or return sections use `version_added:` containing the *collection* version which they will be first released in
* this usually is the next minor release, sometimes the next major release (example: if 2.7.5 is the current release, the next minor release will be 2.8.0, and the next major release will be 3.0.0)
- [ ] FQCNs are used for `extends_documentation_fragment:`, unless the author is referring to doc_fragments from ansible-core
**Tests (if applicable and technically possible to implement)**
- [ ] the pull request has [integration tests](https://docs.ansible.com/ansible/devel/dev_guide/testing_integration.html)
- [ ] the pull request has [unit tests](https://docs.ansible.com/ansible/devel/dev_guide/testing_units.html)
- [ ] all changes are covered
- [ ] integration tests also cover `check_mode` (if it is supported)
- [ ] integration tests check an actual state of the system, not only what the module reports (for example, if the module changes a file, check that the file was actually changed by using the `ansible.builtin.stat` module)
**Other**
- [ ] the pull request does not contain merge commits (see GitHub warnings at the bottom of the pull request) - in this case, ask the author to rebase the pull request branch
- [ ] if the pull request contains breaking changes, ask the author and the collection maintainers if it is really needed and there is no way not to introduce them

165
TESTING.md Normal file
View file

@ -0,0 +1,165 @@
# Tests
This collection uses GitHub Actions to run ansible-test to validate its content. Three type of tests are used: Sanity, Integration and Units.
The tests covers plugins and roles (no role available yet, but tests are ready) and can be found here:
- Plugins: *.github/workflows/ansible-test-plugins.yml*
- Roles: *.github/workflows/ansible-test-roles.yml* (unused yet)
Everytime you push on your fork or you create a pull request, both workflows runs. You can see the output on the "Actions" tab.
## Integration tests
You can use GitHub to run ansible-test either on the community repo or your fork. But sometimes you want to quickly test a single version or a single target. To do that, you can use the Makefile present at the root of this repository.
For now, the makefile only supports Podman.
### Requirements
- python >= 3.8 and <= 3.10
- make
- podman
- Minimum 15GB of free space on the device storing containers images and volumes. You can use this command to check: `podman system info --format='{{.Store.GraphRoot}}'|xargs findmnt --noheadings --nofsroot --output SOURCE --target|xargs df -h --output=size,used,avail,pcent,target`
- Minimum 2GB of RAM
### Custom ansible-test containers
Our integrations tests use custom containers for ansible-test. Those images have their definition file stored in the directory [test-containers](test-containers/). We build and publish the images on ghcr.io under the ansible-collection namespace: E.G.:
`ghcr.io/ansible-collections/community.mysql/test-container-mariadb106-py310-mysqlclient211:latest`.
Availables images are listed [here](https://github.com/orgs/ansible-collections/packages).
### Makefile options
The Makefile accept the following options
- `local_python_version`
- Mandatory: false
- Choices:
- "3.8"
- "3.9"
- "3.10"
- Description: If `Python -V` shows an unsupported version, use this option and choose one of the version available on your system. Use `ls /usr/bin/python3*|grep -v config` to list them.
- `ansible`
- Mandatory: true
- Choices:
- "stable-2.12"
- "stable-2.13"
- "stable-2.14"
- Description: Version of ansible to install in a venv to run ansible-test
- `db_engine_name`
- Mandatory: true
- Choices:
- "mysql"
- "mariadb"
- Description: The name of the database engine to use for the service containers that will host a primary database and two replicas.
- `db_engine_version`
- Mandatory: true
- Choices:
- "5.7.40" <- mysql
- "8.0.31" <- mysql
- "10.4.24" <- mariadb
- "10.5.18" <- mariadb
- "10.6.11" <- mariadb
- Description: The tag of the container to use for the service containers that will host a primary database and two replicas. Do not use short version, like `mysql:8` (don't do that) because our tests expect a full version to filter tests precisely. For instance: `when: db_version is version ('8.0.22', '>')`. You can use any tag available on [hub.docker.com/_/mysql](https://hub.docker.com/_/mysql) and [hub.docker.com/_/mariadb](https://hub.docker.com/_/mariadb) but GitHub Action will only use the versions listed above.
- `connector_name`
- Mandatory: true
- Choices:
- "pymysql
- "mysqlclient"
- Description: The python package of the connector to use. In addition to selecting the test container, this value is also used for tests filtering: `when: connector_name == 'pymysql'`.
- `connector_version`
- Mandatory: true
- Choices:
- "0.7.11" <- pymysql (Only for MySQL 5.7)
- "0.9.3" <- pymysql
- "1.0.2" <- pymysql (Not working, need fix)
- "2.0.1" <- mysqlclient
- "2.0.3" <- mysqlclient
- "2.1.1" <- mysqlclient
- Description: The version of the python package of the connector to use. This value is used to filter tests meant for other connectors.
- `python`
- Mandatory: true
- Choices:
- "3.8"
- "3.9"
- "3.10"
- Description: The python version to use in the controller (ansible-test container).
- `target`
- Mandatory: false
- Choices:
- "test_mysql_db"
- "test_mysql_info"
- "test_mysql_query"
- "test_mysql_replication"
- "test_mysql_role"
- "test_mysql_user"
- "test_mysql_variables"
- Description: If omitted, all test targets will run. But you can limit the tests to a single target to speed up your tests.
- `keep_containers_alive`
- Mandatory: false
- Description: This option keeps all tree databases containers and the ansible-test container alive at the end of tests or in case of failure. This is useful to enter one of the containers with `podman exec -it <container-name> bash` for debugging. Rerunning the
tests will overwrite the 3 databases containers so no need to kill them in advance. But nothing will kill the ansible-test container. You must do that using `podman stop` and `podman rm`. Add any value to activate this option: `keep_containers_alive=1`
- `continue_on_errors`
- Mandatory: false
- Description: Tells ansible-test to retry on errors and also continue on errors. This is the way the GitHub Action's workflow runs the tests. This can be used to catch all errors in a single run, but you'll need to scroll up to find them. Add any value to activate this option: `continue_on_errors=1`
#### Makefile usage examples:
```sh
# Run all targets
make ansible="stable-2.12" db_engine_name="mysql" db_engine_version="5.7.40" python="3.8" connector_name="pymysql" connector_version="0.7.11"
# A single target
make ansible="stable-2.14" db_engine_name="mysql" db_engine_version="5.7.40" python="3.8" connector_name="pymysql" connector_version="0.7.11" target="test_mysql_info"
# Keep databases and ansible tests containers alives
# A single target and continue on errors
make ansible="stable-2.14" db_engine_name="mysql" db_engine_version="8.0.31" python="3.9" connector_name="mysqlclient" connector_version="2.0.3" target="test_mysql_query" keep_containers_alive=1 continue_on_errors=1
# If your system has an usupported version of Python:
make local_python_version="3.8" ansible="stable-2.14" db_engine_name="mariadb" db_engine_version="10.6.11" python="3.9" connector_name="pymysql" connector_version="0.9.3"
```
### Run all tests
GitHub Action offer a test matrix that run every combination of Python, MySQL, MariaDB and Connector against each other. To reproduce this, this repo provides a script called *run_all_tests.py*.
Examples:
```sh
python run_all_tests.py
```
### Add a new Python, Connector or Database version
You can look into `[.github/workflows/ansible-test-plugins.yml](https://github.com/ansible-collections/community.mysql/tree/main/.github/workflows)` to see how those containers are built using [build-docker-image.yml](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/build-docker-image.yml) and all [docker-image-xxx.yml](https://github.com/ansible-collections/community.mysql/blob/main/.github/workflows/docker-image-mariadb103-py38-mysqlclient201.yml) files.
1. Add a workflow in [.github/workflows/](.github/workflows)
1. Add a new folder in [test-containers](test-containers) containing a new Dockerfile. Your container must contains 3 things:
- Python
- A connector: The python package to connect to the database (pymysql, mysqlclient, ...)
- A mysql client to prepare databases before our tests starts. This client must provide both `mysql` and `mysqldump` commands.
1. Add your version in the matrix of *.github/workflows/ansible-test-plugins.yml*. You can use [run_all_tests.py](run_all_tests.py) to help you see what the matrix will be. Simply comment out the line `os.system(make_cmd)` before runing the script. You can also add `print(len(matrix))` to display how many tests there will be on GitHub Action.
1. Ask the lead maintainer to mark your new image(s) as `public` under [https://github.com/orgs/ansible-collections/packages](https://github.com/orgs/ansible-collections/packages)
After pushing your commit to the remote, the container will be built and published on ghcr.io. Have a look in the "Action" tab to see if it worked. In case of error `failed to copy: io: read/write on closed pipe` re-run the workflow, this append unfortunately a lot.
To see the docker image produced, go to the package page in the ansible-collection namespace [https://github.com/orgs/ansible-collections/packages](https://github.com/orgs/ansible-collections/packages). This page indicate a "Published x days ago" that is updated infrequently. To see the last time the container has been updated you must click on its title and look in the right hands side bellow the title "Last published".

View file

@ -1,206 +0,0 @@
========================================
Community MySQL Collection Release Notes
========================================
.. contents:: Topics
v1.3.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 1.2.0.
Major Changes
-------------
- mysql_replication - the mode options values ``getslave``, ``startslave``, ``stopslave``, ``resetslave``, ``resetslaveall` and the master_use_gtid option ``slave_pos`` are deprecated (see the alternative values) and will be removed in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/pull/97).
- mysql_replication - the word ``SLAVE`` in messages returned by the module will be changed to ``REPLICA`` in ``community.mysql`` 2.0.0 (https://github.com/ansible-collections/community.mysql/issues/98).
Minor Changes
-------------
- mysql_replication - deprecate offending terminology, add alternative choices to the ``mode`` option (https://github.com/ansible-collections/community.mysql/issues/78).
Bugfixes
--------
- mysql_user - fix handling of INSERT, UPDATE, REFERENCES on columns (https://github.com/ansible-collections/community.mysql/issues/106).
- mysql_user - the module is not idempotent when SELECT on columns granted (https://github.com/ansible-collections/community.mysql/issues/99).
v1.2.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 1.1.2.
Minor Changes
-------------
- mysql_user - refactor to reduce cursor.execute() calls in preparation for adding query logging (https://github.com/ansible-collections/community.mysql/pull/76).
Bugfixes
--------
- mysql_user - add ``SHOW_ROUTINE`` privilege support (https://github.com/ansible-collections/community.mysql/issues/86).
- mysql_user - fixed creating user with encrypted password in MySQL 8.0 (https://github.com/ansible-collections/community.mysql/pull/79).
v1.1.2
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 1.1.1.
Minor Changes
-------------
- mysql_query - simple refactoring of query type check (https://github.com/ansible-collections/community.mysql/pull/58).
- mysql_user - simple refactoring of priv type check (https://github.com/ansible-collections/community.mysql/pull/58).
Bugfixes
--------
- mysql_db - fix false warning related to ``unsafe_login_password`` option (https://github.com/ansible-collections/community.mysql/issues/33).
- mysql_replication - fix crashes of mariadb >= 10.5.1 and mysql >= 8.0.22 caused by using deprecated terminology (https://github.com/ansible-collections/community.mysql/issues/70).
- mysql_user - fixed change detection when using append_privs (https://github.com/ansible-collections/community.mysql/pull/72).
v1.1.1
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 1.1.0.
Bugfixes
--------
- mysql_query - fix failing when single-row query contains commas (https://github.com/ansible-collections/community.mysql/issues/51).
v1.1.0
======
Release Summary
---------------
This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 1.0.2.
Minor Changes
-------------
- mysql modules - add the ``check_hostname`` option (https://github.com/ansible-collections/community.mysql/issues/28).
- mysql modules - patch the ``Connection`` class to add a destructor that ensures connections to the server are explicitly closed (https://github.com/ansible-collections/community.mysql/pull/44).
Bugfixes
--------
- mysql modules - fix crash when ``!includedir`` option is in config file (https://github.com/ansible-collections/community.mysql/issues/46).
v1.0.2
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 1.0.1.
Bugfixes
--------
- mysql_user - fix module's crash when modifying a user with ``host_all`` (https://github.com/ansible-collections/community.mysql/issues/39).
v1.0.1
======
Release Summary
---------------
This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that have been added after the release of ``community.mysql`` 1.0.0.
Bugfixes
--------
- mysql_db - fix false warning related to ``unsafe_login_password`` option (https://github.com/ansible-collections/community.mysql/issues/33).
- mysql_user - added tests to verify that TLS requirements are removed with an empty ``tls_requires`` option (https://github.com/ansible-collections/community.mysql/issues/20).
- mysql_user - correct procedure to check existing TLS requirements (https://github.com/ansible-collections/community.mysql/pull/26).
- mysql_user - minor syntax fixes (https://github.com/ansible-collections/community.mysql/pull/26).
v1.0.0
======
Release Summary
---------------
This is the first proper release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that were added after the release of Ansible 2.9.0.
Minor Changes
-------------
- mysql_db - add ``master_data`` parameter (https://github.com/ansible/ansible/pull/66048).
- mysql_db - add ``skip_lock_tables`` option (https://github.com/ansible/ansible/pull/66688).
- mysql_db - add the ``check_implicit_admin`` parameter (https://github.com/ansible/ansible/issues/24418).
- mysql_db - add the ``dump_extra_args`` parameter (https://github.com/ansible/ansible/pull/67747).
- mysql_db - add the ``executed_commands`` returned value (https://github.com/ansible/ansible/pull/65498).
- mysql_db - add the ``force`` parameter (https://github.com/ansible/ansible/pull/65547).
- mysql_db - add the ``restrict_config_file`` parameter (https://github.com/ansible/ansible/issues/34488).
- mysql_db - add the ``unsafe_login_password`` parameter (https://github.com/ansible/ansible/issues/63955).
- mysql_db - add the ``use_shell`` parameter (https://github.com/ansible/ansible/issues/20196).
- mysql_info - add ``exclude_fields`` parameter (https://github.com/ansible/ansible/issues/63319).
- mysql_info - add ``global_status`` filter parameter option and return (https://github.com/ansible/ansible/pull/63189).
- mysql_info - add ``return_empty_dbs`` parameter to list empty databases (https://github.com/ansible/ansible/issues/65727).
- mysql_replication - add ``channel`` parameter (https://github.com/ansible/ansible/issues/29311).
- mysql_replication - add ``connection_name`` parameter (https://github.com/ansible/ansible/issues/46243).
- mysql_replication - add ``fail_on_error`` parameter (https://github.com/ansible/ansible/pull/66252).
- mysql_replication - add ``master_delay`` parameter (https://github.com/ansible/ansible/issues/51326).
- mysql_replication - add ``master_use_gtid`` parameter (https://github.com/ansible/ansible/pull/62648).
- mysql_replication - add ``queries`` return value (https://github.com/ansible/ansible/pull/63036).
- mysql_replication - add support of ``resetmaster`` choice to ``mode`` parameter (https://github.com/ansible/ansible/issues/42870).
- mysql_user - ``priv`` parameter can be string or dictionary (https://github.com/ansible/ansible/issues/57533).
- mysql_user - add TLS REQUIRES parameters (https://github.com/ansible-collections/community.mysql/pull/9).
- mysql_user - add ``plugin_auth_string`` parameter (https://github.com/ansible/ansible/pull/44267).
- mysql_user - add ``plugin_hash_string`` parameter (https://github.com/ansible/ansible/pull/44267).
- mysql_user - add ``plugin`` parameter (https://github.com/ansible/ansible/pull/44267).
- mysql_user - add the resource_limits parameter (https://github.com/ansible-collections/community.general/issues/133).
- mysql_variables - add ``mode`` parameter (https://github.com/ansible/ansible/issues/60119).
Bugfixes
--------
- mysql - dont mask ``mysql_connect`` function errors from modules (https://github.com/ansible/ansible/issues/64560).
- mysql_db - fix Broken pipe error appearance when state is import and the target file is compressed (https://github.com/ansible/ansible/issues/20196).
- mysql_db - fix bug in the ``db_import`` function introduced by https://github.com/ansible/ansible/pull/56721 (https://github.com/ansible/ansible/issues/65351).
- mysql_info - add parameter for __collect to get only what are wanted (https://github.com/ansible-collections/community.general/pull/136).
- mysql_replication - allow to pass empty values to parameters (https://github.com/ansible/ansible/issues/23976).
- mysql_user - Fix idempotence when long grant lists are used (https://github.com/ansible/ansible/issues/68044)
- mysql_user - Remove false positive ``no_log`` warning for ``update_password`` option
- mysql_user - add ``INVOKE LAMBDA`` privilege support (https://github.com/ansible-collections/community.general/issues/283).
- mysql_user - add missed privileges to support (https://github.com/ansible-collections/community.general/issues/617).
- mysql_user - fix ``host_all`` arguments conversion string formatting error (https://github.com/ansible/ansible/issues/29644).
- mysql_user - fix overriding password to the same (https://github.com/ansible-collections/community.general/issues/543).
- mysql_user - fix support privileges with underscore (https://github.com/ansible/ansible/issues/66974).
- mysql_user - fix the error No database selected (https://github.com/ansible/ansible/issues/68070).
- mysql_user - make sure current_pass_hash is a string before using it in comparison (https://github.com/ansible/ansible/issues/60567).
- mysql_variable - fix the module doesn't support variables name with dot (https://github.com/ansible/ansible/issues/54239).

View file

@ -235,3 +235,308 @@ releases:
- 107-mysql_user_fix_grant_on_col_handling.yml
- 97-mysql_replication_deprecate_offending_terminology.yml
release_date: '2021-03-08'
2.0.0:
changes:
bugfixes:
- mysql_user - add support for ``REPLICA MONITOR`` privilege (https://github.com/ansible-collections/community.mysql/issues/105).
major_changes:
- mysql_replication - the return value ``Is_Slave`` and ``Is_Master`` will be
replaced with ``Is_Replica`` and ``Is_Primary`` in ``community.mysql`` 3.0.0
(https://github.com/ansible-collections/community.mysql/issues/145).
- mysql_replication - the word ``master`` in messages returned by the module
will be replaced with ``primary`` in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/145).
- mysql_replication - the word ``slave`` in messages returned by the module
replaced with ``replica`` (https://github.com/ansible-collections/community.mysql/issues/98).
- mysql_user - the ``REQUIRESSL`` is an alias for the ``ssl`` key in the ``tls_requires``
option in ``community.mysql`` 2.0.0 and support will be dropped altogether
in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/121).
minor_changes:
- mysql module utils - change deprecated connection parameters ``passwd`` and
``db`` to ``password`` and ``database`` (https://github.com/ansible-collections/community.mysql/pull/116).
- mysql_collection - introduce codebabse split to handle divergences between
MySQL and MariaDB (https://github.com/ansible-collections/community.mysql/pull/103).
- mysql_info - add `version.full` and `version.suffix` return values (https://github.com/ansible-collections/community.mysql/issues/114).
- mysql_user - deprecate the ``REQUIRESSL`` privilege (https://github.com/ansible-collections/community.mysql/issues/101).
release_summary: This is release 2.0.0 of the ``community.mysql`` collection,
released on 2021-04-15.
fragments:
- 101-drop-requiressl-support.yml
- 103-mysql_and_mariadb_divergence.yml
- 108-mysql_priv_add_grant.yml
- 115-add_mysql_full_version_suffix_return_var.yml
- 116-change_deprecated_connection_ parameters.yml
- 144-mysql_replication_remove_slave_from_messages.yml
- 2.0.0.yml
release_date: '2021-04-15'
2.1.0:
changes:
bugfixes:
- mysql - revert changes of connector arguments made in pull request 116 causing
the invalid keyword argument error (https://github.com/ansible-collections/community.mysql/pull/116).
major_changes:
- mysql_replication - add deprecation warning that the ``Is_Slave`` and ``Is_Master``
return values will be replaced with ``Is_Primary`` and ``Is_Replica`` in ``community.mysql``
3.0.0 (https://github.com/ansible-collections/community.mysql/pull/147).
- mysql_replication - the choices of the ``state`` option containing ``master``
will be finally replaced with the alternative ``primary`` choices in ``community.mysql``
3.0.0, add deprecation warnings (https://github.com/ansible-collections/community.mysql/pull/150).
minor_changes:
- mysql_replication - add alternative (``primary``) choices to the ``state``
option choices containing ``master`` (https://github.com/ansible-collections/community.mysql/pull/150).
- mysql_replication - add the ``Is_Primary`` and ``Is_Replica`` alternatives
to the ``Is_Slave`` and ``Is_Master`` return values as a preparation for replacement
in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/pull/147).
- mysql_replication - change ``master_`` options to ``primary_`` options, add
aliases to keep compatibility (https://github.com/ansible-collections/community.mysql/pull/150).
release_summary: 'This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.0.0.'
fragments:
- 147-mysql_replication_deprecate_ret_vals.yml
- 150-mysql_replication_master_related.yml
- 153-mysql_revert_connector_changes.yml
release_date: '2021-04-23'
2.1.1:
changes:
minor_changes:
- mysql_query - correctly reflect changed status in replace statements (https://github.com/ansible-collections/community.mysql/pull/193).
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.1.0.'
fragments:
- 193-reflect_changed_status_in_replace_statements.yml
- 2.1.1.yml
release_date: '2021-08-11'
2.2.0:
changes:
release_summary: 'This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.1.1'
fragments:
- 2.2.0.yml
release_date: '2021-09-23'
2.2.0-a1:
changes:
release_summary: 'This is the minor pre-release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.1.1'
fragments:
- 2.2.0-a1.yml
modules:
- description: Adds, removes, or updates a MySQL role
name: mysql_role
namespace: ''
release_date: '2021-08-11'
2.3.0:
changes:
bugfixes:
- mysql_info - fix TypeError failure when there are databases that do not contain
tables (https://github.com/ansible-collections/community.mysql/issues/204).
minor_changes:
- mysql_user - replace VALID_PRIVS constant by get_valid_privs() function (https://github.com/ansible-collections/community.mysql/pull/217).
release_summary: 'This is the minor release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.2.0.'
fragments:
- 2.3.0.yml
- 205-mysql_info_fix_failure_when_no_tables_in_db.yml
- 217-mysql-user-replace-get-valid-privs-from-show-privilegees.yml
release_date: '2021-09-23'
2.3.1:
changes:
bugfixes:
- mysql_user - Fix crash reporting ``Invalid privileges specified`` when passing
privileges that became aliases (https://github.com/ansible-collections/community.mysql/issues/232).
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.0.'
fragments:
- 2.3.1.yml
- 233-mysql_user_return_valid_privs.yml
release_date: '2021-10-19'
2.3.2:
changes:
bugfixes:
- mysql_db - Fix mismatch when database name contains a ``%`` character (https://github.com/ansible-collections/community.mysql/pull/227).
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.1.'
fragments:
- 2.3.2.yml
- 227-db-create-special-name.yaml
release_date: '2021-11-29'
2.3.3:
changes:
bugfixes:
- Collection core functions - use vendored version of ``distutils.version``
instead of the deprecated Python standard library ``distutils`` (https://github.com/ansible-collections/community.mysql/pull/269).
release_summary: This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.2.
fragments:
- 2.3.3.yml
- 267-prepare_for_distutils_be_removed.yml
release_date: '2022-01-18'
2.3.4:
changes:
bugfixes:
- mysql_role - make the ``set_default_role_all`` parameter actually working
(https://github.com/ansible-collections/community.mysql/pull/282).
release_summary: This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.3.
fragments:
- 2.3.4.yml
- 282-mysql_role_fix_set_default_role_all_argument.yml
release_date: '2022-02-16'
2.3.5:
changes:
bugfixes:
- Collection core functions - fixes related to the mysqlclient Python connector
(https://github.com/ansible-collections/community.mysql/issues/292).
release_summary: This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection that
have been added after the release of ``community.mysql`` 2.3.4.
fragments:
- 0-mysqlclient.yml
- 2.3.5.yml
release_date: '2022-03-14'
2.3.6:
changes:
bugfixes:
- mysql_role - remove redundant connection closing (https://github.com/ansible-collections/community.mysql/pull/330).
- mysql_user - fix missing dynamic privileges after revoke and grant privileges
to user (https://github.com/ansible-collections/community.mysql/issues/120).
- mysql_user - fix parsing privs when a user has roles assigned (https://github.com/ansible-collections/community.mysql/issues/231).
- 'mysql_user - fix the possibility for a race condition that breaks certain
(circular) replication configurations when ``DROP USER`` is executed on multiple
nodes in the replica set. Adding ``IF EXISTS`` avoids the need to use ``sql_log_bin:
no`` making the statement always replication safe (https://github.com/ansible-collections/community.mysql/pull/287).'
major_changes:
- The community.mysql collection no longer supports ``Ansible 2.9`` and ``ansible-base
2.10``. While we take no active measures to prevent usage and there are no
plans to introduce incompatible code to the modules, we will stop testing
against ``Ansible 2.9`` and ``ansible-base 2.10``. Both will very soon be
End of Life and if you are still using them, you should consider upgrading
to the ``latest Ansible / ansible-core 2.11 or later`` as soon as possible
(https://github.com/ansible-collections/community.mysql/pull/343).
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.5.'
fragments:
- 001-mysql_user_fix_pars_users_with_roles_assigned.yml
- 2.3.6.yml
- 307-mysql_user_add_if_exists_to_drop.yml
- 329-mysql_role-remove-redudant-connection-closing.yml
- 338-mysql_user_fix_missing_dynamic_privileges.yml
- drop_support_of_2.9-2.10.yml
release_date: '2022-05-13'
2.3.7:
changes:
bugfixes:
- Include ``PSF-license.txt`` file for ``plugins/module_utils/_version.py``.
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.6.'
fragments:
- 2.3.7.yml
- psf-license.yml
release_date: '2022-05-17'
2.3.8:
changes:
bugfixes:
- mysql_query - fix false change reports when ``IF EXISTS/IF NOT EXISTS`` clause
is used (https://github.com/ansible-collections/community.mysql/issues/268).
- 'mysql_role - don''t add members to a role when creating the role and ``detach_members:
true`` is set (https://github.com/ansible-collections/community.mysql/pull/367).'
- 'mysql_role - in some cases (when "SHOW GRANTS" did not use backticks for
quotes), no unwanted members were detached from the role (and redundant "GRANT"
statements were executed for wanted members). This is fixed by querying the
existing role members from the mysql.role_edges (MySQL) or mysql.roles_mapping
(MariaDB) tables instead of parsing the "SHOW GRANTS" output (https://github.com/ansible-collections/community.mysql/pull/368).
'
- mysql_user - fix logic when ``update_password`` is set to ``on_create`` for
users using ``plugin*`` arguments (https://github.com/ansible-collections/community.mysql/issues/334).
The ``on_create`` sets ``password`` to None for old mysql_native_authentication
but not for authentiation methods which uses the ``plugin*`` arguments. This
PR changes this so ``on_create`` also exchange ``plugin``, ``plugin_hash_string``,
``plugin_auth_string`` to None in the list of arguments to change
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.7.'
fragments:
- 2.3.8.yml
- 322-mysql_query_fix_false_change_report.yml
- 334-mysql_user_fix_logic_on_oncreate.yml
- 367-mysql_role-fix-deatch-members.yml
- 368-mysql_role-fix-member-detection.yml
release_date: '2022-06-02'
2.3.9:
changes:
bugfixes:
- Include ``simplified_bsd.txt`` license file for various module utils.
release_summary: 'This is the patch release of the ``community.mysql`` collection.
This changelog contains all changes to the modules in this collection
that have been added after the release of ``community.mysql`` 2.3.8.'
fragments:
- 2.3.9.yml
- simplified-bsd-license.yml
release_date: '2022-08-02'
2.4.0:
changes:
minor_changes:
- mysql_info - add ``connector_name`` and ``connector_version`` to returned
values (https://github.com/ansible-collections/community.mysql/pull/497).
release_summary: 'This is a bugfix release of the ``community.mysql`` collection.
This changelog contains all changes to the modules and plugins in this collection
that have been made after the previous release.'
fragments:
- 2.3.11.yml
- 497_mysql_info_returns_connector_name_and_version.yml
release_date: '2023-02-08'
2.4.1:
changes:
release_summary: Maintenance release of ``community.mysql`` major version 2.
Only contains changes to the CI. There is no functional difference between
2.4.0 and 2.4.1.
fragments:
- 2.4.1.yml
- 490_refactor_integration_tests.yml
release_date: '2023-05-04'
2.4.2:
changes:
major_changes:
- Collection version 2.*.* is EOL, no more bugfixes will be backported. Please
consider upgrading to the latest version.
release_summary: Maintenance release of ``community.mysql`` to inform users
that the collection version 2 is EOL. There were no functional changes made
in this release.
fragments:
- 0-stable-2-eol.yml
- 2.4.2.yml
release_date: '2024-01-22'

View file

@ -1,4 +1,4 @@
changelog_filename_template: CHANGELOG.rst
changelog_filename_template: ../CHANGELOG.rst
changelog_filename_version_depth: 0
changes_file: changelog.yaml
changes_format: combined

View file

@ -1,4 +0,0 @@
minor_changes:
- mysql_user - deprecate the ``REQUIRESSL`` privilege (https://github.com/ansible-collections/community.mysql/issues/101).
major_changes:
- mysql_user - the ``REQUIRESSL`` is an alias for the ``ssl`` key in the ``tls_requires`` option in ``community.mysql`` 2.0.0 and support will be dropped altogether in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/121).

View file

@ -1,2 +0,0 @@
minor_changes:
- mysql_collection - introduce codebabse split to handle divergences between MySQL and MariaDB (https://github.com/ansible-collections/community.mysql/pull/103).

View file

@ -1,2 +0,0 @@
bugfixes:
- mysql_user - add support for ``REPLICA MONITOR`` privilege (https://github.com/ansible-collections/community.mysql/issues/105).

View file

@ -1,2 +0,0 @@
minor_changes:
- mysql_info - add `version.full` and `version.suffix` return values (https://github.com/ansible-collections/community.mysql/issues/114).

View file

@ -1,2 +0,0 @@
minor_changes:
- mysql module utils - change deprecated connection parameters ``passwd`` and ``db`` to ``password`` and ``database`` (https://github.com/ansible-collections/community.mysql/pull/116).

View file

@ -1,4 +0,0 @@
major_changes:
- mysql_replication - the word ``slave`` in messages returned by the module replaced with ``replica`` (https://github.com/ansible-collections/community.mysql/issues/98).
- mysql_replication - the return value ``Is_Slave`` and ``Is_Master`` will be replaced with ``Is_Replica`` and ``Is_Primary`` in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/145).
- mysql_replication - the word ``master`` in messages returned by the module will be replaced with ``primary`` in ``community.mysql`` 3.0.0 (https://github.com/ansible-collections/community.mysql/issues/145).

View file

@ -1,6 +1,6 @@
namespace: community
name: mysql
version: 1.3.0
version: 2.4.2
readme: README.md
authors:
- Ansible community

View file

@ -35,6 +35,7 @@ options:
login_unix_socket:
description:
- The path to a Unix domain socket for local connections.
- Use this parameter to avoid the C(Please explicitly state intended protocol) error.
type: str
connect_timeout:
description:
@ -44,6 +45,9 @@ options:
config_file:
description:
- Specify a config file from which user and password are to be read.
- The default config file, C(~/.my.cnf), if it exists, will be read, even if I(config_file) is not specified.
- The default config file, C(~/.my.cnf), if it exists, must contain a C([client]) section as a MySQL connector requirement.
- To prevent the default config file from being read, set I(config_file) to be an empty string.
type: path
default: '~/.my.cnf'
ca_cert:
@ -67,21 +71,25 @@ options:
- Whether to validate the server host name when an SSL connection is required. Corresponds to MySQL CLIs C(--ssl) switch.
- Setting this to C(false) disables hostname verification. Use with caution.
- Requires pymysql >= 0.7.11.
- This optoin has no effect on MySQLdb.
- This option has no effect on MySQLdb.
type: bool
version_added: '1.1.0'
requirements:
- PyMySQL (Python 2.7 and Python 3.X), or
- mysqlclient (Python 3.5+) or
- PyMySQL (Python 2.7 and Python 3.x) or
- MySQLdb (Python 2.x)
notes:
- Requires the PyMySQL (Python 2.7 and Python 3.X) or MySQL-python (Python 2.X) package installed on the remote host.
The Python package may be installed with apt-get install python-pymysql (Ubuntu; see M(ansible.builtin.apt)) or
yum install python2-PyMySQL (RHEL/CentOS/Fedora; see M(ansible.builtin.yum)). You can also use dnf install python2-PyMySQL
for newer versions of Fedora; see M(ansible.builtin.dnf).
- Be sure you have PyMySQL or MySQLdb library installed on the target machine
for the Python interpreter Ansible uses, for example, if it is Python 3,
you must install the library for Python 3. You can also change the interpreter.
For more information, see U(https://docs.ansible.com/ansible/latest/reference_appendices/interpreter_discovery.html).
- Be sure you have mysqlclient, PyMySQL, or MySQLdb library installed on the target machine
for the Python interpreter Ansible discovers. For example if ansible discovers and uses Python 3, you need to install
the Python 3 version of PyMySQL or mysqlclient. If ansible discovers and uses Python 2, you need to install the Python 2
version of either PyMySQL or MySQL-python.
- If you have trouble, it may help to force Ansible to use the Python interpreter you need by specifying
C(ansible_python_interpreter). For more information, see
U(https://docs.ansible.com/ansible/latest/reference_appendices/interpreter_discovery.html).
- Both C(login_password) and C(login_user) are required when you are
passing credentials. If none are present, the module will attempt to read
the credentials from C(~/.my.cnf), and finally fall back to using the MySQL
@ -94,4 +102,15 @@ notes:
- Alternatively, you can use the mysqlclient library instead of MySQL-python (MySQLdb)
which supports both Python 2.X and Python >=3.5.
See U(https://pypi.org/project/mysqlclient/) how to install it.
- "If credentials from the config file (for example, C(/root/.my.cnf)) are not needed to connect to a database server, but
the file exists and does not contain a C([client]) section, before any other valid directives, it will be read and this
will cause the connection to fail, to prevent this set it to an empty string, (for example C(config_file: ''))."
- "To avoid the C(Please explicitly state intended protocol) error, use the I(login_unix_socket) argument,
for example, C(login_unix_socket: /run/mysqld/mysqld.sock)."
- Alternatively, to avoid using I(login_unix_socket) argument on each invocation you can specify the socket path
using the `socket` option in your MySQL config file (usually C(~/.my.cnf)) on the destination host, for
example C(socket=/var/lib/mysql/mysql.sock).
attributes:
check_mode:
description: Can run in check_mode and return changed status prediction without modifying target.
'''

View file

@ -0,0 +1,343 @@
# Vendored copy of distutils/version.py from CPython 3.9.5
#
# Implements multiple version numbering conventions for the
# Python Module Distribution Utilities.
#
# PSF License (see PSF-license.txt or https://opensource.org/licenses/Python-2.0)
#
"""Provides classes to represent module version numbers (one class for
each style of version numbering). There are currently two such classes
implemented: StrictVersion and LooseVersion.
Every version number class implements the following interface:
* the 'parse' method takes a string and parses it to some internal
representation; if the string is an invalid version number,
'parse' raises a ValueError exception
* the class constructor takes an optional string argument which,
if supplied, is passed to 'parse'
* __str__ reconstructs the string that was passed to 'parse' (or
an equivalent string -- ie. one that will generate an equivalent
version number instance)
* __repr__ generates Python code to recreate the version number instance
* _cmp compares the current instance with either another instance
of the same class or a string (which will be parsed to an instance
of the same class, thus must follow the same rules)
"""
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import re
try:
RE_FLAGS = re.VERBOSE | re.ASCII
except AttributeError:
RE_FLAGS = re.VERBOSE
class Version:
"""Abstract base class for version numbering classes. Just provides
constructor (__init__) and reproducer (__repr__), because those
seem to be the same for all version numbering classes; and route
rich comparisons to _cmp.
"""
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def __repr__(self):
return "%s ('%s')" % (self.__class__.__name__, str(self))
def __eq__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c == 0
def __lt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c < 0
def __le__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c <= 0
def __gt__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c > 0
def __ge__(self, other):
c = self._cmp(other)
if c is NotImplemented:
return c
return c >= 0
# Interface for version-number classes -- must be implemented
# by the following classes (the concrete ones -- Version should
# be treated as an abstract class).
# __init__ (string) - create and take same action as 'parse'
# (string parameter is optional)
# parse (string) - convert a string representation to whatever
# internal representation is appropriate for
# this style of version numbering
# __str__ (self) - convert back to a string; should be very similar
# (if not identical to) the string supplied to parse
# __repr__ (self) - generate Python code to recreate
# the instance
# _cmp (self, other) - compare two version numbers ('other' may
# be an unparsed version string, or another
# instance of your version class)
class StrictVersion(Version):
"""Version numbering for anal retentives and software idealists.
Implements the standard interface for version number classes as
described above. A version number consists of two or three
dot-separated numeric components, with an optional "pre-release" tag
on the end. The pre-release tag consists of the letter 'a' or 'b'
followed by a number. If the numeric components of two version
numbers are equal, then one with a pre-release tag will always
be deemed earlier (lesser) than one without.
The following are valid version numbers (shown in the order that
would be obtained by sorting according to the supplied cmp function):
0.4 0.4.0 (these two are equivalent)
0.4.1
0.5a1
0.5b3
0.5
0.9.6
1.0
1.0.4a3
1.0.4b1
1.0.4
The following are examples of invalid version numbers:
1
2.7.2.2
1.3.a4
1.3pl1
1.3c4
The rationale for this version numbering system will be explained
in the distutils documentation.
"""
version_re = re.compile(r'^(\d+) \. (\d+) (\. (\d+))? ([ab](\d+))?$',
RE_FLAGS)
def parse(self, vstring):
match = self.version_re.match(vstring)
if not match:
raise ValueError("invalid version number '%s'" % vstring)
(major, minor, patch, prerelease, prerelease_num) = \
match.group(1, 2, 4, 5, 6)
if patch:
self.version = tuple(map(int, [major, minor, patch]))
else:
self.version = tuple(map(int, [major, minor])) + (0,)
if prerelease:
self.prerelease = (prerelease[0], int(prerelease_num))
else:
self.prerelease = None
def __str__(self):
if self.version[2] == 0:
vstring = '.'.join(map(str, self.version[0:2]))
else:
vstring = '.'.join(map(str, self.version))
if self.prerelease:
vstring = vstring + self.prerelease[0] + str(self.prerelease[1])
return vstring
def _cmp(self, other):
if isinstance(other, str):
other = StrictVersion(other)
elif not isinstance(other, StrictVersion):
return NotImplemented
if self.version != other.version:
# numeric versions don't match
# prerelease stuff doesn't matter
if self.version < other.version:
return -1
else:
return 1
# have to compare prerelease
# case 1: neither has prerelease; they're equal
# case 2: self has prerelease, other doesn't; other is greater
# case 3: self doesn't have prerelease, other does: self is greater
# case 4: both have prerelease: must compare them!
if (not self.prerelease and not other.prerelease):
return 0
elif (self.prerelease and not other.prerelease):
return -1
elif (not self.prerelease and other.prerelease):
return 1
elif (self.prerelease and other.prerelease):
if self.prerelease == other.prerelease:
return 0
elif self.prerelease < other.prerelease:
return -1
else:
return 1
else:
raise AssertionError("never get here")
# end class StrictVersion
# The rules according to Greg Stein:
# 1) a version number has 1 or more numbers separated by a period or by
# sequences of letters. If only periods, then these are compared
# left-to-right to determine an ordering.
# 2) sequences of letters are part of the tuple for comparison and are
# compared lexicographically
# 3) recognize the numeric components may have leading zeroes
#
# The LooseVersion class below implements these rules: a version number
# string is split up into a tuple of integer and string components, and
# comparison is a simple tuple comparison. This means that version
# numbers behave in a predictable and obvious way, but a way that might
# not necessarily be how people *want* version numbers to behave. There
# wouldn't be a problem if people could stick to purely numeric version
# numbers: just split on period and compare the numbers as tuples.
# However, people insist on putting letters into their version numbers;
# the most common purpose seems to be:
# - indicating a "pre-release" version
# ('alpha', 'beta', 'a', 'b', 'pre', 'p')
# - indicating a post-release patch ('p', 'pl', 'patch')
# but of course this can't cover all version number schemes, and there's
# no way to know what a programmer means without asking him.
#
# The problem is what to do with letters (and other non-numeric
# characters) in a version number. The current implementation does the
# obvious and predictable thing: keep them as strings and compare
# lexically within a tuple comparison. This has the desired effect if
# an appended letter sequence implies something "post-release":
# eg. "0.99" < "0.99pl14" < "1.0", and "5.001" < "5.001m" < "5.002".
#
# However, if letters in a version number imply a pre-release version,
# the "obvious" thing isn't correct. Eg. you would expect that
# "1.5.1" < "1.5.2a2" < "1.5.2", but under the tuple/lexical comparison
# implemented here, this just isn't so.
#
# Two possible solutions come to mind. The first is to tie the
# comparison algorithm to a particular set of semantic rules, as has
# been done in the StrictVersion class above. This works great as long
# as everyone can go along with bondage and discipline. Hopefully a
# (large) subset of Python module programmers will agree that the
# particular flavour of bondage and discipline provided by StrictVersion
# provides enough benefit to be worth using, and will submit their
# version numbering scheme to its domination. The free-thinking
# anarchists in the lot will never give in, though, and something needs
# to be done to accommodate them.
#
# Perhaps a "moderately strict" version class could be implemented that
# lets almost anything slide (syntactically), and makes some heuristic
# assumptions about non-digits in version number strings. This could
# sink into special-case-hell, though; if I was as talented and
# idiosyncratic as Larry Wall, I'd go ahead and implement a class that
# somehow knows that "1.2.1" < "1.2.2a2" < "1.2.2" < "1.2.2pl3", and is
# just as happy dealing with things like "2g6" and "1.13++". I don't
# think I'm smart enough to do it right though.
#
# In any case, I've coded the test suite for this module (see
# ../test/test_version.py) specifically to fail on things like comparing
# "1.2a2" and "1.2". That's not because the *code* is doing anything
# wrong, it's because the simple, obvious design doesn't match my
# complicated, hairy expectations for real-world version numbers. It
# would be a snap to fix the test suite to say, "Yep, LooseVersion does
# the Right Thing" (ie. the code matches the conception). But I'd rather
# have a conception that matches common notions about version numbers.
class LooseVersion(Version):
"""Version numbering for anarchists and software realists.
Implements the standard interface for version number classes as
described above. A version number consists of a series of numbers,
separated by either periods or strings of letters. When comparing
version numbers, the numeric components will be compared
numerically, and the alphabetic components lexically. The following
are all valid version numbers, in no particular order:
1.5.1
1.5.2b2
161
3.10a
8.02
3.4j
1996.07.12
3.2.pl0
3.1.1.6
2g6
11g
0.960923
2.2beta29
1.13++
5.5.kw
2.0b1pl0
In fact, there is no such thing as an invalid version number under
this scheme; the rules for comparison are simple and predictable,
but may not always give the results you want (for some definition
of "want").
"""
component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
def __init__(self, vstring=None):
if vstring:
self.parse(vstring)
def parse(self, vstring):
# I've given up on thinking I can reconstruct the version string
# from the parsed tuple -- so I just store the string here for
# use by __str__
self.vstring = vstring
components = [x for x in self.component_re.split(vstring) if x and x != '.']
for i, obj in enumerate(components):
try:
components[i] = int(obj)
except ValueError:
pass
self.version = components
def __str__(self):
return self.vstring
def __repr__(self):
return "LooseVersion ('%s')" % str(self)
def _cmp(self, other):
if isinstance(other, str):
other = LooseVersion(other)
elif not isinstance(other, LooseVersion):
return NotImplemented
if self.version == other.version:
return 0
if self.version < other.version:
return -1
if self.version > other.version:
return 1
# end class LooseVersion

View file

@ -6,7 +6,7 @@
#
# Copyright (c) 2014, Toshio Kuratomi <tkuratomi@ansible.com>
#
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

View file

@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version
from distutils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.version import LooseVersion
def uses_replica_terminology(cursor):

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible_collections.community.mysql.plugins.module_utils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version
def supports_roles(cursor):
version = get_server_version(cursor)
return LooseVersion(version) >= LooseVersion('10.0.5')
def is_mariadb():
return True

View file

@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from distutils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version

View file

@ -1,8 +1,12 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version
from distutils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.version import LooseVersion
def uses_replica_terminology(cursor):

View file

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible_collections.community.mysql.plugins.module_utils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version
def supports_roles(cursor):
version = get_server_version(cursor)
return LooseVersion(version) >= LooseVersion('8')
def is_mariadb():
return False

View file

@ -1,7 +1,11 @@
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from distutils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.version import LooseVersion
from ansible_collections.community.mysql.plugins.module_utils.mysql import get_server_version

View file

@ -7,7 +7,7 @@
# Copyright (c), Jonathan Mainguy <jon@soh.re>, 2015
# Most of this was originally added by Sven Schliesing @muffl0n in the mysql_user.py module
#
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import (absolute_import, division, print_function)
from functools import reduce
@ -23,13 +23,54 @@ try:
_mysql_cursor_param = 'cursor'
except ImportError:
try:
# mysqlclient is called MySQLdb
import MySQLdb as mysql_driver
import MySQLdb.cursors
_mysql_cursor_param = 'cursorclass'
except ImportError:
mysql_driver = None
mysql_driver_fail_msg = 'The PyMySQL (Python 2.7 and Python 3.X) or MySQL-python (Python 2.X) module is required.'
mysql_driver_fail_msg = ('A MySQL module is required: for Python 2.7 either PyMySQL, or '
'MySQL-python, or for Python 3.X mysqlclient or PyMySQL. '
'Consider setting ansible_python_interpreter to use '
'the intended Python version.')
def get_connector_name(connector):
""" (class) -> str
Return the name of the connector (pymysql or mysqlclient (MySQLdb))
or 'Unknown' if not pymysql or MySQLdb. When adding a
connector here, also modify get_connector_version.
"""
if connector is None or not hasattr(connector, '__name__'):
return 'Unknown'
return connector.__name__
def get_connector_version(connector):
""" (class) -> str
Return the version of pymysql or mysqlclient (MySQLdb).
Return 'Unknown' if the connector name is unknown.
"""
if connector is None:
return 'Unknown'
connector_name = get_connector_name(connector)
if connector_name == 'pymysql':
# pymysql has two methods:
# - __version__ that returns the string: 0.7.11.None
# - VERSION that returns the tuple (0, 7, 11, None)
v = connector.VERSION[:3]
return '.'.join(map(str, v))
elif connector_name == 'MySQLdb':
# version_info returns the tuple (2, 1, 1, 'final', 0)
v = connector.version_info[:3]
return '.'.join(map(str, v))
else:
return 'Unknown'
def parse_from_mysql_config_file(cnf):
@ -79,7 +120,7 @@ def mysql_connect(module, login_user=None, login_password=None, config_file='',
if login_user is not None:
config['user'] = login_user
if login_password is not None:
config['password'] = login_password
config['passwd'] = login_password
if ssl_cert is not None:
config['ssl']['cert'] = ssl_cert
if ssl_key is not None:
@ -87,7 +128,7 @@ def mysql_connect(module, login_user=None, login_password=None, config_file='',
if ssl_ca is not None:
config['ssl']['ca'] = ssl_ca
if db is not None:
config['database'] = db
config['db'] = db
if connect_timeout is not None:
config['connect_timeout'] = connect_timeout
if check_hostname is not None:

View file

@ -0,0 +1,907 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Simplified BSD License (see simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
import string
import re
from ansible.module_utils.six import iteritems
from ansible_collections.community.mysql.plugins.module_utils.mysql import (
mysql_driver,
)
EXTRA_PRIVS = ['ALL', 'ALL PRIVILEGES', 'GRANT', 'REQUIRESSL']
# This list is kept for backwards compatibility after release 2.3.0,
# see https://github.com/ansible-collections/community.mysql/issues/232 for details
VALID_PRIVS = [
'CREATE', 'DROP', 'GRANT', 'GRANT OPTION',
'LOCK TABLES', 'REFERENCES', 'EVENT', 'ALTER',
'DELETE', 'INDEX', 'INSERT', 'SELECT', 'UPDATE',
'CREATE TEMPORARY TABLES', 'TRIGGER', 'CREATE VIEW',
'SHOW VIEW', 'ALTER ROUTINE', 'CREATE ROUTINE',
'EXECUTE', 'FILE', 'CREATE TABLESPACE', 'CREATE USER',
'PROCESS', 'PROXY', 'RELOAD', 'REPLICATION CLIENT',
'REPLICATION SLAVE', 'SHOW DATABASES', 'SHUTDOWN',
'SUPER', 'ALL', 'ALL PRIVILEGES', 'USAGE',
'REQUIRESSL', # Deprecated, to be removed in version 3.0.0
'CREATE ROLE', 'DROP ROLE', 'APPLICATION_PASSWORD_ADMIN',
'AUDIT_ADMIN', 'BACKUP_ADMIN', 'BINLOG_ADMIN',
'BINLOG_ENCRYPTION_ADMIN', 'CLONE_ADMIN', 'CONNECTION_ADMIN',
'ENCRYPTION_KEY_ADMIN', 'FIREWALL_ADMIN', 'FIREWALL_USER',
'GROUP_REPLICATION_ADMIN', 'INNODB_REDO_LOG_ARCHIVE',
'NDB_STORED_USER', 'PERSIST_RO_VARIABLES_ADMIN',
'REPLICATION_APPLIER', 'REPLICATION_SLAVE_ADMIN',
'RESOURCE_GROUP_ADMIN', 'RESOURCE_GROUP_USER',
'ROLE_ADMIN', 'SESSION_VARIABLES_ADMIN', 'SET_USER_ID',
'SYSTEM_USER', 'SYSTEM_VARIABLES_ADMIN', 'SYSTEM_USER',
'TABLE_ENCRYPTION_ADMIN', 'VERSION_TOKEN_ADMIN',
'XA_RECOVER_ADMIN', 'LOAD FROM S3', 'SELECT INTO S3',
'INVOKE LAMBDA',
'ALTER ROUTINE',
'BINLOG ADMIN',
'BINLOG MONITOR',
'BINLOG REPLAY',
'CONNECTION ADMIN',
'READ_ONLY ADMIN',
'REPLICATION MASTER ADMIN',
'REPLICATION SLAVE ADMIN',
'SET USER',
'SHOW_ROUTINE',
'SLAVE MONITOR',
'REPLICA MONITOR',
]
class InvalidPrivsError(Exception):
pass
def get_mode(cursor):
cursor.execute('SELECT @@GLOBAL.sql_mode')
result = cursor.fetchone()
mode_str = result[0]
if 'ANSI' in mode_str:
mode = 'ANSI'
else:
mode = 'NOTANSI'
return mode
def user_exists(cursor, user, host, host_all):
if host_all:
cursor.execute("SELECT count(*) FROM mysql.user WHERE user = %s", (user,))
else:
cursor.execute("SELECT count(*) FROM mysql.user WHERE user = %s AND host = %s", (user, host))
count = cursor.fetchone()
return count[0] > 0
def sanitize_requires(tls_requires):
sanitized_requires = {}
if tls_requires:
for key in tls_requires.keys():
sanitized_requires[key.upper()] = tls_requires[key]
if any(key in ["CIPHER", "ISSUER", "SUBJECT"] for key in sanitized_requires.keys()):
sanitized_requires.pop("SSL", None)
sanitized_requires.pop("X509", None)
return sanitized_requires
if "X509" in sanitized_requires.keys():
sanitized_requires = "X509"
else:
sanitized_requires = "SSL"
return sanitized_requires
return None
def mogrify_requires(query, params, tls_requires):
if tls_requires:
if isinstance(tls_requires, dict):
k, v = zip(*tls_requires.items())
requires_query = " AND ".join(("%s %%s" % key for key in k))
params += v
else:
requires_query = tls_requires
query = " REQUIRE ".join((query, requires_query))
return query, params
def do_not_mogrify_requires(query, params, tls_requires):
return query, params
def get_tls_requires(cursor, user, host):
if user:
if not impl.use_old_user_mgmt(cursor):
query = "SHOW CREATE USER '%s'@'%s'" % (user, host)
else:
query = "SHOW GRANTS for '%s'@'%s'" % (user, host)
cursor.execute(query)
require_list = [tuple[0] for tuple in filter(lambda x: "REQUIRE" in x[0], cursor.fetchall())]
require_line = require_list[0] if require_list else ""
pattern = r"(?<=\bREQUIRE\b)(.*?)(?=(?:\bPASSWORD\b|$))"
requires_match = re.search(pattern, require_line)
requires = requires_match.group().strip() if requires_match else ""
if any((requires.startswith(req) for req in ('SSL', 'X509', 'NONE'))):
requires = requires.split()[0]
if requires == 'NONE':
requires = None
else:
import shlex
items = iter(shlex.split(requires))
requires = dict(zip(items, items))
return requires or None
def get_valid_privs(cursor):
cursor.execute("SHOW PRIVILEGES")
show_privs = [priv[0].upper() for priv in cursor.fetchall()]
# See the comment above VALID_PRIVS declaration
all_privs = show_privs + EXTRA_PRIVS + VALID_PRIVS
return frozenset(all_privs)
def get_grants(cursor, user, host):
cursor.execute("SHOW GRANTS FOR %s@%s", (user, host))
grants_line = list(filter(lambda x: "ON *.*" in x[0], cursor.fetchall()))[0]
pattern = r"(?<=\bGRANT\b)(.*?)(?=(?:\bON\b))"
grants = re.search(pattern, grants_line[0]).group().strip()
return grants.split(", ")
def user_add(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, new_priv,
tls_requires, check_mode):
# we cannot create users without a proper hostname
if host_all:
return False
if check_mode:
return True
# Determine what user management method server uses
old_user_mgmt = impl.use_old_user_mgmt(cursor)
mogrify = do_not_mogrify_requires if old_user_mgmt else mogrify_requires
if password and encrypted:
if impl.supports_identified_by_password(cursor):
query_with_args = "CREATE USER %s@%s IDENTIFIED BY PASSWORD %s", (user, host, password)
else:
query_with_args = "CREATE USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, password)
elif password and not encrypted:
if old_user_mgmt:
query_with_args = "CREATE USER %s@%s IDENTIFIED BY %s", (user, host, password)
else:
cursor.execute("SELECT CONCAT('*', UCASE(SHA1(UNHEX(SHA1(%s)))))", (password,))
encrypted_password = cursor.fetchone()[0]
query_with_args = "CREATE USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, encrypted_password)
elif plugin and plugin_hash_string:
query_with_args = "CREATE USER %s@%s IDENTIFIED WITH %s AS %s", (user, host, plugin, plugin_hash_string)
elif plugin and plugin_auth_string:
query_with_args = "CREATE USER %s@%s IDENTIFIED WITH %s BY %s", (user, host, plugin, plugin_auth_string)
elif plugin:
query_with_args = "CREATE USER %s@%s IDENTIFIED WITH %s", (user, host, plugin)
else:
query_with_args = "CREATE USER %s@%s", (user, host)
query_with_args_and_tls_requires = query_with_args + (tls_requires,)
cursor.execute(*mogrify(*query_with_args_and_tls_requires))
if new_priv is not None:
for db_table, priv in iteritems(new_priv):
privileges_grant(cursor, user, host, db_table, priv, tls_requires)
if tls_requires is not None:
privileges_grant(cursor, user, host, "*.*", get_grants(cursor, user, host), tls_requires)
return True
def is_hash(password):
ishash = False
if len(password) == 41 and password[0] == '*':
if frozenset(password[1:]).issubset(string.hexdigits):
ishash = True
return ishash
def user_mod(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, new_priv,
append_privs, tls_requires, module, role=False, maria_role=False):
changed = False
msg = "User unchanged"
grant_option = False
# Determine what user management method server uses
old_user_mgmt = impl.use_old_user_mgmt(cursor)
if host_all and not role:
hostnames = user_get_hostnames(cursor, user)
else:
hostnames = [host]
for host in hostnames:
# Handle clear text and hashed passwords.
if not role:
if bool(password):
# Get a list of valid columns in mysql.user table to check if Password and/or authentication_string exist
cursor.execute("""
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME IN ('Password', 'authentication_string')
ORDER BY COLUMN_NAME DESC LIMIT 1
""")
colA = cursor.fetchone()
cursor.execute("""
SELECT COLUMN_NAME FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME IN ('Password', 'authentication_string')
ORDER BY COLUMN_NAME ASC LIMIT 1
""")
colB = cursor.fetchone()
# Select hash from either Password or authentication_string, depending which one exists and/or is filled
cursor.execute("""
SELECT COALESCE(
CASE WHEN %s = '' THEN NULL ELSE %s END,
CASE WHEN %s = '' THEN NULL ELSE %s END
)
FROM mysql.user WHERE user = %%s AND host = %%s
""" % (colA[0], colA[0], colB[0], colB[0]), (user, host))
current_pass_hash = cursor.fetchone()[0]
if isinstance(current_pass_hash, bytes):
current_pass_hash = current_pass_hash.decode('ascii')
if encrypted:
encrypted_password = password
if not is_hash(encrypted_password):
module.fail_json(msg="encrypted was specified however it does not appear to be a valid hash expecting: *SHA1(SHA1(your_password))")
else:
if old_user_mgmt:
cursor.execute("SELECT PASSWORD(%s)", (password,))
else:
cursor.execute("SELECT CONCAT('*', UCASE(SHA1(UNHEX(SHA1(%s)))))", (password,))
encrypted_password = cursor.fetchone()[0]
if current_pass_hash != encrypted_password:
msg = "Password updated"
if module.check_mode:
return (True, msg)
if old_user_mgmt:
cursor.execute("SET PASSWORD FOR %s@%s = %s", (user, host, encrypted_password))
msg = "Password updated (old style)"
else:
try:
cursor.execute("ALTER USER %s@%s IDENTIFIED WITH mysql_native_password AS %s", (user, host, encrypted_password))
msg = "Password updated (new style)"
except (mysql_driver.Error) as e:
# https://stackoverflow.com/questions/51600000/authentication-string-of-root-user-on-mysql
# Replacing empty root password with new authentication mechanisms fails with error 1396
if e.args[0] == 1396:
cursor.execute(
"UPDATE mysql.user SET plugin = %s, authentication_string = %s, Password = '' WHERE User = %s AND Host = %s",
('mysql_native_password', encrypted_password, user, host)
)
cursor.execute("FLUSH PRIVILEGES")
msg = "Password forced update"
else:
raise e
changed = True
# Handle plugin authentication
if plugin and not role:
cursor.execute("SELECT plugin, authentication_string FROM mysql.user "
"WHERE user = %s AND host = %s", (user, host))
current_plugin = cursor.fetchone()
update = False
if current_plugin[0] != plugin:
update = True
if plugin_hash_string and current_plugin[1] != plugin_hash_string:
update = True
if plugin_auth_string and current_plugin[1] != plugin_auth_string:
# this case can cause more updates than expected,
# as plugin can hash auth_string in any way it wants
# and there's no way to figure it out for
# a check, so I prefer to update more often than never
update = True
if update:
if plugin_hash_string:
query_with_args = "ALTER USER %s@%s IDENTIFIED WITH %s AS %s", (user, host, plugin, plugin_hash_string)
elif plugin_auth_string:
query_with_args = "ALTER USER %s@%s IDENTIFIED WITH %s BY %s", (user, host, plugin, plugin_auth_string)
else:
query_with_args = "ALTER USER %s@%s IDENTIFIED WITH %s", (user, host, plugin)
cursor.execute(*query_with_args)
changed = True
# Handle privileges
if new_priv is not None:
curr_priv = privileges_get(cursor, user, host, maria_role)
# If the user has privileges on a db.table that doesn't appear at all in
# the new specification, then revoke all privileges on it.
for db_table, priv in iteritems(curr_priv):
# If the user has the GRANT OPTION on a db.table, revoke it first.
if "GRANT" in priv:
grant_option = True
if db_table not in new_priv:
if user != "root" and "PROXY" not in priv and not append_privs:
msg = "Privileges updated"
if module.check_mode:
return (True, msg)
privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role)
changed = True
# If the user doesn't currently have any privileges on a db.table, then
# we can perform a straight grant operation.
for db_table, priv in iteritems(new_priv):
if db_table not in curr_priv:
msg = "New privileges granted"
if module.check_mode:
return (True, msg)
privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
changed = True
# If the db.table specification exists in both the user's current privileges
# and in the new privileges, then we need to see if there's a difference.
db_table_intersect = set(new_priv.keys()) & set(curr_priv.keys())
for db_table in db_table_intersect:
# If appending privileges, only the set difference between new privileges and current privileges matter.
# The symmetric difference isn't relevant for append because existing privileges will not be revoked.
if append_privs:
priv_diff = set(new_priv[db_table]) - set(curr_priv[db_table])
else:
priv_diff = set(new_priv[db_table]) ^ set(curr_priv[db_table])
if len(priv_diff) > 0:
msg = "Privileges updated"
if module.check_mode:
return (True, msg)
if not append_privs:
privileges_revoke(cursor, user, host, db_table, curr_priv[db_table], grant_option, maria_role)
privileges_grant(cursor, user, host, db_table, new_priv[db_table], tls_requires, maria_role)
changed = True
if role:
continue
# Handle TLS requirements
current_requires = get_tls_requires(cursor, user, host)
if current_requires != tls_requires:
msg = "TLS requires updated"
if module.check_mode:
return (True, msg)
if not old_user_mgmt:
pre_query = "ALTER USER"
else:
pre_query = "GRANT %s ON *.* TO" % ",".join(get_grants(cursor, user, host))
if tls_requires is not None:
query = " ".join((pre_query, "%s@%s"))
query_with_args = mogrify_requires(query, (user, host), tls_requires)
else:
query = " ".join((pre_query, "%s@%s REQUIRE NONE"))
query_with_args = query, (user, host)
cursor.execute(*query_with_args)
changed = True
return (changed, msg)
def user_delete(cursor, user, host, host_all, check_mode):
if check_mode:
return True
if host_all:
hostnames = user_get_hostnames(cursor, user)
else:
hostnames = [host]
for hostname in hostnames:
try:
cursor.execute("DROP USER IF EXISTS %s@%s", (user, hostname))
except Exception:
cursor.execute("DROP USER %s@%s", (user, hostname))
return True
def user_get_hostnames(cursor, user):
cursor.execute("SELECT Host FROM mysql.user WHERE user = %s", (user,))
hostnames_raw = cursor.fetchall()
hostnames = []
for hostname_raw in hostnames_raw:
hostnames.append(hostname_raw[0])
return hostnames
def privileges_get(cursor, user, host, maria_role=False):
""" MySQL doesn't have a better method of getting privileges aside from the
SHOW GRANTS query syntax, which requires us to then parse the returned string.
Here's an example of the string that is returned from MySQL:
GRANT USAGE ON *.* TO 'user'@'localhost' IDENTIFIED BY 'pass';
This function makes the query and returns a dictionary containing the results.
The dictionary format is the same as that returned by privileges_unpack() below.
"""
output = {}
if not maria_role:
cursor.execute("SHOW GRANTS FOR %s@%s", (user, host))
else:
cursor.execute("SHOW GRANTS FOR %s", (user,))
grants = cursor.fetchall()
def pick(x):
if x == 'ALL PRIVILEGES':
return 'ALL'
else:
return x
for grant in grants:
if not maria_role:
res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\\6)? ?(.*)""", grant[0])
else:
res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3""", grant[0])
if res is None:
# If a user has roles assigned, we'll have one of priv tuples looking like
# GRANT `admin`@`%` TO `user1`@`localhost`
# which will result None as res value.
# As we use the mysql_role module to manipulate roles
# we just ignore such privs below:
res = re.match("""GRANT (.+) TO (['`"]).*""", grant[0])
if not maria_role and res:
continue
raise InvalidPrivsError('unable to parse the MySQL grant string: %s' % grant[0])
privileges = res.group(1).split(",")
privileges = [pick(x.strip()) for x in privileges]
# Handle cases when there's privs like GRANT SELECT (colA, ...) in privs.
# To this point, the privileges list can look like
# ['SELECT (`A`', '`B`)', 'INSERT'] that is incorrect (SELECT statement is splitted).
# Columns should also be sorted to compare it with desired privileges later.
# Determine if there's a case similar to the above:
privileges = normalize_col_grants(privileges)
if not maria_role:
if "WITH GRANT OPTION" in res.group(7):
privileges.append('GRANT')
db = res.group(2)
output.setdefault(db, []).extend(privileges)
return output
def normalize_col_grants(privileges):
"""Fix and sort grants on columns in privileges list
Make ['SELECT (A, B)', 'INSERT (A, B)', 'DETELE']
from ['SELECT (A', 'B)', 'INSERT (B', 'A)', 'DELETE'].
See unit tests in tests/unit/plugins/modules/test_mysql_user.py
"""
for grant in ('SELECT', 'UPDATE', 'INSERT', 'REFERENCES'):
start, end = has_grant_on_col(privileges, grant)
# If not, either start and end will be None
if start is not None:
privileges = handle_grant_on_col(privileges, start, end)
return privileges
def has_grant_on_col(privileges, grant):
"""Check if there is a statement like SELECT (colA, colB)
in the privilege list.
Return (start index, end index).
"""
# Determine elements of privileges where
# columns are listed
start = None
end = None
for n, priv in enumerate(privileges):
if '%s (' % grant in priv:
# We found the start element
start = n
if start is not None and ')' in priv:
# We found the end element
end = n
break
if start is not None and end is not None:
# if the privileges list consist of, for example,
# ['SELECT (A', 'B), 'INSERT'], return indexes of related elements
return start, end
else:
# If start and end position is the same element,
# it means there's expression like 'SELECT (A)',
# so no need to handle it
return None, None
def handle_grant_on_col(privileges, start, end):
"""Handle cases when the privs like SELECT (colA, ...) is in the privileges list."""
# When the privileges list look like ['SELECT (colA,', 'colB)']
# (Notice that the statement is splitted)
if start != end:
output = list(privileges[:start])
select_on_col = ', '.join(privileges[start:end + 1])
select_on_col = sort_column_order(select_on_col)
output.append(select_on_col)
output.extend(privileges[end + 1:])
# When it look like it should be, e.g. ['SELECT (colA, colB)'],
# we need to be sure, the columns is sorted
else:
output = list(privileges)
output[start] = sort_column_order(output[start])
return output
def sort_column_order(statement):
"""Sort column order in grants like SELECT (colA, colB, ...).
MySQL changes columns order like below:
---------------------------------------
mysql> GRANT SELECT (testColA, testColB), INSERT ON `testDb`.`testTable` TO 'testUser'@'localhost';
Query OK, 0 rows affected (0.04 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW GRANTS FOR testUser@localhost;
+---------------------------------------------------------------------------------------------+
| Grants for testUser@localhost |
+---------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'testUser'@'localhost' |
| GRANT SELECT (testColB, testColA), INSERT ON `testDb`.`testTable` TO 'testUser'@'localhost' |
+---------------------------------------------------------------------------------------------+
We should sort columns in our statement, otherwise the module always will return
that the state has changed.
"""
# 1. Extract stuff inside ()
# 2. Split
# 3. Sort
# 4. Put between () and return
# "SELECT/UPDATE/.. (colA, colB) => "colA, colB"
tmp = statement.split('(')
priv_name = tmp[0]
columns = tmp[1].rstrip(')')
# "colA, colB" => ["colA", "colB"]
columns = columns.split(',')
for i, col in enumerate(columns):
col = col.strip()
columns[i] = col.strip('`')
columns.sort()
return '%s(%s)' % (priv_name, ', '.join(columns))
def privileges_unpack(priv, mode, valid_privs):
""" Take a privileges string, typically passed as a parameter, and unserialize
it into a dictionary, the same format as privileges_get() above. We have this
custom format to avoid using YAML/JSON strings inside YAML playbooks. Example
of a privileges string:
mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanother.*:ALL
The privilege USAGE stands for no privileges, so we add that in on *.* if it's
not specified in the string, as MySQL will always provide this by default.
"""
if mode == 'ANSI':
quote = '"'
else:
quote = '`'
output = {}
privs = []
for item in priv.strip().split('/'):
pieces = item.strip().rsplit(':', 1)
dbpriv = pieces[0].rsplit(".", 1)
# Check for FUNCTION or PROCEDURE object types
parts = dbpriv[0].split(" ", 1)
object_type = ''
if len(parts) > 1 and (parts[0] == 'FUNCTION' or parts[0] == 'PROCEDURE'):
object_type = parts[0] + ' '
dbpriv[0] = parts[1]
# Do not escape if privilege is for database or table, i.e.
# neither quote *. nor .*
for i, side in enumerate(dbpriv):
if side.strip('`') != '*':
dbpriv[i] = '%s%s%s' % (quote, side.strip('`'), quote)
pieces[0] = object_type + '.'.join(dbpriv)
if '(' in pieces[1]:
output[pieces[0]] = re.split(r',\s*(?=[^)]*(?:\(|$))', pieces[1].upper())
for i in output[pieces[0]]:
privs.append(re.sub(r'\s*\(.*\)', '', i))
else:
output[pieces[0]] = pieces[1].upper().split(',')
privs = output[pieces[0]]
# Handle cases when there's privs like GRANT SELECT (colA, ...) in privs.
output[pieces[0]] = normalize_col_grants(output[pieces[0]])
new_privs = frozenset(privs)
if not new_privs.issubset(valid_privs):
raise InvalidPrivsError('Invalid privileges specified: %s' % new_privs.difference(valid_privs))
if '*.*' not in output:
output['*.*'] = ['USAGE']
return output
def privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role=False):
# Escape '%' since mysql db.execute() uses a format string
db_table = db_table.replace('%', '%%')
if grant_option:
query = ["REVOKE GRANT OPTION ON %s" % db_table]
if not maria_role:
query.append("FROM %s@%s")
else:
query.append("FROM %s")
query = ' '.join(query)
cursor.execute(query, (user, host))
priv_string = ",".join([p for p in priv if p not in ('GRANT', )])
query = ["REVOKE %s ON %s" % (priv_string, db_table)]
if not maria_role:
query.append("FROM %s@%s")
params = (user, host)
else:
query.append("FROM %s")
params = (user,)
query = ' '.join(query)
cursor.execute(query, params)
cursor.execute("FLUSH PRIVILEGES")
def privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role=False):
# Escape '%' since mysql db.execute uses a format string and the
# specification of db and table often use a % (SQL wildcard)
db_table = db_table.replace('%', '%%')
priv_string = ",".join([p for p in priv if p not in ('GRANT', )])
query = ["GRANT %s ON %s" % (priv_string, db_table)]
# MySQL and MariaDB don't store roles in the user table the same manner:
# select user, host from mysql.user;
# +------------------+-----------+
# | user | host |
# +------------------+-----------+
# | role_foo | % | <- MySQL
# | role_foo | | <- MariaDB
# +------------------+-----------+
if not maria_role:
query.append("TO %s@%s")
params = (user, host)
else:
query.append("TO %s")
params = (user)
if tls_requires and impl.use_old_user_mgmt(cursor):
query, params = mogrify_requires(" ".join(query), params, tls_requires)
query = [query]
if 'GRANT' in priv:
query.append("WITH GRANT OPTION")
query = ' '.join(query)
if isinstance(params, str):
params = (params,)
cursor.execute(query, params)
def convert_priv_dict_to_str(priv):
"""Converts privs dictionary to string of certain format.
Args:
priv (dict): Dict of privileges that needs to be converted to string.
Returns:
priv (str): String representation of input argument.
"""
priv_list = ['%s:%s' % (key, val) for key, val in iteritems(priv)]
return '/'.join(priv_list)
def handle_requiressl_in_priv_string(module, priv, tls_requires):
module.deprecate('The "REQUIRESSL" privilege is deprecated, use the "tls_requires" option instead.',
version='3.0.0', collection_name='community.mysql')
priv_groups = re.search(r"(.*?)(\*\.\*:)([^/]*)(.*)", priv)
if priv_groups.group(3) == "REQUIRESSL":
priv = priv_groups.group(1) + priv_groups.group(4) or None
else:
inner_priv_groups = re.search(r"(.*?),?REQUIRESSL,?(.*)", priv_groups.group(3))
priv = '{0}{1}{2}{3}'.format(
priv_groups.group(1),
priv_groups.group(2),
','.join(filter(None, (inner_priv_groups.group(1), inner_priv_groups.group(2)))),
priv_groups.group(4)
)
if not tls_requires:
tls_requires = "SSL"
else:
module.warn('Ignoring "REQUIRESSL" privilege as "tls_requires" is defined and it takes precedence.')
return priv, tls_requires
# Alter user is supported since MySQL 5.6 and MariaDB 10.2.0
def server_supports_alter_user(cursor):
"""Check if the server supports ALTER USER statement or doesn't.
Args:
cursor (cursor): DB driver cursor object.
Returns: True if supports, False otherwise.
"""
cursor.execute("SELECT VERSION()")
version_str = cursor.fetchone()[0]
version = version_str.split('.')
if 'mariadb' in version_str.lower():
# MariaDB 10.2 and later
if int(version[0]) * 1000 + int(version[1]) >= 10002:
return True
else:
return False
else:
# MySQL 5.6 and later
if int(version[0]) * 1000 + int(version[1]) >= 5006:
return True
else:
return False
def get_resource_limits(cursor, user, host):
"""Get user resource limits.
Args:
cursor (cursor): DB driver cursor object.
user (str): User name.
host (str): User host name.
Returns: Dictionary containing current resource limits.
"""
query = ('SELECT max_questions AS MAX_QUERIES_PER_HOUR, '
'max_updates AS MAX_UPDATES_PER_HOUR, '
'max_connections AS MAX_CONNECTIONS_PER_HOUR, '
'max_user_connections AS MAX_USER_CONNECTIONS '
'FROM mysql.user WHERE User = %s AND Host = %s')
cursor.execute(query, (user, host))
res = cursor.fetchone()
if not res:
return None
current_limits = {
'MAX_QUERIES_PER_HOUR': res[0],
'MAX_UPDATES_PER_HOUR': res[1],
'MAX_CONNECTIONS_PER_HOUR': res[2],
'MAX_USER_CONNECTIONS': res[3],
}
return current_limits
def match_resource_limits(module, current, desired):
"""Check and match limits.
Args:
module (AnsibleModule): Ansible module object.
current (dict): Dictionary with current limits.
desired (dict): Dictionary with desired limits.
Returns: Dictionary containing parameters that need to change.
"""
if not current:
# It means the user does not exists, so we need
# to set all limits after its creation
return desired
needs_to_change = {}
for key, val in iteritems(desired):
if key not in current:
# Supported keys are listed in the documentation
# and must be determined in the get_resource_limits function
# (follow 'AS' keyword)
module.fail_json(msg="resource_limits: key '%s' is unsupported." % key)
try:
val = int(val)
except Exception:
module.fail_json(msg="Can't convert value '%s' to integer." % val)
if val != current.get(key):
needs_to_change[key] = val
return needs_to_change
def limit_resources(module, cursor, user, host, resource_limits, check_mode):
"""Limit user resources.
Args:
module (AnsibleModule): Ansible module object.
cursor (cursor): DB driver cursor object.
user (str): User name.
host (str): User host name.
resource_limit (dict): Dictionary with desired limits.
check_mode (bool): Run the function in check mode or not.
Returns: True, if changed, False otherwise.
"""
if not server_supports_alter_user(cursor):
module.fail_json(msg="The server version does not match the requirements "
"for resource_limits parameter. See module's documentation.")
current_limits = get_resource_limits(cursor, user, host)
needs_to_change = match_resource_limits(module, current_limits, resource_limits)
if not needs_to_change:
return False
if needs_to_change and check_mode:
return True
# If not check_mode
tmp = []
for key, val in iteritems(needs_to_change):
tmp.append('%s %s' % (key, val))
query = "ALTER USER %s@%s"
query += ' WITH %s' % ' '.join(tmp)
cursor.execute(query, (user, host))
return True
def get_impl(cursor):
global impl
cursor.execute("SELECT VERSION()")
if 'mariadb' in cursor.fetchone()[0].lower():
from ansible_collections.community.mysql.plugins.module_utils.implementations.mariadb import user as mariauser
impl = mariauser
else:
from ansible_collections.community.mysql.plugins.module_utils.implementations.mysql import user as mysqluser
impl = mysqluser

View file

@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2021, Felix Fontein <felix@fontein.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
"""Provide version object to compare version numbers."""
from __future__ import absolute_import, division, print_function
__metaclass__ = type
# Once we drop support for ansible-core 2.11, we can
# remove the _version.py file, and replace the following import by
#
# from ansible.module_utils.compat.version import LooseVersion
from ._version import LooseVersion

View file

@ -53,12 +53,12 @@ options:
description:
- Execute the dump in a single transaction.
type: bool
default: no
default: false
quick:
description:
- Option used for dumping large tables.
type: bool
default: yes
default: true
ignore_tables:
description:
- A list of table names that will be ignored in the dump
@ -70,14 +70,14 @@ options:
description:
- Dump binary columns using hexadecimal notation.
type: bool
default: no
default: false
version_added: '0.1.0'
force:
description:
- Continue dump or import even if we get an SQL error.
- Used only when I(state) is C(dump) or C(import).
type: bool
default: no
default: false
version_added: '0.1.0'
master_data:
description:
@ -96,7 +96,7 @@ options:
description:
- Skip locking tables for read. Used when I(state=dump), ignored otherwise.
type: bool
default: no
default: false
version_added: '0.1.0'
dump_extra_args:
description:
@ -110,7 +110,7 @@ options:
- If C(yes), the module will internally execute commands via a shell.
- Used when I(state=import), ignored otherwise.
type: bool
default: no
default: false
version_added: '0.1.0'
unsafe_login_password:
description:
@ -121,7 +121,7 @@ options:
- Used only when I(state) is C(import) or C(dump) and
I(login_password) is passed, ignored otherwise.
type: bool
default: no
default: false
version_added: '0.1.0'
restrict_config_file:
description:
@ -132,14 +132,14 @@ options:
under the hood that read named option file in addition to usual option files.
- If this behavior is undesirable, use C(yes) to read only named option file.
type: bool
default: no
default: false
version_added: '0.1.0'
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
default: false
version_added: '0.1.0'
config_overrides_defaults:
description:
@ -148,7 +148,7 @@ options:
- Used when I(stat) is C(present) or C(absent), ignored otherwise.
- It needs Python 3.5+ as the default interpreter on a target host.
type: bool
default: no
default: false
version_added: '0.1.0'
seealso:
@ -173,20 +173,24 @@ requirements:
- mysql (command line binary)
- mysqldump (command line binary)
notes:
- Supports C(check_mode).
- Requires the mysql and mysqldump binaries on the remote host.
- This module is B(not idempotent) when I(state) is C(import),
and will import the dump file each time if run more than once.
attributes:
check_mode:
support: full
extends_documentation_fragment:
- community.mysql.mysql
'''
EXAMPLES = r'''
# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument
- name: Create a new database with name 'bobdata'
community.mysql.mysql_db:
name: bobdata
state: present
login_unix_socket: /run/mysqld/mysqld.sock
- name: Create new databases with names 'foo' and 'bar'
community.mysql.mysql_db:
@ -212,7 +216,7 @@ EXAMPLES = r'''
name: my_db
state: import
target: /tmp/dump.sql.bz2
force: yes
force: true
- name: Dump multiple databases
community.mysql.mysql_db:
@ -284,7 +288,7 @@ EXAMPLES = r'''
- name: Try to create database as root/nopassword first. If not allowed, pass the credentials
community.mysql.mysql_db:
check_implicit_admin: yes
check_implicit_admin: true
login_user: bob
login_password: 123456
name: bobdata
@ -330,7 +334,7 @@ executed_commands = []
def db_exists(cursor, db):
res = 0
for each_db in db:
res += cursor.execute("SHOW DATABASES LIKE %s", (each_db.replace("_", r"\_"),))
res += cursor.execute("SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = %s", (each_db,))
return res == len(db)
@ -442,7 +446,7 @@ def db_import(module, host, user, password, db_name, target, all_databases, port
cmd.append("--defaults-extra-file=%s" % shlex_quote(config_file))
if check_implicit_admin:
cmd += " --user=root --password=''"
cmd.append("--user=root --password=''")
else:
if user:
cmd.append("--user=%s" % shlex_quote(user))
@ -519,7 +523,8 @@ def db_create(cursor, db, encoding, collation):
query_params = dict(enc=encoding, collate=collation)
res = 0
for each_db in db:
query = ['CREATE DATABASE %s' % mysql_quote_identifier(each_db, 'database')]
# Escape '%' since mysql cursor.execute() uses a format string
query = ['CREATE DATABASE %s' % mysql_quote_identifier(each_db, 'database').replace('%', '%%')]
if encoding:
query.append("CHARACTER SET %(enc)s")
if collation:

View file

@ -42,12 +42,15 @@ options:
description:
- Includes names of empty databases to returned dictionary.
type: bool
default: no
default: false
notes:
- Calculating the size of a database might be slow, depending on the number and size of tables in it.
To avoid this, use I(exclude_fields=db_size).
- Supports C(check_mode).
attributes:
check_mode:
support: full
seealso:
- module: community.mysql.mysql_variables
@ -58,6 +61,7 @@ seealso:
author:
- Andrew Klychkov (@Andersson007)
- Sebastian Gumprich (@rndmh3ro)
- Laurent Indermühle (@laurent-indermuehle)
extends_documentation_fragment:
- community.mysql.mysql
@ -76,9 +80,12 @@ EXAMPLES = r'''
# Display all info from databases group except settings:
# ansible databases -m mysql_info -a 'filter=!settings'
# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument
- name: Collect all possible information using passwordless root access
community.mysql.mysql_info:
login_user: root
login_unix_socket: /run/mysqld/mysqld.sock
- name: Get MySQL version with non-default credentials
community.mysql.mysql_info:
@ -93,14 +100,14 @@ EXAMPLES = r'''
filter: "!settings,!users"
- name: Collect info about databases and version using ~/.my.cnf as a credential file
become: yes
become: true
community.mysql.mysql_info:
filter:
- databases
- version
- name: Collect info about databases and version using ~alice/.my.cnf as a credential file
become: yes
become: true
community.mysql.mysql_info:
config_file: /home/alice/.my.cnf
filter:
@ -108,13 +115,13 @@ EXAMPLES = r'''
- version
- name: Collect info about databases including empty and excluding their sizes
become: yes
become: true
community.mysql.mysql_info:
config_file: /home/alice/.my.cnf
filter:
- databases
exclude_fields: db_size
return_empty_dbs: yes
return_empty_dbs: true
'''
RETURN = r'''
@ -203,6 +210,21 @@ slave_hosts:
type: dict
sample:
- { "2": { "Host": "", "Master_id": 1, "Port": 3306 } }
connector_name:
description: Name of the python connector used by the module. When the connector is not identified, returns C(Unknown).
returned: always
type: str
sample:
- "pymysql"
- "MySQLdb"
version_added: '2.4.0'
connector_version:
description: Version of the python connector used by the module. When the connector is not identified, returns C(Unknown).
returned: always
type: str
sample:
- "1.0.2"
version_added: '2.4.0'
'''
from decimal import Decimal
@ -213,6 +235,8 @@ from ansible_collections.community.mysql.plugins.module_utils.mysql import (
mysql_common_argument_spec,
mysql_driver,
mysql_driver_fail_msg,
get_connector_name,
get_connector_version,
)
from ansible.module_utils.six import iteritems
from ansible.module_utils._text import to_native
@ -474,6 +498,9 @@ class MySQL_Info(object):
self.info['databases'][db['name']] = {}
if not exclude_fields or 'db_size' not in exclude_fields:
if db['size'] is None:
db['size'] = 0
self.info['databases'][db['name']]['size'] = int(db['size'])
# If empty dbs are not needed in the returned dict, exit from the method
@ -552,21 +579,29 @@ def main():
if mysql_driver is None:
module.fail_json(msg=mysql_driver_fail_msg)
connector_name = get_connector_name(mysql_driver)
connector_version = get_connector_version(mysql_driver)
try:
cursor, db_conn = mysql_connect(module, login_user, login_password,
config_file, ssl_cert, ssl_key, ssl_ca, db,
check_hostname=check_hostname,
connect_timeout=connect_timeout, cursor_class='DictCursor')
except Exception as e:
module.fail_json(msg="unable to connect to database, check login_user and login_password are correct or %s has the credentials. "
"Exception message: %s" % (config_file, to_native(e)))
msg = ('unable to connect to database using %s %s, check login_user '
'and login_password are correct or %s has the credentials. '
'Exception message: %s' % (connector_name, connector_version, config_file, to_native(e)))
module.fail_json(msg)
###############################
# Create object and do main job
mysql = MySQL_Info(module, cursor)
module.exit_json(changed=False, **mysql.get_info(filter_, exclude_fields, return_empty_dbs))
module.exit_json(changed=False,
connector_name=connector_name,
connector_version=connector_version,
**mysql.get_info(filter_, exclude_fields, return_empty_dbs))
if __name__ == '__main__':

View file

@ -22,8 +22,15 @@ options:
description:
- SQL query to run. Multiple queries can be passed using YAML list syntax.
- Must be a string or YAML list containing strings.
- If you use I(named_args) or I(positional_args) any C(%) will be interpreted
as a formatting character. All literal C(%) characters in the query should be
escaped as C(%%).
- Note that if you use the C(IF EXISTS/IF NOT EXISTS) clauses in your query
and C(mysqlclient) connector, the module will report that
the state has been changed even if it has not. If it is important in your
workflow, use the C(PyMySQL) connector instead.
type: raw
required: yes
required: true
positional_args:
description:
- List of values to be passed as positional arguments to the query.
@ -42,7 +49,10 @@ options:
description:
- Where passed queries run in a single transaction (C(yes)) or commit them one-by-one (C(no)).
type: bool
default: no
default: false
attributes:
check_mode:
support: none
seealso:
- module: community.mysql.mysql_db
author:
@ -53,10 +63,13 @@ extends_documentation_fragment:
'''
EXAMPLES = r'''
# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument
- name: Simple select query to acme db
community.mysql.mysql_query:
login_db: acme
query: SELECT * FROM orders
login_unix_socket: /run/mysqld/mysqld.sock
- name: Select query to db acme with positional arguments
community.mysql.mysql_query:
@ -80,7 +93,7 @@ EXAMPLES = r'''
query:
- INSERT INTO articles (id, story) VALUES (2, 'my_long_story')
- INSERT INTO prices (id, price) VALUES (123, '100.00')
single_transaction: yes
single_transaction: true
'''
RETURN = r'''
@ -103,6 +116,8 @@ rowcount:
sample: [5, 1]
'''
import warnings
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.community.mysql.plugins.module_utils.mysql import (
mysql_connect,
@ -112,7 +127,7 @@ from ansible_collections.community.mysql.plugins.module_utils.mysql import (
)
from ansible.module_utils._text import to_native
DML_QUERY_KEYWORDS = ('INSERT', 'UPDATE', 'DELETE')
DML_QUERY_KEYWORDS = ('INSERT', 'UPDATE', 'DELETE', 'REPLACE')
# TRUNCATE is not DDL query but it also returns 0 rows affected:
DDL_QUERY_KEYWORDS = ('CREATE', 'DROP', 'ALTER', 'RENAME', 'TRUNCATE')
@ -196,9 +211,22 @@ def main():
executed_queries = []
rowcount = []
already_exists = False
for q in query:
try:
cursor.execute(q, arguments)
with warnings.catch_warnings():
warnings.filterwarnings(action='error',
message='.*already exists*',
category=mysql_driver.Warning)
try:
cursor.execute(q, arguments)
except mysql_driver.Warning:
# When something is run with IF NOT EXISTS
# and there's "already exists" MySQL warning,
# set the flag as True.
# PyMySQL throws the warning, mysqlclinet does NOT.
already_exists = True
except Exception as e:
if not autocommit:
@ -208,7 +236,8 @@ def main():
module.fail_json(msg="Cannot execute SQL '%s' args [%s]: %s" % (q, arguments, to_native(e)))
try:
query_result.append([dict(row) for row in cursor.fetchall()])
if not already_exists:
query_result.append([dict(row) for row in cursor.fetchall()])
except Exception as e:
if not autocommit:
@ -224,8 +253,12 @@ def main():
for keyword in DDL_QUERY_KEYWORDS:
if keyword in q:
changed = True
if already_exists:
# Indicates the entity already exists
changed = False
already_exists = False # Reset flag
else:
changed = True
try:
executed_queries.append(cursor._last_executed)
except AttributeError:

View file

@ -15,7 +15,7 @@ DOCUMENTATION = r'''
module: mysql_replication
short_description: Manage MySQL replication
description:
- Manages MySQL server replication, replica, master status, get and change master host.
- Manages MySQL server replication, replica, primary status, get and change primary host.
author:
- Balazs Pocze (@banyek)
- Andrew Klychkov (@Andersson007)
@ -23,17 +23,19 @@ options:
mode:
description:
- Module operating mode. Could be
C(changemaster) (CHANGE MASTER TO),
C(getmaster) (SHOW MASTER STATUS),
C(changeprimary | changemaster) (CHANGE PRIMARY | MASTER TO),
C(getprimary | getmaster) (SHOW PRIMARY | MASTER STATUS),
C(getreplica | getslave) (SHOW REPLICA | SLAVE STATUS),
C(startreplica | startslave) (START REPLICA | SLAVE),
C(stopreplica | stopslave) (STOP REPLICA | SLAVE),
C(resetmaster) (RESET MASTER) - supported since community.mysql 0.1.0,
C(resetprimary | resetmaster) (RESET PRIMARY | MASTER) - supported since community.mysql 0.1.0,
C(resetreplica, resetslave) (RESET REPLICA | SLAVE),
C(resetreplicaall, resetslave) (RESET REPLICA | SLAVE ALL).
type: str
choices:
- changeprimary
- changemaster
- getprimary
- getmaster
- getreplica
- getslave
@ -41,40 +43,48 @@ options:
- startslave
- stopreplica
- stopslave
- resetprimary
- resetmaster
- resetreplica
- resetslave
- resetreplicaall
- resetslaveall
default: getreplica
master_host:
primary_host:
description:
- Same as mysql variable.
- Same as the C(MASTER_HOST) mysql variable.
type: str
master_user:
aliases: [master_host]
primary_user:
description:
- Same as mysql variable.
- Same as the C(MASTER_USER) mysql variable.
type: str
master_password:
aliases: [master_user]
primary_password:
description:
- Same as mysql variable.
- Same as the C(MASTER_PASSWORD) mysql variable.
type: str
master_port:
aliases: [master_password]
primary_port:
description:
- Same as mysql variable.
- Same as the C(MASTER_PORT) mysql variable.
type: int
master_connect_retry:
aliases: [master_port]
primary_connect_retry:
description:
- Same as mysql variable.
- Same as the C(MASTER_CONNECT_RETRY) mysql variable.
type: int
master_log_file:
aliases: [master_connect_retry]
primary_log_file:
description:
- Same as mysql variable.
- Same as the C(MASTER_LOG_FILE) mysql variable.
type: str
master_log_pos:
aliases: [master_log_file]
primary_log_pos:
description:
- Same as mysql variable.
- Same as the C(MASTER_LOG_POS) mysql variable.
type: int
aliases: [master_log_pos]
relay_log_file:
description:
- Same as mysql variable.
@ -83,7 +93,7 @@ options:
description:
- Same as mysql variable.
type: int
master_ssl:
primary_ssl:
description:
- Same as the C(MASTER_SSL) mysql variable.
- When setting it to C(yes), the connection attempt only succeeds
@ -92,43 +102,51 @@ options:
L(MySQL encrypted replication documentation,https://dev.mysql.com/doc/refman/8.0/en/replication-solutions-encrypted-connections.html).
type: bool
default: false
master_ssl_ca:
aliases: [master_ssl]
primary_ssl_ca:
description:
- Same as the C(MASTER_SSL_CA) mysql variable.
- For details, refer to
L(MySQL encrypted replication documentation,https://dev.mysql.com/doc/refman/8.0/en/replication-solutions-encrypted-connections.html).
type: str
master_ssl_capath:
aliases: [master_ssl_ca]
primary_ssl_capath:
description:
- Same as the C(MASTER_SSL_CAPATH) mysql variable.
- For details, refer to
L(MySQL encrypted replication documentation,https://dev.mysql.com/doc/refman/8.0/en/replication-solutions-encrypted-connections.html).
type: str
master_ssl_cert:
aliases: [master_ssl_capath]
primary_ssl_cert:
description:
- Same as the C(MASTER_SSL_CERT) mysql variable.
- For details, refer to
L(MySQL encrypted replication documentation,https://dev.mysql.com/doc/refman/8.0/en/replication-solutions-encrypted-connections.html).
type: str
master_ssl_key:
aliases: [master_ssl_cert]
primary_ssl_key:
description:
- Same as the C(MASTER_SSL_KEY) mysql variable.
- For details, refer to
L(MySQL encrypted replication documentation,https://dev.mysql.com/doc/refman/8.0/en/replication-solutions-encrypted-connections.html).
type: str
master_ssl_cipher:
aliases: [master_ssl_key]
primary_ssl_cipher:
description:
- Same as the C(MASTER_SSL_CIPHER) mysql variable.
- Specifies a colon-separated list of one or more ciphers permitted by the replica for the replication connection.
- For details, refer to
L(MySQL encrypted replication documentation,https://dev.mysql.com/doc/refman/8.0/en/replication-solutions-encrypted-connections.html).
type: str
master_auto_position:
aliases: [master_ssl_cipher]
primary_auto_position:
description:
- Whether the host uses GTID based replication or not.
- Same as the C(MASTER_AUTO_POSITION) mysql variable.
type: bool
default: false
master_use_gtid:
aliases: [master_auto_position]
primary_use_gtid:
description:
- Configures the replica to use the MariaDB Global Transaction ID.
- C(disabled) equals MASTER_USE_GTID=no command.
@ -140,16 +158,19 @@ options:
choices: [current_pos, replica_pos, slave_pos, disabled]
type: str
version_added: '0.1.0'
master_delay:
aliases: [master_use_gtid]
primary_delay:
description:
- Time lag behind the master's state (in seconds).
- Time lag behind the primary's state (in seconds).
- Same as the C(MASTER_DELAY) mysql variable.
- Available from MySQL 5.6.
- For more information see U(https://dev.mysql.com/doc/refman/8.0/en/replication-delayed.html).
type: int
version_added: '0.1.0'
aliases: [master_delay]
connection_name:
description:
- Name of the master connection.
- Name of the primary connection.
- Supported from MariaDB 10.0.1.
- Mutually exclusive with I(channel).
- For more information see U(https://mariadb.com/kb/en/library/multi-source-replication/).
@ -167,16 +188,19 @@ options:
description:
- Fails on error when calling mysql.
type: bool
default: False
default: false
version_added: '0.1.0'
notes:
- If an empty value for the parameter of string type is needed, use an empty string.
attributes:
check_mode:
support: none
extends_documentation_fragment:
- community.mysql.mysql
seealso:
- module: community.mysql.mysql_info
- name: MySQL replication reference
@ -191,20 +215,23 @@ seealso:
'''
EXAMPLES = r'''
# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument
- name: Stop mysql replica thread
community.mysql.mysql_replication:
mode: stopreplica
login_unix_socket: /run/mysqld/mysqld.sock
- name: Get master binlog file name and binlog position
- name: Get primary binlog file name and binlog position
community.mysql.mysql_replication:
mode: getmaster
mode: getprimary
- name: Change master to master server 192.0.2.1 and use binary log 'mysql-bin.000009' with position 4578
- name: Change primary to primary server 192.0.2.1 and use binary log 'mysql-bin.000009' with position 4578
community.mysql.mysql_replication:
mode: changemaster
master_host: 192.0.2.1
master_log_file: mysql-bin.000009
master_log_pos: 4578
mode: changeprimary
primary_host: 192.0.2.1
primary_log_file: mysql-bin.000009
primary_log_pos: 4578
- name: Check replica status using port 3308
community.mysql.mysql_replication:
@ -212,43 +239,43 @@ EXAMPLES = r'''
login_host: ansible.example.com
login_port: 3308
- name: On MariaDB change master to use GTID current_pos
- name: On MariaDB change primary to use GTID current_pos
community.mysql.mysql_replication:
mode: changemaster
master_use_gtid: current_pos
mode: changeprimary
primary_use_gtid: current_pos
- name: Change master to use replication delay 3600 seconds
- name: Change primary to use replication delay 3600 seconds
community.mysql.mysql_replication:
mode: changemaster
master_host: 192.0.2.1
master_delay: 3600
mode: changeprimary
primary_host: 192.0.2.1
primary_delay: 3600
- name: Start MariaDB replica with connection name master-1
- name: Start MariaDB replica with connection name primary-1
community.mysql.mysql_replication:
mode: startreplica
connection_name: master-1
connection_name: primary-1
- name: Stop replication in channel master-1
- name: Stop replication in channel primary-1
community.mysql.mysql_replication:
mode: stopreplica
channel: master-1
channel: primary-1
- name: >
Run RESET MASTER command which will delete all existing binary log files
and reset the binary log index file on the master
and reset the binary log index file on the primary
community.mysql.mysql_replication:
mode: resetmaster
mode: resetprimary
- name: Run start replica and fail the task on errors
community.mysql.mysql_replication:
mode: startreplica
connection_name: master-1
fail_on_error: yes
connection_name: primary-1
fail_on_error: true
- name: Change master and fail on error (like when replica thread is running)
- name: Change primary and fail on error (like when replica thread is running)
community.mysql.mysql_replication:
mode: changemaster
fail_on_error: yes
mode: changeprimary
fail_on_error: true
'''
@ -257,7 +284,7 @@ queries:
description: List of executed queries which modified DB's state.
returned: always
type: list
sample: ["CHANGE MASTER TO MASTER_HOST='master2.example.com',MASTER_PORT=3306"]
sample: ["CHANGE MASTER TO MASTER_HOST='primary2.example.com',MASTER_PORT=3306"]
version_added: '0.1.0'
'''
@ -272,15 +299,17 @@ from ansible_collections.community.mysql.plugins.module_utils.mysql import (
mysql_common_argument_spec,
)
from ansible.module_utils._text import to_native
from distutils.version import LooseVersion
executed_queries = []
def get_master_status(cursor):
def get_primary_status(cursor):
# TODO: when it's available to change on MySQL's side,
# change MASTER to PRIMARY using the approach from
# get_replica_status() function. Same for other functions.
cursor.execute("SHOW MASTER STATUS")
masterstatus = cursor.fetchone()
return masterstatus
primarystatus = cursor.fetchone()
return primarystatus
def get_replica_status(cursor, connection_name='', channel='', term='REPLICA'):
@ -363,7 +392,7 @@ def reset_replica_all(module, cursor, connection_name='', channel='', fail_on_er
return reset
def reset_master(module, cursor, fail_on_error=False):
def reset_primary(module, cursor, fail_on_error=False):
query = 'RESET MASTER'
try:
executed_queries.append(query)
@ -400,7 +429,7 @@ def start_replica(module, cursor, connection_name='', channel='', fail_on_error=
return started
def changemaster(cursor, chm, connection_name='', channel=''):
def changeprimary(cursor, chm, connection_name='', channel=''):
if connection_name:
query = "CHANGE MASTER '%s' TO %s" % (connection_name, ','.join(chm))
else:
@ -417,29 +446,33 @@ def main():
argument_spec = mysql_common_argument_spec()
argument_spec.update(
mode=dict(type='str', default='getreplica', choices=[
'getmaster', 'getreplica', 'getslave', 'changemaster',
'stopreplica', 'stopslave', 'startreplica', 'startslave',
'resetmaster', 'resetreplica', 'resetslave',
'getprimary', 'getmaster',
'getreplica', 'getslave',
'changeprimary', 'changemaster',
'stopreplica', 'stopslave',
'startreplica', 'startslave',
'resetprimary', 'resetmaster',
'resetreplica', 'resetslave',
'resetreplicaall', 'resetslaveall']),
master_auto_position=dict(type='bool', default=False),
master_host=dict(type='str'),
master_user=dict(type='str'),
master_password=dict(type='str', no_log=True),
master_port=dict(type='int'),
master_connect_retry=dict(type='int'),
master_log_file=dict(type='str'),
master_log_pos=dict(type='int'),
primary_auto_position=dict(type='bool', default=False, aliases=['master_auto_position']),
primary_host=dict(type='str', aliases=['master_host']),
primary_user=dict(type='str', aliases=['master_user']),
primary_password=dict(type='str', no_log=True, aliases=['master_password']),
primary_port=dict(type='int', aliases=['master_port']),
primary_connect_retry=dict(type='int', aliases=['master_connect_retry']),
primary_log_file=dict(type='str', aliases=['master_log_file']),
primary_log_pos=dict(type='int', aliases=['master_log_pos']),
relay_log_file=dict(type='str'),
relay_log_pos=dict(type='int'),
master_ssl=dict(type='bool', default=False),
master_ssl_ca=dict(type='str'),
master_ssl_capath=dict(type='str'),
master_ssl_cert=dict(type='str'),
master_ssl_key=dict(type='str', no_log=False),
master_ssl_cipher=dict(type='str'),
master_use_gtid=dict(type='str', choices=[
'current_pos', 'replica_pos', 'slave_pos', 'disabled']),
master_delay=dict(type='int'),
primary_ssl=dict(type='bool', default=False, aliases=['master_ssl']),
primary_ssl_ca=dict(type='str', aliases=['master_ssl_ca']),
primary_ssl_capath=dict(type='str', aliases=['master_ssl_capath']),
primary_ssl_cert=dict(type='str', aliases=['master_ssl_cert']),
primary_ssl_key=dict(type='str', no_log=False, aliases=['master_ssl_key']),
primary_ssl_cipher=dict(type='str', aliases=['master_ssl_cipher']),
primary_use_gtid=dict(type='str', choices=[
'current_pos', 'replica_pos', 'slave_pos', 'disabled'], aliases=['master_use_gtid']),
primary_delay=dict(type='int', aliases=['master_delay']),
connection_name=dict(type='str'),
channel=dict(type='str'),
fail_on_error=dict(type='bool', default=False),
@ -451,33 +484,33 @@ def main():
],
)
mode = module.params["mode"]
master_host = module.params["master_host"]
master_user = module.params["master_user"]
master_password = module.params["master_password"]
master_port = module.params["master_port"]
master_connect_retry = module.params["master_connect_retry"]
master_log_file = module.params["master_log_file"]
master_log_pos = module.params["master_log_pos"]
primary_host = module.params["primary_host"]
primary_user = module.params["primary_user"]
primary_password = module.params["primary_password"]
primary_port = module.params["primary_port"]
primary_connect_retry = module.params["primary_connect_retry"]
primary_log_file = module.params["primary_log_file"]
primary_log_pos = module.params["primary_log_pos"]
relay_log_file = module.params["relay_log_file"]
relay_log_pos = module.params["relay_log_pos"]
master_ssl = module.params["master_ssl"]
master_ssl_ca = module.params["master_ssl_ca"]
master_ssl_capath = module.params["master_ssl_capath"]
master_ssl_cert = module.params["master_ssl_cert"]
master_ssl_key = module.params["master_ssl_key"]
master_ssl_cipher = module.params["master_ssl_cipher"]
master_auto_position = module.params["master_auto_position"]
primary_ssl = module.params["primary_ssl"]
primary_ssl_ca = module.params["primary_ssl_ca"]
primary_ssl_capath = module.params["primary_ssl_capath"]
primary_ssl_cert = module.params["primary_ssl_cert"]
primary_ssl_key = module.params["primary_ssl_key"]
primary_ssl_cipher = module.params["primary_ssl_cipher"]
primary_auto_position = module.params["primary_auto_position"]
ssl_cert = module.params["client_cert"]
ssl_key = module.params["client_key"]
ssl_ca = module.params["ca_cert"]
check_hostname = module.params["check_hostname"]
connect_timeout = module.params['connect_timeout']
config_file = module.params['config_file']
master_delay = module.params['master_delay']
if module.params.get("master_use_gtid") == 'disabled':
master_use_gtid = 'no'
primary_delay = module.params['primary_delay']
if module.params.get("primary_use_gtid") == 'disabled':
primary_use_gtid = 'no'
else:
master_use_gtid = module.params["master_use_gtid"]
primary_use_gtid = module.params["primary_use_gtid"]
connection_name = module.params["connection_name"]
channel = module.params['channel']
fail_on_error = module.params['fail_on_error']
@ -512,21 +545,35 @@ def main():
# "REPLICA" must be used instead of "SLAVE"
if impl.uses_replica_terminology(cursor):
replica_term = 'REPLICA'
if master_use_gtid == 'slave_pos':
module.deprecate('master_use_gtid "slave_pos" value is deprecated, use "replica_pos" instead.',
if primary_use_gtid == 'slave_pos':
module.deprecate('primary_use_gtid | master_use_gtid "slave_pos" value is '
'deprecated, use "replica_pos" instead.',
version='3.0.0', collection_name='community.mysql')
master_use_gtid = 'replica_pos'
primary_use_gtid = 'replica_pos'
else:
replica_term = 'SLAVE'
if master_use_gtid == 'replica_pos':
master_use_gtid = 'slave_pos'
if primary_use_gtid == 'replica_pos':
primary_use_gtid = 'slave_pos'
if mode in "getmaster":
status = get_master_status(cursor)
if mode in ('getprimary', 'getmaster'):
if mode == 'getmaster':
module.deprecate('"getmaster" option is deprecated, use "getprimary" instead.',
version='3.0.0', collection_name='community.mysql')
status = get_primary_status(cursor)
if not isinstance(status, dict):
status = dict(Is_Master=False, msg="Server is not configured as mysql master")
# TODO: change the word master to primary in 3.0.0
status = dict(Is_Master=False, Is_Primary=False,
msg="Server is not configured as mysql master")
else:
status['Is_Master'] = True
status['Is_Primary'] = True
module.deprecate('"Is_Master" and "Is_Slave" return values are deprecated '
'and will be replaced with "Is_Primary" and "Is_Replica" '
'in the next major release. Use "Is_Primary" and "Is_Replica" instead.',
version='3.0.0', collection_name='community.mysql')
module.exit_json(queries=executed_queries, **status)
elif mode in ("getreplica", "getslave"):
@ -536,56 +583,62 @@ def main():
status = get_replica_status(cursor, connection_name, channel, replica_term)
if not isinstance(status, dict):
# TODO: announce it and replace with Replica
# in the next major release. Maybe a warning?
status = dict(Is_Slave=False, msg="Server is not configured as mysql replica")
status = dict(Is_Slave=False, Is_Replica=False, msg="Server is not configured as mysql replica")
else:
# TODO: announce it and replace with Replica
# in the next major release. Maybe a warning?
status['Is_Slave'] = True
status['Is_Replica'] = True
module.deprecate('"Is_Master" and "Is_Slave" return values are deprecated '
'and will be replaced with "Is_Primary" and "Is_Replica" '
'in the next major release. Use "Is_Primary" and "Is_Replica" instead.',
version='3.0.0', collection_name='community.mysql')
module.exit_json(queries=executed_queries, **status)
elif mode in "changemaster":
elif mode in ('changeprimary', 'changemaster'):
if mode == 'changemaster':
module.deprecate('"changemaster" option is deprecated, use "changeprimary" instead.',
version='3.0.0', collection_name='community.mysql')
chm = []
result = {}
if master_host is not None:
chm.append("MASTER_HOST='%s'" % master_host)
if master_user is not None:
chm.append("MASTER_USER='%s'" % master_user)
if master_password is not None:
chm.append("MASTER_PASSWORD='%s'" % master_password)
if master_port is not None:
chm.append("MASTER_PORT=%s" % master_port)
if master_connect_retry is not None:
chm.append("MASTER_CONNECT_RETRY=%s" % master_connect_retry)
if master_log_file is not None:
chm.append("MASTER_LOG_FILE='%s'" % master_log_file)
if master_log_pos is not None:
chm.append("MASTER_LOG_POS=%s" % master_log_pos)
if master_delay is not None:
chm.append("MASTER_DELAY=%s" % master_delay)
if primary_host is not None:
chm.append("MASTER_HOST='%s'" % primary_host)
if primary_user is not None:
chm.append("MASTER_USER='%s'" % primary_user)
if primary_password is not None:
chm.append("MASTER_PASSWORD='%s'" % primary_password)
if primary_port is not None:
chm.append("MASTER_PORT=%s" % primary_port)
if primary_connect_retry is not None:
chm.append("MASTER_CONNECT_RETRY=%s" % primary_connect_retry)
if primary_log_file is not None:
chm.append("MASTER_LOG_FILE='%s'" % primary_log_file)
if primary_log_pos is not None:
chm.append("MASTER_LOG_POS=%s" % primary_log_pos)
if primary_delay is not None:
chm.append("MASTER_DELAY=%s" % primary_delay)
if relay_log_file is not None:
chm.append("RELAY_LOG_FILE='%s'" % relay_log_file)
if relay_log_pos is not None:
chm.append("RELAY_LOG_POS=%s" % relay_log_pos)
if master_ssl:
if primary_ssl:
chm.append("MASTER_SSL=1")
if master_ssl_ca is not None:
chm.append("MASTER_SSL_CA='%s'" % master_ssl_ca)
if master_ssl_capath is not None:
chm.append("MASTER_SSL_CAPATH='%s'" % master_ssl_capath)
if master_ssl_cert is not None:
chm.append("MASTER_SSL_CERT='%s'" % master_ssl_cert)
if master_ssl_key is not None:
chm.append("MASTER_SSL_KEY='%s'" % master_ssl_key)
if master_ssl_cipher is not None:
chm.append("MASTER_SSL_CIPHER='%s'" % master_ssl_cipher)
if master_auto_position:
if primary_ssl_ca is not None:
chm.append("MASTER_SSL_CA='%s'" % primary_ssl_ca)
if primary_ssl_capath is not None:
chm.append("MASTER_SSL_CAPATH='%s'" % primary_ssl_capath)
if primary_ssl_cert is not None:
chm.append("MASTER_SSL_CERT='%s'" % primary_ssl_cert)
if primary_ssl_key is not None:
chm.append("MASTER_SSL_KEY='%s'" % primary_ssl_key)
if primary_ssl_cipher is not None:
chm.append("MASTER_SSL_CIPHER='%s'" % primary_ssl_cipher)
if primary_auto_position:
chm.append("MASTER_AUTO_POSITION=1")
if master_use_gtid is not None:
chm.append("MASTER_USE_GTID=%s" % master_use_gtid)
if primary_use_gtid is not None:
chm.append("MASTER_USE_GTID=%s" % primary_use_gtid)
try:
changemaster(cursor, chm, connection_name, channel)
changeprimary(cursor, chm, connection_name, channel)
except mysql_driver.Warning as e:
result['warning'] = to_native(e)
except Exception as e:
@ -612,11 +665,17 @@ def main():
module.exit_json(msg="Replica stopped", changed=True, queries=executed_queries)
else:
module.exit_json(msg="Replica already stopped", changed=False, queries=executed_queries)
elif mode in "resetmaster":
reset = reset_master(module, cursor, fail_on_error)
elif mode in ('resetprimary', 'resetmaster'):
if mode == 'resetmaster':
module.deprecate('"resetmaster" option is deprecated, use "resetprimary" instead.',
version='3.0.0', collection_name='community.mysql')
reset = reset_primary(module, cursor, fail_on_error)
if reset is True:
# TODO: Change "Master" to "Primary" in release 3.0.0
module.exit_json(msg="Master reset", changed=True, queries=executed_queries)
else:
# TODO: Change "Master" to "Primary" in release 3.0.0
module.exit_json(msg="Master already reset", changed=False, queries=executed_queries)
elif mode in ("resetreplica", "resetslave"):
if mode == "resetslave":

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@ options:
description:
- Variable name to operate.
type: str
required: yes
required: true
value:
description:
- If set, then sets variable value to this.
@ -44,8 +44,9 @@ options:
default: global
version_added: '0.1.0'
notes:
- Does not support C(check_mode).
attributes:
check_mode:
support: none
seealso:
- module: community.mysql.mysql_info
@ -58,9 +59,12 @@ extends_documentation_fragment:
'''
EXAMPLES = r'''
# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument
- name: Check for sync_binlog setting
community.mysql.mysql_variables:
variable: sync_binlog
login_unix_socket: /run/mysqld/mysqld.sock
- name: Set read_only variable to 1 persistently
community.mysql.mysql_variables:

115
run_all_tests.py Executable file
View file

@ -0,0 +1,115 @@
#!/usr/bin/env python
import yaml
import os
github_workflow_file = '.github/workflows/ansible-test-plugins.yml'
def read_github_workflow_file():
with open(github_workflow_file, 'r') as gh_file:
try:
return yaml.safe_load(gh_file)
except yaml.YAMLError as exc:
print(exc)
def extract_value(target, dict_yaml):
for key, value in dict_yaml.items():
if key == target:
return value
def extract_matrix(workflow_yaml):
jobs = extract_value('jobs', workflow_yaml)
integration = extract_value('integration', jobs)
strategy = extract_value('strategy', integration)
matrix = extract_value('matrix', strategy)
return matrix
def is_exclude(exclude_list, test_suite):
test_is_excluded = False
for excl in exclude_list:
match = 0
if 'ansible' in excl:
if excl.get('ansible') == test_suite.get('ansible'):
match += 1
if 'db_engine_name' in excl:
if excl.get('db_engine_name') == test_suite.get('db_engine_name'):
match += 1
if 'db_engine_version' in excl:
if excl.get('db_engine_version') == test_suite.get('db_engine_version'):
match += 1
if 'python' in excl:
if excl.get('python') == test_suite.get('python'):
match += 1
if 'connector_name' in excl:
if excl.get('connector_name') == test_suite.get('connector_name'):
match += 1
if 'connector_version' in excl:
if excl.get('connector_version') == test_suite.get('connector_version'):
match += 1
if match > 1:
test_is_excluded = True
return test_is_excluded
return test_is_excluded
def main():
workflow_yaml = read_github_workflow_file()
tests_matrix_yaml = extract_matrix(workflow_yaml)
matrix = []
exclude_list = tests_matrix_yaml.get('exclude')
for ansible in tests_matrix_yaml.get('ansible'):
for db_engine_name in tests_matrix_yaml.get('db_engine_name'):
for db_engine_version in tests_matrix_yaml.get('db_engine_version'):
for python in tests_matrix_yaml.get('python'):
for connector_name in tests_matrix_yaml.get('connector_name'):
for connector_version in tests_matrix_yaml.get('connector_version'):
test_suite = {
'ansible': ansible,
'db_engine_name': db_engine_name,
'db_engine_version': db_engine_version,
'python': python,
'connector_name': connector_name,
'connector_version': connector_version
}
if not is_exclude(exclude_list, test_suite):
matrix.append(test_suite)
for tests in matrix:
a = tests.get('ansible')
dn = tests.get('db_engine_name')
dv = tests.get('db_engine_version')
p = tests.get('python')
cn = tests.get('connector_name')
cv = tests.get('connector_version')
make_cmd = (
f'make '
f'ansible="{a}" '
f'db_engine_name="{dn}" '
f'db_engine_version="{dv}" '
f'python="{p}" '
f'connector_name="{cn}" '
f'connector_version="{cv}" '
f'test-integration'
)
print(f'Run tests for: Ansible: {a}, DB: {dn} {dv}, Python: {p}, Connector: {cn} {cv}')
os.system(make_cmd)
# TODO, allow for CTRL+C to break the loop more easily
# TODO, store the failures from this iteration
# TODO, display a summary of failures from every iterations
if __name__ == '__main__':
main()

8
simplified_bsd.txt Normal file
View file

@ -0,0 +1,8 @@
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu2204-test-container:main
# ubuntu2204 comes with mariadb-client-10.6
# iproute2 # To grab docker network gateway address
# python3.10-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.10 \
python3.10-dev \
mariadb-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.1.1
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,15 @@
FROM quay.io/ansible/ubuntu2204-test-container:main
# ubuntu2204 comes with mariadb-client-10.6
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.10 \
mariadb-client \
iproute2
RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir pymysql==1.0.2
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mariadb-client-10.3
# iproute2 # To grab docker network gateway address
# python3.8-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
python3.8-dev \
mariadb-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.1
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,15 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mariadb-client-10.3
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
mariadb-client \
iproute2
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mariadb-client-10.3
# iproute2 # To grab docker network gateway address
# python3.9-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.9 \
python3.9-dev \
mariadb-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,15 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mariadb-client-10.3
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.9 \
mariadb-client \
iproute2
RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu1804-test-container:main
# ubuntu1804 comes with mysql-client-5.7
# iproute2 # To grab docker network gateway address
# python3.8-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
python3.8-dev \
mysql-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.1
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu1804-test-container:main
# ubuntu1804 comes with mysql-client-5.7
# iproute2 # To grab docker network gateway address
# python3.8-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
python3.8-dev \
mysql-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.7.11
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,15 @@
FROM quay.io/ansible/ubuntu1804-test-container:main
# ubuntu1804 comes with mysql-client-5.7
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
mysql-client \
iproute2
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu2204-test-container:main
# ubuntu2204 comes with mysql-client-8
# iproute2 # To grab docker network gateway address
# python3.10-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.10 \
python3.10-dev \
mysql-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.1.1
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,15 @@
FROM quay.io/ansible/ubuntu2204-test-container:main
# ubuntu2204 comes with mysql-client-8
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.10 \
mysql-client \
iproute2
RUN python3.10 -m pip install --disable-pip-version-check --no-cache-dir pymysql==1.0.2
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mysql-client-8
# iproute2 # To grab docker network gateway address
# python3.8-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
python3.8-dev \
mysql-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.1
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,15 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mysql-client-8
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.8 \
mysql-client \
iproute2
RUN python3.8 -m pip install --disable-pip-version-check --no-cache-dir pymysql==0.9.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,21 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mysql-client-8
# iproute2 # To grab docker network gateway address
# python3.9-dev # Reqs for mysqlclient
# default-libmysqlclient-dev # Reqs for mysqlclient
# build-essential # Reqs for mysqlclient
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.9 \
python3.9-dev \
mysql-client \
iproute2 \
default-libmysqlclient-dev \
build-essential
RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir mysqlclient==2.0.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -0,0 +1,16 @@
FROM quay.io/ansible/ubuntu2004-test-container:main
# ubuntu2004 comes with mysql-client-8
# iproute2 # To grab docker network gateway address
RUN apt-get update -y && \
DEBIAN_FRONTEND=noninteractive apt-get upgrade -y --no-install-recommends && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
python3.9 \
mysql-client \
iproute2
# cffi # To connect to MySQL 8 with Python3.9 and PyMySQL
RUN python3.9 -m pip install --disable-pip-version-check --no-cache-dir cffi pymysql==0.9.3
ENV container=docker
CMD ["/sbin/init"]

View file

@ -1,3 +1,5 @@
---
mysql_host: "{{ gateway_addr }}"
master_port: 3306
standby_port: 3307
test_db: test_db

View file

@ -11,7 +11,7 @@
# Auxiliary step:
- name: Get master status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: getmaster
register: primary_status
@ -19,10 +19,10 @@
# Set master_use_gtid disabled:
- name: Run replication
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: changemaster
master_host: 127.0.0.1
master_host: '{{ mysql_host }}'
master_port: "{{ primary_db.port }}"
master_user: "{{ replication_user }}"
master_password: "{{ replication_pass }}"
@ -38,13 +38,13 @@
# Start standby for further tests:
- name: Start standby
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: startslave
- name: Get standby status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: getslave
register: slave_status
@ -56,7 +56,7 @@
# Stop standby for further tests:
- name: Stop standby
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: stopslave
@ -67,7 +67,7 @@
# Auxiliary step:
- name: Get master status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: getmaster
register: primary_status
@ -75,10 +75,10 @@
# Set master_use_gtid current_pos:
- name: Run replication
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: changemaster
master_host: 127.0.0.1
master_host: '{{ mysql_host }}'
master_port: "{{ primary_db.port }}"
master_user: "{{ replication_user }}"
master_password: "{{ replication_pass }}"
@ -94,13 +94,13 @@
# Start standby for further tests:
- name: Start standby
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: startslave
- name: Get standby status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: getslave
register: slave_status
@ -112,7 +112,7 @@
# Stop standby for further tests:
- name: Stop standby
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: stopslave
@ -123,7 +123,7 @@
# Auxiliary step:
- name: Get master status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: getmaster
register: primary_status
@ -131,10 +131,10 @@
# Set master_use_gtid slave_pos:
- name: Run replication
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: changemaster
master_host: 127.0.0.1
master_host: '{{ mysql_host }}'
master_port: "{{ primary_db.port }}"
master_user: "{{ replication_user }}"
master_password: "{{ replication_pass }}"
@ -150,13 +150,13 @@
# Start standby for further tests:
- name: Start standby
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: startslave
- name: Get standby status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: getslave
register: slave_status
@ -168,6 +168,6 @@
# Stop standby for further tests:
- name: Stop standby
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: stopslave

View file

@ -4,20 +4,20 @@
# Needs for further tests:
- name: Stop slave
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: stopslave
- name: Reset slave all
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: resetslaveall
# Get master log pos:
- name: Get master status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: getmaster
register: primary_status
@ -25,10 +25,10 @@
# Test changemaster mode:
- name: Run replication with connection_name
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: changemaster
master_host: 127.0.0.1
master_host: '{{ mysql_host }}'
master_port: "{{ primary_db.port }}"
master_user: "{{ replication_user }}"
master_password: "{{ replication_pass }}"
@ -45,7 +45,7 @@
# Test startslave mode:
- name: Start slave with connection_name
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: startslave
connection_name: "{{ conn_name }}"
@ -59,7 +59,7 @@
# Test getslave mode:
- name: Get standby statu with connection_name
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: getslave
connection_name: "{{ conn_name }}"
@ -68,7 +68,7 @@
- assert:
that:
- slave_status.Is_Slave == true
- slave_status.Master_Host == '127.0.0.1'
- slave_status.Master_Host == ''{{ mysql_host }}''
- slave_status.Exec_Master_Log_Pos == primary_status.Position
- slave_status.Master_Port == {{ primary_db.port }}
- slave_status.Last_IO_Errno == 0
@ -78,7 +78,7 @@
# Test stopslave mode:
- name: Stop slave with connection_name
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: stopslave
connection_name: "{{ conn_name }}"
@ -92,7 +92,7 @@
# Test reset
- name: Reset slave with connection_name
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: resetslave
connection_name: "{{ conn_name }}"
@ -106,7 +106,7 @@
# Test reset all
- name: Reset slave all with connection_name
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: resetslaveall
connection_name: "{{ conn_name }}"

View file

@ -3,11 +3,11 @@
# Preparation:
- name: Create user for replication
shell: "echo \"GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'localhost' IDENTIFIED BY '{{ replication_pass }}'; FLUSH PRIVILEGES;\" | mysql -P {{ primary_db.port }} -h 127.0.0.1"
shell: "echo \"GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'localhost' IDENTIFIED BY '{{ replication_pass }}'; FLUSH PRIVILEGES;\" | mysql -P {{ primary_db.port }} -h '{{ mysql_host }}'"
- name: Create test database
mysql_db:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ primary_db.port }}'
state: present
name: '{{ test_db }}'
@ -16,12 +16,12 @@
shell: 'mysqldump -P {{ primary_db.port }} -h 127.0.01 --all-databases --master-data=2 > {{ dump_path }}'
- name: Restore the dump to the replica
shell: 'mysql -P {{ replica_db.port }} -h 127.0.0.1 < {{ dump_path }}'
shell: "mysql -P {{ replica_db.port }} -h '{{ mysql_host }}' < {{ dump_path }}"
# Test getmaster mode:
- name: Get master status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ primary_db.port }}"
mode: getmaster
register: master_status
@ -35,10 +35,10 @@
# Test changemaster mode:
- name: Run replication
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: changemaster
master_host: 127.0.0.1
master_host: '{{ mysql_host }}'
master_port: "{{ primary_db.port }}"
master_user: "{{ replication_user }}"
master_password: "{{ replication_pass }}"
@ -54,7 +54,7 @@
# Test startslave mode:
- name: Start slave
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: startslave
register: result
@ -67,7 +67,7 @@
# Test getslave mode:
- name: Get replica status
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: getslave
register: slave_status
@ -75,7 +75,7 @@
- assert:
that:
- slave_status.Is_Slave == true
- slave_status.Master_Host == '127.0.0.1'
- slave_status.Master_Host == ''{{ mysql_host }}''
- slave_status.Exec_Master_Log_Pos == master_status.Position
- slave_status.Master_Port == {{ primary_db.port }}
- slave_status.Last_IO_Errno == 0
@ -85,7 +85,7 @@
# Test stopslave mode:
- name: Stop slave
mysql_replication:
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: "{{ replica_db.port }}"
mode: stopslave
register: result

View file

@ -0,0 +1,11 @@
---
- name: "{{ role_name }} | Fake root | Ensure folder"
ansible.builtin.file:
path: "{{ playbook_dir }}/root"
state: directory
- name: "{{ role_name }} | Fake root | Ensure default file exists"
ansible.builtin.file:
path: "{{ playbook_dir }}/root/.my.cnf"
state: touch

View file

@ -0,0 +1,18 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
####################################################################
- name: Prepare the fake root folder
ansible.builtin.import_tasks:
file: fake_root.yml
# setvars.yml requires the iproute2 package installed by install.yml
- name: Set variables
ansible.builtin.import_tasks:
file: setvars.yml
- name: Verify all components version under test
ansible.builtin.import_tasks:
file: verify.yml

View file

@ -0,0 +1,79 @@
---
- name: "{{ role_name }} | Setvars | Extract Podman/Docker Network Gateway"
ansible.builtin.shell:
cmd: ip route|grep default|awk '{print $3}'
register: ip_route_output
- name: "{{ role_name }} | Setvars | Set Fact"
ansible.builtin.set_fact:
gateway_addr: "{{ ip_route_output.stdout }}"
connector_name_lookup: >-
{{ lookup(
'file',
'/root/ansible_collections/community/mysql/tests/integration/connector_name'
) }}
connector_version_lookup: >-
{{ lookup(
'file',
'/root/ansible_collections/community/mysql/tests/integration/connector_version'
) }}
db_engine_name_lookup: >-
{{ lookup(
'file',
'/root/ansible_collections/community/mysql/tests/integration/db_engine_name'
) }}
db_engine_version_lookup: >-
{{ lookup(
'file',
'/root/ansible_collections/community/mysql/tests/integration/db_engine_version'
) }}
python_version_lookup: >-
{{ lookup(
'file',
'/root/ansible_collections/community/mysql/tests/integration/python'
) }}
ansible_version_lookup: >-
{{ lookup(
'file',
'/root/ansible_collections/community/mysql/tests/integration/ansible'
) }}
- name: "{{ role_name }} | Setvars | Set Fact using above facts"
ansible.builtin.set_fact:
connector_name: "{{ connector_name_lookup.strip() }}"
connector_version: "{{ connector_version_lookup.strip() }}"
db_engine: "{{ db_engine_name_lookup.strip() }}"
db_version: "{{ db_engine_version_lookup.strip() }}"
python_version: "{{ python_version_lookup.strip() }}"
test_ansible_version: >-
{%- if ansible_version_lookup == 'devel' -%}
{{ ansible_version_lookup }}
{%- else -%}
{{ ansible_version_lookup.split('-')[1].strip() }}
{%- endif -%}
mysql_command: >-
mysql
-h{{ gateway_addr }}
-P{{ mysql_primary_port }}
-u{{ mysql_user }}
-p{{ mysql_password }}
--protocol=tcp
mysql_command_wo_port: >-
mysql
-h{{ gateway_addr }}
-u{{ mysql_user }}
-p{{ mysql_password }}
--protocol=tcp
- name: "{{ role_name }} | Setvars | Output test informations"
vars:
msg: |-
connector_name: {{ connector_name }}
connector_version: {{ connector_version }}
db_engine: {{ db_engine }}
db_version: {{ db_version }}
python_version: {{ python_version }}
test_ansible_version: {{ test_ansible_version }}
ansible.builtin.debug:
msg: "{{ msg.split('\n') }}"

View file

@ -0,0 +1,63 @@
---
- vars:
mysql_parameters: &mysql_params
login_user: root
login_password: msandbox
login_host: "{{ gateway_addr }}"
login_port: 3307
block:
- name: Query Primary container over TCP for MySQL/MariaDB version
mysql_info:
<<: *mysql_params
filter:
- version
register: primary_info
- name: Assert that test container runs the expected MySQL/MariaDB version
assert:
that:
- registred_db_version == db_version
vars:
registred_db_version:
"{{ primary_info.version.major }}.{{ primary_info.version.minor }}\
.{{ primary_info.version.release }}"
- name: Assert that mysql_info module used the expected version of pymysql
assert:
that:
- primary_info.connector_name == connector_name
- primary_info.connector_version == connector_version
when:
- connector_name == 'pymysql'
- name: Assert that mysql_info module used the expected version of mysqlclient
assert:
that:
- primary_info.connector_name == 'MySQLdb'
- primary_info.connector_version == connector_version
when:
- connector_name == 'mysqlclient'
- name: Display the python version in use
command:
cmd: python{{ python_version }} -V
changed_when: false
register: python_in_use
- name: Assert that expected Python is installed
assert:
that:
- python_in_use.stdout is search(python_version)
- name: Assert that we run the expected ansible version
assert:
that:
- ansible_running_version == test_ansible_version
vars:
ansible_running_version:
"{{ ansible_version.major }}.{{ ansible_version.minor }}"
when:
- test_ansible_version != 'devel' # Devel will change overtime

View file

@ -1,13 +0,0 @@
dbdeployer_version: 1.52.0
dbdeployer_home_dir: /opt/dbdeployer
home_dir: /root
percona_client_version: 5.7
mariadb_install: false
mysql_version: 8.0.22
mariadb_version: 10.5.4
mysql_base_port: 3306

View file

@ -1,6 +0,0 @@
---
- name: "{{ role_name }} | handler | create dbdeployer installed file"
template:
src: installed_file.j2
dest: "{{ dbdeployer_installed_file }}"
listen: create zookeeper installed file

View file

@ -1,15 +0,0 @@
---
- name: "{{ role_name }} | config | download mysql tarball"
get_url:
url: "{{ install_src }}"
dest: "{{ dbdeployer_sandbox_download_dir }}/{{ install_tarball }}"
- name: "{{ role_name }} | config | run unpack tarball"
shell:
cmd: "dbdeployer unpack {{ dbdeployer_sandbox_download_dir }}/{{ install_tarball }}"
creates: "{{ dbdeployer_sandbox_binary_dir }}/{{ install_version }}"
- name: "{{ role_name }} | config | setup replication topology"
shell:
cmd: "dbdeployer deploy multiple {{ install_version }} --base-port {{ mysql_base_port }} --my-cnf-options=\"master_info_repository='TABLE'\" --my-cnf-options=\"relay_log_info_repository='TABLE'\""
creates: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}"

View file

@ -1,11 +0,0 @@
---
- name: "{{ role_name }} | dir | create dbdeployer directories"
file:
state: directory
path: "{{ item }}"
loop:
- "{{ dbdeployer_home_dir }}"
- "{{ dbdeployer_install_dir }}"
- "{{ dbdeployer_sandbox_download_dir }}"
- "{{ dbdeployer_sandbox_binary_dir }}"
- "{{ dbdeployer_sandbox_home_dir }}"

View file

@ -1,59 +0,0 @@
---
- name: "{{ role_name }} | install | add apt signing key for percona"
apt_key:
keyserver: keyserver.ubuntu.com
id: 4D1BB29D63D98E422B2113B19334A25F8507EFA5
state: present
- name: "{{ role_name }} | install | add percona repositories"
apt_repository:
repo: "{{ item }}"
state: present
loop: "{{ percona_mysql_repos }}"
- name: "{{ role_name }} | install | install packages required by percona"
apt:
name: "{{ percona_mysql_packages }}"
state: present
environment:
DEBIAN_FRONTEND: noninteractive
- name: "{{ role_name }} | install | install packages required by mysql connector"
apt:
name: "{{ install_python_prereqs }}"
state: present
environment:
DEBIAN_FRONTEND: noninteractive
- name: "{{ role_name }} | install | install python packages"
pip:
name: "{{ python_packages }}"
- name: "{{ role_name }} | install | install packages required by mysql"
apt:
name: "{{ install_prereqs }}"
state: present
environment:
DEBIAN_FRONTEND: noninteractive
- name: "{{ role_name }} | install | download and unpack dbdeployer"
unarchive:
remote_src: true
src: "{{ dbdeployer_src }}"
dest: "{{ dbdeployer_install_dir }}"
creates: "{{ dbdeployer_installed_file }}"
register: dbdeployer_tarball_install
notify:
- create zookeeper installed file
until: dbdeployer_tarball_install is not failed
retries: 6
delay: 5
- name: "{{ role_name }} | install | create symlink"
file:
src: "{{ dbdeployer_install_dir }}/dbdeployer-{{ dbdeployer_version }}.linux"
dest: /usr/local/bin/dbdeployer
follow: false
state: link
- meta: flush_handlers

View file

@ -1,28 +0,0 @@
---
- name: "{{ role_name }} | setvars | split mysql version in parts"
set_fact:
mysql_version_parts: "{{ mysql_version.split('.') }}"
- name: "{{ role_name }} | setvars | get mysql major version"
set_fact:
mysql_major_version: "{{ mysql_version_parts[0] + '.' + mysql_version_parts[1] }}"
- name: "{{ role_name }} | setvars | set the appropriate extension dependent on the mysql version"
set_fact:
mysql_compression_extension: "{{ mysql_version is version('8.0.0', '<') | ternary('gz', 'xz') }}"
- name: "{{ role_name }} | setvars | set the install type"
set_fact:
install_type: "{{ mariadb_install | ternary('mariadb', 'mysql') }}"
- name: "{{ role_name }} | setvars | set install_version"
set_fact:
install_version: "{{ lookup('vars', install_type + '_version') }}"
- name: "{{ role_name }} | setvars | set install_tarball"
set_fact:
install_tarball: "{{ lookup('vars', install_type + '_tarball') }}"
- name: "{{ role_name }} | setvars | set install_src"
set_fact:
install_src: "{{ lookup('vars', install_type + '_src') }}"

View file

@ -1,27 +0,0 @@
---
- name: "{{ role_name }} | verify | confirm primary is running and get the port"
shell: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}/n1 -BNe'select @@port'"
register: primary_port
- name: "{{ role_name }} | verify | confirm replica1 is running and get the port"
shell: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}/n2 -BNe'select @@port'"
register: replica1_port
- name: "{{ role_name }} | verify | confirm replica2 is running and get the port"
shell: "{{ dbdeployer_sandbox_home_dir }}/multi_msb_{{ install_version|replace('.','_') }}/n3 -BNe'select @@port'"
register: replica2_port
- name: "{{ role_name }} | verify | confirm primary is running on expected port"
assert:
that:
- primary_port.stdout|int == 3307
- name: "{{ role_name }} | verify | confirm replica1 is running on expected port"
assert:
that:
- replica1_port.stdout|int == 3308
- name: "{{ role_name }} | verify | confirm replica2 is running on expected port"
assert:
that:
- replica2_port.stdout|int == 3309

View file

@ -1 +0,0 @@
{{ dbdeployer_version }}

View file

@ -1,31 +0,0 @@
---
dbdeployer_install_dir: "{{ dbdeployer_home_dir }}/dbdeployer_{{ dbdeployer_version }}"
dbdeployer_src: "https://github.com/datacharmer/dbdeployer/releases/download/v{{ dbdeployer_version }}/dbdeployer-{{ dbdeployer_version }}.linux.tar.gz"
dbdeployer_installed_file: "{{ dbdeployer_home_dir }}/dbdeployer_installed"
dbdeployer_sandbox_download_dir: "{{ home_dir }}/downloads"
dbdeployer_sandbox_binary_dir: "{{ home_dir }}/opt/mysql"
dbdeployer_sandbox_home_dir: "{{ home_dir }}/sandboxes"
percona_mysql_repos:
- deb http://repo.percona.com/apt {{ ansible_lsb.codename }} main
- deb-src http://repo.percona.com/apt {{ ansible_lsb.codename }} main
percona_mysql_packages:
- percona-server-client-{{ percona_client_version }}
python_packages: [pymysql == 0.9.3]
install_prereqs:
- libaio1
- libnuma1
install_python_prereqs:
- python3-dev
- default-libmysqlclient-dev
- build-essential
mysql_tarball: "mysql-{{ mysql_version }}-linux-glibc2.12-x86_64.tar.{{ mysql_compression_extension }}"
mysql_src: "https://dev.mysql.com/get/Downloads/MySQL-{{ mysql_major_version }}/{{ mysql_tarball }}"
mariadb_tarball: "mariadb-{{ mariadb_version }}-linux-x86_64.tar.gz"
mariadb_src: "https://downloads.mariadb.com/MariaDB/mariadb-{{ mariadb_version }}/bintar-linux-x86_64/{{ mariadb_tarball }}"

View file

@ -2,9 +2,20 @@
# defaults file for test_mysql_db
mysql_user: root
mysql_password: msandbox
mysql_host: '{{ gateway_addr }}'
mysql_primary_port: 3307
db_name: 'data'
# Database names
db_names:
- "data"
- "db%"
# Database formats
db_formats:
- { format_type: "sql", file: "dbdata.sql", format_msg_type: "ASCII", file2: "dump2.sql", file3: "dump3.sql", file4: "dump4.sql" }
- { format_type: "gz", file: "dbdata.gz", format_msg_type: "gzip", file2: "dump2.gz", file3: "dump3.gz", file4: "dump4.gz" }
- { format_type: "bz2", file: "dbdata.bz2", format_msg_type: "bzip2", file2: "dump2.bz2", file3: "dump3.bz2", file4: "dump4.bz2" }
db_name2: 'data2'
db_user1: 'datauser1'
db_user2: 'datauser2'

View file

@ -1,2 +1,2 @@
dependencies:
- setup_mysql
- setup_controller

View file

@ -1,43 +1,59 @@
- set_fact:
---
- name: Config overrides | Set facts
set_fact:
db_to_create: testdb1
config_file: "/root/.my1.cnf"
config_file: "{{ playbook_dir }}/.my1.cnf"
fake_port: 9999
fake_host: "blahblah.local"
include_dir: "/root/mycnf.d"
include_dir: "{{ playbook_dir }}/mycnf.d"
- name: Create custom config file
- name: Config overrides | Create custom config file
shell: 'echo "[client]" > {{ config_file }}'
- name: Add fake port to config file
- name: Config overrides | Add fake port to config file
shell: 'echo "port = {{ fake_port }}" >> {{ config_file }}'
- name: Get pymysql version
shell: pip show pymysql | awk '/Version/ {print $2}'
register: pymysql_version
- name: Add blank line
- name: Config overrides | Add blank line
shell: 'echo "" >> {{ config_file }}'
when: (pymysql_version.stdout | default('1000', true)) is version('0.9.3', '>=')
when:
- >
connector_name != 'pymysql'
or (
connector_name == 'pymysql'
and connector_version is version('0.9.3', '>=')
)
- name: Create include_dir
- name: Config overrides | Create include_dir
file:
path: '{{ include_dir }}'
state: directory
mode: '0777'
when: (pymysql_version.stdout | default('1000', true)) is version('0.9.3', '>=')
when:
- >
connector_name != 'pymysql'
or (
connector_name == 'pymysql'
and connector_version is version('0.9.3', '>=')
)
- name: Add include_dir
- name: Config overrides | Add include_dir
lineinfile:
path: '{{ config_file }}'
line: '!includedir {{ include_dir }}'
insertafter: EOF
when: (pymysql_version.stdout | default('1000', true)) is version('0.9.3', '>=')
when:
- >
connector_name != 'pymysql'
or (
connector_name == 'pymysql'
and connector_version is version('0.9.3', '>=')
)
- name: Create database using fake port to connect to, must fail
- name: Config overrides | Create database using fake port to connect to, must fail
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_to_create }}'
state: present
@ -47,17 +63,17 @@
ignore_errors: yes
register: result
- name: Must fail because login_port default has beed overriden by wrong value from config file
- name: Config overrides | Must fail because login_port default has beed overriden by wrong value from config file
assert:
that:
- result is failed
- result.msg is search("unable to connect to database")
- result is failed
- result.msg is search("unable to connect to database")
- name: Create database using default port
- name: Config overrides | Create database using default port
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_to_create }}'
state: present
@ -66,22 +82,22 @@
config_overrides_defaults: no
register: result
- name: Must not fail because of the default of login_port is correct
- name: Config overrides | Must not fail because of the default of login_port is correct
assert:
that:
- result is changed
- result is changed
- name: Reinit custom config file
- name: Config overrides | Reinit custom config file
shell: 'echo "[client]" > {{ config_file }}'
- name: Add fake host to config file
- name: Config overrides | Add fake host to config file
shell: 'echo "host = {{ fake_host }}" >> {{ config_file }}'
- name: Remove database using fake login_host
- name: Config overrides | Remove database using fake login_host
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_to_create }}'
state: absent
@ -90,18 +106,17 @@
register: result
ignore_errors: yes
- name: Must fail because login_host default has beed overriden by wrong value from config file
- name: Config overrides | Must fail because login_host default has beed overriden by wrong value from config file
assert:
that:
- result is failed
- result.msg is search("Can't connect to MySQL server on '{{ fake_host }}'") or result.msg is search("Unknown MySQL server host '{{ fake_host }}'")
- result is failed
- result.msg is search("Can't connect to MySQL server on '{{ fake_host }}'") or result.msg is search("Unknown MySQL server host '{{ fake_host }}'")
# Clean up
- name: Remove test db
- name: Config overrides | Clean up test database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_to_create }}'
state: absent

View file

@ -1,98 +1,105 @@
---
- set_fact:
latin1_file1: "{{tmp_dir}}/{{file}}"
- name: Encoding | Set fact
set_fact:
latin1_file1: "{{ tmp_dir }}/{{ file }}"
- name: Deleting Latin1 encoded Database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_latin1_name }}'
state: absent
- name: create Latin1 encoded database
- name: Encoding | Create Latin1 encoded database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_latin1_name }}'
state: present
encoding: latin1
- name: create a table in Latin1 database
- name: Encoding | Create a table in Latin1 database
command: "{{ mysql_command }} {{ 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
- name: Encoding | Inserting data into Latin1 database
command: "{{ mysql_command }} {{ db_latin1_name }} -e \"insert into testlatin1 value(47,'Amédée Bôlüt')\""
- name: selecting table
- name: Encoding | Selecting table
command: "{{ mysql_command }} {{ db_latin1_name }} -e \"select * from testlatin1\""
register: output
- name: Dumping a table in Latin1 database
- name: Encoding | Dumping a table in Latin1 database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: "{{ db_latin1_name }}"
encoding: latin1
target: "{{ latin1_file1 }}"
state: dump
register: dump_result
register: result
- assert:
that:
- result is changed
- result is changed
- name: state dump - file name should exist
- name: Encoding | State dump - file name should exist (latin1_file1)
file:
name: '{{ latin1_file1 }}'
state: file
- name: od the file and check of latin1 encoded string is present
- 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
- name: Encoding | Dropping {{ db_latin1_name }} database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_latin1_name }}'
state: absent
- name: Importing the latin1 mysql script
- name: Encoding | Importing the latin1 mysql script
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
state: import
encoding: latin1
name: '{{ db_latin1_name }}'
target: "{{ latin1_file1 }}"
register: result
- assert:
- name: Encoding | Assert that importing latin1 is changed
assert:
that:
- result is changed
- result is changed
- name: check encoding of table
shell: "{{ mysql_command }} {{ db_latin1_name }} -e \"SHOW FULL COLUMNS FROM testlatin1\""
- name: Encoding | Check encoding of table
ansible.builtin.command:
cmd: >
{{ mysql_command }}
{{ db_latin1_name }}
-e "SHOW FULL COLUMNS FROM {{ db_latin1_name }}.testlatin1"
register: output
failed_when: '"latin1_swedish_ci" not in output.stdout'
- name: remove database
- name: Encoding | Clean up database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: '{{ db_latin1_name }}'
state: absent

View file

@ -1,17 +1,20 @@
---
- name: set fact tls_enabled
command: "{{ mysql_command }} \"-e SHOW VARIABLES LIKE 'have_ssl';\""
register: result
- set_fact:
tls_enabled: "{{ 'YES' in result.stdout | bool | default('false', true) }}"
- vars:
mysql_parameters: &mysql_params
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
when: tls_enabled
block:
# ============================================================
- shell: pip show pymysql | awk '/Version/ {print $2}'
register: pymysql_version
- name: get server certificate
copy:
content: "{{ lookup('pipe', \"openssl s_client -starttls mysql -connect localhost:3307 -showcerts 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'\") }}"
@ -22,6 +25,7 @@
mysql_user:
<<: *mysql_params
name: '{{ user_name_1 }}'
host_all: true
state: absent
ignore_errors: yes
@ -29,6 +33,7 @@
mysql_user:
<<: *mysql_params
name: "{{ user_name_1 }}"
host: "%"
password: "{{ user_password_1 }}"
priv: '*.*:ALL,GRANT'
tls_requires:
@ -40,7 +45,7 @@
state: absent
login_user: '{{ user_name_1 }}'
login_password: '{{ user_password_1 }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
ca_cert: /tmp/cert.pem
register: result
@ -49,12 +54,14 @@
- assert:
that:
- result is failed
when: pymysql_version.stdout != ""
when:
- connector_name == 'pymysql'
- assert:
that:
- result is succeeded
when: pymysql_version.stdout == ""
when:
- connector_name != 'pymysql'
- name: attempt connection with newly created user ignoring hostname
mysql_db:
@ -62,7 +69,7 @@
state: absent
login_user: '{{ user_name_1 }}'
login_password: '{{ user_password_1 }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
ca_cert: /tmp/cert.pem
check_hostname: no
@ -77,5 +84,5 @@
mysql_user:
<<: *mysql_params
name: '{{ user_name_1 }}'
host: 127.0.0.1
host_all: true
state: absent

View file

@ -1,3 +1,4 @@
---
####################################################################
# WARNING: These are designed specifically for Ansible tests #
# and should not be used as examples of how to write Ansible roles #
@ -21,306 +22,41 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# ============================================================
- name: alias mysql command to include default options
set_fact:
mysql_command: "mysql -u{{ mysql_user }} -p{{ mysql_password }} -P{{ mysql_primary_port }} --protocol=tcp"
- name: Check state present/absent
include_tasks: state_present_absent.yml
vars:
db_name: "{{ item }}"
loop: "{{ db_names }}"
- name: remove database if it exists
command: >
"{{ mysql_command }} -sse 'drop database {{ db_name }}'"
ignore_errors: True
- name: Check state dump/import
include_tasks: state_dump_import.yml
vars:
db_name: "{{ item.0 }}"
file: "{{ item.1.file }}"
file2: "{{ item.1.file2 }}"
file3: "{{ item.1.file3 }}"
file4: "{{ item.1.file4 }}"
format_msg_type: "{{ item.1.format_msg_type }}"
format_type: "{{ item.1.format_type }}"
with_nested:
- "{{ db_names }}"
- "{{ db_formats }}"
- name: make sure the test database is not there
command: "{{ mysql_command }} {{ db_name }}"
register: mysql_db_check
failed_when: "'1049' not in mysql_db_check.stderr"
- name: Check state present/absent with multiple databases
include_tasks: multi_db_create_delete.yml
- name: test state=present for a database name (expect changed=true)
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: '{{ db_name }}'
state: present
register: result
- name: Check state dump/import with encoding
include_tasks: encoding_dump_import.yml
vars:
file: "latin1.sql"
format_msg_type: "ASCII"
- name: assert output message that database exist
assert:
that:
- result is changed
- result.db == '{{ db_name }}'
- result.executed_commands == ["CREATE DATABASE `{{ db_name }}`"]
- name: run command to test state=present for a database name (expect db_name in stdout)
command: "{{ mysql_command }} -e \"show databases like '{{ db_name }}'\""
register: result
- name: assert database exist
assert:
that:
- "'{{ db_name }}' in result.stdout"
# ============================================================
- name: test state=absent for a database name (expect changed=true)
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: '{{ db_name }}'
state: absent
register: result
- name: assert output message that database does not exist
assert:
that:
- result is changed
- result.db == '{{ db_name }}'
- result.executed_commands == ["DROP DATABASE `{{ db_name }}`"]
- name: run command to test state=absent for a database name (expect db_name not in stdout)
command: "{{ mysql_command }} -e \"show databases like '{{ db_name }}'\""
register: result
- name: assert database does not exist
assert:
that:
- "'{{ db_name }}' not in result.stdout"
# ============================================================
- name: test mysql_db encoding param not valid - issue 8075
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: datanotvalid
state: present
encoding: notvalid
register: result
ignore_errors: true
- name: assert test mysql_db encoding param not valid - issue 8075 (failed=true)
assert:
that:
- "result.failed == true"
- "'Traceback' not in result.msg"
- "'Unknown character set' in result.msg"
# ============================================================
- name: test mysql_db using a valid encoding utf8 (expect changed=true)
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: 'en{{ db_name }}'
state: present
encoding: utf8
register: result
- name: assert output message created a database
assert:
that:
- result is changed
- result.executed_commands == ["CREATE DATABASE `en{{ db_name }}` CHARACTER SET 'utf8'"]
- name: test database was created
command: "{{ mysql_command }} -e \"SHOW CREATE DATABASE en{{ db_name }}\""
register: result
- name: assert created database is of encoding utf8
assert:
that:
- "'utf8' in result.stdout"
- name: remove database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: 'en{{ db_name }}'
state: absent
# ============================================================
- name: test mysql_db using valid encoding binary (expect changed=true)
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: 'en{{ db_name }}'
state: present
encoding: binary
register: result
- name: assert output message that database was created
assert:
that:
- result is changed
- result.executed_commands == ["CREATE DATABASE `en{{ db_name }}` CHARACTER SET 'binary'"]
- name: run command to test database was created
command: "{{ mysql_command }} -e \"SHOW CREATE DATABASE en{{ db_name }}\""
register: result
- name: assert created database is of encoding binary
assert:
that:
- "'binary' in result.stdout"
- name: remove database
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: 'en{{ db_name }}'
state: absent
# ============================================================
- name: create user1 to access database dbuser1
mysql_user:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: user1
password: 'Hfd6fds^dfA8Ga'
priv: '*.*:ALL'
state: present
- name: create database dbuser1 using user1
mysql_db:
login_user: user1
login_password: 'Hfd6fds^dfA8Ga'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: '{{ db_user1 }}'
state: present
register: result
- name: assert output message that database was created
assert:
that:
- "result.changed == true"
- name: run command to test database was created using user1
command: "{{ mysql_command }} -e \"show databases like '{{ db_user1 }}'\""
register: result
- name: assert database exist
assert:
that:
- "'{{ db_user1 }}' in result.stdout"
# ============================================================
- name: create user2 to access database with privilege select only
mysql_user:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: user2
password: 'kjsfd&F7safjad'
priv: '*.*:SELECT'
state: present
- name: create database dbuser2 using user2 with no privilege to create (expect failed=true)
mysql_db:
login_user: user2
login_password: 'kjsfd&F7safjad'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: '{{ db_user2 }}'
state: present
register: result
ignore_errors: true
- name: assert output message that database was not created using dbuser2
assert:
that:
- "result.failed == true"
- "'Access denied' in result.msg"
- name: run command to test that database was not created
command: "{{ mysql_command }} -e \"show databases like '{{ db_user2 }}'\""
register: result
- name: assert database does not exist
assert:
that:
- "'{{ db_user2 }}' not in result.stdout"
# ============================================================
- name: delete database using user2 with no privilege to delete (expect failed=true)
mysql_db:
login_user: user2
login_password: 'kjsfd&F7safjad'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: '{{ db_user1 }}'
state: absent
register: result
ignore_errors: true
- name: assert output message that database was not deleted using dbuser2
assert:
that:
- "result.failed == true"
- "'Access denied' in result.msg"
- name: run command to test database was not deleted
command: "{{ mysql_command }} -e \"show databases like '{{ db_user1 }}'\""
register: result
- name: assert database still exist
assert:
that:
- "'{{ db_user1 }}' in result.stdout"
# ============================================================
- name: delete database using user1 with all privilege to delete a database (expect changed=true)
mysql_db:
login_user: user1
login_password: 'Hfd6fds^dfA8Ga'
login_host: 127.0.0.1
login_port: '{{ mysql_primary_port }}'
name: '{{ db_user1 }}'
state: absent
register: result
ignore_errors: true
- name: assert output message that database was deleted using user1
assert:
that:
- result is changed
- result.executed_commands == ["DROP DATABASE `{{ db_user1 }}`"]
- name: run command to test database was deleted using user1
command: "{{ mysql_command }} -e \"show databases like '{{ db_name }}'\""
register: result
- name: assert database does not exist
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 file4=dump4.sql
- 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 file4=dump4.bz2
- include: multi_db_create_delete.yml
- include: encoding_dump_import.yml file=latin1.sql format_msg_type=ASCII
- include: config_overrides_defaults.yml
- name: Check MySQL config file
include_tasks: config_overrides_defaults.yml
when: ansible_python.version_info[0] >= 3
- include: issue-28.yml
- name: Check issue 28
include_tasks: issue-28.yml
vars:
db_name: "{{ item }}"
loop: "{{ db_names }}"

View file

@ -14,6 +14,18 @@
#
# ==========================================================================
# Initial check - To confirm that database does not exist before executing check mode tasks
- name: Drop databases before test
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
- '{{ db2_name }}'
- '{{ db3_name }}'
state: absent
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
register: mysql_result
@ -31,7 +43,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -44,7 +56,7 @@
- name: assert successful completion of create database using check_mode since databases does not exist prior
assert:
that:
- check_mode_result.changed == true
- check_mode_result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -63,7 +75,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -75,7 +87,7 @@
- name: assert successful completion of create database
assert:
that:
- result.changed == true
- result is changed
- result.db_list == ['{{ db1_name }}', '{{ db2_name }}', '{{ db3_name }}']
- name: run command to list databases like specified database name
@ -95,7 +107,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -108,7 +120,7 @@
- name: assert that recreation of existing databases does not make change (since recreated using check mode)
assert:
that:
- check_mode_result.changed == false
- check_mode_result is not changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -127,7 +139,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -139,7 +151,7 @@
- name: assert that recreation of existing databases does not make change
assert:
that:
- result.changed == false
- result is not changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -158,7 +170,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db2_name }}'
@ -168,7 +180,7 @@
- name: assert successful completion of deleting database
assert:
that:
- result.changed == true
- result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -187,7 +199,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -200,7 +212,7 @@
- name: assert successful completion of recreation of partially existing database using check mode
assert:
that:
- check_mode_result.changed == true
- check_mode_result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -219,7 +231,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -231,7 +243,7 @@
- name: assert successful completion of create database
assert:
that:
- result.changed == true
- result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -259,7 +271,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -272,7 +284,7 @@
- name: assert successful completion of dump operation using check mode
assert:
that:
- check_mode_dump_result.changed == true
- check_mode_dump_result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -296,7 +308,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- "{{ db1_name }}"
@ -336,7 +348,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- "{{ db4_name }}"
@ -372,11 +384,12 @@
# ==========================================================================
# Dump existing databases
- name: Dump existing databases
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -386,13 +399,13 @@
target: '{{ dump1_file }}'
register: dump_result
- name: assert successful completion of dump operation
- name: Assert successful completion of dump operation (existing database)
assert:
that:
- dump_result.changed == true
- dump_result is changed
- dump_result.db_list == ['{{ db1_name }}', '{{ db2_name }}', '{{ db3_name }}']
- name: run command to list databases like specified database name
- name: Run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
register: mysql_result
@ -403,7 +416,7 @@
- "'{{ db2_name }}' in mysql_result.stdout"
- "'{{ db3_name }}' in mysql_result.stdout"
- name: state dump - file name should exist
- name: State dump - file name should exist (dump1_file)
file:
name: '{{ dump1_file }}'
state: file
@ -429,7 +442,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name: all
state: dump
@ -439,7 +452,7 @@
- name: assert successful completion of dump operation
assert:
that:
- dump_result.changed == true
- dump_result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -454,7 +467,7 @@
- "'{{ db4_name }}' not in mysql_result.stdout"
- "'{{ db5_name }}' not in mysql_result.stdout"
- name: state dump - file name should exist
- name: state dump - file name should exist (dump2_file)
file:
name: '{{ dump2_file }}'
state: file
@ -467,7 +480,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db2_name }}'
@ -479,7 +492,7 @@
- name: assert successful completion of delete databases which already exists using check mode
assert:
that:
- check_mode_result.changed == true
- check_mode_result is changed
- name: run command to test state=absent for a database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -497,7 +510,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db2_name }}'
@ -508,7 +521,7 @@
- name: assert successful completion of deleting database
assert:
that:
- result.changed == true
- result is changed
- result.db_list == ['{{ db2_name }}', '{{ db3_name }}']
- name: run command to list databases like specified database name
@ -527,7 +540,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db2_name }}'
@ -539,7 +552,7 @@
- name: assert that deletion of non existing databases does not make change (using check mode)
assert:
that:
- check_mode_result.changed == false
- check_mode_result is not changed
- name: run command to test state=absent for a database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -557,7 +570,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db2_name }}'
@ -568,7 +581,7 @@
- name: assert that deletion of non existing databases does not make change
assert:
that:
- result.changed == false
- result is not changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""
@ -586,7 +599,7 @@
mysql_db:
login_user: '{{ mysql_user }}'
login_password: '{{ mysql_password }}'
login_host: 127.0.0.1
login_host: '{{ mysql_host }}'
login_port: '{{ mysql_primary_port }}'
name:
- '{{ db1_name }}'
@ -600,7 +613,7 @@
- name: assert successful completion of deleting database
assert:
that:
- result.changed == true
- result is changed
- name: run command to list databases like specified database name
command: "{{ mysql_command }} \"-e show databases like 'database%'\""

Some files were not shown because too many files have changed in this diff Show more