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:
parent
fb0c9714c1
commit
6e057c529e
|
@ -5,11 +5,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/configs"
|
"github.com/hashicorp/terraform/configs"
|
||||||
"github.com/hashicorp/terraform/configs/configschema"
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/zclconf/go-cty/cty"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config represents the complete configuration source
|
// Config represents the complete configuration source
|
||||||
|
@ -30,9 +31,11 @@ type providerConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type module struct {
|
type module struct {
|
||||||
Outputs map[string]configOutput `json:"outputs,omitempty"`
|
Outputs map[string]configOutput `json:"outputs,omitempty"`
|
||||||
Resources []resource `json:"resources,omitempty"`
|
// Resources are sorted in a user-friendly order that is undefined at this
|
||||||
ModuleCalls []moduleCall `json:"module_calls,omitempty"`
|
// time, but consistent.
|
||||||
|
Resources []resource `json:"resources,omitempty"`
|
||||||
|
ModuleCalls []moduleCall `json:"module_calls,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type moduleCall struct {
|
type moduleCall struct {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package jsonplan
|
||||||
// module is the representation of a module in state. This can be the root
|
// module is the representation of a module in state. This can be the root
|
||||||
// module or a child module.
|
// module or a child module.
|
||||||
type module struct {
|
type module struct {
|
||||||
|
// Resources are sorted in a user-friendly order that is undefined at this
|
||||||
|
// time, but consistent.
|
||||||
Resources []resource `json:"resources,omitempty"`
|
Resources []resource `json:"resources,omitempty"`
|
||||||
|
|
||||||
// Address is the absolute module address, omitted for the root module
|
// Address is the absolute module address, omitted for the root module
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/command/jsonconfig"
|
"github.com/hashicorp/terraform/command/jsonconfig"
|
||||||
|
@ -15,8 +16,6 @@ import (
|
||||||
"github.com/hashicorp/terraform/states"
|
"github.com/hashicorp/terraform/states"
|
||||||
"github.com/hashicorp/terraform/states/statefile"
|
"github.com/hashicorp/terraform/states/statefile"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
|
||||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FormatVersion represents the version of the json format and will be
|
// 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
|
// Plan is the top-level representation of the json format of a plan. It includes
|
||||||
// the complete config and current state.
|
// the complete config and current state.
|
||||||
type plan struct {
|
type plan struct {
|
||||||
FormatVersion string `json:"format_version,omitempty"`
|
FormatVersion string `json:"format_version,omitempty"`
|
||||||
PlannedValues stateValues `json:"planned_values,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"`
|
ResourceChanges []resourceChange `json:"resource_changes,omitempty"`
|
||||||
OutputChanges map[string]change `json:"output_changes,omitempty"`
|
OutputChanges map[string]change `json:"output_changes,omitempty"`
|
||||||
PriorState json.RawMessage `json:"prior_state,omitempty"`
|
PriorState json.RawMessage `json:"prior_state,omitempty"`
|
||||||
|
|
|
@ -3,14 +3,15 @@ package jsonplan
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/addrs"
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/configs/configschema"
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
"github.com/hashicorp/terraform/plans"
|
"github.com/hashicorp/terraform/plans"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// stateValues is the common representation of resolved values for both the
|
// 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)
|
ret = append(ret, resource)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Slice(ret, func(i, j int) bool {
|
||||||
|
return ret[i].Address < ret[j].Address
|
||||||
|
})
|
||||||
|
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ type output struct {
|
||||||
// module is the representation of a module in state. This can be the root module
|
// module is the representation of a module in state. This can be the root module
|
||||||
// or a child module
|
// or a child module
|
||||||
type module struct {
|
type module struct {
|
||||||
|
// Resources are sorted in a user-friendly order that is undefined at this
|
||||||
|
// time, but consistent.
|
||||||
Resources []resource `json:"resources,omitempty"`
|
Resources []resource `json:"resources,omitempty"`
|
||||||
|
|
||||||
// Address is the absolute module address, omitted for the root module
|
// Address is the absolute module address, omitted for the root module
|
||||||
|
|
|
@ -2,7 +2,8 @@ variable "test_var" {
|
||||||
default = "bar"
|
default = "bar"
|
||||||
}
|
}
|
||||||
resource "test_instance" "test" {
|
resource "test_instance" "test" {
|
||||||
ami = var.test_var
|
ami = var.test_var
|
||||||
|
count = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
output "test" {
|
output "test" {
|
||||||
|
|
|
@ -10,7 +10,26 @@
|
||||||
"root_module": {
|
"root_module": {
|
||||||
"resources": [
|
"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",
|
"mode": "managed",
|
||||||
"type": "test_instance",
|
"type": "test_instance",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
|
@ -22,7 +41,50 @@
|
||||||
},
|
},
|
||||||
"resource_changes": [
|
"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",
|
"mode": "managed",
|
||||||
"type": "test_instance",
|
"type": "test_instance",
|
||||||
"name": "test",
|
"name": "test",
|
||||||
|
@ -71,7 +133,9 @@
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"provider_config_key": "provider.test",
|
"provider_config_key": "provider.test",
|
||||||
"schema_version": 0,
|
"schema_version": 0,
|
||||||
"count_expression": {},
|
"count_expression": {
|
||||||
|
"constant_value": 3
|
||||||
|
},
|
||||||
"for_each_expression": {}
|
"for_each_expression": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue