diff --git a/ghost/resource_ghost_app.go b/ghost/resource_ghost_app.go index fc37d4c..2d1205c 100644 --- a/ghost/resource_ghost_app.go +++ b/ghost/resource_ghost_app.go @@ -71,7 +71,7 @@ func resourceGhostApp() *schema.Resource { Type: schema.TypeList, Optional: true, MaxItems: 1, - DiffSuppressFunc: SuppressDiffEmptyStruct(), + DiffSuppressFunc: SuppressDiffAutoscale(), Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { @@ -150,7 +150,7 @@ func resourceGhostApp() *schema.Resource { Type: schema.TypeList, Optional: true, MaxItems: 1, - DiffSuppressFunc: SuppressDiffEmptyStruct(), + DiffSuppressFunc: SuppressDiffRootBlockDevice(), Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "size": { @@ -333,7 +333,7 @@ func resourceGhostApp() *schema.Resource { Type: schema.TypeList, Optional: true, MaxItems: 1, - DiffSuppressFunc: SuppressDiffEmptyStruct(), + DiffSuppressFunc: SuppressDiffLifecycleHooks(), Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "pre_buildimage": { @@ -418,7 +418,7 @@ func resourceGhostApp() *schema.Resource { Type: schema.TypeList, Optional: true, MaxItems: 1, - DiffSuppressFunc: SuppressDiffEmptyStruct(), + DiffSuppressFunc: SuppressDiffSafeDeployment(), Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "ha_backend": { @@ -1075,60 +1075,83 @@ func flattenGhostAppSafeDeployment(safeDeployment *ghost.SafeDeployment) []inter return values } -// Check that the struct is empty meaning there's no change -func hasNoChange(k string, d *schema.ResourceData) bool { - if d == nil { +// Check that the struct is empty meaning that there's no change +func hasNoChangeAutoscale(k string, d *schema.ResourceData) bool { + val, ok := d.GetOk("autoscale") + if !ok { return true } + autoscale := expandGhostAppAutoscale(val.([]interface{})) + return autoscale == nil || (autoscale.EnableMetrics && + autoscale.Max == 0 && autoscale.Min == 0 && autoscale.Name == "") +} +func hasNoChangeLifecycleHooks(k string, d *schema.ResourceData) bool { + val, ok := d.GetOk("lifecycle_hooks") + if !ok { + return true + } + lifecycle_hooks := expandGhostAppLifecycleHooks(val.([]interface{})) + return lifecycle_hooks == nil || (lifecycle_hooks.PostBootstrap == "" && + lifecycle_hooks.PostBuildimage == "" && lifecycle_hooks.PreBootstrap == "" && + lifecycle_hooks.PreBuildimage == "") +} +func hasNoChangeRootBlockDevice(k string, d *schema.ResourceData) bool { + val, ok := d.GetOk("environment_infos") + if !ok { + return true + } + environment_infos := expandGhostAppEnvironmentInfos(val.([]interface{})) + return environment_infos.RootBlockDevice == nil || + (environment_infos.RootBlockDevice.Name == "" && + environment_infos.RootBlockDevice.Size == 0) +} - switch k { - case "autoscale.#": - val, ok := d.GetOk("autoscale") - if !ok { - return true - } - autoscale := expandGhostAppAutoscale(val.([]interface{})) - return autoscale == nil || (autoscale.EnableMetrics && - autoscale.Max == 0 && autoscale.Min == 0 && autoscale.Name == "") - case "lifecycle_hooks.#": - val, ok := d.GetOk("lifecycle_hooks") - if !ok { - return true - } - lifecycle_hooks := expandGhostAppLifecycleHooks(val.([]interface{})) - return lifecycle_hooks == nil || (lifecycle_hooks.PostBootstrap == "" && - lifecycle_hooks.PostBuildimage == "" && lifecycle_hooks.PreBootstrap == "" && - lifecycle_hooks.PreBuildimage == "") - case "environment_infos.0.root_block_device.#": - val, ok := d.GetOk("environment_infos") - if !ok { - return true +func hasNoChangeSafeDeployment(k string, d *schema.ResourceData) bool { + val, ok := d.GetOk("safe_deployment") + if !ok { + return true + } + safe_deployment := expandGhostAppSafeDeployment(val.([]interface{})) + return safe_deployment == nil || (safe_deployment.ApiPort == 0 && + safe_deployment.AppTagValue == "" && safe_deployment.HaBackend == "" && + safe_deployment.LoadBalancerType == "" && safe_deployment.WaitAfterDeploy == 0 && + safe_deployment.WaitBeforeDeploy == 0) + return false +} + +// Remove plan diffs due to empty struct created by ghost +func SuppressDiffAutoscale() schema.SchemaDiffSuppressFunc { + return func(k, old, new string, d *schema.ResourceData) bool { + if k != "autoscale.#" { + return false } - environment_infos := expandGhostAppEnvironmentInfos(val.([]interface{})) - return environment_infos.RootBlockDevice == nil || - (environment_infos.RootBlockDevice.Name == "" && - environment_infos.RootBlockDevice.Size == 0) - case "safe_deployment.#": - val, ok := d.GetOk("safe_deployment") - if !ok { - return true + return old == "1" && new == "0" && hasNoChangeAutoscale(k, d) + } +} + +func SuppressDiffRootBlockDevice() schema.SchemaDiffSuppressFunc { + return func(k, old, new string, d *schema.ResourceData) bool { + if k != "environment_infos.0.root_block_device.#" { + return false } - safe_deployment := expandGhostAppSafeDeployment(val.([]interface{})) - return safe_deployment == nil || (safe_deployment.ApiPort == 0 && - safe_deployment.AppTagValue == "" && safe_deployment.HaBackend == "" && - safe_deployment.LoadBalancerType == "" && safe_deployment.WaitAfterDeploy == 0 && - safe_deployment.WaitBeforeDeploy == 0) - default: - return false + return old == "1" && new == "0" && hasNoChangeRootBlockDevice(k, d) } } -// Remove plan diffs due to empty struct created by ghost -func SuppressDiffEmptyStruct() schema.SchemaDiffSuppressFunc { +func SuppressDiffLifecycleHooks() schema.SchemaDiffSuppressFunc { return func(k, old, new string, d *schema.ResourceData) bool { - list := []string{"autoscale.#", "lifecycle_hooks.#", "safe_deployment.#", - "environment_infos.0.root_block_device.#"} + if k != "lifecycle_hooks.#" { + return false + } + return old == "1" && new == "0" && hasNoChangeLifecycleHooks(k, d) + } +} - return IsInList(k, list) && hasNoChange(k, d) && old == "1" && new == "0" +func SuppressDiffSafeDeployment() schema.SchemaDiffSuppressFunc { + return func(k, old, new string, d *schema.ResourceData) bool { + if k != "safe_deployment.#" { + return false + } + return old == "1" && new == "0" && hasNoChangeSafeDeployment(k, d) } } diff --git a/ghost/resource_ghost_app_test.go b/ghost/resource_ghost_app_test.go index c601024..53a91a2 100644 --- a/ghost/resource_ghost_app_test.go +++ b/ghost/resource_ghost_app_test.go @@ -1323,8 +1323,38 @@ func TestSuppressDiffFeatureParameters(t *testing.T) { } } -func TestSuppressDiffEmptyStruct(t *testing.T) { - suppressDiffEmptyStruct := SuppressDiffEmptyStruct() +func TestSuppressDiffRootBlockDevice(t *testing.T) { + suppressDiffRootBlockDevice := SuppressDiffRootBlockDevice() + + resource := resourceGhostApp() + nonEmptyResourceData := resource.Data(&terraform.InstanceState{ + ID: "ghost_app.test.id", + }) + flattenGhostApp(nonEmptyResourceData, app) + + cases := []struct { + ParameterName string + OldValue string + NewValue string + ExpectedOutput bool + ResourceData *schema.ResourceData + }{ + {"environment_infos.0.root_block_device.#", "1", "0", true, &schema.ResourceData{}}, + {"environment_infos.0.root_block_device.#", "1", "0", false, nonEmptyResourceData}, + {"environment_infos.0.root_block_device.0.name", "1", "0", false, &schema.ResourceData{}}, + } + + for _, tc := range cases { + output := suppressDiffRootBlockDevice(tc.ParameterName, tc.OldValue, tc.NewValue, tc.ResourceData) + if !reflect.DeepEqual(output, tc.ExpectedOutput) { + t.Fatalf("Unexpected output from SuppressDiffRootBlockDevice.\nExpected: %#v\nGiven: %#v", + tc.ExpectedOutput, output) + } + } +} + +func TestSuppressDiffAutoscale(t *testing.T) { + suppressDiffAutoscale := SuppressDiffAutoscale() resource := resourceGhostApp() nonEmptyResourceData := resource.Data(&terraform.InstanceState{ @@ -1343,18 +1373,72 @@ func TestSuppressDiffEmptyStruct(t *testing.T) { {"autoscale.#", "1", "0", false, nonEmptyResourceData}, {"autoscale.#", "0", "1", false, &schema.ResourceData{}}, {"autoscale.0.min", "1", "0", false, &schema.ResourceData{}}, + } + + for _, tc := range cases { + output := suppressDiffAutoscale(tc.ParameterName, tc.OldValue, tc.NewValue, tc.ResourceData) + if !reflect.DeepEqual(output, tc.ExpectedOutput) { + t.Fatalf("Unexpected output from SuppressDiffAutoscale.\nExpected: %#v\nGiven: %#v", + tc.ExpectedOutput, output) + } + } +} + +func TestSuppressDiffLifecycleHooks(t *testing.T) { + suppressDiffLifecycleHooks := SuppressDiffLifecycleHooks() + + resource := resourceGhostApp() + nonEmptyResourceData := resource.Data(&terraform.InstanceState{ + ID: "ghost_app.test.id", + }) + flattenGhostApp(nonEmptyResourceData, app) + + cases := []struct { + ParameterName string + OldValue string + NewValue string + ExpectedOutput bool + ResourceData *schema.ResourceData + }{ {"lifecycle_hooks.#", "1", "0", true, &schema.ResourceData{}}, {"lifecycle_hooks.#", "1", "0", false, nonEmptyResourceData}, - {"environment_infos.0.root_block_device.#", "1", "0", true, &schema.ResourceData{}}, - {"environment_infos.0.root_block_device.#", "1", "0", false, nonEmptyResourceData}, + {"lifecycle_hooks.0.pre_buildimage", "1", "0", false, &schema.ResourceData{}}, + } + + for _, tc := range cases { + output := suppressDiffLifecycleHooks(tc.ParameterName, tc.OldValue, tc.NewValue, tc.ResourceData) + if !reflect.DeepEqual(output, tc.ExpectedOutput) { + t.Fatalf("Unexpected output from SuppressDiffLifecycleHooks.\nExpected: %#v\nGiven: %#v", + tc.ExpectedOutput, output) + } + } +} + +func TestSuppressDiffSafeDeployment(t *testing.T) { + suppressDiffSafeDeployment := SuppressDiffSafeDeployment() + + resource := resourceGhostApp() + nonEmptyResourceData := resource.Data(&terraform.InstanceState{ + ID: "ghost_app.test.id", + }) + flattenGhostApp(nonEmptyResourceData, app) + + cases := []struct { + ParameterName string + OldValue string + NewValue string + ExpectedOutput bool + ResourceData *schema.ResourceData + }{ {"safe_deployment.#", "1", "0", true, &schema.ResourceData{}}, {"safe_deployment.#", "1", "0", false, nonEmptyResourceData}, + {"safe_deployment.0.wait_before_deploy", "1", "0", false, &schema.ResourceData{}}, } for _, tc := range cases { - output := suppressDiffEmptyStruct(tc.ParameterName, tc.OldValue, tc.NewValue, tc.ResourceData) + output := suppressDiffSafeDeployment(tc.ParameterName, tc.OldValue, tc.NewValue, tc.ResourceData) if !reflect.DeepEqual(output, tc.ExpectedOutput) { - t.Fatalf("Unexpected output from SuppressDiffEmptyStruct.\nExpected: %#v\nGiven: %#v", + t.Fatalf("Unexpected output from SuppressDiffSafeDeployment.\nExpected: %#v\nGiven: %#v", tc.ExpectedOutput, output) } }