mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-25 16:31:10 -06:00
terraform: ResourceTransformer to ResourceTransformerOld
This commit is contained in:
parent
d7aa59be3c
commit
4cdaf6f687
@ -156,7 +156,7 @@ func (n *GraphNodeConfigResource) DynamicExpand(ctx EvalContext) (*Graph, error)
|
|||||||
steps := make([]GraphTransformer, 0, 5)
|
steps := make([]GraphTransformer, 0, 5)
|
||||||
|
|
||||||
// Expand counts.
|
// Expand counts.
|
||||||
steps = append(steps, &ResourceCountTransformer{
|
steps = append(steps, &ResourceCountTransformerOld{
|
||||||
Resource: n.Resource,
|
Resource: n.Resource,
|
||||||
Destroy: n.Destroy,
|
Destroy: n.Destroy,
|
||||||
Targets: n.Targets,
|
Targets: n.Targets,
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NodePlannableResource represents a resource that is "plannable":
|
// NodePlannableResource represents a resource that is "plannable":
|
||||||
// it is ready to be planned in order to create a diff.
|
// it is ready to be planned in order to create a diff.
|
||||||
type NodePlannableResource struct {
|
type NodePlannableResource struct {
|
||||||
@ -14,194 +8,41 @@ type NodePlannableResource struct {
|
|||||||
|
|
||||||
// GraphNodeEvalable
|
// GraphNodeEvalable
|
||||||
func (n *NodePlannableResource) EvalTree() EvalNode {
|
func (n *NodePlannableResource) EvalTree() EvalNode {
|
||||||
addr := n.NodeAbstractResource.Addr
|
|
||||||
|
|
||||||
// stateId is the ID to put into the state
|
|
||||||
stateId := addr.stateId()
|
|
||||||
if addr.Index > -1 {
|
|
||||||
stateId = fmt.Sprintf("%s.%d", stateId, addr.Index)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the instance info. More of this will be populated during eval
|
|
||||||
info := &InstanceInfo{
|
|
||||||
Id: stateId,
|
|
||||||
Type: addr.Type,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the resource for eval
|
|
||||||
resource := &Resource{
|
|
||||||
Name: addr.Name,
|
|
||||||
Type: addr.Type,
|
|
||||||
CountIndex: addr.Index,
|
|
||||||
}
|
|
||||||
if resource.CountIndex < 0 {
|
|
||||||
resource.CountIndex = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the dependencies for the state. We use some older
|
|
||||||
// code for this that we've used for a long time.
|
|
||||||
var stateDeps []string
|
|
||||||
{
|
|
||||||
oldN := &graphNodeExpandedResource{Resource: n.Config}
|
|
||||||
stateDeps = oldN.StateDependencies()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eval info is different depending on what kind of resource this is
|
|
||||||
switch n.Config.Mode {
|
|
||||||
case config.ManagedResourceMode:
|
|
||||||
return n.evalTreeManagedResource(
|
|
||||||
stateId, info, resource, stateDeps,
|
|
||||||
)
|
|
||||||
case config.DataResourceMode:
|
|
||||||
return n.evalTreeDataResource(
|
|
||||||
stateId, info, resource, stateDeps)
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NodePlannableResource) evalTreeDataResource(
|
|
||||||
stateId string, info *InstanceInfo,
|
|
||||||
resource *Resource, stateDeps []string) EvalNode {
|
|
||||||
var provider ResourceProvider
|
|
||||||
var config *ResourceConfig
|
|
||||||
var diff *InstanceDiff
|
|
||||||
var state *InstanceState
|
|
||||||
|
|
||||||
return &EvalSequence{
|
return &EvalSequence{
|
||||||
Nodes: []EvalNode{
|
Nodes: []EvalNode{
|
||||||
// Get the saved diff for apply
|
// The EvalTree for a plannable resource primarily involves
|
||||||
&EvalReadDiff{
|
// interpolating the count since it can contain variables
|
||||||
Name: stateId,
|
// we only just received access to.
|
||||||
Diff: &diff,
|
//
|
||||||
},
|
// With the interpolated count, we can then DynamicExpand
|
||||||
|
// into the proper number of instances.
|
||||||
// Stop here if we don't actually have a diff
|
&EvalInterpolate{Config: n.Config.RawCount},
|
||||||
&EvalIf{
|
|
||||||
If: func(ctx EvalContext) (bool, error) {
|
|
||||||
if diff == nil {
|
|
||||||
return true, EvalEarlyExitError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if diff.GetAttributesLen() == 0 {
|
|
||||||
return true, EvalEarlyExitError{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
},
|
|
||||||
Then: EvalNoop{},
|
|
||||||
},
|
|
||||||
|
|
||||||
// We need to re-interpolate the config here, rather than
|
|
||||||
// just using the diff's values directly, because we've
|
|
||||||
// potentially learned more variable values during the
|
|
||||||
// apply pass that weren't known when the diff was produced.
|
|
||||||
&EvalInterpolate{
|
|
||||||
Config: n.Config.RawConfig.Copy(),
|
|
||||||
Resource: resource,
|
|
||||||
Output: &config,
|
|
||||||
},
|
|
||||||
|
|
||||||
&EvalGetProvider{
|
|
||||||
Name: n.ProvidedBy()[0],
|
|
||||||
Output: &provider,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Make a new diff with our newly-interpolated config.
|
|
||||||
&EvalReadDataDiff{
|
|
||||||
Info: info,
|
|
||||||
Config: &config,
|
|
||||||
Previous: &diff,
|
|
||||||
Provider: &provider,
|
|
||||||
Output: &diff,
|
|
||||||
},
|
|
||||||
|
|
||||||
&EvalReadDataApply{
|
|
||||||
Info: info,
|
|
||||||
Diff: &diff,
|
|
||||||
Provider: &provider,
|
|
||||||
Output: &state,
|
|
||||||
},
|
|
||||||
|
|
||||||
&EvalWriteState{
|
|
||||||
Name: stateId,
|
|
||||||
ResourceType: n.Config.Type,
|
|
||||||
Provider: n.Config.Provider,
|
|
||||||
Dependencies: stateDeps,
|
|
||||||
State: &state,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Clear the diff now that we've applied it, so
|
|
||||||
// later nodes won't see a diff that's now a no-op.
|
|
||||||
&EvalWriteDiff{
|
|
||||||
Name: stateId,
|
|
||||||
Diff: nil,
|
|
||||||
},
|
|
||||||
|
|
||||||
&EvalUpdateStateHook{},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodePlannableResource) evalTreeManagedResource(
|
/*
|
||||||
stateId string, info *InstanceInfo,
|
// GraphNodeDynamicExpandable
|
||||||
resource *Resource, stateDeps []string) EvalNode {
|
func (n *NodePlannableResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
||||||
// Declare a bunch of variables that are used for state during
|
state, lock := ctx.State()
|
||||||
// evaluation. Most of this are written to by-address below.
|
lock.RLock()
|
||||||
var provider ResourceProvider
|
defer lock.RUnlock()
|
||||||
var diff *InstanceDiff
|
|
||||||
var state *InstanceState
|
|
||||||
var resourceConfig *ResourceConfig
|
|
||||||
|
|
||||||
return &EvalSequence{
|
// Start creating the steps
|
||||||
Nodes: []EvalNode{
|
steps := make([]GraphTransformer, 0, 5)
|
||||||
&EvalInterpolate{
|
|
||||||
Config: n.Config.RawConfig.Copy(),
|
// Expand counts.
|
||||||
Resource: resource,
|
steps = append(steps, &ResourceCountTransformer{
|
||||||
Output: &resourceConfig,
|
Resource: n.Resource,
|
||||||
},
|
Destroy: n.Destroy,
|
||||||
&EvalGetProvider{
|
Targets: n.Targets,
|
||||||
Name: n.ProvidedBy()[0],
|
})
|
||||||
Output: &provider,
|
|
||||||
},
|
// Always end with the root being added
|
||||||
// Re-run validation to catch any errors we missed, e.g. type
|
steps = append(steps, &RootTransformer{})
|
||||||
// mismatches on computed values.
|
|
||||||
&EvalValidateResource{
|
// Build the graph
|
||||||
Provider: &provider,
|
b := &BasicGraphBuilder{Steps: steps, Validate: true}
|
||||||
Config: &resourceConfig,
|
return b.Build(ctx.Path())
|
||||||
ResourceName: n.Config.Name,
|
|
||||||
ResourceType: n.Config.Type,
|
|
||||||
ResourceMode: n.Config.Mode,
|
|
||||||
IgnoreWarnings: true,
|
|
||||||
},
|
|
||||||
&EvalReadState{
|
|
||||||
Name: stateId,
|
|
||||||
Output: &state,
|
|
||||||
},
|
|
||||||
&EvalDiff{
|
|
||||||
Info: info,
|
|
||||||
Config: &resourceConfig,
|
|
||||||
Resource: n.Config,
|
|
||||||
Provider: &provider,
|
|
||||||
State: &state,
|
|
||||||
OutputDiff: &diff,
|
|
||||||
OutputState: &state,
|
|
||||||
},
|
|
||||||
&EvalCheckPreventDestroy{
|
|
||||||
Resource: n.Config,
|
|
||||||
Diff: &diff,
|
|
||||||
},
|
|
||||||
&EvalWriteState{
|
|
||||||
Name: stateId,
|
|
||||||
ResourceType: n.Config.Type,
|
|
||||||
Provider: n.Config.Provider,
|
|
||||||
Dependencies: stateDeps,
|
|
||||||
State: &state,
|
|
||||||
},
|
|
||||||
&EvalWriteDiff{
|
|
||||||
Name: stateId,
|
|
||||||
Diff: &diff,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
196
terraform/node_resource_plan_instance.go
Normal file
196
terraform/node_resource_plan_instance.go
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NodePlannableResourceInstance represents a _single_ resource
|
||||||
|
// instance that is plannable. This means this represents a single
|
||||||
|
// count index, for example.
|
||||||
|
type NodePlannableResourceInstance struct {
|
||||||
|
*NodeAbstractResource
|
||||||
|
}
|
||||||
|
|
||||||
|
// GraphNodeEvalable
|
||||||
|
func (n *NodePlannableResourceInstance) EvalTree() EvalNode {
|
||||||
|
addr := n.NodeAbstractResource.Addr
|
||||||
|
|
||||||
|
// stateId is the ID to put into the state
|
||||||
|
stateId := addr.stateId()
|
||||||
|
if addr.Index > -1 {
|
||||||
|
stateId = fmt.Sprintf("%s.%d", stateId, addr.Index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the instance info. More of this will be populated during eval
|
||||||
|
info := &InstanceInfo{
|
||||||
|
Id: stateId,
|
||||||
|
Type: addr.Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the resource for eval
|
||||||
|
resource := &Resource{
|
||||||
|
Name: addr.Name,
|
||||||
|
Type: addr.Type,
|
||||||
|
CountIndex: addr.Index,
|
||||||
|
}
|
||||||
|
if resource.CountIndex < 0 {
|
||||||
|
resource.CountIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the dependencies for the state. We use some older
|
||||||
|
// code for this that we've used for a long time.
|
||||||
|
var stateDeps []string
|
||||||
|
{
|
||||||
|
oldN := &graphNodeExpandedResource{Resource: n.Config}
|
||||||
|
stateDeps = oldN.StateDependencies()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eval info is different depending on what kind of resource this is
|
||||||
|
switch n.Config.Mode {
|
||||||
|
case config.ManagedResourceMode:
|
||||||
|
return n.evalTreeManagedResource(
|
||||||
|
stateId, info, resource, stateDeps,
|
||||||
|
)
|
||||||
|
case config.DataResourceMode:
|
||||||
|
return n.evalTreeDataResource(
|
||||||
|
stateId, info, resource, stateDeps)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NodePlannableResourceInstance) evalTreeDataResource(
|
||||||
|
stateId string, info *InstanceInfo,
|
||||||
|
resource *Resource, stateDeps []string) EvalNode {
|
||||||
|
var provider ResourceProvider
|
||||||
|
var config *ResourceConfig
|
||||||
|
var diff *InstanceDiff
|
||||||
|
var state *InstanceState
|
||||||
|
|
||||||
|
return &EvalSequence{
|
||||||
|
Nodes: []EvalNode{
|
||||||
|
&EvalReadState{
|
||||||
|
Name: stateId,
|
||||||
|
Output: &state,
|
||||||
|
},
|
||||||
|
|
||||||
|
// We need to re-interpolate the config here because some
|
||||||
|
// of the attributes may have become computed during
|
||||||
|
// earlier planning, due to other resources having
|
||||||
|
// "requires new resource" diffs.
|
||||||
|
&EvalInterpolate{
|
||||||
|
Config: n.Config.RawConfig.Copy(),
|
||||||
|
Resource: resource,
|
||||||
|
Output: &config,
|
||||||
|
},
|
||||||
|
|
||||||
|
&EvalIf{
|
||||||
|
If: func(ctx EvalContext) (bool, error) {
|
||||||
|
computed := config.ComputedKeys != nil && len(config.ComputedKeys) > 0
|
||||||
|
|
||||||
|
// If the configuration is complete and we
|
||||||
|
// already have a state then we don't need to
|
||||||
|
// do any further work during apply, because we
|
||||||
|
// already populated the state during refresh.
|
||||||
|
if !computed && state != nil {
|
||||||
|
return true, EvalEarlyExitError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
},
|
||||||
|
Then: EvalNoop{},
|
||||||
|
},
|
||||||
|
|
||||||
|
&EvalGetProvider{
|
||||||
|
Name: n.ProvidedBy()[0],
|
||||||
|
Output: &provider,
|
||||||
|
},
|
||||||
|
|
||||||
|
&EvalReadDataDiff{
|
||||||
|
Info: info,
|
||||||
|
Config: &config,
|
||||||
|
Provider: &provider,
|
||||||
|
Output: &diff,
|
||||||
|
OutputState: &state,
|
||||||
|
},
|
||||||
|
|
||||||
|
&EvalWriteState{
|
||||||
|
Name: stateId,
|
||||||
|
ResourceType: n.Config.Type,
|
||||||
|
Provider: n.Config.Provider,
|
||||||
|
Dependencies: stateDeps,
|
||||||
|
State: &state,
|
||||||
|
},
|
||||||
|
|
||||||
|
&EvalWriteDiff{
|
||||||
|
Name: stateId,
|
||||||
|
Diff: &diff,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NodePlannableResourceInstance) evalTreeManagedResource(
|
||||||
|
stateId string, info *InstanceInfo,
|
||||||
|
resource *Resource, stateDeps []string) EvalNode {
|
||||||
|
// Declare a bunch of variables that are used for state during
|
||||||
|
// evaluation. Most of this are written to by-address below.
|
||||||
|
var provider ResourceProvider
|
||||||
|
var diff *InstanceDiff
|
||||||
|
var state *InstanceState
|
||||||
|
var resourceConfig *ResourceConfig
|
||||||
|
|
||||||
|
return &EvalSequence{
|
||||||
|
Nodes: []EvalNode{
|
||||||
|
&EvalInterpolate{
|
||||||
|
Config: n.Config.RawConfig.Copy(),
|
||||||
|
Resource: resource,
|
||||||
|
Output: &resourceConfig,
|
||||||
|
},
|
||||||
|
&EvalGetProvider{
|
||||||
|
Name: n.ProvidedBy()[0],
|
||||||
|
Output: &provider,
|
||||||
|
},
|
||||||
|
// Re-run validation to catch any errors we missed, e.g. type
|
||||||
|
// mismatches on computed values.
|
||||||
|
&EvalValidateResource{
|
||||||
|
Provider: &provider,
|
||||||
|
Config: &resourceConfig,
|
||||||
|
ResourceName: n.Config.Name,
|
||||||
|
ResourceType: n.Config.Type,
|
||||||
|
ResourceMode: n.Config.Mode,
|
||||||
|
IgnoreWarnings: true,
|
||||||
|
},
|
||||||
|
&EvalReadState{
|
||||||
|
Name: stateId,
|
||||||
|
Output: &state,
|
||||||
|
},
|
||||||
|
&EvalDiff{
|
||||||
|
Info: info,
|
||||||
|
Config: &resourceConfig,
|
||||||
|
Resource: n.Config,
|
||||||
|
Provider: &provider,
|
||||||
|
State: &state,
|
||||||
|
OutputDiff: &diff,
|
||||||
|
OutputState: &state,
|
||||||
|
},
|
||||||
|
&EvalCheckPreventDestroy{
|
||||||
|
Resource: n.Config,
|
||||||
|
Diff: &diff,
|
||||||
|
},
|
||||||
|
&EvalWriteState{
|
||||||
|
Name: stateId,
|
||||||
|
ResourceType: n.Config.Type,
|
||||||
|
Provider: n.Config.Provider,
|
||||||
|
Dependencies: stateDeps,
|
||||||
|
State: &state,
|
||||||
|
},
|
||||||
|
&EvalWriteDiff{
|
||||||
|
Name: stateId,
|
||||||
|
Diff: &diff,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -8,15 +8,15 @@ import (
|
|||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResourceCountTransformer is a GraphTransformer that expands the count
|
// ResourceCountTransformerOld is a GraphTransformer that expands the count
|
||||||
// out for a specific resource.
|
// out for a specific resource.
|
||||||
type ResourceCountTransformer struct {
|
type ResourceCountTransformerOld struct {
|
||||||
Resource *config.Resource
|
Resource *config.Resource
|
||||||
Destroy bool
|
Destroy bool
|
||||||
Targets []ResourceAddress
|
Targets []ResourceAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ResourceCountTransformer) Transform(g *Graph) error {
|
func (t *ResourceCountTransformerOld) Transform(g *Graph) error {
|
||||||
// Expand the resource count
|
// Expand the resource count
|
||||||
count, err := t.Resource.Count()
|
count, err := t.Resource.Count()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -72,7 +72,7 @@ func (t *ResourceCountTransformer) Transform(g *Graph) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ResourceCountTransformer) nodeIsTargeted(node dag.Vertex) bool {
|
func (t *ResourceCountTransformerOld) nodeIsTargeted(node dag.Vertex) bool {
|
||||||
// no targets specified, everything stays in the graph
|
// no targets specified, everything stays in the graph
|
||||||
if len(t.Targets) == 0 {
|
if len(t.Targets) == 0 {
|
||||||
return true
|
return true
|
||||||
|
@ -5,64 +5,64 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResourceCountTransformer(t *testing.T) {
|
func TestResourceCountTransformerOld(t *testing.T) {
|
||||||
cfg := testModule(t, "transform-resource-count-basic").Config()
|
cfg := testModule(t, "transform-resource-count-basic").Config()
|
||||||
resource := cfg.Resources[0]
|
resource := cfg.Resources[0]
|
||||||
|
|
||||||
g := Graph{Path: RootModulePath}
|
g := Graph{Path: RootModulePath}
|
||||||
{
|
{
|
||||||
tf := &ResourceCountTransformer{Resource: resource}
|
tf := &ResourceCountTransformerOld{Resource: resource}
|
||||||
if err := tf.Transform(&g); err != nil {
|
if err := tf.Transform(&g); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testResourceCountTransformStr)
|
expected := strings.TrimSpace(testResourceCountTransformOldStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n\n%s", actual)
|
t.Fatalf("bad:\n\n%s", actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourceCountTransformer_countNegative(t *testing.T) {
|
func TestResourceCountTransformerOld_countNegative(t *testing.T) {
|
||||||
cfg := testModule(t, "transform-resource-count-negative").Config()
|
cfg := testModule(t, "transform-resource-count-negative").Config()
|
||||||
resource := cfg.Resources[0]
|
resource := cfg.Resources[0]
|
||||||
|
|
||||||
g := Graph{Path: RootModulePath}
|
g := Graph{Path: RootModulePath}
|
||||||
{
|
{
|
||||||
tf := &ResourceCountTransformer{Resource: resource}
|
tf := &ResourceCountTransformerOld{Resource: resource}
|
||||||
if err := tf.Transform(&g); err == nil {
|
if err := tf.Transform(&g); err == nil {
|
||||||
t.Fatal("should error")
|
t.Fatal("should error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResourceCountTransformer_deps(t *testing.T) {
|
func TestResourceCountTransformerOld_deps(t *testing.T) {
|
||||||
cfg := testModule(t, "transform-resource-count-deps").Config()
|
cfg := testModule(t, "transform-resource-count-deps").Config()
|
||||||
resource := cfg.Resources[0]
|
resource := cfg.Resources[0]
|
||||||
|
|
||||||
g := Graph{Path: RootModulePath}
|
g := Graph{Path: RootModulePath}
|
||||||
{
|
{
|
||||||
tf := &ResourceCountTransformer{Resource: resource}
|
tf := &ResourceCountTransformerOld{Resource: resource}
|
||||||
if err := tf.Transform(&g); err != nil {
|
if err := tf.Transform(&g); err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := strings.TrimSpace(g.String())
|
actual := strings.TrimSpace(g.String())
|
||||||
expected := strings.TrimSpace(testResourceCountTransformDepsStr)
|
expected := strings.TrimSpace(testResourceCountTransformOldDepsStr)
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
t.Fatalf("bad:\n\n%s", actual)
|
t.Fatalf("bad:\n\n%s", actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const testResourceCountTransformStr = `
|
const testResourceCountTransformOldStr = `
|
||||||
aws_instance.foo #0
|
aws_instance.foo #0
|
||||||
aws_instance.foo #1
|
aws_instance.foo #1
|
||||||
aws_instance.foo #2
|
aws_instance.foo #2
|
||||||
`
|
`
|
||||||
|
|
||||||
const testResourceCountTransformDepsStr = `
|
const testResourceCountTransformOldDepsStr = `
|
||||||
aws_instance.foo #0
|
aws_instance.foo #0
|
||||||
aws_instance.foo #1
|
aws_instance.foo #1
|
||||||
aws_instance.foo #0
|
aws_instance.foo #0
|
||||||
|
Loading…
Reference in New Issue
Block a user