Repository: ansible/ansible

Issue:
mysql_user module fails when checking current privileges
<!---
Verify first that your issue/request is not already reported on GitHub.
THIS FORM WILL BE READ BY A MACHINE, COMPLETE ALL SECTIONS AS DESCRIBED.
Also test if the latest release, and devel branch are affected too.
ALWAYS add information AFTER (OUTSIDE) these html comments.
Otherwise it may end up being automatically closed by our bot. -->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
mysql_user

##### ANSIBLE VERSION
```
ansible 2.5.1
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]

```

##### CONFIGURATION
ANSIBLE_PIPELINING(/etc/ansible/ansible.cfg) = True

##### OS / ENVIRONMENT
Ubuntu Server 16.04 LTS

##### SUMMARY
The mysql_user module fails when checking a user's current privileges in a MySQL 8.0.11 database. The creation of the user succeeds because there are no privileges, but subsequent runs of the playbook end with an error.

I traced the error to a failure when parsing the output of a "SHOW GRANTS" command, Ansible expects the server to quote strings with single quotes ('), MySQL 8.0.11 instead uses backticks (`).

##### STEPS TO REPRODUCE
Write a playbook that creates an user with privileges to a table or database on a MySQL 8.0.11 server, then run it more than once.

<!--- Paste example playbooks or commands between quotes below -->
```yaml
    - name: create a new user
      mysql_user:
        name: "{{ item.username }}"
        password: "{{ item.password }}"
        priv: "{{ item.dbname }}.*:ALL"
```

##### EXPECTED RESULTS
Ansible should see that the privileges aren't changing and pass to the next task.

##### ACTUAL RESULTS
Ansible fails with a parsing error.

```
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: InvalidPrivsError: unable to parse the MySQL grant string: GRANT USAGE ON *.* TO `user`@`localhost`
failed: [testserver] (item={u'password': u'test', u'username': u'user', u'dbname': u'dbtest'}) => {"changed": false, "item": {"password": "test", "username": "user", "dbname": "dbtest"}, "msg": "unable to parse the MySQL grant string: GRANT USAGE ON *.* TO `user`@`localhost`"}

```



Discussion:

Resolving patch:
diff --git a/lib/ansible/modules/database/mysql/mysql_user.py b/lib/ansible/modules/database/mysql/mysql_user.py
--- a/lib/ansible/modules/database/mysql/mysql_user.py
+++ b/lib/ansible/modules/database/mysql/mysql_user.py
@@ -434,14 +434,14 @@ def pick(x):
             return x
 
     for grant in grants:
-        res = re.match("GRANT (.+) ON (.+) TO '.*'@'.*'( IDENTIFIED BY PASSWORD '.+')? ?(.*)", grant[0])
+        res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\5)? ?(.*)""", grant[0])
         if res is None:
             raise InvalidPrivsError('unable to parse the MySQL grant string: %s' % grant[0])
         privileges = res.group(1).split(", ")
         privileges = [pick(x) for x in privileges]
-        if "WITH GRANT OPTION" in res.group(4):
+        if "WITH GRANT OPTION" in res.group(7):
             privileges.append('GRANT')
-        if "REQUIRE SSL" in res.group(4):
+        if "REQUIRE SSL" in res.group(7):
             privileges.append('REQUIRESSL')
         db = res.group(2)
         output[db] = privileges


Test patch: