diff --git a/go.mod b/go.mod index 226c803..8a573ce 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/alexanderzobnin/grafana-zabbix go 1.12 require ( + github.com/bitly/go-simplejson v0.5.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 diff --git a/go.sum b/go.sum index ffdaafa..810a376 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +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/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= diff --git a/pkg/datasource.go b/pkg/datasource.go index e72f843..2623b87 100644 --- a/pkg/datasource.go +++ b/pkg/datasource.go @@ -1,6 +1,9 @@ package main import ( + "errors" + + 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" @@ -13,5 +16,52 @@ type ZabbixDatasource struct { } func (ds *ZabbixDatasource) Query(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { - return nil, ctx.Err() + queryType, err := GetQueryType(tsdbReq) + if err != nil { + return nil, err + } + + dsInfo := tsdbReq.GetDatasource() + ds.logger.Debug("createRequest", "dsInfo", dsInfo) + + ds.logger.Debug("createRequest", "queryType", queryType) + + switch queryType { + case "zabbixAPI": + return ds.ZabbixAPIQuery(ctx, tsdbReq) + default: + return nil, errors.New("Query is not implemented yet") + } +} + +func GetQueryType(tsdbReq *datasource.DatasourceRequest) (string, error) { + queryType := "query" + if len(tsdbReq.Queries) > 0 { + firstQuery := tsdbReq.Queries[0] + queryJson, err := simplejson.NewJson([]byte(firstQuery.ModelJson)) + if err != nil { + return "", err + } + queryType = queryJson.Get("queryType").MustString("query") + } + return queryType, nil +} + +func (ds *ZabbixDatasource) ZabbixAPIQuery(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) { + jsonQueries := make([]*simplejson.Json, 0) + for _, query := range tsdbReq.Queries { + json, err := simplejson.NewJson([]byte(query.ModelJson)) + apiMethod := json.GetPath("target", "method").MustString() + apiParams := json.GetPath("target", "params") + + if err != nil { + return nil, err + } + + ds.logger.Debug("ZabbixAPIQuery", "method", apiMethod, "params", apiParams) + + jsonQueries = append(jsonQueries, json) + } + + return nil, errors.New("ZabbixAPIQuery is not implemented yet") } diff --git a/src/datasource-zabbix/datasource.js b/src/datasource-zabbix/datasource.js index 09faf6d..18205ca 100644 --- a/src/datasource-zabbix/datasource.js +++ b/src/datasource-zabbix/datasource.js @@ -17,6 +17,7 @@ export class ZabbixDatasource { /** @ngInject */ constructor(instanceSettings, templateSrv, backendSrv, datasourceSrv, zabbixAlertingSrv) { this.templateSrv = templateSrv; + this.backendSrv = backendSrv; this.zabbixAlertingSrv = zabbixAlertingSrv; this.enableDebugLog = config.buildInfo.env === 'development'; @@ -25,6 +26,7 @@ export class ZabbixDatasource { this.replaceTemplateVars = _.partial(replaceTemplateVars, this.templateSrv); // General data source settings + this.datasourceId = instanceSettings.id; this.name = instanceSettings.name; this.url = instanceSettings.url; this.basicAuth = instanceSettings.basicAuth; @@ -74,7 +76,7 @@ export class ZabbixDatasource { dbConnectionRetentionPolicy: this.dbConnectionRetentionPolicy, }; - this.zabbix = new Zabbix(zabbixOptions, datasourceSrv, backendSrv); + this.zabbix = new Zabbix(zabbixOptions, datasourceSrv, backendSrv, this.datasourceId); } //////////////////////// @@ -87,6 +89,9 @@ export class ZabbixDatasource { * @return {Object} Grafana metrics object with timeseries data for each target. */ query(options) { + // console.log('invoking doTsdbRequest()'); + // this.doTsdbRequest(options); + // Get alerts for current panel if (this.alertingEnabled) { this.alertQuery(options).then(alert => { @@ -166,6 +171,27 @@ export class ZabbixDatasource { }); } + doTsdbRequest(options) { + const tsdbRequestData = { + queries: options.targets.map(target => { + target.datasourceId = this.datasourceId; + target.queryType = 'zabbixAPI'; + return target; + }), + }; + + if (options.range) { + tsdbRequestData.from = options.range.from.valueOf().toString(); + tsdbRequestData.to = options.range.to.valueOf().toString(); + } + + return this.backendSrv.datasourceRequest({ + url: '/api/tsdb/query', + method: 'POST', + data: tsdbRequestData + }); + } + /** * Query target data for Metrics mode */ diff --git a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.js b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.js index f3a9a9b..6ad3831 100644 --- a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.js +++ b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.js @@ -10,7 +10,7 @@ import { ZBX_ACK_ACTION_NONE, ZBX_ACK_ACTION_ACK, ZBX_ACK_ACTION_ADD_MESSAGE, MI * Wraps API calls and provides high-level methods. */ export class ZabbixAPIConnector { - constructor(api_url, username, password, version, basicAuth, withCredentials, backendSrv) { + constructor(api_url, username, password, version, basicAuth, withCredentials, backendSrv, datasourceId) { this.url = api_url; this.username = username; this.password = password; @@ -22,6 +22,9 @@ export class ZabbixAPIConnector { withCredentials: withCredentials }; + this.datasourceId = datasourceId; + this.backendSrv = backendSrv; + this.loginPromise = null; this.loginErrorCount = 0; this.maxLoginAttempts = 3; @@ -37,6 +40,8 @@ export class ZabbixAPIConnector { ////////////////////////// request(method, params) { + this.tsdbRequest(method, params); + return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth) .catch(error => { if (isNotAuthorized(error.data)) { @@ -55,6 +60,25 @@ export class ZabbixAPIConnector { }); } + tsdbRequest(method, params) { + const tsdbRequestData = { + queries: [{ + datasourceId: this.datasourceId, + queryType: 'zabbixAPI', + target: { + method, + params, + }, + }], + }; + + return this.backendSrv.datasourceRequest({ + url: '/api/tsdb/query', + method: 'POST', + data: tsdbRequestData + }); + } + /** * 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 diff --git a/src/datasource-zabbix/zabbix/zabbix.js b/src/datasource-zabbix/zabbix/zabbix.js index 74139a4..eaf9d0d 100644 --- a/src/datasource-zabbix/zabbix/zabbix.js +++ b/src/datasource-zabbix/zabbix/zabbix.js @@ -25,7 +25,7 @@ const REQUESTS_TO_BIND = [ ]; export class Zabbix { - constructor(options, datasourceSrv, backendSrv) { + constructor(options, datasourceSrv, backendSrv, datasourceId) { let { url, username, @@ -49,7 +49,7 @@ export class Zabbix { }; this.cachingProxy = new CachingProxy(cacheOptions); - this.zabbixAPI = new ZabbixAPIConnector(url, username, password, zabbixVersion, basicAuth, withCredentials, backendSrv); + this.zabbixAPI = new ZabbixAPIConnector(url, username, password, zabbixVersion, basicAuth, withCredentials, backendSrv, datasourceId); this.proxyfyRequests(); this.cacheRequests();