Skip to content
Open
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
47 changes: 46 additions & 1 deletion plugins/module_utils/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class InvalidPrivsError(Exception):
pass


diff_current = {}
diff_new = {}


def get_mode(cursor):
cursor.execute('SELECT @@sql_mode')
result = cursor.fetchone()
Expand All @@ -49,6 +53,10 @@ def user_exists(cursor, user, host, host_all):
cursor.execute("SELECT count(*) FROM mysql.user WHERE user = %s AND host = %s", (user, host))

count = cursor.fetchone()
if count[0] > 0:
diff_current['state'] = "present"
else:
diff_current['state'] = "absent"
return count[0] > 0


Expand All @@ -62,12 +70,15 @@ def user_is_locked(cursor, user, host):
# Need to handle both DictCursor and non-DictCursor
if isinstance(result, tuple):
if result[0].find('ACCOUNT LOCK') > 0:
diff_current['locked'] = True
return True
elif isinstance(result, dict):
for res in result.values():
if res.find('ACCOUNT LOCK') > 0:
diff_current['locked'] = True
return True

diff_current['locked'] = False
return False


Expand Down Expand Up @@ -111,6 +122,7 @@ def get_grants(cursor, 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()
diff_current['grants'] = grants.split(", ")
return grants.split(", ")


Expand Down Expand Up @@ -172,6 +184,7 @@ def get_existing_authentication(cursor, user, host=None):
'plugin': r[0],
'plugin_auth_string': r[1],
'plugin_hash_string': r[1]})
diff_current['auth_list'] = existing_auth_list

return existing_auth_list

Expand Down Expand Up @@ -301,6 +314,8 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
hostnames = [host]

password_changed = False
diff_current['password'] = "<filtered password>"
diff_new['password'] = "<filtered password>"
for host in hostnames:
# Handle clear text and hashed passwords.
if not role:
Expand Down Expand Up @@ -345,6 +360,7 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
encrypted_password = cursor.fetchone()[0]

if current_pass_hash != encrypted_password:
diff_new['password'] = "<filtered new password>"
password_changed = True
msg = "Password updated"
if not module.check_mode:
Expand Down Expand Up @@ -378,6 +394,14 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
mariadb_role = True if "mariadb" in str(impl.__name__) else False
current_password_policy = get_password_expiration_policy(cursor, user, host, maria_role=mariadb_role)
password_expired = is_password_expired(cursor, user, host)
diff_current['password_policy'] = current_password_policy
if password_expired == "default":
diff_new['password_policy'] = -1
elif password_expired == "never":
diff_new['password_policy'] = 0
elif password_expired == "interval":
diff_new['password_policy'] = 1

# Check if changes needed to be applied.
if not ((current_password_policy == -1 and password_expire == "default") or
(current_password_policy == 0 and password_expire == "never") or
Expand All @@ -396,6 +420,8 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
cursor.execute("SELECT plugin, authentication_string FROM mysql.user "
"WHERE user = %s AND host = %s", (user, host))
current_plugin = cursor.fetchone()
diff_current['plugin'] = current_plugin
diff_new['plugin'] = plugin

update = False

Expand Down Expand Up @@ -469,6 +495,8 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
if not module.check_mode:
privileges_grant(cursor, user, host, db_table, priv, tls_requires, maria_role)
changed = True
diff_current['privileges'] = curr_priv
diff_new['privileges'] = new_priv

# 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.
Expand Down Expand Up @@ -527,6 +555,8 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
module.fail_json(msg="user attributes were specified but the server does not support user attributes")
else:
current_attributes = attributes_get(cursor, user, host)
diff_current['attributes'] = current_attributes
diff_new['attributes'] = attributes

if current_attributes is None:
current_attributes = {}
Expand Down Expand Up @@ -558,6 +588,11 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
if attribute_support:
final_attributes = attributes_get(cursor, user, host)

diff_current['locked'] = user_is_locked(cursor, user, host)
diff_new['locked'] = locked
if diff_new['locked'] is None:
diff_new['locked'] = False

if not role and locked is not None and user_is_locked(cursor, user, host) != locked:
if not module.check_mode:
if locked:
Expand All @@ -579,6 +614,10 @@ def user_mod(cursor, user, host, host_all, password, encrypted,

# Handle TLS requirements
current_requires = sanitize_requires(impl.get_tls_requires(cursor, user, host))

diff_current['requires_tls'] = current_requires
diff_new['requires_tls'] = tls_requires

if current_requires != tls_requires:
msg = "TLS requires updated"
if not module.check_mode:
Expand All @@ -597,10 +636,12 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
cursor.execute(*query_with_args)
changed = True

return {'changed': changed, 'msg': msg, 'password_changed': password_changed, 'attributes': final_attributes}
return {'changed': changed, 'msg': msg, 'password_changed': password_changed, 'attributes': final_attributes,
'diff_current': diff_current, 'diff_new': diff_new}


def user_delete(cursor, user, host, host_all, check_mode):
diff_new['state'] = "absent"
if check_mode:
return True

Expand All @@ -626,6 +667,8 @@ def user_get_hostnames(cursor, user):
for hostname_raw in hostnames_raw:
hostnames.append(hostname_raw[0])

diff_current['hostnames'] = hostnames

return hostnames


Expand Down Expand Up @@ -1022,6 +1065,8 @@ def match_resource_limits(module, current, desired):
Returns: Dictionary containing parameters that need to change.
"""

diff_current['resource_limits'] = current
diff_new['resource_limits'] = desired
if not current:
# It means the user does not exists, so we need
# to set all limits after its creation
Expand Down
11 changes: 10 additions & 1 deletion plugins/modules/mysql_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,10 @@


def main():
diff_current = {}
diff_current['state'] = "present"
diff_new = {}
diff_new['state'] = "present"
argument_spec = mysql_common_argument_spec()
argument_spec.update(
name=dict(type='str', required=True, aliases=['user'], deprecated_aliases=[
Expand Down Expand Up @@ -609,6 +613,8 @@ def main():
msg = result['msg']
password_changed = result['password_changed']
final_attributes = result['attributes']
diff_current = result['diff_current'] | diff_current
diff_new = result['diff_new'] | diff_new

except (SQLParseError, InvalidPrivsError, mysql_driver.Error) as e:
module.fail_json(msg=to_native(e))
Expand All @@ -628,6 +634,7 @@ def main():
final_attributes = result['attributes']
if changed:
msg = "User added"
diff_new['state'] = "present"

except (SQLParseError, InvalidPrivsError, mysql_driver.Error) as e:
module.fail_json(msg=to_native(e))
Expand All @@ -639,10 +646,12 @@ def main():
if user_exists(cursor, user, host, host_all):
changed = user_delete(cursor, user, host, host_all, module.check_mode)
msg = "User deleted"
diff_new['state'] = "absent"
else:
changed = False
msg = "User doesn't exist"
module.exit_json(changed=changed, user=user, msg=msg, password_changed=password_changed, attributes=final_attributes)
module.exit_json(changed=changed, diff={'before': diff_current, 'after': diff_new}, user=user, msg=msg,
password_changed=password_changed, attributes=final_attributes)


if __name__ == '__main__':
Expand Down
Loading