Skip to content

Commit fb57e8b

Browse files
committed
fix (app): prevent spurious forced replacements
Prevents cascading replacement due to irrelevant change on a dependency
1 parent 76825c8 commit fb57e8b

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

cloudfoundry/provider/resource_app.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,23 @@ func (r *appResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
7575
Required: true,
7676
PlanModifiers: []planmodifier.String{
7777
stringplanmodifier.RequiresReplace(),
78+
stringplanmodifier.UseStateForUnknown(),
7879
},
7980
},
8081
"space_name": schema.StringAttribute{
8182
MarkdownDescription: "The name of the associated Cloud Foundry space.",
8283
Required: true,
8384
PlanModifiers: []planmodifier.String{
8485
stringplanmodifier.RequiresReplace(),
86+
stringplanmodifier.UseStateForUnknown(),
8587
},
8688
},
8789
"org_name": schema.StringAttribute{
8890
MarkdownDescription: "The name of the associated Cloud Foundry organization.",
8991
Required: true,
9092
PlanModifiers: []planmodifier.String{
9193
stringplanmodifier.RequiresReplace(),
94+
stringplanmodifier.UseStateForUnknown(),
9295
},
9396
},
9497
"enable_ssh": schema.BoolAttribute{

cloudfoundry/provider/resource_app_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package provider
22

33
import (
4+
"fmt"
45
"testing"
56

67
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-testing/terraform"
79
)
810

911
func TestAppResource_Configure(t *testing.T) {
@@ -290,4 +292,90 @@ resource "cloudfoundry_app" "app" {
290292
},
291293
})
292294
})
295+
// This test verifies that updating a space's allow_ssh attribute does not cause
296+
// apps in that space to be replaced. This is a regression test for an issue where
297+
// changing a referenced resource caused the app's space_name attribute to appear
298+
// as "known after apply", triggering unwanted replacement. The app's space_name
299+
// references cloudfoundry_space.test.name so that when the space is updated, the
300+
// name flows through as "known after apply" during planning. The UseStateForUnknown
301+
// plan modifier prevents this from triggering a replacement.
302+
t.Run("happy path - app not replaced when space allow_ssh changes", func(t *testing.T) {
303+
resourceName := "cloudfoundry_app.app_stability"
304+
cfg := getCFHomeConf()
305+
rec := cfg.SetupVCR(t, "fixtures/resource_app_space_allow_ssh_update")
306+
defer stopQuietly(rec)
307+
308+
var appID string
309+
310+
resource.Test(t, resource.TestCase{
311+
IsUnitTest: true,
312+
ProtoV6ProviderFactories: getProviders(rec.GetDefaultClient()),
313+
Steps: []resource.TestStep{
314+
{
315+
// Step 1: Create a space with allow_ssh=false and a docker app
316+
// that references cloudfoundry_space.test.name for space_name
317+
Config: hclProvider(nil) + `
318+
resource "cloudfoundry_space" "test" {
319+
name = "tf-space-1"
320+
org = "` + testOrgGUID + `"
321+
allow_ssh = false
322+
}
323+
resource "cloudfoundry_app" "app_stability" {
324+
name = "stability-test-app"
325+
space_name = cloudfoundry_space.test.name
326+
org_name = "PerformanceTeamBLR"
327+
docker_image = "kennethreitz/httpbin"
328+
no_route = true
329+
}
330+
`,
331+
Check: resource.ComposeTestCheckFunc(
332+
resource.TestMatchResourceAttr(resourceName, "id", regexpValidUUID),
333+
resource.TestCheckResourceAttr(resourceName, "name", "stability-test-app"),
334+
resource.TestCheckResourceAttr(resourceName, "space_name", "tf-space-1"),
335+
func(s *terraform.State) error {
336+
rs, ok := s.RootModule().Resources[resourceName]
337+
if !ok {
338+
return fmt.Errorf("resource not found: %s", resourceName)
339+
}
340+
appID = rs.Primary.ID
341+
return nil
342+
},
343+
),
344+
},
345+
{
346+
// Step 2: Change allow_ssh on the space. This causes the space
347+
// resource to be updated, making cloudfoundry_space.test.name
348+
// appear as "known after apply" during planning. Without
349+
// UseStateForUnknown on the app's space_name attribute,
350+
// this would trigger a replacement.
351+
Config: hclProvider(nil) + `
352+
resource "cloudfoundry_space" "test" {
353+
name = "tf-space-1"
354+
org = "` + testOrgGUID + `"
355+
allow_ssh = true
356+
}
357+
resource "cloudfoundry_app" "app_stability" {
358+
name = "stability-test-app"
359+
space_name = cloudfoundry_space.test.name
360+
org_name = "PerformanceTeamBLR"
361+
docker_image = "kennethreitz/httpbin"
362+
no_route = true
363+
}
364+
`,
365+
Check: resource.ComposeTestCheckFunc(
366+
func(s *terraform.State) error {
367+
rs, ok := s.RootModule().Resources[resourceName]
368+
if !ok {
369+
return fmt.Errorf("resource not found: %s", resourceName)
370+
}
371+
if rs.Primary.ID != appID {
372+
return fmt.Errorf("app was unexpectedly replaced: old ID %s, new ID %s", appID, rs.Primary.ID)
373+
}
374+
return nil
375+
},
376+
),
377+
},
378+
},
379+
})
380+
})
293381
}

0 commit comments

Comments
 (0)