Skip to content
Merged
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
11 changes: 7 additions & 4 deletions pkg/clouds/pulumi/gcp/gke_autopilot_stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,13 @@ func GkeAutopilotStack(ctx *sdk.Context, stack api.Stack, input api.ResourceInpu
return nil, errors.Wrapf(err, "failed to unmarshal caddy config from parent stack: JSON was %q", caddyConfigJson)
}

// Attempt to patch caddy deployment annotations (non-critical - skip if it fails)
// Use deployment name override if specified, otherwise generate using single-dash convention
// to match the actual Caddy deployment naming (e.g., "caddy-staging" not "caddy--staging")
defaultDeploymentName := kubernetes.GenerateCaddyDeploymentName(input.StackParams.Environment)
// Attempt to patch caddy deployment annotations (non-critical - skip if it fails).
// Use deployment name override if specified, otherwise resolve via the parent-aware helper
// so sub-env client stacks (parentEnv != stackEnv) target the parent's caddy-<parentEnv>
// deployment instead of a non-existent caddy-<stackEnv>.
// input.StackParams.ParentEnv is reliably populated for this code path by the
// custom-stack fix-up at the top of this function.
defaultDeploymentName := kubernetes.CaddyDeploymentNameForChild(input.StackParams.Environment, input.StackParams.ParentEnv)
deploymentName := lo.If(caddyCfg.DeploymentName != nil, lo.FromPtr(caddyCfg.DeploymentName)).Else(defaultDeploymentName)
namespace := lo.If(caddyCfg.Namespace != nil, lo.FromPtr(caddyCfg.Namespace)).Else("caddy")

Expand Down
12 changes: 8 additions & 4 deletions pkg/clouds/pulumi/kubernetes/kube_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,14 @@ func KubeRun(ctx *sdk.Context, stack api.Stack, input api.ResourceInput, params
}

if caddyConfig != nil {
// Attempt to patch caddy deployment annotations (non-critical - skip if it fails)
// Use deployment name override if specified, otherwise generate using single-dash convention
// to match the actual Caddy deployment naming (e.g., "caddy-staging" not "caddy--staging")
defaultCaddyName := GenerateCaddyDeploymentName(input.StackParams.Environment)
// Attempt to patch caddy deployment annotations (non-critical - skip if it fails).
// Use deployment name override if specified, otherwise resolve via the parent-aware helper
// so sub-env client stacks (parentEnv != stackEnv) target the parent's caddy-<parentEnv>
// deployment instead of a non-existent caddy-<stackEnv>.
// parentEnv lives on params.ParentStack — input.StackParams.ParentEnv is empty for client
// stack deploys (matches the pattern in aws/compute_proc.go and gcp/compute_proc.go).
parentEnv := lo.FromPtr(params.ParentStack).ParentEnv
defaultCaddyName := CaddyDeploymentNameForChild(input.StackParams.Environment, parentEnv)
caddyServiceName := lo.If(caddyConfig.DeploymentName != nil, lo.FromPtr(caddyConfig.DeploymentName)).Else(defaultCaddyName)

// Cast params.Provider to Kubernetes provider for patch operations
Expand Down
18 changes: 18 additions & 0 deletions pkg/clouds/pulumi/kubernetes/naming.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,21 @@ func GenerateCaddyDeploymentName(stackEnv string) string {
}
return "caddy"
}

// CaddyDeploymentNameForChild returns the Caddy deployment name a *child* (client) stack
// must target when patching annotations to trigger a Caddy rolling restart.
//
// Caddy is provisioned by the parent infra stack, so its deployment name is keyed on
// parentEnv (e.g. caddy-production). For sub-env client stacks where parentEnv differs
// from stackEnv (e.g. parentEnv=production, stackEnv=gl-pay), passing stackEnv would
// produce caddy-gl-pay — which doesn't exist — and the patch would fail silently.
// For single-env stacks (parentEnv empty or equal to stackEnv) this falls back to stackEnv.
//
// Note: this is the call site asymmetric to GenerateCaddyDeploymentName, which is used
// from the parent stack's own provisioning where Environment is the correct input.
func CaddyDeploymentNameForChild(stackEnv, parentEnv string) string {
if isCustomStack(stackEnv, parentEnv) {
return GenerateCaddyDeploymentName(parentEnv)
}
return GenerateCaddyDeploymentName(stackEnv)
}
50 changes: 50 additions & 0 deletions pkg/clouds/pulumi/kubernetes/naming_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,56 @@ func TestNamespaceIsStackName(t *testing.T) {
}
}

func TestCaddyDeploymentNameForChild(t *testing.T) {
tests := []struct {
name string
stackEnv string
parentEnv string
expected string
}{
{
name: "single-env stack falls back to stackEnv",
stackEnv: "production",
parentEnv: "",
expected: "caddy-production",
},
{
name: "self-reference falls back to stackEnv",
stackEnv: "staging",
parentEnv: "staging",
expected: "caddy-staging",
},
{
name: "sub-env stack targets parent's caddy",
stackEnv: "gl-pay",
parentEnv: "production",
expected: "caddy-production",
},
{
name: "preview env targets parent staging caddy",
stackEnv: "staging-preview",
parentEnv: "staging",
expected: "caddy-staging",
},
{
name: "empty stackEnv with parentEnv still resolves to parent",
stackEnv: "",
parentEnv: "production",
expected: "caddy-production",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := CaddyDeploymentNameForChild(tt.stackEnv, tt.parentEnv)
if result != tt.expected {
t.Errorf("CaddyDeploymentNameForChild(%q, %q) = %v, expected %v",
tt.stackEnv, tt.parentEnv, result, tt.expected)
}
})
}
}

func TestIsCustomStack(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading