terraform/plugin/convert/diagnostics.go

89 lines
2.4 KiB
Go

package convert
import (
"github.com/hashicorp/terraform/plugin/proto"
"github.com/hashicorp/terraform/tfdiags"
"github.com/zclconf/go-cty/cty"
)
// WarnsAndErrorsToProto converts the warnings and errors return by the legacy
// provider to protobuf diagnostics.
func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) {
for _, w := range warns {
diags = AppendProtoDiag(diags, w)
}
for _, e := range errs {
diags = AppendProtoDiag(diags, e)
}
return diags
}
// AppendProtoDiag appends a new diagnostic from a warning string or an error.
// This panics if d is not a string or error.
func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic {
switch d := d.(type) {
case error:
diags = append(diags, &proto.Diagnostic{
Severity: proto.Diagnostic_ERROR,
Summary: d.Error(),
})
case string:
diags = append(diags, &proto.Diagnostic{
Severity: proto.Diagnostic_WARNING,
Summary: d,
})
case *proto.Diagnostic:
diags = append(diags, d)
case []*proto.Diagnostic:
diags = append(diags, d...)
}
return diags
}
// ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics.
func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
for _, d := range ds {
var severity tfdiags.Severity
switch d.Severity {
case proto.Diagnostic_ERROR:
severity = tfdiags.Error
case proto.Diagnostic_WARNING:
severity = tfdiags.Warning
}
var newDiag tfdiags.Diagnostic
// if there's an attribute path, we need to create a AttributeValue diagnostic
if d.Attribute != nil {
path := AttributePathToPath(d.Attribute)
newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
} else {
newDiag = tfdiags.Sourceless(severity, d.Summary, d.Detail)
}
diags = diags.Append(newDiag)
}
return diags
}
// AttributePathToPath takes the proto encoded path and converts it to a cty.Path
func AttributePathToPath(ap *proto.AttributePath) cty.Path {
var p cty.Path
for _, step := range ap.Steps {
switch selector := step.Selector.(type) {
case *proto.AttributePath_Step_AttributeName:
p = p.GetAttr(selector.AttributeName)
case *proto.AttributePath_Step_ElementKeyString:
p = p.Index(cty.StringVal(selector.ElementKeyString))
case *proto.AttributePath_Step_ElementKeyInt:
p = p.Index(cty.NumberIntVal(selector.ElementKeyInt))
}
}
return p
}