diff --git a/command/jsonconfig/config.go b/command/jsonconfig/config.go index a1a170312..2e75db87e 100644 --- a/command/jsonconfig/config.go +++ b/command/jsonconfig/config.go @@ -5,11 +5,12 @@ import ( "fmt" "sort" + "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs" "github.com/hashicorp/terraform/configs/configschema" "github.com/hashicorp/terraform/terraform" - "github.com/zclconf/go-cty/cty" ) // Config represents the complete configuration source @@ -30,9 +31,11 @@ type providerConfig struct { } type module struct { - Outputs map[string]configOutput `json:"outputs,omitempty"` - Resources []resource `json:"resources,omitempty"` - ModuleCalls []moduleCall `json:"module_calls,omitempty"` + Outputs map[string]configOutput `json:"outputs,omitempty"` + // Resources are sorted in a user-friendly order that is undefined at this + // time, but consistent. + Resources []resource `json:"resources,omitempty"` + ModuleCalls []moduleCall `json:"module_calls,omitempty"` } type moduleCall struct { diff --git a/command/jsonplan/module.go b/command/jsonplan/module.go index 4531429e9..a122e77da 100644 --- a/command/jsonplan/module.go +++ b/command/jsonplan/module.go @@ -3,6 +3,8 @@ package jsonplan // module is the representation of a module in state. This can be the root // module or a child module. type module struct { + // Resources are sorted in a user-friendly order that is undefined at this + // time, but consistent. Resources []resource `json:"resources,omitempty"` // Address is the absolute module address, omitted for the root module diff --git a/command/jsonplan/plan.go b/command/jsonplan/plan.go index 48b5d70e8..91c92b6c9 100644 --- a/command/jsonplan/plan.go +++ b/command/jsonplan/plan.go @@ -6,6 +6,7 @@ import ( "sort" "github.com/zclconf/go-cty/cty" + ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/command/jsonconfig" @@ -15,8 +16,6 @@ import ( "github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/states/statefile" "github.com/hashicorp/terraform/terraform" - - ctyjson "github.com/zclconf/go-cty/cty/json" ) // FormatVersion represents the version of the json format and will be @@ -27,8 +26,10 @@ const FormatVersion = "0.1" // Plan is the top-level representation of the json format of a plan. It includes // the complete config and current state. type plan struct { - FormatVersion string `json:"format_version,omitempty"` - PlannedValues stateValues `json:"planned_values,omitempty"` + FormatVersion string `json:"format_version,omitempty"` + PlannedValues stateValues `json:"planned_values,omitempty"` + // ResourceChanges are sorted in a user-friendly order that is undefined at + // this time, but consistent. ResourceChanges []resourceChange `json:"resource_changes,omitempty"` OutputChanges map[string]change `json:"output_changes,omitempty"` PriorState json.RawMessage `json:"prior_state,omitempty"` diff --git a/command/jsonplan/values.go b/command/jsonplan/values.go index 5a28433d3..2df050197 100644 --- a/command/jsonplan/values.go +++ b/command/jsonplan/values.go @@ -3,14 +3,15 @@ package jsonplan import ( "encoding/json" "fmt" + "sort" "github.com/zclconf/go-cty/cty" + ctyjson "github.com/zclconf/go-cty/cty/json" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs/configschema" "github.com/hashicorp/terraform/plans" "github.com/hashicorp/terraform/terraform" - ctyjson "github.com/zclconf/go-cty/cty/json" ) // stateValues is the common representation of resolved values for both the @@ -171,6 +172,10 @@ func marshalPlanResources(changes *plans.Changes, ris []addrs.AbsResourceInstanc ret = append(ret, resource) } + sort.Slice(ret, func(i, j int) bool { + return ret[i].Address < ret[j].Address + }) + return ret, nil } diff --git a/command/jsonstate/state.go b/command/jsonstate/state.go index 8e08c2e9c..15a22cd8d 100644 --- a/command/jsonstate/state.go +++ b/command/jsonstate/state.go @@ -43,6 +43,8 @@ type output struct { // module is the representation of a module in state. This can be the root module // or a child module type module struct { + // Resources are sorted in a user-friendly order that is undefined at this + // time, but consistent. Resources []resource `json:"resources,omitempty"` // Address is the absolute module address, omitted for the root module diff --git a/command/test-fixtures/show-json/basic-create/main.tf b/command/test-fixtures/show-json/basic-create/main.tf index 3b857b329..d9e282763 100644 --- a/command/test-fixtures/show-json/basic-create/main.tf +++ b/command/test-fixtures/show-json/basic-create/main.tf @@ -2,7 +2,8 @@ variable "test_var" { default = "bar" } resource "test_instance" "test" { - ami = var.test_var + ami = var.test_var + count = 3 } output "test" { diff --git a/command/test-fixtures/show-json/basic-create/output.json b/command/test-fixtures/show-json/basic-create/output.json index 4284d821e..8db83be19 100644 --- a/command/test-fixtures/show-json/basic-create/output.json +++ b/command/test-fixtures/show-json/basic-create/output.json @@ -10,7 +10,26 @@ "root_module": { "resources": [ { - "address": "test_instance.test", + "address": "test_instance.test[0]", + "index": 0, + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "test", + "schema_version": 0 + }, + { + "address": "test_instance.test[1]", + "index": 1, + "mode": "managed", + "type": "test_instance", + "name": "test", + "provider_name": "test", + "schema_version": 0 + }, + { + "address": "test_instance.test[2]", + "index": 2, "mode": "managed", "type": "test_instance", "name": "test", @@ -22,7 +41,50 @@ }, "resource_changes": [ { - "address": "test_instance.test", + "address": "test_instance.test[0]", + "index": 0, + "mode": "managed", + "type": "test_instance", + "name": "test", + "deposed": true, + "change": { + "actions": [ + "create" + ], + "before": null, + "after_unknown": { + "ami": false, + "id": true + }, + "after": { + "ami": "bar" + } + } + }, + { + "address": "test_instance.test[1]", + "index": 1, + "mode": "managed", + "type": "test_instance", + "name": "test", + "deposed": true, + "change": { + "actions": [ + "create" + ], + "before": null, + "after_unknown": { + "ami": false, + "id": true + }, + "after": { + "ami": "bar" + } + } + }, + { + "address": "test_instance.test[2]", + "index": 2, "mode": "managed", "type": "test_instance", "name": "test", @@ -71,7 +133,9 @@ "name": "test", "provider_config_key": "provider.test", "schema_version": 0, - "count_expression": {}, + "count_expression": { + "constant_value": 3 + }, "for_each_expression": {} } ]