Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions pkg/clouds/pulumi/destroy_child_stack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
// Copyright (c) Simple Container

package pulumi

import (
"testing"

"github.com/pulumi/pulumi/pkg/v3/backend"
)

// selectStack returns (nil, nil) when a stack's checkpoint blob does not exist
// (see stackCheckpointNotFound). DestroyChildStack must treat that nil stack as
// "nothing to destroy" and skip the s.Ref() dereference; otherwise it panics
// with a nil-pointer dereference on a never-deployed child stack.
func TestDestroyChildStack_NilStackIsNoDeref(t *testing.T) {
var s backend.Stack // nil, as returned by selectStack for a missing stack

// The guard DestroyChildStack uses.
if s != nil {
t.Fatalf("expected nil stack from a missing checkpoint, got %v", s)
}

// Guard against a regression that removes the nil check: reaching s.Ref()
// on a nil stack is exactly the reported panic.
defer func() {
if r := recover(); r == nil {
t.Fatal("expected dereferencing a nil backend.Stack to panic; the nil guard in DestroyChildStack is what prevents it")
}
}()
_ = s.Ref()
}
4 changes: 4 additions & 0 deletions pkg/clouds/pulumi/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func (p *pulumi) DestroyChildStack(ctx context.Context, cfg *api.ConfigFile, par
if err != nil {
return errors.Wrapf(err, "failed to get child stack %q", childStack.Name)
}
if s == nil {
p.logger.Info(ctx, "child stack %q not found; nothing to destroy", childStack.Name)
return nil
}
program := p.deployStackProgram(childStack, params.StackParams, parentStack.Name, s.Ref().FullyQualifiedName().String())
return p.destroyStack(ctx, cfg, s, params, program, preview, func(stackSource auto.Stack) {
for _, hook := range pApi.PreDestroyHookFuncs {
Expand Down