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: env0_aws_credentials - apply after import will delete+create #371

Merged
merged 2 commits into from
May 13, 2022

Conversation

TomerHeber
Copy link
Collaborator

@TomerHeber TomerHeber commented May 10, 2022

I'm keeping open, to adding support for other credential types.

Solution

Added import.
Removed a schema requirements and instead enforce during read.
Added acceptance tests.
Added a "resource" tag.
Added import examples.
Fixed some other issues I noticed.

@@ -37,7 +33,7 @@ type AwsCredentialsCreatePayload struct {
}

type AwsCredentialsValuePayload struct {
RoleArn string `json:"roleArn"`
RoleArn string `json:"roleArn" resource:"arn"`
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

new tag type for serialization. See usage below.
(Basically in terraform the resource is "arn" and not "role_arn" - so needed to resolve this).

@@ -89,7 +85,7 @@ func (client *ApiClient) CloudCredentials(id string) (Credentials, error) {
}
}

return Credentials{}, fmt.Errorf("CloudCredentials: [%s] not found ", id)
return Credentials{}, &NotFoundError{}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Used to handle drift later.

"github.com/google/uuid"
)

func getCredentialsByName(name string, prefix string, meta interface{}) (client.Credentials, error) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Common helper functions for credentials (can be used by GCP and Azure in the future). (In case import is added to them as well).

@@ -61,7 +61,7 @@ func dataNotificationRead(ctx context.Context, d *schema.ResourceData, meta inte
}

if err := writeResourceData(notification, d); err != nil {
diag.Errorf("schema resource data serialization failed: %v", err)
return diag.Errorf("schema resource data serialization failed: %v", err)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

bug.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

there are a few places with the same bug...

@@ -27,7 +30,6 @@ func resourceAwsCredentials() *schema.Resource {
Optional: true,
ForceNew: true,
ConflictsWith: []string{"access_key_id"},
ExactlyOneOf: []string{"access_key_id"},
Copy link
Collaborator Author

@TomerHeber TomerHeber May 10, 2022

Choose a reason for hiding this comment

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

The "ExactlyOneOf" cannot be enforced in the schema level. (Will fail on import).
(Enforced in the code level).

@@ -62,29 +63,32 @@ func resourceAwsCredentials() *schema.Resource {
}

func resourceAwsCredentialsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
_, accessKeyExist := d.GetOk("access_key_id")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Enforcing the exactlyOnce in the code level only for creation (not for read/import).

}
if externalId, ok := d.GetOk("external_id"); ok {
value.ExternalId = externalId.(string)
if err := readResourceData(&value, d); err != nil {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

some small refactoring (less lines of code).

env0/utils.go Outdated
fieldNameSC := toSnakeCase(fieldName)
if resFieldName, ok := val.Type().Field(i).Tag.Lookup("resource"); ok {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is for the new tag I created (resource). Ping me if this is still unclear.

Copy link
Contributor

Choose a reason for hiding this comment

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

Very cool 👏
Just wondering together with you whether resourcee is a decent tag name or we can come up with a better name. Maybe something that indicates that this is related to the TF schema would do better.

Also - WDYT about adding some note regarding it in DEVELOPMENT.md?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes and yes.
How about tfschema or tfresource ? (I'm bad with names).

Copy link
Contributor

@yaronya yaronya May 12, 2022

Choose a reason for hiding this comment

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

Both are better. If you want me to choose then I'd go with tfschema 😅

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

we have a winner (:

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done!

@@ -91,6 +91,24 @@ func TestReadResourceDataNotification(t *testing.T) {
assert.Equal(t, expectedPayload, payload)
}

func TestReadResourceDataWithTag(t *testing.T) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

test for the new resource tag (hopefully this test helps clarify it).

@TomerHeber TomerHeber requested a review from yaronya May 10, 2022 19:32
@@ -108,7 +116,7 @@ func TestUnitAwsCredentialsResource(t *testing.T) {
Steps: []resource.TestStep{
{
Config: resourceConfigCreate(resourceType, resourceName, mutuallyExclusiveErrorResource),
ExpectError: regexp.MustCompile("only one of `access_key_id,arn` can be specified"),
ExpectError: regexp.MustCompile(`"external_id": conflicts with access_key_id`),
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There are multiple errors., the following just come before.

Copy link
Contributor

@yaronya yaronya left a comment

Choose a reason for hiding this comment

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

Nice work!
Left some few minor comments

Comment on lines 110 to 111
d.Set("name", credentials.Name)
d.SetId(credentials.Id)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use the seralization logic here instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yeah sure. In general, I use it when there a multiple fields.
Either way is fine by me. I'll fix it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think always using it makes a lot of sense since we wouldn't need to change anything when we'll add a new field 💪

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done!

env0/resource_aws_credentials.go Outdated Show resolved Hide resolved
env0/utils.go Outdated
fieldNameSC := toSnakeCase(fieldName)
if resFieldName, ok := val.Type().Field(i).Tag.Lookup("resource"); ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

Very cool 👏
Just wondering together with you whether resourcee is a decent tag name or we can come up with a better name. Maybe something that indicates that this is related to the TF schema would do better.

Also - WDYT about adding some note regarding it in DEVELOPMENT.md?

@@ -14,6 +15,8 @@ func resourceAwsCredentials() *schema.Resource {
ReadContext: resourceAwsCredentialsRead,
DeleteContext: resourceAwsCredentialsDelete,

Importer: &schema.ResourceImporter{StateContext: resourceAwsCredentialsImport},
Copy link
Contributor

Choose a reason for hiding this comment

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

@TomerHeber if we're already at it, can we perhaps also support import for all other credentials type? I'd do it in a separate PR tho

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

keeping the issue open.

@github-actions github-actions bot added ready to merge PR approved - can be merged once the PR owner is ready and removed pending final review labels May 13, 2022
@TomerHeber TomerHeber merged commit f488f56 into main May 13, 2022
@TomerHeber TomerHeber deleted the fix-apply-will-delete-create-#99 branch May 13, 2022 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-client examples fix provider ready to merge PR approved - can be merged once the PR owner is ready
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants