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

Fix grant import #118

Closed
wants to merge 3 commits into from
Closed

Fix grant import #118

wants to merge 3 commits into from

Conversation

gallois
Copy link

@gallois gallois commented Mar 4, 2024

This fixes the issue described in
#112 where it's
not possible to import some grants. In short, it:

  • Adds type for parsing the grant resource from data,
    desiredProcedureGrant, separating it from desiredGrant, which now
    becomes desiredTableGrant. This is used when trying to find a
    conflict and can probably be made a bit more generic, but it's likely
    outside the scope of this change (see below)
  • Refactors the old formatDatabaseName into produceGrantId which, as
    the name says, produced the grant id that is going to be used by the
    provider.
  • Sets some additional required fields for importing the grants, the
    most important one being the id which was missing and causing the
    errors that were seen in the issue above.

It also fixes a typo in the docs that I introduced earlier.

There are a few things worth noting:

  • Role grants are not covered. Unfortunately, I don't currently have a use case for
    that, so there's no good way of testing it properly.
  • As mentioned before, there are parts of the code that could be
    refactored to be more generic. That being said, it would also require
    implementing the fixes for role grants to write it in such a
    way that it would be properly generic.

gallois added 2 commits March 4, 2024 09:02
This fixes the issue described in
petoju#112 where it's
not possible to import some grants. In short, it:
- Adds an additional type for parsing the grant resource from data,
  `desiredProcedureGrant`, separating it from `desiredGrant`, which now
  becomes `desiredTableGrant`. This is used when trying to find a
  conflict and can probably be made a bit more generic, but it's likely
  outside the scope of this change (see below)
- Refactors the old `formatDatabaseName` into `produceGrantId` which, as
  the name says, produced the grant id that is going to be used by the
  provider.
- Sets some additional required fields for importing the grants, the
  most important one being the `id` which was missing and causing the
  errors that were seen in the issue above.

It also fixes a typo in the docs that I introduced earlier.

There are a few things worth noting:
- Role grants are not covered. I don't currently have a use case for
  that, hence no good way of testing it properly.
- As mentioned before, there are parts of the code that could be
  refactored to be more generic. That being said, it would require
  implementing the fixes for role grants as well to write it in such a
  way that it would be properly generic.
