github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/jsonchecks/checks.go (about) 1 package jsonchecks 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sort" 7 8 "github.com/hashicorp/terraform/internal/states" 9 ) 10 11 // MarshalCheckStates is the main entry-point for this package, which takes 12 // the top-level model object for checks in state and plan, and returns a 13 // JSON representation of it suitable for use in public integration points. 14 func MarshalCheckStates(results *states.CheckResults) []byte { 15 jsonResults := make([]checkResultStatic, 0, results.ConfigResults.Len()) 16 17 for _, elem := range results.ConfigResults.Elems { 18 staticAddr := elem.Key 19 aggrResult := elem.Value 20 21 objects := make([]checkResultDynamic, 0, aggrResult.ObjectResults.Len()) 22 for _, elem := range aggrResult.ObjectResults.Elems { 23 dynamicAddr := elem.Key 24 result := elem.Value 25 26 problems := make([]checkProblem, 0, len(result.FailureMessages)) 27 for _, msg := range result.FailureMessages { 28 problems = append(problems, checkProblem{ 29 Message: msg, 30 }) 31 } 32 sort.Slice(problems, func(i, j int) bool { 33 return problems[i].Message < problems[j].Message 34 }) 35 36 objects = append(objects, checkResultDynamic{ 37 Address: makeDynamicObjectAddr(dynamicAddr), 38 Status: checkStatusForJSON(result.Status), 39 Problems: problems, 40 }) 41 } 42 43 sort.Slice(objects, func(i, j int) bool { 44 return objects[i].Address["to_display"].(string) < objects[j].Address["to_display"].(string) 45 }) 46 47 jsonResults = append(jsonResults, checkResultStatic{ 48 Address: makeStaticObjectAddr(staticAddr), 49 Status: checkStatusForJSON(aggrResult.Status), 50 Instances: objects, 51 }) 52 } 53 54 sort.Slice(jsonResults, func(i, j int) bool { 55 return jsonResults[i].Address["to_display"].(string) < jsonResults[j].Address["to_display"].(string) 56 }) 57 58 ret, err := json.Marshal(jsonResults) 59 if err != nil { 60 // We totally control the input to json.Marshal, so any error here 61 // is a bug in the code above. 62 panic(fmt.Sprintf("invalid input to json.Marshal: %s", err)) 63 } 64 return ret 65 } 66 67 // checkResultStatic is the container for the static, configuration-driven 68 // idea of "checkable object" -- a resource block with conditions, for example -- 69 // which ensures that we can always say _something_ about each checkable 70 // object in the configuration even if Terraform Core encountered an error 71 // before being able to determine the dynamic instances of the checkable object. 72 type checkResultStatic struct { 73 ExperimentalNote experimentalNote `json:"//"` 74 75 // Address is the address of the checkable object this result relates to. 76 Address staticObjectAddr `json:"address"` 77 78 // Status is the aggregate status for all of the dynamic objects belonging 79 // to this static object. 80 Status checkStatus `json:"status"` 81 82 // Instances contains the results for each individual dynamic object that 83 // belongs to this static object. 84 Instances []checkResultDynamic `json:"instances,omitempty"` 85 } 86 87 // checkResultDynamic describes the check result for a dynamic object, which 88 // results from Terraform Core evaluating the "expansion" (e.g. count or for_each) 89 // of the containing object or its own containing module(s). 90 type checkResultDynamic struct { 91 // Address augments the Address of the containing checkResultStatic with 92 // instance-specific extra properties or overridden properties. 93 Address dynamicObjectAddr `json:"address"` 94 95 // Status is the status for this specific dynamic object. 96 Status checkStatus `json:"status"` 97 98 // Problems describes some optional details associated with a failure 99 // status, describing what fails. 100 // 101 // This does not include the errors for status "error", because Terraform 102 // Core emits those separately as normal diagnostics. However, if a 103 // particular object has a mixture of conditions that failed and conditions 104 // that were invalid then status can be "error" while simultaneously 105 // returning problems in this property. 106 Problems []checkProblem `json:"problems,omitempty"` 107 } 108 109 // checkProblem describes one of potentially several problems that led to 110 // a check being classified as status "fail". 111 type checkProblem struct { 112 // Message is the condition error message provided by the author. 113 Message string `json:"message"` 114 115 // We don't currently have any other problem-related data, but this is 116 // intentionally an object to allow us to add other data over time, such 117 // as the source location where the failing condition was defined. 118 } 119 120 type experimentalNote struct{} 121 122 func (n experimentalNote) MarshalJSON() ([]byte, error) { 123 return []byte(`"EXPERIMENTAL: see docs for details"`), nil 124 }