Merge pull request #25500 from hashicorp/jbardin/destroy-output-expand

Do not evaluate output when doing a full destroy
This commit is contained in:
James Bardin 2020-07-08 10:07:20 -04:00 committed by GitHub
commit 8e79611e59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 19 deletions

View File

@ -6275,13 +6275,24 @@ func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) {
func TestContext2Apply_destroyOutputs(t *testing.T) { func TestContext2Apply_destroyOutputs(t *testing.T) {
m := testModule(t, "apply-destroy-outputs") m := testModule(t, "apply-destroy-outputs")
p := testProvider("aws") p := testProvider("test")
p.ApplyFn = testApplyFn p.ApplyFn = testApplyFn
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
// add the required id
m := req.Config.AsValueMap()
m["id"] = cty.StringVal("foo")
return providers.ReadDataSourceResponse{
State: cty.ObjectVal(m),
}
}
ctx := testContext2(t, &ContextOpts{ ctx := testContext2(t, &ContextOpts{
Config: m, Config: m,
Providers: map[addrs.Provider]providers.Factory{ Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
}, },
}) })
@ -6302,7 +6313,7 @@ func TestContext2Apply_destroyOutputs(t *testing.T) {
State: state, State: state,
Config: m, Config: m,
Providers: map[addrs.Provider]providers.Factory{ Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
}, },
}) })
@ -6326,7 +6337,7 @@ func TestContext2Apply_destroyOutputs(t *testing.T) {
State: state, State: state,
Config: m, Config: m,
Providers: map[addrs.Provider]providers.Factory{ Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
}, },
}) })
if _, diags := ctx.Plan(); diags.HasErrors() { if _, diags := ctx.Plan(); diags.HasErrors() {

View File

@ -165,7 +165,7 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
// directly. A destroy is identical to a normal apply, except for the // directly. A destroy is identical to a normal apply, except for the
// fact that we also have configuration to evaluate. While the rest of // fact that we also have configuration to evaluate. While the rest of
// the unused nodes can be programmatically pruned (via // the unused nodes can be programmatically pruned (via
// pruneUnusedNodesTransformer), root module outputs only have an // pruneUnusedNodesTransformer), root module outputs always have an
// implied dependency on remote state. This means that if they exist in // implied dependency on remote state. This means that if they exist in
// the configuration, the only signal to remove them is via the destroy // the configuration, the only signal to remove them is via the destroy
// command itself. // command itself.

View File

@ -1,12 +1,26 @@
resource "aws_instance" "foo" { data "test_data_source" "foo" {
num = "2" foo = "ok"
} }
resource "aws_instance" "bar" { locals {
foo = "{aws_instance.foo.num}" l = [
dep = "foo" {
name = data.test_data_source.foo.id
val = "null"
},
]
m = { for v in local.l :
v.name => v
}
} }
output "foo" { resource "test_instance" "bar" {
value = "${aws_instance.foo.id}" for_each = local.m
foo = format("%s", each.value.name)
dep = each.value.val
}
output "out" {
value = test_instance.bar
} }

View File

@ -207,10 +207,10 @@ func (t *pruneUnusedNodesTransformer) Transform(g *Graph) error {
modules = append(modules, mod) modules = append(modules, mod)
} }
// Sort them by path length, longest first, so that start with the deepest // Sort them by path length, longest first, so that we start with the
// modules. The order of modules at the same tree level doesn't matter, we // deepest modules. The order of modules at the same tree level doesn't
// just need to ensure that child modules are processed before parent // matter, we just need to ensure that child modules are processed before
// modules. // parent modules.
sort.Slice(modules, func(i, j int) bool { sort.Slice(modules, func(i, j int) bool {
return len(modules[i].addr) > len(modules[j].addr) return len(modules[i].addr) > len(modules[j].addr)
}) })

View File

@ -88,13 +88,14 @@ func (t *destroyRootOutputTransformer) Transform(g *Graph) error {
deps := g.UpEdges(v) deps := g.UpEdges(v)
// the destroy node must depend on the eval node
deps.Add(v)
for _, d := range deps { for _, d := range deps {
log.Printf("[TRACE] %s depends on %s", node.Name(), dag.VertexName(d)) log.Printf("[TRACE] %s depends on %s", node.Name(), dag.VertexName(d))
g.Connect(dag.BasicEdge(node, d)) g.Connect(dag.BasicEdge(node, d))
} }
// We no longer need the expand node, since we intend to remove this
// output from the state.
g.Remove(v)
} }
return nil return nil
} }