2015-07-10 22:08:49 +02:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2019-06-01 03:09:20 +02:00
|
|
|
"errors"
|
2015-07-10 22:08:49 +02:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
2018-05-05 04:24:06 +02:00
|
|
|
|
2018-05-23 02:53:56 +02:00
|
|
|
"github.com/davecgh/go-spew/spew"
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
"github.com/google/go-cmp/cmp"
|
2018-05-05 04:24:06 +02:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2021-05-17 21:00:50 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/addrs"
|
2021-05-17 21:17:09 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/configs/configschema"
|
|
|
|
"github.com/hashicorp/terraform/internal/configs/hcl2shim"
|
2021-05-17 19:40:40 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/providers"
|
2021-05-17 19:51:48 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/provisioners"
|
2021-05-17 19:11:06 +02:00
|
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
2018-09-28 02:57:08 +02:00
|
|
|
"github.com/hashicorp/terraform/plans"
|
|
|
|
"github.com/hashicorp/terraform/states"
|
2015-07-10 22:08:49 +02:00
|
|
|
)
|
|
|
|
|
2016-11-06 08:00:05 +01:00
|
|
|
func TestContext2Plan_basic(t *testing.T) {
|
2015-07-10 22:08:49 +02:00
|
|
|
m := testModule(t, "plan-good")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2017-06-06 02:08:02 +02:00
|
|
|
ProviderSHA256s: map[string][]byte{
|
|
|
|
"aws": []byte("placeholder"),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if l := len(plan.Changes.Resources); l < 2 {
|
|
|
|
t.Fatalf("wrong number of resources %d; want fewer than two\n%s", l, spew.Sdump(plan.Changes.Resources))
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2017-06-06 02:08:02 +02:00
|
|
|
if !reflect.DeepEqual(plan.ProviderSHA256s, ctx.providerSHA256s) {
|
|
|
|
t.Errorf("wrong ProviderSHA256s %#v; want %#v", plan.ProviderSHA256s, ctx.providerSHA256s)
|
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if !ctx.State().Empty() {
|
|
|
|
t.Fatalf("expected empty state, got %#v\n", ctx.State())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
for _, r := range plan.Changes.Resources {
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := r.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
2018-09-19 00:44:51 +02:00
|
|
|
foo := ric.After.GetAttr("foo").AsString()
|
2018-09-15 00:40:09 +02:00
|
|
|
if foo != "2" {
|
2018-09-19 00:44:51 +02:00
|
|
|
t.Fatalf("incorrect plan for 'bar': %#v", ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
}
|
|
|
|
case "aws_instance.foo":
|
2018-09-19 00:44:51 +02:00
|
|
|
num, _ := ric.After.GetAttr("num").AsBigFloat().Int64()
|
2018-09-18 01:25:11 +02:00
|
|
|
if num != 2 {
|
2018-09-19 00:44:51 +02:00
|
|
|
t.Fatalf("incorrect plan for 'foo': %#v", ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2020-11-03 00:23:00 +01:00
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
if !p.ValidateProviderConfigCalled {
|
2020-11-03 00:23:00 +01:00
|
|
|
t.Fatal("provider config was not checked before Configure")
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2016-11-28 22:35:29 +01:00
|
|
|
func TestContext2Plan_createBefore_deposed(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-cbd")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2016-11-28 22:35:29 +01:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
|
2016-11-28 22:35:29 +01:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceDeposed(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
states.DeposedKey("00000001"),
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"foo"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
2016-11-28 22:35:29 +01:00
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2016-11-28 22:35:29 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-11-28 22:35:29 +01:00
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
// the state should still show one deposed
|
|
|
|
expectedState := strings.TrimSpace(`
|
|
|
|
aws_instance.foo: (1 deposed)
|
|
|
|
ID = baz
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
2020-10-08 14:56:03 +02:00
|
|
|
type = aws_instance
|
2018-09-18 01:25:11 +02:00
|
|
|
Deposed ID 1 = foo`)
|
2016-11-28 22:35:29 +01:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if ctx.State().String() != expectedState {
|
|
|
|
t.Fatalf("\nexpected: %q\ngot: %q\n", expectedState, ctx.State().String())
|
|
|
|
}
|
2016-11-28 22:35:29 +01:00
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-11-28 22:35:29 +01:00
|
|
|
|
2018-09-21 01:09:02 +02:00
|
|
|
type InstanceGen struct {
|
2018-09-24 21:14:32 +02:00
|
|
|
Addr string
|
2018-09-21 01:09:02 +02:00
|
|
|
DeposedKey states.DeposedKey
|
2018-09-15 00:40:09 +02:00
|
|
|
}
|
2018-09-21 01:09:02 +02:00
|
|
|
want := map[InstanceGen]bool{
|
|
|
|
{
|
|
|
|
Addr: "aws_instance.foo",
|
|
|
|
}: true,
|
|
|
|
{
|
2018-09-24 21:14:32 +02:00
|
|
|
Addr: "aws_instance.foo",
|
2018-09-21 01:09:02 +02:00
|
|
|
DeposedKey: states.DeposedKey("00000001"),
|
|
|
|
}: true,
|
|
|
|
}
|
|
|
|
got := make(map[InstanceGen]bool)
|
|
|
|
changes := make(map[InstanceGen]*plans.ResourceInstanceChangeSrc)
|
2018-09-15 00:40:09 +02:00
|
|
|
|
2018-09-21 01:09:02 +02:00
|
|
|
for _, change := range plan.Changes.Resources {
|
|
|
|
k := InstanceGen{
|
|
|
|
Addr: change.Addr.String(),
|
|
|
|
DeposedKey: change.DeposedKey,
|
|
|
|
}
|
|
|
|
got[k] = true
|
|
|
|
changes[k] = change
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(got, want) {
|
|
|
|
t.Fatalf("wrong resource instance object changes in plan\ngot: %s\nwant: %s", spew.Sdump(got), spew.Sdump(want))
|
2018-09-15 00:40:09 +02:00
|
|
|
}
|
|
|
|
|
2018-09-21 01:09:02 +02:00
|
|
|
{
|
2018-09-24 21:14:32 +02:00
|
|
|
ric, err := changes[InstanceGen{Addr: "aws_instance.foo"}].Decode(ty)
|
2018-09-21 01:09:02 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := ric.Action, plans.NoOp; got != want {
|
|
|
|
t.Errorf("current object change action is %s; want %s", got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
// the existing instance should only have an unchanged id
|
2020-10-08 14:56:03 +02:00
|
|
|
expected, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("baz"),
|
|
|
|
"type": cty.StringVal("aws_instance"),
|
|
|
|
}))
|
2018-09-21 01:09:02 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkVals(t, expected, ric.After)
|
2016-11-28 22:35:29 +01:00
|
|
|
}
|
2018-09-15 00:40:09 +02:00
|
|
|
|
2018-09-21 01:09:02 +02:00
|
|
|
{
|
2018-09-24 21:14:32 +02:00
|
|
|
ric, err := changes[InstanceGen{Addr: "aws_instance.foo", DeposedKey: states.DeposedKey("00000001")}].Decode(ty)
|
2018-09-21 01:09:02 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := ric.Action, plans.Delete; got != want {
|
|
|
|
t.Errorf("deposed object change action is %s; want %s", got, want)
|
|
|
|
}
|
|
|
|
}
|
2016-11-28 22:35:29 +01:00
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-cbd-maintain-root")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if !ctx.State().Empty() {
|
|
|
|
t.Fatal("expected empty state, got:", ctx.State())
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if len(plan.Changes.Resources) != 4 {
|
|
|
|
t.Error("expected 4 resource in plan, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
// these should all be creates
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("unexpected action %s for %s", res.Action, res.Addr.String())
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_emptyDiff(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-empty")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
2020-10-08 14:56:03 +02:00
|
|
|
resp.PlannedState = req.ProposedNewState
|
|
|
|
return resp
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if !ctx.State().Empty() {
|
|
|
|
t.Fatal("expected empty state, got:", ctx.State())
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
actions := map[string]plans.Action{}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
actions[res.Addr.String()] = res.Action
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := map[string]plans.Action{
|
|
|
|
"aws_instance.foo": plans.Create,
|
|
|
|
"aws_instance.bar": plans.Create,
|
|
|
|
}
|
|
|
|
if !cmp.Equal(expected, actions) {
|
|
|
|
t.Fatal(cmp.Diff(expected, actions))
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-19 21:37:55 +01:00
|
|
|
func TestContext2Plan_escapedVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-escaped-var")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2016-01-19 21:37:55 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-01-19 21:37:55 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-01-19 21:37:55 +01:00
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Error("expected 1 resource in plan, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
res := plan.Changes.Resources[0]
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2016-01-19 21:37:55 +01:00
|
|
|
}
|
2018-09-15 00:40:09 +02:00
|
|
|
|
|
|
|
expected := objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("bar-${baz}"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
|
|
|
})
|
2018-09-15 00:40:09 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, expected, ric.After)
|
2016-01-19 21:37:55 +01:00
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_minimal(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-empty")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if !ctx.State().Empty() {
|
|
|
|
t.Fatal("expected empty state, got:", ctx.State())
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
actions := map[string]plans.Action{}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
actions[res.Addr.String()] = res.Action
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := map[string]plans.Action{
|
|
|
|
"aws_instance.foo": plans.Create,
|
|
|
|
"aws_instance.bar": plans.Create,
|
|
|
|
}
|
|
|
|
if !cmp.Equal(expected, actions) {
|
|
|
|
t.Fatal(cmp.Diff(expected, actions))
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_modules(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-modules")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if len(plan.Changes.Resources) != 3 {
|
|
|
|
t.Error("expected 3 resource in plan, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
expectFoo := objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("2"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
|
|
|
})
|
2018-09-15 00:40:09 +02:00
|
|
|
|
|
|
|
expectNum := objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
|
|
|
})
|
2018-09-15 00:40:09 +02:00
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var expected cty.Value
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
expected = expectFoo
|
|
|
|
case "aws_instance.foo":
|
|
|
|
expected = expectNum
|
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
expected = expectNum
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, expected, ric.After)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
2020-03-25 20:29:34 +01:00
|
|
|
func TestContext2Plan_moduleExpand(t *testing.T) {
|
|
|
|
// Test a smattering of plan expansion behavior
|
|
|
|
m := testModule(t, "plan-modules-expand")
|
2020-02-24 23:42:32 +01:00
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2020-02-24 23:42:32 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2020-02-24 23:42:32 +01:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
2020-03-25 20:29:34 +01:00
|
|
|
expected := map[string]struct{}{
|
|
|
|
`aws_instance.foo["a"]`: struct{}{},
|
|
|
|
`module.count_child[1].aws_instance.foo[0]`: struct{}{},
|
|
|
|
`module.count_child[1].aws_instance.foo[1]`: struct{}{},
|
|
|
|
`module.count_child[0].aws_instance.foo[0]`: struct{}{},
|
|
|
|
`module.count_child[0].aws_instance.foo[1]`: struct{}{},
|
|
|
|
`module.for_each_child["a"].aws_instance.foo[1]`: struct{}{},
|
|
|
|
`module.for_each_child["a"].aws_instance.foo[0]`: struct{}{},
|
|
|
|
}
|
2020-02-24 23:42:32 +01:00
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2020-03-25 20:29:34 +01:00
|
|
|
_, ok := expected[ric.Addr.String()]
|
|
|
|
if !ok {
|
|
|
|
t.Fatal("unexpected resource:", ric.Addr.String())
|
2020-02-24 23:42:32 +01:00
|
|
|
}
|
2020-03-25 20:29:34 +01:00
|
|
|
delete(expected, ric.Addr.String())
|
|
|
|
}
|
|
|
|
for addr := range expected {
|
|
|
|
t.Error("missing resource", addr)
|
2020-02-24 23:42:32 +01:00
|
|
|
}
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
|
|
|
// GH-1475
|
|
|
|
func TestContext2Plan_moduleCycle(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-cycle")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
2018-05-23 18:59:03 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
"some_input": {Type: cty.String, Optional: true},
|
2019-02-12 02:05:24 +01:00
|
|
|
"type": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var expected cty.Value
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.b":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
|
|
|
case "aws_instance.c":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"some_input": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, expected, ric.After)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleDeadlock(t *testing.T) {
|
2015-08-10 22:03:02 +02:00
|
|
|
testCheckDeadlock(t, func() {
|
|
|
|
m := testModule(t, "plan-module-deadlock")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-08-10 22:03:02 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, err := ctx.Plan()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
expected := objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.foo[0]":
|
|
|
|
case "module.child.aws_instance.foo[1]":
|
|
|
|
case "module.child.aws_instance.foo[2]":
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, expected, ric.After)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2015-08-10 22:03:02 +02:00
|
|
|
})
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleInput(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-input")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var expected cty.Value
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("2"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("42"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, expected, ric.After)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleInputComputed(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-input-computed")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2019-02-12 02:05:24 +01:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2019-02-12 02:05:24 +01:00
|
|
|
"compute": cty.StringVal("foo"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleInputFromVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-input-var")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Variables: InputValues{
|
|
|
|
"foo": &InputValue{
|
|
|
|
Value: cty.StringVal("52"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("2"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("52"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleMultiVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-multi-var")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
"baz": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 5 {
|
|
|
|
t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.parent[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.parent[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.bar[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"baz": cty.StringVal("baz"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.bar[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"baz": cty.StringVal("baz"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("baz,baz"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleOrphans(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-modules-remove")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
|
|
|
child.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"baz"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("expected resource delete, got %s", res.Action)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
expectedState := `<no state>
|
|
|
|
module.child:
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = baz
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]`
|
2018-09-15 00:40:09 +02:00
|
|
|
|
|
|
|
if ctx.State().String() != expectedState {
|
|
|
|
t.Fatalf("\nexpected state: %q\n\ngot: %q", expectedState, ctx.State().String())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
// https://github.com/hashicorp/terraform/issues/3114
|
|
|
|
func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-modules-remove-provisioners")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2021-01-12 18:39:25 +01:00
|
|
|
pr := testProvisioner()
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.top").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"top","type":"aws_instance"}`),
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
child1 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child1", addrs.NoKey))
|
|
|
|
child1.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
child2 := state.EnsureModule(addrs.RootModuleInstance.Child("parent", addrs.NoKey).Child("child2", addrs.NoKey))
|
|
|
|
child2.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"baz","type":"aws_instance"}`),
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2020-11-13 18:43:28 +01:00
|
|
|
Provisioners: map[string]provisioners.Factory{
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
State: state,
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 3 {
|
|
|
|
t.Error("expected 3 planned resources, got", len(plan.Changes.Resources))
|
|
|
|
}
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2020-03-31 20:03:33 +02:00
|
|
|
case "module.parent.module.child1.aws_instance.foo":
|
2018-09-15 00:40:09 +02:00
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("expected resource Delete, got %s", res.Action)
|
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
case "module.parent.module.child2.aws_instance.foo":
|
2018-09-15 00:40:09 +02:00
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("expected resource Delete, got %s", res.Action)
|
|
|
|
}
|
|
|
|
case "aws_instance.top":
|
|
|
|
if res.Action != plans.NoOp {
|
2020-03-31 20:03:33 +02:00
|
|
|
t.Fatalf("expected no changes, got %s", res.Action)
|
2018-09-15 00:40:09 +02:00
|
|
|
}
|
|
|
|
default:
|
2018-09-19 00:44:51 +02:00
|
|
|
t.Fatalf("unknown instance: %s\nafter: %#v", i, hcl2shim.ConfigValueFromHCL2(ric.After))
|
2018-09-15 00:40:09 +02:00
|
|
|
}
|
|
|
|
}
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
expectedState := `aws_instance.top:
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
ID = top
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
2020-10-08 14:56:03 +02:00
|
|
|
type = aws_instance
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
module.parent.child1:
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
aws_instance.foo:
|
|
|
|
ID = baz
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
2020-10-08 14:56:03 +02:00
|
|
|
type = aws_instance
|
2020-03-31 20:03:33 +02:00
|
|
|
module.parent.child2:
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
aws_instance.foo:
|
|
|
|
ID = baz
|
2020-10-08 14:56:03 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
|
|
|
type = aws_instance`
|
2018-09-15 00:40:09 +02:00
|
|
|
|
|
|
|
if expectedState != ctx.State().String() {
|
2020-03-31 20:03:33 +02:00
|
|
|
t.Fatalf("\nexpect state:\n%s\n\ngot state:\n%s\n", expectedState, ctx.State().String())
|
core: fix bug detecting deeply nested module orphans
Context:
As part of building up a Plan, Terraform needs to detect "orphaned"
resources--resources which are present in the state but not in the
config. This happens when config for those resources is removed by the
user, making it Terraform's responsibility to destroy them.
Both state and config are organized by Module into a logical tree, so
the process of finding orphans involves checking for orphaned Resources
in the current module and for orphaned Modules, which themselves will
have all their Resources marked as orphans.
Bug:
In #3114 a problem was exposed where, given a module tree that looked
like this:
```
root
|
+-- parent (empty, except for sub-modules)
|
+-- child1 (1 resource)
|
+-- child2 (1 resource)
```
If `parent` was removed, a bunch of error messages would occur during
the plan. The root cause of this was duplicate orphans appearing for the
resources in child1 and child2.
Fix:
This turned out to be a bug in orphaned module detection. When looking
for deeply nested orphaned modules, root.parent was getting added twice
as an orphaned module to the graph.
Here, we add an additional check to prevent a double add, which
addresses this scenario properly.
Fixes #3114 (the Provisioner side of it was fixed in #4877)
2016-02-05 19:19:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_moduleProviderInherit(t *testing.T) {
|
|
|
|
var l sync.Mutex
|
|
|
|
var calls []string
|
|
|
|
|
|
|
|
m := testModule(t, "plan-module-provider-inherit")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-03-31 20:03:33 +02:00
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"from": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
2018-05-23 02:53:56 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"from": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
2020-10-08 18:26:12 +02:00
|
|
|
from := req.Config.GetAttr("from")
|
|
|
|
if from.IsNull() || from.AsString() != "root" {
|
|
|
|
resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root"))
|
2018-05-23 02:53:56 +02:00
|
|
|
}
|
2017-04-22 02:40:46 +02:00
|
|
|
|
2020-10-08 18:26:12 +02:00
|
|
|
return
|
2020-03-31 20:03:33 +02:00
|
|
|
}
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
2020-10-08 14:56:03 +02:00
|
|
|
from := req.Config.GetAttr("from").AsString()
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
2020-10-08 14:56:03 +02:00
|
|
|
calls = append(calls, from)
|
|
|
|
return testDiffFn(req)
|
2020-03-31 20:03:33 +02:00
|
|
|
}
|
|
|
|
return p, nil
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, err := ctx.Plan()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := calls
|
|
|
|
sort.Strings(actual)
|
|
|
|
expected := []string{"child", "root"}
|
|
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
|
|
t.Fatalf("bad: %#v", actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-24 21:56:13 +01:00
|
|
|
// This tests (for GH-11282) that deeply nested modules properly inherit
|
|
|
|
// configuration.
|
|
|
|
func TestContext2Plan_moduleProviderInheritDeep(t *testing.T) {
|
|
|
|
var l sync.Mutex
|
|
|
|
|
|
|
|
m := testModule(t, "plan-module-provider-inherit-deep")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
|
|
|
|
var from string
|
|
|
|
p := testProvider("aws")
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-03-31 20:03:33 +02:00
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"from": {Type: cty.String, Optional: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2017-04-22 02:40:46 +02:00
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
2020-10-08 18:26:12 +02:00
|
|
|
v := req.Config.GetAttr("from")
|
|
|
|
if v.IsNull() || v.AsString() != "root" {
|
|
|
|
resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("not root"))
|
2017-01-24 21:56:13 +01:00
|
|
|
}
|
2020-10-08 18:26:12 +02:00
|
|
|
from = v.AsString()
|
2017-01-24 21:56:13 +01:00
|
|
|
|
2020-10-08 18:26:12 +02:00
|
|
|
return
|
2020-03-31 20:03:33 +02:00
|
|
|
}
|
2017-01-24 21:56:13 +01:00
|
|
|
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
2020-03-31 20:03:33 +02:00
|
|
|
if from != "root" {
|
2020-10-08 14:56:03 +02:00
|
|
|
resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("bad resource"))
|
|
|
|
return
|
2017-01-24 21:56:13 +01:00
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
|
2020-10-08 14:56:03 +02:00
|
|
|
return testDiffFn(req)
|
2020-03-31 20:03:33 +02:00
|
|
|
}
|
|
|
|
return p, nil
|
2017-01-24 21:56:13 +01:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
2017-01-24 21:56:13 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
_, err := ctx.Plan()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
|
|
|
|
var l sync.Mutex
|
|
|
|
var calls []string
|
|
|
|
|
|
|
|
m := testModule(t, "plan-module-provider-defaults-var")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): func() (providers.Interface, error) {
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-03-31 20:03:33 +02:00
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"to": {Type: cty.String, Optional: true},
|
|
|
|
"from": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
2018-05-23 02:53:56 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"from": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
2020-03-31 20:03:33 +02:00
|
|
|
var buf bytes.Buffer
|
2020-10-08 18:26:12 +02:00
|
|
|
from := req.Config.GetAttr("from")
|
|
|
|
if !from.IsNull() {
|
|
|
|
buf.WriteString(from.AsString() + "\n")
|
2018-05-23 02:53:56 +02:00
|
|
|
}
|
2020-10-08 18:26:12 +02:00
|
|
|
to := req.Config.GetAttr("to")
|
|
|
|
if !to.IsNull() {
|
|
|
|
buf.WriteString(to.AsString() + "\n")
|
2017-04-22 02:40:46 +02:00
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
|
|
|
calls = append(calls, buf.String())
|
2020-10-08 18:26:12 +02:00
|
|
|
return
|
2020-03-31 20:03:33 +02:00
|
|
|
}
|
2020-10-08 18:26:12 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
return p, nil
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Variables: InputValues{
|
|
|
|
"foo": &InputValue{
|
|
|
|
Value: cty.StringVal("root"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
_, err := ctx.Plan()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := []string{
|
2017-10-13 16:11:10 +02:00
|
|
|
"child\nchild\n",
|
2017-11-01 23:34:18 +01:00
|
|
|
"root\n",
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2017-11-01 23:34:18 +01:00
|
|
|
sort.Strings(calls)
|
2015-07-10 22:08:49 +02:00
|
|
|
if !reflect.DeepEqual(calls, expected) {
|
2017-10-13 16:11:10 +02:00
|
|
|
t.Fatalf("expected:\n%#v\ngot:\n%#v\n", expected, calls)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 06:22:21 +01:00
|
|
|
func TestContext2Plan_moduleProviderVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-provider-var")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"value": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"value": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2016-12-14 06:22:21 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-12-14 06:22:21 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-12-14 06:22:21 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.test":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"value": cty.StringVal("hello"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-12-14 06:22:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_moduleVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-var")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var expected cty.Value
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("2"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-15 00:40:09 +02:00
|
|
|
})
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, expected, ric.After)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-07 22:55:35 +01:00
|
|
|
func TestContext2Plan_moduleVarWrongTypeBasic(t *testing.T) {
|
2016-04-15 21:07:54 +02:00
|
|
|
m := testModule(t, "plan-module-wrong-var-type")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-04-15 21:07:54 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("succeeded; want errors")
|
2016-04-15 21:07:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleVarWrongTypeNested(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-wrong-var-type-nested")
|
2017-04-22 02:40:46 +02:00
|
|
|
p := testProvider("null")
|
2016-04-15 21:07:54 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-04-15 21:07:54 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("succeeded; want errors")
|
2016-04-15 21:07:54 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-22 06:30:34 +02:00
|
|
|
func TestContext2Plan_moduleVarWithDefaultValue(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-var-with-default-value")
|
|
|
|
p := testProvider("null")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-04-22 06:30:34 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-04-22 06:30:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_moduleVarComputed(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-var-computed")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-15 00:40:09 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-15 00:40:09 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-15 00:40:09 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
case "module.child.aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2019-02-12 02:05:24 +01:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2019-02-12 02:05:24 +01:00
|
|
|
"compute": cty.StringVal("foo"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-15 00:40:09 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_preventDestroy_bad(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-prevent-destroy-bad")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, err := ctx.Plan()
|
|
|
|
|
2018-05-22 20:45:07 +02:00
|
|
|
expectedErr := "aws_instance.foo has lifecycle.prevent_destroy"
|
2015-07-10 22:08:49 +02:00
|
|
|
if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if plan != nil {
|
|
|
|
t.Logf(legacyDiffComparisonString(plan.Changes))
|
|
|
|
}
|
|
|
|
t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_preventDestroy_good(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-prevent-destroy-good")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123","type":"aws_instance"}`),
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2018-05-21 20:32:43 +02:00
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if !plan.Changes.Empty() {
|
2018-09-15 00:40:09 +02:00
|
|
|
t.Fatalf("expected no changes, got %#v\n", plan.Changes)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-29 03:31:47 +02:00
|
|
|
func TestContext2Plan_preventDestroy_countBad(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-prevent-destroy-count-bad")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc345"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-10-29 03:31:47 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2016-10-29 03:31:47 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, err := ctx.Plan()
|
|
|
|
|
2018-05-22 20:45:07 +02:00
|
|
|
expectedErr := "aws_instance.foo[1] has lifecycle.prevent_destroy"
|
2016-10-29 03:31:47 +02:00
|
|
|
if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if plan != nil {
|
|
|
|
t.Logf(legacyDiffComparisonString(plan.Changes))
|
|
|
|
}
|
|
|
|
t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, err)
|
2016-10-29 03:31:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_preventDestroy_countGood(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-prevent-destroy-count-good")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"current": {Type: cty.String, Optional: true},
|
2020-03-31 20:03:33 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc345"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-10-29 03:31:47 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2016-10-29 03:31:47 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-10-29 03:31:47 +02:00
|
|
|
}
|
2018-05-21 20:32:43 +02:00
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if plan.Changes.Empty() {
|
|
|
|
t.Fatalf("Expected non-empty plan, got %s", legacyDiffComparisonString(plan.Changes))
|
2016-10-29 03:31:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_preventDestroy_countGoodNoChange(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-prevent-destroy-count-good")
|
|
|
|
p := testProvider("aws")
|
2021-01-12 18:39:25 +01:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"current": {Type: cty.String, Optional: true},
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": {Type: cty.String, Optional: true, Computed: true},
|
2020-03-31 20:03:33 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123","current":"0","type":"aws_instance"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-10-29 03:31:47 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2016-10-29 03:31:47 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-10-29 03:31:47 +02:00
|
|
|
}
|
2018-05-21 20:32:43 +02:00
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if !plan.Changes.Empty() {
|
|
|
|
t.Fatalf("Expected empty plan, got %s", legacyDiffComparisonString(plan.Changes))
|
2016-10-29 03:31:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-prevent-destroy-good")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
plan, diags := ctx.Plan()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-05-22 20:45:07 +02:00
|
|
|
expectedErr := "aws_instance.foo has lifecycle.prevent_destroy"
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if !strings.Contains(fmt.Sprintf("%s", diags.Err()), expectedErr) {
|
|
|
|
if plan != nil {
|
|
|
|
t.Logf(legacyDiffComparisonString(plan.Changes))
|
|
|
|
}
|
|
|
|
t.Fatalf("expected err would contain %q\nerr: %s", expectedErr, diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-30 22:27:08 +01:00
|
|
|
func TestContext2Plan_provisionerCycle(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-provisioner-cycle")
|
|
|
|
p := testProvider("aws")
|
|
|
|
pr := testProvisioner()
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2020-11-13 18:43:28 +01:00
|
|
|
Provisioners: map[string]provisioners.Factory{
|
2016-10-30 22:27:08 +01:00
|
|
|
"local-exec": testProvisionerFuncFixed(pr),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("succeeded; want errors")
|
2016-10-30 22:27:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_computed(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2019-02-12 02:05:24 +01:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2019-02-12 02:05:24 +01:00
|
|
|
"compute": cty.StringVal("foo"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-09 00:32:53 +02:00
|
|
|
func TestContext2Plan_blockNestingGroup(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-block-nesting-group")
|
|
|
|
p := testProvider("test")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2019-04-09 00:32:53 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test": {
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"blah": {
|
|
|
|
Nesting: configschema.NestingGroup,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"baz": {Type: cty.String, Required: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2019-04-09 00:32:53 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
|
|
|
return providers.PlanResourceChangeResponse{
|
|
|
|
PlannedState: req.ProposedNewState,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
2019-04-09 00:32:53 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := 1, len(plan.Changes.Resources); got != want {
|
|
|
|
t.Fatalf("wrong number of planned resource changes %d; want %d\n%s", got, want, spew.Sdump(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
if !p.PlanResourceChangeCalled {
|
|
|
|
t.Fatalf("PlanResourceChange was not called at all")
|
|
|
|
}
|
|
|
|
|
|
|
|
got := p.PlanResourceChangeRequest
|
|
|
|
want := providers.PlanResourceChangeRequest{
|
|
|
|
TypeName: "test",
|
|
|
|
|
|
|
|
// Because block type "blah" is defined as NestingGroup, we get a non-null
|
|
|
|
// value for it with null nested attributes, rather than the "blah" object
|
|
|
|
// itself being null, when there's no "blah" block in the config at all.
|
|
|
|
//
|
|
|
|
// This represents the situation where the remote service _always_ creates
|
|
|
|
// a single "blah", regardless of whether the block is present, but when
|
|
|
|
// the block _is_ present the user can override some aspects of it. The
|
|
|
|
// absense of the block means "use the defaults", in that case.
|
|
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"blah": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"baz": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"blah": cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"baz": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
if !cmp.Equal(got, want, valueTrans) {
|
|
|
|
t.Errorf("wrong PlanResourceChange request\n%s", cmp.Diff(got, want, valueTrans))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-21 22:00:46 +02:00
|
|
|
func TestContext2Plan_computedDataResource(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-data-resource")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"num": {Type: cty.String, Optional: true},
|
|
|
|
"compute": {Type: cty.String, Optional: true},
|
|
|
|
"foo": {Type: cty.String, Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
|
|
|
"aws_vpc": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2016-05-21 22:00:46 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-05-21 22:00:46 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-05-21 22:00:46 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.DataSources["aws_vpc"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-05-21 22:00:46 +02:00
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if rc := plan.Changes.ResourceInstance(addrs.Resource{Mode: addrs.ManagedResourceMode, Type: "aws_instance", Name: "foo"}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance)); rc == nil {
|
2016-05-21 22:00:46 +02:00
|
|
|
t.Fatalf("missing diff for aws_instance.foo")
|
|
|
|
}
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
rcs := plan.Changes.ResourceInstance(addrs.Resource{
|
|
|
|
Mode: addrs.DataResourceMode,
|
|
|
|
Type: "aws_vpc",
|
|
|
|
Name: "bar",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
|
|
|
|
if rcs == nil {
|
2016-05-21 22:00:46 +02:00
|
|
|
t.Fatalf("missing diff for data.aws_vpc.bar")
|
|
|
|
}
|
2016-05-21 22:23:28 +02:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
rc, err := rcs.Decode(ty)
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2016-05-21 22:23:28 +02:00
|
|
|
}
|
2018-09-18 01:25:11 +02:00
|
|
|
|
|
|
|
checkVals(t,
|
|
|
|
cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
|
|
|
rc.After,
|
|
|
|
)
|
2016-05-21 22:00:46 +02:00
|
|
|
}
|
|
|
|
|
2018-10-02 10:45:17 +02:00
|
|
|
func TestContext2Plan_computedInFunction(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-in-function")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-10-02 10:45:17 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"attr": {Type: cty.Number, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
|
|
|
"aws_data_source": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"computed": {Type: cty.List(cty.String), Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2021-01-09 21:33:38 +01:00
|
|
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
2018-10-02 19:58:49 +02:00
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"computed": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("foo"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
}
|
2018-10-02 10:45:17 +02:00
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-10-02 10:45:17 +02:00
|
|
|
})
|
|
|
|
|
2018-10-02 19:58:49 +02:00
|
|
|
diags := ctx.Validate()
|
|
|
|
assertNoErrors(t, diags)
|
2018-10-02 10:45:17 +02:00
|
|
|
|
2020-09-22 02:59:50 +02:00
|
|
|
_, diags = ctx.Plan()
|
2018-10-02 19:58:49 +02:00
|
|
|
assertNoErrors(t, diags)
|
2018-10-02 10:45:17 +02:00
|
|
|
|
2018-10-02 19:58:49 +02:00
|
|
|
if !p.ReadDataSourceCalled {
|
2020-09-22 02:59:50 +02:00
|
|
|
t.Fatalf("ReadDataSource was not called on provider during plan; should've been called")
|
2018-10-02 10:45:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-02 22:29:25 +02:00
|
|
|
func TestContext2Plan_computedDataCountResource(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-data-count")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"num": {Type: cty.String, Optional: true},
|
|
|
|
"compute": {Type: cty.String, Optional: true},
|
|
|
|
"foo": {Type: cty.String, Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
|
|
|
"aws_vpc": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2016-09-02 22:29:25 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-09-02 22:29:25 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-09-02 22:29:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we created 3 "bar"s
|
|
|
|
for i := 0; i < 3; i++ {
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.DataResourceMode,
|
|
|
|
Type: "aws_vpc",
|
|
|
|
Name: "bar",
|
|
|
|
}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
if rcs := plan.Changes.ResourceInstance(addr); rcs == nil {
|
|
|
|
t.Fatalf("missing changes for %s", addr)
|
2016-09-02 22:29:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-01 18:35:49 +02:00
|
|
|
func TestContext2Plan_localValueCount(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-local-value-count")
|
|
|
|
p := testProvider("test")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
2017-09-01 18:35:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2017-09-01 18:35:49 +02:00
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
// make sure we created 3 "foo"s
|
2017-09-01 18:35:49 +02:00
|
|
|
for i := 0; i < 3; i++ {
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
addr := addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_resource",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.IntKey(i)).Absolute(addrs.RootModuleInstance)
|
|
|
|
|
|
|
|
if rcs := plan.Changes.ResourceInstance(addr); rcs == nil {
|
|
|
|
t.Fatalf("missing changes for %s", addr)
|
2017-09-01 18:35:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
func TestContext2Plan_dataResourceBecomesComputed(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-data-resource-becomes-computed")
|
2016-07-01 01:22:20 +02:00
|
|
|
p := testProvider("aws")
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
2018-09-18 01:25:11 +02:00
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
"computed": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
2018-09-18 01:25:11 +02:00
|
|
|
"aws_data_source": {
|
2018-05-23 02:53:56 +02:00
|
|
|
Attributes: map[string]*configschema.Attribute{
|
2020-05-06 03:23:27 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-09-18 01:25:11 +02:00
|
|
|
"foo": {Type: cty.String, Optional: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-09-18 01:25:11 +02:00
|
|
|
|
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
2019-02-08 02:33:17 +01:00
|
|
|
fooVal := req.ProposedNewState.GetAttr("foo")
|
2018-09-18 01:25:11 +02:00
|
|
|
return providers.PlanResourceChangeResponse{
|
2019-02-08 02:33:17 +01:00
|
|
|
PlannedState: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"foo": fooVal,
|
|
|
|
"computed": cty.UnknownVal(cty.String),
|
|
|
|
}),
|
2018-09-18 01:25:11 +02:00
|
|
|
PlannedPrivate: req.PriorPrivate,
|
2018-09-05 23:35:30 +02:00
|
|
|
}
|
2016-07-01 01:22:20 +02:00
|
|
|
}
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.DataSources["aws_data_source"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
2021-01-09 21:33:38 +01:00
|
|
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
2019-02-08 02:33:17 +01:00
|
|
|
// This should not be called, because the configuration for the
|
|
|
|
// data resource contains an unknown value for "foo".
|
|
|
|
Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("ReadDataSource called, but should not have been")),
|
2016-07-01 01:22:20 +02:00
|
|
|
}
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("data.aws_data_source.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123","foo":"baz"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-07-01 01:22:20 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2016-07-01 01:22:20 +02:00
|
|
|
})
|
|
|
|
|
2018-10-03 01:50:53 +02:00
|
|
|
_, diags := ctx.Refresh()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors during refresh: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
2018-10-03 01:50:53 +02:00
|
|
|
t.Fatalf("unexpected errors during plan: %s", diags.Err())
|
2016-07-01 01:22:20 +02:00
|
|
|
}
|
2016-05-28 21:39:36 +02:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
rcs := plan.Changes.ResourceInstance(addrs.Resource{
|
|
|
|
Mode: addrs.DataResourceMode,
|
|
|
|
Type: "aws_data_source",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
|
|
|
|
if rcs == nil {
|
2018-10-03 01:50:53 +02:00
|
|
|
t.Logf("full changeset: %s", spew.Sdump(plan.Changes))
|
2018-09-18 01:25:11 +02:00
|
|
|
t.Fatalf("missing diff for data.aws_data_resource.foo")
|
|
|
|
}
|
2016-05-28 21:39:36 +02:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
rc, err := rcs.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-10-18 01:29:24 +02:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
// foo should now be unknown
|
|
|
|
foo := rc.After.GetAttr("foo")
|
|
|
|
if foo.IsKnown() {
|
|
|
|
t.Fatalf("foo should be unknown, got %#v", foo)
|
|
|
|
}
|
2016-05-28 21:39:36 +02:00
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_computedList(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-list")
|
|
|
|
p := testProvider("aws")
|
2021-01-12 18:39:25 +01:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"compute": {Type: cty.String, Optional: true},
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
"num": {Type: cty.String, Optional: true},
|
|
|
|
"list": {Type: cty.List(cty.String), Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2019-02-12 02:05:24 +01:00
|
|
|
"list": cty.UnknownVal(cty.List(cty.String)),
|
|
|
|
"num": cty.NumberIntVal(2),
|
|
|
|
"compute": cty.StringVal("list.#"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-11 01:17:29 +01:00
|
|
|
// GH-8695. This tests that you can index into a computed list on a
|
|
|
|
// splatted resource.
|
|
|
|
func TestContext2Plan_computedMultiIndex(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-multi-index")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2018-11-19 22:59:27 +01:00
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-09-18 01:25:11 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"compute": {Type: cty.String, Optional: true},
|
|
|
|
"foo": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
"ip": {Type: cty.List(cty.String), Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2016-12-11 01:17:29 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-12-11 01:17:29 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-12-11 01:17:29 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 3 {
|
|
|
|
t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2019-02-12 02:05:24 +01:00
|
|
|
"ip": cty.UnknownVal(cty.List(cty.String)),
|
|
|
|
"foo": cty.NullVal(cty.List(cty.String)),
|
|
|
|
"compute": cty.StringVal("ip.#"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2019-02-12 02:05:24 +01:00
|
|
|
"ip": cty.UnknownVal(cty.List(cty.String)),
|
|
|
|
"foo": cty.NullVal(cty.List(cty.String)),
|
|
|
|
"compute": cty.StringVal("ip.#"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.bar[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"foo": cty.UnknownVal(cty.List(cty.String)),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-12-11 01:17:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_count(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 6 {
|
|
|
|
t.Fatal("expected 6 changes, got", len(plan.Changes.Resources))
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo,foo,foo,foo,foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[3]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[4]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countComputed(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-computed")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, err := ctx.Plan()
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("should error")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-11 20:02:49 +01:00
|
|
|
func TestContext2Plan_countComputedModule(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-computed-module")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2016-11-11 20:02:49 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-11-11 20:02:49 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
_, err := ctx.Plan()
|
|
|
|
|
2018-05-24 00:03:01 +02:00
|
|
|
expectedErr := `The "count" value depends on resource attributes`
|
2016-11-11 20:02:49 +01:00
|
|
|
if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
|
|
|
|
t.Fatalf("expected err would contain %q\nerr: %s\n",
|
|
|
|
expectedErr, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-28 05:32:55 +01:00
|
|
|
func TestContext2Plan_countModuleStatic(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-module-static")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2017-01-28 05:32:55 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2017-01-28 05:32:55 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2017-01-28 05:32:55 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
2017-01-28 05:32:55 +01:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
if len(plan.Changes.Resources) != 3 {
|
|
|
|
t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2017-01-28 05:32:55 +01:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-01-28 05:32:55 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "module.child.aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "module.child.aws_instance.foo[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "module.child.aws_instance.foo[2]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2017-01-28 05:32:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-28 05:38:07 +01:00
|
|
|
func TestContext2Plan_countModuleStaticGrandchild(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-module-static-grandchild")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2017-01-28 05:38:07 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2017-01-28 05:38:07 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2017-01-28 05:38:07 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
2017-01-28 05:38:07 +01:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
if len(plan.Changes.Resources) != 3 {
|
|
|
|
t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2017-01-28 05:38:07 +01:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-01-28 05:38:07 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "module.child.module.child.aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "module.child.module.child.aws_instance.foo[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "module.child.module.child.aws_instance.foo[2]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2017-01-28 05:38:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_countIndex(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-index")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("0"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("1"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-var")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Variables: InputValues{
|
2018-05-23 18:59:03 +02:00
|
|
|
"instance_count": &InputValue{
|
2018-05-05 04:24:06 +02:00
|
|
|
Value: cty.StringVal("3"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 4 {
|
|
|
|
t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
2018-09-18 01:25:11 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo,foo,foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2018-09-18 01:25:11 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countZero(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-zero")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.DynamicPseudoType, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-09-19 00:44:51 +02:00
|
|
|
|
|
|
|
// This schema contains a DynamicPseudoType, and therefore can't go through any shim functions
|
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
|
|
|
resp.PlannedState = req.ProposedNewState
|
|
|
|
resp.PlannedPrivate = req.PriorPrivate
|
|
|
|
return resp
|
|
|
|
}
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-18 01:25:11 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-18 01:25:11 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
res := plan.Changes.Resources[0]
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2018-09-18 01:25:11 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
expected := cty.TupleVal(nil)
|
2018-09-18 01:25:11 +02:00
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
foo := ric.After.GetAttr("foo")
|
|
|
|
|
|
|
|
if !cmp.Equal(expected, foo, valueComparer) {
|
|
|
|
t.Fatal(cmp.Diff(expected, foo, valueComparer))
|
2018-09-19 00:44:51 +02:00
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countOneIndex(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-one-index")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countDecreaseToOne(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-dec")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 4 {
|
|
|
|
t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("bar"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("resource %s should be unchanged", i)
|
|
|
|
}
|
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("expected resource delete, got %s", res.Action)
|
|
|
|
}
|
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("expected resource delete, got %s", res.Action)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-11 17:42:05 +02:00
|
|
|
expectedState := `aws_instance.foo:
|
2018-09-19 00:44:51 +02:00
|
|
|
ID = bar
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
2018-09-19 00:44:51 +02:00
|
|
|
foo = foo
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.foo.1:
|
|
|
|
ID = bar
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
2018-09-19 00:44:51 +02:00
|
|
|
aws_instance.foo.2:
|
|
|
|
ID = bar
|
2020-03-31 20:03:33 +02:00
|
|
|
provider = provider["registry.terraform.io/hashicorp/aws"]`
|
2018-09-19 00:44:51 +02:00
|
|
|
|
|
|
|
if ctx.State().String() != expectedState {
|
|
|
|
t.Fatalf("epected state:\n%q\n\ngot state:\n%q\n", expectedState, ctx.State().String())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-inc")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance","foo":"foo"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 4 {
|
|
|
|
t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("bar"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("resource %s should be unchanged", i)
|
|
|
|
}
|
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-inc")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 4 {
|
|
|
|
t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("bar"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("resource %s should be unchanged", i)
|
|
|
|
}
|
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/PeoplePerHour/terraform/pull/11
|
|
|
|
//
|
|
|
|
// This tests a case where both a "resource" and "resource.0" are in
|
|
|
|
// the state file, which apparently is a reasonable backwards compatibility
|
|
|
|
// concern found in the above 3rd party repo.
|
|
|
|
func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-inc")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","foo":"foo","type":"aws_instance"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 5 {
|
|
|
|
t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("bar"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be removed", i)
|
|
|
|
}
|
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("resource %s should be unchanged", i)
|
|
|
|
}
|
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-05 01:46:48 +02:00
|
|
|
// A common pattern in TF configs is to have a set of resources with the same
|
|
|
|
// count and to use count.index to create correspondences between them:
|
|
|
|
//
|
|
|
|
// foo_id = "${foo.bar.*.id[count.index]}"
|
|
|
|
//
|
|
|
|
// This test is for the situation where some instances already exist and the
|
|
|
|
// count is increased. In that case, we should see only the create diffs
|
|
|
|
// for the new instances and not any update diffs for the existing ones.
|
|
|
|
func TestContext2Plan_countIncreaseWithSplatReference(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-count-splat-reference")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"name": {Type: cty.String, Optional: true},
|
|
|
|
"foo_name": {Type: cty.String, Optional: true},
|
2020-03-31 20:03:33 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","name":"foo 0"}`),
|
2017-05-05 01:46:48 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","name":"foo 1"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 0"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","foo_name":"foo 1"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2017-05-05 01:46:48 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2017-05-05 01:46:48 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2017-05-05 01:46:48 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2017-05-05 01:46:48 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 6 {
|
|
|
|
t.Fatal("expected 6 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2017-05-05 01:46:48 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-05-05 01:46:48 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar[0]", "aws_instance.bar[1]", "aws_instance.foo[0]", "aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("resource %s should be unchanged", i)
|
|
|
|
}
|
|
|
|
case "aws_instance.bar[2]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
// The instance ID changed, so just check that the name updated
|
|
|
|
if ric.After.GetAttr("foo_name") != cty.StringVal("foo 2") {
|
|
|
|
t.Fatalf("resource %s attr \"foo_name\" should be changed", i)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
case "aws_instance.foo[2]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource create, got %s", res.Action)
|
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
// The instance ID changed, so just check that the name updated
|
|
|
|
if ric.After.GetAttr("name") != cty.StringVal("foo 2") {
|
|
|
|
t.Fatalf("resource %s attr \"name\" should be changed", i)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2017-05-05 01:46:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-12 17:07:32 +02:00
|
|
|
func TestContext2Plan_forEach(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-for-each")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2019-06-12 17:07:32 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2019-06-12 17:07:32 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 8 {
|
|
|
|
t.Fatal("expected 8 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
_, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2019-08-26 19:27:33 +02:00
|
|
|
}
|
|
|
|
|
2019-08-26 21:25:03 +02:00
|
|
|
func TestContext2Plan_forEachUnknownValue(t *testing.T) {
|
2019-10-08 00:24:16 +02:00
|
|
|
// This module has a variable defined, but it's value is unknown. We
|
|
|
|
// expect this to produce an error, but not to panic.
|
2019-08-26 21:25:03 +02:00
|
|
|
m := testModule(t, "plan-for-each-unknown-value")
|
2019-08-26 19:27:33 +02:00
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2019-10-08 00:24:16 +02:00
|
|
|
Variables: InputValues{
|
|
|
|
"foo": {
|
|
|
|
Value: cty.UnknownVal(cty.String),
|
|
|
|
SourceType: ValueFromCLIArg,
|
|
|
|
},
|
|
|
|
},
|
2019-08-26 19:27:33 +02:00
|
|
|
})
|
|
|
|
|
2019-08-26 21:25:03 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
2019-08-26 21:30:42 +02:00
|
|
|
// Should get this error:
|
|
|
|
// Invalid for_each argument: The "for_each" value depends on resource attributes that cannot be determined until apply...
|
|
|
|
t.Fatal("succeeded; want errors")
|
|
|
|
}
|
|
|
|
|
|
|
|
gotErrStr := diags.Err().Error()
|
|
|
|
wantErrStr := "Invalid for_each argument"
|
|
|
|
if !strings.Contains(gotErrStr, wantErrStr) {
|
|
|
|
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
|
2019-08-26 19:27:33 +02:00
|
|
|
}
|
2019-06-12 17:07:32 +02:00
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_destroy(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-destroy")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.one").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.two").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"baz"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if len(plan.Changes.Resources) != 2 {
|
2018-09-19 00:44:51 +02:00
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.one", "aws_instance.two":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be removed", i)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleDestroy(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-destroy")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
|
|
|
child.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo", "module.child.aws_instance.foo":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be removed", i)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GH-1835
|
|
|
|
func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-destroy-gh-1835")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
aModule := state.EnsureModule(addrs.RootModuleInstance.Child("a_module", addrs.NoKey))
|
|
|
|
aModule.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.a").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"a"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
bModule := state.EnsureModule(addrs.RootModuleInstance.Child("b_module", addrs.NoKey))
|
|
|
|
bModule.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.b").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"b"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "module.a_module.aws_instance.a", "module.b_module.aws_instance.b":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be removed", i)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-destroy-multivar")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
|
|
|
child.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar0"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
child.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar1"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "module.child.aws_instance.foo[0]", "module.child.aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be removed", i)
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_pathVar(t *testing.T) {
|
|
|
|
cwd, err := os.Getwd()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
m := testModule(t, "plan-path-var")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"cwd": {Type: cty.String, Optional: true},
|
|
|
|
"module": {Type: cty.String, Optional: true},
|
|
|
|
"root": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-05 04:24:06 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("err: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", i)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"cwd": cty.StringVal(cwd + "/barpath"),
|
|
|
|
"module": cty.StringVal(m.Module.SourceDir + "/foopath"),
|
|
|
|
"root": cty.StringVal(m.Module.SourceDir + "/barpath"),
|
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_diffVar(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-diffvar")
|
|
|
|
p := testProvider("aws")
|
2021-01-12 18:39:25 +01:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", i)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(3),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Update {
|
|
|
|
t.Fatalf("resource %s should be updated", i)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.StringVal("bar"),
|
|
|
|
"num": cty.NumberIntVal(2),
|
|
|
|
"type": cty.StringVal("aws_instance"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.Before)
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.StringVal("bar"),
|
|
|
|
"num": cty.NumberIntVal(3),
|
|
|
|
"type": cty.StringVal("aws_instance"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_hook(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-good")
|
|
|
|
h := new(MockHook)
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2015-07-10 22:08:49 +02:00
|
|
|
Hooks: []Hook{h},
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if !h.PreDiffCalled {
|
|
|
|
t.Fatal("should be called")
|
|
|
|
}
|
|
|
|
if !h.PostDiffCalled {
|
|
|
|
t.Fatal("should be called")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-04 21:00:09 +01:00
|
|
|
func TestContext2Plan_closeProvider(t *testing.T) {
|
|
|
|
// this fixture only has an aliased provider located in the module, to make
|
|
|
|
// sure that the provier name contains a path more complex than
|
|
|
|
// "provider.aws".
|
|
|
|
m := testModule(t, "plan-close-module-provider")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-01-04 21:00:09 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2018-01-04 21:00:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if !p.CloseCalled {
|
|
|
|
t.Fatal("provider not closed")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_orphan(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-orphan")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.baz").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.baz":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be removed", i)
|
|
|
|
}
|
2021-04-28 21:02:34 +02:00
|
|
|
if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", i)
|
|
|
|
}
|
2021-04-28 21:02:34 +02:00
|
|
|
if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-14 19:17:42 +01:00
|
|
|
// This tests that configurations with UUIDs don't produce errors.
|
|
|
|
// For shadows, this would produce errors since a UUID changes every time.
|
|
|
|
func TestContext2Plan_shadowUuid(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-shadow-uuid")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-11-14 19:17:42 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-11-14 19:17:42 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_state(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-good")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
if len(plan.Changes.Resources) < 2 {
|
|
|
|
t.Fatalf("bad: %#v", plan.Changes.Resources)
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", i)
|
|
|
|
}
|
2021-04-28 21:02:34 +02:00
|
|
|
if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("2"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Update {
|
|
|
|
t.Fatalf("resource %s should be updated", i)
|
|
|
|
}
|
2021-04-28 21:02:34 +02:00
|
|
|
if got, want := ric.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("bar"),
|
|
|
|
"num": cty.NullVal(cty.Number),
|
|
|
|
"type": cty.NullVal(cty.String),
|
|
|
|
}), ric.Before)
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("bar"),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 21:02:34 +02:00
|
|
|
func TestContext2Plan_requiresReplace(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-requires-replace")
|
|
|
|
p := testProvider("test")
|
|
|
|
p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
|
|
|
|
Provider: providers.Schema{
|
|
|
|
Block: &configschema.Block{},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]providers.Schema{
|
|
|
|
"test_thing": providers.Schema{
|
|
|
|
Block: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"v": {
|
|
|
|
Type: cty.String,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
|
|
|
return providers.PlanResourceChangeResponse{
|
|
|
|
PlannedState: req.ProposedNewState,
|
|
|
|
RequiresReplace: []cty.Path{
|
|
|
|
cty.GetAttrPath("v"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_thing.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"v":"hello"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["test_thing"].Block
|
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if got, want := len(plan.Changes.Resources), 1; got != want {
|
|
|
|
t.Fatalf("got %d changes; want %d", got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
t.Run(res.Addr.String(), func(t *testing.T) {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "test_thing.foo":
|
|
|
|
if got, want := ric.Action, plans.DeleteThenCreate; got != want {
|
|
|
|
t.Errorf("wrong action\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseCannotUpdate; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"v": cty.StringVal("goodbye"),
|
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatalf("unexpected resource instance %s", i)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_taint(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-taint")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","num":"2","type":"aws_instance"}`),
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.bar").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectTainted,
|
|
|
|
AttrsJSON: []byte(`{"id":"baz"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
2021-04-28 21:02:34 +02:00
|
|
|
t.Run(res.Addr.String(), func(t *testing.T) {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2018-09-19 00:44:51 +02:00
|
|
|
}
|
2021-04-28 21:02:34 +02:00
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.bar":
|
|
|
|
if got, want := res.Action, plans.DeleteThenCreate; got != want {
|
|
|
|
t.Errorf("wrong action\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("2"),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if got, want := res.Action, plans.NoOp; got != want {
|
|
|
|
t.Errorf("wrong action\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
if got, want := res.ActionReason, plans.ResourceInstanceChangeNoReason; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
2018-09-19 00:44:51 +02:00
|
|
|
}
|
2021-04-28 21:02:34 +02:00
|
|
|
})
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 01:20:32 +02:00
|
|
|
func TestContext2Plan_taintIgnoreChanges(t *testing.T) {
|
2016-10-27 14:44:59 +02:00
|
|
|
m := testModule(t, "plan-taint-ignore-changes")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
2018-09-19 00:44:51 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
"vars": {Type: cty.String, Optional: true},
|
2018-09-19 00:44:51 +02:00
|
|
|
"type": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectTainted,
|
|
|
|
AttrsJSON: []byte(`{"id":"foo","vars":"foo","type":"aws_instance"}`),
|
2016-10-27 14:44:59 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-10-27 14:44:59 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2016-10-27 14:44:59 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-10-27 14:44:59 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo":
|
2021-04-28 21:02:34 +02:00
|
|
|
if got, want := res.Action, plans.DeleteThenCreate; got != want {
|
|
|
|
t.Errorf("wrong action\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
if got, want := res.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
2018-09-19 00:44:51 +02:00
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("foo"),
|
|
|
|
"vars": cty.StringVal("foo"),
|
|
|
|
"type": cty.StringVal("aws_instance"),
|
|
|
|
}), ric.Before)
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"vars": cty.StringVal("foo"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-10-27 14:44:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-06 00:40:35 +01:00
|
|
|
// Fails about 50% of the time before the fix for GH-4982, covers the fix.
|
|
|
|
func TestContext2Plan_taintDestroyInterpolatedCountRace(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-taint-interpolated-count")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectTainted,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
|
2016-02-06 00:40:35 +01:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","type":"aws_instance"}`),
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
2016-02-06 00:40:35 +01:00
|
|
|
|
|
|
|
for i := 0; i < 100; i++ {
|
2018-09-19 00:44:51 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2020-09-11 17:42:05 +02:00
|
|
|
State: state.DeepCopy(),
|
2018-09-19 00:44:51 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-02-06 00:40:35 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-02-06 00:40:35 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 3 {
|
|
|
|
t.Fatal("expected 3 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2016-02-06 00:40:35 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-02-06 00:40:35 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo[0]":
|
2021-04-28 21:02:34 +02:00
|
|
|
if got, want := ric.Action, plans.DeleteThenCreate; got != want {
|
|
|
|
t.Errorf("wrong action\ngot: %s\nwant: %s", got, want)
|
|
|
|
}
|
|
|
|
if got, want := ric.ActionReason, plans.ResourceInstanceReplaceBecauseTainted; got != want {
|
|
|
|
t.Errorf("wrong action reason\ngot: %s\nwant: %s", got, want)
|
2018-09-19 00:44:51 +02:00
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.StringVal("bar"),
|
|
|
|
"type": cty.StringVal("aws_instance"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.Before)
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[1]", "aws_instance.foo[2]":
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("resource %s should not be changed", i)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-02-06 00:40:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
func TestContext2Plan_targeted(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2015-07-10 22:08:49 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Resource(
|
|
|
|
addrs.ManagedResourceMode, "aws_instance", "foo",
|
|
|
|
),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", i)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2015-11-11 18:35:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-13 05:54:46 +01:00
|
|
|
// Test that targeting a module properly plans any inputs that depend
|
|
|
|
// on another module.
|
|
|
|
func TestContext2Plan_targetedCrossModule(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted-cross-module")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2016-12-13 05:54:46 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Child("B", addrs.NoKey),
|
|
|
|
},
|
2016-12-13 05:54:46 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-12-13 05:54:46 +01:00
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-12-13 05:54:46 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2016-12-13 05:54:46 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", ric.Addr)
|
|
|
|
}
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "module.A.aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.StringVal("bar"),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "module.B.aws_instance.bar":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"foo": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-12-13 05:54:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-17 18:21:29 +01:00
|
|
|
func TestContext2Plan_targetedModuleWithProvider(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted-module-with-provider")
|
|
|
|
p := testProvider("null")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
Provider: &configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"key": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"null_resource": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2017-02-17 18:21:29 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("null"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Child("child2", addrs.NoKey),
|
|
|
|
},
|
2017-02-17 18:21:29 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2017-02-17 18:21:29 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["null_resource"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2017-02-17 18:21:29 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2017-02-17 18:21:29 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
res := plan.Changes.Resources[0]
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-02-17 18:21:29 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if ric.Addr.String() != "module.child2.null_resource.foo" {
|
|
|
|
t.Fatalf("unexpcetd resource: %s", ric.Addr)
|
2017-02-17 18:21:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-11 18:35:35 +01:00
|
|
|
func TestContext2Plan_targetedOrphan(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted-orphan")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.orphan").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-789xyz"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-11-11 18:35:35 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Resource(
|
|
|
|
addrs.ManagedResourceMode, "aws_instance", "orphan",
|
|
|
|
),
|
|
|
|
},
|
2015-11-11 18:35:35 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-11-11 18:35:35 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2015-11-11 18:35:35 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2015-11-11 18:35:35 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2015-11-11 18:35:35 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.orphan":
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be destroyed", ric.Addr)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-01-07 21:43:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/hashicorp/terraform/issues/2538
|
|
|
|
func TestContext2Plan_targetedModuleOrphan(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted-module-orphan")
|
|
|
|
p := testProvider("aws")
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
child := state.EnsureModule(addrs.RootModuleInstance.Child("child", addrs.NoKey))
|
|
|
|
child.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.orphan").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-789xyz"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
child.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.nottargeted").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"i-abc123"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-01-07 21:43:43 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2021-04-06 00:22:30 +02:00
|
|
|
State: state,
|
|
|
|
PlanMode: plans.DestroyMode,
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Child("child", addrs.NoKey).Resource(
|
|
|
|
addrs.ManagedResourceMode, "aws_instance", "orphan",
|
|
|
|
),
|
|
|
|
},
|
2016-01-07 21:43:43 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-01-07 21:43:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-01-07 21:43:43 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2016-01-07 21:43:43 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
res := plan.Changes.Resources[0]
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2016-01-07 21:43:43 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if ric.Addr.String() != "module.child.aws_instance.orphan" {
|
|
|
|
t.Fatalf("unexpected resource :%s", ric.Addr)
|
|
|
|
}
|
|
|
|
if res.Action != plans.Delete {
|
|
|
|
t.Fatalf("resource %s should be deleted", ric.Addr)
|
2016-01-07 21:43:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 17:53:13 +02:00
|
|
|
func TestContext2Plan_targetedModuleUntargetedVariable(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted-module-untargeted-variable")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2016-07-29 17:53:13 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Resource(
|
|
|
|
addrs.ManagedResourceMode, "aws_instance", "blue",
|
|
|
|
),
|
|
|
|
addrs.RootModuleInstance.Child("blue_mod", addrs.NoKey),
|
|
|
|
},
|
2016-07-29 17:53:13 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-07-29 17:53:13 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-07-29 17:53:13 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
2016-07-29 17:53:13 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", ric.Addr)
|
|
|
|
}
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.blue":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "module.blue_mod.aws_instance.mod":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"value": cty.UnknownVal(cty.String),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-07-29 17:53:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-20 01:32:37 +01:00
|
|
|
// ensure that outputs missing references due to targetting are removed from
|
|
|
|
// the graph.
|
|
|
|
func TestContext2Plan_outputContainsTargetedResource(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-untargeted-resource-output")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Child("mod", addrs.NoKey).Resource(
|
|
|
|
addrs.ManagedResourceMode, "aws_instance", "a",
|
|
|
|
),
|
|
|
|
},
|
2018-03-20 01:32:37 +01:00
|
|
|
})
|
|
|
|
|
2019-09-12 21:11:54 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("err: %s", diags)
|
|
|
|
}
|
|
|
|
if len(diags) != 1 {
|
|
|
|
t.Fatalf("got %d diagnostics; want 1", diags)
|
|
|
|
}
|
|
|
|
if got, want := diags[0].Severity(), tfdiags.Warning; got != want {
|
|
|
|
t.Errorf("wrong diagnostic severity %#v; want %#v", got, want)
|
|
|
|
}
|
|
|
|
if got, want := diags[0].Description().Summary, "Resource targeting is in effect"; got != want {
|
|
|
|
t.Errorf("wrong diagnostic summary %#v; want %#v", got, want)
|
2018-03-20 01:32:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-07 21:43:43 +01:00
|
|
|
// https://github.com/hashicorp/terraform/issues/4515
|
|
|
|
func TestContext2Plan_targetedOverTen(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted-over-ten")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2016-01-07 21:43:43 +01:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
2016-01-07 21:43:43 +01:00
|
|
|
for i := 0; i < 13; i++ {
|
2020-03-31 20:03:33 +02:00
|
|
|
key := fmt.Sprintf("aws_instance.foo[%d]", i)
|
2016-01-07 21:43:43 +01:00
|
|
|
id := fmt.Sprintf("i-abc%d", i)
|
2020-10-08 14:56:03 +02:00
|
|
|
attrs := fmt.Sprintf(`{"id":"%s","type":"aws_instance"}`, id)
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr(key).Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(attrs),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
2016-01-07 21:43:43 +01:00
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
|
2016-01-07 21:43:43 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2018-05-05 04:24:06 +02:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.ResourceInstance(
|
|
|
|
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(1),
|
|
|
|
),
|
|
|
|
},
|
2016-01-07 21:43:43 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-01-07 21:43:43 +01:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
2016-01-07 21:43:43 +01:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("unexpected action %s for %s", res.Action, ric.Addr)
|
|
|
|
}
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_provider(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-provider")
|
|
|
|
p := testProvider("aws")
|
|
|
|
|
|
|
|
var value interface{}
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
|
2020-10-08 18:26:12 +02:00
|
|
|
value = req.Config.GetAttr("foo").AsString()
|
|
|
|
return
|
2015-07-10 22:08:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Variables: InputValues{
|
|
|
|
"foo": &InputValue{
|
|
|
|
Value: cty.StringVal("bar"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if value != "bar" {
|
|
|
|
t.Fatalf("bad: %#v", value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_varListErr(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-var-list-err")
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2015-07-10 22:08:49 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, err := ctx.Plan()
|
2016-04-15 21:07:54 +02:00
|
|
|
|
2015-07-10 22:08:49 +02:00
|
|
|
if err == nil {
|
|
|
|
t.Fatal("should error")
|
|
|
|
}
|
|
|
|
}
|
2015-08-09 10:02:28 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_ignoreChanges(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-ignore-changes")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
|
2015-08-09 10:02:28 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2015-08-09 10:02:28 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Variables: InputValues{
|
|
|
|
"foo": &InputValue{
|
|
|
|
Value: cty.StringVal("ami-1234abcd"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
2015-08-09 10:02:28 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
State: state,
|
2015-08-09 10:02:28 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2015-08-09 10:02:28 +02:00
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2018-09-19 00:44:51 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
res := plan.Changes.Resources[0]
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2015-08-09 10:02:28 +02:00
|
|
|
|
2018-09-19 00:44:51 +02:00
|
|
|
if ric.Addr.String() != "aws_instance.foo" {
|
|
|
|
t.Fatalf("unexpected resource: %s", ric.Addr)
|
2015-08-09 10:02:28 +02:00
|
|
|
}
|
2018-09-19 00:44:51 +02:00
|
|
|
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2020-10-08 14:56:03 +02:00
|
|
|
"id": cty.StringVal("bar"),
|
|
|
|
"ami": cty.StringVal("ami-abcd1234"),
|
|
|
|
"type": cty.StringVal("aws_instance"),
|
2018-09-19 00:44:51 +02:00
|
|
|
}), ric.After)
|
2015-08-09 10:02:28 +02:00
|
|
|
}
|
2016-07-06 16:11:46 +02:00
|
|
|
|
2016-09-02 15:44:35 +02:00
|
|
|
func TestContext2Plan_ignoreChangesWildcard(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-ignore-changes-wildcard")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2020-03-31 20:03:33 +02:00
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","instance":"t2.micro","type":"aws_instance"}`),
|
2016-09-02 15:44:35 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
2016-09-02 15:44:35 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-05 04:24:06 +02:00
|
|
|
Variables: InputValues{
|
|
|
|
"foo": &InputValue{
|
|
|
|
Value: cty.StringVal("ami-1234abcd"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
|
|
|
"bar": &InputValue{
|
|
|
|
Value: cty.StringVal("t2.small"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
2016-09-02 15:44:35 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
State: state,
|
2016-09-02 15:44:35 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-09-02 15:44:35 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("unexpected resource diffs in root module: %s", spew.Sdump(plan.Changes.Resources))
|
|
|
|
}
|
2016-09-02 15:44:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-19 01:03:33 +02:00
|
|
|
func TestContext2Plan_ignoreChangesInMap(t *testing.T) {
|
|
|
|
p := testProvider("test")
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2019-06-19 01:03:33 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_ignore_changes_map": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"tags": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2019-06-19 01:03:33 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
|
|
|
return providers.PlanResourceChangeResponse{
|
|
|
|
PlannedState: req.ProposedNewState,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s := states.BuildState(func(ss *states.SyncState) {
|
|
|
|
ss.SetResourceInstanceCurrent(
|
|
|
|
addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_ignore_changes_map",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"foo","tags":{"ignored":"from state","other":"from state"},"type":"aws_instance"}`),
|
2019-06-19 01:03:33 +02:00
|
|
|
},
|
2020-02-13 21:32:58 +01:00
|
|
|
addrs.AbsProviderConfig{
|
2020-03-31 20:03:33 +02:00
|
|
|
Provider: addrs.NewDefaultProvider("test"),
|
2020-03-11 02:21:19 +01:00
|
|
|
Module: addrs.RootModule,
|
2020-02-13 21:32:58 +01:00
|
|
|
},
|
2019-06-19 01:03:33 +02:00
|
|
|
)
|
|
|
|
})
|
|
|
|
m := testModule(t, "plan-ignore-changes-in-map")
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
2019-06-19 01:03:33 +02:00
|
|
|
State: s,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["test_ignore_changes_map"].Block
|
2019-06-19 01:03:33 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if got, want := len(plan.Changes.Resources), 1; got != want {
|
|
|
|
t.Fatalf("wrong number of changes %d; want %d", got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
res := plan.Changes.Resources[0]
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if res.Action != plans.Update {
|
|
|
|
t.Fatalf("resource %s should be updated, got %s", ric.Addr, res.Action)
|
|
|
|
}
|
|
|
|
|
|
|
|
if got, want := ric.Addr.String(), "test_ignore_changes_map.foo"; got != want {
|
|
|
|
t.Fatalf("unexpected resource address %s; want %s", got, want)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"tags": cty.MapVal(map[string]cty.Value{
|
|
|
|
"ignored": cty.StringVal("from state"),
|
|
|
|
"other": cty.StringVal("from config"),
|
|
|
|
}),
|
|
|
|
}), ric.After)
|
|
|
|
}
|
|
|
|
|
2020-10-20 18:20:52 +02:00
|
|
|
func TestContext2Plan_ignoreChangesSensitive(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-ignore-changes-sensitive")
|
|
|
|
p := testProvider("aws")
|
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"bar","ami":"ami-abcd1234","type":"aws_instance"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
Variables: InputValues{
|
|
|
|
"foo": &InputValue{
|
|
|
|
Value: cty.StringVal("ami-1234abcd"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2020-10-20 18:20:52 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
res := plan.Changes.Resources[0]
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ric.Addr.String() != "aws_instance.foo" {
|
|
|
|
t.Fatalf("unexpected resource: %s", ric.Addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("bar"),
|
2021-05-12 14:55:10 +02:00
|
|
|
"ami": cty.StringVal("ami-abcd1234").Mark("sensitive"),
|
2020-10-20 18:20:52 +02:00
|
|
|
"type": cty.StringVal("aws_instance"),
|
|
|
|
}), ric.After)
|
|
|
|
}
|
|
|
|
|
2016-07-06 16:11:46 +02:00
|
|
|
func TestContext2Plan_moduleMapLiteral(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-map-literal")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"meta": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
"tags": {Type: cty.Map(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
2020-10-08 14:56:03 +02:00
|
|
|
s := req.ProposedNewState.AsValueMap()
|
|
|
|
m := s["tags"].AsValueMap()
|
|
|
|
|
|
|
|
if m["foo"].AsString() != "bar" {
|
2016-07-06 16:11:46 +02:00
|
|
|
t.Fatalf("Bad value in tags attr: %#v", m)
|
|
|
|
}
|
2020-10-08 14:56:03 +02:00
|
|
|
|
|
|
|
meta := s["meta"].AsValueMap()
|
|
|
|
if len(meta) != 0 {
|
|
|
|
t.Fatalf("Meta attr not empty: %#v", meta)
|
2016-07-06 16:11:46 +02:00
|
|
|
}
|
2020-10-08 14:56:03 +02:00
|
|
|
return testDiffFn(req)
|
2016-07-06 16:11:46 +02:00
|
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-07-06 16:11:46 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-07-06 16:11:46 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-07 20:14:33 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_computedValueInMap(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-value-in-map")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"looked_up": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"aws_computed_source": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"computed_read_only": {Type: cty.String, Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
2020-10-08 14:56:03 +02:00
|
|
|
resp = testDiffFn(req)
|
|
|
|
|
|
|
|
if req.TypeName != "aws_computed_source" {
|
|
|
|
return
|
2016-07-07 20:14:33 +02:00
|
|
|
}
|
|
|
|
|
2020-10-08 14:56:03 +02:00
|
|
|
planned := resp.PlannedState.AsValueMap()
|
|
|
|
planned["computed_read_only"] = cty.UnknownVal(cty.String)
|
|
|
|
resp.PlannedState = cty.ObjectVal(planned)
|
|
|
|
return resp
|
2016-07-07 20:14:33 +02:00
|
|
|
}
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2016-07-07 20:14:33 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-07-07 20:14:33 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-07-07 20:14:33 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
2016-07-07 20:14:33 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
|
2018-09-20 03:31:59 +02:00
|
|
|
|
|
|
|
ric, err := res.Decode(schema.ImpliedType())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", ric.Addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_computed_source.intermediates":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"computed_read_only": cty.UnknownVal(cty.String),
|
|
|
|
}), ric.After)
|
|
|
|
case "module.test_mod.aws_instance.inner2":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"looked_up": cty.UnknownVal(cty.String),
|
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-07-07 20:14:33 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-13 19:23:56 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_moduleVariableFromSplat(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-module-variable-from-splat")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"thing": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2016-07-13 19:23:56 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-07-13 19:23:56 +02:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-07-13 19:23:56 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
if len(plan.Changes.Resources) != 4 {
|
|
|
|
t.Fatal("expected 4 changes, got", len(plan.Changes.Resources))
|
2016-07-13 19:23:56 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
|
2018-09-20 03:31:59 +02:00
|
|
|
|
|
|
|
ric, err := res.Decode(schema.ImpliedType())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", ric.Addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "module.mod1.aws_instance.test[0]",
|
|
|
|
"module.mod1.aws_instance.test[1]",
|
|
|
|
"module.mod2.aws_instance.test[0]",
|
|
|
|
"module.mod2.aws_instance.test[1]":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"thing": cty.StringVal("doesnt"),
|
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2016-07-13 19:23:56 +02:00
|
|
|
}
|
|
|
|
}
|
2016-11-03 23:31:25 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_createBeforeDestroy_depends_datasource(t *testing.T) {
|
2018-05-25 01:07:15 +02:00
|
|
|
m := testModule(t, "plan-cbd-depends-datasource")
|
2016-11-03 23:31:25 +01:00
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
2018-09-20 03:31:59 +02:00
|
|
|
"num": {Type: cty.String, Optional: true},
|
|
|
|
"computed": {Type: cty.String, Optional: true, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DataSources: map[string]*configschema.Block{
|
|
|
|
"aws_vpc": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
2018-05-25 01:23:33 +02:00
|
|
|
"id": {Type: cty.String, Computed: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
"foo": {Type: cty.Number, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-09-28 23:54:59 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
2019-02-08 03:33:05 +01:00
|
|
|
computedVal := req.ProposedNewState.GetAttr("computed")
|
|
|
|
if computedVal.IsNull() {
|
|
|
|
computedVal = cty.UnknownVal(cty.String)
|
|
|
|
}
|
2018-09-28 03:17:06 +02:00
|
|
|
return providers.PlanResourceChangeResponse{
|
2019-02-08 03:33:05 +01:00
|
|
|
PlannedState: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"num": req.ProposedNewState.GetAttr("num"),
|
|
|
|
"computed": computedVal,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
|
2020-05-05 17:45:33 +02:00
|
|
|
cfg := req.Config.AsValueMap()
|
|
|
|
cfg["id"] = cty.StringVal("data_id")
|
2019-02-08 03:33:05 +01:00
|
|
|
return providers.ReadDataSourceResponse{
|
2020-05-05 17:45:33 +02:00
|
|
|
State: cty.ObjectVal(cfg),
|
2018-09-28 03:17:06 +02:00
|
|
|
}
|
|
|
|
}
|
2018-05-23 02:53:56 +02:00
|
|
|
|
2016-11-03 23:31:25 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-11-03 23:31:25 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-11-03 23:31:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-08 03:33:05 +01:00
|
|
|
seenAddrs := make(map[string]struct{})
|
2018-09-20 03:31:59 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
var schema *configschema.Block
|
|
|
|
switch res.Addr.Resource.Resource.Mode {
|
|
|
|
case addrs.DataResourceMode:
|
2021-02-18 16:13:43 +01:00
|
|
|
schema = p.GetProviderSchemaResponse.DataSources[res.Addr.Resource.Resource.Type].Block
|
2018-09-20 03:31:59 +02:00
|
|
|
case addrs.ManagedResourceMode:
|
2021-02-18 16:13:43 +01:00
|
|
|
schema = p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
}
|
2018-09-20 03:31:59 +02:00
|
|
|
|
|
|
|
ric, err := res.Decode(schema.ImpliedType())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-02-08 03:33:05 +01:00
|
|
|
seenAddrs[ric.Addr.String()] = struct{}{}
|
|
|
|
|
2018-09-28 23:54:59 +02:00
|
|
|
t.Run(ric.Addr.String(), func(t *testing.T) {
|
2018-09-28 03:17:06 +02:00
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo[0]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"num": cty.StringVal("2"),
|
2020-05-05 17:45:33 +02:00
|
|
|
"computed": cty.StringVal("data_id"),
|
2018-09-28 03:17:06 +02:00
|
|
|
}), ric.After)
|
|
|
|
case "aws_instance.foo[1]":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created, got %s", ric.Addr, ric.Action)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"num": cty.StringVal("2"),
|
2020-05-05 17:45:33 +02:00
|
|
|
"computed": cty.StringVal("data_id"),
|
2018-09-28 03:17:06 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
2018-09-20 03:31:59 +02:00
|
|
|
}
|
2018-09-28 03:17:06 +02:00
|
|
|
})
|
2016-11-03 23:31:25 +01:00
|
|
|
}
|
2019-02-08 03:33:05 +01:00
|
|
|
|
|
|
|
wantAddrs := map[string]struct{}{
|
|
|
|
"aws_instance.foo[0]": struct{}{},
|
|
|
|
"aws_instance.foo[1]": struct{}{},
|
|
|
|
}
|
|
|
|
if !cmp.Equal(seenAddrs, wantAddrs) {
|
|
|
|
t.Errorf("incorrect addresses in changeset:\n%s", cmp.Diff(wantAddrs, seenAddrs))
|
|
|
|
}
|
2016-11-03 23:31:25 +01:00
|
|
|
}
|
2016-12-15 19:22:53 +01:00
|
|
|
|
|
|
|
// interpolated lists need to be stored in the original order.
|
|
|
|
func TestContext2Plan_listOrder(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-list-order")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2016-12-15 19:22:53 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2016-12-15 19:22:53 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2016-12-15 19:22:53 +01:00
|
|
|
}
|
|
|
|
|
terraform: Ugly huge change to weave in new State and Plan types
Due to how often the state and plan types are referenced throughout
Terraform, there isn't a great way to switch them out gradually. As a
consequence, this huge commit gets us from the old world to a _compilable_
new world, but still has a large number of known test failures due to
key functionality being stubbed out.
The stubs here are for anything that interacts with providers, since we
now need to do the follow-up work to similarly replace the old
terraform.ResourceProvider interface with its replacement in the new
"providers" package. That work, along with work to fix the remaining
failing tests, will follow in subsequent commits.
The aim here was to replace all references to terraform.State and its
downstream types with states.State, terraform.Plan with plans.Plan,
state.State with statemgr.State, and switch to the new implementations of
the state and plan file formats. However, due to the number of times those
types are used, this also ended up affecting numerous other parts of core
such as terraform.Hook, the backend.Backend interface, and most of the CLI
commands.
Just as with 5861dbf3fc49b19587a31816eb06f511ab861bb4 before, I apologize
in advance to the person who inevitably just found this huge commit while
spelunking through the commit history.
2018-08-14 23:24:45 +02:00
|
|
|
changes := plan.Changes
|
|
|
|
rDiffA := changes.ResourceInstance(addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "aws_instance",
|
|
|
|
Name: "a",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
|
|
|
|
rDiffB := changes.ResourceInstance(addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "aws_instance",
|
|
|
|
Name: "b",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance))
|
2016-12-15 19:22:53 +01:00
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
if !cmp.Equal(rDiffA.After, rDiffB.After, valueComparer) {
|
|
|
|
t.Fatal(cmp.Diff(rDiffA.After, rDiffB.After, valueComparer))
|
2016-12-15 19:22:53 +01:00
|
|
|
}
|
|
|
|
}
|
2017-03-20 22:17:14 +01:00
|
|
|
|
|
|
|
// Make sure ignore-changes doesn't interfere with set/list/map diffs.
|
|
|
|
// If a resource was being replaced by a RequiresNew attribute that gets
|
2017-03-20 16:23:31 +01:00
|
|
|
// ignored, we need to filter the diff properly to properly update rather than
|
|
|
|
// replace.
|
2017-03-20 22:17:14 +01:00
|
|
|
func TestContext2Plan_ignoreChangesWithFlatmaps(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-ignore-changes-with-flatmaps")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-05-23 02:53:56 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"user_data": {Type: cty.String, Optional: true},
|
|
|
|
"require_new": {Type: cty.String, Optional: true},
|
2018-05-24 21:40:33 +02:00
|
|
|
|
|
|
|
// This test predates the 0.12 work to integrate cty and
|
|
|
|
// HCL, and so it was ported as-is where its expected
|
|
|
|
// test output was clearly expecting a list of maps here
|
|
|
|
// even though it is named "set".
|
|
|
|
"set": {Type: cty.List(cty.Map(cty.String)), Optional: true},
|
|
|
|
"lst": {Type: cty.List(cty.String), Optional: true},
|
2018-05-23 02:53:56 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{
|
|
|
|
"user_data":"x","require_new":"",
|
|
|
|
"set":[{"a":"1"}],
|
|
|
|
"lst":["j"]
|
|
|
|
}`),
|
2017-03-20 22:17:14 +01:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
2018-09-20 03:31:59 +02:00
|
|
|
|
2017-03-20 22:17:14 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2017-03-20 22:17:14 +01:00
|
|
|
})
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
2017-03-20 22:17:14 +01:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
res := plan.Changes.Resources[0]
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes[res.Addr.Resource.Resource.Type].Block
|
2018-09-20 03:31:59 +02:00
|
|
|
|
|
|
|
ric, err := res.Decode(schema.ImpliedType())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if res.Action != plans.Update {
|
|
|
|
t.Fatalf("resource %s should be updated, got %s", ric.Addr, ric.Action)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ric.Addr.String() != "aws_instance.foo" {
|
|
|
|
t.Fatalf("unknown resource: %s", ric.Addr)
|
2017-03-20 22:17:14 +01:00
|
|
|
}
|
2018-09-20 03:31:59 +02:00
|
|
|
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"lst": cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("j"),
|
|
|
|
cty.StringVal("k"),
|
|
|
|
}),
|
|
|
|
"require_new": cty.StringVal(""),
|
|
|
|
"user_data": cty.StringVal("x"),
|
|
|
|
"set": cty.ListVal([]cty.Value{cty.MapVal(map[string]cty.Value{
|
|
|
|
"a": cty.StringVal("1"),
|
|
|
|
"b": cty.StringVal("2"),
|
|
|
|
})}),
|
|
|
|
}), ric.After)
|
2017-03-20 22:17:14 +01:00
|
|
|
}
|
2017-04-20 07:23:52 +02:00
|
|
|
|
|
|
|
// TestContext2Plan_resourceNestedCount ensures resource sets that depend on
|
|
|
|
// the count of another resource set (ie: count of a data source that depends
|
|
|
|
// on another data source's instance count - data.x.foo.*.id) get properly
|
|
|
|
// normalized to the indexes they should be. This case comes up when there is
|
|
|
|
// an existing state (after an initial apply).
|
|
|
|
func TestContext2Plan_resourceNestedCount(t *testing.T) {
|
|
|
|
m := testModule(t, "nested-resource-count-plan")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2018-09-05 23:35:30 +02:00
|
|
|
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
|
|
|
|
return providers.ReadResourceResponse{
|
|
|
|
NewState: req.PriorState,
|
|
|
|
}
|
2017-04-20 07:23:52 +02:00
|
|
|
}
|
2020-03-31 20:03:33 +02:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"foo0","type":"aws_instance"}`),
|
2017-04-20 07:23:52 +02:00
|
|
|
},
|
2020-03-31 20:03:33 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"foo1","type":"aws_instance"}`),
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.bar[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar0","type":"aws_instance"}`),
|
2020-09-24 17:57:43 +02:00
|
|
|
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.bar[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"bar1","type":"aws_instance"}`),
|
2020-09-24 17:57:43 +02:00
|
|
|
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.foo")},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.baz[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"baz0","type":"aws_instance"}`),
|
2020-09-24 17:57:43 +02:00
|
|
|
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.baz[1]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"baz1","type":"aws_instance"}`),
|
2020-09-24 17:57:43 +02:00
|
|
|
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("aws_instance.bar")},
|
2020-03-31 20:03:33 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
|
|
|
)
|
2017-04-20 07:23:52 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
2018-05-05 04:24:06 +02:00
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
2017-04-20 07:23:52 +02:00
|
|
|
})
|
|
|
|
|
2017-11-22 00:08:00 +01:00
|
|
|
diags := ctx.Validate()
|
2018-05-21 20:32:43 +02:00
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("validate errors: %s", diags.Err())
|
2017-04-20 07:23:52 +02:00
|
|
|
}
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
_, diags = ctx.Refresh()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("refresh errors: %s", diags.Err())
|
2017-04-20 07:23:52 +02:00
|
|
|
}
|
|
|
|
|
2018-05-21 20:32:43 +02:00
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("plan errors: %s", diags.Err())
|
2017-04-20 07:23:52 +02:00
|
|
|
}
|
|
|
|
|
2018-09-20 03:31:59 +02:00
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.NoOp {
|
2020-10-08 14:56:03 +02:00
|
|
|
t.Fatalf("resource %s should not change, plan returned %s", res.Addr, res.Action)
|
2018-09-20 03:31:59 +02:00
|
|
|
}
|
2017-04-20 07:23:52 +02:00
|
|
|
}
|
|
|
|
}
|
2018-05-25 22:12:07 +02:00
|
|
|
|
|
|
|
// Higher level test at TestResource_dataSourceListApplyPanic
|
|
|
|
func TestContext2Plan_computedAttrRefTypeMismatch(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-computed-attr-ref-type-mismatch")
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
|
2018-09-05 23:35:30 +02:00
|
|
|
var diags tfdiags.Diagnostics
|
|
|
|
if req.TypeName == "aws_instance" {
|
|
|
|
amiVal := req.Config.GetAttr("ami")
|
|
|
|
if amiVal.Type() != cty.String {
|
|
|
|
diags = diags.Append(fmt.Errorf("Expected ami to be cty.String, got %#v", amiVal))
|
2018-05-25 22:12:07 +02:00
|
|
|
}
|
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
return providers.ValidateResourceConfigResponse{
|
2018-09-05 23:35:30 +02:00
|
|
|
Diagnostics: diags,
|
|
|
|
}
|
2018-05-25 22:12:07 +02:00
|
|
|
}
|
2020-10-08 19:13:13 +02:00
|
|
|
p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
|
2020-10-08 14:56:03 +02:00
|
|
|
if req.TypeName != "aws_ami_list" {
|
|
|
|
t.Fatalf("Reached apply for unexpected resource type! %s", req.TypeName)
|
2018-05-25 22:12:07 +02:00
|
|
|
}
|
|
|
|
// Pretend like we make a thing and the computed list "ids" is populated
|
2020-10-08 14:56:03 +02:00
|
|
|
s := req.PlannedState.AsValueMap()
|
|
|
|
s["id"] = cty.StringVal("someid")
|
|
|
|
s["ids"] = cty.ListVal([]cty.Value{
|
|
|
|
cty.StringVal("ami-abc123"),
|
|
|
|
cty.StringVal("ami-bcd345"),
|
|
|
|
})
|
|
|
|
|
|
|
|
resp.NewState = cty.ObjectVal(s)
|
|
|
|
return
|
2018-05-25 22:12:07 +02:00
|
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-05-25 22:12:07 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("Succeeded; want type mismatch error for 'ami' argument")
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := `Inappropriate value for attribute "ami"`
|
|
|
|
if errStr := diags.Err().Error(); !strings.Contains(errStr, expected) {
|
|
|
|
t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", errStr, expected)
|
|
|
|
}
|
|
|
|
}
|
2018-06-23 01:54:27 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_selfRef(t *testing.T) {
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-06-23 01:54:27 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-06-23 01:54:27 +02:00
|
|
|
|
|
|
|
m := testModule(t, "plan-self-ref")
|
|
|
|
c := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-06-23 01:54:27 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
diags := c.Validate()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected validation failure: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
_, diags = c.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("plan succeeded; want error")
|
|
|
|
}
|
|
|
|
|
|
|
|
gotErrStr := diags.Err().Error()
|
|
|
|
wantErrStr := "Self-referential block"
|
|
|
|
if !strings.Contains(gotErrStr, wantErrStr) {
|
|
|
|
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_selfRefMulti(t *testing.T) {
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-06-23 01:54:27 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-06-23 01:54:27 +02:00
|
|
|
|
|
|
|
m := testModule(t, "plan-self-ref-multi")
|
|
|
|
c := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-06-23 01:54:27 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
diags := c.Validate()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected validation failure: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
_, diags = c.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("plan succeeded; want error")
|
|
|
|
}
|
|
|
|
|
|
|
|
gotErrStr := diags.Err().Error()
|
|
|
|
wantErrStr := "Self-referential block"
|
|
|
|
if !strings.Contains(gotErrStr, wantErrStr) {
|
|
|
|
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_selfRefMultiAll(t *testing.T) {
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-06-23 01:54:27 +02:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.List(cty.String), Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-06-23 01:54:27 +02:00
|
|
|
|
|
|
|
m := testModule(t, "plan-self-ref-multi-all")
|
|
|
|
c := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-06-23 01:54:27 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
diags := c.Validate()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected validation failure: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
_, diags = c.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatalf("plan succeeded; want error")
|
|
|
|
}
|
|
|
|
|
|
|
|
gotErrStr := diags.Err().Error()
|
2018-09-20 03:31:59 +02:00
|
|
|
|
|
|
|
// The graph is checked for cycles before we can walk it, so we don't
|
|
|
|
// encounter the self-reference check.
|
|
|
|
//wantErrStr := "Self-referential block"
|
|
|
|
wantErrStr := "Cycle"
|
2018-06-23 01:54:27 +02:00
|
|
|
if !strings.Contains(gotErrStr, wantErrStr) {
|
|
|
|
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
|
|
|
|
}
|
|
|
|
}
|
2018-09-15 00:40:09 +02:00
|
|
|
|
2018-09-24 21:14:32 +02:00
|
|
|
func TestContext2Plan_invalidOutput(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
data "aws_data_source" "name" {}
|
|
|
|
|
|
|
|
output "out" {
|
2020-05-06 03:34:31 +02:00
|
|
|
value = data.aws_data_source.name.missing
|
2018-09-24 21:14:32 +02:00
|
|
|
}`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2021-01-09 21:33:38 +01:00
|
|
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
2020-05-06 03:34:31 +02:00
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("data_id"),
|
|
|
|
"foo": cty.StringVal("foo"),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2018-09-24 21:14:32 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-09-24 21:14:32 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
// Should get this error:
|
|
|
|
// Unsupported attribute: This object does not have an attribute named "missing"
|
|
|
|
t.Fatal("succeeded; want errors")
|
|
|
|
}
|
|
|
|
|
|
|
|
gotErrStr := diags.Err().Error()
|
|
|
|
wantErrStr := "Unsupported attribute"
|
|
|
|
if !strings.Contains(gotErrStr, wantErrStr) {
|
|
|
|
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_invalidModuleOutput(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"child/main.tf": `
|
|
|
|
data "aws_data_source" "name" {}
|
|
|
|
|
|
|
|
output "out" {
|
|
|
|
value = "${data.aws_data_source.name.missing}"
|
|
|
|
}`,
|
|
|
|
"main.tf": `
|
|
|
|
module "child" {
|
|
|
|
source = "./child"
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
foo = "${module.child.out}"
|
|
|
|
}`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2021-01-09 21:33:38 +01:00
|
|
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
2020-05-06 03:34:31 +02:00
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("data_id"),
|
|
|
|
"foo": cty.StringVal("foo"),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2018-09-24 21:14:32 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-09-24 21:14:32 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
// Should get this error:
|
|
|
|
// Unsupported attribute: This object does not have an attribute named "missing"
|
|
|
|
t.Fatal("succeeded; want errors")
|
|
|
|
}
|
|
|
|
|
|
|
|
gotErrStr := diags.Err().Error()
|
|
|
|
wantErrStr := "Unsupported attribute"
|
|
|
|
if !strings.Contains(gotErrStr, wantErrStr) {
|
|
|
|
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-01 03:09:20 +02:00
|
|
|
func TestContext2Plan_variableValidation(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
variable "x" {
|
|
|
|
default = "bar"
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
foo = var.x
|
|
|
|
}`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
|
2019-06-01 03:09:20 +02:00
|
|
|
foo := req.Config.GetAttr("foo").AsString()
|
|
|
|
if foo == "bar" {
|
|
|
|
resp.Diagnostics = resp.Diagnostics.Append(errors.New("foo cannot be bar"))
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
|
|
|
resp.PlannedState = req.ProposedNewState
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2019-06-01 03:09:20 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
// Should get this error:
|
|
|
|
// Unsupported attribute: This object does not have an attribute named "missing"
|
|
|
|
t.Fatal("succeeded; want errors")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 22:06:37 +02:00
|
|
|
func TestContext2Plan_variableSensitivity(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-variable-sensitivity")
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
|
|
|
resp.PlannedState = req.ProposedNewState
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2020-09-10 22:06:37 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "aws_instance.foo":
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2021-05-12 14:55:10 +02:00
|
|
|
"foo": cty.StringVal("foo").Mark("sensitive"),
|
2020-09-10 22:06:37 +02:00
|
|
|
}), ric.After)
|
2020-09-16 22:48:28 +02:00
|
|
|
if len(res.ChangeSrc.BeforeValMarks) != 0 {
|
|
|
|
t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks)
|
|
|
|
}
|
|
|
|
if len(res.ChangeSrc.AfterValMarks) != 1 {
|
|
|
|
t.Errorf("unexpected AfterValMarks: %#v", res.ChangeSrc.AfterValMarks)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
pvm := res.ChangeSrc.AfterValMarks[0]
|
|
|
|
if got, want := pvm.Path, cty.GetAttrPath("foo"); !got.Equals(want) {
|
2020-09-16 22:54:04 +02:00
|
|
|
t.Errorf("unexpected path for mark\n got: %#v\nwant: %#v", got, want)
|
|
|
|
}
|
|
|
|
if got, want := pvm.Marks, cty.NewValueMarks("sensitive"); !got.Equal(want) {
|
|
|
|
t.Errorf("unexpected value for mark\n got: %#v\nwant: %#v", got, want)
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_variableSensitivityModule(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-variable-sensitivity-module")
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2020-09-10 22:06:37 +02:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
|
|
|
resp.PlannedState = req.ProposedNewState
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2020-12-03 23:10:30 +01:00
|
|
|
Variables: InputValues{
|
|
|
|
"another_var": &InputValue{
|
|
|
|
Value: cty.StringVal("boop"),
|
|
|
|
SourceType: ValueFromCaller,
|
|
|
|
},
|
|
|
|
},
|
2020-09-10 22:06:37 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2020-09-10 22:06:37 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
2020-09-16 22:54:04 +02:00
|
|
|
case "module.child.aws_instance.foo":
|
2020-09-10 22:06:37 +02:00
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
2021-05-12 14:55:10 +02:00
|
|
|
"foo": cty.StringVal("foo").Mark("sensitive"),
|
|
|
|
"value": cty.StringVal("boop").Mark("sensitive"),
|
2020-09-10 22:06:37 +02:00
|
|
|
}), ric.After)
|
2020-09-16 22:54:04 +02:00
|
|
|
if len(res.ChangeSrc.BeforeValMarks) != 0 {
|
|
|
|
t.Errorf("unexpected BeforeValMarks: %#v", res.ChangeSrc.BeforeValMarks)
|
|
|
|
}
|
2020-12-03 23:10:30 +01:00
|
|
|
if len(res.ChangeSrc.AfterValMarks) != 2 {
|
|
|
|
t.Errorf("expected AfterValMarks to contain two elements: %#v", res.ChangeSrc.AfterValMarks)
|
2020-09-16 22:54:04 +02:00
|
|
|
continue
|
|
|
|
}
|
2020-12-03 23:10:30 +01:00
|
|
|
// validate that the after marks have "foo" and "value"
|
|
|
|
contains := func(pvmSlice []cty.PathValueMarks, stepName string) bool {
|
|
|
|
for _, pvm := range pvmSlice {
|
|
|
|
if pvm.Path.Equals(cty.GetAttrPath(stepName)) {
|
|
|
|
if pvm.Marks.Equal(cty.NewValueMarks("sensitive")) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2020-09-16 22:48:28 +02:00
|
|
|
}
|
2020-12-03 23:10:30 +01:00
|
|
|
if !contains(res.ChangeSrc.AfterValMarks, "foo") {
|
|
|
|
t.Error("unexpected AfterValMarks to contain \"foo\" with sensitive mark")
|
|
|
|
}
|
|
|
|
if !contains(res.ChangeSrc.AfterValMarks, "value") {
|
|
|
|
t.Error("unexpected AfterValMarks to contain \"value\" with sensitive mark")
|
2020-09-16 22:48:28 +02:00
|
|
|
}
|
2020-09-10 22:06:37 +02:00
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-15 00:40:09 +02:00
|
|
|
func checkVals(t *testing.T, expected, got cty.Value) {
|
|
|
|
t.Helper()
|
2021-05-12 14:55:10 +02:00
|
|
|
// The GoStringer format seems to result in the closest thing to a useful
|
|
|
|
// diff for values with marks.
|
|
|
|
// TODO: if we want to continue using cmp.Diff on cty.Values, we should
|
|
|
|
// make a transformer that creates a more comparable structure.
|
|
|
|
valueTrans := cmp.Transformer("gostring", func(v cty.Value) string {
|
|
|
|
return fmt.Sprintf("%#v\n", v)
|
|
|
|
})
|
2018-09-15 00:40:09 +02:00
|
|
|
if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) {
|
|
|
|
t.Fatal(cmp.Diff(expected, got, valueTrans, equateEmpty))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func objectVal(t *testing.T, schema *configschema.Block, m map[string]cty.Value) cty.Value {
|
|
|
|
t.Helper()
|
|
|
|
v, err := schema.CoerceValue(
|
|
|
|
cty.ObjectVal(m),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
2018-10-31 21:41:36 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_requiredModuleOutput(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-required-output")
|
|
|
|
p := testProvider("test")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-10-31 21:41:36 +01:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_resource": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"required": {Type: cty.String, Required: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-10-31 21:41:36 +01:00
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-10-31 21:41:36 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
|
2018-11-02 01:41:35 +01:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var expected cty.Value
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "test_resource.root":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"required": cty.UnknownVal(cty.String),
|
|
|
|
})
|
|
|
|
case "module.mod.test_resource.for_output":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"required": cty.StringVal("val"),
|
|
|
|
})
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
|
|
|
|
checkVals(t, expected, ric.After)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestContext2Plan_requiredModuleObject(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-required-whole-mod")
|
|
|
|
p := testProvider("test")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2018-11-02 01:41:35 +01:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_resource": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"required": {Type: cty.String, Required: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2018-11-02 01:41:35 +01:00
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-03-31 20:03:33 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
2018-11-02 01:41:35 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["test_resource"].Block
|
2018-10-31 21:41:36 +01:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 2 {
|
|
|
|
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
2018-11-02 01:32:30 +01:00
|
|
|
t.Run(fmt.Sprintf("%s %s", res.Action, res.Addr), func(t *testing.T) {
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("expected resource creation, got %s", res.Action)
|
|
|
|
}
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-10-31 21:41:36 +01:00
|
|
|
|
2018-11-02 01:32:30 +01:00
|
|
|
var expected cty.Value
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "test_resource.root":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"required": cty.UnknownVal(cty.String),
|
|
|
|
})
|
|
|
|
case "module.mod.test_resource.for_output":
|
|
|
|
expected = objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"required": cty.StringVal("val"),
|
|
|
|
})
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
2018-10-31 21:41:36 +01:00
|
|
|
|
2018-11-02 01:32:30 +01:00
|
|
|
checkVals(t, expected, ric.After)
|
|
|
|
})
|
2018-10-31 21:41:36 +01:00
|
|
|
}
|
|
|
|
}
|
2020-03-27 17:42:00 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_expandOrphan(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
module "mod" {
|
|
|
|
count = 1
|
|
|
|
source = "./mod"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
"mod/main.tf": `
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(0))).SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
|
2020-03-27 17:42:00 +01:00
|
|
|
},
|
2020-04-06 18:50:37 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
2020-03-27 17:42:00 +01:00
|
|
|
)
|
|
|
|
state.EnsureModule(addrs.RootModuleInstance.Child("mod", addrs.IntKey(1))).SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("aws_instance.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"child","type":"aws_instance"}`),
|
2020-03-27 17:42:00 +01:00
|
|
|
},
|
2020-04-06 18:50:37 +02:00
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
|
2020-03-27 17:42:00 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-03-27 17:42:00 +01:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
2020-04-06 18:50:37 +02:00
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
2020-03-27 17:42:00 +01:00
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
|
2020-03-27 22:16:08 +01:00
|
|
|
expected := map[string]plans.Action{
|
|
|
|
`module.mod[1].aws_instance.foo`: plans.Delete,
|
|
|
|
`module.mod[0].aws_instance.foo`: plans.NoOp,
|
2020-03-27 17:42:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
2020-03-27 22:16:08 +01:00
|
|
|
want := expected[res.Addr.String()]
|
|
|
|
if res.Action != want {
|
|
|
|
t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
|
2020-03-27 17:42:00 +01:00
|
|
|
}
|
2020-04-03 17:28:31 +02:00
|
|
|
delete(expected, res.Addr.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
for res, action := range expected {
|
|
|
|
t.Errorf("missing %s change for %s", action, res)
|
2020-03-27 17:42:00 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-10 22:52:47 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_indexInVar(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
module "a" {
|
|
|
|
count = 1
|
|
|
|
source = "./mod"
|
|
|
|
in = "test"
|
|
|
|
}
|
|
|
|
|
|
|
|
module "b" {
|
|
|
|
count = 1
|
|
|
|
source = "./mod"
|
|
|
|
in = length(module.a)
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
"mod/main.tf": `
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
foo = var.in
|
|
|
|
}
|
|
|
|
|
|
|
|
variable "in" {
|
|
|
|
}
|
|
|
|
|
|
|
|
output"out" {
|
|
|
|
value = aws_instance.foo.id
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
}
|
2020-06-10 22:11:05 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_targetExpandedAddress(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
module "mod" {
|
|
|
|
count = 3
|
|
|
|
source = "./mod"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
"mod/main.tf": `
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
count = 2
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
|
|
|
|
|
|
|
targets := []addrs.Targetable{}
|
|
|
|
target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo[0]")
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
targets = append(targets, target.Subject)
|
|
|
|
|
|
|
|
target, diags = addrs.ParseTargetStr("module.mod[2]")
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
targets = append(targets, target.Subject)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
Targets: targets,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := map[string]plans.Action{
|
|
|
|
// the single targeted mod[1] instances
|
|
|
|
`module.mod[1].aws_instance.foo[0]`: plans.Create,
|
|
|
|
// the whole mode[2]
|
|
|
|
`module.mod[2].aws_instance.foo[0]`: plans.Create,
|
|
|
|
`module.mod[2].aws_instance.foo[1]`: plans.Create,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
want := expected[res.Addr.String()]
|
|
|
|
if res.Action != want {
|
|
|
|
t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
|
|
|
|
}
|
|
|
|
delete(expected, res.Addr.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
for res, action := range expected {
|
|
|
|
t.Errorf("missing %s change for %s", action, res)
|
|
|
|
}
|
|
|
|
}
|
2020-06-16 02:45:23 +02:00
|
|
|
|
2020-08-05 23:50:23 +02:00
|
|
|
func TestContext2Plan_targetResourceInModuleInstance(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
module "mod" {
|
|
|
|
count = 3
|
|
|
|
source = "./mod"
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
"mod/main.tf": `
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
|
|
|
|
|
|
|
target, diags := addrs.ParseTargetStr("module.mod[1].aws_instance.foo")
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
|
|
|
|
targets := []addrs.Targetable{target.Subject}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
Targets: targets,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := map[string]plans.Action{
|
|
|
|
// the single targeted mod[1] instance
|
|
|
|
`module.mod[1].aws_instance.foo`: plans.Create,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
want := expected[res.Addr.String()]
|
|
|
|
if res.Action != want {
|
|
|
|
t.Fatalf("expected %s action, got: %q %s", want, res.Addr, res.Action)
|
|
|
|
}
|
|
|
|
delete(expected, res.Addr.String())
|
|
|
|
}
|
|
|
|
|
|
|
|
for res, action := range expected {
|
|
|
|
t.Errorf("missing %s change for %s", action, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-16 02:45:23 +02:00
|
|
|
func TestContext2Plan_moduleRefIndex(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
module "mod" {
|
|
|
|
for_each = {
|
|
|
|
a = "thing"
|
|
|
|
}
|
|
|
|
in = null
|
|
|
|
source = "./mod"
|
|
|
|
}
|
|
|
|
|
|
|
|
module "single" {
|
|
|
|
source = "./mod"
|
|
|
|
in = module.mod["a"]
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
"mod/main.tf": `
|
|
|
|
variable "in" {
|
|
|
|
}
|
|
|
|
|
|
|
|
output "out" {
|
|
|
|
value = "foo"
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "aws_instance" "foo" {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("aws")
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
}
|
2020-06-19 01:05:45 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_noChangeDataPlan(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
data "test_data_source" "foo" {}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := new(MockProvider)
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-06-19 01:05:45 +02:00
|
|
|
DataSources: map[string]*configschema.Block{
|
|
|
|
"test_data_source": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {
|
|
|
|
Type: cty.String,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
"foo": {
|
|
|
|
Type: cty.String,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2020-06-19 01:05:45 +02:00
|
|
|
|
2021-01-09 21:33:38 +01:00
|
|
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
2020-06-19 01:05:45 +02:00
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("data_id"),
|
|
|
|
"foo": cty.StringVal("foo"),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("data.test_data_source.foo").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"data_id", "foo":"foo"}`),
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
if res.Action != plans.NoOp {
|
|
|
|
t.Fatalf("expected NoOp, got: %q %s", res.Addr, res.Action)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-23 23:17:06 +02:00
|
|
|
|
|
|
|
// for_each can reference a resource with 0 instances
|
|
|
|
func TestContext2Plan_scaleInForEach(t *testing.T) {
|
|
|
|
p := testProvider("test")
|
|
|
|
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
locals {
|
|
|
|
m = {}
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "test_instance" "a" {
|
|
|
|
for_each = local.m
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "test_instance" "b" {
|
|
|
|
for_each = test_instance.a
|
|
|
|
}
|
|
|
|
`})
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_instance.a[0]").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"a0"}`),
|
|
|
|
Dependencies: []addrs.ConfigResource{},
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_instance.b").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"b"}`),
|
2020-09-24 17:57:43 +02:00
|
|
|
Dependencies: []addrs.ConfigResource{mustConfigResourceAddr("test_instance.a")},
|
2020-07-23 23:17:06 +02:00
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
assertNoErrors(t, diags)
|
|
|
|
}
|
2020-08-10 18:16:20 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_targetedModuleInstance(t *testing.T) {
|
|
|
|
m := testModule(t, "plan-targeted")
|
|
|
|
p := testProvider("aws")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-08-10 18:16:20 +02:00
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Child("mod", addrs.IntKey(0)),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatalf("unexpected errors: %s", diags.Err())
|
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
schema := p.GetProviderSchemaResponse.ResourceTypes["aws_instance"].Block
|
2020-08-10 18:16:20 +02:00
|
|
|
ty := schema.ImpliedType()
|
|
|
|
|
|
|
|
if len(plan.Changes.Resources) != 1 {
|
|
|
|
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, res := range plan.Changes.Resources {
|
|
|
|
ric, err := res.Decode(ty)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch i := ric.Addr.String(); i {
|
|
|
|
case "module.mod[0].aws_instance.foo":
|
|
|
|
if res.Action != plans.Create {
|
|
|
|
t.Fatalf("resource %s should be created", i)
|
|
|
|
}
|
|
|
|
checkVals(t, objectVal(t, schema, map[string]cty.Value{
|
|
|
|
"id": cty.UnknownVal(cty.String),
|
|
|
|
"num": cty.NumberIntVal(2),
|
2020-10-08 14:56:03 +02:00
|
|
|
"type": cty.UnknownVal(cty.String),
|
2020-08-10 18:16:20 +02:00
|
|
|
}), ric.After)
|
|
|
|
default:
|
|
|
|
t.Fatal("unknown instance:", i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-17 23:12:10 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_dataRefreshedInPlan(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
data "test_data_source" "d" {
|
|
|
|
}
|
|
|
|
`})
|
|
|
|
|
|
|
|
p := testProvider("test")
|
2021-01-09 21:33:38 +01:00
|
|
|
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
|
2020-09-17 23:12:10 +02:00
|
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
|
|
"id": cty.StringVal("this"),
|
|
|
|
"foo": cty.NullVal(cty.String),
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.ErrWithWarnings())
|
|
|
|
}
|
|
|
|
|
2021-05-05 00:59:58 +02:00
|
|
|
d := plan.PriorState.ResourceInstance(mustResourceInstanceAddr("data.test_data_source.d"))
|
2020-09-17 23:12:10 +02:00
|
|
|
if d == nil || d.Current == nil {
|
2021-05-05 00:59:58 +02:00
|
|
|
t.Fatal("data.test_data_source.d not found in state:", plan.PriorState)
|
2020-09-17 23:12:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if d.Current.Status != states.ObjectReady {
|
|
|
|
t.Fatal("expected data.test_data_source.d to be fully read in refreshed state, got status", d.Current.Status)
|
|
|
|
}
|
|
|
|
}
|
2020-09-17 21:32:32 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_dataReferencesResource(t *testing.T) {
|
|
|
|
p := testProvider("test")
|
|
|
|
|
|
|
|
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
|
|
|
|
resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("data source should not be read"))
|
|
|
|
return resp
|
|
|
|
}
|
|
|
|
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
locals {
|
2020-10-01 19:49:27 +02:00
|
|
|
x = "value"
|
2020-09-17 21:32:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
resource "test_resource" "a" {
|
2020-10-01 19:49:27 +02:00
|
|
|
value = local.x
|
2020-09-17 21:32:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// test_resource.a.value can be resolved during plan, but the reference implies
|
|
|
|
// that the data source should wait until the resource is created.
|
|
|
|
data "test_data_source" "d" {
|
2020-10-01 19:49:27 +02:00
|
|
|
foo = test_resource.a.value
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure referencing an indexed instance that has not yet created will also
|
|
|
|
// delay reading the data source
|
|
|
|
resource "test_resource" "b" {
|
|
|
|
count = 2
|
|
|
|
value = local.x
|
|
|
|
}
|
|
|
|
|
|
|
|
data "test_data_source" "e" {
|
|
|
|
foo = test_resource.b[0].value
|
2020-09-17 21:32:32 +02:00
|
|
|
}
|
|
|
|
`})
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
assertNoErrors(t, diags)
|
|
|
|
}
|
2020-09-23 17:06:56 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_skipRefresh(t *testing.T) {
|
|
|
|
p := testProvider("test")
|
2020-10-08 19:13:13 +02:00
|
|
|
p.PlanResourceChangeFn = testDiffFn
|
2020-09-23 17:06:56 +02:00
|
|
|
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
resource "test_instance" "a" {
|
|
|
|
}
|
|
|
|
`})
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_instance.a").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-10-08 14:56:03 +02:00
|
|
|
AttrsJSON: []byte(`{"id":"a","type":"test_instance"}`),
|
2020-09-23 17:06:56 +02:00
|
|
|
Dependencies: []addrs.ConfigResource{},
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
SkipRefresh: true,
|
|
|
|
})
|
|
|
|
|
2020-10-01 22:04:35 +02:00
|
|
|
plan, diags := ctx.Plan()
|
2020-09-23 17:06:56 +02:00
|
|
|
assertNoErrors(t, diags)
|
|
|
|
|
|
|
|
if p.ReadResourceCalled {
|
|
|
|
t.Fatal("Resource should not have been refreshed")
|
|
|
|
}
|
2020-10-01 22:04:35 +02:00
|
|
|
|
|
|
|
for _, c := range plan.Changes.Resources {
|
|
|
|
if c.Action != plans.NoOp {
|
|
|
|
t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
|
|
|
|
}
|
|
|
|
}
|
2020-09-23 17:06:56 +02:00
|
|
|
}
|
2020-09-25 15:49:52 +02:00
|
|
|
|
|
|
|
func TestContext2Plan_dataInModuleDependsOn(t *testing.T) {
|
|
|
|
p := testProvider("test")
|
|
|
|
|
|
|
|
readDataSourceB := false
|
|
|
|
p.ReadDataSourceFn = func(req providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
|
|
|
|
cfg := req.Config.AsValueMap()
|
|
|
|
foo := cfg["foo"].AsString()
|
|
|
|
|
|
|
|
cfg["id"] = cty.StringVal("ID")
|
|
|
|
cfg["foo"] = cty.StringVal("new")
|
|
|
|
|
|
|
|
if foo == "b" {
|
|
|
|
readDataSourceB = true
|
|
|
|
}
|
|
|
|
|
|
|
|
resp.State = cty.ObjectVal(cfg)
|
|
|
|
return resp
|
|
|
|
}
|
|
|
|
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
module "a" {
|
|
|
|
source = "./mod_a"
|
|
|
|
}
|
|
|
|
|
|
|
|
module "b" {
|
|
|
|
source = "./mod_b"
|
|
|
|
depends_on = [module.a]
|
|
|
|
}`,
|
|
|
|
"mod_a/main.tf": `
|
|
|
|
data "test_data_source" "a" {
|
|
|
|
foo = "a"
|
|
|
|
}`,
|
|
|
|
"mod_b/main.tf": `
|
|
|
|
data "test_data_source" "b" {
|
|
|
|
foo = "b"
|
|
|
|
}`,
|
|
|
|
})
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
assertNoErrors(t, diags)
|
|
|
|
|
|
|
|
// The change to data source a should not prevent data source b from being
|
|
|
|
// read.
|
|
|
|
if !readDataSourceB {
|
|
|
|
t.Fatal("data source b was not read during plan")
|
|
|
|
}
|
|
|
|
}
|
2020-10-28 19:51:04 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_rpcDiagnostics(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
resource "test_instance" "a" {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("test")
|
2020-10-28 22:38:01 +01:00
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
|
|
|
resp := testDiffFn(req)
|
|
|
|
resp.Diagnostics = resp.Diagnostics.Append(tfdiags.SimpleWarning("don't frobble"))
|
|
|
|
return resp
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-10-28 19:51:04 +01:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2020-10-28 19:51:04 +01:00
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
|
2020-10-28 22:38:01 +01:00
|
|
|
if len(diags) == 0 {
|
|
|
|
t.Fatal("expected warnings")
|
|
|
|
}
|
|
|
|
|
2020-10-28 19:51:04 +01:00
|
|
|
for _, d := range diags {
|
|
|
|
des := d.Description().Summary
|
2020-10-28 22:38:01 +01:00
|
|
|
if !strings.Contains(des, "frobble") {
|
|
|
|
t.Fatalf(`expected frobble, got %q`, des)
|
2020-10-28 19:51:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-03 23:42:03 +01:00
|
|
|
|
|
|
|
// ignore_changes needs to be re-applied to the planned value for provider
|
|
|
|
// using the LegacyTypeSystem
|
|
|
|
func TestContext2Plan_legacyProviderIgnoreChanges(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
resource "test_instance" "a" {
|
|
|
|
lifecycle {
|
|
|
|
ignore_changes = [data]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("test")
|
|
|
|
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
|
|
|
m := req.ProposedNewState.AsValueMap()
|
|
|
|
// this provider "hashes" the data attribute as bar
|
|
|
|
m["data"] = cty.StringVal("bar")
|
|
|
|
|
|
|
|
resp.PlannedState = cty.ObjectVal(m)
|
|
|
|
resp.LegacyTypeSystem = true
|
|
|
|
return resp
|
|
|
|
}
|
|
|
|
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-12-03 23:42:03 +01:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"data": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2020-12-03 23:42:03 +01:00
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_instance.a").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"a","data":"foo"}`),
|
|
|
|
Dependencies: []addrs.ConfigResource{},
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range plan.Changes.Resources {
|
|
|
|
if c.Action != plans.NoOp {
|
|
|
|
t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-03 23:58:46 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_validateIgnoreAll(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
resource "test_instance" "a" {
|
|
|
|
lifecycle {
|
|
|
|
ignore_changes = all
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("test")
|
2021-02-18 16:13:43 +01:00
|
|
|
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
|
2020-12-03 23:58:46 +01:00
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_instance": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"data": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2021-01-11 21:45:50 +01:00
|
|
|
})
|
2021-02-18 16:13:43 +01:00
|
|
|
p.ValidateResourceConfigFn = func(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
|
2020-12-03 23:58:46 +01:00
|
|
|
var diags tfdiags.Diagnostics
|
|
|
|
if req.TypeName == "test_instance" {
|
|
|
|
if !req.Config.GetAttr("id").IsNull() {
|
|
|
|
diags = diags.Append(errors.New("id cannot be set in config"))
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 16:13:43 +01:00
|
|
|
return providers.ValidateResourceConfigResponse{
|
2020-12-03 23:58:46 +01:00
|
|
|
Diagnostics: diags,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_instance.a").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"a","data":"foo"}`),
|
|
|
|
Dependencies: []addrs.ConfigResource{},
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
}
|
2020-12-16 20:10:51 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_dataRemovalNoProvider(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
resource "test_instance" "a" {
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("test")
|
|
|
|
|
|
|
|
state := states.NewState()
|
|
|
|
root := state.EnsureModule(addrs.RootModuleInstance)
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("test_instance.a").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"a","data":"foo"}`),
|
|
|
|
Dependencies: []addrs.ConfigResource{},
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
// the provider for this data source is no longer in the config, but that
|
|
|
|
// should not matter for state removal.
|
|
|
|
root.SetResourceInstanceCurrent(
|
|
|
|
mustResourceInstanceAddr("data.test_data_source.d").Resource,
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
|
|
|
AttrsJSON: []byte(`{"id":"d"}`),
|
|
|
|
Dependencies: []addrs.ConfigResource{},
|
|
|
|
},
|
|
|
|
mustProviderConfig(`provider["registry.terraform.io/local/test"]`),
|
|
|
|
)
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
// We still need to be able to locate the provider to decode the
|
|
|
|
// state, since we do not know during init that this provider is
|
|
|
|
// only used for an orphaned data source.
|
|
|
|
addrs.NewProvider("registry.terraform.io", "local", "test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: state,
|
|
|
|
})
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
}
|
2020-12-17 18:41:34 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_noSensitivityChange(t *testing.T) {
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
variable "sensitive_var" {
|
|
|
|
default = "hello"
|
|
|
|
sensitive = true
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "test_resource" "foo" {
|
|
|
|
value = var.sensitive_var
|
|
|
|
sensitive_value = var.sensitive_var
|
|
|
|
}`,
|
|
|
|
})
|
|
|
|
|
|
|
|
p := testProvider("test")
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
State: states.BuildState(func(s *states.SyncState) {
|
|
|
|
s.SetResourceInstanceCurrent(
|
|
|
|
addrs.Resource{
|
|
|
|
Mode: addrs.ManagedResourceMode,
|
|
|
|
Type: "test_resource",
|
|
|
|
Name: "foo",
|
|
|
|
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
|
|
|
&states.ResourceInstanceObjectSrc{
|
|
|
|
Status: states.ObjectReady,
|
2020-12-18 20:53:26 +01:00
|
|
|
AttrsJSON: []byte(`{"id":"foo", "value":"hello", "sensitive_value":"hello"}`),
|
2020-12-17 18:41:34 +01:00
|
|
|
AttrSensitivePaths: []cty.PathValueMarks{
|
2020-12-18 20:53:26 +01:00
|
|
|
{Path: cty.Path{cty.GetAttrStep{Name: "value"}}, Marks: cty.NewValueMarks("sensitive")},
|
|
|
|
{Path: cty.Path{cty.GetAttrStep{Name: "sensitive_value"}}, Marks: cty.NewValueMarks("sensitive")},
|
2020-12-17 18:41:34 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
addrs.AbsProviderConfig{
|
|
|
|
Provider: addrs.NewDefaultProvider("test"),
|
|
|
|
Module: addrs.RootModule,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range plan.Changes.Resources {
|
|
|
|
if c.Action != plans.NoOp {
|
|
|
|
t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-05 19:49:04 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_variableCustomValidationsSensitive(t *testing.T) {
|
|
|
|
m := testModule(t, "validate-variable-custom-validations-child-sensitive")
|
|
|
|
|
|
|
|
p := testProvider("test")
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
Providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
_, diags := ctx.Plan()
|
|
|
|
if !diags.HasErrors() {
|
|
|
|
t.Fatal("succeeded; want errors")
|
|
|
|
}
|
|
|
|
if got, want := diags.Err().Error(), `Invalid value for variable: Value must not be "nope".`; !strings.Contains(got, want) {
|
|
|
|
t.Fatalf("wrong error:\ngot: %s\nwant: message containing %q", got, want)
|
|
|
|
}
|
|
|
|
}
|
2021-01-14 14:59:31 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_nullOutputNoOp(t *testing.T) {
|
|
|
|
// this should always plan a NoOp change for the output
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
output "planned" {
|
|
|
|
value = false ? 1 : null
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
State: states.BuildState(func(s *states.SyncState) {
|
|
|
|
r := s.Module(addrs.RootModuleInstance)
|
|
|
|
r.SetOutputValue("planned", cty.NullVal(cty.DynamicPseudoType), false)
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range plan.Changes.Outputs {
|
|
|
|
if c.Action != plans.NoOp {
|
|
|
|
t.Fatalf("expected no changes, got %s for %q", c.Action, c.Addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-14 15:24:47 +01:00
|
|
|
|
|
|
|
func TestContext2Plan_createOutput(t *testing.T) {
|
|
|
|
// this should always plan a NoOp change for the output
|
|
|
|
m := testModuleInline(t, map[string]string{
|
|
|
|
"main.tf": `
|
|
|
|
output "planned" {
|
|
|
|
value = 1
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
|
|
Config: m,
|
|
|
|
State: states.NewState(),
|
|
|
|
})
|
|
|
|
plan, diags := ctx.Plan()
|
|
|
|
if diags.HasErrors() {
|
|
|
|
t.Fatal(diags.Err())
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range plan.Changes.Outputs {
|
|
|
|
if c.Action != plans.Create {
|
|
|
|
t.Fatalf("expected Create change, got %s for %q", c.Action, c.Addr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-21 18:43:50 +01:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// NOTE: Due to the size of this file, new tests should be added to
|
|
|
|
// context_plan2_test.go.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|