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

Add MySQLUser and MySQLAADUser v1alpha2 #1357

Merged
merged 11 commits into from
Feb 1, 2021

Conversation

babbageclunk
Copy link
Member

@babbageclunk babbageclunk commented Jan 13, 2021

The new versions of MySQLUser and MySQLAADUser have roles per-database and server-level roles rather than a user being specific to one database. This adds conversions from v1alpha1 -> v1alpha2 (these are always possible), and supports conversion back to v1alpha1 as long as the user doesn't have any server-level roles and has roles in exactly one database. It also includes the yaml situps to connect the conversion webhooks.

This implements #1346 for MySQL. The initial plan had been to split this change into two PRs with the reconciliation changes in a follow-up, but because envtest doesn't support conversion webhooks the CI tests would have prevented this, so reconciliation and controller tests are included as the last two commits.

How does this PR make you feel:
gif

If applicable:

  • this PR contains documentation (in the form of samples)
  • this PR contains tests

matthchr
matthchr previously approved these changes Jan 13, 2021
api/v1alpha1/mysqlaaduser_conversion.go Outdated Show resolved Hide resolved
api/v1alpha1/mysqluser_conversion.go Outdated Show resolved Hide resolved
api/v1alpha1/mysqlaaduser_conversion.go Outdated Show resolved Hide resolved
api/v1alpha2/mysqlaaduser_conversion.go Show resolved Hide resolved
api/v1alpha2/mysqlaaduser_types.go Outdated Show resolved Hide resolved
config/crd/patches/webhook_in_mysqlusers.yaml Show resolved Hide resolved
config/samples/azure_v1alpha2_mysqlaaduser.yaml Outdated Show resolved Hide resolved
config/samples/azure_v1alpha2_mysqlaaduser.yaml Outdated Show resolved Hide resolved
config/samples/azure_v1alpha2_mysqluser.yaml Outdated Show resolved Hide resolved
config/samples/azure_v1alpha2_mysqluser.yaml Outdated Show resolved Hide resolved
@babbageclunk babbageclunk force-pushed the mysql-user-no-db branch 2 times, most recently from f26d51e to 6339871 Compare January 14, 2021 02:26
matthchr
matthchr previously approved these changes Jan 14, 2021
@matthchr
Copy link
Member

Looks like CI failed - could be related to your changes as the tests that failed were some of the negative test cases in MySQLUser?

@babbageclunk
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@babbageclunk babbageclunk force-pushed the mysql-user-no-db branch 4 times, most recently from 8c68932 to c35d61f Compare January 21, 2021 01:19
@babbageclunk
Copy link
Member Author

It turns out that envtest doesn't yet support conversion webhooks. That means the tests for this PR wouldn't pass without the reconciliation and tests being updated to use the v1alpha2 versions of MySQLUser and MySQLAADUser, so I've included those in this PR (the last two commits).

@babbageclunk babbageclunk changed the title Add MySQLUser and MySQLAADUser v1alpha2 + conversion webhooks Add MySQLUser and MySQLAADUser v1alpha2 Jan 21, 2021
This removes DbName from MySQLUser and adds DatabaseRoles to store
per-database permissions. Roles will now only store server-wide
permissions.

Add conversions between v1alpha1 and v1alpha2 versions.
This removes DBName from MySQLAADUser and adds DatabaseRoles to store
per-database permissions. Roles will now only store server-wide
permissions.

Add conversions between v1alpha1 and v1alpha2 versions.
These were set for all types with version conversions but not the
others (which aren't in use since they are still commented out in
kustomization.yaml). Turning them on in the rest to remove one step in
the process of adding conversion webhooks to types in the future.

This setting is required for conversion to work - it seems like the
only reason it's not set in the patches is that they were generated by
kubebuilder before the setting was mandatory.
They now check server-level (in USER_PRIVILEGES) and
database-level (SCHEMA_PRIVILEGES) permissions.
Copy link
Member

@matthchr matthchr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments asking for improved comments in a few places, and then one sorta big comment about the behavior when there are failures reconciling DB permissions.

pkg/resourcemanager/mysql/mysqlaaduser/reconcile.go Outdated Show resolved Hide resolved
pkg/resourcemanager/mysql/mysqlaaduser/reconcile.go Outdated Show resolved Hide resolved
pkg/resourcemanager/mysql/mysqlhelper.go Outdated Show resolved Hide resolved
@@ -168,7 +213,53 @@ func GrantUserRoles(ctx context.Context, user string, database string, roles []s
return nil
}

func addRoles(ctx context.Context, db *sql.DB, database string, user string, roles map[string]struct{}) error {
// EnsureUserDatabaseRoles revokes and grants database roles as needed
// so they match the ones passed in. It returns warning messages if
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not totally clear how the comment:

It returns warning messages if some databases don't exist

is correct?

  1. Is ExtractUserDatabaseRoles succeeding (but with 0 roles) if the DB doesn't exist? It's not clear to me if that's an error case or an "empty return" case.
  2. Other errors when adding/removing roles will also just get reported as warnings right? As a matter of fact based on my read of this function and its caller it seems like even if we cannot assign some roles to some DBs we will still say Provisioned = true and State = "Succeeded" - that seems probably not correct?

I can sorta see the reasoning around bypassing DB not exists (as maybe next reconcile loop it will), but wonder if we need to be more explicit about checking for errors that aren't that one. Even for that error it might make sense to leave this resource in a "provisioned=false" state as it's not done with all that was asked?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a lot of sense - after our discussion I'll accumulate the errors for different databases into one error from the Ensure function (even though we still apply the roles for the later databases on an error) and have the user still be provisioned=false in the reconciler.

config/samples/azure_v1alpha2_mysqlaaduser.yaml Outdated Show resolved Hide resolved
config/samples/azure_v1alpha2_mysqluser.yaml Outdated Show resolved Hide resolved
config/samples/azure_v1alpha2_mysqluser.yaml Show resolved Hide resolved
mysql.MySQLServerPort,
adminUser,
adminPassword)
assert.NoError(err)

expectedRoles := mysql.SliceToSet(updatedRoles)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be lacking some tests around the the "DBName doesn't exist" case - it was explicitly mentioned in one of the comments but not sure that this test covers it?

pkg/resourcemanager/mysql/mysqluser/mysqluser_reconcile.go Outdated Show resolved Hide resolved
}

err = mysql.GrantUserRoles(ctx, user, instance.Spec.DbName, instance.Spec.Roles, db)
warnings, err := mysql.EnsureUserDatabaseRoles(ctx, db, user, instance.Spec.DatabaseRoles)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here about if we really know that what is ending up in warnings here is something we're ok classifying as a warning.

Also rename the ServerPort and DriverName constants so they don't
repeat the name of the package.
And change the reconciliation code for user and aad user to just treat
that as a provisioning failure, rather than saying that it had
succeeded but there were some errors which is just confusing. We still
try to apply changes to all databases even if there is an error for
one of them.

Also other review changes, thanks @matthchr!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants