Skip to content

Commit

Permalink
Fix: env0_azure_credentials - apply after import will delete+create (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerHeber committed May 16, 2022
1 parent 02dc52d commit fcf606a
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 10 deletions.
39 changes: 32 additions & 7 deletions env0/resource_azure_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 resourceAzureCredentials() *schema.Resource {
ReadContext: resourceAzureCredentialsRead,
DeleteContext: resourceAzureCredentialsDelete,

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

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -51,21 +54,21 @@ func resourceAzureCredentials() *schema.Resource {
}

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

apiClient := meta.(client.ApiClientInterface)

value := client.AzureCredentialsValuePayload{
ClientId: d.Get("client_id").(string),
ClientSecret: d.Get("client_secret").(string),
SubscriptionId: d.Get("subscription_id").(string),
TenantId: d.Get("tenant_id").(string),
}
requestType := client.AzureServicePrincipalCredentialsType

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

credentials, err := apiClient.AzureCredentialsCreate(request)
if err != nil {
return diag.Errorf("could not create credentials key: %v", err)
Expand All @@ -80,10 +83,16 @@ func resourceAzureCredentialsRead(ctx context.Context, d *schema.ResourceData, m
apiClient := meta.(client.ApiClientInterface)

id := d.Id()
_, err := apiClient.CloudCredentials(id)

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

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

return nil
}

Expand All @@ -97,3 +106,19 @@ func resourceAzureCredentialsDelete(ctx context.Context, d *schema.ResourceData,
}
return nil
}

func resourceAzureCredentialsImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
credentials, err := getCredentials(d.Id(), "AZURE_", meta)
if err != nil {
if _, ok := err.(*client.NotFoundError); ok {
return nil, fmt.Errorf("azure 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_azure_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 TestUnitAzureCredentialsResource(t *testing.T) {

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

azureCredentialResource := map[string]interface{}{
Expand Down Expand Up @@ -55,15 +58,22 @@ func TestUnitAzureCredentialsResource(t *testing.T) {
}

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

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

updateReturnValues := client.Credentials{
Id: "id2",
Name: "update",
Id: "f595c4b6-0a24-4c22-89f7-7030045de3aa",
Name: "testUpdate",
OrganizationId: "id",
Type: string(client.AzureServicePrincipalCredentialsType),
}
Expand Down Expand Up @@ -176,4 +186,97 @@ func TestUnitAzureCredentialsResource(t *testing.T) {
)
})
})

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

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().AzureCredentialsCreate(azureCredCreatePayload).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, azureCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: returnValues.Id,
ImportStateVerify: false,
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().AzureCredentialsCreate(azureCredCreatePayload).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, azureCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: otherTypeReturnValues.Id,
ImportStateVerify: true,
ExpectError: regexp.MustCompile(fmt.Sprintf("azure credentials resource with id %v not found", otherTypeReturnValues.Id)),
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().AzureCredentialsCreate(azureCredCreatePayload).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, azureCredentialResource),
},
{
ResourceName: resourceNameImport,
ImportState: true,
ImportStateId: azureCredentialResource["name"].(string),
ImportStateVerify: true,
ExpectError: regexp.MustCompile(fmt.Sprintf("credentials with name %v not found", azureCredentialResource["name"].(string))),
},
},
}

runUnitTest(t, testCase, func(mock *client.MockApiClientInterface) {
mock.EXPECT().AzureCredentialsCreate(azureCredCreatePayload).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_azure_credentials/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
terraform import env0_azure_credentials.by_id d31a6b30-5f69-4d24-937c-22322754934e
terraform import env0_azure_credentials.by_name "credentials name"

0 comments on commit fcf606a

Please sign in to comment.