-
Notifications
You must be signed in to change notification settings - Fork 416
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: Secret resource #3110
base: main
Are you sure you want to change the base?
feat: Secret resource #3110
Conversation
… oauth_scopes to use helper function
…ource # Conflicts: # pkg/acceptance/check_destroy.go # pkg/acceptance/helpers/secret_client.go # pkg/provider/provider.go # pkg/provider/resources/resources.go # pkg/resources/secret_common.go
… dateTime input formats for refresh_token_expiry_time
# Conflicts: # pkg/acceptance/bettertestspoc/assert/objectassert/gen/sdk_object_def.go # pkg/acceptance/helpers/secret_client.go # pkg/sdk/poc/README.md # pkg/sdk/secrets_gen_test.go # pkg/sdk/secrets_impl_gen.go # pkg/sdk/secrets_validations_gen.go # pkg/sdk/testint/secrets_gen_integration_test.go
Integration tests failure for 07dc9e29726c465f1635293ac6b23b7e13fdaf9b |
Integration tests failure for 5c6d9ee8b438ea658b934cbd02c5f6bccbc83dcd |
Integration tests failure for 805c61e39315df81ff6f61aa9098a2b699ce26bd |
Integration tests failure for 044c4846d411d361ab761f43443b18bdaa26af4f |
Integration tests failure for 4ae36a482dc1a7721e769128cc8a2ad23dd79efe |
Integration tests failure for 4ac851a10ed73c3b48e20d37e3d20f124c75991e |
}, | ||
"username": { | ||
Type: schema.TypeString, | ||
Optional: true, |
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.
Why optional? In other fields too.
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.
Describe for secret in Snowflake leaves some of those fields as "null" since secret can be one of four different types. Thought it needs to be included here as well, but it works as it should after removing the Optional from those fields.
} | ||
if details.OauthRefreshTokenExpiryTime != nil { | ||
s["oauth_refresh_token_expiry_time"] = details.OauthRefreshTokenExpiryTime.String() | ||
} |
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.
created_on
is missing.
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.
added created_on
to SecretDescriptionToSchema()
@@ -71,7 +71,7 @@ func (c *SecretClient) CreateWithBasicAuthenticationFlow(t *testing.T, id sdk.Sc | |||
func (c *SecretClient) CreateWithGenericString(t *testing.T, id sdk.SchemaObjectIdentifier, secretString string) (*sdk.Secret, func()) { | |||
t.Helper() | |||
ctx := context.Background() | |||
request := sdk.NewCreateWithGenericStringSecretRequest(id, secretString) | |||
request := sdk.NewCreateWithGenericStringSecretRequest(id, secretString).WithOrReplace(true) |
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.
We should not use OrReplace by default. It should be either an argument, or the function should be called CreateOrReplace...
or Recreate...
ShowOutputAttributeName: { | ||
Type: schema.TypeList, | ||
Computed: true, | ||
Description: "Outputs the result of `SHOW SECRET` for the given secret.", |
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.
should be SHOW SECRETS
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.
has been changed
if err := d.Set("database", secret.DatabaseName); err != nil { | ||
return err | ||
} | ||
if err := d.Set("schema", secret.SchemaName); err != nil { |
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.
name
, database
, and schema
should be only in the import function.
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.
removed
return diag.FromErr(err) | ||
} | ||
|
||
if err := client.Secrets.Drop(ctx, sdk.NewDropSecretRequest(id).WithIfExists(*sdk.Bool(true))); err != nil { |
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.
It could be simply WithIfExists(true)
. This applies to other resources.
}) | ||
} | ||
|
||
func TestAcc_SecretWithAuthorizationCodeGrant_DifferentTimeFormats(t *testing.T) { |
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.
👍
name = "EXAMPLE_SECRET" | ||
database = "EXAMPLE_DB" | ||
schema = "EXAMPLE_SCHEMA" | ||
api_authentication = "EXAMPLE_SECURITY_INTEGRATION_NAME" |
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.
We have the fully_qualified_name
field in most of the resources, and we prefer using this instead. Security integrations have simple IDs, but schema-level objects and resources with arguments have complex IDs that are error-prone. Just for the future :)
HasDatabaseString(id.DatabaseName()). | ||
HasSchemaString(id.SchemaName()). | ||
HasApiAuthenticationString(integrationId.Name()), | ||
assert.Check(resource.TestCheckResourceAttr(secretModel.ResourceReference(), "oauth_scopes.#", "1")), |
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.
You can add a custom method in the resourceassert package - check _ext
files. This way we can assert slices, because generator doesn't handle them properly. There, you can compare slices by length, and then check if they have the same elements.
}, | ||
// set oauth_scopes and comment in config | ||
{ | ||
Config: config.FromModel(t, secretModel. |
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.
Please also add a test case that checks for external changes - see how we do it in other resources. Add them to all of the secret resources.
I forgot to add, but there are missing entries in MIGRATION GUIDE and custom templates in |
description: |- | ||
Secret with OAuth authorization code grant where Secrets Type attribute is set to OAUTH2. | ||
--- | ||
|
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.
The documentation for new resources should contain note at the top that it's v1 candidate. You have to create custom template that's under template/resources/*
directory (ask if you need guidance on that; same for other newly added resources).
@@ -0,0 +1,10 @@ | |||
# basic resource |
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.
We usually give a basic example that contains only a minimal field resources to create it (e.g., comment is not needed; it's optional) and a complete example with all options set. Of course every resource is different, but this one is pretty straight forward and basic + complete examples would be sufficient. (same applies to other resources).
@@ -71,7 +71,7 @@ func (c *SecretClient) CreateWithBasicAuthenticationFlow(t *testing.T, id sdk.Sc | |||
func (c *SecretClient) CreateWithGenericString(t *testing.T, id sdk.SchemaObjectIdentifier, secretString string) (*sdk.Secret, func()) { | |||
t.Helper() | |||
ctx := context.Background() | |||
request := sdk.NewCreateWithGenericStringSecretRequest(id, secretString) | |||
request := sdk.NewCreateWithGenericStringSecretRequest(id, secretString).WithOrReplace(true) |
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.
Is this needed? I'm guessing it was needed because in some of the tests you're calling Create too many times?
if err := d.Set("database", secret.DatabaseName); err != nil { | ||
return err | ||
} | ||
if err := d.Set("schema", secret.SchemaName); err != nil { |
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.
We don't set "name", "database", "schema" in read, we only do it in the import, remove them from here
return nil | ||
} | ||
|
||
func handleSecretUpdate(id sdk.SchemaObjectIdentifier, d *schema.ResourceData) *sdk.AlterSecretRequest { |
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 would refactor this function to take in *sdk.AlterSecretRequest
rather than create it here and either return it or nil. I can imagine there's a bug (or could be) that we would like to use that request and it's nil, because there were no changes done to "comment" field where the request is created.
return nil, err | ||
} | ||
|
||
if err := d.Set("oauth_refresh_token_expiry_time", secretDescription.OauthRefreshTokenExpiryTime.String()); err != nil { |
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.
Why this is not read in the Read operation?
if err := d.Set("oauth_refresh_token_expiry_time", secretDescription.OauthRefreshTokenExpiryTime.String()); err != nil { | ||
return nil, err | ||
} | ||
if err := d.Set("api_authentication", secretDescription.IntegrationName); err != nil { |
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.
Import is constructed in a way that always after Import there's Read, so if you read this value in Read operation you can safely remove it.
return diag.FromErr(err) | ||
} | ||
|
||
if err = setStateToValuesFromConfig(d, secretAuthorizationCodeGrantSchema, []string{"oauth_refresh_token_expiry_time"}); err != nil { |
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 think normal d.Set would be sufficient here (it would change the behaviour, but I think it's better suited for this case.
WithComment(newComment), | ||
), | ||
ConfigPlanChecks: resource.ConfigPlanChecks{ | ||
PreApply: []plancheck.PlanCheck{ |
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.
you can also check action for the whole resource with:
plancheck.ExpectResourceAction(secretModel.ResourceReference(), plancheck.ResourceActionUpdate),
return diag.Diagnostics{ | ||
diag.Diagnostic{ | ||
Severity: diag.Warning, | ||
Summary: "Failed to retrieve secret. Target object not found. Marking the resource as removed.", |
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.
It's also to give details here like in the diag below (it's easier to detect for which id this error happened; for us and the user).
Changes
snowflake_secret_with_client_credentials
resourcesnowflake_secret_with_authorization_code_grant
resourcesnowflake_secret_with_basic_authentication
resourcesnowflake_secret_with_generic_string
resourceTest Plan
References
https://docs.snowflake.com/en/sql-reference/sql/create-secret