diff --git a/pkg/cmd/grafana-server/server.go b/pkg/cmd/grafana-server/server.go index 31ba8350086..2ec3bdf6b81 100644 --- a/pkg/cmd/grafana-server/server.go +++ b/pkg/cmd/grafana-server/server.go @@ -22,7 +22,6 @@ import ( "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/plugins" - tsdbplugins "github.com/grafana/grafana/pkg/plugins/backend" "github.com/grafana/grafana/pkg/services/alerting" "github.com/grafana/grafana/pkg/services/cleanup" "github.com/grafana/grafana/pkg/services/notifications" @@ -67,13 +66,13 @@ func (g *GrafanaServerImpl) Start() { search.Init() login.Init() social.NewOAuthService() - plugins.Init() - pluginClient, err := tsdbplugins.Init() + + pluginCloser, err := plugins.Init() if err != nil { g.log.Error("failed to start plugins", "error", err) g.Shutdown(1, "Startup failed") } - defer pluginClient.Kill() + defer pluginCloser() if err := provisioning.Init(g.context, setting.HomePath, setting.Cfg); err != nil { logger.Error("Failed to provision Grafana from config", "error", err) @@ -81,13 +80,13 @@ func (g *GrafanaServerImpl) Start() { return } - closer, err := tracing.Init(setting.Cfg) + tracingCloser, err := tracing.Init(setting.Cfg) if err != nil { g.log.Error("Tracing settings is not valid", "error", err) g.Shutdown(1, "Startup failed") return } - defer closer.Close() + defer tracingCloser.Close() // init alerting if setting.AlertingEnabled && setting.ExecuteAlerts { diff --git a/pkg/plugins/backend/log-wrapper.go b/pkg/plugins/backend/log-wrapper.go index 8a046f118a7..cf623695581 100644 --- a/pkg/plugins/backend/log-wrapper.go +++ b/pkg/plugins/backend/log-wrapper.go @@ -1,4 +1,4 @@ -package plugins +package backend import ( "log" @@ -7,32 +7,32 @@ import ( hclog "github.com/hashicorp/go-hclog" ) -type logWrapper struct { - logger glog.Logger +type LogWrapper struct { + Logger glog.Logger } -func (lw logWrapper) Trace(msg string, args ...interface{}) {} -func (lw logWrapper) Debug(msg string, args ...interface{}) {} -func (lw logWrapper) Info(msg string, args ...interface{}) {} -func (lw logWrapper) Warn(msg string, args ...interface{}) {} -func (lw logWrapper) Error(msg string, args ...interface{}) {} +func (lw LogWrapper) Trace(msg string, args ...interface{}) {} +func (lw LogWrapper) Debug(msg string, args ...interface{}) {} +func (lw LogWrapper) Info(msg string, args ...interface{}) {} +func (lw LogWrapper) Warn(msg string, args ...interface{}) {} +func (lw LogWrapper) Error(msg string, args ...interface{}) {} -func (lw logWrapper) IsTrace() bool { return true } -func (lw logWrapper) IsDebug() bool { return true } -func (lw logWrapper) IsInfo() bool { return true } -func (lw logWrapper) IsWarn() bool { return true } -func (lw logWrapper) IsError() bool { return true } +func (lw LogWrapper) IsTrace() bool { return true } +func (lw LogWrapper) IsDebug() bool { return true } +func (lw LogWrapper) IsInfo() bool { return true } +func (lw LogWrapper) IsWarn() bool { return true } +func (lw LogWrapper) IsError() bool { return true } -func (lw logWrapper) With(args ...interface{}) hclog.Logger { - return logWrapper{logger: glog.New("logger", args)} +func (lw LogWrapper) With(args ...interface{}) hclog.Logger { + return LogWrapper{Logger: glog.New("logger", args)} } -func (lw logWrapper) Named(name string) hclog.Logger { - return logWrapper{logger: glog.New(name)} +func (lw LogWrapper) Named(name string) hclog.Logger { + return LogWrapper{Logger: glog.New(name)} } -func (lw logWrapper) ResetNamed(name string) hclog.Logger { - return logWrapper{logger: glog.New(name)} +func (lw LogWrapper) ResetNamed(name string) hclog.Logger { + return LogWrapper{Logger: glog.New(name)} } -func (lw logWrapper) StandardLogger(ops *hclog.StandardLoggerOptions) *log.Logger { +func (lw LogWrapper) StandardLogger(ops *hclog.StandardLoggerOptions) *log.Logger { return nil } diff --git a/pkg/plugins/backend/mock_tsdb_plugin/Makefile b/pkg/plugins/backend/mock_tsdb_plugin/Makefile deleted file mode 100644 index b288077e604..00000000000 --- a/pkg/plugins/backend/mock_tsdb_plugin/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: build - -build: - go build -o simple-plugin . \ No newline at end of file diff --git a/pkg/plugins/backend/mock_tsdb_plugin/plugin.go b/pkg/plugins/backend/mock_tsdb_plugin/plugin.go deleted file mode 100644 index 9d548882282..00000000000 --- a/pkg/plugins/backend/mock_tsdb_plugin/plugin.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "golang.org/x/net/context" - - "log" - - shared "github.com/grafana/grafana/pkg/plugins/backend/shared" - proto "github.com/grafana/grafana/pkg/tsdb/models" - plugin "github.com/hashicorp/go-plugin" -) - -type Tsdb struct { - plugin.NetRPCUnsupportedPlugin -} - -func (Tsdb) Get(ctx context.Context, req *proto.TsdbRequest) (*proto.TsdbResponse, error) { - log.Print("Tsdb.Get() from plugin") - - return &proto.TsdbResponse{ - MetaJson: "from plugins! meta meta", - }, nil -} - -func main() { - plugin.Serve(&plugin.ServeConfig{ - HandshakeConfig: plugin.HandshakeConfig{ - ProtocolVersion: 1, - MagicCookieKey: "BASIC_PLUGIN", - MagicCookieValue: "hello", - }, - Plugins: map[string]plugin.Plugin{ - "tsdb_mock": &shared.TsdbPluginImpl{Plugin: &Tsdb{}}, - }, - - // A non-nil value here enables gRPC serving for this plugin... - GRPCServer: plugin.DefaultGRPCServer, - }) -} diff --git a/pkg/plugins/backend/mock_tsdb_plugin/simple-plugin b/pkg/plugins/backend/mock_tsdb_plugin/simple-plugin deleted file mode 100755 index 543a6e85be0..00000000000 Binary files a/pkg/plugins/backend/mock_tsdb_plugin/simple-plugin and /dev/null differ diff --git a/pkg/plugins/backend/plugins.go b/pkg/plugins/backend/plugins.go deleted file mode 100644 index cffb482e134..00000000000 --- a/pkg/plugins/backend/plugins.go +++ /dev/null @@ -1,55 +0,0 @@ -package plugins - -import ( - "os/exec" - - "golang.org/x/net/context" - - "github.com/grafana/grafana/pkg/log" - "github.com/grafana/grafana/pkg/plugins/backend/shared" - "github.com/grafana/grafana/pkg/tsdb/models" - plugin "github.com/hashicorp/go-plugin" -) - -func Init() (*plugin.Client, error) { - /* - setup protoc using https://gist.github.com/bergquist/5df1f201bb605e42538ef40f6ccf82a9 - run "protoc --go_out=plugins=grpc:. *.proto" to update proto files - */ - - logger := log.New("grafana.plugins") - client := plugin.NewClient(&plugin.ClientConfig{ - HandshakeConfig: plugin.HandshakeConfig{ - ProtocolVersion: 1, - MagicCookieKey: "BASIC_PLUGIN", - MagicCookieValue: "hello", - }, - Plugins: shared.PluginMap, - Cmd: exec.Command("sh", "-c", "/home/carl/go/src/github.com/grafana/grafana/pkg/plugins/backend/mock_tsdb_plugin/simple-plugin"), - AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, - Logger: logWrapper{logger: logger}, - }) - - // Connect via RPC - rpcClient, err := client.Client() - if err != nil { - return nil, err - } - - // Request the plugin - raw, err := rpcClient.Dispense("tsdb_mock") - if err != nil { - return nil, err - } - - plugin := raw.(shared.TsdbPlugin) - response, err := plugin.Get(context.Background(), &proto.TsdbRequest{}) - - if err != nil { - logger.Error("Response from plugin. ", "response", response) - } else { - logger.Info("Response from plugin. ", "response", response) - } - - return client, nil -} diff --git a/pkg/plugins/backend/shared/grpc.go b/pkg/plugins/backend/shared/grpc.go deleted file mode 100644 index d438f13fa5b..00000000000 --- a/pkg/plugins/backend/shared/grpc.go +++ /dev/null @@ -1,22 +0,0 @@ -package shared - -import ( - proto "github.com/grafana/grafana/pkg/tsdb/models" - "golang.org/x/net/context" -) - -type GRPCClient struct { - proto.TsdbPluginClient -} - -func (m *GRPCClient) Get(ctx context.Context, req *proto.TsdbRequest) (*proto.TsdbResponse, error) { - return m.TsdbPluginClient.Get(ctx, req) -} - -type GRPCServer struct { - TsdbPlugin -} - -func (m *GRPCServer) Get(ctx context.Context, req *proto.TsdbRequest) (*proto.TsdbResponse, error) { - return m.TsdbPlugin.Get(ctx, req) -} diff --git a/pkg/plugins/backend_datasource.go b/pkg/plugins/backend_datasource.go new file mode 100644 index 00000000000..9c6cb2f8687 --- /dev/null +++ b/pkg/plugins/backend_datasource.go @@ -0,0 +1,90 @@ +package plugins + +import ( + "context" + "encoding/json" + "os/exec" + "path" + + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/plugins/backend" + "github.com/grafana/grafana/pkg/tsdb" + + "github.com/grafana/grafana/pkg/log" + proto "github.com/grafana/grafana/pkg/tsdb/models" + shared "github.com/grafana/grafana/pkg/tsdb/models/proxy" + plugin "github.com/hashicorp/go-plugin" +) + +type BackendDatasource struct { + *PluginBase + + Executable string + client *plugin.Client +} + +type Killable interface { + Kill() +} + +type NoopKiller struct{} + +func (nk NoopKiller) Kill() {} + +func (p *BackendDatasource) initBackendPlugin() (Killable, error) { + logger := log.New("grafana.plugins") + + p.client = plugin.NewClient(&plugin.ClientConfig{ + HandshakeConfig: plugin.HandshakeConfig{ + ProtocolVersion: 1, + MagicCookieKey: "BASIC_PLUGIN", + MagicCookieValue: "hello", + }, + Plugins: map[string]plugin.Plugin{p.Id: &shared.TsdbPluginImpl{}}, + Cmd: exec.Command("sh", "-c", path.Join(p.PluginDir, p.Executable)), + AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, + Logger: backend.LogWrapper{Logger: logger}, + }) + + rpcClient, err := p.client.Client() + if err != nil { + return NoopKiller{}, err + } + + raw, err := rpcClient.Dispense(p.Id) + if err != nil { + return NoopKiller{}, err + } + + plugin := raw.(shared.TsdbPlugin) + response, err := plugin.Query(context.Background(), &proto.TsdbQuery{}) + + if err != nil { + logger.Error("Response from plugin. ", "response", response) + } else { + logger.Info("Response from plugin. ", "response", response) + } + + tsdb.RegisterTsdbQueryEndpoint(p.Id, func(dsInfo *models.DataSource) (tsdb.TsdbQueryEndpoint, error) { + return &shared.TsdbWrapper{TsdbPlugin: plugin}, nil + }) + + return p.client, nil +} + +func (p *BackendDatasource) Kill() { + p.client.Kill() +} + +func (p *BackendDatasource) Load(decoder *json.Decoder, pluginDir string) error { + if err := decoder.Decode(&p); err != nil { + return err + } + + if err := p.registerPlugin(pluginDir); err != nil { + return err + } + + BackendDatasources[p.Id] = p + return nil +} diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index 885bd5c9e03..a4a8f62d063 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -17,12 +17,13 @@ import ( ) var ( - DataSources map[string]*DataSourcePlugin - Panels map[string]*PanelPlugin - StaticRoutes []*PluginStaticRoute - Apps map[string]*AppPlugin - Plugins map[string]*PluginBase - PluginTypes map[string]interface{} + DataSources map[string]*DataSourcePlugin + Panels map[string]*PanelPlugin + StaticRoutes []*PluginStaticRoute + Apps map[string]*AppPlugin + Plugins map[string]*PluginBase + BackendDatasources map[string]*BackendDatasource + PluginTypes map[string]interface{} GrafanaLatestVersion string GrafanaHasUpdate bool @@ -34,7 +35,9 @@ type PluginScanner struct { errors []error } -func Init() error { +type Dispose func() + +func Init() (Dispose, error) { plog = log.New("plugins") DataSources = make(map[string]*DataSourcePlugin) @@ -42,10 +45,12 @@ func Init() error { Panels = make(map[string]*PanelPlugin) Apps = make(map[string]*AppPlugin) Plugins = make(map[string]*PluginBase) + BackendDatasources = make(map[string]*BackendDatasource) PluginTypes = map[string]interface{}{ - "panel": PanelPlugin{}, - "datasource": DataSourcePlugin{}, - "app": AppPlugin{}, + "panel": PanelPlugin{}, + "datasource": DataSourcePlugin{}, + "app": AppPlugin{}, + "backend-datasource": BackendDatasource{}, } plog.Info("Starting plugin search") @@ -77,10 +82,26 @@ func Init() error { app.initApp() } + killers := []Killable{} + for _, be := range BackendDatasources { + killable, err := be.initBackendPlugin() + if err != nil { + plog.Error("failed to init plugin", "id", be.Id, "error", err) + } else { + killers = append(killers, killable) + } + } + go StartPluginUpdateChecker() go updateAppDashboards() - return nil + return dispose, nil +} + +func dispose() { + for _, p := range BackendDatasources { + p.Kill() + } } func checkPluginPaths() error { diff --git a/pkg/tsdb/models.go b/pkg/tsdb/models.go index cbda7c97515..dee7289af7f 100644 --- a/pkg/tsdb/models.go +++ b/pkg/tsdb/models.go @@ -14,9 +14,7 @@ type TsdbQuery struct { type Query struct { RefId string Model *simplejson.Json - Depends []string DataSource *models.DataSource - Results []*TimeSeries MaxDataPoints int64 IntervalMs int64 } diff --git a/pkg/tsdb/models/proxy/grpc.go b/pkg/tsdb/models/proxy/grpc.go new file mode 100644 index 00000000000..76a110385fe --- /dev/null +++ b/pkg/tsdb/models/proxy/grpc.go @@ -0,0 +1,24 @@ +package proxy + +import ( + proto "github.com/grafana/grafana/pkg/tsdb/models" + "golang.org/x/net/context" +) + +type GRPCClient struct { + proto.TsdbPluginClient +} + +//Query(ctx context.Context, ds *models.DataSource, query *TsdbQuery) (*Response, error) + +func (m *GRPCClient) Query(ctx context.Context, req *proto.TsdbQuery) (*proto.Response, error) { + return m.TsdbPluginClient.Query(ctx, req) +} + +type GRPCServer struct { + TsdbPlugin +} + +func (m *GRPCServer) Query(ctx context.Context, req *proto.TsdbQuery) (*proto.Response, error) { + return m.TsdbPlugin.Query(ctx, req) +} diff --git a/pkg/plugins/backend/shared/interface.go b/pkg/tsdb/models/proxy/interface.go similarity index 82% rename from pkg/plugins/backend/shared/interface.go rename to pkg/tsdb/models/proxy/interface.go index c9a3c646242..313eac613e5 100644 --- a/pkg/plugins/backend/shared/interface.go +++ b/pkg/tsdb/models/proxy/interface.go @@ -1,8 +1,10 @@ -package shared +package proxy import ( "golang.org/x/net/context" + //tsdb "github.com/grafana/grafana/pkg/tsdb" + proto "github.com/grafana/grafana/pkg/tsdb/models" plugin "github.com/hashicorp/go-plugin" "google.golang.org/grpc" @@ -13,7 +15,7 @@ var PluginMap = map[string]plugin.Plugin{ } type TsdbPlugin interface { - Get(ctx context.Context, req *proto.TsdbRequest) (*proto.TsdbResponse, error) + Query(ctx context.Context, req *proto.TsdbQuery) (*proto.Response, error) } type TsdbPluginImpl struct { //LOL IMPL LOL diff --git a/pkg/tsdb/models/proxy/wrapper.go b/pkg/tsdb/models/proxy/wrapper.go new file mode 100644 index 00000000000..880bed0c121 --- /dev/null +++ b/pkg/tsdb/models/proxy/wrapper.go @@ -0,0 +1,83 @@ +package proxy + +import ( + "github.com/golang/protobuf/ptypes" + "github.com/grafana/grafana/pkg/components/null" + "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/tsdb" + proto "github.com/grafana/grafana/pkg/tsdb/models" + "golang.org/x/net/context" +) + +type TsdbWrapper struct { + TsdbPlugin +} + +func (tw *TsdbWrapper) Query(ctx context.Context, ds *models.DataSource, query *tsdb.TsdbQuery) (*tsdb.Response, error) { + jsonData, _ := ds.JsonData.MarshalJSON() + now, _ := ptypes.TimestampProto(query.TimeRange.Now) + + pbQuery := &proto.TsdbQuery{ + Datasource: &proto.DatasourceInfo{ + Access: string(ds.Access), + BasicAuth: ds.BasicAuth, + BasicAuthUser: ds.BasicAuthUser, + BasicAuthPassword: ds.BasicAuthPassword, + JsonData: string(jsonData), + Name: ds.Name, + Type: ds.Type, + Url: ds.Url, + }, + Timerange: &proto.Timerange{ + From: query.TimeRange.From, + To: query.TimeRange.To, + Now: now, + }, + Queries: []*proto.Query{}, + } + + for _, q := range query.Queries { + modelJson, _ := q.Model.MarshalJSON() + + pbQuery.Queries = append(pbQuery.Queries, &proto.Query{ + ModelJson: string(modelJson), + IntervalMs: q.IntervalMs, + RefId: q.RefId, + MaxDataPoints: q.MaxDataPoints, + }) + } + + pbres, err := tw.TsdbPlugin.Query(ctx, pbQuery) + + if err != nil { + return nil, err + } + + res := &tsdb.Response{ + Message: pbres.Message, + } + + for _, r := range pbres.Results { + res.Results[r.RefId] = &tsdb.QueryResult{ + RefId: r.RefId, + Series: []*tsdb.TimeSeries{}, + } + + for _, s := range r.Series { + points := tsdb.TimeSeriesPoints{} + + for _, p := range s.Points { + po := tsdb.NewTimePoint(null.FloatFrom(float64(p.Timestamp.Nanos)), p.Value) + points = append(points, po) + } + + res.Results[r.RefId].Series = append(res.Results[r.RefId].Series, &tsdb.TimeSeries{ + Name: s.Name, + Tags: s.Tags, + Points: points, + }) + } + } + + return res, nil +} diff --git a/pkg/tsdb/models/tsdb_plugin.pb.go b/pkg/tsdb/models/tsdb_plugin.pb.go index e3a98d87b4f..ee937cce10b 100644 --- a/pkg/tsdb/models/tsdb_plugin.pb.go +++ b/pkg/tsdb/models/tsdb_plugin.pb.go @@ -8,16 +8,21 @@ It is generated from these files: tsdb_plugin.proto It has these top-level messages: - TsdbRequest TsdbQuery - TsdbResponse + Query + Timerange + Response + QueryResult + DatasourceInfo TsdbSeries + Point */ package proto import proto1 "github.com/golang/protobuf/proto" import fmt "fmt" import math "math" +import google_protobuf "github.com/golang/protobuf/ptypes/timestamp" import ( context "golang.org/x/net/context" @@ -36,55 +41,143 @@ var _ = math.Inf const _ = proto1.ProtoPackageIsVersion2 // please upgrade the proto package // Message represents a simple message sent to the Echo service. -type TsdbRequest struct { - From int64 `protobuf:"varint,1,opt,name=from" json:"from,omitempty"` - To int64 `protobuf:"varint,2,opt,name=to" json:"to,omitempty"` - Queries []*TsdbQuery `protobuf:"bytes,3,rep,name=queries" json:"queries,omitempty"` +type TsdbQuery struct { + Timerange *Timerange `protobuf:"bytes,1,opt,name=timerange" json:"timerange,omitempty"` + Datasource *DatasourceInfo `protobuf:"bytes,2,opt,name=datasource" json:"datasource,omitempty"` + Queries []*Query `protobuf:"bytes,3,rep,name=queries" json:"queries,omitempty"` } -func (m *TsdbRequest) Reset() { *m = TsdbRequest{} } -func (m *TsdbRequest) String() string { return proto1.CompactTextString(m) } -func (*TsdbRequest) ProtoMessage() {} -func (*TsdbRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } +func (m *TsdbQuery) Reset() { *m = TsdbQuery{} } +func (m *TsdbQuery) String() string { return proto1.CompactTextString(m) } +func (*TsdbQuery) ProtoMessage() {} +func (*TsdbQuery) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } -func (m *TsdbRequest) GetFrom() int64 { +func (m *TsdbQuery) GetTimerange() *Timerange { if m != nil { - return m.From + return m.Timerange } - return 0 + return nil } -func (m *TsdbRequest) GetTo() int64 { +func (m *TsdbQuery) GetDatasource() *DatasourceInfo { if m != nil { - return m.To + return m.Datasource } - return 0 + return nil } -func (m *TsdbRequest) GetQueries() []*TsdbQuery { +func (m *TsdbQuery) GetQueries() []*Query { if m != nil { return m.Queries } return nil } -type TsdbQuery struct { - QueryJson string `protobuf:"bytes,1,opt,name=queryJson" json:"queryJson,omitempty"` +type Query struct { + RefId string `protobuf:"bytes,1,opt,name=refId" json:"refId,omitempty"` + ModelJson string `protobuf:"bytes,2,opt,name=modelJson" json:"modelJson,omitempty"` + MaxDataPoints int64 `protobuf:"varint,3,opt,name=MaxDataPoints" json:"MaxDataPoints,omitempty"` + IntervalMs int64 `protobuf:"varint,4,opt,name=intervalMs" json:"intervalMs,omitempty"` + Datasource *DatasourceInfo `protobuf:"bytes,5,opt,name=datasource" json:"datasource,omitempty"` } -func (m *TsdbQuery) Reset() { *m = TsdbQuery{} } -func (m *TsdbQuery) String() string { return proto1.CompactTextString(m) } -func (*TsdbQuery) ProtoMessage() {} -func (*TsdbQuery) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *Query) Reset() { *m = Query{} } +func (m *Query) String() string { return proto1.CompactTextString(m) } +func (*Query) ProtoMessage() {} +func (*Query) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } -func (m *TsdbQuery) GetQueryJson() string { +func (m *Query) GetRefId() string { if m != nil { - return m.QueryJson + return m.RefId } return "" } -type TsdbResponse struct { +func (m *Query) GetModelJson() string { + if m != nil { + return m.ModelJson + } + return "" +} + +func (m *Query) GetMaxDataPoints() int64 { + if m != nil { + return m.MaxDataPoints + } + return 0 +} + +func (m *Query) GetIntervalMs() int64 { + if m != nil { + return m.IntervalMs + } + return 0 +} + +func (m *Query) GetDatasource() *DatasourceInfo { + if m != nil { + return m.Datasource + } + return nil +} + +type Timerange struct { + From string `protobuf:"bytes,1,opt,name=from" json:"from,omitempty"` + To string `protobuf:"bytes,2,opt,name=to" json:"to,omitempty"` + Now *google_protobuf.Timestamp `protobuf:"bytes,3,opt,name=now" json:"now,omitempty"` +} + +func (m *Timerange) Reset() { *m = Timerange{} } +func (m *Timerange) String() string { return proto1.CompactTextString(m) } +func (*Timerange) ProtoMessage() {} +func (*Timerange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *Timerange) GetFrom() string { + if m != nil { + return m.From + } + return "" +} + +func (m *Timerange) GetTo() string { + if m != nil { + return m.To + } + return "" +} + +func (m *Timerange) GetNow() *google_protobuf.Timestamp { + if m != nil { + return m.Now + } + return nil +} + +type Response struct { + Message string `protobuf:"bytes,1,opt,name=message" json:"message,omitempty"` + Results []*QueryResult `protobuf:"bytes,2,rep,name=results" json:"results,omitempty"` +} + +func (m *Response) Reset() { *m = Response{} } +func (m *Response) String() string { return proto1.CompactTextString(m) } +func (*Response) ProtoMessage() {} +func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *Response) GetMessage() string { + if m != nil { + return m.Message + } + return "" +} + +func (m *Response) GetResults() []*QueryResult { + if m != nil { + return m.Results + } + return nil +} + +type QueryResult struct { Error string `protobuf:"bytes,1,opt,name=error" json:"error,omitempty"` ErrorString string `protobuf:"bytes,2,opt,name=errorString" json:"errorString,omitempty"` RefId string `protobuf:"bytes,3,opt,name=refId" json:"refId,omitempty"` @@ -92,54 +185,136 @@ type TsdbResponse struct { Series []*TsdbSeries `protobuf:"bytes,5,rep,name=series" json:"series,omitempty"` } -func (m *TsdbResponse) Reset() { *m = TsdbResponse{} } -func (m *TsdbResponse) String() string { return proto1.CompactTextString(m) } -func (*TsdbResponse) ProtoMessage() {} -func (*TsdbResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } +func (m *QueryResult) Reset() { *m = QueryResult{} } +func (m *QueryResult) String() string { return proto1.CompactTextString(m) } +func (*QueryResult) ProtoMessage() {} +func (*QueryResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } -func (m *TsdbResponse) GetError() string { +func (m *QueryResult) GetError() string { if m != nil { return m.Error } return "" } -func (m *TsdbResponse) GetErrorString() string { +func (m *QueryResult) GetErrorString() string { if m != nil { return m.ErrorString } return "" } -func (m *TsdbResponse) GetRefId() string { +func (m *QueryResult) GetRefId() string { if m != nil { return m.RefId } return "" } -func (m *TsdbResponse) GetMetaJson() string { +func (m *QueryResult) GetMetaJson() string { if m != nil { return m.MetaJson } return "" } -func (m *TsdbResponse) GetSeries() []*TsdbSeries { +func (m *QueryResult) GetSeries() []*TsdbSeries { if m != nil { return m.Series } return nil } +type DatasourceInfo struct { + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type" json:"type,omitempty"` + Access string `protobuf:"bytes,3,opt,name=access" json:"access,omitempty"` + Url string `protobuf:"bytes,4,opt,name=url" json:"url,omitempty"` + BasicAuth bool `protobuf:"varint,5,opt,name=basicAuth" json:"basicAuth,omitempty"` + BasicAuthUser string `protobuf:"bytes,6,opt,name=basicAuthUser" json:"basicAuthUser,omitempty"` + BasicAuthPassword string `protobuf:"bytes,7,opt,name=basicAuthPassword" json:"basicAuthPassword,omitempty"` + JsonData string `protobuf:"bytes,8,opt,name=jsonData" json:"jsonData,omitempty"` + SecureJsonData string `protobuf:"bytes,9,opt,name=secureJsonData" json:"secureJsonData,omitempty"` +} + +func (m *DatasourceInfo) Reset() { *m = DatasourceInfo{} } +func (m *DatasourceInfo) String() string { return proto1.CompactTextString(m) } +func (*DatasourceInfo) ProtoMessage() {} +func (*DatasourceInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *DatasourceInfo) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *DatasourceInfo) GetType() string { + if m != nil { + return m.Type + } + return "" +} + +func (m *DatasourceInfo) GetAccess() string { + if m != nil { + return m.Access + } + return "" +} + +func (m *DatasourceInfo) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *DatasourceInfo) GetBasicAuth() bool { + if m != nil { + return m.BasicAuth + } + return false +} + +func (m *DatasourceInfo) GetBasicAuthUser() string { + if m != nil { + return m.BasicAuthUser + } + return "" +} + +func (m *DatasourceInfo) GetBasicAuthPassword() string { + if m != nil { + return m.BasicAuthPassword + } + return "" +} + +func (m *DatasourceInfo) GetJsonData() string { + if m != nil { + return m.JsonData + } + return "" +} + +func (m *DatasourceInfo) GetSecureJsonData() string { + if m != nil { + return m.SecureJsonData + } + return "" +} + type TsdbSeries struct { - Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` + Tags map[string]string `protobuf:"bytes,2,rep,name=tags" json:"tags,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + Points []*Point `protobuf:"bytes,3,rep,name=points" json:"points,omitempty"` } func (m *TsdbSeries) Reset() { *m = TsdbSeries{} } func (m *TsdbSeries) String() string { return proto1.CompactTextString(m) } func (*TsdbSeries) ProtoMessage() {} -func (*TsdbSeries) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } +func (*TsdbSeries) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } func (m *TsdbSeries) GetName() string { if m != nil { @@ -148,11 +323,53 @@ func (m *TsdbSeries) GetName() string { return "" } +func (m *TsdbSeries) GetTags() map[string]string { + if m != nil { + return m.Tags + } + return nil +} + +func (m *TsdbSeries) GetPoints() []*Point { + if m != nil { + return m.Points + } + return nil +} + +type Point struct { + Timestamp *google_protobuf.Timestamp `protobuf:"bytes,1,opt,name=timestamp" json:"timestamp,omitempty"` + Value float64 `protobuf:"fixed64,2,opt,name=value" json:"value,omitempty"` +} + +func (m *Point) Reset() { *m = Point{} } +func (m *Point) String() string { return proto1.CompactTextString(m) } +func (*Point) ProtoMessage() {} +func (*Point) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *Point) GetTimestamp() *google_protobuf.Timestamp { + if m != nil { + return m.Timestamp + } + return nil +} + +func (m *Point) GetValue() float64 { + if m != nil { + return m.Value + } + return 0 +} + func init() { - proto1.RegisterType((*TsdbRequest)(nil), "plugins.TsdbRequest") proto1.RegisterType((*TsdbQuery)(nil), "plugins.TsdbQuery") - proto1.RegisterType((*TsdbResponse)(nil), "plugins.TsdbResponse") + proto1.RegisterType((*Query)(nil), "plugins.Query") + proto1.RegisterType((*Timerange)(nil), "plugins.Timerange") + proto1.RegisterType((*Response)(nil), "plugins.Response") + proto1.RegisterType((*QueryResult)(nil), "plugins.QueryResult") + proto1.RegisterType((*DatasourceInfo)(nil), "plugins.DatasourceInfo") proto1.RegisterType((*TsdbSeries)(nil), "plugins.TsdbSeries") + proto1.RegisterType((*Point)(nil), "plugins.Point") } // Reference imports to suppress errors if they are not otherwise used. @@ -166,7 +383,7 @@ const _ = grpc.SupportPackageIsVersion4 // Client API for TsdbPlugin service type TsdbPluginClient interface { - Get(ctx context.Context, in *TsdbRequest, opts ...grpc.CallOption) (*TsdbResponse, error) + Query(ctx context.Context, in *TsdbQuery, opts ...grpc.CallOption) (*Response, error) } type tsdbPluginClient struct { @@ -177,9 +394,9 @@ func NewTsdbPluginClient(cc *grpc.ClientConn) TsdbPluginClient { return &tsdbPluginClient{cc} } -func (c *tsdbPluginClient) Get(ctx context.Context, in *TsdbRequest, opts ...grpc.CallOption) (*TsdbResponse, error) { - out := new(TsdbResponse) - err := grpc.Invoke(ctx, "/plugins.TsdbPlugin/Get", in, out, c.cc, opts...) +func (c *tsdbPluginClient) Query(ctx context.Context, in *TsdbQuery, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := grpc.Invoke(ctx, "/plugins.TsdbPlugin/Query", in, out, c.cc, opts...) if err != nil { return nil, err } @@ -189,27 +406,27 @@ func (c *tsdbPluginClient) Get(ctx context.Context, in *TsdbRequest, opts ...grp // Server API for TsdbPlugin service type TsdbPluginServer interface { - Get(context.Context, *TsdbRequest) (*TsdbResponse, error) + Query(context.Context, *TsdbQuery) (*Response, error) } func RegisterTsdbPluginServer(s *grpc.Server, srv TsdbPluginServer) { s.RegisterService(&_TsdbPlugin_serviceDesc, srv) } -func _TsdbPlugin_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(TsdbRequest) +func _TsdbPlugin_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TsdbQuery) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(TsdbPluginServer).Get(ctx, in) + return srv.(TsdbPluginServer).Query(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/plugins.TsdbPlugin/Get", + FullMethod: "/plugins.TsdbPlugin/Query", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(TsdbPluginServer).Get(ctx, req.(*TsdbRequest)) + return srv.(TsdbPluginServer).Query(ctx, req.(*TsdbQuery)) } return interceptor(ctx, in, info, handler) } @@ -219,8 +436,8 @@ var _TsdbPlugin_serviceDesc = grpc.ServiceDesc{ HandlerType: (*TsdbPluginServer)(nil), Methods: []grpc.MethodDesc{ { - MethodName: "Get", - Handler: _TsdbPlugin_Get_Handler, + MethodName: "Query", + Handler: _TsdbPlugin_Query_Handler, }, }, Streams: []grpc.StreamDesc{}, @@ -230,23 +447,46 @@ var _TsdbPlugin_serviceDesc = grpc.ServiceDesc{ func init() { proto1.RegisterFile("tsdb_plugin.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 280 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x51, 0xc1, 0x4e, 0x83, 0x40, - 0x10, 0x0d, 0x50, 0x8a, 0x0c, 0xc6, 0xc4, 0xb1, 0x26, 0xa4, 0xf1, 0x40, 0x38, 0xd5, 0x68, 0x38, - 0xe0, 0x0f, 0x18, 0x2f, 0x46, 0x4f, 0xba, 0xf5, 0xe4, 0xa5, 0x29, 0x61, 0xda, 0x90, 0x08, 0x4b, - 0x77, 0x97, 0x43, 0x3f, 0xc8, 0xff, 0x34, 0xcc, 0xae, 0xad, 0xf5, 0xc4, 0xbc, 0xb7, 0x6f, 0xde, - 0xcc, 0x1b, 0xe0, 0xd2, 0xe8, 0xba, 0x5a, 0xf5, 0x5f, 0xc3, 0xb6, 0xe9, 0x8a, 0x5e, 0x49, 0x23, - 0x31, 0xb2, 0x48, 0xe7, 0x2b, 0x48, 0x3e, 0x74, 0x5d, 0x09, 0xda, 0x0d, 0xa4, 0x0d, 0x22, 0x4c, - 0x36, 0x4a, 0xb6, 0xa9, 0x97, 0x79, 0x8b, 0x40, 0x70, 0x8d, 0x17, 0xe0, 0x1b, 0x99, 0xfa, 0xcc, - 0xf8, 0x46, 0xe2, 0x3d, 0x44, 0xbb, 0x81, 0x54, 0x43, 0x3a, 0x0d, 0xb2, 0x60, 0x91, 0x94, 0x58, - 0x38, 0xb7, 0x62, 0xb4, 0x7a, 0x1f, 0x48, 0xed, 0xc5, 0xaf, 0x24, 0xbf, 0x85, 0xf8, 0xc0, 0xe2, - 0x0d, 0xc4, 0x23, 0xbf, 0x7f, 0xd5, 0xb2, 0xe3, 0x19, 0xb1, 0x38, 0x12, 0xf9, 0xb7, 0x07, 0xe7, - 0x76, 0x19, 0xdd, 0xcb, 0x4e, 0x13, 0xce, 0x20, 0x24, 0xa5, 0xa4, 0x72, 0x52, 0x0b, 0x30, 0x83, - 0x84, 0x8b, 0xa5, 0x51, 0x4d, 0xb7, 0xe5, 0xc5, 0x62, 0xf1, 0x97, 0x1a, 0xfb, 0x14, 0x6d, 0x5e, - 0xea, 0x34, 0xb0, 0x7d, 0x0c, 0x70, 0x0e, 0x67, 0x2d, 0x99, 0x35, 0xcf, 0x9e, 0xf0, 0xc3, 0x01, - 0xe3, 0x1d, 0x4c, 0xb5, 0x8d, 0x14, 0x72, 0xa4, 0xab, 0x93, 0x48, 0x4b, 0x7e, 0x12, 0x4e, 0x92, - 0x67, 0x00, 0x47, 0x76, 0x3c, 0x59, 0xb7, 0x6e, 0xc9, 0xed, 0xc8, 0x75, 0xf9, 0x68, 0x15, 0x6f, - 0xec, 0x81, 0x25, 0x04, 0xcf, 0x64, 0x70, 0x76, 0xe2, 0xe9, 0x2e, 0x3e, 0xbf, 0xfe, 0xc7, 0xda, - 0xe8, 0x4f, 0xd1, 0x67, 0xc8, 0x7f, 0xaa, 0x9a, 0xf2, 0xe7, 0xe1, 0x27, 0x00, 0x00, 0xff, 0xff, - 0x11, 0xda, 0x61, 0xe4, 0xc5, 0x01, 0x00, 0x00, + // 652 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x54, 0x4d, 0x6f, 0xd4, 0x3a, + 0x14, 0x55, 0xe6, 0x3b, 0x77, 0xf4, 0x46, 0xaf, 0x7e, 0xd5, 0x23, 0x1a, 0xf1, 0x51, 0x45, 0xa8, + 0x1a, 0x89, 0x2a, 0x85, 0x61, 0xd1, 0x0a, 0xb1, 0x01, 0xc1, 0xa2, 0x95, 0x2a, 0x15, 0x77, 0x10, + 0x12, 0x12, 0x42, 0x9e, 0x89, 0x27, 0x04, 0x92, 0x78, 0xb0, 0x9d, 0x96, 0xf9, 0x27, 0x2c, 0x59, + 0xf0, 0x13, 0x58, 0xf1, 0xeb, 0x90, 0x6f, 0xec, 0x64, 0xa6, 0x54, 0x88, 0x55, 0xee, 0x3d, 0xf7, + 0xd8, 0x39, 0x3e, 0xf7, 0xda, 0xb0, 0xa3, 0x55, 0x3c, 0x7f, 0xbf, 0xca, 0xca, 0x24, 0x2d, 0xa2, + 0x95, 0x14, 0x5a, 0x90, 0x7e, 0x95, 0xa9, 0xf1, 0xbd, 0x44, 0x88, 0x24, 0xe3, 0x87, 0x08, 0xcf, + 0xcb, 0xe5, 0xa1, 0x4e, 0x73, 0xae, 0x34, 0xcb, 0x57, 0x15, 0x33, 0xfc, 0xe6, 0x81, 0x3f, 0x53, + 0xf1, 0xfc, 0x55, 0xc9, 0xe5, 0x9a, 0x3c, 0x04, 0xdf, 0x10, 0x24, 0x2b, 0x12, 0x1e, 0x78, 0x7b, + 0xde, 0x64, 0x38, 0x25, 0x91, 0xdd, 0x2b, 0x9a, 0xb9, 0x0a, 0x6d, 0x48, 0xe4, 0x08, 0x20, 0x66, + 0x9a, 0x29, 0x51, 0xca, 0x05, 0x0f, 0x5a, 0xb8, 0xe4, 0x56, 0xbd, 0xe4, 0x45, 0x5d, 0x3a, 0x29, + 0x96, 0x82, 0x6e, 0x50, 0xc9, 0x04, 0xfa, 0x9f, 0x4b, 0x2e, 0x53, 0xae, 0x82, 0xf6, 0x5e, 0x7b, + 0x32, 0x9c, 0x8e, 0xea, 0x55, 0xa8, 0x85, 0xba, 0x72, 0xf8, 0xd3, 0x83, 0x6e, 0x25, 0x6f, 0x17, + 0xba, 0x92, 0x2f, 0x4f, 0x62, 0x94, 0xe6, 0xd3, 0x2a, 0x21, 0xb7, 0xc1, 0xcf, 0x45, 0xcc, 0xb3, + 0x53, 0x25, 0x0a, 0x54, 0xe0, 0xd3, 0x06, 0x20, 0xf7, 0xe1, 0x9f, 0x33, 0xf6, 0xc5, 0x08, 0x39, + 0x17, 0x69, 0xa1, 0xcd, 0xdf, 0xbc, 0x49, 0x9b, 0x6e, 0x83, 0xe4, 0x2e, 0x40, 0x5a, 0x68, 0x2e, + 0x2f, 0x59, 0x76, 0xa6, 0x82, 0x0e, 0x52, 0x36, 0x90, 0x6b, 0xc7, 0xec, 0xfe, 0xf5, 0x31, 0xc3, + 0x77, 0xe0, 0xd7, 0xbe, 0x11, 0x02, 0x9d, 0xa5, 0x14, 0xb9, 0x95, 0x8f, 0x31, 0x19, 0x41, 0x4b, + 0x0b, 0x2b, 0xbb, 0xa5, 0x05, 0x39, 0x80, 0x76, 0x21, 0xae, 0x50, 0xe5, 0x70, 0x3a, 0x8e, 0xaa, + 0xfe, 0x45, 0xae, 0x7f, 0xd8, 0x04, 0xec, 0x1f, 0x35, 0xb4, 0x70, 0x06, 0x03, 0xca, 0xd5, 0x4a, + 0x14, 0x8a, 0x93, 0x00, 0xfa, 0x39, 0x57, 0x8a, 0xd9, 0xd6, 0xf9, 0xd4, 0xa5, 0x24, 0x82, 0xbe, + 0xe4, 0xaa, 0xcc, 0xb4, 0x0a, 0x5a, 0xe8, 0xf5, 0xee, 0x35, 0xaf, 0xb1, 0x48, 0x1d, 0x29, 0xfc, + 0xee, 0xc1, 0x70, 0xa3, 0x60, 0x7c, 0xe7, 0x52, 0x0a, 0xe9, 0x7c, 0xc7, 0x84, 0xec, 0xc1, 0x10, + 0x83, 0x0b, 0x2d, 0xd3, 0x22, 0xb1, 0x47, 0xd8, 0x84, 0x9a, 0x7e, 0xb5, 0x37, 0xfb, 0x35, 0x86, + 0x41, 0xce, 0x35, 0xc3, 0x76, 0x75, 0xb0, 0x50, 0xe7, 0xe4, 0x01, 0xf4, 0x54, 0x35, 0x14, 0x5d, + 0x14, 0xfa, 0x5f, 0x33, 0x7d, 0x2a, 0x9e, 0x5f, 0x60, 0x89, 0x5a, 0x4a, 0xf8, 0xb5, 0x05, 0xa3, + 0x6d, 0xeb, 0x8d, 0xc3, 0x05, 0xcb, 0x9d, 0x01, 0x18, 0x1b, 0x4c, 0xaf, 0x57, 0xdc, 0x0a, 0xc4, + 0x98, 0xfc, 0x0f, 0x3d, 0xb6, 0x58, 0x70, 0xa5, 0xac, 0x34, 0x9b, 0x91, 0x7f, 0xa1, 0x5d, 0xca, + 0xcc, 0xca, 0x32, 0xa1, 0x99, 0xae, 0x39, 0x53, 0xe9, 0xe2, 0x59, 0xa9, 0x3f, 0x60, 0xe3, 0x07, + 0xb4, 0x01, 0xcc, 0x74, 0xd5, 0xc9, 0x6b, 0xc5, 0x65, 0xd0, 0xc3, 0x95, 0xdb, 0x20, 0x39, 0x80, + 0x9d, 0x1a, 0x38, 0x67, 0x4a, 0x5d, 0x09, 0x19, 0x07, 0x7d, 0x64, 0xfe, 0x5e, 0x30, 0xfe, 0x7c, + 0x54, 0xa2, 0x30, 0x27, 0x0b, 0x06, 0x95, 0x3f, 0x2e, 0x27, 0xfb, 0x30, 0x52, 0x7c, 0x51, 0x4a, + 0x7e, 0xea, 0x18, 0x3e, 0x32, 0xae, 0xa1, 0xe1, 0x0f, 0x0f, 0xa0, 0x71, 0xec, 0x46, 0x5b, 0x1e, + 0x41, 0x47, 0xb3, 0xc4, 0x4d, 0xc4, 0x9d, 0x1b, 0x8c, 0x8e, 0x66, 0x2c, 0x51, 0x2f, 0x0b, 0x2d, + 0xd7, 0x14, 0xa9, 0x64, 0x1f, 0x7a, 0x2b, 0x77, 0x89, 0xb6, 0xaf, 0x2c, 0x5e, 0x23, 0x6a, 0xab, + 0xe3, 0x23, 0xf0, 0xeb, 0xa5, 0xc6, 0xd2, 0x4f, 0x7c, 0x6d, 0x7f, 0x6d, 0x42, 0x33, 0x16, 0x97, + 0x2c, 0x2b, 0x5d, 0x47, 0xaa, 0xe4, 0x49, 0xeb, 0xd8, 0x0b, 0xdf, 0x40, 0x17, 0x77, 0x22, 0xc7, + 0xd5, 0x43, 0x84, 0x93, 0x6e, 0x1f, 0xa2, 0x3f, 0xdd, 0x85, 0x86, 0xbc, 0xbd, 0xb9, 0x67, 0x37, + 0x9f, 0x3e, 0xad, 0xec, 0x38, 0x47, 0xb9, 0x24, 0x72, 0x0f, 0x0a, 0xd9, 0x3a, 0x35, 0x62, 0xe3, + 0x9d, 0x1a, 0x73, 0x37, 0xeb, 0x79, 0xff, 0x6d, 0xb7, 0xfa, 0x69, 0x0f, 0x3f, 0x8f, 0x7f, 0x05, + 0x00, 0x00, 0xff, 0xff, 0x56, 0x20, 0xfa, 0x8b, 0x73, 0x05, 0x00, 0x00, } diff --git a/pkg/tsdb/models/tsdb_plugin.proto b/pkg/tsdb/models/tsdb_plugin.proto index dd0430e81e0..2625e4c891c 100644 --- a/pkg/tsdb/models/tsdb_plugin.proto +++ b/pkg/tsdb/models/tsdb_plugin.proto @@ -3,30 +3,66 @@ option go_package = "proto"; package plugins; +import "google/protobuf/timestamp.proto"; + // Message represents a simple message sent to the Echo service. -message TsdbRequest { - int64 from = 1; - int64 to = 2; - repeated TsdbQuery queries = 3; -} - message TsdbQuery { - string queryJson = 1; + Timerange timerange = 1; + DatasourceInfo datasource = 2; + repeated Query queries = 3; } -message TsdbResponse { - string error = 1; - string errorString = 2; - string refId = 3; - string metaJson = 4; - repeated TsdbSeries series = 5; - //repeat TsdbTables tables = x; +message Query { + string refId = 1; + string modelJson = 2; + int64 MaxDataPoints = 3; + int64 intervalMs = 4; + DatasourceInfo datasource = 5; +} + +message Timerange { + string from = 1; + string to = 2; + google.protobuf.Timestamp now = 3; +} + +message Response { + string message = 1; + repeated QueryResult results = 2; +} + +message QueryResult { + string error = 1; + string errorString = 2; + string refId = 3; + string metaJson = 4; + repeated TsdbSeries series = 5; + //repeat TsdbTables tables = x; +} + +message DatasourceInfo { + string name = 1; + string type = 2; + string access = 3; + string url = 4; + bool basicAuth = 5; + string basicAuthUser = 6; + string basicAuthPassword = 7; + string jsonData = 8; + string secureJsonData = 9; } message TsdbSeries { string name = 1; + map tags = 2; + repeated Point points = 3; +} + +message Point { + google.protobuf.Timestamp timestamp = 1; + double value = 2; } service TsdbPlugin { - rpc Get(TsdbRequest) returns (TsdbResponse); + rpc Query(TsdbQuery) returns (Response); } \ No newline at end of file