Influx: Support flux in the influx datasource (#25308)
* add flux * add token to datasource config editor * add backend for flux * make the interpolated query available in query inspector * go mod tidy * Chore: fixes a couple of strict null errors in influxdb plugin Co-authored-by: kyle <kyle@grafana.com> Co-authored-by: Lukas Siatka <lukasz.siatka@grafana.com>
This commit is contained in:
co-authored by
kyle
Lukas Siatka
parent
c7aac1fd40
commit
5f1f820bb9
@@ -25,8 +25,8 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/go-stack/stack v1.8.0
|
github.com/go-stack/stack v1.8.0
|
||||||
github.com/gobwas/glob v0.2.3
|
github.com/gobwas/glob v0.2.3
|
||||||
github.com/golang/protobuf v1.3.4
|
github.com/golang/protobuf v1.4.0
|
||||||
github.com/google/go-cmp v0.3.1
|
github.com/google/go-cmp v0.4.0
|
||||||
github.com/gorilla/websocket v1.4.1
|
github.com/gorilla/websocket v1.4.1
|
||||||
github.com/gosimple/slug v1.4.2
|
github.com/gosimple/slug v1.4.2
|
||||||
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
|
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
|
||||||
@@ -35,6 +35,7 @@ require (
|
|||||||
github.com/hashicorp/go-plugin v1.2.2
|
github.com/hashicorp/go-plugin v1.2.2
|
||||||
github.com/hashicorp/go-version v1.1.0
|
github.com/hashicorp/go-version v1.1.0
|
||||||
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec
|
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec
|
||||||
|
github.com/influxdata/influxdb-client-go v1.1.1-0.20200511153144-e63a28ffeba7
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
|
||||||
github.com/jung-kurt/gofpdf v1.10.1
|
github.com/jung-kurt/gofpdf v1.10.1
|
||||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
|
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
|
||||||
@@ -70,13 +71,11 @@ require (
|
|||||||
github.com/yudai/pp v2.0.1+incompatible // indirect
|
github.com/yudai/pp v2.0.1+incompatible // indirect
|
||||||
go.uber.org/atomic v1.5.1 // indirect
|
go.uber.org/atomic v1.5.1 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
|
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||||
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-20191204190536-9bdfabe68543
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
|
||||||
google.golang.org/grpc v1.27.1
|
google.golang.org/grpc v1.29.1
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||||
gopkg.in/ini.v1 v1.46.0
|
gopkg.in/ini.v1 v1.46.0
|
||||||
@@ -85,7 +84,7 @@ require (
|
|||||||
gopkg.in/mail.v2 v2.3.1
|
gopkg.in/mail.v2 v2.3.1
|
||||||
gopkg.in/redis.v5 v5.2.9
|
gopkg.in/redis.v5 v5.2.9
|
||||||
gopkg.in/square/go-jose.v2 v2.4.1
|
gopkg.in/square/go-jose.v2 v2.4.1
|
||||||
gopkg.in/yaml.v2 v2.2.5
|
gopkg.in/yaml.v2 v2.2.8
|
||||||
xorm.io/core v0.7.3
|
xorm.io/core v0.7.3
|
||||||
xorm.io/xorm v0.8.1
|
xorm.io/xorm v0.8.1
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
|||||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
github.com/couchbase/gomemcached v0.0.0-20190515232915-c4b4ca0eb21d/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||||
@@ -47,10 +48,13 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
|
|||||||
github.com/crewjam/saml v0.0.0-20191031171751-c42136edf9b1 h1:PKeiHI5SxrkdEtI8FVdk1ubBl2wjnOmHQf5D4ZJOKFE=
|
github.com/crewjam/saml v0.0.0-20191031171751-c42136edf9b1 h1:PKeiHI5SxrkdEtI8FVdk1ubBl2wjnOmHQf5D4ZJOKFE=
|
||||||
github.com/crewjam/saml v0.0.0-20191031171751-c42136edf9b1/go.mod h1:pzACCdpqjQKTvpPZs5P3FzFNQ+RSOJX5StwHwh7ZUgw=
|
github.com/crewjam/saml v0.0.0-20191031171751-c42136edf9b1/go.mod h1:pzACCdpqjQKTvpPZs5P3FzFNQ+RSOJX5StwHwh7ZUgw=
|
||||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||||
|
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
github.com/dchest/uniuri v0.0.0-20160212164326-8902c56451e9/go.mod h1:GgB8SF9nRG+GqaDtLcwJZsQFhcogVCJ79j4EdT0c2V4=
|
||||||
|
github.com/deepmap/oapi-codegen v1.3.6 h1:Wj44p9A0V0PJ+AUg0BWdyGcsS1LY18U+0rCuPQgK0+o=
|
||||||
|
github.com/deepmap/oapi-codegen v1.3.6/go.mod h1:aBozjEveG+33xPiP55Iw/XbVkhtZHEGLq3nxlX0+hfU=
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
||||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
@@ -59,7 +63,9 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
|
|||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||||
@@ -75,6 +81,9 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
|||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
|
github.com/getkin/kin-openapi v0.2.0/go.mod h1:V1z9xl9oF5Wt7v32ne4FmiF1alpS4dM6mNzoywPOXlk=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
@@ -108,17 +117,28 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
|||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||||
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
|
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||||
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A=
|
github.com/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A=
|
||||||
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
@@ -156,6 +176,10 @@ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
|||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178=
|
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec h1:CGkYB1Q7DSsH/ku+to+foV4agt2F2miquaLUgF6L178=
|
||||||
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||||
|
github.com/influxdata/influxdb-client-go v1.1.1-0.20200511153144-e63a28ffeba7 h1:4Inzo/mjTMm7DdqVNkbHmEo6UIwQDpWHMYdlu4+I/W4=
|
||||||
|
github.com/influxdata/influxdb-client-go v1.1.1-0.20200511153144-e63a28ffeba7/go.mod h1:ZVjaPW87aKp5hzyny2WVpWVF0UY+iqtPz9veOZ2T1zw=
|
||||||
|
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 h1:W9WBk7wlPfJLvMCdtV4zPulc4uCPrlywQOmbFOhgQNU=
|
||||||
|
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo=
|
||||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||||
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
@@ -188,6 +212,10 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
|
||||||
|
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||||
|
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||||
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
@@ -197,10 +225,16 @@ github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbat
|
|||||||
github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0=
|
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 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE=
|
||||||
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
|
||||||
|
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||||
github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY=
|
github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY=
|
||||||
github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI=
|
github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI=
|
||||||
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
@@ -322,6 +356,11 @@ github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
|
|||||||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
|
||||||
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||||
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
|
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
|
||||||
|
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/xorcare/pointer v1.1.0 h1:sFwXOhRF8QZ0tyVZrtxWGIoVZNEmRzBCaFWdONPQIUM=
|
github.com/xorcare/pointer v1.1.0 h1:sFwXOhRF8QZ0tyVZrtxWGIoVZNEmRzBCaFWdONPQIUM=
|
||||||
github.com/xorcare/pointer v1.1.0/go.mod h1:6KLhkOh6YbuvZkT4YbxIbR/wzLBjyMxOiNzZhJTor2Y=
|
github.com/xorcare/pointer v1.1.0/go.mod h1:6KLhkOh6YbuvZkT4YbxIbR/wzLBjyMxOiNzZhJTor2Y=
|
||||||
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
|
||||||
@@ -345,8 +384,7 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
|
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71 h1:DOmugCavvUtnUD114C1Wh+UgTgQZ4pMLzXxi1pSt+/Y=
|
||||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@@ -355,10 +393,8 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
|
|||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -375,12 +411,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
|
||||||
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -388,6 +427,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||||
|
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -395,15 +436,21 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||||
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
@@ -422,12 +469,9 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
|
|||||||
golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f h1:kDxGY2VmgABOe55qheT/TFqUMtcTHnomIPS1iv3G4Ms=
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935 h1:kJQZhwFzSwJS2BxboKjdZzWczQOZx8VuH7Y8hhuGUtM=
|
|
||||||
golang.org/x/tools v0.0.0-20191213221258-04c2e8eff935/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
@@ -447,8 +491,17 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
|
|||||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
|
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||||
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
|
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||||
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
@@ -481,6 +534,8 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -0,0 +1,182 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
influxdb2 "github.com/influxdata/influxdb-client-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Copied from: (Apache 2 license)
|
||||||
|
// https://github.com/influxdata/influxdb-client-go/blob/master/query.go#L30
|
||||||
|
const (
|
||||||
|
stringDatatype = "string"
|
||||||
|
doubleDatatype = "double"
|
||||||
|
boolDatatype = "bool"
|
||||||
|
longDatatype = "long"
|
||||||
|
uLongDatatype = "unsignedLong"
|
||||||
|
durationDatatype = "duration"
|
||||||
|
base64BinaryDataType = "base64Binary"
|
||||||
|
timeDatatypeRFC = "dateTime:RFC3339"
|
||||||
|
timeDatatypeRFCNano = "dateTime:RFC3339Nano"
|
||||||
|
)
|
||||||
|
|
||||||
|
type columnInfo struct {
|
||||||
|
name string
|
||||||
|
converter *data.FieldConverter
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an interface to help testing
|
||||||
|
type FrameBuilder struct {
|
||||||
|
tableId int64
|
||||||
|
active *data.Frame
|
||||||
|
frames []*data.Frame
|
||||||
|
value *data.FieldConverter
|
||||||
|
columns []columnInfo
|
||||||
|
labels []string
|
||||||
|
maxPoints int // max points in a series
|
||||||
|
maxSeries int // max number of series
|
||||||
|
totalSeries int
|
||||||
|
isTimeSeries bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTag(schk string) bool {
|
||||||
|
return (schk != "result" && schk != "table" && schk[0] != '_')
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConverter(t string) (*data.FieldConverter, error) {
|
||||||
|
switch t {
|
||||||
|
case stringDatatype:
|
||||||
|
return &AnyToOptionalString, nil
|
||||||
|
case timeDatatypeRFC:
|
||||||
|
return &Int64ToOptionalInt64, nil
|
||||||
|
case timeDatatypeRFCNano:
|
||||||
|
return &Int64ToOptionalInt64, nil
|
||||||
|
case durationDatatype:
|
||||||
|
return &Int64ToOptionalInt64, nil
|
||||||
|
case doubleDatatype:
|
||||||
|
return &Float64ToOptionalFloat64, nil
|
||||||
|
case boolDatatype:
|
||||||
|
return &BoolToOptionalBool, nil
|
||||||
|
case longDatatype:
|
||||||
|
return &Int64ToOptionalInt64, nil
|
||||||
|
case uLongDatatype:
|
||||||
|
return &UInt64ToOptionalUInt64, nil
|
||||||
|
case base64BinaryDataType:
|
||||||
|
return &AnyToOptionalString, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("No matching converter found for [%v]", t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initializes the frame to be returned
|
||||||
|
// fields points at entries in the frame, and provides easier access
|
||||||
|
// names indexes the columns encountered
|
||||||
|
func (fb *FrameBuilder) Init(metadata *influxdb2.FluxTableMetadata) error {
|
||||||
|
columns := metadata.Columns()
|
||||||
|
fb.frames = make([]*data.Frame, 0)
|
||||||
|
fb.tableId = -1
|
||||||
|
fb.value = nil
|
||||||
|
fb.columns = make([]columnInfo, 0)
|
||||||
|
fb.isTimeSeries = false
|
||||||
|
|
||||||
|
for _, col := range columns {
|
||||||
|
switch {
|
||||||
|
case col.Name() == "_value":
|
||||||
|
if fb.value != nil {
|
||||||
|
return fmt.Errorf("multiple values found")
|
||||||
|
}
|
||||||
|
converter, err := getConverter(col.DataType())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fb.value = converter
|
||||||
|
case col.Name() == "_measurement":
|
||||||
|
fb.isTimeSeries = true
|
||||||
|
case isTag(col.Name()):
|
||||||
|
fb.labels = append(fb.labels, col.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fb.isTimeSeries {
|
||||||
|
fb.labels = make([]string, 0)
|
||||||
|
for _, col := range columns {
|
||||||
|
converter, err := getConverter(col.DataType())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fb.columns = append(fb.columns, columnInfo{
|
||||||
|
name: col.Name(),
|
||||||
|
converter: converter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends a single entry from an influxdb2 record to a data frame
|
||||||
|
// Values are appended to _value
|
||||||
|
// Tags are appended as labels
|
||||||
|
// _measurement holds the dataframe name
|
||||||
|
// _field holds the field name.
|
||||||
|
func (fb *FrameBuilder) Append(record *influxdb2.FluxRecord) error {
|
||||||
|
table, ok := record.ValueByKey("table").(int64)
|
||||||
|
if ok && table != fb.tableId {
|
||||||
|
fb.totalSeries++
|
||||||
|
if fb.totalSeries > fb.maxSeries {
|
||||||
|
return fmt.Errorf("reached max series limit (%d)", fb.maxSeries)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fb.isTimeSeries {
|
||||||
|
// Series Data
|
||||||
|
labels := make(map[string]string)
|
||||||
|
for _, name := range fb.labels {
|
||||||
|
labels[name] = record.ValueByKey(name).(string)
|
||||||
|
}
|
||||||
|
fb.active = data.NewFrame(
|
||||||
|
record.Measurement(),
|
||||||
|
data.NewFieldFromFieldType(data.FieldTypeTime, 0),
|
||||||
|
data.NewFieldFromFieldType(fb.value.OutputFieldType, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
fb.active.Fields[0].Name = "Time"
|
||||||
|
fb.active.Fields[1].Name = record.Field()
|
||||||
|
fb.active.Fields[1].Labels = labels
|
||||||
|
} else {
|
||||||
|
fields := make([]*data.Field, len(fb.columns))
|
||||||
|
for idx, col := range fb.columns {
|
||||||
|
fields[idx] = data.NewFieldFromFieldType(col.converter.OutputFieldType, 0)
|
||||||
|
fields[idx].Name = col.name
|
||||||
|
}
|
||||||
|
fb.active = data.NewFrame("", fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
fb.frames = append(fb.frames, fb.active)
|
||||||
|
fb.tableId = table
|
||||||
|
}
|
||||||
|
|
||||||
|
if fb.isTimeSeries {
|
||||||
|
val, err := fb.value.Converter(record.Value())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fb.active.Fields[0].Append(record.Time())
|
||||||
|
fb.active.Fields[1].Append(val)
|
||||||
|
} else {
|
||||||
|
// Table view
|
||||||
|
for idx, col := range fb.columns {
|
||||||
|
val, err := col.converter.Converter(record.ValueByKey(col.name))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fb.active.Fields[idx].Append(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fb.active.Fields[0].Len() > fb.maxPoints {
|
||||||
|
return fmt.Errorf("returned too many points in a series: %d", fb.maxPoints)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var isField = regexp.MustCompile(`^_(time|value|measurement|field|start|stop)$`)
|
||||||
|
|
||||||
|
func TestColumnIdentification(t *testing.T) {
|
||||||
|
t.Run("Test Field Identification", func(t *testing.T) {
|
||||||
|
fieldNames := []string{"_time", "_value", "_measurement", "_field", "_start", "_stop"}
|
||||||
|
for _, item := range fieldNames {
|
||||||
|
if !isField.MatchString(item) {
|
||||||
|
t.Fatal("Field", item, "Expected field, but got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Test Not Field Identification", func(t *testing.T) {
|
||||||
|
fieldNames := []string{"_header", "_cpu", "_hello", "_doctor"}
|
||||||
|
for _, item := range fieldNames {
|
||||||
|
if isField.MatchString(item) {
|
||||||
|
t.Fatal("Field", item, "Expected NOT a field, but got true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Test Tag Identification", func(t *testing.T) {
|
||||||
|
tagNames := []string{"header", "value", "tag"}
|
||||||
|
for _, item := range tagNames {
|
||||||
|
if !isTag(item) {
|
||||||
|
t.Fatal("Tag", item, "Expected tag, but got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Test Special Case Tag Identification", func(t *testing.T) {
|
||||||
|
notTagNames := []string{"table", "result"}
|
||||||
|
for _, item := range notTagNames {
|
||||||
|
if isTag(item) {
|
||||||
|
t.Fatal("Special tag", item, "Expected NOT a tag, but got true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Int64NOOP .....
|
||||||
|
var Int64NOOP = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeInt64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolNOOP .....
|
||||||
|
var BoolNOOP = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeBool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64NOOP .....
|
||||||
|
var Float64NOOP = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeFloat64,
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringNOOP value is already in the proper format
|
||||||
|
var StringNOOP = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeString,
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnyToOptionalString any value as a string
|
||||||
|
var AnyToOptionalString = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeNullableString,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
str := fmt.Sprintf("%+v", v) // the +v adds field names
|
||||||
|
return &str, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64ToOptionalFloat64 optional float value
|
||||||
|
var Float64ToOptionalFloat64 = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeNullableFloat64,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
val, ok := v.(float64)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[float] expected float64 input but got type %T", v)
|
||||||
|
}
|
||||||
|
return &val, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64ToOptionalInt64 optional int value
|
||||||
|
var Int64ToOptionalInt64 = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeNullableInt64,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
val, ok := v.(int64)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[int] expected int64 input but got type %T", v)
|
||||||
|
}
|
||||||
|
return &val, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// UInt64ToOptionalUInt64 optional int value
|
||||||
|
var UInt64ToOptionalUInt64 = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeNullableUint64,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
val, ok := v.(uint64)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[uint] expected uint64 input but got type %T", v)
|
||||||
|
}
|
||||||
|
return &val, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolToOptionalBool optional int value
|
||||||
|
var BoolToOptionalBool = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeNullableBool,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
val, ok := v.(bool)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[bool] expected bool input but got type %T", v)
|
||||||
|
}
|
||||||
|
return &val, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// RFC3339StringToNullableTime .....
|
||||||
|
func RFC3339StringToNullableTime(s string) (*time.Time, error) {
|
||||||
|
if s == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rv, err := time.Parse(time.RFC3339, s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
u := rv.UTC()
|
||||||
|
return &u, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToOptionalFloat64 string to float
|
||||||
|
var StringToOptionalFloat64 = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeNullableFloat64,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
if v == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
val, ok := v.(string)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[floatz] expected string input but got type %T", v)
|
||||||
|
}
|
||||||
|
fV, err := strconv.ParseFloat(val, 64)
|
||||||
|
return &fV, err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64EpochSecondsToTime numeric seconds to time
|
||||||
|
var Float64EpochSecondsToTime = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeTime,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
fV, ok := v.(float64)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[seconds] expected float64 input but got type %T", v)
|
||||||
|
}
|
||||||
|
return time.Unix(int64(fV), 0).UTC(), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64EpochMillisToTime convert to time
|
||||||
|
var Float64EpochMillisToTime = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeTime,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
fV, ok := v.(float64)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[ms] expected float64 input but got type %T", v)
|
||||||
|
}
|
||||||
|
return time.Unix(0, int64(fV)*int64(time.Millisecond)).UTC(), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean ...
|
||||||
|
var Boolean = data.FieldConverter{
|
||||||
|
OutputFieldType: data.FieldTypeBool,
|
||||||
|
Converter: func(v interface{}) (interface{}, error) {
|
||||||
|
fV, ok := v.(bool)
|
||||||
|
if !ok { // or return some default value instead of erroring
|
||||||
|
return nil, fmt.Errorf("[ms] expected bool input but got type %T", v)
|
||||||
|
}
|
||||||
|
return fV, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||||
|
influxdb2 "github.com/influxdata/influxdb-client-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExecuteQuery runs a flux query using the QueryModel to interpolate the query and the runner to execute it.
|
||||||
|
// maxSeries somehow limits the response.
|
||||||
|
func ExecuteQuery(ctx context.Context, query QueryModel, runner queryRunner, maxSeries int) (dr backend.DataResponse) {
|
||||||
|
dr = backend.DataResponse{}
|
||||||
|
|
||||||
|
flux, err := Interpolate(query)
|
||||||
|
if err != nil {
|
||||||
|
dr.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.Debug("Flux", "interpolated query", flux)
|
||||||
|
|
||||||
|
tables, err := runner.runQuery(ctx, flux)
|
||||||
|
if err != nil {
|
||||||
|
dr.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dr = readDataFrames(tables, int(float64(query.MaxDataPoints)*1.5), maxSeries)
|
||||||
|
|
||||||
|
for _, frame := range dr.Frames {
|
||||||
|
if frame.Meta == nil {
|
||||||
|
frame.Meta = &data.FrameMeta{}
|
||||||
|
}
|
||||||
|
frame.Meta.ExecutedQueryString = flux
|
||||||
|
}
|
||||||
|
|
||||||
|
return dr
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDataFrames(result *influxdb2.QueryTableResult, maxPoints int, maxSeries int) (dr backend.DataResponse) {
|
||||||
|
dr = backend.DataResponse{}
|
||||||
|
|
||||||
|
builder := &FrameBuilder{
|
||||||
|
maxPoints: maxPoints,
|
||||||
|
maxSeries: maxSeries,
|
||||||
|
}
|
||||||
|
|
||||||
|
for result.Next() {
|
||||||
|
// Observe when there is new grouping key producing new table
|
||||||
|
if result.TableChanged() {
|
||||||
|
if builder.frames != nil {
|
||||||
|
for _, frame := range builder.frames {
|
||||||
|
dr.Frames = append(dr.Frames, frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err := builder.Init(result.TableMetadata())
|
||||||
|
if err != nil {
|
||||||
|
dr.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if builder.frames == nil {
|
||||||
|
dr.Error = fmt.Errorf("Invalid state")
|
||||||
|
return dr
|
||||||
|
}
|
||||||
|
|
||||||
|
err := builder.Append(result.Record())
|
||||||
|
if err != nil {
|
||||||
|
dr.Error = err
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the inprogress record
|
||||||
|
if builder.frames != nil {
|
||||||
|
for _, frame := range builder.frames {
|
||||||
|
dr.Frames = append(dr.Frames, frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach any errors (may be null)
|
||||||
|
dr.Error = result.Err()
|
||||||
|
return dr
|
||||||
|
}
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
influxdb2 "github.com/influxdata/influxdb-client-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
//--------------------------------------------------------------
|
||||||
|
// TestData -- reads result from saved files
|
||||||
|
//--------------------------------------------------------------
|
||||||
|
|
||||||
|
// MockRunner reads local file path for testdata.
|
||||||
|
type MockRunner struct {
|
||||||
|
testDataPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *MockRunner) runQuery(ctx context.Context, q string) (*influxdb2.QueryTableResult, error) {
|
||||||
|
bytes, err := ioutil.ReadFile("./testdata/" + r.testDataPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
if r.Method == http.MethodPost {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write(bytes)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
client := influxdb2.NewClient(server.URL, "a")
|
||||||
|
return client.QueryApi("x").Query(ctx, q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteSimple(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Simple Test", func(t *testing.T) {
|
||||||
|
runner := &MockRunner{
|
||||||
|
testDataPath: "simple.csv",
|
||||||
|
}
|
||||||
|
|
||||||
|
dr := ExecuteQuery(ctx, QueryModel{MaxDataPoints: 100}, runner, 50)
|
||||||
|
|
||||||
|
if dr.Error != nil {
|
||||||
|
t.Fatal(dr.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dr.Frames) != 1 {
|
||||||
|
t.Fatalf("Expected 1 frame, received [%d] frames", len(dr.Frames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(dr.Frames[0].Name, "test") {
|
||||||
|
t.Fatalf("Frame must match _measurement column. Expected [%s] Got [%s]", "test", dr.Frames[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dr.Frames[0].Fields[1].Labels) != 2 {
|
||||||
|
t.Fatalf("Error parsing labels. Expected [%d] Got [%d]", 2, len(dr.Frames[0].Fields[1].Labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
if dr.Frames[0].Fields[0].Name != "Time" {
|
||||||
|
t.Fatalf("Error parsing fields. Field 1 should always be time. Got name [%s]", dr.Frames[0].Fields[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, _ := dr.Frames[0].StringTable(-1, -1)
|
||||||
|
fmt.Println(st)
|
||||||
|
fmt.Println("----------------------")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteMultiple(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Multiple Test", func(t *testing.T) {
|
||||||
|
runner := &MockRunner{
|
||||||
|
testDataPath: "multiple.csv",
|
||||||
|
}
|
||||||
|
|
||||||
|
dr := ExecuteQuery(ctx, QueryModel{MaxDataPoints: 100}, runner, 50)
|
||||||
|
|
||||||
|
if dr.Error != nil {
|
||||||
|
t.Fatal(dr.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dr.Frames) != 4 {
|
||||||
|
t.Fatalf("Expected 4 frames, received [%d] frames", len(dr.Frames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(dr.Frames[0].Name, "test") {
|
||||||
|
t.Fatalf("Frame must include _measurement column. Expected [%s] Got [%s]", "test", dr.Frames[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dr.Frames[0].Fields[1].Labels) != 2 {
|
||||||
|
t.Fatalf("Error parsing labels. Expected [%d] Got [%d]", 2, len(dr.Frames[0].Fields[1].Labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
if dr.Frames[0].Fields[0].Name != "Time" {
|
||||||
|
t.Fatalf("Error parsing fields. Field 1 should always be time. Got name [%s]", dr.Frames[0].Fields[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, _ := dr.Frames[0].StringTable(-1, -1)
|
||||||
|
fmt.Println(st)
|
||||||
|
fmt.Println("----------------------")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecuteGrouping(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Grouping Test", func(t *testing.T) {
|
||||||
|
runner := &MockRunner{
|
||||||
|
testDataPath: "grouping.csv",
|
||||||
|
}
|
||||||
|
|
||||||
|
dr := ExecuteQuery(ctx, QueryModel{MaxDataPoints: 100}, runner, 50)
|
||||||
|
|
||||||
|
if dr.Error != nil {
|
||||||
|
t.Fatal(dr.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dr.Frames) != 3 {
|
||||||
|
t.Fatalf("Expected 3 frames, received [%d] frames", len(dr.Frames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(dr.Frames[0].Name, "system") {
|
||||||
|
t.Fatalf("Frame must match _measurement column. Expected [%s] Got [%s]", "test", dr.Frames[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(dr.Frames[0].Fields[1].Labels) != 1 {
|
||||||
|
t.Fatalf("Error parsing labels. Expected [%d] Got [%d]", 1, len(dr.Frames[0].Fields[1].Labels))
|
||||||
|
}
|
||||||
|
|
||||||
|
if dr.Frames[0].Fields[0].Name != "Time" {
|
||||||
|
t.Fatalf("Error parsing fields. Field 1 should always be time. Got name [%s]", dr.Frames[0].Fields[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, _ := dr.Frames[0].StringTable(-1, -1)
|
||||||
|
fmt.Println(st)
|
||||||
|
fmt.Println("----------------------")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBuckets(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Buckes", func(t *testing.T) {
|
||||||
|
runner := &MockRunner{
|
||||||
|
testDataPath: "buckets.csv",
|
||||||
|
}
|
||||||
|
|
||||||
|
dr := ExecuteQuery(ctx, QueryModel{MaxDataPoints: 100}, runner, 50)
|
||||||
|
|
||||||
|
if dr.Error != nil {
|
||||||
|
t.Fatal(dr.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, _ := dr.Frames[0].StringTable(-1, -1)
|
||||||
|
fmt.Println(st)
|
||||||
|
fmt.Println("----------------------")
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
influxdb2 "github.com/influxdata/influxdb-client-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
glog log.Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
glog = log.New("tsdb.influx_flux")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query builds flux queries, executes them, and returns the results.
|
||||||
|
func Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||||
|
tRes := &tsdb.Response{
|
||||||
|
Results: make(map[string]*tsdb.QueryResult),
|
||||||
|
}
|
||||||
|
runner, err := RunnerFromDataSource(dsInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, query := range tsdbQuery.Queries {
|
||||||
|
|
||||||
|
qm, err := GetQueryModelTSDB(query, tsdbQuery.TimeRange, dsInfo)
|
||||||
|
if err != nil {
|
||||||
|
tRes.Results[query.RefId] = &tsdb.QueryResult{Error: err}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
res := ExecuteQuery(context.Background(), *qm, runner, 10)
|
||||||
|
|
||||||
|
tRes.Results[query.RefId] = backendDataResponseToTSDBResponse(&res, query.RefId)
|
||||||
|
}
|
||||||
|
return tRes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runner is an influxdb2 Client with an attached org property and is used
|
||||||
|
// for running flux queries.
|
||||||
|
type Runner struct {
|
||||||
|
client influxdb2.Client
|
||||||
|
org string
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an interface to help testing
|
||||||
|
type queryRunner interface {
|
||||||
|
runQuery(ctx context.Context, q string) (*influxdb2.QueryTableResult, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// runQuery executes fluxQuery against the Runner's organization and returns an flux typed result.
|
||||||
|
func (r *Runner) runQuery(ctx context.Context, fluxQuery string) (*influxdb2.QueryTableResult, error) {
|
||||||
|
return r.client.QueryApi(r.org).Query(ctx, fluxQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunnerFromDataSource creates a runner from the datasource model (the datasource instance's configuration).
|
||||||
|
func RunnerFromDataSource(dsInfo *models.DataSource) (*Runner, error) {
|
||||||
|
org := dsInfo.JsonData.Get("organization").MustString("")
|
||||||
|
if org == "" {
|
||||||
|
return nil, fmt.Errorf("missing organization in datasource configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
url := dsInfo.Url
|
||||||
|
if url == "" {
|
||||||
|
return nil, fmt.Errorf("missing url from datasource configuration")
|
||||||
|
}
|
||||||
|
token, found := dsInfo.SecureJsonData.DecryptedValue("token")
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("token is missing from datasource configuration and is needed to use Flux")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Runner{
|
||||||
|
client: influxdb2.NewClient(url, token),
|
||||||
|
org: org,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// backendDataResponseToTSDBResponse takes the SDK's style response and changes it into a
|
||||||
|
// tsdb.QueryResult. This is a wrapper so less of existing code needs to be changed. This should
|
||||||
|
// be able to be removed in the near future https://github.com/grafana/grafana/pull/25472.
|
||||||
|
func backendDataResponseToTSDBResponse(dr *backend.DataResponse, refID string) *tsdb.QueryResult {
|
||||||
|
qr := &tsdb.QueryResult{RefId: refID}
|
||||||
|
|
||||||
|
if dr.Error != nil {
|
||||||
|
qr.Error = dr.Error
|
||||||
|
return qr
|
||||||
|
}
|
||||||
|
|
||||||
|
if dr.Frames != nil {
|
||||||
|
qr.Dataframes = tsdb.NewDecodedDataFrames(dr.Frames)
|
||||||
|
}
|
||||||
|
return qr
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
const variableFilter = `(?m)([a-zA-Z]+)\.([a-zA-Z]+)`
|
||||||
|
|
||||||
|
// Interpolate processes macros
|
||||||
|
func Interpolate(query QueryModel) (string, error) {
|
||||||
|
|
||||||
|
flux := query.RawQuery
|
||||||
|
|
||||||
|
variableFilterExp, err := regexp.Compile(variableFilter)
|
||||||
|
matches := variableFilterExp.FindAllStringSubmatch(flux, -1)
|
||||||
|
if matches != nil {
|
||||||
|
timeRange := query.TimeRange
|
||||||
|
from := timeRange.From.UTC().Format(time.RFC3339)
|
||||||
|
to := timeRange.To.UTC().Format(time.RFC3339)
|
||||||
|
for _, match := range matches {
|
||||||
|
switch match[2] {
|
||||||
|
case "timeRangeStart":
|
||||||
|
flux = strings.ReplaceAll(flux, match[0], from)
|
||||||
|
case "timeRangeStop":
|
||||||
|
flux = strings.ReplaceAll(flux, match[0], to)
|
||||||
|
case "windowPeriod":
|
||||||
|
flux = strings.ReplaceAll(flux, match[0], query.Interval.String())
|
||||||
|
case "bucket":
|
||||||
|
flux = strings.ReplaceAll(flux, match[0], "\""+query.Options.Bucket+"\"")
|
||||||
|
case "defaultBucket":
|
||||||
|
flux = strings.ReplaceAll(flux, match[0], "\""+query.Options.DefaultBucket+"\"")
|
||||||
|
case "organization":
|
||||||
|
flux = strings.ReplaceAll(flux, match[0], "\""+query.Options.Organization+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
backend.Logger.Info(fmt.Sprintf("%s => %v", flux, query.Options))
|
||||||
|
return flux, err
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInterpolate(t *testing.T) {
|
||||||
|
// Unix sec: 1500376552
|
||||||
|
// Unix ms: 1500376552001
|
||||||
|
|
||||||
|
timeRange := backend.TimeRange{
|
||||||
|
From: time.Unix(0, 0),
|
||||||
|
To: time.Unix(0, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
options := QueryOptions{
|
||||||
|
Organization: "grafana1",
|
||||||
|
Bucket: "grafana2",
|
||||||
|
DefaultBucket: "grafana3",
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
before string
|
||||||
|
after string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "interpolate flux variables",
|
||||||
|
before: `v.timeRangeStart, something.timeRangeStop, XYZ.bucket, uuUUu.defaultBucket, aBcDefG.organization, window.windowPeriod, a91{}.bucket`,
|
||||||
|
after: `1970-01-01T00:00:00Z, 1970-01-01T00:00:00Z, "grafana2", "grafana3", "grafana1", 1s, a91{}.bucket`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
||||||
|
query := QueryModel{
|
||||||
|
RawQuery: tt.before,
|
||||||
|
Options: options,
|
||||||
|
TimeRange: timeRange,
|
||||||
|
MaxDataPoints: 1,
|
||||||
|
Interval: 1000 * 1000 * 1000,
|
||||||
|
}
|
||||||
|
interpolatedQuery, err := Interpolate(query)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(tt.after, interpolatedQuery); diff != "" {
|
||||||
|
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package flux
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QueryOptions represents datasource configuration options
|
||||||
|
type QueryOptions struct {
|
||||||
|
Bucket string `json:"bucket"`
|
||||||
|
DefaultBucket string `json:"defaultBucket"`
|
||||||
|
Organization string `json:"organization"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryModel represents a spreadsheet query.
|
||||||
|
type QueryModel struct {
|
||||||
|
RawQuery string `json:"query"`
|
||||||
|
Options QueryOptions `json:"options"`
|
||||||
|
|
||||||
|
// Not from JSON
|
||||||
|
TimeRange backend.TimeRange `json:"-"`
|
||||||
|
MaxDataPoints int64 `json:"-"`
|
||||||
|
Interval time.Duration `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following is commented out but kept as it should be useful when
|
||||||
|
// restoring this code to be closer to the SDK's models.
|
||||||
|
|
||||||
|
// func GetQueryModel(query backend.DataQuery) (*QueryModel, error) {
|
||||||
|
// model := &QueryModel{}
|
||||||
|
|
||||||
|
// err := json.Unmarshal(query.JSON, &model)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, fmt.Errorf("error reading query: %s", err.Error())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Copy directly from the well typed query
|
||||||
|
// model.TimeRange = query.TimeRange
|
||||||
|
// model.MaxDataPoints = query.MaxDataPoints
|
||||||
|
// model.Interval = query.Interval
|
||||||
|
// return model, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// GetQueryModelTSDB builds a QueryModel from tsdb.Query information and datasource configuration (dsInfo).
|
||||||
|
func GetQueryModelTSDB(query *tsdb.Query, timeRange *tsdb.TimeRange, dsInfo *models.DataSource) (*QueryModel, error) {
|
||||||
|
model := &QueryModel{}
|
||||||
|
queryBytes, err := query.Model.Encode()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to re-encode the flux query into JSON: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(queryBytes, &model)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading query: %s", err.Error())
|
||||||
|
}
|
||||||
|
if model.Options.DefaultBucket == "" {
|
||||||
|
model.Options.DefaultBucket = dsInfo.JsonData.Get("defaultBucket").MustString("")
|
||||||
|
}
|
||||||
|
if model.Options.Bucket == "" {
|
||||||
|
model.Options.Bucket = model.Options.DefaultBucket
|
||||||
|
}
|
||||||
|
if model.Options.Organization == "" {
|
||||||
|
model.Options.Organization = dsInfo.JsonData.Get("organization").MustString("")
|
||||||
|
}
|
||||||
|
startTime, err := timeRange.ParseFrom()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endTime, err := timeRange.ParseTo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy directly from the well typed query
|
||||||
|
model.TimeRange = backend.TimeRange{
|
||||||
|
From: startTime,
|
||||||
|
To: endTime,
|
||||||
|
}
|
||||||
|
model.MaxDataPoints = query.MaxDataPoints
|
||||||
|
model.Interval = time.Millisecond * time.Duration(query.IntervalMs)
|
||||||
|
return model, nil
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
#datatype,string,long,string,string,string,string,long
|
||||||
|
#group,false,false,false,false,true,false,false
|
||||||
|
#default,_result,,,,,,
|
||||||
|
,result,table,name,id,organizationID,retentionPolicy,retentionPeriod
|
||||||
|
,,0,grafana,059b46a59abab001,059b46a59abab000,,604800000000000
|
||||||
|
,,0,_tasks,059b46a59abab002,059b46a59abab000,,259200000000000
|
||||||
|
,,0,_monitoring,059b46a59abab003,059b46a59abab000,,604800000000000
|
||||||
|
+21
@@ -0,0 +1,21 @@
|
|||||||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,double,dateTime:RFC3339
|
||||||
|
#group,false,false,true,true,true,true,true,false,false
|
||||||
|
#default,mean,,,,,,,,
|
||||||
|
,result,table,_start,_stop,_field,_measurement,host,_value,_time
|
||||||
|
,,0,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load1,system,hostname,,2020-05-05T18:38:50Z
|
||||||
|
,,0,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load1,system,hostname,3.56,2020-05-05T18:39:00Z
|
||||||
|
,,0,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load1,system,hostname,,2020-05-05T19:38:47.207881833Z
|
||||||
|
,,1,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load15,system,hostname,,2020-05-05T18:38:50Z
|
||||||
|
,,1,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load15,system,hostname,2.51,2020-05-05T18:39:00Z
|
||||||
|
,,1,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load15,system,hostname,1.74,2020-05-05T19:38:40Z
|
||||||
|
,,1,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load15,system,hostname,,2020-05-05T19:38:47.207881833Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,,2020-05-05T18:38:50Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,3.14,2020-05-05T18:39:00Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,3.04,2020-05-05T18:39:10Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,1.8,2020-05-05T19:37:50Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,1.76,2020-05-05T19:38:00Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,1.75,2020-05-05T19:38:10Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,1.71,2020-05-05T19:38:20Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,1.77,2020-05-05T19:38:30Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,1.71,2020-05-05T19:38:40Z
|
||||||
|
,,2,2020-05-05T18:38:47.207881833Z,2020-05-05T19:38:47.207881833Z,load5,system,hostname,,2020-05-05T19:38:47.207881833Z
|
||||||
|
+25
@@ -0,0 +1,25 @@
|
|||||||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||||||
|
#group,false,false,true,true,false,false,true,true,true,true
|
||||||
|
#default,_result,,,,,,,,,
|
||||||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||||||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,1.4,f,test,1,adsfasdf
|
||||||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,6.6,f,test,1,adsfasdf
|
||||||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,string,string,string
|
||||||
|
#group,false,false,true,true,false,false,true,true,true,true
|
||||||
|
#default,_result,,,,,,,,,
|
||||||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||||||
|
,,1,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,4,i,test,1,adsfasdf
|
||||||
|
,,1,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,-1,i,test,1,adsfasdf
|
||||||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,bool,string,string,string,string
|
||||||
|
#group,false,false,true,true,false,false,true,true,true,true
|
||||||
|
#default,_result,,,,,,,,,
|
||||||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||||||
|
,,2,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.62797864Z,false,f,test,0,adsfasdf
|
||||||
|
,,2,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.969100374Z,true,f,test,0,adsfasdf
|
||||||
|
#datatype,string,long,dateTime:RFC3339Nano,dateTime:RFC3339Nano,dateTime:RFC3339Nano,unsignedLong,string,string,string,string
|
||||||
|
#group,false,false,true,true,false,false,true,true,true,true
|
||||||
|
#default,_result,,,,,,,,,
|
||||||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||||||
|
,,3,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.62797864Z,0,i,test,0,adsfasdf
|
||||||
|
,,3,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.969100374Z,2,i,test,0,adsfasdf
|
||||||
|
|
||||||
|
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
|
||||||
|
#group,false,false,true,true,false,false,true,true,true,true
|
||||||
|
#default,_result,,,,,,,,,
|
||||||
|
,result,table,_start,_stop,_time,_value,_field,_measurement,a,b
|
||||||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T10:34:08.135814545Z,1.4,f,test,1,adsfasdf
|
||||||
|
,,0,2020-02-17T22:19:49.747562847Z,2020-02-18T22:19:49.747562847Z,2020-02-18T22:08:44.850214724Z,6.6,f,test,1,adsfasdf
|
||||||
|
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/tsdb"
|
"github.com/grafana/grafana/pkg/tsdb"
|
||||||
|
"github.com/grafana/grafana/pkg/tsdb/influxdb/flux"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -42,8 +43,35 @@ func init() {
|
|||||||
tsdb.RegisterTsdbQueryEndpoint("influxdb", NewInfluxDBExecutor)
|
tsdb.RegisterTsdbQueryEndpoint("influxdb", NewInfluxDBExecutor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AllFlux(queries *tsdb.TsdbQuery) (bool, error) {
|
||||||
|
var hasFlux bool
|
||||||
|
var allFlux bool
|
||||||
|
for i, q := range queries.Queries {
|
||||||
|
qType := q.Model.Get("queryType").MustString("")
|
||||||
|
if qType == "Flux" {
|
||||||
|
hasFlux = true
|
||||||
|
if i == 0 && hasFlux {
|
||||||
|
allFlux = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allFlux && qType != "Flux" {
|
||||||
|
return true, fmt.Errorf("when using flux, all queries must be a flux query")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allFlux, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *InfluxDBExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
func (e *InfluxDBExecutor) Query(ctx context.Context, dsInfo *models.DataSource, tsdbQuery *tsdb.TsdbQuery) (*tsdb.Response, error) {
|
||||||
result := &tsdb.Response{}
|
result := &tsdb.Response{}
|
||||||
|
allFlux, err := AllFlux(tsdbQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if allFlux {
|
||||||
|
return flux.Query(ctx, dsInfo, tsdbQuery)
|
||||||
|
}
|
||||||
|
|
||||||
query, err := e.getQuery(dsInfo, tsdbQuery.Queries, tsdbQuery)
|
query, err := e.getQuery(dsInfo, tsdbQuery.Queries, tsdbQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -24,6 +24,21 @@ export class ConfigEditor extends PureComponent<Props> {
|
|||||||
updateDatasourcePluginResetOption(this.props, 'password');
|
updateDatasourcePluginResetOption(this.props, 'password');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onResetToken = () => {
|
||||||
|
updateDatasourcePluginResetOption(this.props, 'token');
|
||||||
|
};
|
||||||
|
|
||||||
|
onToggleFlux = (event: React.SyntheticEvent<HTMLInputElement>) => {
|
||||||
|
const { options, onOptionsChange } = this.props;
|
||||||
|
onOptionsChange({
|
||||||
|
...options,
|
||||||
|
jsonData: {
|
||||||
|
...options.jsonData,
|
||||||
|
enableFlux: !options.jsonData.enableFlux,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { options, onOptionsChange } = this.props;
|
const { options, onOptionsChange } = this.props;
|
||||||
const { secureJsonFields } = options;
|
const { secureJsonFields } = options;
|
||||||
@@ -39,6 +54,50 @@ export class ConfigEditor extends PureComponent<Props> {
|
|||||||
|
|
||||||
<h3 className="page-heading">InfluxDB Details</h3>
|
<h3 className="page-heading">InfluxDB Details</h3>
|
||||||
<div className="gf-form-group">
|
<div className="gf-form-group">
|
||||||
|
<div className="gf-form-inline">
|
||||||
|
<LegacyForms.Switch
|
||||||
|
label="Enable flux"
|
||||||
|
labelClass="width-10"
|
||||||
|
checked={options.jsonData.enableFlux || false}
|
||||||
|
onChange={this.onToggleFlux}
|
||||||
|
tooltip="Suport flux query endpoint"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{options.jsonData.enableFlux && (
|
||||||
|
<>
|
||||||
|
<div className="gf-form-inline">
|
||||||
|
<div className="gf-form">
|
||||||
|
<InlineFormLabel className="width-10">Organization</InlineFormLabel>
|
||||||
|
<div className="width-10">
|
||||||
|
<Input
|
||||||
|
className="width-10"
|
||||||
|
placeholder="enter organization"
|
||||||
|
value={options.jsonData.organization || ''}
|
||||||
|
onChange={onUpdateDatasourceJsonDataOption(this.props, 'organization')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="gf-form-inline">
|
||||||
|
<div className="gf-form">
|
||||||
|
<InlineFormLabel className="width-10">Default Bucket</InlineFormLabel>
|
||||||
|
<div className="width-10">
|
||||||
|
<Input
|
||||||
|
className="width-10"
|
||||||
|
placeholder="default bucket"
|
||||||
|
value={options.jsonData.defaultBucket || ''}
|
||||||
|
onChange={onUpdateDatasourceJsonDataOption(this.props, 'defaultBucket')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="gf-form-inline">
|
<div className="gf-form-inline">
|
||||||
<div className="gf-form">
|
<div className="gf-form">
|
||||||
<InlineFormLabel className="width-10">Database</InlineFormLabel>
|
<InlineFormLabel className="width-10">Database</InlineFormLabel>
|
||||||
@@ -76,6 +135,19 @@ export class ConfigEditor extends PureComponent<Props> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="gf-form-inline">
|
||||||
|
<div className="gf-form">
|
||||||
|
<SecretFormField
|
||||||
|
isConfigured={(secureJsonFields && secureJsonFields.token) as boolean}
|
||||||
|
value={secureJsonData.token || ''}
|
||||||
|
label="Token"
|
||||||
|
labelWidth={10}
|
||||||
|
inputWidth={20}
|
||||||
|
onReset={this.onResetPassword}
|
||||||
|
onChange={onUpdateDatasourceSecureJsonDataOption(this.props, 'token')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div className="gf-form-inline">
|
<div className="gf-form-inline">
|
||||||
<div className="gf-form">
|
<div className="gf-form">
|
||||||
<InlineFormLabel
|
<InlineFormLabel
|
||||||
|
|||||||
+108
@@ -41,6 +41,17 @@ exports[`Render should disable basic auth password input 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="gf-form-group"
|
className="gf-form-group"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
checked={false}
|
||||||
|
label="Enable flux"
|
||||||
|
labelClass="width-10"
|
||||||
|
onChange={[Function]}
|
||||||
|
tooltip="Suport flux query endpoint"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -101,6 +112,22 @@ exports[`Render should disable basic auth password input 1`] = `
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form"
|
||||||
|
>
|
||||||
|
<SecretFormField
|
||||||
|
inputWidth={20}
|
||||||
|
label="Token"
|
||||||
|
labelWidth={10}
|
||||||
|
onChange={[Function]}
|
||||||
|
onReset={[Function]}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -258,6 +285,17 @@ exports[`Render should hide basic auth fields when switch off 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="gf-form-group"
|
className="gf-form-group"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
checked={false}
|
||||||
|
label="Enable flux"
|
||||||
|
labelClass="width-10"
|
||||||
|
onChange={[Function]}
|
||||||
|
tooltip="Suport flux query endpoint"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -318,6 +356,22 @@ exports[`Render should hide basic auth fields when switch off 1`] = `
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form"
|
||||||
|
>
|
||||||
|
<SecretFormField
|
||||||
|
inputWidth={20}
|
||||||
|
label="Token"
|
||||||
|
labelWidth={10}
|
||||||
|
onChange={[Function]}
|
||||||
|
onReset={[Function]}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -475,6 +529,17 @@ exports[`Render should hide white listed cookies input when browser access chose
|
|||||||
<div
|
<div
|
||||||
className="gf-form-group"
|
className="gf-form-group"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
checked={false}
|
||||||
|
label="Enable flux"
|
||||||
|
labelClass="width-10"
|
||||||
|
onChange={[Function]}
|
||||||
|
tooltip="Suport flux query endpoint"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -535,6 +600,22 @@ exports[`Render should hide white listed cookies input when browser access chose
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form"
|
||||||
|
>
|
||||||
|
<SecretFormField
|
||||||
|
inputWidth={20}
|
||||||
|
label="Token"
|
||||||
|
labelWidth={10}
|
||||||
|
onChange={[Function]}
|
||||||
|
onReset={[Function]}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -692,6 +773,17 @@ exports[`Render should render component 1`] = `
|
|||||||
<div
|
<div
|
||||||
className="gf-form-group"
|
className="gf-form-group"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
checked={false}
|
||||||
|
label="Enable flux"
|
||||||
|
labelClass="width-10"
|
||||||
|
onChange={[Function]}
|
||||||
|
tooltip="Suport flux query endpoint"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
@@ -752,6 +844,22 @@ exports[`Render should render component 1`] = `
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className="gf-form-inline"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="gf-form"
|
||||||
|
>
|
||||||
|
<SecretFormField
|
||||||
|
inputWidth={20}
|
||||||
|
label="Token"
|
||||||
|
labelWidth={10}
|
||||||
|
onChange={[Function]}
|
||||||
|
onReset={[Function]}
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="gf-form-inline"
|
className="gf-form-inline"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import { dateMath, DataSourceApi, DataSourceInstanceSettings, ScopedVars } from '@grafana/data';
|
import { dateMath, DataSourceInstanceSettings, ScopedVars, DataQueryRequest, DataQueryResponse } from '@grafana/data';
|
||||||
import InfluxSeries from './influx_series';
|
import InfluxSeries from './influx_series';
|
||||||
import InfluxQueryModel from './influx_query_model';
|
import InfluxQueryModel from './influx_query_model';
|
||||||
import ResponseParser from './response_parser';
|
import ResponseParser from './response_parser';
|
||||||
import { InfluxQueryBuilder } from './query_builder';
|
import { InfluxQueryBuilder } from './query_builder';
|
||||||
import { InfluxQuery, InfluxOptions } from './types';
|
import { InfluxQuery, InfluxOptions, InfluxQueryType } from './types';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv, getTemplateSrv, DataSourceWithBackend } from '@grafana/runtime';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { Observable, from } from 'rxjs';
|
||||||
|
|
||||||
export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxOptions> {
|
export default class InfluxDatasource extends DataSourceWithBackend<InfluxQuery, InfluxOptions> {
|
||||||
type: string;
|
type: string;
|
||||||
urls: any;
|
urls: string[];
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -21,17 +21,17 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
interval: any;
|
interval: any;
|
||||||
responseParser: any;
|
responseParser: any;
|
||||||
httpMode: string;
|
httpMode: string;
|
||||||
|
enableFlux: boolean;
|
||||||
|
|
||||||
/** @ngInject */
|
constructor(instanceSettings: DataSourceInstanceSettings<InfluxOptions>) {
|
||||||
constructor(instanceSettings: DataSourceInstanceSettings<InfluxOptions>, private templateSrv: TemplateSrv) {
|
|
||||||
super(instanceSettings);
|
super(instanceSettings);
|
||||||
this.type = 'influxdb';
|
this.type = 'influxdb';
|
||||||
this.urls = _.map(instanceSettings.url.split(','), url => {
|
this.urls = _.map(instanceSettings.url.split(','), url => {
|
||||||
return url.trim();
|
return url.trim();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.username = instanceSettings.username;
|
this.username = instanceSettings.username ?? '';
|
||||||
this.password = instanceSettings.password;
|
this.password = instanceSettings.password ?? '';
|
||||||
this.name = instanceSettings.name;
|
this.name = instanceSettings.name;
|
||||||
this.database = instanceSettings.database;
|
this.database = instanceSettings.database;
|
||||||
this.basicAuth = instanceSettings.basicAuth;
|
this.basicAuth = instanceSettings.basicAuth;
|
||||||
@@ -40,15 +40,69 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
this.interval = settingsData.timeInterval;
|
this.interval = settingsData.timeInterval;
|
||||||
this.httpMode = settingsData.httpMode || 'GET';
|
this.httpMode = settingsData.httpMode || 'GET';
|
||||||
this.responseParser = new ResponseParser();
|
this.responseParser = new ResponseParser();
|
||||||
|
this.enableFlux = !!settingsData.enableFlux;
|
||||||
}
|
}
|
||||||
|
|
||||||
query(options: any) {
|
query(request: DataQueryRequest<InfluxQuery>): Observable<DataQueryResponse> {
|
||||||
|
let hasFlux = false;
|
||||||
|
let allFlux = true;
|
||||||
|
|
||||||
|
// Update the queryType fields and manage migrations
|
||||||
|
for (const target of request.targets) {
|
||||||
|
if (target.queryType === InfluxQueryType.Flux) {
|
||||||
|
hasFlux = true;
|
||||||
|
} else {
|
||||||
|
allFlux = false;
|
||||||
|
if (target.queryType === InfluxQueryType.Classic) {
|
||||||
|
delete target.rawQuery;
|
||||||
|
} else if (target.rawQuery) {
|
||||||
|
target.queryType = InfluxQueryType.InfluxQL;
|
||||||
|
} else if (target.queryType === InfluxQueryType.InfluxQL) {
|
||||||
|
target.rawQuery = true; // so the old version works
|
||||||
|
} else {
|
||||||
|
target.queryType = InfluxQueryType.Classic; // Explicitly set it to classic
|
||||||
|
delete target.rawQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proces flux queries (data frame request)
|
||||||
|
if (hasFlux) {
|
||||||
|
if (!this.enableFlux) {
|
||||||
|
throw 'Flux not enabled for this datasource';
|
||||||
|
}
|
||||||
|
if (!allFlux) {
|
||||||
|
throw 'All queries must be flux';
|
||||||
|
}
|
||||||
|
// Calls /api/tsdb/query
|
||||||
|
return super.query(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to classic query support
|
||||||
|
return from(this.classicQuery(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only applied on flux queries
|
||||||
|
*/
|
||||||
|
applyTemplateVariables(query: InfluxQuery, scopedVars: ScopedVars): Record<string, any> {
|
||||||
|
return {
|
||||||
|
...query,
|
||||||
|
query: getTemplateSrv().replace(query.query, scopedVars), // The raw query text
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unchanged pre 7.1 query implementation
|
||||||
|
*/
|
||||||
|
async classicQuery(options: any): Promise<DataQueryResponse> {
|
||||||
let timeFilter = this.getTimeFilter(options);
|
let timeFilter = this.getTimeFilter(options);
|
||||||
const scopedVars = options.scopedVars;
|
const scopedVars = options.scopedVars;
|
||||||
const targets = _.cloneDeep(options.targets);
|
const targets = _.cloneDeep(options.targets);
|
||||||
const queryTargets: any[] = [];
|
const queryTargets: any[] = [];
|
||||||
let queryModel: InfluxQueryModel;
|
let queryModel: InfluxQueryModel;
|
||||||
let i, y;
|
let i, y;
|
||||||
|
const templateSrv = getTemplateSrv();
|
||||||
|
|
||||||
let allQueries = _.map(targets, target => {
|
let allQueries = _.map(targets, target => {
|
||||||
if (target.hide) {
|
if (target.hide) {
|
||||||
@@ -60,7 +114,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
// backward compatibility
|
// backward compatibility
|
||||||
scopedVars.interval = scopedVars.__interval;
|
scopedVars.interval = scopedVars.__interval;
|
||||||
|
|
||||||
queryModel = new InfluxQueryModel(target, this.templateSrv, scopedVars);
|
queryModel = new InfluxQueryModel(target, templateSrv, scopedVars);
|
||||||
return queryModel.render(true);
|
return queryModel.render(true);
|
||||||
}).reduce((acc, current) => {
|
}).reduce((acc, current) => {
|
||||||
if (current !== '') {
|
if (current !== '') {
|
||||||
@@ -74,7 +128,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add global adhoc filters to timeFilter
|
// add global adhoc filters to timeFilter
|
||||||
const adhocFilters = this.templateSrv.getAdhocFilters(this.name);
|
const adhocFilters = (templateSrv as any).getAdhocFilters(this.name);
|
||||||
if (adhocFilters.length > 0) {
|
if (adhocFilters.length > 0) {
|
||||||
timeFilter += ' AND ' + queryModel.renderAdhocFilters(adhocFilters);
|
timeFilter += ' AND ' + queryModel.renderAdhocFilters(adhocFilters);
|
||||||
}
|
}
|
||||||
@@ -83,7 +137,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
scopedVars.timeFilter = { value: timeFilter };
|
scopedVars.timeFilter = { value: timeFilter };
|
||||||
|
|
||||||
// replace templated variables
|
// replace templated variables
|
||||||
allQueries = this.templateSrv.replace(allQueries, scopedVars);
|
allQueries = templateSrv.replace(allQueries, scopedVars);
|
||||||
|
|
||||||
return this._seriesQuery(allQueries, options).then((data: any): any => {
|
return this._seriesQuery(allQueries, options).then((data: any): any => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
@@ -100,7 +154,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
const target = queryTargets[i];
|
const target = queryTargets[i];
|
||||||
let alias = target.alias;
|
let alias = target.alias;
|
||||||
if (alias) {
|
if (alias) {
|
||||||
alias = this.templateSrv.replace(target.alias, options.scopedVars);
|
alias = templateSrv.replace(target.alias, options.scopedVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
const influxSeries = new InfluxSeries({
|
const influxSeries = new InfluxSeries({
|
||||||
@@ -136,7 +190,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
|
|
||||||
const timeFilter = this.getTimeFilter({ rangeRaw: options.rangeRaw, timezone: options.timezone });
|
const timeFilter = this.getTimeFilter({ rangeRaw: options.rangeRaw, timezone: options.timezone });
|
||||||
let query = options.annotation.query.replace('$timeFilter', timeFilter);
|
let query = options.annotation.query.replace('$timeFilter', timeFilter);
|
||||||
query = this.templateSrv.replace(query, null, 'regex');
|
query = getTemplateSrv().replace(query, null, 'regex');
|
||||||
|
|
||||||
return this._seriesQuery(query, options).then((data: any) => {
|
return this._seriesQuery(query, options).then((data: any) => {
|
||||||
if (!data || !data.results || !data.results[0]) {
|
if (!data || !data.results || !data.results[0]) {
|
||||||
@@ -150,16 +204,18 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
}
|
}
|
||||||
|
|
||||||
targetContainsTemplate(target: any) {
|
targetContainsTemplate(target: any) {
|
||||||
|
const templateSrv = getTemplateSrv() as any; // :(
|
||||||
|
|
||||||
for (const group of target.groupBy) {
|
for (const group of target.groupBy) {
|
||||||
for (const param of group.params) {
|
for (const param of group.params) {
|
||||||
if (this.templateSrv.variableExists(param)) {
|
if (templateSrv.variableExists(param)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const i in target.tags) {
|
for (const i in target.tags) {
|
||||||
if (this.templateSrv.variableExists(target.tags[i].value)) {
|
if (templateSrv.variableExists(target.tags[i].value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,23 +230,25 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
|
|
||||||
let expandedQueries = queries;
|
let expandedQueries = queries;
|
||||||
if (queries && queries.length > 0) {
|
if (queries && queries.length > 0) {
|
||||||
|
const templateSrv = getTemplateSrv();
|
||||||
|
|
||||||
expandedQueries = queries.map(query => {
|
expandedQueries = queries.map(query => {
|
||||||
const expandedQuery = {
|
const expandedQuery = {
|
||||||
...query,
|
...query,
|
||||||
datasource: this.name,
|
datasource: this.name,
|
||||||
measurement: this.templateSrv.replace(query.measurement, scopedVars, 'regex'),
|
measurement: templateSrv.replace(query.measurement ?? '', scopedVars, 'regex'),
|
||||||
policy: this.templateSrv.replace(query.policy, scopedVars, 'regex'),
|
policy: templateSrv.replace(query.policy ?? '', scopedVars, 'regex'),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (query.rawQuery) {
|
if (query.rawQuery) {
|
||||||
expandedQuery.query = this.templateSrv.replace(query.query, scopedVars, 'regex');
|
expandedQuery.query = templateSrv.replace(query.query ?? '', scopedVars, 'regex');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.tags) {
|
if (query.tags) {
|
||||||
const expandedTags = query.tags.map(tag => {
|
const expandedTags = query.tags.map(tag => {
|
||||||
const expandedTag = {
|
const expandedTag = {
|
||||||
...tag,
|
...tag,
|
||||||
value: this.templateSrv.replace(tag.value, null, 'regex'),
|
value: templateSrv.replace(tag.value, null, 'regex'),
|
||||||
};
|
};
|
||||||
return expandedTag;
|
return expandedTag;
|
||||||
});
|
});
|
||||||
@@ -203,7 +261,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
}
|
}
|
||||||
|
|
||||||
metricFindQuery(query: string, options?: any) {
|
metricFindQuery(query: string, options?: any) {
|
||||||
const interpolated = this.templateSrv.replace(query, null, 'regex');
|
const interpolated = getTemplateSrv().replace(query, null, 'regex');
|
||||||
|
|
||||||
return this._seriesQuery(interpolated, options).then(resp => {
|
return this._seriesQuery(interpolated, options).then(resp => {
|
||||||
return this.responseParser.parse(query, resp);
|
return this.responseParser.parse(query, resp);
|
||||||
@@ -253,6 +311,7 @@ export default class InfluxDatasource extends DataSourceApi<InfluxQuery, InfluxO
|
|||||||
).join('&');
|
).join('&');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove this so that everything gets sent to /healthcheck!
|
||||||
testDatasource() {
|
testDatasource() {
|
||||||
const queryBuilder = new InfluxQueryBuilder({ measurement: '', tags: [] }, this.database);
|
const queryBuilder = new InfluxQueryBuilder({ measurement: '', tags: [] }, this.database);
|
||||||
const query = queryBuilder.buildExploreQuery('RETENTION POLICIES');
|
const query = queryBuilder.buildExploreQuery('RETENTION POLICIES');
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import queryPart from './query_part';
|
|||||||
import kbn from 'app/core/utils/kbn';
|
import kbn from 'app/core/utils/kbn';
|
||||||
import { InfluxQuery, InfluxQueryTag } from './types';
|
import { InfluxQuery, InfluxQueryTag } from './types';
|
||||||
import { ScopedVars } from '@grafana/data';
|
import { ScopedVars } from '@grafana/data';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from '@grafana/runtime';
|
||||||
|
|
||||||
export default class InfluxQueryModel {
|
export default class InfluxQueryModel {
|
||||||
target: InfluxQuery;
|
target: InfluxQuery;
|
||||||
|
|||||||
@@ -1,5 +1,37 @@
|
|||||||
<query-editor-row query-ctrl="ctrl" can-collapse="true" has-text-edit-mode="true">
|
<query-editor-row query-ctrl="ctrl" can-collapse="true" has-text-edit-mode="true">
|
||||||
<div ng-if="ctrl.target.rawQuery">
|
<div ng-if="ctrl.datasource.enableFlux" class="gf-form-inline">
|
||||||
|
<div class="gf-form">
|
||||||
|
<label class="gf-form-label query-keyword width-7">QUERY</label>
|
||||||
|
<div class="gf-form-select-wrapper">
|
||||||
|
<select
|
||||||
|
class="gf-form-input gf-size-auto"
|
||||||
|
ng-model="ctrl.target.queryType"
|
||||||
|
ng-options="f.value as f.text for f in ctrl.queryTypes"
|
||||||
|
ng-change="ctrl.refresh()"
|
||||||
|
></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="gf-form gf-form--grow">
|
||||||
|
<div class="gf-form-label gf-form-label--grow"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- TODO use monaco flux editor -->
|
||||||
|
<div ng-if="ctrl.target.queryType === 'Flux'">
|
||||||
|
<div class="gf-form">
|
||||||
|
<textarea
|
||||||
|
rows="3"
|
||||||
|
class="gf-form-input"
|
||||||
|
ng-model="ctrl.target.query"
|
||||||
|
spellcheck="false"
|
||||||
|
placeholder="Flux Query"
|
||||||
|
ng-model-onblur
|
||||||
|
ng-change="ctrl.refresh()"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="ctrl.target.queryType === 'InfluxQL' || !ctrl.target.queryType">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<textarea
|
<textarea
|
||||||
rows="3"
|
rows="3"
|
||||||
@@ -40,7 +72,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="!ctrl.target.rawQuery">
|
<div ng-if="ctrl.target.queryType === 'Classic'">
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<label class="gf-form-label query-keyword width-7">FROM</label>
|
<label class="gf-form-label query-keyword width-7">FROM</label>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import InfluxQueryModel from './influx_query_model';
|
|||||||
import queryPart from './query_part';
|
import queryPart from './query_part';
|
||||||
import { QueryCtrl } from 'app/plugins/sdk';
|
import { QueryCtrl } from 'app/plugins/sdk';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
|
import { InfluxQueryType } from './types';
|
||||||
|
|
||||||
export class InfluxQueryCtrl extends QueryCtrl {
|
export class InfluxQueryCtrl extends QueryCtrl {
|
||||||
static templateUrl = 'partials/query.editor.html';
|
static templateUrl = 'partials/query.editor.html';
|
||||||
@@ -13,6 +14,7 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
|||||||
queryBuilder: any;
|
queryBuilder: any;
|
||||||
groupBySegment: any;
|
groupBySegment: any;
|
||||||
resultFormats: any[];
|
resultFormats: any[];
|
||||||
|
queryTypes: any[];
|
||||||
orderByTime: any[];
|
orderByTime: any[];
|
||||||
policySegment: any;
|
policySegment: any;
|
||||||
tagSegments: any[];
|
tagSegments: any[];
|
||||||
@@ -36,6 +38,16 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
|||||||
{ text: 'Time series', value: 'time_series' },
|
{ text: 'Time series', value: 'time_series' },
|
||||||
{ text: 'Table', value: 'table' },
|
{ text: 'Table', value: 'table' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Show a dropdown for flux
|
||||||
|
if (this.datasource.enableFlux) {
|
||||||
|
this.queryTypes = [
|
||||||
|
{ text: 'Classic', value: InfluxQueryType.Classic },
|
||||||
|
{ text: 'InfluxQL', value: InfluxQueryType.InfluxQL },
|
||||||
|
{ text: 'Flux', value: InfluxQueryType.Flux },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
this.policySegment = uiSegmentSrv.newSegment(this.target.policy);
|
this.policySegment = uiSegmentSrv.newSegment(this.target.policy);
|
||||||
|
|
||||||
if (!this.target.measurement) {
|
if (!this.target.measurement) {
|
||||||
@@ -236,12 +248,21 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleEditorMode() {
|
toggleEditorMode() {
|
||||||
|
console.log('Toggle influx edit mode:', this.target);
|
||||||
try {
|
try {
|
||||||
this.target.query = this.queryModel.render(false);
|
this.target.query = this.queryModel.render(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('query render error');
|
console.log('query render error');
|
||||||
}
|
}
|
||||||
this.target.rawQuery = !this.target.rawQuery;
|
const { queryType } = this.target;
|
||||||
|
if (queryType === InfluxQueryType.Flux || queryType === queryType.InfluxQL) {
|
||||||
|
this.target.queryType = InfluxQueryType.Classic;
|
||||||
|
this.target.rawQuery = false;
|
||||||
|
} else if (this.datasource.enableFlux) {
|
||||||
|
this.target.queryType = InfluxQueryType.Flux;
|
||||||
|
} else {
|
||||||
|
this.target.queryType = InfluxQueryType.InfluxQL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getMeasurements(measurementFilter: any) {
|
getMeasurements(measurementFilter: any) {
|
||||||
|
|||||||
@@ -3,15 +3,17 @@ import InfluxDatasource from '../datasource';
|
|||||||
import { TemplateSrvStub } from 'test/specs/helpers';
|
import { TemplateSrvStub } from 'test/specs/helpers';
|
||||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
const templateSrv = new TemplateSrvStub();
|
||||||
|
|
||||||
jest.mock('@grafana/runtime', () => ({
|
jest.mock('@grafana/runtime', () => ({
|
||||||
...jest.requireActual('@grafana/runtime'),
|
...jest.requireActual('@grafana/runtime'),
|
||||||
getBackendSrv: () => backendSrv,
|
getBackendSrv: () => backendSrv,
|
||||||
|
getTemplateSrv: () => templateSrv,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('InfluxDataSource', () => {
|
describe('InfluxDataSource', () => {
|
||||||
const ctx: any = {
|
const ctx: any = {
|
||||||
//@ts-ignore
|
|
||||||
templateSrv: new TemplateSrvStub(),
|
|
||||||
instanceSettings: { url: 'url', name: 'influxDb', jsonData: { httpMode: 'GET' } },
|
instanceSettings: { url: 'url', name: 'influxDb', jsonData: { httpMode: 'GET' } },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,7 +22,7 @@ describe('InfluxDataSource', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
ctx.instanceSettings.url = '/api/datasources/proxy/1';
|
ctx.instanceSettings.url = '/api/datasources/proxy/1';
|
||||||
ctx.ds = new InfluxDatasource(ctx.instanceSettings, ctx.templateSrv);
|
ctx.ds = new InfluxDatasource(ctx.instanceSettings);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('When issuing metricFindQuery', () => {
|
describe('When issuing metricFindQuery', () => {
|
||||||
@@ -108,7 +110,7 @@ describe('InfluxDataSource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ctx.ds.query(queryOptions);
|
await ctx.ds.query(queryOptions).toPromise();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
expect(err.message).toBe('InfluxDB Error: Query timeout');
|
expect(err.message).toBe('InfluxDB Error: Query timeout');
|
||||||
}
|
}
|
||||||
@@ -117,14 +119,12 @@ describe('InfluxDataSource', () => {
|
|||||||
|
|
||||||
describe('InfluxDataSource in POST query mode', () => {
|
describe('InfluxDataSource in POST query mode', () => {
|
||||||
const ctx: any = {
|
const ctx: any = {
|
||||||
//@ts-ignore
|
|
||||||
templateSrv: new TemplateSrvStub(),
|
|
||||||
instanceSettings: { url: 'url', name: 'influxDb', jsonData: { httpMode: 'POST' } },
|
instanceSettings: { url: 'url', name: 'influxDb', jsonData: { httpMode: 'POST' } },
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
ctx.instanceSettings.url = '/api/datasources/proxy/1';
|
ctx.instanceSettings.url = '/api/datasources/proxy/1';
|
||||||
ctx.ds = new InfluxDatasource(ctx.instanceSettings, ctx.templateSrv);
|
ctx.ds = new InfluxDatasource(ctx.instanceSettings);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('When issuing metricFindQuery', () => {
|
describe('When issuing metricFindQuery', () => {
|
||||||
|
|||||||
@@ -3,10 +3,17 @@ import { DataQuery, DataSourceJsonData } from '@grafana/data';
|
|||||||
export interface InfluxOptions extends DataSourceJsonData {
|
export interface InfluxOptions extends DataSourceJsonData {
|
||||||
timeInterval: string;
|
timeInterval: string;
|
||||||
httpMode: string;
|
httpMode: string;
|
||||||
|
|
||||||
|
// Influx 2.0
|
||||||
|
enableFlux?: boolean;
|
||||||
|
organization?: string;
|
||||||
|
defaultBucket?: string;
|
||||||
|
maxSeries?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InfluxSecureJsonData {
|
export interface InfluxSecureJsonData {
|
||||||
password?: string;
|
password?: string;
|
||||||
|
token?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InfluxQueryPart {
|
export interface InfluxQueryPart {
|
||||||
@@ -22,7 +29,14 @@ export interface InfluxQueryTag {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum InfluxQueryType {
|
||||||
|
Classic = 'Classic', // IFQL query builder
|
||||||
|
InfluxQL = 'InfluxQL', // raw ifql
|
||||||
|
Flux = 'Flux',
|
||||||
|
}
|
||||||
|
|
||||||
export interface InfluxQuery extends DataQuery {
|
export interface InfluxQuery extends DataQuery {
|
||||||
|
queryType?: InfluxQueryType;
|
||||||
policy?: string;
|
policy?: string;
|
||||||
measurement?: string;
|
measurement?: string;
|
||||||
resultFormat?: 'time_series' | 'table';
|
resultFormat?: 'time_series' | 'table';
|
||||||
@@ -34,6 +48,6 @@ export interface InfluxQuery extends DataQuery {
|
|||||||
slimit?: string;
|
slimit?: string;
|
||||||
tz?: string;
|
tz?: string;
|
||||||
fill?: string;
|
fill?: string;
|
||||||
rawQuery?: boolean;
|
rawQuery?: boolean; // deprecated (use raw InfluxQL)
|
||||||
query?: string;
|
query?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user