Skip to content

Commit

Permalink
Fix: env0_aws_credentials - apply after import will delete+create
Browse files Browse the repository at this point in the history
  • Loading branch information
TomerHeber committed May 10, 2022
1 parent ca47ac8 commit a000e9d
Show file tree
Hide file tree
Showing 17 changed files with 258 additions and 41 deletions.
8 changes: 2 additions & 6 deletions client/cloud_credentials.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package client

import (
"fmt"
)

type AwsCredentialsType string
type GcpCredentialsType string
type AzureCredentialsType string
Expand Down Expand Up @@ -37,7 +33,7 @@ type AwsCredentialsCreatePayload struct {
}

type AwsCredentialsValuePayload struct {
RoleArn string `json:"roleArn"`
RoleArn string `json:"roleArn" resource:"arn"`
ExternalId string `json:"externalId"`
AccessKeyId string `json:"accessKeyId"`
SecretAccessKey string `json:"secretAccessKey"`
Expand Down Expand Up @@ -89,7 +85,7 @@ func (client *ApiClient) CloudCredentials(id string) (Credentials, error) {
}
}

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

func (client *ApiClient) CloudCredentialsList() ([]Credentials, error) {
Expand Down
7 changes: 7 additions & 0 deletions client/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package client

type NotFoundError struct{}

func (e *NotFoundError) Error() string {
return "not found"
}
47 changes: 47 additions & 0 deletions env0/credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package env0

import (
"fmt"
"log"
"strings"

"github.com/env0/terraform-provider-env0/client"
"github.com/google/uuid"
)

func getCredentialsByName(name string, prefix string, meta interface{}) (client.Credentials, error) {
apiClient := meta.(client.ApiClientInterface)

credentialsList, err := apiClient.CloudCredentialsList()
if err != nil {
return client.Credentials{}, err
}

var foundCredentials []client.Credentials
for _, credentials := range credentialsList {
if credentials.Name == name && strings.HasPrefix(credentials.Type, prefix) {
foundCredentials = append(foundCredentials, credentials)
}
}

if len(foundCredentials) == 0 {
return client.Credentials{}, fmt.Errorf("credentials with name %v not found", name)
}

if len(foundCredentials) > 1 {
return client.Credentials{}, fmt.Errorf("found multiple credentials with name: %s. Use id instead or make sure credential names are unique %v", name, foundCredentials)
}

return foundCredentials[0], nil
}

func getCredentials(id string, prefix string, meta interface{}) (client.Credentials, error) {
_, err := uuid.Parse(id)
if err == nil {
log.Println("[INFO] Resolving credentials by id: ", id)
return meta.(client.ApiClientInterface).CloudCredentials(id)
} else {
log.Println("[INFO] Resolving credentials by name: ", id)
return getCredentialsByName(id, prefix, meta)
}
}
2 changes: 1 addition & 1 deletion env0/data_notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

return nil
Expand Down
15 changes: 14 additions & 1 deletion env0/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,26 @@ package env0
import (
"log"

"github.com/env0/terraform-provider-env0/client"
"github.com/env0/terraform-provider-env0/client/http"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func ResourceGetFailure(resourceName string, d *schema.ResourceData, err error) diag.Diagnostics {
func driftDetected(d *schema.ResourceData, err error) bool {
if frerr, ok := err.(*http.FailedResponseError); ok && frerr.NotFound() {
return true
}

if _, ok := err.(*client.NotFoundError); ok {
return true
}

return false
}

func ResourceGetFailure(resourceName string, d *schema.ResourceData, err error) diag.Diagnostics {
if driftDetected(d, err) {
log.Printf("[WARN] Drift Detected: Terraform will remove %s from state", d.Id())
d.SetId("")
return nil
Expand Down
4 changes: 2 additions & 2 deletions env0/resource_agent_project_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func resourceAgentProjectAssignmentRead(ctx context.Context, d *schema.ResourceD
}

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

return nil
Expand Down Expand Up @@ -189,7 +189,7 @@ func resourceAgentProjectAssignmentImport(ctx context.Context, d *schema.Resourc
}

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

return []*schema.ResourceData{d}, nil
Expand Down
4 changes: 2 additions & 2 deletions env0/resource_api_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func resourceApiKeyRead(ctx context.Context, d *schema.ResourceData, meta interf
}

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

return nil
Expand Down Expand Up @@ -138,7 +138,7 @@ func resourceApiKeyImport(ctx context.Context, d *schema.ResourceData, meta inte
}

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

return []*schema.ResourceData{d}, nil
Expand Down
54 changes: 38 additions & 16 deletions env0/resource_aws_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 resourceAwsCredentials() *schema.Resource {
ReadContext: resourceAwsCredentialsRead,
DeleteContext: resourceAwsCredentialsDelete,

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

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand All @@ -27,7 +30,6 @@ func resourceAwsCredentials() *schema.Resource {
Optional: true,
ForceNew: true,
ConflictsWith: []string{"access_key_id"},
ExactlyOneOf: []string{"access_key_id"},
},
"external_id": {
Type: schema.TypeString,
Expand All @@ -46,7 +48,6 @@ func resourceAwsCredentials() *schema.Resource {
ForceNew: true,
ConflictsWith: []string{"arn", "external_id"},
RequiredWith: []string{"secret_access_key"},
ExactlyOneOf: []string{"arn"},
},
"secret_access_key": {
Type: schema.TypeString,
Expand All @@ -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")
_, arnExist := d.GetOk("arn")
if !accessKeyExist && !arnExist {
// Due to "import" must be inforced here and not in the schema level.
// This fields are only available during creation (will not be returned in read or import).
return diag.Errorf("one of `access_key_id,arn` must be specified")
}

apiClient := meta.(client.ApiClientInterface)

value := client.AwsCredentialsValuePayload{}
requestType := client.AwsAssumedRoleCredentialsType
if arn, ok := d.GetOk("arn"); ok {
value.RoleArn = arn.(string)
requestType = client.AwsAssumedRoleCredentialsType
}
if externalId, ok := d.GetOk("external_id"); ok {
value.ExternalId = externalId.(string)
if err := readResourceData(&value, d); err != nil {
return diag.Errorf("schema resource data deserialization failed: %v", err)
}
if accessKeyId, ok := d.GetOk("access_key_id"); ok {
value.AccessKeyId = accessKeyId.(string)

requestType := client.AwsAssumedRoleCredentialsType
if _, ok := d.GetOk("access_key_id"); ok {
requestType = client.AwsAccessKeysCredentialsType
}
if secretAccessKey, ok := d.GetOk("secret_access_key"); ok {
value.SecretAccessKey = secretAccessKey.(string)
}

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

credentials, err := apiClient.AwsCredentialsCreate(request)
if err != nil {
return diag.Errorf("could not create credentials key: %v", err)
Expand All @@ -98,11 +102,14 @@ func resourceAwsCredentialsCreate(ctx context.Context, d *schema.ResourceData, m
func resourceAwsCredentialsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
apiClient := meta.(client.ApiClientInterface)

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

d.Set("name", credentials.Name)
d.SetId(credentials.Id)

return nil
}

Expand All @@ -116,3 +123,18 @@ func resourceAwsCredentialsDelete(ctx context.Context, d *schema.ResourceData, m
}
return nil
}

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

d.Set("name", credentials.Name)
d.SetId(credentials.Id)

return []*schema.ResourceData{d}, nil
}
Loading

0 comments on commit a000e9d

Please sign in to comment.