backend: proxy Zabbix API requests through the backend

This commit is contained in:
Alexander Zobnin
2019-09-24 20:45:36 +03:00
parent 0938d06487
commit 6b8c11f4f4
6 changed files with 108 additions and 5 deletions

1
go.mod
View File

@@ -3,6 +3,7 @@ module github.com/alexanderzobnin/grafana-zabbix
go 1.12 go 1.12
require ( require (
github.com/bitly/go-simplejson v0.5.0
github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d github.com/grafana/grafana_plugin_model v0.0.0-20180518082423-84176c64269d
github.com/hashicorp/go-hclog v0.9.2 github.com/hashicorp/go-hclog v0.9.2
github.com/hashicorp/go-plugin v1.0.1 github.com/hashicorp/go-plugin v1.0.1

2
go.sum
View File

@@ -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.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=

View File

@@ -1,6 +1,9 @@
package main package main
import ( import (
"errors"
simplejson "github.com/bitly/go-simplejson"
"github.com/grafana/grafana_plugin_model/go/datasource" "github.com/grafana/grafana_plugin_model/go/datasource"
hclog "github.com/hashicorp/go-hclog" hclog "github.com/hashicorp/go-hclog"
plugin "github.com/hashicorp/go-plugin" 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) { 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")
} }

View File

@@ -17,6 +17,7 @@ export class ZabbixDatasource {
/** @ngInject */ /** @ngInject */
constructor(instanceSettings, templateSrv, backendSrv, datasourceSrv, zabbixAlertingSrv) { constructor(instanceSettings, templateSrv, backendSrv, datasourceSrv, zabbixAlertingSrv) {
this.templateSrv = templateSrv; this.templateSrv = templateSrv;
this.backendSrv = backendSrv;
this.zabbixAlertingSrv = zabbixAlertingSrv; this.zabbixAlertingSrv = zabbixAlertingSrv;
this.enableDebugLog = config.buildInfo.env === 'development'; this.enableDebugLog = config.buildInfo.env === 'development';
@@ -25,6 +26,7 @@ export class ZabbixDatasource {
this.replaceTemplateVars = _.partial(replaceTemplateVars, this.templateSrv); this.replaceTemplateVars = _.partial(replaceTemplateVars, this.templateSrv);
// General data source settings // General data source settings
this.datasourceId = instanceSettings.id;
this.name = instanceSettings.name; this.name = instanceSettings.name;
this.url = instanceSettings.url; this.url = instanceSettings.url;
this.basicAuth = instanceSettings.basicAuth; this.basicAuth = instanceSettings.basicAuth;
@@ -74,7 +76,7 @@ export class ZabbixDatasource {
dbConnectionRetentionPolicy: this.dbConnectionRetentionPolicy, 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. * @return {Object} Grafana metrics object with timeseries data for each target.
*/ */
query(options) { query(options) {
// console.log('invoking doTsdbRequest()');
// this.doTsdbRequest(options);
// Get alerts for current panel // Get alerts for current panel
if (this.alertingEnabled) { if (this.alertingEnabled) {
this.alertQuery(options).then(alert => { 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 * Query target data for Metrics mode
*/ */

View File

@@ -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. * Wraps API calls and provides high-level methods.
*/ */
export class ZabbixAPIConnector { 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.url = api_url;
this.username = username; this.username = username;
this.password = password; this.password = password;
@@ -22,6 +22,9 @@ export class ZabbixAPIConnector {
withCredentials: withCredentials withCredentials: withCredentials
}; };
this.datasourceId = datasourceId;
this.backendSrv = backendSrv;
this.loginPromise = null; this.loginPromise = null;
this.loginErrorCount = 0; this.loginErrorCount = 0;
this.maxLoginAttempts = 3; this.maxLoginAttempts = 3;
@@ -37,6 +40,8 @@ export class ZabbixAPIConnector {
////////////////////////// //////////////////////////
request(method, params) { request(method, params) {
this.tsdbRequest(method, params);
return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth) return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth)
.catch(error => { .catch(error => {
if (isNotAuthorized(error.data)) { 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() * 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 * call. But auth token is common to all requests. This function wraps login() method

View File

@@ -25,7 +25,7 @@ const REQUESTS_TO_BIND = [
]; ];
export class Zabbix { export class Zabbix {
constructor(options, datasourceSrv, backendSrv) { constructor(options, datasourceSrv, backendSrv, datasourceId) {
let { let {
url, url,
username, username,
@@ -49,7 +49,7 @@ export class Zabbix {
}; };
this.cachingProxy = new CachingProxy(cacheOptions); 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.proxyfyRequests();
this.cacheRequests(); this.cacheRequests();