diff --git a/env0/resource_gcp_credentials.go b/env0/resource_gcp_credentials.go index 9e056fba..0c5dce54 100644 --- a/env0/resource_gcp_credentials.go +++ b/env0/resource_gcp_credentials.go @@ -2,6 +2,7 @@ package env0 import ( "context" + "fmt" "github.com/env0/terraform-provider-env0/client" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -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, @@ -40,12 +43,13 @@ 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{ @@ -53,6 +57,7 @@ func resourceGcpCredentialsCreate(ctx context.Context, d *schema.ResourceData, m Value: value, Type: requestType, } + credentials, err := apiClient.GcpCredentialsCreate(request) if err != nil { return diag.Errorf("could not create credentials key: %v", err) @@ -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 } @@ -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 +} diff --git a/env0/resource_gcp_credentials_test.go b/env0/resource_gcp_credentials_test.go index 13bf02ab..20e1f7df 100644 --- a/env0/resource_gcp_credentials_test.go +++ b/env0/resource_gcp_credentials_test.go @@ -1,6 +1,8 @@ package env0 import ( + "fmt" + "regexp" "testing" "github.com/env0/terraform-provider-env0/client" @@ -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{}{ @@ -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", } @@ -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), @@ -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) + }) + }) } diff --git a/examples/resources/env0_gcp_credentials/import.sh b/examples/resources/env0_gcp_credentials/import.sh new file mode 100644 index 00000000..66ca3f79 --- /dev/null +++ b/examples/resources/env0_gcp_credentials/import.sh @@ -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" \ No newline at end of file