mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Backend Plugins: (breaking change) Add PluginContext (#23788)
* breaking change for newer backend plugins * use exported protobuf converters and sdk types to reduce duplicate code * uses grafana-plugin-sdk-go@v0.54.0
This commit is contained in:
4
go.mod
4
go.mod
@@ -31,7 +31,7 @@ require (
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/gosimple/slug v1.4.2
|
||||
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.42.0
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.54.0
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd
|
||||
github.com/hashicorp/go-plugin v1.2.2
|
||||
github.com/hashicorp/go-version v1.1.0
|
||||
@@ -76,7 +76,7 @@ require (
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
||||
google.golang.org/grpc v1.27.1
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
|
21
go.sum
21
go.sum
@@ -14,8 +14,8 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191025121910-b789226ccb21 h1:xI+FQ/TsyD7jy22vP9wQBtJsPFRQTLZHfrr1IMLl0g0=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191025121910-b789226ccb21/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20200403134915-89ce1cadb678 h1:R72+9UXiP7TnpTAdznM1okjzyqb3bzopSA7HCP7p3gM=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20200403134915-89ce1cadb678/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/aws/aws-sdk-go v1.25.48 h1:J82DYDGZHOKHdhx6hD24Tm30c2C3GchYGfN0mf9iKUk=
|
||||
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
@@ -98,6 +98,7 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
@@ -133,8 +134,12 @@ github.com/gosimple/slug v1.4.2 h1:jDmprx3q/9Lfk4FkGZtvzDQ9Cj9eAmsjzeQGp24PeiQ=
|
||||
github.com/gosimple/slug v1.4.2/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0=
|
||||
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 h1:SPdxCL9BChFTlyi0Khv64vdCW4TMna8+sxL7+Chx+Ag=
|
||||
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4/go.mod h1:nc0XxBzjeGcrMltCDw269LoWF9S8ibhgxolCdA1R8To=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.42.0 h1:8oiAQa/uABBFT70GDAv3BnqHfdMOxy/P8SzYVURJH6Y=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.42.0/go.mod h1:xRhfTHl+Dkqf2Py6Lr4pcHBC5pm8/N+IwPJ0R/iAHMM=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.54.0 h1:DTrS6LmEo2gUfq2OLDTraNC1+vZKT8LO+hrOXJPJ2/c=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.54.0/go.mod h1:cJqtJv4uuWOB3SAUToTMa8yQoNxEtF07CabXHwsr5fc=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
|
||||
@@ -169,6 +174,7 @@ github.com/jung-kurt/gofpdf v1.10.1 h1:mbprTswkr0n86clAmJ4NGCFC4fdGySCAshWzrYb3x
|
||||
github.com/jung-kurt/gofpdf v1.10.1/go.mod h1:s/VXv+TdctEOx2wCEguezYaR7f0OwUAd6H9VGfRkcSs=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
@@ -188,6 +194,7 @@ github.com/linkedin/goavro/v2 v2.9.7 h1:Vd++Rb/RKcmNJjM0HP/JJFMEWa21eUBVKPYlKehO
|
||||
github.com/linkedin/goavro/v2 v2.9.7/go.mod h1:UgQUb2N/pmueQYH9bfqFioWxzYCZXSfF8Jw03O5sjqA=
|
||||
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
|
||||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0=
|
||||
github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE=
|
||||
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||
github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY=
|
||||
github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI=
|
||||
@@ -320,8 +327,11 @@ github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
|
||||
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -390,6 +400,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@@ -408,6 +419,8 @@ golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935/go.mod h1:TB2adYChydJhpapK
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
|
@@ -6,11 +6,13 @@ import (
|
||||
"net/url"
|
||||
"sort"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/datasource/wrapper"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
)
|
||||
@@ -296,23 +298,18 @@ func (hs *HTTPServer) CallDatasourceResource(c *models.ReqContext) {
|
||||
return
|
||||
}
|
||||
|
||||
config := backendplugin.PluginConfig{
|
||||
OrgID: c.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
DataSourceConfig: &backendplugin.DataSourceConfig{
|
||||
ID: ds.Id,
|
||||
Name: ds.Name,
|
||||
URL: ds.Url,
|
||||
Database: ds.Database,
|
||||
User: ds.User,
|
||||
BasicAuthEnabled: ds.BasicAuth,
|
||||
BasicAuthUser: ds.BasicAuthUser,
|
||||
JSONData: ds.JsonData,
|
||||
DecryptedSecureJSONData: ds.DecryptedValues(),
|
||||
Updated: ds.Updated,
|
||||
},
|
||||
dsInstanceSettings, err := wrapper.ModelToInstanceSettings(ds)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to process datasource instance model", err)
|
||||
}
|
||||
hs.BackendPluginManager.CallResource(config, c, c.Params("*"))
|
||||
|
||||
pCtx := backend.PluginContext{
|
||||
User: wrapper.BackendUserFromSignedInUser(c.SignedInUser),
|
||||
OrgID: c.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
DataSourceInstanceSettings: dsInstanceSettings,
|
||||
}
|
||||
hs.BackendPluginManager.CallResource(pCtx, c, c.Params("*"))
|
||||
}
|
||||
|
||||
func convertModelToDtos(ds *models.DataSource) dtos.DataSource {
|
||||
@@ -367,24 +364,18 @@ func (hs *HTTPServer) CheckDatasourceHealth(c *models.ReqContext) {
|
||||
return
|
||||
}
|
||||
|
||||
config := &backendplugin.PluginConfig{
|
||||
OrgID: c.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
DataSourceConfig: &backendplugin.DataSourceConfig{
|
||||
ID: ds.Id,
|
||||
Name: ds.Name,
|
||||
URL: ds.Url,
|
||||
Database: ds.Database,
|
||||
User: ds.User,
|
||||
BasicAuthEnabled: ds.BasicAuth,
|
||||
BasicAuthUser: ds.BasicAuthUser,
|
||||
JSONData: ds.JsonData,
|
||||
DecryptedSecureJSONData: ds.DecryptedValues(),
|
||||
Updated: ds.Updated,
|
||||
},
|
||||
dsInstanceSettings, err := wrapper.ModelToInstanceSettings(ds)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "Unable to get datasource model", err)
|
||||
}
|
||||
pCtx := backend.PluginContext{
|
||||
User: wrapper.BackendUserFromSignedInUser(c.SignedInUser),
|
||||
OrgID: c.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
DataSourceInstanceSettings: dsInstanceSettings,
|
||||
}
|
||||
|
||||
resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), config)
|
||||
resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), pCtx)
|
||||
if err != nil {
|
||||
if err == backendplugin.ErrPluginNotRegistered {
|
||||
c.JsonApiErr(404, "Plugin not found", err)
|
||||
|
@@ -7,49 +7,56 @@ import (
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/datasource/wrapper"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
)
|
||||
|
||||
// ErrPluginNotFound is returned when an requested plugin is not installed.
|
||||
var ErrPluginNotFound error = errors.New("plugin not found, no installed plugin with that id")
|
||||
|
||||
func (hs *HTTPServer) getPluginConfig(pluginID string, user *models.SignedInUser) (backendplugin.PluginConfig, error) {
|
||||
pluginConfig := backendplugin.PluginConfig{}
|
||||
func (hs *HTTPServer) getPluginContext(pluginID string, user *models.SignedInUser) (backend.PluginContext, error) {
|
||||
pc := backend.PluginContext{}
|
||||
plugin, exists := plugins.Plugins[pluginID]
|
||||
if !exists {
|
||||
return pluginConfig, ErrPluginNotFound
|
||||
return pc, ErrPluginNotFound
|
||||
}
|
||||
|
||||
var jsonData *simplejson.Json
|
||||
var jsonData json.RawMessage
|
||||
var decryptedSecureJSONData map[string]string
|
||||
var updated time.Time
|
||||
|
||||
ps, err := hs.getCachedPluginSettings(pluginID, user)
|
||||
if err != nil {
|
||||
if err != models.ErrPluginSettingNotFound {
|
||||
return pluginConfig, errutil.Wrap("Failed to get plugin settings", err)
|
||||
return pc, errutil.Wrap("Failed to get plugin settings", err)
|
||||
}
|
||||
jsonData, err = json.Marshal(ps.JsonData)
|
||||
if err != nil {
|
||||
return pc, errutil.Wrap("Failed to unmarshal plugin json data", err)
|
||||
}
|
||||
jsonData = simplejson.New()
|
||||
decryptedSecureJSONData = make(map[string]string)
|
||||
} else {
|
||||
decryptedSecureJSONData = ps.DecryptedValues()
|
||||
updated = ps.Updated
|
||||
}
|
||||
|
||||
return backendplugin.PluginConfig{
|
||||
OrgID: user.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
JSONData: jsonData,
|
||||
DecryptedSecureJSONData: decryptedSecureJSONData,
|
||||
Updated: updated,
|
||||
return backend.PluginContext{
|
||||
OrgID: user.OrgId,
|
||||
PluginID: plugin.Id,
|
||||
User: wrapper.BackendUserFromSignedInUser(user),
|
||||
AppInstanceSettings: &backend.AppInstanceSettings{
|
||||
JSONData: jsonData,
|
||||
DecryptedSecureJSONData: decryptedSecureJSONData,
|
||||
Updated: updated,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -289,7 +296,7 @@ func (hs *HTTPServer) CollectPluginMetrics(c *models.ReqContext) Response {
|
||||
func (hs *HTTPServer) CheckHealth(c *models.ReqContext) Response {
|
||||
pluginID := c.Params("pluginId")
|
||||
|
||||
config, err := hs.getPluginConfig(pluginID, c.SignedInUser)
|
||||
pCtx, err := hs.getPluginContext(pluginID, c.SignedInUser)
|
||||
if err != nil {
|
||||
if err == ErrPluginNotFound {
|
||||
return Error(404, "Plugin not found, no installed plugin with that id", nil)
|
||||
@@ -298,7 +305,7 @@ func (hs *HTTPServer) CheckHealth(c *models.ReqContext) Response {
|
||||
return Error(500, "Failed to get plugin settings", err)
|
||||
}
|
||||
|
||||
resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), &config)
|
||||
resp, err := hs.BackendPluginManager.CheckHealth(c.Req.Context(), pCtx)
|
||||
if err != nil {
|
||||
if err == backendplugin.ErrPluginNotRegistered {
|
||||
return Error(404, "Plugin not found", err)
|
||||
@@ -346,7 +353,7 @@ func (hs *HTTPServer) CheckHealth(c *models.ReqContext) Response {
|
||||
func (hs *HTTPServer) CallResource(c *models.ReqContext) {
|
||||
pluginID := c.Params("pluginId")
|
||||
|
||||
config, err := hs.getPluginConfig(pluginID, c.SignedInUser)
|
||||
pCtx, err := hs.getPluginContext(pluginID, c.SignedInUser)
|
||||
if err != nil {
|
||||
if err == ErrPluginNotFound {
|
||||
c.JsonApiErr(404, "Plugin not found, no installed plugin with that id", nil)
|
||||
@@ -356,8 +363,7 @@ func (hs *HTTPServer) CallResource(c *models.ReqContext) {
|
||||
c.JsonApiErr(500, "Failed to get plugin settings", err)
|
||||
return
|
||||
}
|
||||
|
||||
hs.BackendPluginManager.CallResource(config, c, c.Params("*"))
|
||||
hs.BackendPluginManager.CallResource(pCtx, c, c.Params("*"))
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) getCachedPluginSettings(pluginID string, user *models.SignedInUser) (*models.PluginSetting, error) {
|
||||
|
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
datasourceV1 "github.com/grafana/grafana-plugin-model/go/datasource"
|
||||
rendererV1 "github.com/grafana/grafana-plugin-model/go/renderer"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
|
||||
@@ -175,50 +175,21 @@ func (p *BackendPlugin) CollectMetrics(ctx context.Context) (*pluginv2.CollectMe
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (p *BackendPlugin) checkHealth(ctx context.Context, config *PluginConfig) (*pluginv2.CheckHealthResponse, error) {
|
||||
var toProto = backend.ToProto()
|
||||
|
||||
func (p *BackendPlugin) checkHealth(ctx context.Context, pCtx backend.PluginContext) (*pluginv2.CheckHealthResponse, error) {
|
||||
if p.diagnostics == nil || p.client == nil || p.client.Exited() {
|
||||
return &pluginv2.CheckHealthResponse{
|
||||
Status: pluginv2.CheckHealthResponse_UNKNOWN,
|
||||
}, nil
|
||||
}
|
||||
|
||||
jsonDataBytes, err := config.JSONData.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pconfig := &pluginv2.PluginConfig{
|
||||
OrgId: config.OrgID,
|
||||
PluginId: config.PluginID,
|
||||
JsonData: jsonDataBytes,
|
||||
DecryptedSecureJsonData: config.DecryptedSecureJSONData,
|
||||
LastUpdatedMS: config.Updated.UnixNano() / int64(time.Millisecond),
|
||||
}
|
||||
|
||||
if config.DataSourceConfig != nil {
|
||||
datasourceJSONData, err := config.DataSourceConfig.JSONData.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pconfig.DatasourceConfig = &pluginv2.DataSourceConfig{
|
||||
Id: config.DataSourceConfig.ID,
|
||||
Name: config.DataSourceConfig.Name,
|
||||
Url: config.DataSourceConfig.URL,
|
||||
User: config.DataSourceConfig.User,
|
||||
Database: config.DataSourceConfig.Database,
|
||||
BasicAuthEnabled: config.DataSourceConfig.BasicAuthEnabled,
|
||||
BasicAuthUser: config.DataSourceConfig.BasicAuthUser,
|
||||
JsonData: datasourceJSONData,
|
||||
DecryptedSecureJsonData: config.DataSourceConfig.DecryptedSecureJSONData,
|
||||
LastUpdatedMS: config.DataSourceConfig.Updated.Unix() / int64(time.Millisecond),
|
||||
}
|
||||
}
|
||||
protoContext := toProto.PluginContext(pCtx)
|
||||
|
||||
var res *pluginv2.CheckHealthResponse
|
||||
err = InstrumentPluginRequest(p.id, "checkhealth", func() error {
|
||||
err := InstrumentPluginRequest(p.id, "checkhealth", func() error {
|
||||
var innerErr error
|
||||
res, innerErr = p.diagnostics.CheckHealth(ctx, &pluginv2.CheckHealthRequest{Config: pconfig})
|
||||
res, innerErr = p.diagnostics.CheckHealth(ctx, &pluginv2.CheckHealthRequest{PluginContext: protoContext})
|
||||
return innerErr
|
||||
})
|
||||
|
||||
@@ -237,66 +208,14 @@ func (p *BackendPlugin) checkHealth(ctx context.Context, config *PluginConfig) (
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (p *BackendPlugin) callResource(ctx context.Context, req CallResourceRequest) (callResourceResultStream, error) {
|
||||
func (p *BackendPlugin) callResource(ctx context.Context, req *backend.CallResourceRequest) (callResourceResultStream, error) {
|
||||
p.logger.Debug("Calling resource", "path", req.Path, "method", req.Method)
|
||||
|
||||
if p.resource == nil || p.client == nil || p.client.Exited() {
|
||||
return nil, errors.New("plugin not running, cannot call resource")
|
||||
}
|
||||
|
||||
reqHeaders := map[string]*pluginv2.StringList{}
|
||||
for k, v := range req.Headers {
|
||||
reqHeaders[k] = &pluginv2.StringList{Values: v}
|
||||
}
|
||||
|
||||
jsonDataBytes, err := req.Config.JSONData.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protoReq := &pluginv2.CallResourceRequest{
|
||||
Config: &pluginv2.PluginConfig{
|
||||
OrgId: req.Config.OrgID,
|
||||
PluginId: req.Config.PluginID,
|
||||
JsonData: jsonDataBytes,
|
||||
DecryptedSecureJsonData: req.Config.DecryptedSecureJSONData,
|
||||
LastUpdatedMS: req.Config.Updated.UnixNano() / int64(time.Millisecond),
|
||||
},
|
||||
Path: req.Path,
|
||||
Method: req.Method,
|
||||
Url: req.URL,
|
||||
Headers: reqHeaders,
|
||||
Body: req.Body,
|
||||
}
|
||||
|
||||
if req.User != nil {
|
||||
protoReq.User = &pluginv2.User{
|
||||
Name: req.User.Name,
|
||||
Login: req.User.Login,
|
||||
Email: req.User.Email,
|
||||
Role: string(req.User.OrgRole),
|
||||
}
|
||||
}
|
||||
|
||||
if req.Config.DataSourceConfig != nil {
|
||||
datasourceJSONData, err := req.Config.DataSourceConfig.JSONData.ToDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
protoReq.Config.DatasourceConfig = &pluginv2.DataSourceConfig{
|
||||
Id: req.Config.DataSourceConfig.ID,
|
||||
Name: req.Config.DataSourceConfig.Name,
|
||||
Url: req.Config.DataSourceConfig.URL,
|
||||
Database: req.Config.DataSourceConfig.Database,
|
||||
User: req.Config.DataSourceConfig.User,
|
||||
BasicAuthEnabled: req.Config.DataSourceConfig.BasicAuthEnabled,
|
||||
BasicAuthUser: req.Config.DataSourceConfig.BasicAuthUser,
|
||||
JsonData: datasourceJSONData,
|
||||
DecryptedSecureJsonData: req.Config.DataSourceConfig.DecryptedSecureJSONData,
|
||||
LastUpdatedMS: req.Config.DataSourceConfig.Updated.UnixNano() / int64(time.Millisecond),
|
||||
}
|
||||
}
|
||||
protoReq := toProto.CallResourceRequest(req)
|
||||
|
||||
protoStream, err := p.resource.CallResource(ctx, protoReq)
|
||||
if err != nil {
|
||||
|
@@ -2,10 +2,6 @@ package backendplugin
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
|
||||
)
|
||||
@@ -76,38 +72,6 @@ type CollectMetricsResult struct {
|
||||
PrometheusMetrics []byte
|
||||
}
|
||||
|
||||
type DataSourceConfig struct {
|
||||
ID int64
|
||||
Name string
|
||||
URL string
|
||||
User string
|
||||
Database string
|
||||
BasicAuthEnabled bool
|
||||
BasicAuthUser string
|
||||
JSONData *simplejson.Json
|
||||
DecryptedSecureJSONData map[string]string
|
||||
Updated time.Time
|
||||
}
|
||||
|
||||
type PluginConfig struct {
|
||||
OrgID int64
|
||||
PluginID string
|
||||
JSONData *simplejson.Json
|
||||
DecryptedSecureJSONData map[string]string
|
||||
Updated time.Time
|
||||
DataSourceConfig *DataSourceConfig
|
||||
}
|
||||
|
||||
type CallResourceRequest struct {
|
||||
Config PluginConfig
|
||||
Path string
|
||||
Method string
|
||||
URL string
|
||||
Headers map[string][]string
|
||||
Body []byte
|
||||
User *models.SignedInUser
|
||||
}
|
||||
|
||||
// CallResourceResult call resource result.
|
||||
type CallResourceResult struct {
|
||||
Status int
|
||||
|
@@ -2,12 +2,14 @@ package backendplugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util/errutil"
|
||||
@@ -45,9 +47,9 @@ type Manager interface {
|
||||
// CollectMetrics collects metrics from a registered backend plugin.
|
||||
CollectMetrics(ctx context.Context, pluginID string) (*CollectMetricsResult, error)
|
||||
// CheckHealth checks the health of a registered backend plugin.
|
||||
CheckHealth(ctx context.Context, pluginConfig *PluginConfig) (*CheckHealthResult, error)
|
||||
CheckHealth(ctx context.Context, pCtx backend.PluginContext) (*CheckHealthResult, error)
|
||||
// CallResource calls a plugin resource.
|
||||
CallResource(pluginConfig PluginConfig, ctx *models.ReqContext, path string)
|
||||
CallResource(pluginConfig backend.PluginContext, ctx *models.ReqContext, path string)
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
@@ -187,7 +189,7 @@ func (m *manager) CollectMetrics(ctx context.Context, pluginID string) (*Collect
|
||||
}
|
||||
|
||||
// CheckHealth checks the health of a registered backend plugin.
|
||||
func (m *manager) CheckHealth(ctx context.Context, pluginConfig *PluginConfig) (*CheckHealthResult, error) {
|
||||
func (m *manager) CheckHealth(ctx context.Context, pluginConfig backend.PluginContext) (*CheckHealthResult, error) {
|
||||
m.pluginsMu.RLock()
|
||||
p, registered := m.plugins[pluginConfig.PluginID]
|
||||
m.pluginsMu.RUnlock()
|
||||
@@ -209,10 +211,14 @@ func (m *manager) CheckHealth(ctx context.Context, pluginConfig *PluginConfig) (
|
||||
return checkHealthResultFromProto(res), nil
|
||||
}
|
||||
|
||||
type keepCookiesJSONModel struct {
|
||||
KeepCookies []string `json:"keepCookies"`
|
||||
}
|
||||
|
||||
// CallResource calls a plugin resource.
|
||||
func (m *manager) CallResource(config PluginConfig, reqCtx *models.ReqContext, path string) {
|
||||
func (m *manager) CallResource(pCtx backend.PluginContext, reqCtx *models.ReqContext, path string) {
|
||||
m.pluginsMu.RLock()
|
||||
p, registered := m.plugins[config.PluginID]
|
||||
p, registered := m.plugins[pCtx.PluginID]
|
||||
m.pluginsMu.RUnlock()
|
||||
|
||||
if !registered {
|
||||
@@ -221,14 +227,15 @@ func (m *manager) CallResource(config PluginConfig, reqCtx *models.ReqContext, p
|
||||
}
|
||||
|
||||
clonedReq := reqCtx.Req.Clone(reqCtx.Req.Context())
|
||||
keepCookieNames := []string{}
|
||||
if config.JSONData != nil {
|
||||
if keepCookies := config.JSONData.Get("keepCookies"); keepCookies != nil {
|
||||
keepCookieNames = keepCookies.MustStringArray()
|
||||
keepCookieModel := keepCookiesJSONModel{}
|
||||
if dis := pCtx.DataSourceInstanceSettings; dis != nil {
|
||||
err := json.Unmarshal(dis.JSONData, &keepCookieModel)
|
||||
if err != nil {
|
||||
p.logger.Error("Failed to to unpack JSONData in datasource instance settings", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
proxyutil.ClearCookieHeader(clonedReq, keepCookieNames)
|
||||
proxyutil.ClearCookieHeader(clonedReq, keepCookieModel.KeepCookies)
|
||||
proxyutil.PrepareProxyRequest(clonedReq)
|
||||
|
||||
body, err := reqCtx.Req.Body().Bytes()
|
||||
@@ -237,14 +244,13 @@ func (m *manager) CallResource(config PluginConfig, reqCtx *models.ReqContext, p
|
||||
return
|
||||
}
|
||||
|
||||
req := CallResourceRequest{
|
||||
Config: config,
|
||||
Path: path,
|
||||
Method: clonedReq.Method,
|
||||
URL: clonedReq.URL.String(),
|
||||
Headers: clonedReq.Header,
|
||||
Body: body,
|
||||
User: reqCtx.SignedInUser,
|
||||
req := &backend.CallResourceRequest{
|
||||
PluginContext: pCtx,
|
||||
Path: path,
|
||||
Method: clonedReq.Method,
|
||||
URL: clonedReq.URL.String(),
|
||||
Headers: clonedReq.Header,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
err = InstrumentPluginRequest(p.id, "resource", func() error {
|
||||
|
@@ -3,11 +3,11 @@ package wrapper
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/genproto/pluginv2"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
@@ -25,39 +25,40 @@ type DatasourcePluginWrapperV2 struct {
|
||||
pluginType string
|
||||
}
|
||||
|
||||
func (tw *DatasourcePluginWrapperV2) Query(ctx context.Context, ds *models.DataSource, query *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
func ModelToInstanceSettings(ds *models.DataSource) (*backend.DataSourceInstanceSettings, error) {
|
||||
jsonDataBytes, err := ds.JsonData.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pbQuery := &pluginv2.QueryDataRequest{
|
||||
Config: &pluginv2.PluginConfig{
|
||||
OrgId: ds.OrgId,
|
||||
PluginId: tw.pluginId,
|
||||
LastUpdatedMS: ds.Updated.UnixNano() / int64(time.Millisecond),
|
||||
DatasourceConfig: &pluginv2.DataSourceConfig{
|
||||
Id: ds.Id,
|
||||
Name: ds.Name,
|
||||
Url: ds.Url,
|
||||
Database: ds.Database,
|
||||
User: ds.User,
|
||||
BasicAuthEnabled: ds.BasicAuth,
|
||||
BasicAuthUser: ds.BasicAuthUser,
|
||||
JsonData: jsonDataBytes,
|
||||
DecryptedSecureJsonData: ds.DecryptedValues(),
|
||||
},
|
||||
},
|
||||
Queries: []*pluginv2.DataQuery{},
|
||||
return &backend.DataSourceInstanceSettings{
|
||||
ID: ds.Id,
|
||||
Name: ds.Name,
|
||||
URL: ds.Url,
|
||||
Database: ds.Database,
|
||||
User: ds.User,
|
||||
BasicAuthEnabled: ds.BasicAuth,
|
||||
BasicAuthUser: ds.BasicAuthUser,
|
||||
JSONData: jsonDataBytes,
|
||||
DecryptedSecureJSONData: ds.DecryptedValues(),
|
||||
Updated: ds.Updated,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tw *DatasourcePluginWrapperV2) Query(ctx context.Context, ds *models.DataSource, query *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
instanceSettings, err := ModelToInstanceSettings(ds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if query.User != nil {
|
||||
pbQuery.User = &pluginv2.User{
|
||||
Name: query.User.Name,
|
||||
Login: query.User.Login,
|
||||
Email: query.User.Email,
|
||||
Role: string(query.User.OrgRole),
|
||||
}
|
||||
pbQuery := &pluginv2.QueryDataRequest{
|
||||
PluginContext: &pluginv2.PluginContext{
|
||||
OrgId: ds.OrgId,
|
||||
PluginId: tw.pluginId,
|
||||
User: backend.ToProto().User(BackendUserFromSignedInUser(query.User)),
|
||||
DataSourceInstanceSettings: backend.ToProto().DataSourceInstanceSettings(instanceSettings),
|
||||
},
|
||||
Queries: []*pluginv2.DataQuery{},
|
||||
}
|
||||
|
||||
for _, q := range query.Queries {
|
||||
@@ -110,3 +111,17 @@ func (tw *DatasourcePluginWrapperV2) Query(ctx context.Context, ds *models.DataS
|
||||
|
||||
return tR, nil
|
||||
}
|
||||
|
||||
// BackendUserFromSignedInUser converts Grafana's SignedInUser model
|
||||
// to the backend plugin's model.
|
||||
func BackendUserFromSignedInUser(su *models.SignedInUser) *backend.User {
|
||||
if su == nil {
|
||||
return nil
|
||||
}
|
||||
return &backend.User{
|
||||
Login: su.Login,
|
||||
Name: su.Name,
|
||||
Email: su.Name,
|
||||
Role: string(su.OrgRole),
|
||||
}
|
||||
}
|
||||
|
@@ -77,7 +77,9 @@ type TransformWrapper struct {
|
||||
|
||||
func (tw *TransformWrapper) Transform(ctx context.Context, query *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||
pbQuery := &pluginv2.QueryDataRequest{
|
||||
Config: &pluginv2.PluginConfig{},
|
||||
PluginContext: &pluginv2.PluginContext{
|
||||
// TODO: Things probably
|
||||
},
|
||||
Queries: []*pluginv2.DataQuery{},
|
||||
}
|
||||
|
||||
@@ -134,12 +136,12 @@ func (s *transformCallback) QueryData(ctx context.Context, req *pluginv2.QueryDa
|
||||
|
||||
datasourceID := int64(0)
|
||||
|
||||
if req.Config.DatasourceConfig != nil {
|
||||
datasourceID = req.Config.DatasourceConfig.Id
|
||||
if req.PluginContext.DataSourceInstanceSettings != nil {
|
||||
datasourceID = req.PluginContext.DataSourceInstanceSettings.Id
|
||||
}
|
||||
|
||||
getDsInfo := &models.GetDataSourceByIdQuery{
|
||||
OrgId: req.Config.OrgId,
|
||||
OrgId: req.PluginContext.OrgId,
|
||||
Id: datasourceID,
|
||||
}
|
||||
|
||||
|
@@ -49,7 +49,7 @@ func FrameToSeriesSlice(frame *data.Frame) (TimeSeriesSlice, error) {
|
||||
// If Long, make wide
|
||||
if tsSchema.Type == data.TimeSeriesTypeLong {
|
||||
var err error
|
||||
frame, err = data.LongToWide(frame)
|
||||
frame, err = data.LongToWide(frame, nil)
|
||||
if err != nil {
|
||||
return nil, errutil.Wrap("failed to convert long to wide series when converting from dataframe", err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user