From 6e47833c5ca90ee402bd02eca50b59ecd2056c9f Mon Sep 17 00:00:00 2001 From: Tomer Heber Date: Wed, 25 Oct 2023 07:29:58 -0500 Subject: [PATCH 1/2] Feat: add support to Drift Detection on env0_project_policy (#727) --- client/project_policy.go | 4 ++++ env0/provider.go | 2 +- env0/resource_project_policy.go | 34 ++++++++++++++++++---------- env0/resource_project_policy_test.go | 9 +++++++- tests/integration/011_policy/main.tf | 1 + 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/client/project_policy.go b/client/project_policy.go index 31878b83..59bd74f9 100644 --- a/client/project_policy.go +++ b/client/project_policy.go @@ -16,6 +16,8 @@ type Policy struct { MaxTtl *string `json:"maxTtl,omitempty" tfschema:",omitempty"` DefaultTtl *string `json:"defaultTtl,omitempty" tfschema:",omitempty"` ForceRemoteBackend bool `json:"forceRemoteBackend"` + DriftDetectionCron string `json:"driftDetectionCron"` + DriftDetectionEnabled bool `json:"driftDetectionEnabled"` } type PolicyUpdatePayload struct { @@ -32,6 +34,8 @@ type PolicyUpdatePayload struct { MaxTtl string `json:"maxTtl,omitempty"` DefaultTtl string `json:"defaultTtl,omitempty"` ForceRemoteBackend bool `json:"forceRemoteBackend"` + DriftDetectionCron string `json:"driftDetectionCron"` + DriftDetectionEnabled bool `json:"driftDetectionEnabled"` } // Policy retrieves a policy from the API diff --git a/env0/provider.go b/env0/provider.go index 25ffc032..96a2b50c 100644 --- a/env0/provider.go +++ b/env0/provider.go @@ -94,7 +94,7 @@ func Provider(version string) plugin.ProviderFunc { }, ResourcesMap: map[string]*schema.Resource{ "env0_project": resourceProject(), - "env0_project_policy": resourcePolicy(), + "env0_project_policy": resourceProjectPolicy(), "env0_configuration_variable": resourceConfigurationVariable(), "env0_template": resourceTemplate(), "env0_ssh_key": resourceSshKey(), diff --git a/env0/resource_project_policy.go b/env0/resource_project_policy.go index 27b42dc7..cfd9f838 100644 --- a/env0/resource_project_policy.go +++ b/env0/resource_project_policy.go @@ -10,14 +10,14 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) -func resourcePolicy() *schema.Resource { +func resourceProjectPolicy() *schema.Resource { return &schema.Resource{ - CreateContext: resourcePolicyCreate, - ReadContext: resourcePolicyRead, - UpdateContext: resourcePolicyUpdate, - DeleteContext: resourcePolicyDelete, + CreateContext: resourceProjectPolicyCreate, + ReadContext: resourceProjectPolicyRead, + UpdateContext: resourceProjectPolicyUpdate, + DeleteContext: resourceProjectPolicyDelete, - Importer: &schema.ResourceImporter{StateContext: resourcePolicyImport}, + Importer: &schema.ResourceImporter{StateContext: resourceProjectPolicyImport}, Schema: map[string]*schema.Schema{ "id": { @@ -105,12 +105,18 @@ func resourcePolicy() *schema.Resource { Optional: true, Default: false, }, + "drift_detection_cron": { + Type: schema.TypeString, + Description: "default cron expression for new environments", + Optional: true, + ValidateDiagFunc: ValidateCronExpression, + }, }, } } -func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - if err := resourcePolicyUpdate(ctx, d, meta); err != nil { +func resourceProjectPolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + if err := resourceProjectPolicyUpdate(ctx, d, meta); err != nil { return err } @@ -120,7 +126,7 @@ func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, meta inte return nil } -func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceProjectPolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) projectId := d.Id() @@ -139,7 +145,7 @@ func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interf return nil } -func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceProjectPolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) payload := client.PolicyUpdatePayload{} @@ -165,6 +171,10 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta inte payload.MaxTtl = "" } + if payload.DriftDetectionCron != "" { + payload.DriftDetectionEnabled = true + } + if _, err := apiClient.PolicyUpdate(payload); err != nil { return diag.Errorf("could not update policy: %v", err) } @@ -172,7 +182,7 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta inte return nil } -func resourcePolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourceProjectPolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { apiClient := meta.(client.ApiClientInterface) projectId := d.Id() @@ -195,7 +205,7 @@ func resourcePolicyDelete(ctx context.Context, d *schema.ResourceData, meta inte return nil } -func resourcePolicyImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { +func resourceProjectPolicyImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { projectId := d.Id() policy, err := getPolicyByProjectId(projectId, meta) diff --git a/env0/resource_project_policy_test.go b/env0/resource_project_policy_test.go index 4aeaad88..c15262c9 100644 --- a/env0/resource_project_policy_test.go +++ b/env0/resource_project_policy_test.go @@ -10,7 +10,7 @@ import ( "go.uber.org/mock/gomock" ) -func TestUnitPolicyResource(t *testing.T) { +func TestUnitProjectPolicyResource(t *testing.T) { resourceType := "env0_project_policy" resourceName := "test" accessor := resourceAccessor(resourceType, resourceName) @@ -28,6 +28,8 @@ func TestUnitPolicyResource(t *testing.T) { MaxTtl: stringPtr("inherit"), DefaultTtl: stringPtr("inherit"), ForceRemoteBackend: true, + DriftDetectionCron: "0 4 * * *", + DriftDetectionEnabled: true, } updatedPolicy := client.Policy{ @@ -67,6 +69,7 @@ func TestUnitPolicyResource(t *testing.T) { "run_pull_request_plan_default": policy.RunPullRequestPlanDefault, "continuous_deployment_default": policy.ContinuousDeploymentDefault, "force_remote_backend": policy.ForceRemoteBackend, + "drift_detection_cron": policy.DriftDetectionCron, }), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(accessor, "project_id", policy.ProjectId), @@ -82,6 +85,7 @@ func TestUnitPolicyResource(t *testing.T) { resource.TestCheckResourceAttr(accessor, "max_ttl", "inherit"), resource.TestCheckResourceAttr(accessor, "default_ttl", "inherit"), resource.TestCheckResourceAttr(accessor, "force_remote_backend", strconv.FormatBool(policy.ForceRemoteBackend)), + resource.TestCheckResourceAttr(accessor, "drift_detection_cron", policy.DriftDetectionCron), ), }, { @@ -107,6 +111,7 @@ func TestUnitPolicyResource(t *testing.T) { resource.TestCheckResourceAttr(accessor, "max_ttl", "Infinite"), resource.TestCheckResourceAttr(accessor, "default_ttl", *updatedPolicy.DefaultTtl), resource.TestCheckResourceAttr(accessor, "force_remote_backend", strconv.FormatBool(updatedPolicy.ForceRemoteBackend)), + resource.TestCheckResourceAttr(accessor, "drift_detection_cron", updatedPolicy.DriftDetectionCron), ), }, }, @@ -127,6 +132,8 @@ func TestUnitPolicyResource(t *testing.T) { MaxTtl: "inherit", DefaultTtl: "inherit", ForceRemoteBackend: true, + DriftDetectionEnabled: true, + DriftDetectionCron: policy.DriftDetectionCron, }).Times(1).Return(policy, nil), mock.EXPECT().Policy(gomock.Any()).Times(2).Return(policy, nil), // 1 after create, 1 before update // Update diff --git a/tests/integration/011_policy/main.tf b/tests/integration/011_policy/main.tf index a5e1d730..ea478b18 100644 --- a/tests/integration/011_policy/main.tf +++ b/tests/integration/011_policy/main.tf @@ -17,6 +17,7 @@ resource "env0_project_policy" "test_policy" { skip_apply_when_plan_is_empty = false disable_destroy_environments = false skip_redundant_deployments = false + drift_detection_cron = var.second_run ? "0 4 * * *" : "0 3 * * *" } resource "env0_project_policy" "test_policy_2" { From bb5f991a38e7e6d3ba0a4d5a50a709241eacf438 Mon Sep 17 00:00:00 2001 From: update generated docs action Date: Wed, 25 Oct 2023 12:30:30 +0000 Subject: [PATCH 2/2] Update docs --- docs/resources/project_policy.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/resources/project_policy.md b/docs/resources/project_policy.md index bbfdaabd..c6ef7850 100644 --- a/docs/resources/project_policy.md +++ b/docs/resources/project_policy.md @@ -41,6 +41,7 @@ resource "env0_project_policy" "example" { - `continuous_deployment_default` (Boolean) Redeploy on every push to the git branch default value - `default_ttl` (String) the default environment time-to-live allowed on deploy time. Format is - (Examples: 12-h, 3-d, 1-w, 1-M). Default value is 'inherit' which inherits the organization policy. must be equal or shorter than max_ttl - `disable_destroy_environments` (Boolean) Disallow destroying environment in the project +- `drift_detection_cron` (String) default cron expression for new environments - `force_remote_backend` (Boolean) if 'true' all environments created in this project will be forced to use env0 remote backend. Default is 'false' - `include_cost_estimation` (Boolean) Enable cost estimation for the project - `max_ttl` (String) the maximum environment time-to-live allowed on deploy time. Format is - (Examples: 12-h, 3-d, 1-w, 1-M). Default value is 'inherit' which inherits the organization policy. must be equal or longer than default_ttl