Skip to content

Commit

Permalink
bugfix: error reports are not generated when error in terraform plan
Browse files Browse the repository at this point in the history
  • Loading branch information
ms-henglu committed Nov 20, 2023
1 parent 54cf9fd commit 225e435
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 19 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ BUG FIXES:
- Fix the bug that other dependency resolvers are not called when error occurs in the previous dependency resolver.
- Fix the bug that the generated resources are not in the correct order.
- Fix the bug that `HEAD` method and other methods combination couldn't be handled correctly.
- Fix the bug that error reports are not generated for other azapi resources.
- Fix the bug that error reports are not generated when error happens during the `terraform plan`.

## v0.12.0
FEATURES:
Expand Down
38 changes: 20 additions & 18 deletions commands/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ func (c TestCommand) Execute() int {
}

logrus.Infof("running plan command to verify test resource...")
plan, err = terraform.Plan()
if err != nil {
logrus.Fatalf("error running terraform plan: %+v\n", err)
plan, planErr := terraform.Plan()
if planErr != nil {
logrus.Errorf("error running terraform plan: %+v\n", planErr)
}

reportDir := fmt.Sprintf("armstrong_reports_%s", time.Now().Format(time.Stamp))
Expand All @@ -150,24 +150,26 @@ func (c TestCommand) Execute() int {

logrus.Infof("generating reports...")
var passReport types.PassReport
if applyErr == nil && len(tf.GetChanges(plan)) == 0 {
if state, err := terraform.Show(); err == nil {
passReport = tf.NewPassReportFromState(state)
coverageReport, err := tf.NewCoverageReportFromState(state, c.swaggerPath)
if planErr == nil {
if applyErr == nil && len(tf.GetChanges(plan)) == 0 {
if state, err := terraform.Show(); err == nil {
passReport = tf.NewPassReportFromState(state)
coverageReport, err := tf.NewCoverageReportFromState(state, c.swaggerPath)
if err != nil {
logrus.Errorf("error producing coverage report: %+v", err)
}
storePassReport(passReport, coverageReport, reportDir, allPassedReportFileName)
} else {
logrus.Fatalf("error showing terraform state: %+v", err)
}
} else {
passReport = tf.NewPassReport(plan)
coverageReport, err := tf.NewCoverageReport(plan, c.swaggerPath)
if err != nil {
logrus.Errorf("error producing coverage report: %+v", err)
}
storePassReport(passReport, coverageReport, reportDir, allPassedReportFileName)
} else {
logrus.Fatalf("error showing terraform state: %+v", err)
}
} else {
passReport = tf.NewPassReport(plan)
coverageReport, err := tf.NewCoverageReport(plan, c.swaggerPath)
if err != nil {
logrus.Errorf("error producing coverage report: %+v", err)
storePassReport(passReport, coverageReport, reportDir, partialPassedReportFileName)
}
storePassReport(passReport, coverageReport, reportDir, partialPassedReportFileName)
}

errorReport := tf.NewErrorReport(applyErr, logs)
Expand All @@ -176,7 +178,7 @@ func (c TestCommand) Execute() int {
diffReport := tf.NewDiffReport(plan, logs)
storeDiffReport(diffReport, reportDir)

if applyErr == nil && c.destroyAfterTest {
if applyErr == nil && planErr == nil && c.destroyAfterTest {
logrus.Infof("running destroy command to delete resources...")
destroyErr := terraform.Destroy()
if destroyErr != nil {
Expand Down
2 changes: 1 addition & 1 deletion tf/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func NewErrorReport(applyErr error, logs []paltypes.RequestTrace) types.ErrorRep
id = matches[0][1]
apiVersion = matches[0][2]
}
if matches := regexp.MustCompile(`resource "azapi_resource" "(.+)"`).FindAllStringSubmatch(e, -1); len(matches) != 0 {
if matches := regexp.MustCompile(`resource "azapi_.+" "(.+)"`).FindAllStringSubmatch(e, -1); len(matches) != 0 {
label = matches[0][1]
}
if len(label) == 0 {
Expand Down
95 changes: 95 additions & 0 deletions tf/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package tf_test

import (
"fmt"
"testing"

"github.com/ms-henglu/armstrong/tf"
"github.com/ms-henglu/armstrong/types"
)

func Test_NewErrorReport(t *testing.T) {
var testcases = []struct {
Input error
Expect []types.Error
}{
{
Input: nil,
Expect: []types.Error{},
},
{
Input: fmt.Errorf(`error running terraform apply: exit status 1
Error: performing action of "Resource: (ResourceId \"/subscriptions/******/resourceGroups/acctest1220/providers/Microsoft.AppPlatform/Spring/acctest1220/buildServices/default/agentPools/acctest1220\" / Api Version \"2023-11-01-preview\")": PUT https://management.azure.com/subscriptions/******/resourceGroups/acctest1220/providers/Microsoft.AppPlatform/Spring/acctest1220/buildServices/default/agentPools/acctest1220
--------------------------------------------------------------------------------
RESPONSE 404: 404 Not Found
ERROR CODE: NotFound
--------------------------------------------------------------------------------
{
"error": {
"code": "NotFound",
"message": "build service default's agent pool acctest1220 does not exist",
"target": "/subscriptions/******/resourceGroups/acctest1220/providers/Microsoft.AppPlatform/Spring/acctest1220/buildServices/default/agentPools/acctest1220",
"details": null
}
}
--------------------------------------------------------------------------------
with azapi_resource_action.put_agentPool,
on main.tf line 71, in resource "azapi_resource_action" "put_agentPool":
71: resource "azapi_resource_action" "put_agentPool" {
`),
Expect: []types.Error{
{
Type: "Microsoft.AppPlatform/Spring/buildServices/agentPools@2023-11-01-preview",
Label: "put_agentPool",
Id: "/subscriptions/******/resourceGroups/acctest1220/providers/Microsoft.AppPlatform/Spring/acctest1220/buildServices/default/agentPools/acctest1220",
},
},
},
{
Input: fmt.Errorf(`error running terraform apply: exit status 1
Error: performing action of "Resource: (ResourceId \"/subscriptions/******/resourceGroups/acctest8179/providers/Microsoft.AppPlatform/Spring/acctest8179/eurekaServers/default\" / Api Version \"2023-11-01-preview\")": PUT https://management.azure.com/subscriptions/******/resourceGroups/acctest8179/providers/Microsoft.AppPlatform/Spring/acctest8179/eurekaServers/default
--------------------------------------------------------------------------------
RESPONSE 404: 404 Not Found
ERROR CODE UNAVAILABLE
--------------------------------------------------------------------------------
Response contained no body
--------------------------------------------------------------------------------
with azapi_resource_action.put_eurekaServer,
on main.tf line 54, in resource "azapi_resource_action" "put_eurekaServer":
54: resource "azapi_resource_action" "put_eurekaServer" {`),
Expect: []types.Error{
{
Type: "Microsoft.AppPlatform/Spring/eurekaServers@2023-11-01-preview",
Label: "put_eurekaServer",
Id: "/subscriptions/******/resourceGroups/acctest8179/providers/Microsoft.AppPlatform/Spring/acctest8179/eurekaServers/default",
},
},
},
}

for _, testcase := range testcases {
actual := tf.NewErrorReport(testcase.Input, nil)
if len(actual.Errors) != len(testcase.Expect) {
t.Errorf("Expect %d errors, but got %d", len(testcase.Expect), len(actual.Errors))
continue
}
for i := 0; i < len(actual.Errors); i++ {
if actual.Errors[i].Type != testcase.Expect[i].Type {
t.Errorf("Expect error type %s, but got %s", testcase.Expect[i].Type, actual.Errors[i].Type)
}
if actual.Errors[i].Id != testcase.Expect[i].Id {
t.Errorf("Expect error id %s, but got %s", testcase.Expect[i].Id, actual.Errors[i].Id)
}
if actual.Errors[i].Label != testcase.Expect[i].Label {
t.Errorf("Expect error label %s, but got %s", testcase.Expect[i].Label, actual.Errors[i].Label)
}
}
}
}

0 comments on commit 225e435

Please sign in to comment.