-
Notifications
You must be signed in to change notification settings - Fork 89
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
feat[mysql_user]: add support for mysql user attributes #604
feat[mysql_user]: add support for mysql user attributes #604
Conversation
- MySQL server must support the INFORMATION_SCHEMA.USER_ATTRIBUTES table. Provided since MySQL 8.0. | ||
- To delete an existing attribute, set its value to False. | ||
type: dict | ||
version_added: '3.9.0' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not bump the version in galaxy.yml
yet; unsure what the process is for shipping new versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3.9.0
is OK here
@@ -405,6 +418,7 @@ def main(): | |||
tls_requires=dict(type='dict'), | |||
append_privs=dict(type='bool', default=False), | |||
subtract_privs=dict(type='bool', default=False), | |||
attributes=dict(type='dict'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can change the parameter ordering here if desired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fine now
4e146a2
to
8685d4a
Compare
I'll work on resolving the lint and integration tests over the next day or so. |
8685d4a
to
e7f707f
Compare
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #604 +/- ##
==========================================
- Coverage 76.66% 75.13% -1.53%
==========================================
Files 28 18 -10
Lines 2447 2361 -86
Branches 603 595 -8
==========================================
- Hits 1876 1774 -102
- Misses 388 405 +17
+ Partials 183 182 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
e7f707f
to
7012a27
Compare
Existing integration tests are passing, going to work on writing new ones for this feature. |
3467950
to
0e56260
Compare
0e56260
to
9a8b53d
Compare
Integration tests written, everything should be good for a review at this point. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@n-cc hello, thanks for the PR!
could you please add a changelog fragment?
Also will you be responsive in case of related bug reports? If not really, should we implement it somehow separately from all those functions you're changing here? But i hope you're going to be around and even join our Matrix channel and Forum group:) See the communication guide.
tests/integration/targets/test_mysql_user/tasks/test_user_attributes.yml
Outdated
Show resolved
Hide resolved
plugins/module_utils/user.py
Outdated
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 | |
# convert JSON string stored in row into a dict - mysql enforces that user_attributes entires are in JSON format | |
return json.loads(r[0]) if r and r[0] else None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this will return None
rather than an empty dict if the user exists but does not have any attributes set - are you recommending returning None
over {}
in that scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should be fine, but there are a few things to keep in mind about None
vs {}
when it comes to attributes... if a CREATE USER
is ran without the ATTRIBUTES '{}'
option, the user's attributes are stored as NULL
until attributes are set, and if all attributes are deleted, attributes will then be stored as {}
and cannot be changed back to NULL
(as far as I can tell):
mysql> CREATE USER 'testuser'@'localhost';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT ATTRIBUTE from INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = 'testuser' and host = 'localhost';
+-----------+
| ATTRIBUTE |
+-----------+
| NULL |
+-----------+
1 row in set (0.00 sec)
mysql> ALTER USER 'testuser'@'localhost' ATTRIBUTE '{ "foo": "bar" }';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT ATTRIBUTE from INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = 'testuser' and host = 'localhost';
+----------------+
| ATTRIBUTE |
+----------------+
| {"foo": "bar"} |
+----------------+
1 row in set (0.00 sec)
mysql> ALTER USER 'testuser'@'localhost' ATTRIBUTE '{ "foo": null }';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT ATTRIBUTE from INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = 'testuser' and host = 'localhost';
+-----------+
| ATTRIBUTE |
+-----------+
| {} |
+-----------+
1 row in set (0.00 sec)
mysql>
I think there are a couple different options:
- Represent no attributes as
{}
even if theATTRIBUTE
database value isNULL
- This is what I was doing originally; I chose this method so that someone using
register: foo
withmysql_user
could still treatfoo.attributes
as a dictionary even if theATTRIBUTE
value isNULL
. It also makes the code a bit cleaner ifattributes_get
always returns a dict for users that exist. - With this method, we could also explicitly run the
CREATE USER
query inuser_add
withATTRIBUTES {}
even if no attributes are specified, so that theATTRIBUTE
database value will always be{}
for ansible-created users on servers with attribute support.
- This is what I was doing originally; I chose this method so that someone using
- Represent no attributes as
None
even if theATTRIBUTE
database value is{}
(I think this is what you were proposing) - Represent no attributes as either
None
or{}
depending on the database value
Option 2 is how this feature behaves as of my latest commit (I also wrote tests to assert the attributes return value for users without attributes). I think any of these options are fine depending on ansible best practices. I can stick with option 2 if you think it's preferred, I just wanted to make sure this caveat was documented in this PR.
- MySQL server must support the INFORMATION_SCHEMA.USER_ATTRIBUTES table. Provided since MySQL 8.0. | ||
- To delete an existing attribute, set its value to False. | ||
type: dict | ||
version_added: '3.9.0' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3.9.0
is OK here
@@ -405,6 +418,7 @@ def main(): | |||
tls_requires=dict(type='dict'), | |||
append_privs=dict(type='bool', default=False), | |||
subtract_privs=dict(type='bool', default=False), | |||
attributes=dict(type='dict'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's fine now
Certainly if there are any immediate problems, but you could also consider me a maintainer of this feature if future problems arise. I don't actively use irc/matrix, but I should be reachable via Github pings. That being said, if implementing attribute support separately from |
0119896
to
9eb4cc3
Compare
9eb4cc3
to
c35bfb9
Compare
Requested changes have been implemented, aside from the two I had questions on. |
that's nice to hear! Could you please take a look at the comment about using |
6c4c394
to
b84d8fb
Compare
b84d8fb
to
55e896e
Compare
Responded and updated. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@n-cc one small thing to change, the rest LGTM
Thanks much, updated |
@laurent-indermuehle is it OK for you? if yes, please merge |
as @laurent-indermuehle is busy, I'm merging this PR @n-cc thanks for the contribution! |
051aa48
into
ansible-collections:main
SUMMARY
This PR adds support for MySQL user attributes (essentially arbitrary comments associated with a user in a key: value format) to the mysql_user module. It adds the ability to add, update, and delete user attributes, and get existing attributes by checking the
attributes
attribute of themysql_user
task.ISSUE TYPE
COMPONENT NAME
community.mysql.mysql_user
ADDITIONAL INFORMATION
user_mod
would prematurely return at various points in check mode when changes were detected. IMO, this is not ideal, as the entirety of the module that will execute in non-check mode is not ran in check mode, and it means we have to support returning a specifically-constructed dict in multiple locations. As part of this PR, since I am modifying the return dict ofuser_mod
, I removed the premature returns when in check mode in favor of the final return at the end of the function. I can revert this if desired, but I think it makes the code cleaner and safer. It is worth noting that messages from the module are still masked if a later message is registered.attributes
return value, but I could add return value documentation if desired.LOCAL TESTING
SERVER SUPPORTS ATTRIBUTES
Creating a new user without attributes:
Creating a new user with attributes:
Updating an existing user's attributes:
No change when existing attributes are already in line with the attributes specified in the
attributes
parameter:No change when the
attributes
parameter is not specified:SERVER DOES NOT SUPPORT ATTRIBUTES
Creating a new user without attributes:
Reading an existing user:
Creating a new user with attributes:
Updating an existing user's attributes: