From f0daa9fcb995d6d09c0721ff426c4cdf3293fa24 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 28 May 2020 17:04:49 +0300 Subject: [PATCH] Migrate to new backend sdk, use /zabbix-api endpoint for API queries --- go.mod | 9 +- go.sum | 146 ++++++++++++++++ pkg/cache.go | 4 +- pkg/datasource.go | 159 +++++++++++++----- pkg/datasource_test.go | 12 +- pkg/models.go | 20 ++- pkg/plugin.go | 59 ++++--- pkg/resource_handler.go | 49 ++++++ pkg/zabbix_api.go | 89 ++++++---- pkg/zabbix_api_core.go | 36 ++-- pkg/zabbix_api_test.go | 15 +- .../zabbix_api/zabbixAPIConnector.ts | 21 ++- 12 files changed, 478 insertions(+), 141 deletions(-) create mode 100644 pkg/resource_handler.go diff --git a/go.mod b/go.mod index 1b61780..55f886b 100644 --- a/go.mod +++ b/go.mod @@ -5,17 +5,16 @@ go 1.12 require ( github.com/bitly/go-simplejson v0.5.0 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect - github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-cmp v0.3.1 // indirect + github.com/grafana/grafana-plugin-sdk-go v0.65.0 github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d github.com/hashicorp/go-hclog v0.9.2 - github.com/hashicorp/go-plugin v1.0.1 + github.com/hashicorp/go-plugin v1.2.2 github.com/kr/pretty v0.1.0 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.8.1 // indirect - github.com/stretchr/testify v1.3.0 - golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 - golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect + github.com/stretchr/testify v1.5.1 + golang.org/x/net v0.0.0-20190923162816-aa69164e4478 golang.org/x/text v0.3.2 // indirect gotest.tools v2.2.0+incompatible ) diff --git a/go.sum b/go.sum index 0957b02..9015e23 100644 --- a/go.sum +++ b/go.sum @@ -1,67 +1,213 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/apache/arrow/go/arrow v0.0.0-20200403134915-89ce1cadb678 h1:R72+9UXiP7TnpTAdznM1okjzyqb3bzopSA7HCP7p3gM= +github.com/apache/arrow/go/arrow v0.0.0-20200403134915-89ce1cadb678/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +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-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +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/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A= +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.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/grafana/grafana-plugin-sdk-go v0.65.0 h1:l6cPKCFxf3AN3gd7Sprum2TuhcqsGI98Xa/1dDuin9E= +github.com/grafana/grafana-plugin-sdk-go v0.65.0/go.mod h1:w855JyiC5PDP3naWUJP0h/vY8RlzlE4+4fodyoXph+4= github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d h1:Ep6bjWDwurT9NpUATiqa8NYIllmZbLDXLn6Ib4lCtAA= github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d/go.mod h1:70BFhO60E3e7kq+ssiouwX/HX5DvQ3L6XffdH0S2YfU= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-plugin v1.2.2 h1:mgDpq0PkoK5gck2w4ivaMpWRHv/matdOR4xmeScmf/w= +github.com/hashicorp/go-plugin v1.2.2/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY= +github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0 h1:ElTg5tNp4DqfV7UQjDqv2+RJlNzsDtvNAWccbItceIE= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +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-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= 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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +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-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk/jwn79LUL43rES2g8o= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +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.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/cache.go b/pkg/cache.go index 22f52fc..de7245c 100644 --- a/pkg/cache.go +++ b/pkg/cache.go @@ -6,7 +6,7 @@ import ( "encoding/json" "time" - "github.com/grafana/grafana_plugin_model/go/datasource" + "github.com/grafana/grafana-plugin-sdk-go/backend" cache "github.com/patrickmn/go-cache" ) @@ -40,7 +40,7 @@ func HashString(text string) string { } // HashDatasourceInfo converts the given datasource info to hash string -func HashDatasourceInfo(dsInfo *datasource.DatasourceInfo) string { +func HashDatasourceInfo(dsInfo *backend.DataSourceInstanceSettings) string { digester := sha1.New() if err := json.NewEncoder(digester).Encode(dsInfo); err != nil { panic(err) // This shouldn't be possible but just in case DatasourceInfo changes diff --git a/pkg/datasource.go b/pkg/datasource.go index 7ed0c31..1521162 100644 --- a/pkg/datasource.go +++ b/pkg/datasource.go @@ -3,82 +3,141 @@ package main import ( "context" "encoding/json" - "errors" "fmt" + "net/http" + "os" + "time" simplejson "github.com/bitly/go-simplejson" "github.com/grafana/grafana_plugin_model/go/datasource" hclog "github.com/hashicorp/go-hclog" plugin "github.com/hashicorp/go-plugin" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/backend/log" ) -// ZabbixPlugin implements the Grafana backend interface and forwards queries to the ZabbixDatasource +// ZabbixPlugin implements the Grafana backend interface and forwards queries to the ZabbixDatasourceInstance type ZabbixPlugin struct { plugin.NetRPCUnsupportedPlugin logger hclog.Logger datasourceCache *Cache } -func (p *ZabbixPlugin) NewZabbixDatasource(dsInfo *datasource.DatasourceInfo) (*ZabbixDatasource, error) { - ds, err := newZabbixDatasource(dsInfo) +type ZabbixDatasource struct { + datasourceCache *Cache + logger log.Logger +} + +func NewDatasource(logger log.Logger, mux *http.ServeMux) *ZabbixDatasource { + variableName := "GFX_ZABBIX_DATA_PATH" + path, exist := os.LookupEnv(variableName) + if !exist { + logger.Error("could not read environment variable", variableName) + } else { + logger.Debug("environment variable for storage found", "variable", variableName, "value", path) + } + + ds := &ZabbixDatasource{ + logger: logger, + datasourceCache: NewCache(10*time.Minute, 10*time.Minute), + } + + mux.HandleFunc("/", ds.rootHandler) + mux.HandleFunc("/zabbix-api", ds.zabbixAPIHandler) + // mux.Handle("/scenarios", getScenariosHandler(logger)) + + return ds +} + +// CheckHealth checks if the plugin is running properly +func (ds *ZabbixDatasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { + res := &backend.CheckHealthResult{} + + // Just checking that the plugin exe is alive and running + if req.PluginContext.DataSourceInstanceSettings == nil { + res.Status = backend.HealthStatusOk + res.Message = "Plugin is running" + return res, nil + } + + // TODO? actually check datasource settings? + res.Status = backend.HealthStatusOk + res.Message = "Success" + return res, nil +} + +func (gds *ZabbixDatasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { + qdr := backend.NewQueryDataResponse() + + for _, q := range req.Queries { + res := backend.DataResponse{} + qdr.Responses[q.RefID] = res + } + + return qdr, nil +} + +// func (p *ZabbixPlugin) GetDatasourceById(datasourceId int64) (*ZabbixDatasourceInstance, error) { +// } + +func (ds *ZabbixDatasource) NewZabbixDatasource(dsInfo *backend.DataSourceInstanceSettings) (*ZabbixDatasourceInstance, error) { + dsInstance, err := newZabbixDatasource(dsInfo) if err != nil { return nil, err } - ds.logger = p.logger - return ds, nil + dsInstance.logger = ds.logger + return dsInstance, nil } // Query receives requests from the Grafana backend. Requests are filtered by query type and sent to the // applicable ZabbixDatasource. -func (p *ZabbixPlugin) Query(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (resp *datasource.DatasourceResponse, err error) { - zabbixDS, err := p.GetDatasource(tsdbReq) - if err != nil { - return nil, err - } +// func (p *ZabbixPlugin) Query(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (resp *datasource.DatasourceResponse, err error) { +// zabbixDS, err := p.GetDatasource(tsdbReq) +// if err != nil { +// return nil, err +// } - queryType, err := GetQueryType(tsdbReq) - if err != nil { - return nil, err - } +// queryType, err := GetQueryType(tsdbReq) +// if err != nil { +// return nil, err +// } - switch queryType { - case "zabbixAPI": - resp, err = zabbixDS.ZabbixAPIQuery(ctx, tsdbReq) - case "query": - resp, err = zabbixDS.queryNumericItems(ctx, tsdbReq) - case "connectionTest": - resp, err = zabbixDS.TestConnection(ctx, tsdbReq) - default: - err = errors.New("Query not implemented") - return BuildErrorResponse(err), nil - } +// switch queryType { +// case "zabbixAPI": +// resp, err = zabbixDS.ZabbixAPIQuery(ctx, tsdbReq) +// case "query": +// resp, err = zabbixDS.queryNumericItems(ctx, tsdbReq) +// case "connectionTest": +// resp, err = zabbixDS.TestConnection(ctx, tsdbReq) +// default: +// err = errors.New("Query not implemented") +// return BuildErrorResponse(err), nil +// } - return -} +// return +// } // GetDatasource Returns cached datasource or creates new one -func (p *ZabbixPlugin) GetDatasource(tsdbReq *datasource.DatasourceRequest) (*ZabbixDatasource, error) { - dsInfoHash := HashDatasourceInfo(tsdbReq.GetDatasource()) +func (ds *ZabbixDatasource) GetDatasource(orgID int64, dsInfo *backend.DataSourceInstanceSettings) (*ZabbixDatasourceInstance, error) { + dsInfoHash := HashDatasourceInfo(dsInfo) - if cachedData, ok := p.datasourceCache.Get(dsInfoHash); ok { - if cachedDS, ok := cachedData.(*ZabbixDatasource); ok { + if cachedData, ok := ds.datasourceCache.Get(dsInfoHash); ok { + if cachedDS, ok := cachedData.(*ZabbixDatasourceInstance); ok { return cachedDS, nil } } - dsInfo := tsdbReq.GetDatasource() - if p.logger.IsDebug() { - p.logger.Debug(fmt.Sprintf("Datasource cache miss (Org %d Id %d '%s' %s)", dsInfo.GetOrgId(), dsInfo.GetId(), dsInfo.GetName(), dsInfoHash)) - } + ds.logger.Debug(fmt.Sprintf("Datasource cache miss (Org %d Id %d '%s' %s)", orgID, dsInfo.ID, dsInfo.Name, dsInfoHash)) - ds, err := p.NewZabbixDatasource(dsInfo) + dsInstance, err := ds.NewZabbixDatasource(dsInfo) if err != nil { return nil, err } - p.datasourceCache.Set(dsInfoHash, ds) - return ds, nil + ds.datasourceCache.Set(dsInfoHash, dsInstance) + return dsInstance, nil } // GetQueryType determines the query type from a query or list of queries @@ -95,6 +154,22 @@ func GetQueryType(tsdbReq *datasource.DatasourceRequest) (string, error) { return queryType, nil } +// // BuildDataResponse transforms a Zabbix API response to the QueryDataResponse +// func BuildDataResponse(responseData interface{}) (*backend.QueryDataResponse, error) { +// jsonBytes, err := json.Marshal(responseData) +// if err != nil { +// return nil, err +// } + +// return &backend.QueryDataResponse{ +// Responses: map[string]backend.DataResponse{ +// "zabbixAPI": { +// Frames: , +// } +// }, +// }, nil +// } + // BuildResponse transforms a Zabbix API response to a DatasourceResponse func BuildResponse(responseData interface{}) (*datasource.DatasourceResponse, error) { jsonBytes, err := json.Marshal(responseData) @@ -104,7 +179,7 @@ func BuildResponse(responseData interface{}) (*datasource.DatasourceResponse, er return &datasource.DatasourceResponse{ Results: []*datasource.QueryResult{ - &datasource.QueryResult{ + { RefId: "zabbixAPI", MetaJson: string(jsonBytes), }, @@ -116,7 +191,7 @@ func BuildResponse(responseData interface{}) (*datasource.DatasourceResponse, er func BuildErrorResponse(err error) *datasource.DatasourceResponse { return &datasource.DatasourceResponse{ Results: []*datasource.QueryResult{ - &datasource.QueryResult{ + { RefId: "zabbixAPI", Error: err.Error(), }, @@ -128,7 +203,7 @@ func BuildErrorResponse(err error) *datasource.DatasourceResponse { func BuildMetricsResponse(metrics []*datasource.TimeSeries) (*datasource.DatasourceResponse, error) { return &datasource.DatasourceResponse{ Results: []*datasource.QueryResult{ - &datasource.QueryResult{ + { RefId: "zabbixMetrics", Series: metrics, }, diff --git a/pkg/datasource_test.go b/pkg/datasource_test.go index 756fec5..8c5bb43 100644 --- a/pkg/datasource_test.go +++ b/pkg/datasource_test.go @@ -34,7 +34,7 @@ func TestZabbixBackend_getCachedDatasource(t *testing.T) { name string cache *cache.Cache request *datasource.DatasourceRequest - want *ZabbixDatasource + want *ZabbixDatasourceInstance }{ { name: "Uncached Datasource (nothing in cache)", @@ -46,7 +46,7 @@ func TestZabbixBackend_getCachedDatasource(t *testing.T) { { name: "Uncached Datasource (cache miss)", cache: cache.NewFrom(cache.NoExpiration, cache.NoExpiration, map[string]cache.Item{ - basicDatasourceInfoHash: cache.Item{Object: modifiedDatasource}, + basicDatasourceInfoHash: {Object: modifiedDatasource}, }), request: &datasource.DatasourceRequest{ Datasource: altDatasourceInfo, @@ -56,8 +56,8 @@ func TestZabbixBackend_getCachedDatasource(t *testing.T) { { name: "Cached Datasource", cache: cache.NewFrom(cache.NoExpiration, cache.NoExpiration, map[string]cache.Item{ - altDatasourceInfoHash: cache.Item{Object: basicDS}, - basicDatasourceInfoHash: cache.Item{Object: modifiedDatasource}, + altDatasourceInfoHash: {Object: basicDS}, + basicDatasourceInfoHash: {Object: modifiedDatasource}, }), request: &datasource.DatasourceRequest{ Datasource: basicDatasourceInfo, @@ -105,7 +105,7 @@ func TestBuildResponse(t *testing.T) { responseData: jsonData, want: &datasource.DatasourceResponse{ Results: []*datasource.QueryResult{ - &datasource.QueryResult{ + { RefId: "zabbixAPI", MetaJson: `{"testing":[5,12,75]}`, }, @@ -123,7 +123,7 @@ func TestBuildResponse(t *testing.T) { }, want: &datasource.DatasourceResponse{ Results: []*datasource.QueryResult{ - &datasource.QueryResult{ + { RefId: "zabbixAPI", MetaJson: `{"zabbixVersion":"2.4","dbConnectorStatus":{"dsType":"mysql","dsName":"MyDatabase"}}`, }, diff --git a/pkg/models.go b/pkg/models.go index 5707672..ee434f0 100644 --- a/pkg/models.go +++ b/pkg/models.go @@ -60,7 +60,9 @@ func (p *zabbixParamOutput) UnmarshalJSON(data []byte) error { } -type ZabbixAPIParams struct { +type ZabbixAPIParams = map[string]interface{} + +type ZabbixAPIParamsLegacy struct { Output *zabbixParamOutput `json:"output,omitempty"` SortField string `json:"sortfield,omitempty"` SortOrder string `json:"sortorder,omitempty"` @@ -101,3 +103,19 @@ type ZabbixAPIParams struct { TimeFrom int64 `json:"time_from,omitempty"` TimeTill int64 `json:"time_till,omitempty"` } + +type ZabbixAPIResourceRequest struct { + DatasourceId int64 `json:"datasourceId"` + Method string `json:"method"` + Params map[string]interface{} `json:"params,omitempty"` +} + +type ZabbixAPIRequest struct { + Method string `json:"method"` + Params map[string]interface{} `json:"params,omitempty"` +} + +func (r *ZabbixAPIRequest) String() string { + jsonRequest, _ := json.Marshal(r.Params) + return r.Method + string(jsonRequest) +} diff --git a/pkg/plugin.go b/pkg/plugin.go index ac42670..793d471 100644 --- a/pkg/plugin.go +++ b/pkg/plugin.go @@ -1,36 +1,49 @@ package main import ( - "time" + "net/http" - "github.com/grafana/grafana_plugin_model/go/datasource" - hclog "github.com/hashicorp/go-hclog" - plugin "github.com/hashicorp/go-plugin" + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/backend/log" + "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" ) -var pluginLogger = hclog.New(&hclog.LoggerOptions{ - Name: "zabbix-datasource", - Level: hclog.LevelFromString("DEBUG"), -}) +const ZABBIX_PLUGIN_ID = "alexanderzobnin-zabbix-datasource" func main() { - pluginLogger.Debug("Running Zabbix backend datasource") + backend.SetupPluginEnvironment(ZABBIX_PLUGIN_ID) - plugin.Serve(&plugin.ServeConfig{ + pluginLogger := log.New() + mux := http.NewServeMux() + ds := NewDatasource(pluginLogger, mux) + httpResourceHandler := httpadapter.New(mux) - HandshakeConfig: plugin.HandshakeConfig{ - ProtocolVersion: 1, - MagicCookieKey: "grafana_plugin_type", - MagicCookieValue: "datasource", - }, - Plugins: map[string]plugin.Plugin{ - "zabbix-backend-datasource": &datasource.DatasourcePluginImpl{Plugin: &ZabbixPlugin{ - datasourceCache: NewCache(10*time.Minute, 10*time.Minute), - logger: pluginLogger, - }}, - }, + pluginLogger.Debug("Starting Zabbix backend datasource") - // A non-nil value here enables gRPC serving for this plugin... - GRPCServer: plugin.DefaultGRPCServer, + err := backend.Serve(backend.ServeOpts{ + CallResourceHandler: httpResourceHandler, + QueryDataHandler: ds, + CheckHealthHandler: ds, }) + if err != nil { + pluginLogger.Error(err.Error()) + } + + // plugin.Serve(&plugin.ServeConfig{ + + // HandshakeConfig: plugin.HandshakeConfig{ + // ProtocolVersion: 1, + // MagicCookieKey: "grafana_plugin_type", + // MagicCookieValue: "datasource", + // }, + // Plugins: map[string]plugin.Plugin{ + // "zabbix-backend-datasource": &datasource.DatasourcePluginImpl{Plugin: &ZabbixPlugin{ + // datasourceCache: NewCache(10*time.Minute, 10*time.Minute), + // logger: pluginLogger, + // }}, + // }, + + // // A non-nil value here enables gRPC serving for this plugin... + // GRPCServer: plugin.DefaultGRPCServer, + // }) } diff --git a/pkg/resource_handler.go b/pkg/resource_handler.go new file mode 100644 index 0000000..f525387 --- /dev/null +++ b/pkg/resource_handler.go @@ -0,0 +1,49 @@ +package main + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter" +) + +func (ds *ZabbixDatasource) rootHandler(rw http.ResponseWriter, req *http.Request) { + ds.logger.Debug("Received resource call", "url", req.URL.String(), "method", req.Method) + + rw.Write([]byte("Hello from Zabbix data source!")) + rw.WriteHeader(http.StatusOK) +} + +func (ds *ZabbixDatasource) zabbixAPIHandler(rw http.ResponseWriter, req *http.Request) { + ds.logger.Debug("Received resource call", "url", req.URL.String(), "method", req.Method) + + if req.Method != http.MethodPost { + return + } + + body, err := ioutil.ReadAll(req.Body) + defer req.Body.Close() + if err != nil || len(body) == 0 { + rw.WriteHeader(http.StatusBadRequest) + } + + var reqData ZabbixAPIResourceRequest + err = json.Unmarshal(body, &reqData) + + pluginCxt := httpadapter.PluginConfigFromContext(req.Context()) + ds.logger.Debug("Received Zabbix API call", "ds", pluginCxt.DataSourceInstanceSettings.Name) + + dsInstance, err := ds.GetDatasource(pluginCxt.OrgID, pluginCxt.DataSourceInstanceSettings) + ds.logger.Debug("Data source found", "ds", dsInstance.dsInfo.Name) + + apiReq := &ZabbixAPIRequest{Method: reqData.Method, Params: reqData.Params} + result, err := dsInstance.ZabbixAPIQuery(req.Context(), apiReq) + resultJson, err := json.Marshal(*result) + ds.logger.Debug("Got response", "result", result) + + ds.logger.Debug("Received Zabbix API call", "ds", reqData.DatasourceId, "method", reqData.Method, "params", reqData.Params) + + rw.Write(resultJson) + rw.WriteHeader(http.StatusOK) +} diff --git a/pkg/zabbix_api.go b/pkg/zabbix_api.go index 8a503f8..572edbc 100644 --- a/pkg/zabbix_api.go +++ b/pkg/zabbix_api.go @@ -25,7 +25,27 @@ type FunctionCategories struct { } // ZabbixAPIQuery handles query requests to Zabbix -func (ds *ZabbixDatasource) ZabbixAPIQuery(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { +func (dsInstance *ZabbixDatasourceInstance) ZabbixAPIQuery(ctx context.Context, apiReq *ZabbixAPIRequest) (*interface{}, error) { + var result interface{} + var err error + var queryExistInCache bool + result, queryExistInCache = dsInstance.queryCache.Get(HashString(apiReq.String())) + + if !queryExistInCache { + result, err = dsInstance.ZabbixRequest(ctx, apiReq.Method, apiReq.Params) + dsInstance.logger.Debug("ZabbixAPIQuery", "result", result) + dsInstance.queryCache.Set(HashString(apiReq.String()), result) + if err != nil { + dsInstance.logger.Debug("ZabbixAPIQuery", "error", err) + return nil, errors.New("ZabbixAPIQuery is not implemented yet") + } + } + + // return BuildResponse(result) + return &result, nil +} + +func (ds *ZabbixDatasourceInstance) ZabbixAPIQueryOld(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { result, queryExistInCache := ds.queryCache.Get(HashString(tsdbReq.String())) if !queryExistInCache { @@ -58,7 +78,7 @@ func (ds *ZabbixDatasource) ZabbixAPIQuery(ctx context.Context, tsdbReq *datasou } // TestConnection checks authentication and version of the Zabbix API and returns that info -func (ds *ZabbixDatasource) TestConnection(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { +func (ds *ZabbixDatasourceInstance) TestConnection(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { err := ds.loginWithDs(ctx) if err != nil { return BuildErrorResponse(fmt.Errorf("Authentication failed: %s", err)), nil @@ -80,7 +100,7 @@ func (ds *ZabbixDatasource) TestConnection(ctx context.Context, tsdbReq *datasou return BuildResponse(testResponse) } -func (ds *ZabbixDatasource) queryNumericItems(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { +func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { tStart := time.Now() jsonQueries := make([]*simplejson.Json, 0) for _, query := range tsdbReq.Queries { @@ -124,7 +144,7 @@ func (ds *ZabbixDatasource) queryNumericItems(ctx context.Context, tsdbReq *data return BuildMetricsResponse(metrics) } -func (ds *ZabbixDatasource) getItems(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string, hostFilter string, appFilter string, itemFilter string, itemType string) (zabbix.Items, error) { +func (ds *ZabbixDatasourceInstance) getItems(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string, hostFilter string, appFilter string, itemFilter string, itemType string) (zabbix.Items, error) { tStart := time.Now() hosts, err := ds.getHosts(ctx, dsInfo, groupFilter, hostFilter) @@ -195,7 +215,7 @@ func (ds *ZabbixDatasource) getItems(ctx context.Context, dsInfo *datasource.Dat return filteredItems, nil } -func (ds *ZabbixDatasource) getApps(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string, hostFilter string, appFilter string) ([]map[string]interface{}, error) { +func (ds *ZabbixDatasourceInstance) getApps(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string, hostFilter string, appFilter string) ([]map[string]interface{}, error) { hosts, err := ds.getHosts(ctx, dsInfo, groupFilter, hostFilter) if err != nil { return nil, err @@ -229,7 +249,7 @@ func (ds *ZabbixDatasource) getApps(ctx context.Context, dsInfo *datasource.Data return apps, nil } -func (ds *ZabbixDatasource) getHosts(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string, hostFilter string) ([]map[string]interface{}, error) { +func (ds *ZabbixDatasourceInstance) getHosts(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string, hostFilter string) ([]map[string]interface{}, error) { groups, err := ds.getGroups(ctx, dsInfo, groupFilter) if err != nil { return nil, err @@ -264,7 +284,7 @@ func (ds *ZabbixDatasource) getHosts(ctx context.Context, dsInfo *datasource.Dat return hosts, nil } -func (ds *ZabbixDatasource) getGroups(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string) ([]map[string]interface{}, error) { +func (ds *ZabbixDatasourceInstance) getGroups(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupFilter string) ([]map[string]interface{}, error) { allGroups, err := ds.getAllGroups(ctx, dsInfo) if err != nil { return nil, err @@ -288,45 +308,46 @@ func (ds *ZabbixDatasource) getGroups(ctx context.Context, dsInfo *datasource.Da return groups, nil } -func (ds *ZabbixDatasource) getAllItems(ctx context.Context, dsInfo *datasource.DatasourceInfo, hostids []string, appids []string, itemtype string) (*simplejson.Json, error) { +func (ds *ZabbixDatasourceInstance) getAllItems(ctx context.Context, dsInfo *datasource.DatasourceInfo, hostids []string, appids []string, itemtype string) (*simplejson.Json, error) { params := ZabbixAPIParams{ - Output: &zabbixParamOutput{Fields: []string{"itemid", "name", "key_", "value_type", "hostid", "status", "state"}}, - SortField: "name", - WebItems: true, - Filter: map[string]interface{}{}, - SelectHosts: []string{"hostid", "name"}, - HostIDs: hostids, - AppIDs: appids, + "output": &zabbixParamOutput{Fields: []string{"itemid", "name", "key_", "value_type", "hostid", "status", "state"}}, + "sortField": "name", + "webItems": true, + "filter": map[string]interface{}{}, + "selectHosts": []string{"hostid", "name"}, + "hostIDs": hostids, + "appIDs": appids, } + filter := params["filter"].(map[string]interface{}) if itemtype == "num" { - params.Filter["value_type"] = []int{0, 3} + filter["value_type"] = []int{0, 3} } else if itemtype == "text" { - params.Filter["value_type"] = []int{1, 2, 4} + filter["value_type"] = []int{1, 2, 4} } return ds.ZabbixRequest(ctx, "item.get", params) } -func (ds *ZabbixDatasource) getAllApps(ctx context.Context, dsInfo *datasource.DatasourceInfo, hostids []string) (*simplejson.Json, error) { - params := ZabbixAPIParams{Output: &zabbixParamOutput{Mode: "extend"}, HostIDs: hostids} +func (ds *ZabbixDatasourceInstance) getAllApps(ctx context.Context, dsInfo *datasource.DatasourceInfo, hostids []string) (*simplejson.Json, error) { + params := ZabbixAPIParams{"output": &zabbixParamOutput{Mode: "extend"}, "hostIDs": hostids} return ds.ZabbixRequest(ctx, "application.get", params) } -func (ds *ZabbixDatasource) getAllHosts(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupids []string) (*simplejson.Json, error) { - params := ZabbixAPIParams{Output: &zabbixParamOutput{Fields: []string{"name", "host"}}, SortField: "name", GroupIDs: groupids} +func (ds *ZabbixDatasourceInstance) getAllHosts(ctx context.Context, dsInfo *datasource.DatasourceInfo, groupids []string) (*simplejson.Json, error) { + params := ZabbixAPIParams{"output": &zabbixParamOutput{Fields: []string{"name", "host"}}, "sortField": "name", "groupIDs": groupids} return ds.ZabbixRequest(ctx, "host.get", params) } -func (ds *ZabbixDatasource) getAllGroups(ctx context.Context, dsInfo *datasource.DatasourceInfo) (*simplejson.Json, error) { - params := ZabbixAPIParams{Output: &zabbixParamOutput{Fields: []string{"name"}}, SortField: "name", RealHosts: true} +func (ds *ZabbixDatasourceInstance) getAllGroups(ctx context.Context, dsInfo *datasource.DatasourceInfo) (*simplejson.Json, error) { + params := ZabbixAPIParams{"output": &zabbixParamOutput{Fields: []string{"name"}}, "sortField": "name", "realHosts": true} return ds.ZabbixRequest(ctx, "hostgroup.get", params) } -func (ds *ZabbixDatasource) queryNumericDataForItems(ctx context.Context, tsdbReq *datasource.DatasourceRequest, items zabbix.Items, jsonQueries []*simplejson.Json, useTrend bool) ([]*datasource.TimeSeries, error) { +func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, tsdbReq *datasource.DatasourceRequest, items zabbix.Items, jsonQueries []*simplejson.Json, useTrend bool) ([]*datasource.TimeSeries, error) { valueType := ds.getTrendValueType(jsonQueries) consolidateBy := ds.getConsolidateBy(jsonQueries) @@ -342,7 +363,7 @@ func (ds *ZabbixDatasource) queryNumericDataForItems(ctx context.Context, tsdbRe return convertHistory(history, items) } -func (ds *ZabbixDatasource) getTrendValueType(jsonQueries []*simplejson.Json) string { +func (ds *ZabbixDatasourceInstance) getTrendValueType(jsonQueries []*simplejson.Json) string { var trendFunctions []string var trendValueFunc string @@ -365,7 +386,7 @@ func (ds *ZabbixDatasource) getTrendValueType(jsonQueries []*simplejson.Json) st return trendValueFunc } -func (ds *ZabbixDatasource) getConsolidateBy(jsonQueries []*simplejson.Json) string { +func (ds *ZabbixDatasourceInstance) getConsolidateBy(jsonQueries []*simplejson.Json) string { var consolidateBy string for _, k := range jsonQueries[0].Get("functions").MustArray() { @@ -379,7 +400,7 @@ func (ds *ZabbixDatasource) getConsolidateBy(jsonQueries []*simplejson.Json) str return consolidateBy } -func (ds *ZabbixDatasource) getHistotyOrTrend(ctx context.Context, tsdbReq *datasource.DatasourceRequest, items zabbix.Items, useTrend bool) (zabbix.History, error) { +func (ds *ZabbixDatasourceInstance) getHistotyOrTrend(ctx context.Context, tsdbReq *datasource.DatasourceRequest, items zabbix.Items, useTrend bool) (zabbix.History, error) { allHistory := zabbix.History{} timeRange := tsdbReq.GetTimeRange() @@ -396,12 +417,12 @@ func (ds *ZabbixDatasource) getHistotyOrTrend(ctx context.Context, tsdbReq *data } params := ZabbixAPIParams{ - Output: &zabbixParamOutput{Mode: "extend"}, - SortField: "clock", - SortOrder: "ASC", - ItemIDs: itemids, - TimeFrom: timeRange.GetFromEpochMs() / 1000, - TimeTill: timeRange.GetToEpochMs() / 1000, + "output": &zabbixParamOutput{Mode: "extend"}, + "sortField": "clock", + "sortOrder": "ASC", + "itemIDs": itemids, + "timeFrom": timeRange.GetFromEpochMs() / 1000, + "timeTill": timeRange.GetToEpochMs() / 1000, } var response *simplejson.Json @@ -409,7 +430,7 @@ func (ds *ZabbixDatasource) getHistotyOrTrend(ctx context.Context, tsdbReq *data if useTrend { response, err = ds.ZabbixRequest(ctx, "trend.get", params) } else { - params.History = &k + params["history"] = &k response, err = ds.ZabbixRequest(ctx, "history.get", params) } diff --git a/pkg/zabbix_api_core.go b/pkg/zabbix_api_core.go index c1c62f5..379e9d0 100644 --- a/pkg/zabbix_api_core.go +++ b/pkg/zabbix_api_core.go @@ -15,31 +15,31 @@ import ( "time" simplejson "github.com/bitly/go-simplejson" - "github.com/grafana/grafana_plugin_model/go/datasource" - hclog "github.com/hashicorp/go-hclog" + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/backend/log" "golang.org/x/net/context/ctxhttp" ) -// ZabbixDatasource stores state about a specific datasource and provides methods to make +// ZabbixDatasourceInstance stores state about a specific datasource and provides methods to make // requests to the Zabbix API -type ZabbixDatasource struct { +type ZabbixDatasourceInstance struct { url *url.URL authToken string - dsInfo *datasource.DatasourceInfo + dsInfo *backend.DataSourceInstanceSettings queryCache *Cache - logger hclog.Logger httpClient *http.Client + logger log.Logger } // newZabbixDatasource returns an initialized ZabbixDatasource -func newZabbixDatasource(dsInfo *datasource.DatasourceInfo) (*ZabbixDatasource, error) { - zabbixURLStr := dsInfo.GetUrl() +func newZabbixDatasource(dsInfo *backend.DataSourceInstanceSettings) (*ZabbixDatasourceInstance, error) { + zabbixURLStr := dsInfo.URL zabbixURL, err := url.Parse(zabbixURLStr) if err != nil { return nil, err } - return &ZabbixDatasource{ + return &ZabbixDatasourceInstance{ url: zabbixURL, dsInfo: dsInfo, queryCache: NewCache(10*time.Minute, 10*time.Minute), @@ -64,7 +64,7 @@ func newZabbixDatasource(dsInfo *datasource.DatasourceInfo) (*ZabbixDatasource, } // ZabbixRequest checks authentication and makes a request to the Zabbix API -func (ds *ZabbixDatasource) ZabbixRequest(ctx context.Context, method string, params ZabbixAPIParams) (*simplejson.Json, error) { +func (ds *ZabbixDatasourceInstance) ZabbixRequest(ctx context.Context, method string, params ZabbixAPIParams) (*simplejson.Json, error) { var result *simplejson.Json var err error @@ -86,16 +86,16 @@ func (ds *ZabbixDatasource) ZabbixRequest(ctx context.Context, method string, pa return result, err } -func (ds *ZabbixDatasource) loginWithDs(ctx context.Context) error { - jsonDataStr := ds.dsInfo.GetJsonData() - jsonData, err := simplejson.NewJson([]byte(jsonDataStr)) +func (ds *ZabbixDatasourceInstance) loginWithDs(ctx context.Context) error { + jsonDataStr := ds.dsInfo.JSONData + jsonData, err := simplejson.NewJson(jsonDataStr) if err != nil { return err } zabbixLogin := jsonData.Get("username").MustString() var zabbixPassword string - if securePassword, exists := ds.dsInfo.GetDecryptedSecureJsonData()["password"]; exists { + if securePassword, exists := ds.dsInfo.DecryptedSecureJSONData["password"]; exists { zabbixPassword = securePassword } else { zabbixPassword = jsonData.Get("password").MustString() @@ -113,10 +113,10 @@ func (ds *ZabbixDatasource) loginWithDs(ctx context.Context) error { return nil } -func (ds *ZabbixDatasource) login(ctx context.Context, username string, password string) (string, error) { +func (ds *ZabbixDatasourceInstance) login(ctx context.Context, username string, password string) (string, error) { params := ZabbixAPIParams{ - User: username, - Password: password, + "user": username, + "password": password, } auth, err := ds.ZabbixAPIRequest(ctx, "user.login", params, "") if err != nil { @@ -126,7 +126,7 @@ func (ds *ZabbixDatasource) login(ctx context.Context, username string, password return auth.MustString(), nil } -func (ds *ZabbixDatasource) ZabbixAPIRequest(ctx context.Context, method string, params ZabbixAPIParams, auth string) (*simplejson.Json, error) { +func (ds *ZabbixDatasourceInstance) ZabbixAPIRequest(ctx context.Context, method string, params ZabbixAPIParams, auth string) (*simplejson.Json, error) { apiRequest := map[string]interface{}{ "jsonrpc": "2.0", "id": 2, diff --git a/pkg/zabbix_api_test.go b/pkg/zabbix_api_test.go index 3e40f40..511becc 100644 --- a/pkg/zabbix_api_test.go +++ b/pkg/zabbix_api_test.go @@ -10,6 +10,7 @@ import ( "time" simplejson "github.com/bitly/go-simplejson" + "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana_plugin_model/go/datasource" hclog "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/assert" @@ -29,27 +30,27 @@ func NewTestClient(fn RoundTripFunc) *http.Client { } } -var basicDatasourceInfo = &datasource.DatasourceInfo{ - Id: 1, +var basicDatasourceInfo = &backend.DataSourceInstanceSettings{ + ID: 1, Name: "TestDatasource", - Url: "http://zabbix.org/zabbix", - JsonData: `{"username":"username", "password":"password"}}`, + URL: "http://zabbix.org/zabbix", + JSONData: []byte(`{"username":"username", "password":"password"}}`), } func mockDataSourceRequest(modelJSON string) *datasource.DatasourceRequest { return &datasource.DatasourceRequest{ Datasource: basicDatasourceInfo, Queries: []*datasource.Query{ - &datasource.Query{ + { ModelJson: modelJSON, }, }, } } -func mockZabbixDataSource(body string, statusCode int) ZabbixDatasource { +func mockZabbixDataSource(body string, statusCode int) ZabbixDatasourceInstance { apiUrl, _ := url.Parse(basicDatasourceInfo.Url) - return ZabbixDatasource{ + return ZabbixDatasourceInstance{ url: apiUrl, dsInfo: basicDatasourceInfo, queryCache: NewCache(10*time.Minute, 10*time.Minute), diff --git a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts index aa4104e..8a53d14 100644 --- a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts +++ b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts @@ -61,7 +61,8 @@ export class ZabbixAPIConnector { request(method, params) { return this.tsdbRequest(method, params).then(response => { - const result = this.handleTsdbResponse(response); + // const result = this.handleTsdbResponse(response); + const result = this.handleZabbixAPIResourceResponse(response); return result; }); @@ -80,10 +81,20 @@ export class ZabbixAPIConnector { }; return getBackendSrv().datasourceRequest({ - url: '/api/tsdb/query', + url: `/api/datasources/${this.datasourceId}/resources/zabbix-api`, method: 'POST', - data: tsdbRequestData + data: { + datasourceId: this.datasourceId, + method, + params, + }, }); + + // return getBackendSrv().datasourceRequest({ + // url: '/api/tsdb/query', + // method: 'POST', + // data: tsdbRequestData + // }); } _request(method: string, params: JSONRPCRequestParams): Promise { @@ -121,6 +132,10 @@ export class ZabbixAPIConnector { return response.data.results['zabbixAPI'].meta; } + handleZabbixAPIResourceResponse(response) { + return response?.data; + } + /** * When API unauthenticated or auth token expired each request produce login() * call. But auth token is common to all requests. This function wraps login() method