Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cut option maria_role as it has nothing to do with roles #579

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions plugins/module_utils/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ def mysql_common_argument_spec():
)


def get_server_type(cursor):
""" Return MySQL or MariaDB after quering the server
using SELECT VERSION()"""
srv_ver = get_server_version(cursor)
return 'mariadb' if 'mariadb' in srv_ver.lower() else "mysql"


def get_server_version(cursor):
"""Returns a string representation of the server version."""
cursor.execute("SELECT VERSION() AS version")
Expand Down
71 changes: 29 additions & 42 deletions plugins/module_utils/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from ansible_collections.community.mysql.plugins.module_utils.mysql import (
mysql_driver,
get_server_type,
)


Expand Down Expand Up @@ -201,7 +202,7 @@ def is_hash(password):

def user_mod(cursor, user, host, host_all, password, encrypted,
plugin, plugin_hash_string, plugin_auth_string, new_priv,
append_privs, subtract_privs, tls_requires, module, role=False, maria_role=False):
append_privs, subtract_privs, tls_requires, module, role=False):
changed = False
msg = "User unchanged"
grant_option = False
Expand Down Expand Up @@ -323,7 +324,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted,

# Handle privileges
if new_priv is not None:
curr_priv = privileges_get(cursor, user, host, maria_role)
curr_priv = privileges_get(cursor, user, host)

# 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.
Expand All @@ -337,7 +338,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
msg = "Privileges updated"
if module.check_mode:
return {'changed': True, 'msg': msg, 'password_changed': password_changed}
privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role)
privileges_revoke(cursor, user, host, db_table, priv, grant_option)
changed = True

# If the user doesn't currently have any privileges on a db.table, then
Expand All @@ -348,7 +349,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
msg = "New privileges granted"
if module.check_mode:
return {'changed': True, 'msg': msg, 'password_changed': password_changed}
privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
privileges_grant(cursor, user, host, db_table, priv, tls_requires)
changed = True

# If the db.table specification exists in both the user's current privileges
Expand Down Expand Up @@ -390,12 +391,12 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
if module.check_mode:
return {'changed': True, 'msg': msg, 'password_changed': password_changed}
if len(revoke_privs) > 0:
privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option, maria_role)
privileges_revoke(cursor, user, host, db_table, revoke_privs, grant_option)
if len(grant_privs) > 0:
privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires, maria_role)
privileges_grant(cursor, user, host, db_table, grant_privs, tls_requires)

# after privilege manipulation, compare privileges from before and now
after_priv = privileges_get(cursor, user, host, maria_role)
after_priv = privileges_get(cursor, user, host)
changed = changed or (curr_priv != after_priv)

if role:
Expand Down Expand Up @@ -454,7 +455,7 @@ def user_get_hostnames(cursor, user):
return hostnames


def privileges_get(cursor, user, host, maria_role=False):
def privileges_get(cursor, user, host):
""" 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:
Expand All @@ -465,10 +466,8 @@ def privileges_get(cursor, user, host, maria_role=False):
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,))
query = "SHOW GRANTS FOR '%s'@'%s'" % (user, host)
cursor.execute(query)
grants = cursor.fetchall()

def pick(x):
Expand All @@ -478,10 +477,10 @@ def pick(x):
return x

for grant in grants:
if not maria_role:
if get_server_type(cursor) == 'mariadb':
res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3@(['`"]).*\\4( IDENTIFIED BY PASSWORD (['`"]).+\\6)? ?(.*)""", grant[0])
else:
res = re.match("""GRANT (.+) ON (.+) TO (['`"]).*\\3""", grant[0])
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
Expand All @@ -490,7 +489,7 @@ def pick(x):
# 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:
if res:
continue

raise InvalidPrivsError('unable to parse the MySQL grant string: %s' % grant[0])
Expand All @@ -505,10 +504,14 @@ def pick(x):
# Determine if there's a case similar to the above:
privileges = normalize_col_grants(privileges)

if not maria_role:
if get_server_type(cursor) == 'mariadb':
if "WITH GRANT OPTION" in res.group(7):
privileges.append('GRANT')
else:
if "WITH GRANT OPTION" in res.group(4):
privileges.append('GRANT')
db = res.group(2)

output.setdefault(db, []).extend(privileges)
return output

Expand Down Expand Up @@ -684,48 +687,33 @@ def privileges_unpack(priv, mode, column_case_sensitive, ensure_usage=True):
return output


def privileges_revoke(cursor, user, host, db_table, priv, grant_option, maria_role=False):
def privileges_revoke(cursor, user, host, db_table, priv, grant_option):
# 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.append("FROM %s@%s")
query = ' '.join(query)
cursor.execute(query, (user, host))
priv_string = ",".join([p for p in priv if p not in ('GRANT', )])

if priv_string != "":
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.append("FROM %s@%s")
query = ' '.join(query)
cursor.execute(query, params)
cursor.execute(query, (user, host))
cursor.execute("FLUSH PRIVILEGES")


def privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role=False):
def privileges_grant(cursor, user, host, db_table, priv, tls_requires):
# 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)]

if not maria_role:
query.append("TO %s@%s")
params = (user, host)
else:
query.append("TO %s")
params = (user)
query.append("TO %s@%s")
params = (user, host)

if tls_requires and impl.use_old_user_mgmt(cursor):
query, params = mogrify_requires(" ".join(query), params, tls_requires)
Expand Down Expand Up @@ -851,8 +839,7 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode):
module.fail_json(msg="The server version does not match the requirements "
"for resource_limits parameter. See module's documentation.")

cursor.execute("SELECT VERSION()")
if 'mariadb' not in cursor.fetchone()[0].lower():
if get_server_type(cursor) != 'mariadb':
if 'MAX_STATEMENT_TIME' in resource_limits:
module.fail_json(msg="MAX_STATEMENT_TIME resource limit is only supported by MariaDB.")

Expand All @@ -879,8 +866,8 @@ def limit_resources(module, cursor, user, host, resource_limits, check_mode):

def get_impl(cursor):
global impl
cursor.execute("SELECT VERSION()")
if 'mariadb' in cursor.fetchone()[0].lower():

if get_server_type(cursor) == 'mariadb':
from ansible_collections.community.mysql.plugins.module_utils.implementations.mariadb import user as mariauser
impl = mariauser
else:
Expand Down
5 changes: 2 additions & 3 deletions plugins/modules/mysql_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,7 @@ def add(self, users, privs, check_mode=False, admin=False,
if privs:
for db_table, priv in iteritems(privs):
privileges_grant(self.cursor, self.name, self.host,
db_table, priv, tls_requires=None,
maria_role=self.is_mariadb)
db_table, priv, tls_requires=None)

return True

Expand Down Expand Up @@ -932,7 +931,7 @@ def update(self, users, privs, check_mode=False,
result = user_mod(self.cursor, self.name, self.host,
None, None, None, None, None, None,
privs, append_privs, subtract_privs, None,
self.module, role=True, maria_role=self.is_mariadb)
self.module, role=True)
changed = result['changed']

if admin:
Expand Down
Loading