kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/plugin6/grpc_error.go (about) 1 package plugin6 2 3 import ( 4 "fmt" 5 "path" 6 "runtime" 7 8 "kubeform.dev/terraform-backend-sdk/tfdiags" 9 "google.golang.org/grpc/codes" 10 "google.golang.org/grpc/status" 11 ) 12 13 // grpcErr extracts some known error types and formats them into better 14 // representations for core. This must only be called from plugin methods. 15 // Since we don't use RPC status errors for the plugin protocol, these do not 16 // contain any useful details, and we can return some text that at least 17 // indicates the plugin call and possible error condition. 18 func grpcErr(err error) (diags tfdiags.Diagnostics) { 19 if err == nil { 20 return 21 } 22 23 // extract the method name from the caller. 24 pc, _, _, ok := runtime.Caller(1) 25 if !ok { 26 logger.Error("unknown grpc call", "error", err) 27 return diags.Append(err) 28 } 29 30 f := runtime.FuncForPC(pc) 31 32 // Function names will contain the full import path. Take the last 33 // segment, which will let users know which method was being called. 34 _, requestName := path.Split(f.Name()) 35 36 // Here we can at least correlate the error in the logs to a particular binary. 37 logger.Error(requestName, "error", err) 38 39 // TODO: while this expands the error codes into somewhat better messages, 40 // this still does not easily link the error to an actual user-recognizable 41 // plugin. The grpc plugin does not know its configured name, and the 42 // errors are in a list of diagnostics, making it hard for the caller to 43 // annotate the returned errors. 44 switch status.Code(err) { 45 case codes.Unavailable: 46 // This case is when the plugin has stopped running for some reason, 47 // and is usually the result of a crash. 48 diags = diags.Append(tfdiags.Sourceless( 49 tfdiags.Error, 50 "Plugin did not respond", 51 fmt.Sprintf("The plugin encountered an error, and failed to respond to the %s call. "+ 52 "The plugin logs may contain more details.", requestName), 53 )) 54 case codes.Canceled: 55 diags = diags.Append(tfdiags.Sourceless( 56 tfdiags.Error, 57 "Request cancelled", 58 fmt.Sprintf("The %s request was cancelled.", requestName), 59 )) 60 case codes.Unimplemented: 61 diags = diags.Append(tfdiags.Sourceless( 62 tfdiags.Error, 63 "Unsupported plugin method", 64 fmt.Sprintf("The %s method is not supported by this plugin.", requestName), 65 )) 66 default: 67 diags = diags.Append(tfdiags.Sourceless( 68 tfdiags.Error, 69 "Plugin error", 70 fmt.Sprintf("The plugin returned an unexpected error from %s: %v", requestName, err), 71 )) 72 } 73 return 74 }