mysql/resource_grant.go Show resolved Hide resolved
mysql/resource_grant.go Outdated Show resolved Hide resolved
@@ -3,14 +3,15 @@ package mysql
import (
Copy link
Owner

Choose a reason for hiding this comment

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

Could you please create a test to catch this case / issue?

Copy link
Author

Choose a reason for hiding this comment

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

I've fixed the existing ones. Anything else you think should be added?

Copy link
Owner

Choose a reason for hiding this comment

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

Generally when you want to fix a regression, there should be a new test catching the very issue you are trying to fix.

So that means you should test importing (I know we don't test it anywhere, but still). And ideally, you should leave all previous tests in place. Or fix them, if there is any error there - but there should be some rationale when removing tests.

Copy link
Author

Choose a reason for hiding this comment

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

I don't think it was a regression in the sense that a feature existed and it stopped working. It was, as I understand, a new issue that was implemented that never really worked. I think the current test is reasonable, ti was just built in a way that worked with the implementation, but that was not working in the first place. I think the current test covers the implementation and I'm not sure what sort of regression, specifically, we'd need to cover.

Copy link
Owner

Choose a reason for hiding this comment

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

In the bug #112 , you described

terraform import mysql_grant.foo_grant_local 'foo_user@localhost@test_db@*'

stopped working. Cannot you test import exactly like that here?

I'd do it based on
https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/import#resource-acceptance-testing-implementation

I'm not completely sure how it works - so if that's too difficult and once I find some time, I can also try looking at that.

mysql/resource_grant.go Show resolved Hide resolved
@@ -888,21 +889,6 @@ func TestAccGrantOnProcedure(t *testing.T) {
prepareProcedure(dbName, procedureName),
),
},
{
Copy link
Owner

Choose a reason for hiding this comment

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

What's wrong with this test? I believe it should stay and possibly be fixed if there's something wrong.

I tried running with it and it shows some issues you'd see, if you ran it manually with config.

Copy link
Author

Choose a reason for hiding this comment

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

My understanding—but keep in mind I'm not an expert on the matter—is that semantically it makes no sense to provide procedure grants with tables, so the test was not meaningful. I couldn't find any references online to such a scenario either, so please do correct me if I'm missing something. Again, I'm not an expert on this so there's a good chance I'm wrong :)

Choose a reason for hiding this comment

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

This test needs to remain. Although it does make no sense semantically, this is something that was supported by the deprecated Hashicorp mysql provider, and has made its way into other modules:

#99 (comment)

I think the fix for this (as described in that issue), is that we need to introduce a v2 of the mysql_grant resource, ideally specific to each type (eg. mysql_table_grant, mysql_procedure_grant, etc).

Copy link
Author

Choose a reason for hiding this comment

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

Got it. I couldn't find a way to identify how the object is defined in terraform in the code so that I can build the resource accordingly. Are there any downsides to normalising it? I mean, if the object is parsed correctly and the representation is not crucial, can we just pick one and go with it?

From what I tested, regardless of how the terraform object is defined, we can use either of the formats and it works the same way

Copy link
Owner

Choose a reason for hiding this comment

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

I mean, if the object is parsed correctly and the representation is not crucial, can we just pick one and go with it?

We cannot do it easily like this.
We could do it, if we:

  • Preserve the backwards compatibility with whatever was there.
  • Write custom DiffSuppressFunc so that this change won't cause a persistent diff.

That's one way to solve the issue. That said, this test needs to remain as it reveals and issue that you introduced and it would pass if there was no diff to the user.

As Derek has pointed out, the best way to solve it would be to introduce mysql_table_grant / mysql_procedure_grant - but that also removes backwards compatibility.

@@ -3,14 +3,15 @@ package mysql
import (
Copy link
Owner

Choose a reason for hiding this comment

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

Generally when you want to fix a regression, there should be a new test catching the very issue you are trying to fix.

So that means you should test importing (I know we don't test it anywhere, but still). And ideally, you should leave all previous tests in place. Or fix them, if there is any error there - but there should be some rationale when removing tests.

Comment on lines -662 to +675
desiredGrant := &TablePrivilegeGrant{
desiredTableGrant := &TablePrivilegeGrant{
Database: database,
Table: table,
Table: tableOrCallable,
Grant: grantOption,
UserOrRole: userOrRole,
}

desiredProcedureGrant := &ProcedurePrivilegeGrant{
Database: database,
CallableName: tableOrCallable,
Grant: grantOption,
UserOrRole: userOrRole,
ObjectT: kProcedure,
}

Choose a reason for hiding this comment

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

I am wondering if we could make this a bit simpler by parsing the tableOrCallable directly:

var desiredGrant *MySQLGrant = nil
if kReProcedureWithoutDatabase.MatchString(database) {
     desiredGrant = &ProcedurePrivilegeGrant{ ... }
} else {
     desiredGrant = &TablePrivilegeGrant{ ... }
}

Copy link
Author

Choose a reason for hiding this comment

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

My understanding is that we don't have this in formation at this point—database is derived from the id string being imported, and the way it's constructed now does not expose this information. My initial approach was to do something like this but I couldn't find a clean way.

@@ -688,20 +697,42 @@ func ImportGrant(ctx context.Context, d *schema.ResourceData, meta interface{})
return results, nil
}

func produceGrantId(database string, username string, host string) string {

Choose a reason for hiding this comment

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

This seems potentially redundant with the GetId interface of MySQLGrant. Why do we need both?

Copy link
Author

Choose a reason for hiding this comment

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

That's right! I don't think we do! Thanks for pointing that out.

database := procedureGrant.Database
id := produceGrantId(database, userOrRole.Name, userOrRole.Host)
d.SetId(id)
d.Set("database", fmt.Sprintf("PROCEDURE %s.%s", database, procedureGrant.CallableName))

Choose a reason for hiding this comment

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

This is not a safe operation, because the user can specify the database as in Example 2:

#99 (comment)

Copy link
Author

Choose a reason for hiding this comment

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

I see, I think I might be able to set table here instead of the string interpolation

@@ -888,21 +889,6 @@ func TestAccGrantOnProcedure(t *testing.T) {
prepareProcedure(dbName, procedureName),
),
},
{

Choose a reason for hiding this comment

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

This test needs to remain. Although it does make no sense semantically, this is something that was supported by the deprecated Hashicorp mysql provider, and has made its way into other modules:

#99 (comment)

I think the fix for this (as described in that issue), is that we need to introduce a v2 of the mysql_grant resource, ideally specific to each type (eg. mysql_table_grant, mysql_procedure_grant, etc).

@gallois
Copy link
Author

gallois commented Mar 8, 2024

Got it. I'm afraid I'm a bit time-constrained right now to be able to implement additional changes, mostly because "it works on my machine"™

I'll close this PR for now and keep following #112 to ensure I jump back to upstream when it's fixed.

Thanks a lot for the effort in maintaining it :)

@gallois gallois closed this Mar 8, 2024
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.

3 participants