From f83d23eb5e384cc467bbed9e0165263690d287b3 Mon Sep 17 00:00:00 2001 From: Tomer Heber Date: Sat, 21 May 2022 13:00:46 -0500 Subject: [PATCH] Feat: refactor resources/data to use the new serialization/deserialization logic --- env0/resource_cost_credentials.go | 6 +- env0/resource_drift_detection.go | 29 ++++---- env0/resource_environment_scheduling.go | 11 +-- env0/resource_project_policy.go | 99 ++++++------------------- env0/resource_project_policy_test.go | 2 +- env0/validators.go | 13 +++- 6 files changed, 54 insertions(+), 106 deletions(-) diff --git a/env0/resource_cost_credentials.go b/env0/resource_cost_credentials.go index 5a717106..09592f20 100644 --- a/env0/resource_cost_credentials.go +++ b/env0/resource_cost_credentials.go @@ -128,13 +128,11 @@ func resourceCostCredentialsRead(ctx context.Context, d *schema.ResourceData, me func resourceCostCredentialsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) - id := d.Id() - err := apiClient.CloudCredentialsDelete(id) - if err != nil { + if err := apiClient.CloudCredentialsDelete(d.Id()); err != nil { return diag.Errorf("could not delete credentials: %v", err) } - return nil + return nil } func sendApiCallToCreateCred(d *schema.ResourceData, meta interface{}) (client.Credentials, error) { diff --git a/env0/resource_drift_detection.go b/env0/resource_drift_detection.go index 7c29d9a2..12a3111d 100644 --- a/env0/resource_drift_detection.go +++ b/env0/resource_drift_detection.go @@ -2,6 +2,7 @@ package env0 import ( "context" + "log" "github.com/env0/terraform-provider-env0/client" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -32,7 +33,7 @@ func resourceDriftDetection() *schema.Resource { } } -func resourceEnvironmentDriftRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceEnvironmentDriftRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) environmentId := d.Id() @@ -43,15 +44,20 @@ func resourceEnvironmentDriftRead(_ context.Context, d *schema.ResourceData, met return diag.Errorf("could not get environment drift detection: %v", err) } - if drift.Enabled { - d.Set("cron", drift.Cron) - } else { + if !drift.Enabled { + log.Printf("[WARN] Drift Detected: Terraform will remove %s from state", environmentId) d.SetId("") + return nil } + + if err := writeResourceData(&drift, d); err != nil { + return diag.Errorf("schema resource data serialization failed: %v", err) + } + return nil } -func resourceEnvironmentDriftCreateOrUpdate(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceEnvironmentDriftCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) environmentId := d.Get("environment_id").(string) @@ -59,24 +65,19 @@ func resourceEnvironmentDriftCreateOrUpdate(_ context.Context, d *schema.Resourc payload := client.EnvironmentSchedulingExpression{Cron: cron, Enabled: true} - _, err := apiClient.EnvironmentUpdateDriftDetection(environmentId, payload) - - if err != nil { + if _, err := apiClient.EnvironmentUpdateDriftDetection(environmentId, payload); err != nil { return diag.Errorf("could not create or update environment drift detection: %v", err) } d.SetId(environmentId) + return nil } -func resourceEnvironmentDriftDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceEnvironmentDriftDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) - environmentId := d.Id() - - err := apiClient.EnvironmentStopDriftDetection(environmentId) - - if err != nil { + if err := apiClient.EnvironmentStopDriftDetection(d.Id()); err != nil { return diag.Errorf("could not stop environment drift detection: %v", err) } diff --git a/env0/resource_environment_scheduling.go b/env0/resource_environment_scheduling.go index 538fccd3..e201ec04 100644 --- a/env0/resource_environment_scheduling.go +++ b/env0/resource_environment_scheduling.go @@ -84,24 +84,19 @@ func resourceEnvironmentSchedulingCreateOrUpdate(ctx context.Context, d *schema. payload.Destroy = &client.EnvironmentSchedulingExpression{Cron: destroyCron, Enabled: true} } - _, err := apiClient.EnvironmentSchedulingUpdate(environmentId, payload) - - if err != nil { + if _, err := apiClient.EnvironmentSchedulingUpdate(environmentId, payload); err != nil { return diag.Errorf("could not create or update environment scheduling: %v", err) } d.SetId(environmentId) + return nil } func resourceEnvironmentSchedulingDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) - environmentId := d.Id() - - err := apiClient.EnvironmentSchedulingDelete(environmentId) - - if err != nil { + if err := apiClient.EnvironmentSchedulingDelete(d.Id()); err != nil { return diag.Errorf("could not delete environment scheduling: %v", err) } diff --git a/env0/resource_project_policy.go b/env0/resource_project_policy.go index 4773d62c..0838478d 100644 --- a/env0/resource_project_policy.go +++ b/env0/resource_project_policy.go @@ -3,11 +3,8 @@ package env0 import ( "context" "errors" - "log" - "strings" "github.com/env0/terraform-provider-env0/client" - "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -28,39 +25,22 @@ func resourcePolicy() *schema.Resource { Computed: true, }, "project_id": { - Type: schema.TypeString, - Description: "id of the project", - Required: true, - ValidateDiagFunc: func(i interface{}, p cty.Path) diag.Diagnostics { - if strings.TrimSpace(i.(string)) == "" { - return diag.Errorf("project id must not be empty") - } - return nil - }, + Type: schema.TypeString, + Description: "id of the project", + Required: true, + ValidateDiagFunc: ValidateNotEmptyString, }, "number_of_environments": { - Type: schema.TypeInt, - Description: "Max number of environments a single user can have in this project, `null` indicates no limit", - Optional: true, - ValidateDiagFunc: func(i interface{}, p cty.Path) diag.Diagnostics { - n := i.(int) - if n < 1 { - return diag.Errorf("Number of environments must be greater than zero") - } - return nil - }, + Type: schema.TypeInt, + Description: "Max number of environments a single user can have in this project, `null` indicates no limit", + Optional: true, + ValidateDiagFunc: NewGreaterThanValidator(0), }, "number_of_environments_total": { - Type: schema.TypeInt, - Description: "Max number of environments in this project, `null` indicates no limit", - Optional: true, - ValidateDiagFunc: func(i interface{}, p cty.Path) diag.Diagnostics { - n := i.(int) - if n < 1 { - return diag.Errorf("Number of total environments must be greater that zero") - } - return nil - }, + Type: schema.TypeInt, + Description: "Max number of environments in this project, `null` indicates no limit", + Optional: true, + ValidateDiagFunc: NewGreaterThanValidator(0), }, "requires_approval_default": { Type: schema.TypeBool, @@ -107,19 +87,8 @@ func resourcePolicy() *schema.Resource { } } -func setPolicySchema(d *schema.ResourceData, policy client.Policy) { - d.Set("id", policy.Id) - d.Set("project_id", policy.ProjectId) - d.Set("number_of_environments", policy.NumberOfEnvironments) - d.Set("number_of_environments_total", policy.NumberOfEnvironmentsTotal) - d.Set("requires_approval_default", policy.RequiresApprovalDefault) - d.Set("include_cost_estimation", policy.IncludeCostEstimation) - d.Set("skip_apply_when_plan_is_empty", policy.SkipApplyWhenPlanIsEmpty) - d.Set("disable_destroy_environments", policy.DisableDestroyEnvironments) - d.Set("skip_redundant_deployments", policy.SkipRedundantDeployments) - d.Set("updated_by", policy.UpdatedBy) - d.Set("run_pull_request_plan_default", policy.RunPullRequestPlanDefault) - d.Set("continuous_deployment_default", policy.ContinuousDeploymentDefault) +func setPolicySchema(d *schema.ResourceData, policy client.Policy) error { + return writeResourceData(&policy, d) } func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -138,8 +107,11 @@ func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interf return diag.Errorf("could not get policy: %v", err) } + if err := setPolicySchema(d, policy); err != nil { + return diag.Errorf("schema resource data serialization failed: %v", err) + } + d.SetId(projectId) - setPolicySchema(d, policy) return nil } @@ -149,40 +121,11 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta inte projectId := d.Id() d.SetId(projectId) - log.Printf("[INFO] updating policy for project: %s\n", projectId) payload := client.PolicyUpdatePayload{} - if projectId, ok := d.GetOk("project_id"); ok { - payload.ProjectId = projectId.(string) - } - if numberOfEnvironments, ok := d.GetOk("number_of_environments"); ok { - payload.NumberOfEnvironments = numberOfEnvironments.(int) - // return diag.Errorf("number of environments: %d", payload.NumberOfEnvironments) - } - if numberOfEnvironmentsTotal, ok := d.GetOk("number_of_environments_total"); ok { - payload.NumberOfEnvironmentsTotal = numberOfEnvironmentsTotal.(int) - // return diag.Errorf("number of environments total: %d", payload.NumberOfEnvironmentsTotal) - } - if requiresApprovalDefault, ok := d.GetOk("requires_approval_default"); ok { - payload.RequiresApprovalDefault = requiresApprovalDefault.(bool) - } - if includeCostEstimation, ok := d.GetOk("include_cost_estimation"); ok { - payload.IncludeCostEstimation = includeCostEstimation.(bool) - } - if skipApplyWhenPlanIsEmpty, ok := d.GetOk("skip_apply_when_plan_is_empty"); ok { - payload.SkipApplyWhenPlanIsEmpty = skipApplyWhenPlanIsEmpty.(bool) - } - if disableDestroyEnvironments, ok := d.GetOk("disable_destroy_environments"); ok { - payload.DisableDestroyEnvironments = disableDestroyEnvironments.(bool) - } - if skipRedundantDeployments, ok := d.GetOk("skip_redundant_deployments"); ok { - payload.SkipRedundantDeployments = skipRedundantDeployments.(bool) - } - if runPullRequestPlanDefault, ok := d.GetOk("run_pull_request_plan_default"); ok { - payload.RunPullRequestPlanDefault = runPullRequestPlanDefault.(bool) - } - if continuousDeploymentDefault, ok := d.GetOk("continuous_deployment_default"); ok { - payload.ContinuousDeploymentDefault = continuousDeploymentDefault.(bool) + + if err := readResourceData(&payload, d); err != nil { + return diag.Errorf("schema resource data deserialization failed: %v", err) } _, err := apiClient.PolicyUpdate(payload) diff --git a/env0/resource_project_policy_test.go b/env0/resource_project_policy_test.go index 4862923f..6c87c55e 100644 --- a/env0/resource_project_policy_test.go +++ b/env0/resource_project_policy_test.go @@ -221,7 +221,7 @@ func TestUnitPolicyInvalidParams(t *testing.T) { Steps: []resource.TestStep{ { Config: resourceConfigCreate("env0_project_policy", "test", map[string]interface{}{"project_id": ""}), - ExpectError: regexp.MustCompile("project id must not be empty"), + ExpectError: regexp.MustCompile("may not be empty"), }, }, } diff --git a/env0/validators.go b/env0/validators.go index 35cd36a6..f798be1f 100644 --- a/env0/validators.go +++ b/env0/validators.go @@ -38,7 +38,7 @@ func ValidateCronExpression(i interface{}, path cty.Path) diag.Diagnostics { } func ValidateNotEmptyString(i interface{}, path cty.Path) diag.Diagnostics { - s := i.(string) + s := strings.TrimSpace(i.(string)) if len(s) == 0 { return diag.Errorf("may not be empty") } @@ -69,3 +69,14 @@ func NewStringInValidator(allowedValues []string) schema.SchemaValidateDiagFunc return diag.Errorf("'%s' must be one of: %s", value, strings.Join(allowedValues, ", ")) } } + +func NewGreaterThanValidator(greaterThan int) schema.SchemaValidateDiagFunc { + return func(i interface{}, p cty.Path) diag.Diagnostics { + value := i.(int) + if value <= greaterThan { + return diag.Errorf("%d must be greater than %d", value, greaterThan) + } + + return nil + } +}