failing test for module instance replace cycle
Destroy-time references are not correctly or fully inverted when crossing module boundaries, causing cycle during apply.
This commit is contained in:
parent
470362b051
commit
3eb0e74ef9
|
@ -10602,3 +10602,148 @@ func TestContext2Apply_invalidIndexRef(t *testing.T) {
|
|||
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErr, wantErr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Apply_moduleReplaceCycle(t *testing.T) {
|
||||
for _, mode := range []string{"normal", "cbd"} {
|
||||
var m *configs.Config
|
||||
|
||||
switch mode {
|
||||
case "normal":
|
||||
m = testModule(t, "apply-module-replace-cycle")
|
||||
case "cbd":
|
||||
m = testModule(t, "apply-module-replace-cycle-cbd")
|
||||
}
|
||||
|
||||
p := testProvider("aws")
|
||||
p.DiffFn = testDiffFn
|
||||
p.ApplyFn = testApplyFn
|
||||
|
||||
instanceSchema := &configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"id": {Type: cty.String, Computed: true},
|
||||
"require_new": {Type: cty.String, Optional: true},
|
||||
},
|
||||
}
|
||||
|
||||
p.GetSchemaReturn = &ProviderSchema{
|
||||
ResourceTypes: map[string]*configschema.Block{
|
||||
"aws_instance": instanceSchema,
|
||||
},
|
||||
}
|
||||
|
||||
state := states.NewState()
|
||||
modA := state.EnsureModule(addrs.RootModuleInstance.Child("a", addrs.NoKey))
|
||||
modA.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "aws_instance",
|
||||
Name: "a",
|
||||
}.Instance(addrs.NoKey),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
Status: states.ObjectReady,
|
||||
AttrsJSON: []byte(`{"id":"a","require_new":"old"}`),
|
||||
},
|
||||
addrs.ProviderConfig{
|
||||
Type: "aws",
|
||||
}.Absolute(addrs.RootModuleInstance),
|
||||
)
|
||||
|
||||
modB := state.EnsureModule(addrs.RootModuleInstance.Child("b", addrs.NoKey))
|
||||
modB.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "aws_instance",
|
||||
Name: "b",
|
||||
}.Instance(addrs.IntKey(0)),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
Status: states.ObjectReady,
|
||||
AttrsJSON: []byte(`{"id":"b","require_new":"old"}`),
|
||||
},
|
||||
addrs.ProviderConfig{
|
||||
Type: "aws",
|
||||
}.Absolute(addrs.RootModuleInstance),
|
||||
)
|
||||
|
||||
aBefore, _ := plans.NewDynamicValue(
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("a"),
|
||||
"require_new": cty.StringVal("old"),
|
||||
}), instanceSchema.ImpliedType())
|
||||
aAfter, _ := plans.NewDynamicValue(
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
"require_new": cty.StringVal("new"),
|
||||
}), instanceSchema.ImpliedType())
|
||||
bBefore, _ := plans.NewDynamicValue(
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.StringVal("b"),
|
||||
"require_new": cty.StringVal("old"),
|
||||
}), instanceSchema.ImpliedType())
|
||||
bAfter, _ := plans.NewDynamicValue(
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
"require_new": cty.UnknownVal(cty.String),
|
||||
}), instanceSchema.ImpliedType())
|
||||
|
||||
var aAction plans.Action
|
||||
switch mode {
|
||||
case "normal":
|
||||
aAction = plans.DeleteThenCreate
|
||||
case "cbd":
|
||||
aAction = plans.CreateThenDelete
|
||||
}
|
||||
|
||||
changes := &plans.Changes{
|
||||
Resources: []*plans.ResourceInstanceChangeSrc{
|
||||
{
|
||||
Addr: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "aws_instance",
|
||||
Name: "a",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("a", addrs.NoKey)),
|
||||
ProviderAddr: addrs.ProviderConfig{
|
||||
Type: "aws",
|
||||
}.Absolute(addrs.RootModuleInstance),
|
||||
ChangeSrc: plans.ChangeSrc{
|
||||
Action: aAction,
|
||||
Before: aBefore,
|
||||
After: aAfter,
|
||||
},
|
||||
},
|
||||
{
|
||||
Addr: addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "aws_instance",
|
||||
Name: "b",
|
||||
}.Instance(addrs.IntKey(0)).Absolute(addrs.RootModuleInstance.Child("b", addrs.NoKey)),
|
||||
ProviderAddr: addrs.ProviderConfig{
|
||||
Type: "aws",
|
||||
}.Absolute(addrs.RootModuleInstance),
|
||||
ChangeSrc: plans.ChangeSrc{
|
||||
Action: plans.DeleteThenCreate,
|
||||
Before: bBefore,
|
||||
After: bAfter,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Config: m,
|
||||
ProviderResolver: providers.ResolverFixed(
|
||||
map[string]providers.Factory{
|
||||
"aws": testProviderFuncFixed(p),
|
||||
},
|
||||
),
|
||||
State: state,
|
||||
Changes: changes,
|
||||
})
|
||||
|
||||
t.Run(mode, func(t *testing.T) {
|
||||
_, diags := ctx.Apply()
|
||||
if diags.HasErrors() {
|
||||
t.Fatal(diags.Err())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
module "a" {
|
||||
source = "./mod1"
|
||||
}
|
||||
|
||||
module "b" {
|
||||
source = "./mod2"
|
||||
ids = module.a.ids
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
resource "aws_instance" "a" {
|
||||
require_new = "new"
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
output "ids" {
|
||||
value = [aws_instance.a.id]
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
resource "aws_instance" "b" {
|
||||
count = length(var.ids)
|
||||
require_new = var.ids[count.index]
|
||||
}
|
||||
|
||||
variable "ids" {
|
||||
type = list(string)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
module "a" {
|
||||
source = "./mod1"
|
||||
}
|
||||
|
||||
module "b" {
|
||||
source = "./mod2"
|
||||
ids = module.a.ids
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
resource "aws_instance" "a" {
|
||||
require_new = "new"
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
output "ids" {
|
||||
value = [aws_instance.a.id]
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
resource "aws_instance" "b" {
|
||||
count = length(var.ids)
|
||||
require_new = var.ids[count.index]
|
||||
}
|
||||
|
||||
variable "ids" {
|
||||
type = list(string)
|
||||
}
|
Loading…
Reference in New Issue