Skip to content

Commit 014bd30

Browse files
authored
Merge pull request #26353 from hashicorp/jbardin/refresh-false
Re-implement -refresh=false
2 parents c2566bf + 37569f5 commit 014bd30

File tree

8 files changed

+111
-36
lines changed

8 files changed

+111
-36
lines changed

backend/local/backend_local.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, *configload.
7878
opts.Targets = op.Targets
7979
opts.UIInput = op.UIIn
8080

81+
opts.SkipRefresh = op.Type == backend.OperationTypePlan && !op.PlanRefresh
82+
if opts.SkipRefresh {
83+
log.Printf("[DEBUG] backend/local: skipping refresh of managed resources")
84+
}
85+
8186
// Load the latest state. If we enter contextFromPlanFile below then the
8287
// state snapshot in the plan file must match this, or else it'll return
8388
// error diagnostics.

backend/local/backend_plan_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ func TestLocal_planOutPathNoChange(t *testing.T) {
678678
Type: "local",
679679
Config: cfgRaw,
680680
}
681+
op.PlanRefresh = true
681682

682683
run, err := b.Operation(context.Background(), op)
683684
if err != nil {

backend/local/backend_refresh.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ func (b *Local) opRefresh(
4242
}
4343
}
4444

45+
// Refresh now happens via a plan, so we need to ensure this is enabled
46+
op.PlanRefresh = true
47+
4548
// Get our context
4649
tfCtx, _, opState, contextDiags := b.context(op)
4750
diags = diags.Append(contextDiags)

terraform/context.go

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ var (
4747
// ContextOpts are the user-configurable options to create a context with
4848
// NewContext.
4949
type ContextOpts struct {
50-
Config *configs.Config
51-
Changes *plans.Changes
52-
State *states.State
53-
Targets []addrs.Targetable
54-
Variables InputValues
55-
Meta *ContextMeta
56-
Destroy bool
50+
Config *configs.Config
51+
Changes *plans.Changes
52+
State *states.State
53+
Targets []addrs.Targetable
54+
Variables InputValues
55+
Meta *ContextMeta
56+
Destroy bool
57+
SkipRefresh bool
5758

5859
Hooks []Hook
5960
Parallelism int
@@ -97,6 +98,7 @@ type Context struct {
9798
changes *plans.Changes
9899
state *states.State
99100
refreshState *states.State
101+
skipRefresh bool
100102
targets []addrs.Targetable
101103
variables InputValues
102104
meta *ContextMeta
@@ -233,6 +235,7 @@ func NewContext(opts *ContextOpts) (*Context, tfdiags.Diagnostics) {
233235
config: config,
234236
state: state,
235237
refreshState: state.DeepCopy(),
238+
skipRefresh: opts.SkipRefresh,
236239
targets: opts.Targets,
237240
uiInput: opts.UIInput,
238241
variables: variables,
@@ -293,12 +296,13 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags.
293296
case GraphTypePlan:
294297
// Create the plan graph builder
295298
return (&PlanGraphBuilder{
296-
Config: c.config,
297-
State: c.state,
298-
Components: c.components,
299-
Schemas: c.schemas,
300-
Targets: c.targets,
301-
Validate: opts.Validate,
299+
Config: c.config,
300+
State: c.state,
301+
Components: c.components,
302+
Schemas: c.schemas,
303+
Targets: c.targets,
304+
Validate: opts.Validate,
305+
skipRefresh: c.skipRefresh,
302306
}).Build(addrs.RootModuleInstance)
303307

304308
case GraphTypePlanDestroy:

terraform/context_plan_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6374,3 +6374,43 @@ data "test_data_source" "d" {
63746374
_, diags := ctx.Plan()
63756375
assertNoErrors(t, diags)
63766376
}
6377+
6378+
func TestContext2Plan_skipRefresh(t *testing.T) {
6379+
p := testProvider("test")
6380+
p.ApplyFn = testApplyFn
6381+
p.DiffFn = testDiffFn
6382+
6383+
m := testModuleInline(t, map[string]string{
6384+
"main.tf": `
6385+
resource "test_instance" "a" {
6386+
}
6387+
`})
6388+
6389+
state := states.NewState()
6390+
root := state.EnsureModule(addrs.RootModuleInstance)
6391+
root.SetResourceInstanceCurrent(
6392+
mustResourceInstanceAddr("test_instance.a").Resource,
6393+
&states.ResourceInstanceObjectSrc{
6394+
Status: states.ObjectReady,
6395+
AttrsJSON: []byte(`{"id":"a"}`),
6396+
Dependencies: []addrs.ConfigResource{},
6397+
},
6398+
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
6399+
)
6400+
6401+
ctx := testContext2(t, &ContextOpts{
6402+
Config: m,
6403+
Providers: map[addrs.Provider]providers.Factory{
6404+
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
6405+
},
6406+
State: state,
6407+
SkipRefresh: true,
6408+
})
6409+
6410+
_, diags := ctx.Plan()
6411+
assertNoErrors(t, diags)
6412+
6413+
if p.ReadResourceCalled {
6414+
t.Fatal("Resource should not have been refreshed")
6415+
}
6416+
}

terraform/graph_builder_plan.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ type PlanGraphBuilder struct {
4242
// Validate will do structural validation of the graph.
4343
Validate bool
4444

45+
// skipRefresh indicates that we should skip refreshing managed resources
46+
skipRefresh bool
47+
4548
// CustomConcrete can be set to customize the node types created
4649
// for various parts of the plan. This is useful in order to customize
4750
// the plan behavior.
@@ -196,6 +199,7 @@ func (b *PlanGraphBuilder) init() {
196199
b.ConcreteResource = func(a *NodeAbstractResource) dag.Vertex {
197200
return &nodeExpandPlannableResource{
198201
NodeAbstractResource: a,
202+
skipRefresh: b.skipRefresh,
199203
}
200204
}
201205

terraform/node_resource_plan.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ type nodeExpandPlannableResource struct {
2121
// on regardless of what the configuration says.
2222
ForceCreateBeforeDestroy *bool
2323

24+
// skipRefresh indicates that we should skip refreshing individual instances
25+
skipRefresh bool
26+
2427
// We attach dependencies to the Resource during refresh, since the
2528
// instances are instantiated during DynamicExpand.
2629
dependencies []addrs.ConfigResource
@@ -82,6 +85,7 @@ func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, er
8285
Addr: resAddr,
8386
ForceCreateBeforeDestroy: n.ForceCreateBeforeDestroy,
8487
dependencies: n.dependencies,
88+
skipRefresh: n.skipRefresh,
8589
})
8690
}
8791

@@ -144,6 +148,9 @@ type NodePlannableResource struct {
144148
// on regardless of what the configuration says.
145149
ForceCreateBeforeDestroy *bool
146150

151+
// skipRefresh indicates that we should skip refreshing individual instances
152+
skipRefresh bool
153+
147154
dependencies []addrs.ConfigResource
148155
}
149156

@@ -243,6 +250,7 @@ func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
243250
// to force on CreateBeforeDestroy due to dependencies on other
244251
// nodes that have it.
245252
ForceCreateBeforeDestroy: n.CreateBeforeDestroy(),
253+
skipRefresh: n.skipRefresh,
246254
}
247255
}
248256

terraform/node_resource_plan_instance.go

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
type NodePlannableResourceInstance struct {
1717
*NodeAbstractResourceInstance
1818
ForceCreateBeforeDestroy bool
19+
skipRefresh bool
1920
}
2021

2122
var (
@@ -134,29 +135,38 @@ func (n *NodePlannableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe
134135
ProviderSchema: &providerSchema,
135136
},
136137

137-
// Refresh the instance
138-
&EvalReadState{
139-
Addr: addr.Resource,
140-
Provider: &provider,
141-
ProviderSchema: &providerSchema,
142-
Output: &instanceRefreshState,
143-
},
144-
&EvalRefresh{
145-
Addr: addr.Resource,
146-
ProviderAddr: n.ResolvedProvider,
147-
Provider: &provider,
148-
ProviderMetas: n.ProviderMetas,
149-
ProviderSchema: &providerSchema,
150-
State: &instanceRefreshState,
151-
Output: &instanceRefreshState,
152-
},
153-
&EvalWriteState{
154-
Addr: addr.Resource,
155-
ProviderAddr: n.ResolvedProvider,
156-
State: &instanceRefreshState,
157-
ProviderSchema: &providerSchema,
158-
targetState: refreshState,
159-
Dependencies: &n.Dependencies,
138+
&EvalIf{
139+
If: func(ctx EvalContext) (bool, error) {
140+
return !n.skipRefresh, nil
141+
},
142+
Then: &EvalSequence{
143+
Nodes: []EvalNode{
144+
// Refresh the instance
145+
&EvalReadState{
146+
Addr: addr.Resource,
147+
Provider: &provider,
148+
ProviderSchema: &providerSchema,
149+
Output: &instanceRefreshState,
150+
},
151+
&EvalRefresh{
152+
Addr: addr.Resource,
153+
ProviderAddr: n.ResolvedProvider,
154+
Provider: &provider,
155+
ProviderMetas: n.ProviderMetas,
156+
ProviderSchema: &providerSchema,
157+
State: &instanceRefreshState,
158+
Output: &instanceRefreshState,
159+
},
160+
&EvalWriteState{
161+
Addr: addr.Resource,
162+
ProviderAddr: n.ResolvedProvider,
163+
State: &instanceRefreshState,
164+
ProviderSchema: &providerSchema,
165+
targetState: refreshState,
166+
Dependencies: &n.Dependencies,
167+
},
168+
},
169+
},
160170
},
161171

162172
// Plan the instance

0 commit comments

Comments
 (0)