terraform show -json: Add Errored field to output for plan (#33372)

* Add Errored field to JSON output

* Fix test error message
This commit is contained in:
Andrew Hickman 2023-06-19 11:16:41 +01:00 committed by GitHub
parent 66e3c20b18
commit 49f99db1c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 15 deletions

View File

@ -63,6 +63,7 @@ type plan struct {
RelevantAttributes []ResourceAttr `json:"relevant_attributes,omitempty"`
Checks json.RawMessage `json:"checks,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
Errored bool `json:"errored"`
}
func newPlan() *plan {
@ -221,6 +222,7 @@ func Marshal(
output := newPlan()
output.TerraformVersion = version.String()
output.Timestamp = p.Timestamp.Format(time.RFC3339)
output.Errored = p.Errored
err := output.marshalPlanVariables(p.VariableValues, config.Module.Variables)
if err != nil {

View File

@ -421,7 +421,43 @@ func TestShow_planWithForceReplaceChange(t *testing.T) {
if !strings.Contains(got, want) {
t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
}
}
func TestShow_planErrored(t *testing.T) {
_, snap := testModuleWithSnapshot(t, "show")
plan := testPlan(t)
plan.Errored = true
planFilePath := testPlanFile(
t,
snap,
states.NewState(),
plan,
)
view, done := testView(t)
c := &ShowCommand{
Meta: Meta{
testingOverrides: metaOverridesForProvider(showFixtureProvider()),
View: view,
},
}
args := []string{
planFilePath,
"-no-color",
}
code := c.Run(args)
output := done(t)
if code != 0 {
t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, output.Stderr())
}
got := output.Stdout()
want := `Planning failed. Terraform encountered an error while generating this plan.`
if !strings.Contains(got, want) {
t.Fatalf("unexpected output\ngot: %s\nwant: %s", got, want)
}
}
func TestShow_plan_json(t *testing.T) {
@ -525,6 +561,20 @@ func TestShow_json_output(t *testing.T) {
t.Fatalf("init failed\n%s", ui.ErrorWriter)
}
// read expected output
wantFile, err := os.Open("output.json")
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
defer wantFile.Close()
byteValue, err := ioutil.ReadAll(wantFile)
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
var want plan
json.Unmarshal([]byte(byteValue), &want)
// plan
planView, planDone := testView(t)
pc := &PlanCommand{
@ -542,8 +592,15 @@ func TestShow_json_output(t *testing.T) {
code := pc.Run(args)
planOutput := planDone(t)
if code != 0 {
t.Fatalf("unexpected exit status %d; want 0\ngot: %s", code, planOutput.Stderr())
var wantedCode int
if want.Errored {
wantedCode = 1
} else {
wantedCode = 0
}
if code != wantedCode {
t.Fatalf("unexpected exit status %d; want %d\ngot: %s", code, wantedCode, planOutput.Stderr())
}
// show
@ -569,22 +626,11 @@ func TestShow_json_output(t *testing.T) {
}
// compare view output to wanted output
var got, want plan
var got plan
gotString := showOutput.Stdout()
json.Unmarshal([]byte(gotString), &got)
wantFile, err := os.Open("output.json")
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
defer wantFile.Close()
byteValue, err := ioutil.ReadAll(wantFile)
if err != nil {
t.Fatalf("unexpected err: %s", err)
}
json.Unmarshal([]byte(byteValue), &want)
// Disregard format version to reduce needless test fixture churn
want.FormatVersion = got.FormatVersion
@ -1150,6 +1196,7 @@ type plan struct {
OutputChanges map[string]interface{} `json:"output_changes,omitempty"`
PriorState priorState `json:"prior_state,omitempty"`
Config map[string]interface{} `json:"configuration,omitempty"`
Errored bool `json:"errored"`
}
type priorState struct {

View File

@ -0,0 +1,15 @@
locals {
ami = "bar"
}
resource "test_instance" "test" {
ami = local.ami
lifecycle {
precondition {
// failing condition
condition = local.ami != "bar"
error_message = "ami is bar"
}
}
}

View File

@ -0,0 +1,35 @@
{
"format_version": "1.2",
"planned_values": {
"root_module": {}
},
"prior_state": {},
"configuration": {
"provider_config": {
"test": {
"full_name": "registry.terraform.io/hashicorp/test",
"name": "test"
}
},
"root_module": {
"resources": [
{
"address": "test_instance.test",
"expressions": {
"ami": {
"references": [
"local.ami"
]
}
},
"mode": "managed",
"name": "test",
"provider_config_key": "test",
"schema_version": 0,
"type": "test_instance"
}
]
}
},
"errored": true
}

View File

@ -229,7 +229,11 @@ For ease of consumption by callers, the plan representation includes a partial r
// resources with postconditions, with as much information as Terraform can
// recognize at plan time. Some objects will have status "unknown" to
// indicate that their status will only be determined after applying the plan.
"checks" <checks-representation>
"checks" <checks-representation>,
// "errored" indicates whether planning failed. An errored plan cannot be applied,
// but the actions planned before failure may help to understand the error.
"errored": false
}
```