From 0052a784ad2853da57d09c384ab6cf27f595450a Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Tue, 2 Dec 2025 08:28:28 -0500 Subject: [PATCH] fix(provisioner): Ensure windsor down destroys terraform Terraform resources were not being destroyed due to lacking the terraform stack during "down" operations. Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- pkg/provisioner/provisioner.go | 41 +++++++++------ pkg/provisioner/provisioner_test.go | 79 ++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 16 deletions(-) diff --git a/pkg/provisioner/provisioner.go b/pkg/provisioner/provisioner.go index 04efd9137..86296820e 100644 --- a/pkg/provisioner/provisioner.go +++ b/pkg/provisioner/provisioner.go @@ -93,17 +93,11 @@ func (i *Provisioner) Up(blueprint *blueprintv1alpha1.Blueprint) error { return fmt.Errorf("blueprint not provided") } + if err := i.ensureTerraformStack(); err != nil { + return err + } if i.TerraformStack == nil { - if i.Runtime != nil && i.Runtime.ConfigHandler != nil { - terraformEnabled := i.Runtime.ConfigHandler.GetBool("terraform.enabled", false) - if terraformEnabled { - i.TerraformStack = terraforminfra.NewStack(i.Runtime) - } else { - return nil - } - } else { - return nil - } + return nil } if err := i.TerraformStack.Up(blueprint); err != nil { return fmt.Errorf("failed to run terraform up: %w", err) @@ -121,6 +115,9 @@ func (i *Provisioner) Down(blueprint *blueprintv1alpha1.Blueprint) error { return fmt.Errorf("blueprint not provided") } + if err := i.ensureTerraformStack(); err != nil { + return err + } if i.TerraformStack == nil { return nil } @@ -223,11 +220,9 @@ func (i *Provisioner) CheckNodeHealth(ctx context.Context, options NodeHealthChe if hasNodeCheck { if i.ClusterClient == nil { - if i.Runtime != nil && i.Runtime.ConfigHandler != nil { - clusterDriver := i.Runtime.ConfigHandler.GetString("cluster.driver", "") - if clusterDriver == "talos" || clusterDriver == "omni" { - i.ClusterClient = cluster.NewTalosClusterClient() - } + clusterDriver := i.Runtime.ConfigHandler.GetString("cluster.driver", "") + if clusterDriver == "talos" || clusterDriver == "omni" { + i.ClusterClient = cluster.NewTalosClusterClient() } } @@ -352,3 +347,19 @@ func (i *Provisioner) Close() { i.ClusterClient.Close() } } + +// ============================================================================= +// Private Methods +// ============================================================================= + +// ensureTerraformStack initializes the TerraformStack if terraform is enabled and the stack is not already initialized. +// Returns an error if initialization fails, or nil if terraform is disabled or already initialized. +func (i *Provisioner) ensureTerraformStack() error { + if i.TerraformStack != nil { + return nil + } + if i.Runtime.ConfigHandler.GetBool("terraform.enabled", false) { + i.TerraformStack = terraforminfra.NewStack(i.Runtime) + } + return nil +} diff --git a/pkg/provisioner/provisioner_test.go b/pkg/provisioner/provisioner_test.go index d65c0bb75..6205daa1a 100644 --- a/pkg/provisioner/provisioner_test.go +++ b/pkg/provisioner/provisioner_test.go @@ -332,6 +332,40 @@ func TestProvisioner_Up(t *testing.T) { if err != nil { t.Errorf("Expected no error when terraform is disabled, got: %v", err) } + + if provisioner.TerraformStack != nil { + t.Error("Expected TerraformStack to remain nil when terraform is disabled") + } + }) + + t.Run("SuccessInitializesTerraformStackLazily", func(t *testing.T) { + mocks := setupProvisionerMocks(t) + mockConfigHandler := mocks.ConfigHandler.(*config.MockConfigHandler) + mockConfigHandler.GetBoolFunc = func(key string, defaultValue ...bool) bool { + if key == "terraform.enabled" { + return true + } + if len(defaultValue) > 0 { + return defaultValue[0] + } + return false + } + provisioner := NewProvisioner(mocks.Runtime, mocks.BlueprintHandler) + + if provisioner.TerraformStack != nil { + t.Error("Expected TerraformStack to be nil before Up() is called") + } + + blueprint := createTestBlueprint() + err := provisioner.Up(blueprint) + + if provisioner.TerraformStack == nil { + t.Error("Expected TerraformStack to be initialized after Up() when terraform is enabled, even if operation fails") + } + + if err == nil { + t.Log("Up() succeeded (unexpected but not a test failure)") + } }) t.Run("ErrorTerraformStackUp", func(t *testing.T) { @@ -393,8 +427,17 @@ func TestProvisioner_Down(t *testing.T) { t.Run("SuccessSkipsTerraformWhenDisabled", func(t *testing.T) { mocks := setupProvisionerMocks(t) + mockConfigHandler := mocks.ConfigHandler.(*config.MockConfigHandler) + mockConfigHandler.GetBoolFunc = func(key string, defaultValue ...bool) bool { + if key == "terraform.enabled" { + return false + } + if len(defaultValue) > 0 { + return defaultValue[0] + } + return false + } provisioner := NewProvisioner(mocks.Runtime, mocks.BlueprintHandler) - provisioner.TerraformStack = nil blueprint := createTestBlueprint() err := provisioner.Down(blueprint) @@ -402,6 +445,40 @@ func TestProvisioner_Down(t *testing.T) { if err != nil { t.Errorf("Expected no error when terraform is disabled, got: %v", err) } + + if provisioner.TerraformStack != nil { + t.Error("Expected TerraformStack to remain nil when terraform is disabled") + } + }) + + t.Run("SuccessInitializesTerraformStackLazily", func(t *testing.T) { + mocks := setupProvisionerMocks(t) + mockConfigHandler := mocks.ConfigHandler.(*config.MockConfigHandler) + mockConfigHandler.GetBoolFunc = func(key string, defaultValue ...bool) bool { + if key == "terraform.enabled" { + return true + } + if len(defaultValue) > 0 { + return defaultValue[0] + } + return false + } + provisioner := NewProvisioner(mocks.Runtime, mocks.BlueprintHandler) + + if provisioner.TerraformStack != nil { + t.Error("Expected TerraformStack to be nil before Down() is called") + } + + blueprint := createTestBlueprint() + err := provisioner.Down(blueprint) + + if err != nil { + t.Errorf("Expected no error, got: %v", err) + } + + if provisioner.TerraformStack == nil { + t.Error("Expected TerraformStack to be initialized after Down() when terraform is enabled") + } }) t.Run("ErrorTerraformStackDown", func(t *testing.T) {