Skip to content

Commit

Permalink
command/jsonstate: fix inconsistency with resource address (hashicorp…
Browse files Browse the repository at this point in the history
…#24256)

* command/jsonstate: fix inconsistency with resource address

Resource addresses in state output were not including index for
instances created with for_each or count, while the index was appearing
in the plan output. This PR fixes that inconsistency, adds tests, and
updates the existing tests.

Fixes hashicorp#24110

* add tests showing expected prior state resource addressing
* added example of show json state output with modules
  • Loading branch information
mildwonkey committed Mar 5, 2020
1 parent 1305ea3 commit 2ddea68
Show file tree
Hide file tree
Showing 13 changed files with 508 additions and 17 deletions.
8 changes: 4 additions & 4 deletions command/jsonstate/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func marshalRootModule(s *states.State, schemas *terraform.Schemas) (module, err
var err error

ret.Address = ""
ret.Resources, err = marshalResources(s.RootModule().Resources, schemas)
ret.Resources, err = marshalResources(s.RootModule().Resources, addrs.RootModuleInstance, schemas)
if err != nil {
return ret, err
}
Expand Down Expand Up @@ -225,7 +225,7 @@ func marshalModules(
stateMod := s.Module(child)
// cm for child module, naming things is hard.
cm := module{Address: stateMod.Addr.String()}
rs, err := marshalResources(stateMod.Resources, schemas)
rs, err := marshalResources(stateMod.Resources, stateMod.Addr, schemas)
if err != nil {
return nil, err
}
Expand All @@ -244,14 +244,14 @@ func marshalModules(
return ret, nil
}

func marshalResources(resources map[string]*states.Resource, schemas *terraform.Schemas) ([]resource, error) {
func marshalResources(resources map[string]*states.Resource, module addrs.ModuleInstance, schemas *terraform.Schemas) ([]resource, error) {
var ret []resource

for _, r := range resources {
for k, ri := range r.Instances {

current := resource{
Address: r.Addr.String(),
Address: r.Addr.Absolute(module).Instance(k).String(),
Type: r.Addr.Type,
Name: r.Addr.Name,
ProviderName: r.ProviderConfig.Provider.LegacyString(),
Expand Down
102 changes: 93 additions & 9 deletions command/jsonstate/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,48 @@ func TestMarshalResources(t *testing.T) {
"single resource": {
map[string]*states.Resource{
"test_thing.baz": {
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "bar",
},
EachMode: states.NoEach,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.NoKey: {
Current: &states.ResourceInstanceObjectSrc{
SchemaVersion: 1,
Status: states.ObjectReady,
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
},
},
},
ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewLegacyProvider("test"),
Module: addrs.RootModuleInstance,
},
},
},
testSchemas(),
[]resource{
resource{
Address: "test_thing.bar",
Mode: "managed",
Type: "test_thing",
Name: "bar",
Index: addrs.InstanceKey(nil),
ProviderName: "test",
SchemaVersion: 1,
AttributeValues: attributeValues{
"foozles": json.RawMessage(`null`),
"woozles": json.RawMessage(`"confuzles"`),
},
},
},
false,
},
"resource with count": {
map[string]*states.Resource{
"test_thing.bar": {
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Expand All @@ -210,7 +252,7 @@ func TestMarshalResources(t *testing.T) {
testSchemas(),
[]resource{
resource{
Address: "test_thing.bar",
Address: "test_thing.bar[0]",
Mode: "managed",
Type: "test_thing",
Name: "bar",
Expand All @@ -225,6 +267,48 @@ func TestMarshalResources(t *testing.T) {
},
false,
},
"resource with for_each": {
map[string]*states.Resource{
"test_thing.bar": {
Addr: addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "test_thing",
Name: "bar",
},
EachMode: states.EachMap,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.StringKey("rockhopper"): {
Current: &states.ResourceInstanceObjectSrc{
SchemaVersion: 1,
Status: states.ObjectReady,
AttrsJSON: []byte(`{"woozles":"confuzles"}`),
},
},
},
ProviderConfig: addrs.AbsProviderConfig{
Provider: addrs.NewLegacyProvider("test"),
Module: addrs.RootModuleInstance,
},
},
},
testSchemas(),
[]resource{
resource{
Address: "test_thing.bar[\"rockhopper\"]",
Mode: "managed",
Type: "test_thing",
Name: "bar",
Index: addrs.StringKey("rockhopper"),
ProviderName: "test",
SchemaVersion: 1,
AttributeValues: attributeValues{
"foozles": json.RawMessage(`null`),
"woozles": json.RawMessage(`"confuzles"`),
},
},
},
false,
},
"deposed resource": {
map[string]*states.Resource{
"test_thing.baz": {
Expand All @@ -233,9 +317,9 @@ func TestMarshalResources(t *testing.T) {
Type: "test_thing",
Name: "bar",
},
EachMode: states.EachList,
EachMode: states.NoEach,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.IntKey(0): {
addrs.NoKey: {
Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{
states.DeposedKey(deposedKey): &states.ResourceInstanceObjectSrc{
SchemaVersion: 1,
Expand All @@ -258,7 +342,7 @@ func TestMarshalResources(t *testing.T) {
Mode: "managed",
Type: "test_thing",
Name: "bar",
Index: addrs.IntKey(0),
Index: addrs.InstanceKey(nil),
ProviderName: "test",
DeposedKey: deposedKey.String(),
AttributeValues: attributeValues{
Expand All @@ -277,9 +361,9 @@ func TestMarshalResources(t *testing.T) {
Type: "test_thing",
Name: "bar",
},
EachMode: states.EachList,
EachMode: states.NoEach,
Instances: map[addrs.InstanceKey]*states.ResourceInstance{
addrs.IntKey(0): {
addrs.NoKey: {
Deposed: map[states.DeposedKey]*states.ResourceInstanceObjectSrc{
states.DeposedKey(deposedKey): &states.ResourceInstanceObjectSrc{
SchemaVersion: 1,
Expand Down Expand Up @@ -307,7 +391,7 @@ func TestMarshalResources(t *testing.T) {
Mode: "managed",
Type: "test_thing",
Name: "bar",
Index: addrs.IntKey(0),
Index: addrs.InstanceKey(nil),
ProviderName: "test",
SchemaVersion: 1,
AttributeValues: attributeValues{
Expand All @@ -320,7 +404,7 @@ func TestMarshalResources(t *testing.T) {
Mode: "managed",
Type: "test_thing",
Name: "bar",
Index: addrs.IntKey(0),
Index: addrs.InstanceKey(nil),
ProviderName: "test",
DeposedKey: deposedKey.String(),
AttributeValues: attributeValues{
Expand All @@ -335,7 +419,7 @@ func TestMarshalResources(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
got, err := marshalResources(test.Resources, test.Schemas)
got, err := marshalResources(test.Resources, addrs.RootModuleInstance, test.Schemas)
if test.Err {
if err == nil {
t.Fatal("succeeded; want error")
Expand Down
4 changes: 0 additions & 4 deletions command/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,7 @@ func TestShow_json_output(t *testing.T) {
if !cmp.Equal(got, want) {
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
}

})

}
}

Expand Down Expand Up @@ -405,9 +403,7 @@ func TestShow_json_output_state(t *testing.T) {
if !cmp.Equal(got, want) {
t.Fatalf("wrong result:\n %v\n", cmp.Diff(got, want))
}

})

}
}

Expand Down
36 changes: 36 additions & 0 deletions command/testdata/show-json-state/basic/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"format_version": "0.1",
"terraform_version": "0.12.0",
"values": {
"root_module": {
"resources": [
{
"address": "test_instance.example[0]",
"mode": "managed",
"type": "test_instance",
"name": "example",
"index": 0,
"provider_name": "test",
"schema_version": 0,
"values": {
"ami": null,
"id": "621124146446964903"
}
},
{
"address": "test_instance.example[1]",
"mode": "managed",
"type": "test_instance",
"name": "example",
"index": 1,
"provider_name": "test",
"schema_version": 0,
"values": {
"ami": null,
"id": "4330206298367988603"
}
}
]
}
}
}
34 changes: 34 additions & 0 deletions command/testdata/show-json-state/basic/terraform.tfstate
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"version": 4,
"terraform_version": "0.12.0",
"serial": 1,
"lineage": "00bfda35-ad61-ec8d-c013-14b0320bc416",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "test_instance",
"name": "example",
"each": "list",
"provider": "provider.test",
"instances": [
{
"index_key": 0,
"schema_version": 0,
"attributes": {
"id": "621124146446964903"
},
"private": "bnVsbA=="
},
{
"index_key": 1,
"schema_version": 0,
"attributes": {
"id": "4330206298367988603"
},
"private": "bnVsbA=="
}
]
}
]
}
11 changes: 11 additions & 0 deletions command/testdata/show-json-state/modules/bar/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
variable "test_var" {
default = "bar-var"
}

output "test" {
value = var.test_var
}

resource "test_instance" "test" {
ami = var.test_var
}
14 changes: 14 additions & 0 deletions command/testdata/show-json-state/modules/foo/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
variable "test_var" {
default = "foo-var"
}

resource "test_instance" "test" {
ami = var.test_var
count = 1
}

output "test" {
value = var.test_var
}

provider "test" {}
13 changes: 13 additions & 0 deletions command/testdata/show-json-state/modules/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module "module_test_foo" {
source = "./foo"
test_var = "baz"
}

module "module_test_bar" {
source = "./bar"
}

output "test" {
value = module.module_test_foo.test
depends_on = [module.module_test_foo]
}
51 changes: 51 additions & 0 deletions command/testdata/show-json-state/modules/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"format_version": "0.1",
"terraform_version": "0.12.0",
"values": {
"outputs": {
"test": {
"sensitive": false,
"value": "baz"
}
},
"root_module": {
"child_modules": [
{
"resources": [
{
"address": "module.module_test_foo.test_instance.example[0]",
"mode": "managed",
"type": "test_instance",
"name": "example",
"index": 0,
"provider_name": "test",
"schema_version": 0,
"values": {
"ami": "foo-var",
"id": null
}
}
],
"address": "module.module_test_foo"
},
{
"resources": [
{
"address": "module.module_test_bar.test_instance.example",
"mode": "managed",
"type": "test_instance",
"name": "example",
"provider_name": "test",
"schema_version": 0,
"values": {
"ami": "bar-var",
"id": null
}
}
],
"address": "module.module_test_bar"
}
]
}
}
}
Loading

0 comments on commit 2ddea68

Please sign in to comment.