Skip to content

Commit 1bc7d22

Browse files
authored
stacks: removed blocks should refresh during refresh plans (#36916)
* stacks: removed blocks should refresh during refresh plans * fix copywrite headers * clarify return values of DefinedByStackInstance
1 parent 96e50f6 commit 1bc7d22

File tree

5 files changed

+402
-44
lines changed

5 files changed

+402
-44
lines changed

internal/stacks/stackruntime/internal/stackeval/input_variable.go

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,43 +45,59 @@ func newInputVariable(main *Main, addr stackaddrs.AbsInputVariable, stack *Stack
4545
}
4646

4747
// DefinedByStackCallInstance returns the stack call which ought to provide
48-
// the definition (i.e. the final value) of this input variable.
48+
// the definition (i.e. the final value) of this input variable. The source
49+
// of the stack could either be a regular stack call instance or a removed
50+
// stack call instance. One of the two will be returned. They are mutually
51+
// exclusive as it is an error for two blocks to create the same stack instance.
4952
//
5053
// Returns nil if this input variable belongs to the main stack, because
5154
// the main stack's input variables come from the planning options instead.
52-
// Also returns nil if the reciever belongs to a stack config instance
55+
//
56+
// Also returns nil if the receiver belongs to a stack config instance
5357
// that isn't actually declared in the configuration, which typically suggests
5458
// that we don't yet know the number of instances of one of the stack calls
5559
// along the chain.
56-
func (v *InputVariable) DefinedByStackCallInstance(ctx context.Context, phase EvalPhase) *StackCallInstance {
60+
func (v *InputVariable) DefinedByStackCallInstance(ctx context.Context, phase EvalPhase) (*StackCallInstance, *RemovedStackCallInstance) {
5761
declarerAddr := v.addr.Stack
5862
if declarerAddr.IsRoot() {
59-
return nil
63+
return nil, nil
6064
}
6165

6266
callAddr := declarerAddr.Call()
63-
callerCalls := v.stack.parent.EmbeddedStackCalls()
64-
call := callerCalls[callAddr.Item]
65-
if call == nil {
66-
// Suggests that we're descended from a stack call that doesn't
67-
// actually exist, which is odd but we'll tolerate it.
68-
return nil
69-
}
7067

71-
lastStep := declarerAddr[len(declarerAddr)-1]
72-
instKey := lastStep.Key
68+
if call := v.stack.parent.EmbeddedStackCall(callAddr.Item); call != nil {
69+
lastStep := declarerAddr[len(declarerAddr)-1]
70+
instKey := lastStep.Key
71+
72+
callInsts, unknown := call.Instances(ctx, phase)
73+
if unknown {
74+
// Return our static unknown instance for this variable.
75+
return call.UnknownInstance(ctx, instKey, phase), nil
76+
}
77+
if inst, ok := callInsts[instKey]; ok {
78+
return inst, nil
79+
}
7380

74-
callInsts, unknown := call.Instances(ctx, phase)
75-
if unknown {
76-
// Return our static unknown instance for this variable.
77-
return call.UnknownInstance(ctx, instKey, phase)
81+
// otherwise, let's check if we have any removed calls that match the
82+
// target instance
7883
}
79-
if callInsts == nil {
80-
// Could get here if the call's for_each is invalid.
81-
return nil
84+
85+
if calls := v.stack.parent.RemovedEmbeddedStackCall(callAddr.Item); calls != nil {
86+
for _, call := range calls {
87+
callInsts, unknown := call.InstancesFor(ctx, v.stack.addr, phase)
88+
if unknown {
89+
return nil, call.UnknownInstance(ctx, v.stack.addr, phase)
90+
}
91+
for _, inst := range callInsts {
92+
// because we used the exact v.stack.addr in InstancesFor above
93+
// then we should have at most one entry here if there were any
94+
// matches.
95+
return nil, inst
96+
}
97+
}
8298
}
8399

84-
return callInsts[instKey]
100+
return nil, nil
85101
}
86102

87103
func (v *InputVariable) Value(ctx context.Context, phase EvalPhase) cty.Value {
@@ -175,23 +191,32 @@ func (v *InputVariable) CheckValue(ctx context.Context, phase EvalPhase) (cty.Va
175191
return cfg.markValue(val), diags
176192

177193
default:
178-
definedByCallInst := v.DefinedByStackCallInstance(ctx, phase)
179-
if definedByCallInst == nil {
194+
definedByCallInst, definedByRemovedCallInst := v.DefinedByStackCallInstance(ctx, phase)
195+
switch {
196+
case definedByCallInst != nil:
197+
allVals := definedByCallInst.InputVariableValues(ctx, phase)
198+
val := allVals.GetAttr(v.addr.Item.Name)
199+
200+
// TODO: check the value against any custom validation rules
201+
// declared in the configuration.
202+
203+
return cfg.markValue(val), diags
204+
case definedByRemovedCallInst != nil:
205+
allVals, _ := definedByRemovedCallInst.InputVariableValues(ctx, phase)
206+
val := allVals.GetAttr(v.addr.Item.Name)
207+
208+
// TODO: check the value against any custom validation rules
209+
// declared in the configuration.
210+
211+
return cfg.markValue(val), diags
212+
default:
180213
// We seem to belong to a call instance that doesn't actually
181214
// exist in the configuration. That either means that
182215
// something's gone wrong or we are descended from a stack
183216
// call whose instances aren't known yet; we'll assume
184217
// the latter and return a placeholder.
185218
return cfg.markValue(cty.UnknownVal(v.config.config.Type.Constraint)), diags
186219
}
187-
188-
allVals := definedByCallInst.InputVariableValues(ctx, phase)
189-
val := allVals.GetAttr(v.addr.Item.Name)
190-
191-
// TODO: check the value against any custom validation rules
192-
// declared in the configuration.
193-
194-
return cfg.markValue(val), diags
195220
}
196221
},
197222
)

internal/stacks/stackruntime/internal/stackeval/main.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -310,13 +310,7 @@ func (m *Main) MainStack() *Stack {
310310
defer m.mu.Unlock()
311311

312312
if m.mainStack == nil {
313-
314-
mode := plans.NormalMode
315-
if m.Planning() {
316-
mode = m.PlanningOpts().PlanningMode
317-
}
318-
319-
m.mainStack = newStack(m, stackaddrs.RootStackInstance, nil, config, newRemoved(), mode, false)
313+
m.mainStack = newStack(m, stackaddrs.RootStackInstance, nil, config, newRemoved(), m.PlanningMode(), false)
320314
}
321315
return m.mainStack
322316
}
@@ -621,6 +615,16 @@ func (m *Main) PlanTimestamp() time.Time {
621615
return time.Now().UTC()
622616
}
623617

618+
func (m *Main) PlanningMode() plans.Mode {
619+
if m.applying != nil {
620+
return m.applying.plan.Mode
621+
}
622+
if m.planning != nil {
623+
return m.planning.opts.PlanningMode
624+
}
625+
return plans.NormalMode
626+
}
627+
624628
// DependencyLocks returns the dependency locks for the given phase.
625629
func (m *Main) DependencyLocks(phase EvalPhase) *depsfile.Locks {
626630
switch phase {

internal/stacks/stackruntime/internal/stackeval/removed_component_instance.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,15 @@ func (r *RemovedComponentInstance) ModuleTreePlan(ctx context.Context) (*plans.P
121121
}
122122
}
123123

124+
mode := plans.DestroyMode
125+
if r.main.PlanningOpts().PlanningMode == plans.RefreshOnlyMode {
126+
mode = plans.RefreshOnlyMode
127+
}
128+
124129
plantimestamp := r.main.PlanTimestamp()
125130
forget := !r.call.config.config.Destroy
126131
opts := &terraform.PlanOpts{
127-
Mode: plans.DestroyMode,
132+
Mode: mode,
128133
SetVariables: r.PlanPrevInputs(),
129134
ExternalProviders: providerClients,
130135
DeferralAllowed: true,
@@ -244,10 +249,11 @@ func (r *RemovedComponentInstance) PlanChanges(ctx context.Context) ([]stackplan
244249

245250
var changes []stackplan.PlannedChange
246251
if plan != nil {
247-
var action plans.Action
248-
if r.call.config.config.Destroy {
249-
action = plans.Delete
250-
} else {
252+
action := plans.Delete
253+
switch {
254+
case r.main.PlanningOpts().PlanningMode == plans.RefreshOnlyMode:
255+
action = plans.Read
256+
case !r.call.config.config.Destroy:
251257
action = plans.Forget
252258
}
253259
changes, moreDiags = stackplan.FromPlan(ctx, r.ModuleTree(ctx), plan, nil, action, r)

internal/stacks/stackruntime/internal/stackeval/removed_stack_call_instance.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,13 @@ func newRemovedStackCallInstance(call *RemovedStackCall, from stackaddrs.StackIn
4848

4949
func (r *RemovedStackCallInstance) Stack(ctx context.Context, phase EvalPhase) *Stack {
5050
stack, err := r.stack.For(phase).Do(ctx, r.from.String()+" create", func(ctx context.Context) (*Stack, error) {
51-
return newStack(r.main, r.from, r.call.stack, r.call.config.TargetConfig(), r.call.GetExternalRemovedBlocks(), plans.DestroyMode, r.deferred), nil
51+
52+
mode := plans.DestroyMode
53+
if r.main.PlanningMode() == plans.RefreshOnlyMode {
54+
mode = plans.RefreshOnlyMode
55+
}
56+
57+
return newStack(r.main, r.from, r.call.stack, r.call.config.TargetConfig(), r.call.GetExternalRemovedBlocks(), mode, r.deferred), nil
5258
})
5359
if err != nil {
5460
// we never return an error from within the once call, so this shouldn't

0 commit comments

Comments
 (0)