Skip to content

Commit

Permalink
json-output: Omit unchanged resource_drift entries
Browse files Browse the repository at this point in the history
Previously, if any resources were found to have drifted, the JSON plan
output would include a drift entry for every resource in state. This
commit aligns the JSON plan output with the CLI UI, and only includes
those resources where the old value does not equal the new value---i.e.
drift has been detected.

Also fixes a bug where the "address" field was missing from the drift
output, and adds some test coverage.
  • Loading branch information
alisdair committed Jun 18, 2021
1 parent 95df102 commit ef7a4e3
Show file tree
Hide file tree
Showing 6 changed files with 268 additions and 0 deletions.
7 changes: 7 additions & 0 deletions internal/command/jsonplan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ func (p *plan) marshalResourceDrift(oldState, newState *states.State, schemas *t
} else {
newVal = cty.NullVal(ty)
}

if oldVal.RawEquals(newVal) {
// No drift if the two values are semantically equivalent
continue
}

oldSensitive := jsonstate.SensitiveAsBool(oldVal)
newSensitive := jsonstate.SensitiveAsBool(newVal)
oldVal, _ = oldVal.UnmarkDeep()
Expand Down Expand Up @@ -290,6 +296,7 @@ func (p *plan) marshalResourceDrift(oldState, newState *states.State, schemas *t
}

