mirror of https://github.com/grafana/grafana
Backend plugins: Renderer v2 plugin (#23625)
grafana-plugin-model is legacy and is replaced by new backend plugins SDK and architecture. Renderer is not part of SDK and we want to keep it that way for now since it's highly unlikely there will be more than one kind of renderer plugin. So this PR adds support for renderer plugin v2. Also adds support sending a Device Scale Factor parameter to the plugin v2 remote rendering service and by that replaces #22474. Adds support sending a Headers parameter to the plugin v2 and remote rendering service which for now only include Accect-Language header (the user locale in browser when using Grafana), ref grafana/grafana-image-renderer#45. Fixes health check json details response. Adds image renderer plugin configuration settings in defaults.ini and sample.ini. Co-Authored-By: Arve Knudsen <arve.knudsen@gmail.com>pull/23743/head
parent
97bb3dcf2d
commit
871ad73414
@ -0,0 +1,16 @@ |
||||
#!/bin/bash |
||||
|
||||
# To compile all protobuf files in this repository, run |
||||
# "make protobuf" at the top-level. |
||||
|
||||
set -eu |
||||
|
||||
DST_DIR=../genproto/pluginv2 |
||||
|
||||
SOURCE="${BASH_SOURCE[0]}" |
||||
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done |
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" |
||||
|
||||
cd "$DIR" |
||||
|
||||
protoc -I ./ rendererv2.proto --go_out=plugins=grpc:./ |
@ -0,0 +1,35 @@ |
||||
package pluginextensionv2 |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/hashicorp/go-plugin" |
||||
"google.golang.org/grpc" |
||||
) |
||||
|
||||
type RendererPlugin interface { |
||||
RendererClient |
||||
} |
||||
|
||||
type RendererGRPCPlugin struct { |
||||
plugin.NetRPCUnsupportedPlugin |
||||
} |
||||
|
||||
func (p *RendererGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error { |
||||
return nil |
||||
} |
||||
|
||||
func (p *RendererGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { |
||||
return &RendererGRPCClient{NewRendererClient(c)}, nil |
||||
} |
||||
|
||||
type RendererGRPCClient struct { |
||||
RendererClient |
||||
} |
||||
|
||||
func (m *RendererGRPCClient) Render(ctx context.Context, req *RenderRequest, opts ...grpc.CallOption) (*RenderResponse, error) { |
||||
return m.RendererClient.Render(ctx, req) |
||||
} |
||||
|
||||
var _ RendererClient = &RendererGRPCClient{} |
||||
var _ plugin.GRPCPlugin = &RendererGRPCPlugin{} |
@ -0,0 +1,333 @@ |
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: rendererv2.proto
|
||||
|
||||
package pluginextensionv2 |
||||
|
||||
import ( |
||||
context "context" |
||||
fmt "fmt" |
||||
proto "github.com/golang/protobuf/proto" |
||||
grpc "google.golang.org/grpc" |
||||
codes "google.golang.org/grpc/codes" |
||||
status "google.golang.org/grpc/status" |
||||
math "math" |
||||
) |
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal |
||||
var _ = fmt.Errorf |
||||
var _ = math.Inf |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type StringList struct { |
||||
Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` |
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
||||
XXX_unrecognized []byte `json:"-"` |
||||
XXX_sizecache int32 `json:"-"` |
||||
} |
||||
|
||||
func (m *StringList) Reset() { *m = StringList{} } |
||||
func (m *StringList) String() string { return proto.CompactTextString(m) } |
||||
func (*StringList) ProtoMessage() {} |
||||
func (*StringList) Descriptor() ([]byte, []int) { |
||||
return fileDescriptor_412d7c60977d55a2, []int{0} |
||||
} |
||||
|
||||
func (m *StringList) XXX_Unmarshal(b []byte) error { |
||||
return xxx_messageInfo_StringList.Unmarshal(m, b) |
||||
} |
||||
func (m *StringList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
||||
return xxx_messageInfo_StringList.Marshal(b, m, deterministic) |
||||
} |
||||
func (m *StringList) XXX_Merge(src proto.Message) { |
||||
xxx_messageInfo_StringList.Merge(m, src) |
||||
} |
||||
func (m *StringList) XXX_Size() int { |
||||
return xxx_messageInfo_StringList.Size(m) |
||||
} |
||||
func (m *StringList) XXX_DiscardUnknown() { |
||||
xxx_messageInfo_StringList.DiscardUnknown(m) |
||||
} |
||||
|
||||
var xxx_messageInfo_StringList proto.InternalMessageInfo |
||||
|
||||
func (m *StringList) GetValues() []string { |
||||
if m != nil { |
||||
return m.Values |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
type RenderRequest struct { |
||||
Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` |
||||
Width int32 `protobuf:"varint,2,opt,name=width,proto3" json:"width,omitempty"` |
||||
Height int32 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` |
||||
DeviceScaleFactor float32 `protobuf:"fixed32,4,opt,name=deviceScaleFactor,proto3" json:"deviceScaleFactor,omitempty"` |
||||
FilePath string `protobuf:"bytes,5,opt,name=filePath,proto3" json:"filePath,omitempty"` |
||||
RenderKey string `protobuf:"bytes,6,opt,name=renderKey,proto3" json:"renderKey,omitempty"` |
||||
Domain string `protobuf:"bytes,7,opt,name=domain,proto3" json:"domain,omitempty"` |
||||
Timeout int32 `protobuf:"varint,8,opt,name=timeout,proto3" json:"timeout,omitempty"` |
||||
Timezone string `protobuf:"bytes,9,opt,name=timezone,proto3" json:"timezone,omitempty"` |
||||
Headers map[string]*StringList `protobuf:"bytes,10,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
||||
XXX_unrecognized []byte `json:"-"` |
||||
XXX_sizecache int32 `json:"-"` |
||||
} |
||||
|
||||
func (m *RenderRequest) Reset() { *m = RenderRequest{} } |
||||
func (m *RenderRequest) String() string { return proto.CompactTextString(m) } |
||||
func (*RenderRequest) ProtoMessage() {} |
||||
func (*RenderRequest) Descriptor() ([]byte, []int) { |
||||
return fileDescriptor_412d7c60977d55a2, []int{1} |
||||
} |
||||
|
||||
func (m *RenderRequest) XXX_Unmarshal(b []byte) error { |
||||
return xxx_messageInfo_RenderRequest.Unmarshal(m, b) |
||||
} |
||||
func (m *RenderRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
||||
return xxx_messageInfo_RenderRequest.Marshal(b, m, deterministic) |
||||
} |
||||
func (m *RenderRequest) XXX_Merge(src proto.Message) { |
||||
xxx_messageInfo_RenderRequest.Merge(m, src) |
||||
} |
||||
func (m *RenderRequest) XXX_Size() int { |
||||
return xxx_messageInfo_RenderRequest.Size(m) |
||||
} |
||||
func (m *RenderRequest) XXX_DiscardUnknown() { |
||||
xxx_messageInfo_RenderRequest.DiscardUnknown(m) |
||||
} |
||||
|
||||
var xxx_messageInfo_RenderRequest proto.InternalMessageInfo |
||||
|
||||
func (m *RenderRequest) GetUrl() string { |
||||
if m != nil { |
||||
return m.Url |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *RenderRequest) GetWidth() int32 { |
||||
if m != nil { |
||||
return m.Width |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (m *RenderRequest) GetHeight() int32 { |
||||
if m != nil { |
||||
return m.Height |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (m *RenderRequest) GetDeviceScaleFactor() float32 { |
||||
if m != nil { |
||||
return m.DeviceScaleFactor |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (m *RenderRequest) GetFilePath() string { |
||||
if m != nil { |
||||
return m.FilePath |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *RenderRequest) GetRenderKey() string { |
||||
if m != nil { |
||||
return m.RenderKey |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *RenderRequest) GetDomain() string { |
||||
if m != nil { |
||||
return m.Domain |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *RenderRequest) GetTimeout() int32 { |
||||
if m != nil { |
||||
return m.Timeout |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
func (m *RenderRequest) GetTimezone() string { |
||||
if m != nil { |
||||
return m.Timezone |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func (m *RenderRequest) GetHeaders() map[string]*StringList { |
||||
if m != nil { |
||||
return m.Headers |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
type RenderResponse struct { |
||||
Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` |
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"` |
||||
XXX_unrecognized []byte `json:"-"` |
||||
XXX_sizecache int32 `json:"-"` |
||||
} |
||||
|
||||
func (m *RenderResponse) Reset() { *m = RenderResponse{} } |
||||
func (m *RenderResponse) String() string { return proto.CompactTextString(m) } |
||||
func (*RenderResponse) ProtoMessage() {} |
||||
func (*RenderResponse) Descriptor() ([]byte, []int) { |
||||
return fileDescriptor_412d7c60977d55a2, []int{2} |
||||
} |
||||
|
||||
func (m *RenderResponse) XXX_Unmarshal(b []byte) error { |
||||
return xxx_messageInfo_RenderResponse.Unmarshal(m, b) |
||||
} |
||||
func (m *RenderResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |
||||
return xxx_messageInfo_RenderResponse.Marshal(b, m, deterministic) |
||||
} |
||||
func (m *RenderResponse) XXX_Merge(src proto.Message) { |
||||
xxx_messageInfo_RenderResponse.Merge(m, src) |
||||
} |
||||
func (m *RenderResponse) XXX_Size() int { |
||||
return xxx_messageInfo_RenderResponse.Size(m) |
||||
} |
||||
func (m *RenderResponse) XXX_DiscardUnknown() { |
||||
xxx_messageInfo_RenderResponse.DiscardUnknown(m) |
||||
} |
||||
|
||||
var xxx_messageInfo_RenderResponse proto.InternalMessageInfo |
||||
|
||||
func (m *RenderResponse) GetError() string { |
||||
if m != nil { |
||||
return m.Error |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func init() { |
||||
proto.RegisterType((*StringList)(nil), "pluginextensionv2.StringList") |
||||
proto.RegisterType((*RenderRequest)(nil), "pluginextensionv2.RenderRequest") |
||||
proto.RegisterMapType((map[string]*StringList)(nil), "pluginextensionv2.RenderRequest.HeadersEntry") |
||||
proto.RegisterType((*RenderResponse)(nil), "pluginextensionv2.RenderResponse") |
||||
} |
||||
|
||||
func init() { |
||||
proto.RegisterFile("rendererv2.proto", fileDescriptor_412d7c60977d55a2) |
||||
} |
||||
|
||||
var fileDescriptor_412d7c60977d55a2 = []byte{ |
||||
// 380 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x92, 0x5f, 0x6f, 0xd3, 0x30, |
||||
0x14, 0xc5, 0x95, 0x86, 0xa4, 0xcd, 0x2d, 0xa0, 0xd6, 0xfc, 0x91, 0x55, 0x81, 0x14, 0x2a, 0x84, |
||||
0xf2, 0x00, 0x79, 0x48, 0x5f, 0x10, 0xbc, 0x21, 0xf1, 0x47, 0x02, 0x24, 0xe4, 0x3e, 0x95, 0xb7, |
||||
0xac, 0xb9, 0x6b, 0xac, 0xa6, 0x76, 0xe7, 0x38, 0xd9, 0xb2, 0x6f, 0xb4, 0x6f, 0x39, 0xc5, 0x4e, |
||||
0xd6, 0x4d, 0x9d, 0xb6, 0xb7, 0xfb, 0xf3, 0x3d, 0xbe, 0xc7, 0x3e, 0x36, 0x4c, 0x14, 0x8a, 0x0c, |
||||
0x15, 0xaa, 0x3a, 0x89, 0xf7, 0x4a, 0x6a, 0x49, 0xa6, 0xfb, 0xa2, 0xda, 0x70, 0x81, 0x17, 0x1a, |
||||
0x45, 0xc9, 0xa5, 0xa8, 0x93, 0xf9, 0x7b, 0x80, 0xa5, 0x56, 0x5c, 0x6c, 0xfe, 0xf0, 0x52, 0x93, |
||||
0xd7, 0xe0, 0xd7, 0x69, 0x51, 0x61, 0x49, 0x9d, 0xd0, 0x8d, 0x02, 0xd6, 0xd1, 0xfc, 0xca, 0x85, |
||||
0x67, 0xcc, 0x4c, 0x63, 0x78, 0x56, 0x61, 0xa9, 0xc9, 0x04, 0xdc, 0x4a, 0x15, 0xd4, 0x09, 0x9d, |
||||
0x28, 0x60, 0x6d, 0x49, 0x5e, 0x82, 0x77, 0xce, 0x33, 0x9d, 0xd3, 0x41, 0xe8, 0x44, 0x1e, 0xb3, |
||||
0xd0, 0x4e, 0xcc, 0x91, 0x6f, 0x72, 0x4d, 0x5d, 0xb3, 0xdc, 0x11, 0xf9, 0x08, 0xd3, 0x0c, 0x6b, |
||||
0xbe, 0xc6, 0xe5, 0x3a, 0x2d, 0xf0, 0x47, 0xba, 0xd6, 0x52, 0xd1, 0x27, 0xa1, 0x13, 0x0d, 0xd8, |
||||
0x71, 0x83, 0xcc, 0x60, 0x74, 0xca, 0x0b, 0xfc, 0x97, 0xea, 0x9c, 0x7a, 0xc6, 0xf2, 0x86, 0xc9, |
||||
0x1b, 0x08, 0xec, 0x45, 0x7f, 0x63, 0x43, 0x7d, 0xd3, 0x3c, 0x2c, 0xb4, 0xfe, 0x99, 0xdc, 0xa5, |
||||
0x5c, 0xd0, 0xa1, 0x69, 0x75, 0x44, 0x28, 0x0c, 0x35, 0xdf, 0xa1, 0xac, 0x34, 0x1d, 0x99, 0x83, |
||||
0xf5, 0xd8, 0x7a, 0xb5, 0xe5, 0xa5, 0x14, 0x48, 0x03, 0xeb, 0xd5, 0x33, 0xf9, 0x09, 0xc3, 0x1c, |
||||
0xd3, 0x0c, 0x55, 0x49, 0x21, 0x74, 0xa3, 0x71, 0xf2, 0x29, 0x3e, 0x8a, 0x34, 0xbe, 0x13, 0x54, |
||||
0xfc, 0xcb, 0xea, 0xbf, 0x0b, 0xad, 0x1a, 0xd6, 0xef, 0x9e, 0xad, 0xe0, 0xe9, 0xed, 0x46, 0x1b, |
||||
0xe7, 0x16, 0x9b, 0x3e, 0xce, 0x2d, 0x36, 0x64, 0x01, 0x9e, 0x09, 0xdf, 0xc4, 0x39, 0x4e, 0xde, |
||||
0xde, 0x63, 0x74, 0x78, 0x38, 0x66, 0xb5, 0x5f, 0x06, 0x9f, 0x9d, 0xf9, 0x07, 0x78, 0xde, 0x9f, |
||||
0xa0, 0xdc, 0x4b, 0x51, 0x62, 0xfb, 0x32, 0xa8, 0x94, 0x54, 0xdd, 0x78, 0x0b, 0xc9, 0x0a, 0x46, |
||||
0xac, 0xfb, 0x20, 0xe4, 0x2f, 0xf8, 0xb6, 0x26, 0xe1, 0x63, 0x17, 0x9a, 0xbd, 0x7b, 0x40, 0x61, |
||||
0x0d, 0xbf, 0xbd, 0xfa, 0xff, 0x22, 0xfe, 0x7a, 0xa4, 0x3a, 0xf1, 0xcd, 0x2f, 0x5c, 0x5c, 0x07, |
||||
0x00, 0x00, 0xff, 0xff, 0x36, 0x87, 0xfd, 0x2d, 0x99, 0x02, 0x00, 0x00, |
||||
} |
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context |
||||
var _ grpc.ClientConnInterface |
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion6 |
||||
|
||||
// RendererClient is the client API for Renderer service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type RendererClient interface { |
||||
Render(ctx context.Context, in *RenderRequest, opts ...grpc.CallOption) (*RenderResponse, error) |
||||
} |
||||
|
||||
type rendererClient struct { |
||||
cc grpc.ClientConnInterface |
||||
} |
||||
|
||||
func NewRendererClient(cc grpc.ClientConnInterface) RendererClient { |
||||
return &rendererClient{cc} |
||||
} |
||||
|
||||
func (c *rendererClient) Render(ctx context.Context, in *RenderRequest, opts ...grpc.CallOption) (*RenderResponse, error) { |
||||
out := new(RenderResponse) |
||||
err := c.cc.Invoke(ctx, "/pluginextensionv2.Renderer/Render", in, out, opts...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return out, nil |
||||
} |
||||
|
||||
// RendererServer is the server API for Renderer service.
|
||||
type RendererServer interface { |
||||
Render(context.Context, *RenderRequest) (*RenderResponse, error) |
||||
} |
||||
|
||||
// UnimplementedRendererServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedRendererServer struct { |
||||
} |
||||
|
||||
func (*UnimplementedRendererServer) Render(ctx context.Context, req *RenderRequest) (*RenderResponse, error) { |
||||
return nil, status.Errorf(codes.Unimplemented, "method Render not implemented") |
||||
} |
||||
|
||||
func RegisterRendererServer(s *grpc.Server, srv RendererServer) { |
||||
s.RegisterService(&_Renderer_serviceDesc, srv) |
||||
} |
||||
|
||||
func _Renderer_Render_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |
||||
in := new(RenderRequest) |
||||
if err := dec(in); err != nil { |
||||
return nil, err |
||||
} |
||||
if interceptor == nil { |
||||
return srv.(RendererServer).Render(ctx, in) |
||||
} |
||||
info := &grpc.UnaryServerInfo{ |
||||
Server: srv, |
||||
FullMethod: "/pluginextensionv2.Renderer/Render", |
||||
} |
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) { |
||||
return srv.(RendererServer).Render(ctx, req.(*RenderRequest)) |
||||
} |
||||
return interceptor(ctx, in, info, handler) |
||||
} |
||||
|
||||
var _Renderer_serviceDesc = grpc.ServiceDesc{ |
||||
ServiceName: "pluginextensionv2.Renderer", |
||||
HandlerType: (*RendererServer)(nil), |
||||
Methods: []grpc.MethodDesc{ |
||||
{ |
||||
MethodName: "Render", |
||||
Handler: _Renderer_Render_Handler, |
||||
}, |
||||
}, |
||||
Streams: []grpc.StreamDesc{}, |
||||
Metadata: "rendererv2.proto", |
||||
} |
@ -0,0 +1,29 @@ |
||||
syntax = "proto3"; |
||||
package pluginextensionv2; |
||||
|
||||
option go_package = ".;pluginextensionv2"; |
||||
|
||||
message StringList { |
||||
repeated string values = 1; |
||||
} |
||||
|
||||
message RenderRequest { |
||||
string url = 1; |
||||
int32 width = 2; |
||||
int32 height = 3; |
||||
float deviceScaleFactor = 4; |
||||
string filePath = 5; |
||||
string renderKey = 6; |
||||
string domain = 7; |
||||
int32 timeout = 8; |
||||
string timezone = 9; |
||||
map<string, StringList> headers = 10; |
||||
} |
||||
|
||||
message RenderResponse { |
||||
string error = 1; |
||||
} |
||||
|
||||
service Renderer { |
||||
rpc Render(RenderRequest) returns (RenderResponse); |
||||
} |
@ -0,0 +1,25 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
# Check whether protobuf & go plugin are installed |
||||
PROTOC_HELP_URL="http://google.github.io/proto-lens/installing-protoc.html" |
||||
PROTOC_GEN_GO_HELP_URL="https://github.com/golang/protobuf/tree/v1.3.4#installation" |
||||
|
||||
EXIT_CODE=0 |
||||
|
||||
if ! [ -x "$(command -v protoc)" ]; then |
||||
echo "Protocol Buffers not found." |
||||
echo "Please install Protocol Buffers and ensure 'protoc' is available in your PATH." |
||||
echo "See ${PROTOC_HELP_URL} for more." |
||||
echo |
||||
EXIT_CODE=1 |
||||
fi |
||||
|
||||
if ! [ -x "$(command -v protoc-gen-go)" ]; then |
||||
echo "Protocol Buffers Go plugin not found." |
||||
echo "Please install the plugin and ensure 'protoc-gen-go' is available in your PATH." |
||||
echo "See ${PROTOC_GEN_GO_HELP_URL} for more." |
||||
echo |
||||
EXIT_CODE=1 |
||||
fi |
||||
|
||||
exit $EXIT_CODE |
Loading…
Reference in new issue