mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
b40a4fb741
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
75 lines
2.4 KiB
Go
75 lines
2.4 KiB
Go
package plugin6
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"runtime"
|
|
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
// grpcErr extracts some known error types and formats them into better
|
|
// representations for core. This must only be called from plugin methods.
|
|
// Since we don't use RPC status errors for the plugin protocol, these do not
|
|
// contain any useful details, and we can return some text that at least
|
|
// indicates the plugin call and possible error condition.
|
|
func grpcErr(err error) (diags tfdiags.Diagnostics) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
// extract the method name from the caller.
|
|
pc, _, _, ok := runtime.Caller(1)
|
|
if !ok {
|
|
logger.Error("unknown grpc call", "error", err)
|
|
return diags.Append(err)
|
|
}
|
|
|
|
f := runtime.FuncForPC(pc)
|
|
|
|
// Function names will contain the full import path. Take the last
|
|
// segment, which will let users know which method was being called.
|
|
_, requestName := path.Split(f.Name())
|
|
|
|
// Here we can at least correlate the error in the logs to a particular binary.
|
|
logger.Error(requestName, "error", err)
|
|
|
|
// TODO: while this expands the error codes into somewhat better messages,
|
|
// this still does not easily link the error to an actual user-recognizable
|
|
// plugin. The grpc plugin does not know its configured name, and the
|
|
// errors are in a list of diagnostics, making it hard for the caller to
|
|
// annotate the returned errors.
|
|
switch status.Code(err) {
|
|
case codes.Unavailable:
|
|
// This case is when the plugin has stopped running for some reason,
|
|
// and is usually the result of a crash.
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Plugin did not respond",
|
|
fmt.Sprintf("The plugin encountered an error, and failed to respond to the %s call. "+
|
|
"The plugin logs may contain more details.", requestName),
|
|
))
|
|
case codes.Canceled:
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Request cancelled",
|
|
fmt.Sprintf("The %s request was cancelled.", requestName),
|
|
))
|
|
case codes.Unimplemented:
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Unsupported plugin method",
|
|
fmt.Sprintf("The %s method is not supported by this plugin.", requestName),
|
|
))
|
|
default:
|
|
diags = diags.Append(tfdiags.Sourceless(
|
|
tfdiags.Error,
|
|
"Plugin error",
|
|
fmt.Sprintf("The plugin returned an unexpected error from %s: %v", requestName, err),
|
|
))
|
|
}
|
|
return
|
|
}
|