command/jsonplan: sort resources by address (#20113)

* command/jsonplan: sort resources by address
* command/show: extend test case to include resources with count
* command/json*: document resource ordering as consistent but undefined
This commit is contained in:
Kristin Laemmert 2019-01-25 09:17:40 -08:00 committed by GitHub
parent fb0c9714c1
commit 6e057c529e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 13 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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"`

View File

@ -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
}

View File

@ -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

View File

@ -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" {

View File

@ -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": {}
}
]