Skip to content

Commit

Permalink
requested changes pt. 2
Browse files Browse the repository at this point in the history
  • Loading branch information
n-cc authored and n-cc committed Jan 17, 2024
1 parent c35bfb9 commit 55e896e
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 52 deletions.
25 changes: 13 additions & 12 deletions plugins/module_utils/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def user_add(cursor, user, host, host_all, password, encrypted,
if tls_requires is not None:
privileges_grant(cursor, user, host, "*.*", get_grants(cursor, user, host), tls_requires)

final_attributes = {}
final_attributes = None

if attributes:
cursor.execute("ALTER USER %s@%s ATTRIBUTE %s", (user, host, json.dumps(attributes)))
Expand Down Expand Up @@ -434,6 +434,10 @@ 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")

Check warning on line 434 in plugins/module_utils/user.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/user.py#L434

Added line #L434 was not covered by tests
else:
current_attributes = attributes_get(cursor, user, host)

if current_attributes is None:
current_attributes = {}

Check warning on line 439 in plugins/module_utils/user.py

View check run for this annotation

Codecov / codecov/patch

plugins/module_utils/user.py#L439

Added line #L439 was not covered by tests

attributes_to_change = {}

for key, value in attributes.items():
Expand All @@ -451,6 +455,9 @@ def user_mod(cursor, user, host, host_all, password, encrypted,
# Final if statements excludes items whose values are None in attributes_to_change, i.e. attributes that will be deleted
final_attributes = {k: v for d in (current_attributes, attributes_to_change) for k, v in d.items() if k not in attributes_to_change or
attributes_to_change[k] is not None}

# Convert empty dict to None per return value requirements
final_attributes = final_attributes if final_attributes else None
changed = True
else:
final_attributes = current_attributes
Expand Down Expand Up @@ -974,7 +981,6 @@ def get_attribute_support(cursor):
Returns:
True if attributes are supported, False if they are not.
"""

try:
# information_schema.tables does not hold the tables within information_schema itself
cursor.execute("SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES LIMIT 0")
Expand All @@ -994,21 +1000,16 @@ def attributes_get(cursor, user, host):
host (str): User host name.
Returns:
None if the user does not exist, otherwise a dict of attributes set on the user
None if the user does not exist or the user has no attributes set, otherwise a dict of attributes set on the user
"""
cursor.execute("SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = %s AND host = %s", (user, host))

r = cursor.fetchone()
# convert JSON string stored in row into a dict - mysql enforces that user_attributes entires are in JSON format
j = json.loads(r[0]) if r and r[0] else None

if r:
attributes = r[0]
# convert JSON string stored in row into a dict - mysql enforces that user_attributes entires are in JSON format
if attributes:
return json.loads(attributes)
else:
return {}

return None
# if the attributes dict is empty, return None instead
return j if j else None


def get_impl(cursor):
Expand Down
2 changes: 1 addition & 1 deletion plugins/modules/mysql_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ def main():

priv = privileges_unpack(priv, mode, column_case_sensitive, ensure_usage=not subtract_privs)
password_changed = False
final_attributes = {}
final_attributes = None
if state == "present":
if user_exists(cursor, user, host, host_all):
try:
Expand Down
169 changes: 130 additions & 39 deletions tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,60 @@
- when: db_engine == 'mysql'
block:

# ============================================================
# Create user with no attributes (test attributes return type)
#

# Check mode
- name: Attributes | Test creating a user with no attributes in check mode
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
password: '{{ user_password_2 }}'
register: result_module
check_mode: yes

- name: Attributes | Run query to verify user creation with no attributes did not take place in check mode
mysql_query:
<<: *mysql_params
query: 'SELECT user FROM mysql.user WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that user would have been created without attributes
assert:
that:
- result_module is changed
- result_module.attributes is none
- not result_query.query_result[0]

# Real mode
- name: Attributes | Test creating a user with no attributes
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
password: '{{ user_password_2 }}'
register: result_module

- name: Attributes | Run query to verify created user without attributes
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that user was created without attributes
assert:
that:
- result_module is changed
- result_module.attributes is none
- result_query.query_result[0][0]['ATTRIBUTE'] is none

# Clean up user to allow it to be recreated with attributes
- include_tasks: utils/remove_user.yml
vars:
user_name: "{{ user_name_2 }}"

# ============================================================
# Create user with attributes
#
Expand Down Expand Up @@ -227,153 +281,190 @@
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "new_value2"

# ============================================================
# Test deleting attributes
# Test attribute idempotency when specifying attributes
#

# Check mode
- name: Attributes | Test deleting attributes on an existing user in check mode
- name: Attributes | Test attribute idempotency by trying to change an already correct attribute in check mode
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key2: null
key1: "value1"
register: result_module
check_mode: yes

- name: Attributes | Run query to verify deleted attribute in check mode
- name: Attributes | Run query to verify idempotency of already correct attribute in check mode
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that attribute would have been deleted
- name: Attributes | Assert that attribute would not have been updated
assert:
that:
- result_module is changed
- "'key2' not in result_module.attributes"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "new_value2"
- result_module is not changed
- result_module.attributes.key1 == "value1"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"

# Real mode
- name: Attributes | Test deleting attributes on an existing user
- name: Attributes | Test attribute idempotency by trying to change an already correct attribute
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key2: null
key1: "value1"
register: result_module

- name: Attributes | Run query to verify deleted attribute
- name: Attributes | Run query to verify idempotency of already correct attribute
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that attribute was deleted
- name: Attributes | Assert that attribute was not updated
assert:
that:
- result_module is changed
- "'key2' not in result_module.attributes"
- "'key2' not in result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml"
- result_module is not changed
- result_module.attributes.key1 == "value1"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"

# ============================================================
# Test attribute idempotency when specifying attributes
# Test attribute idempotency when not specifying attribute parameter
#

# Check mode
- name: Attributes | Test attribute idempotency by trying to change an already correct attribute in check mode
- name: Attributes | Test attribute idempotency by not specifying attribute parameter in check mode
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key1: "value1"
register: result_module
check_mode: yes

- name: Attributes | Run query to verify idempotency of already correct attribute in check mode
- name: Attributes | Run query to verify idempotency when not specifying attribute parameter in check mode
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that attribute would not have been updated
- name: Attributes | Assert that attribute is returned in check mode
assert:
that:
- result_module is not changed
- result_module.attributes.key1 == "value1"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"

# Real mode
- name: Attributes | Test attribute idempotency by trying to change an already correct attribute
- name: Attributes | Test attribute idempotency by not specifying attribute parameter
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key1: "value1"
register: result_module

- name: Attributes | Run query to verify idempotency of already correct attribute
- name: Attributes | Run query to verify idempotency when not specifying attribute parameter
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that attribute was not updated
- name: Attributes | Assert that attribute is returned
assert:
that:
- result_module is not changed
- result_module.attributes.key1 == "value1"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"

# ============================================================
# Test attribute idempotency when not specifying attribute parameter
# Test deleting attributes
#

# Check mode
- name: Attributes | Test attribute idempotency by not specifying attribute parameter in check mode
- name: Attributes | Test deleting attributes on an existing user in check mode
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key2: null
register: result_module
check_mode: yes

- name: Attributes | Run query to verify idempotency when not specifying attribute parameter in check mode
- name: Attributes | Run query to verify deleted attribute in check mode
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that attribute is returned in check mode
- name: Attributes | Assert that attribute would have been deleted
assert:
that:
- result_module is not changed
- result_module.attributes.key1 == "value1"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
- result_module is changed
- "'key2' not in result_module.attributes"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key2'] == "new_value2"

# Real mode
- name: Attributes | Test attribute idempotency by not specifying attribute parameter
- name: Attributes | Test deleting attributes on an existing user
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key2: null
register: result_module

- name: Attributes | Run query to verify idempotency when not specifying attribute parameter
- name: Attributes | Run query to verify deleted attribute
mysql_query:
<<: *mysql_params
query: 'SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = "{{ user_name_2 }}" AND host = "%"'
register: result_query

- name: Attributes | Assert that attribute is returned
- name: Attributes | Assert that attribute was deleted
assert:
that:
- result_module is not changed
- result_module.attributes.key1 == "value1"
- (result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml)['key1'] == "value1"
- result_module is changed
- "'key2' not in result_module.attributes"
- "'key2' not in result_query.query_result[0][0]['ATTRIBUTE'] | from_yaml"

# ============================================================
# Test attribute return value when no attributes exist
#

# Check mode
- name: Attributes | Test attributes return value when no attributes exist in check mode
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key1: null
register: result_module
check_mode: yes

- name: Attributes | Assert attributes return value when no attributes exist in check mode
assert:
that:
- result_module is changed
- result_module.attributes is none

# Real mode
- name: Attributes | Test attributes return value when no attributes exist
mysql_user:
<<: *mysql_params
name: '{{ user_name_2 }}'
host: '%'
attributes:
key1: null
register: result_module

- name: Attributes | Assert attributes return value when no attributes exist
assert:
that:
- result_module is changed
- result_module.attributes is none

# ============================================================
# Cleanup
Expand Down

0 comments on commit 55e896e

Please sign in to comment.