change := resourceChange{
Address: addr.String(),
ModuleAddress: addr.Module.String(),
Mode: "managed", // drift reporting is only for managed resources
Name: addr.Resource.Resource.Name,
Expand Down
15 changes: 15 additions & 0 deletions internal/command/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,20 @@ func showFixtureSensitiveSchema() *providers.GetProviderSchemaResponse {
func showFixtureProvider() *terraform.MockProvider {
p := testProvider()
p.GetProviderSchemaResponse = showFixtureSchema()
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
idVal := req.PriorState.GetAttr("id")
amiVal := req.PriorState.GetAttr("ami")
if amiVal.RawEquals(cty.StringVal("refresh-me")) {
amiVal = cty.StringVal("refreshed")
}
return providers.ReadResourceResponse{
NewState: cty.ObjectVal(map[string]cty.Value{
"id": idVal,
"ami": amiVal,
}),
Private: req.Private,
}
}
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
idVal := req.ProposedNewState.GetAttr("id")
amiVal := req.ProposedNewState.GetAttr("ami")
Expand Down Expand Up @@ -761,6 +775,7 @@ type plan struct {
FormatVersion string `json:"format_version,omitempty"`
Variables map[string]interface{} `json:"variables,omitempty"`
PlannedValues map[string]interface{} `json:"planned_values,omitempty"`
ResourceDrift []interface{} `json:"resource_drift,omitempty"`
ResourceChanges []interface{} `json:"resource_changes,omitempty"`
OutputChanges map[string]interface{} `json:"output_changes,omitempty"`
PriorState priorState `json:"prior_state,omitempty"`
Expand Down
13 changes: 13 additions & 0 deletions internal/command/testdata/show-json/drift/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# In state with `ami = "foo"`, so this should be a regular update. The provider
# should not detect changes on refresh.
resource "test_instance" "no_refresh" {
ami = "bar"
}

# In state with `ami = "refresh-me"`, but the provider will return
# `"refreshed"` after the refresh phase. The plan should show the drift
# (`"refresh-me"` to `"refreshed"`) and plan the update (`"refreshed"` to
# `"baz"`).
resource "test_instance" "should_refresh" {
ami = "baz"
}
174 changes: 174 additions & 0 deletions internal/command/testdata/show-json/drift/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
{
"format_version": "0.2",
"planned_values": {
"root_module": {
"resources": [
{
"address": "test_instance.no_refresh",
"mode": "managed",
"type": "test_instance",
"name": "no_refresh",
"provider_name": "registry.terraform.io/hashicorp/test",
"schema_version": 0,
"values": {
"ami": "bar",
"id": "placeholder"
},
"sensitive_values": {}
},
{
"address": "test_instance.should_refresh",
"mode": "managed",
"type": "test_instance",
"name": "should_refresh",
"provider_name": "registry.terraform.io/hashicorp/test",
"schema_version": 0,
"values": {
"ami": "baz",
"id": "placeholder"
},
"sensitive_values": {}
}
]
}
},
"resource_drift": [
{
"address": "test_instance.should_refresh",
"mode": "managed",
"type": "test_instance",
"provider_name": "registry.terraform.io/hashicorp/test",
"name": "should_refresh",
"change": {
"actions": [
"update"
],
"before": {
"ami": "refresh-me",
"id": "placeholder"
},
"after": {
"ami": "refreshed",
"id": "placeholder"
},
"after_sensitive": {},
"before_sensitive": {}
}
}
],
"resource_changes": [
{
"address": "test_instance.no_refresh",
"mode": "managed",
"type": "test_instance",
"provider_name": "registry.terraform.io/hashicorp/test",
"name": "no_refresh",
"change": {
"actions": [
"update"
],
"before": {
"ami": "foo",
"id": "placeholder"
},
"after": {
"ami": "bar",
"id": "placeholder"
},
"after_unknown": {},
"after_sensitive": {},
"before_sensitive": {}
}
},
{
"address": "test_instance.should_refresh",
"mode": "managed",
"type": "test_instance",
"provider_name": "registry.terraform.io/hashicorp/test",
"name": "should_refresh",
"change": {
"actions": [
"update"
],
"before": {
"ami": "refreshed",
"id": "placeholder"
},
"after": {
"ami": "baz",
"id": "placeholder"
},
"after_unknown": {},
"after_sensitive": {},
"before_sensitive": {}
}
}
],
"prior_state": {
"format_version": "0.2",
"values": {
"root_module": {
"resources": [
{
"address": "test_instance.no_refresh",
"mode": "managed",
"type": "test_instance",
"name": "no_refresh",
"schema_version": 0,
"provider_name": "registry.terraform.io/hashicorp/test",
"values": {
"ami": "foo",
"id": "placeholder"
},
"sensitive_values": {}
},
{
"address": "test_instance.should_refresh",
"mode": "managed",
"type": "test_instance",
"name": "should_refresh",
"schema_version": 0,
"provider_name": "registry.terraform.io/hashicorp/test",
"values": {
"ami": "refreshed",
"id": "placeholder"
},
"sensitive_values": {}
}
]
}
}
},
"configuration": {
"root_module": {
"resources": [
{
"address": "test_instance.no_refresh",
"mode": "managed",
"type": "test_instance",
"name": "no_refresh",
"provider_config_key": "test",
"schema_version": 0,
"expressions": {
"ami": {
"constant_value": "bar"
}
}
},
{
"address": "test_instance.should_refresh",
"mode": "managed",
"type": "test_instance",
"name": "should_refresh",
"provider_config_key": "test",
"schema_version": 0,
"expressions": {
"ami": {
"constant_value": "baz"
}
}
}
]
}
}
}
38 changes: 38 additions & 0 deletions internal/command/testdata/show-json/drift/terraform.tfstate
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"version": 4,
"terraform_version": "0.12.0",
"serial": 7,
"lineage": "configuredUnchanged",
"resources": [
{
"mode": "managed",
"type": "test_instance",
"name": "no_refresh",
"provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"ami": "foo",
"id": "placeholder"
}
}
]
},
{
"mode": "managed",
"type": "test_instance",
"name": "should_refresh",
"provider": "provider[\"registry.terraform.io/hashicorp/test\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"ami": "refresh-me",
"id": "placeholder"
}
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@
]
}
},
"resource_drift": [
{
"address": "test_instance.test",
"mode": "managed",
"type": "test_instance",
"provider_name": "registry.terraform.io/hashicorp/test",
"name": "test",
"change": {
"actions": [
"delete"
],
"before": {
"ami": "bar",
"id": "placeholder"
},
"after": null,
"before_sensitive": {},
"after_sensitive": false
}
}
],
"resource_changes": [
{
"address": "test_instance.test[0]",
Expand Down

0 comments on commit ef7a4e3

Please sign in to comment.