fix: rewrite onlyDataResources (#9263)

This commit is contained in:
Marcin Tojek
2023-08-23 12:17:16 +02:00
committed by GitHub
parent d37f6d80f7
commit e6d90bd4fe
2 changed files with 144 additions and 10 deletions

View File

@ -264,18 +264,21 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
}, nil }, nil
} }
func onlyDataResources(sm *tfjson.StateModule) *tfjson.StateModule { func onlyDataResources(sm tfjson.StateModule) tfjson.StateModule {
sm2 := *sm filtered := sm
sm2.Resources = make([]*tfjson.StateResource, 0, len(sm.Resources)) filtered.Resources = []*tfjson.StateResource{}
for _, r := range sm.Resources { for _, r := range sm.Resources {
if r.Mode == "data" { if r.Mode == "data" {
sm2.Resources = append(sm2.Resources, r) filtered.Resources = append(filtered.Resources, r)
} }
} }
filtered.ChildModules = []*tfjson.StateModule{}
for _, c := range sm.ChildModules { for _, c := range sm.ChildModules {
sm2.ChildModules = append(sm2.ChildModules, onlyDataResources(c)) filteredChild := onlyDataResources(*c)
filtered.ChildModules = append(filtered.ChildModules, &filteredChild)
} }
return &sm2 return filtered
} }
// planResources must only be called while the lock is held. // planResources must only be called while the lock is held.
@ -300,10 +303,9 @@ func (e *executor) planResources(ctx, killCtx context.Context, planfilePath stri
// We don't want all prior resources, because Quotas (and // We don't want all prior resources, because Quotas (and
// future features) would never know which resources are getting // future features) would never know which resources are getting
// deleted by a stop. // deleted by a stop.
modules = append(
modules, filtered := onlyDataResources(*plan.PriorState.Values.RootModule)
onlyDataResources(plan.PriorState.Values.RootModule), modules = append(modules, &filtered)
)
} }
modules = append(modules, plan.PlannedValues.RootModule) modules = append(modules, plan.PlannedValues.RootModule)

View File

@ -1,8 +1,10 @@
package terraform package terraform
import ( import (
"encoding/json"
"testing" "testing"
tfjson "github.com/hashicorp/terraform-json"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/provisionersdk/proto"
@ -41,3 +43,133 @@ From standing in the English rain`))
} }
require.Equal(t, expected, logr.logs) require.Equal(t, expected, logr.logs)
} }
func TestOnlyDataResources(t *testing.T) {
t.Parallel()
tests := []struct {
name string
stateMod *tfjson.StateModule
expected *tfjson.StateModule
}{
{
name: "empty state module",
stateMod: &tfjson.StateModule{},
expected: &tfjson.StateModule{},
},
{
name: "only data resources",
stateMod: &tfjson.StateModule{
Resources: []*tfjson.StateResource{
{Name: "cat", Type: "coder_parameter", Mode: "data", Address: "cat-address"},
{Name: "cow", Type: "foobaz", Mode: "data", Address: "cow-address"},
},
ChildModules: []*tfjson.StateModule{
{
Resources: []*tfjson.StateResource{
{Name: "child-cat", Type: "coder_parameter", Mode: "data", Address: "child-cat-address"},
{Name: "child-dog", Type: "foobar", Mode: "data", Address: "child-dog-address"},
},
Address: "child-module-1",
},
},
Address: "fake-module",
},
expected: &tfjson.StateModule{
Resources: []*tfjson.StateResource{
{Name: "cat", Type: "coder_parameter", Mode: "data", Address: "cat-address"},
{Name: "cow", Type: "foobaz", Mode: "data", Address: "cow-address"},
},
ChildModules: []*tfjson.StateModule{
{
Resources: []*tfjson.StateResource{
{Name: "child-cat", Type: "coder_parameter", Mode: "data", Address: "child-cat-address"},
{Name: "child-dog", Type: "foobar", Mode: "data", Address: "child-dog-address"},
},
Address: "child-module-1",
},
},
Address: "fake-module",
},
},
{
name: "only non-data resources",
stateMod: &tfjson.StateModule{
Resources: []*tfjson.StateResource{
{Name: "cat", Type: "coder_parameter", Mode: "foobar", Address: "cat-address"},
{Name: "cow", Type: "foobaz", Mode: "foo", Address: "cow-address"},
},
ChildModules: []*tfjson.StateModule{
{
Resources: []*tfjson.StateResource{
{Name: "child-cat", Type: "coder_parameter", Mode: "foobar", Address: "child-cat-address"},
{Name: "child-dog", Type: "foobar", Mode: "foobaz", Address: "child-dog-address"},
},
Address: "child-module-1",
},
},
Address: "fake-module",
},
expected: &tfjson.StateModule{
Address: "fake-module",
ChildModules: []*tfjson.StateModule{
{Address: "child-module-1"},
},
},
},
{
name: "mixed resources",
stateMod: &tfjson.StateModule{
Resources: []*tfjson.StateResource{
{Name: "cat", Type: "coder_parameter", Mode: "data", Address: "cat-address"},
{Name: "dog", Type: "foobar", Mode: "magic", Address: "dog-address"},
{Name: "cow", Type: "foobaz", Mode: "data", Address: "cow-address"},
},
ChildModules: []*tfjson.StateModule{
{
Resources: []*tfjson.StateResource{
{Name: "child-cat", Type: "coder_parameter", Mode: "data", Address: "child-cat-address"},
{Name: "child-dog", Type: "foobar", Mode: "data", Address: "child-dog-address"},
{Name: "child-cow", Type: "foobaz", Mode: "magic", Address: "child-cow-address"},
},
Address: "child-module-1",
},
},
Address: "fake-module",
},
expected: &tfjson.StateModule{
Resources: []*tfjson.StateResource{
{Name: "cat", Type: "coder_parameter", Mode: "data", Address: "cat-address"},
{Name: "cow", Type: "foobaz", Mode: "data", Address: "cow-address"},
},
ChildModules: []*tfjson.StateModule{
{
Resources: []*tfjson.StateResource{
{Name: "child-cat", Type: "coder_parameter", Mode: "data", Address: "child-cat-address"},
{Name: "child-dog", Type: "foobar", Mode: "data", Address: "child-dog-address"},
},
Address: "child-module-1",
},
},
Address: "fake-module",
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
filtered := onlyDataResources(*tt.stateMod)
expected, err := json.Marshal(tt.expected)
require.NoError(t, err)
got, err := json.Marshal(filtered)
require.NoError(t, err)
require.Equal(t, string(expected), string(got))
})
}
}