merge dependencies when refreshing
The resource configuration was always being used to determine dependencies during refresh, because if there were no changes to a resource, there was no chance to replace any incorrect stored dependencies. Now that we are refreshing during plan, we can determine that a resource has no changes and opt to store the new dependencies immediately. Here we clean up the writeResourceInstanceState calls to no longer modify the resource instance state, removing the `dependencies` argument. Callers are now expected to set the Dependencies field as needed.
This commit is contained in:
parent
985124bfa8
commit
7964328f34
|
@ -248,3 +248,124 @@ resource "test_instance" "a" {
|
||||||
t.Fatalf("expected apply order [b, a], got: %v\n", order)
|
t.Fatalf("expected apply order [b, a], got: %v\n", order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verify that dependencies are updated in the state during refresh and apply
|
||||||
|
func TestApply_updateDependencies(t *testing.T) {
|
||||||
|
state := states.NewState()
|
||||||
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
||||||
|
|
||||||
|
fooAddr := mustResourceInstanceAddr("aws_instance.foo")
|
||||||
|
barAddr := mustResourceInstanceAddr("aws_instance.bar")
|
||||||
|
bazAddr := mustResourceInstanceAddr("aws_instance.baz")
|
||||||
|
bamAddr := mustResourceInstanceAddr("aws_instance.bam")
|
||||||
|
binAddr := mustResourceInstanceAddr("aws_instance.bin")
|
||||||
|
root.SetResourceInstanceCurrent(
|
||||||
|
fooAddr.Resource,
|
||||||
|
&states.ResourceInstanceObjectSrc{
|
||||||
|
Status: states.ObjectReady,
|
||||||
|
AttrsJSON: []byte(`{"id":"foo"}`),
|
||||||
|
Dependencies: []addrs.ConfigResource{
|
||||||
|
bazAddr.ContainingResource().Config(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||||
|
)
|
||||||
|
root.SetResourceInstanceCurrent(
|
||||||
|
binAddr.Resource,
|
||||||
|
&states.ResourceInstanceObjectSrc{
|
||||||
|
Status: states.ObjectReady,
|
||||||
|
AttrsJSON: []byte(`{"id":"bin","type":"aws_instance","unknown":"ok"}`),
|
||||||
|
Dependencies: []addrs.ConfigResource{
|
||||||
|
bazAddr.ContainingResource().Config(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||||
|
)
|
||||||
|
root.SetResourceInstanceCurrent(
|
||||||
|
bazAddr.Resource,
|
||||||
|
&states.ResourceInstanceObjectSrc{
|
||||||
|
Status: states.ObjectReady,
|
||||||
|
AttrsJSON: []byte(`{"id":"baz"}`),
|
||||||
|
Dependencies: []addrs.ConfigResource{
|
||||||
|
// Existing dependencies should not be removed from orphaned instances
|
||||||
|
bamAddr.ContainingResource().Config(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||||
|
)
|
||||||
|
root.SetResourceInstanceCurrent(
|
||||||
|
barAddr.Resource,
|
||||||
|
&states.ResourceInstanceObjectSrc{
|
||||||
|
Status: states.ObjectReady,
|
||||||
|
AttrsJSON: []byte(`{"id":"bar","foo":"foo"}`),
|
||||||
|
},
|
||||||
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
||||||
|
)
|
||||||
|
|
||||||
|
m := testModuleInline(t, map[string]string{
|
||||||
|
"main.tf": `
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
foo = aws_instance.foo.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "foo" {
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_instance" "bin" {
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
|
||||||
|
p := testProvider("aws")
|
||||||
|
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Config: m,
|
||||||
|
Providers: map[addrs.Provider]providers.Factory{
|
||||||
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
State: state,
|
||||||
|
})
|
||||||
|
|
||||||
|
plan, diags := ctx.Plan()
|
||||||
|
if diags.HasErrors() {
|
||||||
|
t.Fatal(diags.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
bar := plan.State.ResourceInstance(barAddr)
|
||||||
|
if len(bar.Current.Dependencies) == 0 || !bar.Current.Dependencies[0].Equal(fooAddr.ContainingResource().Config()) {
|
||||||
|
t.Fatalf("bar should depend on foo after refresh, but got %s", bar.Current.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
foo := plan.State.ResourceInstance(fooAddr)
|
||||||
|
if len(foo.Current.Dependencies) == 0 || !foo.Current.Dependencies[0].Equal(bazAddr.ContainingResource().Config()) {
|
||||||
|
t.Fatalf("foo should depend on baz after refresh because of the update, but got %s", foo.Current.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
bin := plan.State.ResourceInstance(binAddr)
|
||||||
|
if len(bin.Current.Dependencies) != 0 {
|
||||||
|
t.Fatalf("bin should depend on nothing after refresh because there is no change, but got %s", bin.Current.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
baz := plan.State.ResourceInstance(bazAddr)
|
||||||
|
if len(baz.Current.Dependencies) == 0 || !baz.Current.Dependencies[0].Equal(bamAddr.ContainingResource().Config()) {
|
||||||
|
t.Fatalf("baz should depend on bam after refresh, but got %s", baz.Current.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
state, diags = ctx.Apply()
|
||||||
|
if diags.HasErrors() {
|
||||||
|
t.Fatal(diags.Err())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(state)
|
||||||
|
|
||||||
|
bar = state.ResourceInstance(barAddr)
|
||||||
|
if len(bar.Current.Dependencies) == 0 || !bar.Current.Dependencies[0].Equal(fooAddr.ContainingResource().Config()) {
|
||||||
|
t.Fatalf("bar should still depend on foo after apply, but got %s", bar.Current.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
foo = state.ResourceInstance(fooAddr)
|
||||||
|
if len(foo.Current.Dependencies) != 0 {
|
||||||
|
t.Fatalf("foo should have no deps after apply, but got %s", foo.Current.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1533,126 +1533,6 @@ func TestContext2Refresh_dataResourceDependsOn(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that dependencies are updated in the state during refresh
|
|
||||||
func TestRefresh_updateDependencies(t *testing.T) {
|
|
||||||
state := states.NewState()
|
|
||||||
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
||||||
root.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "aws_instance",
|
|
||||||
Name: "foo",
|
|
||||||
}.Instance(addrs.NoKey),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"id":"foo"}`),
|
|
||||||
Dependencies: []addrs.ConfigResource{
|
|
||||||
// Existing dependencies should be removed when overridden by the config
|
|
||||||
{
|
|
||||||
Module: addrs.RootModule,
|
|
||||||
Resource: addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "aws_instance",
|
|
||||||
Name: "baz",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
addrs.AbsProviderConfig{
|
|
||||||
Provider: addrs.NewDefaultProvider("aws"),
|
|
||||||
Module: addrs.RootModule,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
root.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "aws_instance",
|
|
||||||
Name: "baz",
|
|
||||||
}.Instance(addrs.NoKey),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"id":"baz"}`),
|
|
||||||
Dependencies: []addrs.ConfigResource{
|
|
||||||
// Existing dependencies should not be removed from orphaned instances
|
|
||||||
{
|
|
||||||
Module: addrs.RootModule,
|
|
||||||
Resource: addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "aws_instance",
|
|
||||||
Name: "bam",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
addrs.AbsProviderConfig{
|
|
||||||
Provider: addrs.NewDefaultProvider("aws"),
|
|
||||||
Module: addrs.RootModule,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
root.SetResourceInstanceCurrent(
|
|
||||||
addrs.Resource{
|
|
||||||
Mode: addrs.ManagedResourceMode,
|
|
||||||
Type: "aws_instance",
|
|
||||||
Name: "bar",
|
|
||||||
}.Instance(addrs.NoKey),
|
|
||||||
&states.ResourceInstanceObjectSrc{
|
|
||||||
Status: states.ObjectReady,
|
|
||||||
AttrsJSON: []byte(`{"id":"bar","foo":"foo"}`),
|
|
||||||
},
|
|
||||||
addrs.AbsProviderConfig{
|
|
||||||
Provider: addrs.NewDefaultProvider("aws"),
|
|
||||||
Module: addrs.RootModule,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
m := testModuleInline(t, map[string]string{
|
|
||||||
"main.tf": `
|
|
||||||
resource "aws_instance" "bar" {
|
|
||||||
foo = aws_instance.foo.id
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "aws_instance" "foo" {
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})
|
|
||||||
|
|
||||||
p := testProvider("aws")
|
|
||||||
|
|
||||||
ctx := testContext2(t, &ContextOpts{
|
|
||||||
Config: m,
|
|
||||||
Providers: map[addrs.Provider]providers.Factory{
|
|
||||||
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
||||||
},
|
|
||||||
State: state,
|
|
||||||
})
|
|
||||||
|
|
||||||
result, diags := ctx.Refresh()
|
|
||||||
if diags.HasErrors() {
|
|
||||||
t.Fatalf("plan errors: %s", diags.Err())
|
|
||||||
}
|
|
||||||
|
|
||||||
expect := strings.TrimSpace(`
|
|
||||||
aws_instance.bar:
|
|
||||||
ID = bar
|
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
|
||||||
foo = foo
|
|
||||||
|
|
||||||
Dependencies:
|
|
||||||
aws_instance.foo
|
|
||||||
aws_instance.baz:
|
|
||||||
ID = baz
|
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
|
||||||
|
|
||||||
Dependencies:
|
|
||||||
aws_instance.bam
|
|
||||||
aws_instance.foo:
|
|
||||||
ID = foo
|
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
|
||||||
`)
|
|
||||||
|
|
||||||
checkStateString(t, result, expect)
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify that create_before_destroy is updated in the state during refresh
|
// verify that create_before_destroy is updated in the state during refresh
|
||||||
func TestRefresh_updateLifecycle(t *testing.T) {
|
func TestRefresh_updateLifecycle(t *testing.T) {
|
||||||
state := states.NewState()
|
state := states.NewState()
|
||||||
|
|
|
@ -267,7 +267,7 @@ const (
|
||||||
//
|
//
|
||||||
// targetState determines which context state we're writing to during plan. The
|
// targetState determines which context state we're writing to during plan. The
|
||||||
// default is the global working state.
|
// default is the global working state.
|
||||||
func (n *NodeAbstractResourceInstance) writeResourceInstanceState(ctx EvalContext, obj *states.ResourceInstanceObject, dependencies []addrs.ConfigResource, targetState phaseState) error {
|
func (n *NodeAbstractResourceInstance) writeResourceInstanceState(ctx EvalContext, obj *states.ResourceInstanceObject, targetState phaseState) error {
|
||||||
absAddr := n.Addr
|
absAddr := n.Addr
|
||||||
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
|
_, providerSchema, err := getProvider(ctx, n.ResolvedProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -290,12 +290,6 @@ func (n *NodeAbstractResourceInstance) writeResourceInstanceState(ctx EvalContex
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// store the new deps in the state.
|
|
||||||
// We check for nil here because don't want to override existing dependencies on orphaned nodes.
|
|
||||||
if dependencies != nil {
|
|
||||||
obj.Dependencies = dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
if providerSchema == nil {
|
if providerSchema == nil {
|
||||||
// Should never happen, unless our state object is nil
|
// Should never happen, unless our state object is nil
|
||||||
panic("writeResourceInstanceState used with nil ProviderSchema")
|
panic("writeResourceInstanceState used with nil ProviderSchema")
|
||||||
|
@ -526,8 +520,6 @@ func (n *NodeAbstractResourceInstance) refresh(ctx EvalContext, state *states.Re
|
||||||
ret := state.DeepCopy()
|
ret := state.DeepCopy()
|
||||||
ret.Value = resp.NewState
|
ret.Value = resp.NewState
|
||||||
ret.Private = resp.Private
|
ret.Private = resp.Private
|
||||||
ret.Dependencies = state.Dependencies
|
|
||||||
ret.CreateBeforeDestroy = state.CreateBeforeDestroy
|
|
||||||
|
|
||||||
// Call post-refresh hook
|
// Call post-refresh hook
|
||||||
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
diags = diags.Append(ctx.Hook(func(h Hook) (HookAction, error) {
|
||||||
|
|
|
@ -145,7 +145,7 @@ func TestNodeAbstractResourceInstance_WriteResourceInstanceState(t *testing.T) {
|
||||||
ctx.ProviderProvider = mockProvider
|
ctx.ProviderProvider = mockProvider
|
||||||
ctx.ProviderSchemaSchema = mockProvider.ProviderSchema()
|
ctx.ProviderSchemaSchema = mockProvider.ProviderSchema()
|
||||||
|
|
||||||
err := node.writeResourceInstanceState(ctx, obj, nil, workingState)
|
err := node.writeResourceInstanceState(ctx, obj, workingState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %s", err.Error())
|
t.Fatalf("unexpected error: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,8 +160,7 @@ func (n *NodeApplyableResourceInstance) dataResourceExecute(ctx EvalContext) (di
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't write dependencies for datasources
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState))
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, state, nil, workingState))
|
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
@ -276,7 +275,11 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||||
|
|
||||||
state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err())
|
state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err())
|
||||||
|
|
||||||
err = n.writeResourceInstanceState(ctx, state, n.Dependencies, workingState)
|
if state != nil {
|
||||||
|
// dependencies are always updated to match the configuration during apply
|
||||||
|
state.Dependencies = n.Dependencies
|
||||||
|
}
|
||||||
|
err = n.writeResourceInstanceState(ctx, state, workingState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diags.Append(err)
|
return diags.Append(err)
|
||||||
}
|
}
|
||||||
|
@ -289,7 +292,7 @@ func (n *NodeApplyableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||||
|
|
||||||
state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err())
|
state = maybeTainted(addr.Absolute(ctx.Path()), state, diffApply, diags.Err())
|
||||||
|
|
||||||
err = n.writeResourceInstanceState(ctx, state, n.Dependencies, workingState)
|
err = n.writeResourceInstanceState(ctx, state, workingState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diags.Append(err)
|
return diags.Append(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,7 +215,7 @@ func (n *NodeDestroyResourceInstance) managedResourceExecute(ctx EvalContext) (d
|
||||||
// we don't return immediately here on error, so that the state can be
|
// we don't return immediately here on error, so that the state can be
|
||||||
// finalized
|
// finalized
|
||||||
|
|
||||||
err = n.writeResourceInstanceState(ctx, state, n.Dependencies, workingState)
|
err = n.writeResourceInstanceState(ctx, state, workingState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return diags.Append(err)
|
return diags.Append(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package terraform
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/plans"
|
"github.com/hashicorp/terraform/plans"
|
||||||
"github.com/hashicorp/terraform/states"
|
"github.com/hashicorp/terraform/states"
|
||||||
|
@ -78,11 +79,11 @@ func (n *NodePlannableResourceInstance) dataResourceExecute(ctx EvalContext) (di
|
||||||
|
|
||||||
// write the data source into both the refresh state and the
|
// write the data source into both the refresh state and the
|
||||||
// working state
|
// working state
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, state, nil, refreshState))
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState))
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, state, nil, workingState))
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, workingState))
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
@ -133,9 +134,19 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceRefreshState = s
|
instanceRefreshState = s
|
||||||
|
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, n.Dependencies, refreshState))
|
if instanceRefreshState != nil {
|
||||||
|
// When refreshing we start by merging the stored dependencies and
|
||||||
|
// the configured dependencies. The configured dependencies will be
|
||||||
|
// stored to state once the changes are applied. If the plan
|
||||||
|
// results in no changes, we will re-write these dependencies
|
||||||
|
// below.
|
||||||
|
instanceRefreshState.Dependencies = mergeDeps(n.Dependencies, instanceRefreshState.Dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
@ -153,11 +164,74 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, instancePlanState, n.Dependencies, workingState))
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instancePlanState, workingState))
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this plan resulted in a NoOp, then apply won't have a chance to make
|
||||||
|
// any changes to the stored dependencies. Since this is a NoOp we know
|
||||||
|
// that the stored dependencies will have no effect during apply, and we can
|
||||||
|
// write them out now.
|
||||||
|
if change.Action == plans.NoOp && !depsEqual(instanceRefreshState.Dependencies, n.Dependencies) {
|
||||||
|
// the refresh state will be the final state for this resource, so
|
||||||
|
// finalize the dependencies here if they need to be updated.
|
||||||
|
instanceRefreshState.Dependencies = n.Dependencies
|
||||||
|
diags = diags.Append(n.writeResourceInstanceState(ctx, instanceRefreshState, refreshState))
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
diags = diags.Append(n.writeChange(ctx, change, ""))
|
diags = diags.Append(n.writeChange(ctx, change, ""))
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mergeDeps returns the union of 2 sets of dependencies
|
||||||
|
func mergeDeps(a, b []addrs.ConfigResource) []addrs.ConfigResource {
|
||||||
|
switch {
|
||||||
|
case len(a) == 0:
|
||||||
|
return b
|
||||||
|
case len(b) == 0:
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
set := make(map[string]addrs.ConfigResource)
|
||||||
|
|
||||||
|
for _, dep := range a {
|
||||||
|
set[dep.String()] = dep
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dep := range b {
|
||||||
|
set[dep.String()] = dep
|
||||||
|
}
|
||||||
|
|
||||||
|
newDeps := make([]addrs.ConfigResource, 0, len(set))
|
||||||
|
for _, dep := range set {
|
||||||
|
newDeps = append(newDeps, dep)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDeps
|
||||||
|
}
|
||||||
|
|
||||||
|
func depsEqual(a, b []addrs.ConfigResource) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
less := func(s []addrs.ConfigResource) func(i, j int) bool {
|
||||||
|
return func(i, j int) bool {
|
||||||
|
return s[i].String() < s[j].String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(a, less(a))
|
||||||
|
sort.Slice(b, less(b))
|
||||||
|
|
||||||
|
for i := range a {
|
||||||
|
if !a[i].Equal(b[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, state, n.Dependencies, refreshState))
|
diags = diags.Append(n.writeResourceInstanceState(ctx, state, refreshState))
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,6 @@ func (n *NodePlannableResourceInstanceOrphan) managedResourceExecute(ctx EvalCon
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
diags = diags.Append(n.writeResourceInstanceState(ctx, nil, n.Dependencies, workingState))
|
diags = diags.Append(n.writeResourceInstanceState(ctx, nil, workingState))
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,6 +281,6 @@ func (n *graphNodeImportStateSub) Execute(ctx EvalContext, op walkOperation) (di
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
diags = diags.Append(riNode.writeResourceInstanceState(ctx, state, nil, workingState))
|
diags = diags.Append(riNode.writeResourceInstanceState(ctx, state, workingState))
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue