Skip to content

Commit

Permalink
Fix: env0_gcp_credentials - apply after import will delete+create (#380)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerHeber committed May 17, 2022
1 parent 0b32813 commit c683c74
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 8 deletions.
36 changes: 31 additions & 5 deletions env0/resource_gcp_credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package env0

import (
"context"
"fmt"

"github.com/env0/terraform-provider-env0/client"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand All @@ -14,6 +15,8 @@ func resourceGcpCredentials() *schema.Resource {
ReadContext: resourceGcpCredentialsRead,
DeleteContext: resourceGcpCredentialsDelete,

Importer: &schema.ResourceImporter{StateContext: resourceGcpCredentialsImport},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand All @@ -40,19 +43,21 @@ func resourceGcpCredentials() *schema.Resource {
}

func resourceGcpCredentialsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
value := client.GcpCredentialsValuePayload{}
if err := readResourceData(&value, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}

apiClient := meta.(client.ApiClientInterface)

value := client.GcpCredentialsValuePayload{
ProjectId: d.Get("project_id").(string),
ServiceAccountKey: d.Get("service_account_key").(string),
}
requestType := client.GcpServiceAccountCredentialsType

request := client.GcpCredentialsCreatePayload{
Name: d.Get("name").(string),
Value: value,
Type: requestType,
}

credentials, err := apiClient.GcpCredentialsCreate(request)
if err != nil {
return diag.Errorf("could not create credentials key: %v", err)
Expand All @@ -67,10 +72,15 @@ func resourceGcpCredentialsRead(ctx context.Context, d *schema.ResourceData, met
apiClient := meta.(client.ApiClientInterface)

id := d.Id()
_, err := apiClient.CloudCredentials(id)
credentials, err := apiClient.CloudCredentials(id)
if err != nil {
return ResourceGetFailure("gcp credentials", d, err)
}

if err := writeResourceData(&credentials, d); err != nil {
return diag.Errorf("schema resource data serialization failed: %v", err)
}

return nil
}

Expand All @@ -84,3 +94,19 @@ func resourceGcpCredentialsDelete(ctx context.Context, d *schema.ResourceData, m
}
return nil
}

func resourceGcpCredentialsImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
credentials, err := getCredentials(d.Id(), "GCP_", meta)
if err != nil {
if _, ok := err.(*client.NotFoundError); ok {
return nil, fmt.Errorf("gcp credentials resource with id %v not found", d.Id())
}
return nil, err
}

if err := writeResourceData(&credentials, d); err != nil {
return nil, fmt.Errorf("schema resource data serialization failed: %v", err)
}

return []*schema.ResourceData{d}, nil
}
109 changes: 106 additions & 3 deletions env0/resource_gcp_credentials_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package env0

import (
"fmt"
"regexp"
"testing"

"github.com/env0/terraform-provider-env0/client"
Expand All @@ -14,6 +16,7 @@ func TestUnitGcpCredentialsResource(t *testing.T) {

resourceType := "env0_gcp_credentials"
resourceName := "test"
resourceNameImport := resourceType + "." + resourceName
accessor := resourceAccessor(resourceType, resourceName)

gcpCredentialResource := map[string]interface{}{
Expand All @@ -23,7 +26,7 @@ func TestUnitGcpCredentialsResource(t *testing.T) {
}

updateGcpCredentialResource := map[string]interface{}{
"name": "testUpdate",
"name": "update",
"project_id": "333_update",
"service_account_key": "444_update",
}
Expand All @@ -47,14 +50,21 @@ func TestUnitGcpCredentialsResource(t *testing.T) {
}

returnValues := client.Credentials{
Id: "id",
Id: "f595c4b6-0a24-4c22-89f7-7030045de300",
Name: "test",
OrganizationId: "id",
Type: string(client.GcpServiceAccountCredentialsType),
}

otherTypeReturnValues := client.Credentials{
Id: "f595c4b6-0a24-4c22-89f7-7030045de30a",
Name: "test",
OrganizationId: "id",
Type: "AZURE_....",
}

updateReturnValues := client.Credentials{
Id: "id2",
Id: "f595c4b6-0a24-4c22-89f7-7030045de311",
Name: "update",
OrganizationId: "id",
Type: string(client.GcpServiceAccountCredentialsType),
Expand Down Expand Up @@ -165,4 +175,97 @@ func TestUnitGcpCredentialsResource(t *testing.T) {
)
})
})

t.Run("import by name", func(t *testing.T) {
testCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: resourceConfigCreate(resourceType, resourceName, gcpCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: gcpCredentialResource["name"].(string),
ImportStateVerify: false,
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().GcpCredentialsCreate(gcpCredCreatePayload).Times(1).Return(returnValues, nil)
mock.EXPECT().CloudCredentials(returnValues.Id).Times(2).Return(returnValues, nil)
mock.EXPECT().CloudCredentialsList().Times(1).Return([]client.Credentials{otherTypeReturnValues, returnValues}, nil)
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil)
})
})

t.Run("import by id", func(t *testing.T) {
testCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: resourceConfigCreate(resourceType, resourceName, gcpCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: returnValues.Id,
ImportStateVerify: false,
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().GcpCredentialsCreate(gcpCredCreatePayload).Times(1).Return(returnValues, nil)
mock.EXPECT().CloudCredentials(returnValues.Id).Times(3).Return(returnValues, nil)
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil)
})
})

t.Run("import by id not found", func(t *testing.T) {
testCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: resourceConfigCreate(resourceType, resourceName, gcpCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: otherTypeReturnValues.Id,
ImportStateVerify: true,
ExpectError: regexp.MustCompile(fmt.Sprintf("gcp credentials resource with id %v not found", otherTypeReturnValues.Id)),
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().GcpCredentialsCreate(gcpCredCreatePayload).Times(1).Return(returnValues, nil)
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil)
mock.EXPECT().CloudCredentials(otherTypeReturnValues.Id).Times(1).Return(client.Credentials{}, &client.NotFoundError{})
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil)
})
})

t.Run("import by name not found", func(t *testing.T) {
testCase := resource.TestCase{
Steps: []resource.TestStep{
{
Config: resourceConfigCreate(resourceType, resourceName, gcpCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: gcpCredentialResource["name"].(string),
ImportStateVerify: true,
ExpectError: regexp.MustCompile(fmt.Sprintf("credentials with name %v not found", gcpCredentialResource["name"].(string))),
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().GcpCredentialsCreate(gcpCredCreatePayload).Times(1).Return(returnValues, nil)
mock.EXPECT().CloudCredentials(returnValues.Id).Times(1).Return(returnValues, nil)
mock.EXPECT().CloudCredentialsList().Times(1).Return([]client.Credentials{otherTypeReturnValues}, nil)
mock.EXPECT().CloudCredentialsDelete(returnValues.Id).Times(1).Return(nil)
})
})
}
2 changes: 2 additions & 0 deletions examples/resources/env0_gcp_credentials/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
terraform import env0_gcp_credentials.by_id d31a6b30-5f69-4d24-937c-22322754934e
terraform import env0_gcp_credentials.by_name "credentials name"

0 comments on commit c683c74

Please sign in to comment.