| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | package grpcplugin | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2020-11-19 20:34:28 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2021-05-19 02:39:56 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2" | 
					
						
							| 
									
										
										
										
											2022-06-10 01:19:27 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin" | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	"github.com/hashicorp/go-plugin" | 
					
						
							|  |  |  | 	"google.golang.org/grpc/codes" | 
					
						
							|  |  |  | 	"google.golang.org/grpc/status" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | type ClientV2 struct { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	grpcplugin.DiagnosticsClient | 
					
						
							|  |  |  | 	grpcplugin.ResourceClient | 
					
						
							|  |  |  | 	grpcplugin.DataClient | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	grpcplugin.StreamClient | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	pluginextensionv2.RendererPlugin | 
					
						
							| 
									
										
										
										
											2022-06-10 01:19:27 +08:00
										 |  |  | 	secretsmanagerplugin.SecretsManagerPlugin | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newClientV2(descriptor PluginDescriptor, logger log.Logger, rpcClient plugin.ClientProtocol) (pluginClient, error) { | 
					
						
							|  |  |  | 	rawDiagnostics, err := rpcClient.Dispense("diagnostics") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rawResource, err := rpcClient.Dispense("resource") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rawData, err := rpcClient.Dispense("data") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	rawStream, err := rpcClient.Dispense("stream") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	rawRenderer, err := rpcClient.Dispense("renderer") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 01:19:27 +08:00
										 |  |  | 	rawSecretsManager, err := rpcClient.Dispense("secretsmanager") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | 	c := ClientV2{} | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if rawDiagnostics != nil { | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 		if diagnosticsClient, ok := rawDiagnostics.(grpcplugin.DiagnosticsClient); ok { | 
					
						
							|  |  |  | 			c.DiagnosticsClient = diagnosticsClient | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rawResource != nil { | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 		if resourceClient, ok := rawResource.(grpcplugin.ResourceClient); ok { | 
					
						
							|  |  |  | 			c.ResourceClient = resourceClient | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if rawData != nil { | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 		if dataClient, ok := rawData.(grpcplugin.DataClient); ok { | 
					
						
							| 
									
										
										
										
											2021-06-03 20:16:58 +08:00
										 |  |  | 			c.DataClient = dataClient | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	if rawStream != nil { | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 		if streamClient, ok := rawStream.(grpcplugin.StreamClient); ok { | 
					
						
							|  |  |  | 			c.StreamClient = streamClient | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if rawRenderer != nil { | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 		if rendererPlugin, ok := rawRenderer.(pluginextensionv2.RendererPlugin); ok { | 
					
						
							|  |  |  | 			c.RendererPlugin = rendererPlugin | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 01:19:27 +08:00
										 |  |  | 	if rawSecretsManager != nil { | 
					
						
							|  |  |  | 		if secretsManagerPlugin, ok := rawSecretsManager.(secretsmanagerplugin.SecretsManagerPlugin); ok { | 
					
						
							|  |  |  | 			c.SecretsManagerPlugin = secretsManagerPlugin | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-03 20:16:58 +08:00
										 |  |  | 	if descriptor.startRendererFn != nil { | 
					
						
							|  |  |  | 		if err := descriptor.startRendererFn(descriptor.pluginID, c.RendererPlugin, logger); err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-10 01:19:27 +08:00
										 |  |  | 	if descriptor.startSecretsManagerFn != nil { | 
					
						
							|  |  |  | 		if err := descriptor.startSecretsManagerFn(descriptor.pluginID, c.SecretsManagerPlugin, logger); err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	return &c, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-10 00:36:53 +08:00
										 |  |  | func (c *ClientV2) CollectMetrics(ctx context.Context, req *backend.CollectMetricsRequest) (*backend.CollectMetricsResult, error) { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if c.DiagnosticsClient == nil { | 
					
						
							|  |  |  | 		return &backend.CollectMetricsResult{}, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-10 00:36:53 +08:00
										 |  |  | 	protoResp, err := c.DiagnosticsClient.CollectMetrics(ctx, backend.ToProto().CollectMetricsRequest(req)) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 			return &backend.CollectMetricsResult{}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return backend.FromProto().CollectMetricsResponse(protoResp), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | func (c *ClientV2) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if c.DiagnosticsClient == nil { | 
					
						
							|  |  |  | 		return nil, backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	protoContext := backend.ToProto().PluginContext(req.PluginContext) | 
					
						
							| 
									
										
										
										
											2022-05-31 23:58:06 +08:00
										 |  |  | 	protoResp, err := c.DiagnosticsClient.CheckHealth(ctx, &pluginv2.CheckHealthRequest{PluginContext: protoContext, Headers: req.Headers}) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 			return &backend.CheckHealthResult{ | 
					
						
							|  |  |  | 				Status:  backend.HealthStatusUnknown, | 
					
						
							|  |  |  | 				Message: "Health check not implemented", | 
					
						
							|  |  |  | 			}, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return backend.FromProto().CheckHealthResponse(protoResp), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | func (c *ClientV2) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { | 
					
						
							| 
									
										
										
										
											2021-06-03 20:16:58 +08:00
										 |  |  | 	if c.DataClient == nil { | 
					
						
							|  |  |  | 		return nil, backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	protoReq := backend.ToProto().QueryDataRequest(req) | 
					
						
							|  |  |  | 	protoResp, err := c.DataClient.QueryData(ctx, protoReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 			return nil, backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-03 15:24:24 +08:00
										 |  |  | 		return nil, fmt.Errorf("%v: %w", "Failed to query data", err) | 
					
						
							| 
									
										
										
										
											2021-06-03 20:16:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return backend.FromProto().QueryDataResponse(protoResp) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | func (c *ClientV2) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	if c.ResourceClient == nil { | 
					
						
							|  |  |  | 		return backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	protoReq := backend.ToProto().CallResourceRequest(req) | 
					
						
							|  |  |  | 	protoStream, err := c.ResourceClient.CallResource(ctx, protoReq) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 			return backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-03 15:24:24 +08:00
										 |  |  | 		return fmt.Errorf("%v: %w", "Failed to call resource", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		protoResp, err := protoStream.Recv() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 				return backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-19 20:34:28 +08:00
										 |  |  | 			if errors.Is(err, io.EOF) { | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-03 15:24:24 +08:00
										 |  |  | 			return fmt.Errorf("%v: %w", "failed to receive call resource response", err) | 
					
						
							| 
									
										
										
										
											2020-06-11 22:14:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := sender.Send(backend.FromProto().CallResourceResponse(protoResp)); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | func (c *ClientV2) SubscribeStream(ctx context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) { | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	if c.StreamClient == nil { | 
					
						
							|  |  |  | 		return nil, backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	protoResp, err := c.StreamClient.SubscribeStream(ctx, backend.ToProto().SubscribeStreamRequest(req)) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	return backend.FromProto().SubscribeStreamResponse(protoResp), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | func (c *ClientV2) PublishStream(ctx context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) { | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	if c.StreamClient == nil { | 
					
						
							|  |  |  | 		return nil, backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	protoResp, err := c.StreamClient.PublishStream(ctx, backend.ToProto().PublishStreamRequest(req)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return backend.FromProto().PublishStreamResponse(protoResp), nil | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-14 20:30:39 +08:00
										 |  |  | func (c *ClientV2) RunStream(ctx context.Context, req *backend.RunStreamRequest, sender *backend.StreamSender) error { | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	if c.StreamClient == nil { | 
					
						
							|  |  |  | 		return backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	protoReq := backend.ToProto().RunStreamRequest(req) | 
					
						
							|  |  |  | 	protoStream, err := c.StreamClient.RunStream(ctx, protoReq) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 			return backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-06-03 15:24:24 +08:00
										 |  |  | 		return fmt.Errorf("%v: %w", "Failed to call resource", err) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2021-05-26 01:29:02 +08:00
										 |  |  | 		p, err := protoStream.Recv() | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			if status.Code(err) == codes.Unimplemented { | 
					
						
							|  |  |  | 				return backendplugin.ErrMethodNotImplemented | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if errors.Is(err, io.EOF) { | 
					
						
							|  |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-05-19 02:39:56 +08:00
										 |  |  | 			return fmt.Errorf("error running stream: %w", err) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-26 01:29:02 +08:00
										 |  |  | 		// From GRPC connection we receive already prepared JSON.
 | 
					
						
							|  |  |  | 		err = sender.SendJSON(p.Data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |