github.com/opentofu/opentofu@v1.7.1/internal/plugin6/convert/diagnostics.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package convert 7 8 import ( 9 "github.com/opentofu/opentofu/internal/tfdiags" 10 proto "github.com/opentofu/opentofu/internal/tfplugin6" 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 // WarnsAndErrorsToProto converts the warnings and errors return by the legacy 15 // provider to protobuf diagnostics. 16 func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) { 17 for _, w := range warns { 18 diags = AppendProtoDiag(diags, w) 19 } 20 21 for _, e := range errs { 22 diags = AppendProtoDiag(diags, e) 23 } 24 25 return diags 26 } 27 28 // AppendProtoDiag appends a new diagnostic from a warning string or an error. 29 // This panics if d is not a string or error. 30 func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic { 31 switch d := d.(type) { 32 case cty.PathError: 33 ap := PathToAttributePath(d.Path) 34 diags = append(diags, &proto.Diagnostic{ 35 Severity: proto.Diagnostic_ERROR, 36 Summary: d.Error(), 37 Attribute: ap, 38 }) 39 case error: 40 diags = append(diags, &proto.Diagnostic{ 41 Severity: proto.Diagnostic_ERROR, 42 Summary: d.Error(), 43 }) 44 case string: 45 diags = append(diags, &proto.Diagnostic{ 46 Severity: proto.Diagnostic_WARNING, 47 Summary: d, 48 }) 49 case *proto.Diagnostic: 50 diags = append(diags, d) 51 case []*proto.Diagnostic: 52 diags = append(diags, d...) 53 } 54 return diags 55 } 56 57 // ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics. 58 func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics { 59 var diags tfdiags.Diagnostics 60 for _, d := range ds { 61 var severity tfdiags.Severity 62 63 switch d.Severity { 64 case proto.Diagnostic_ERROR: 65 severity = tfdiags.Error 66 case proto.Diagnostic_WARNING: 67 severity = tfdiags.Warning 68 } 69 70 var newDiag tfdiags.Diagnostic 71 72 // if there's an attribute path, we need to create a AttributeValue diagnostic 73 if d.Attribute != nil { 74 path := AttributePathToPath(d.Attribute) 75 newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path) 76 } else { 77 newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail) 78 } 79 80 diags = diags.Append(newDiag) 81 } 82 83 return diags 84 } 85 86 // AttributePathToPath takes the proto encoded path and converts it to a cty.Path 87 func AttributePathToPath(ap *proto.AttributePath) cty.Path { 88 var p cty.Path 89 for _, step := range ap.Steps { 90 switch selector := step.Selector.(type) { 91 case *proto.AttributePath_Step_AttributeName: 92 p = p.GetAttr(selector.AttributeName) 93 case *proto.AttributePath_Step_ElementKeyString: 94 p = p.Index(cty.StringVal(selector.ElementKeyString)) 95 case *proto.AttributePath_Step_ElementKeyInt: 96 p = p.Index(cty.NumberIntVal(selector.ElementKeyInt)) 97 } 98 } 99 return p 100 } 101 102 // AttributePathToPath takes a cty.Path and converts it to a proto-encoded path. 103 func PathToAttributePath(p cty.Path) *proto.AttributePath { 104 ap := &proto.AttributePath{} 105 for _, step := range p { 106 switch selector := step.(type) { 107 case cty.GetAttrStep: 108 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{ 109 Selector: &proto.AttributePath_Step_AttributeName{ 110 AttributeName: selector.Name, 111 }, 112 }) 113 case cty.IndexStep: 114 key := selector.Key 115 switch key.Type() { 116 case cty.String: 117 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{ 118 Selector: &proto.AttributePath_Step_ElementKeyString{ 119 ElementKeyString: key.AsString(), 120 }, 121 }) 122 case cty.Number: 123 v, _ := key.AsBigFloat().Int64() 124 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{ 125 Selector: &proto.AttributePath_Step_ElementKeyInt{ 126 ElementKeyInt: v, 127 }, 128 }) 129 default: 130 // We'll bail early if we encounter anything else, and just 131 // return the valid prefix. 132 return ap 133 } 134 } 135 } 136 return ap 137 }