Use backend queries for item id mode

This commit is contained in:
Alexander Zobnin
2021-06-01 13:01:54 +03:00
parent 6e6797653e
commit c81a6ae8c3
8 changed files with 106 additions and 30 deletions

View File

@@ -122,15 +122,22 @@ func (ds *ZabbixDatasource) QueryData(ctx context.Context, req *backend.QueryDat
ds.logger.Debug("DS query", "query", q) ds.logger.Debug("DS query", "query", q)
if err != nil { if err != nil {
res.Error = err res.Error = err
} else if query.Mode != 0 { } else if query.QueryType == MODE_METRICS {
res.Error = ErrNonMetricQueryNotSupported
} else {
frames, err := zabbixDS.queryNumericItems(ctx, &query) frames, err := zabbixDS.queryNumericItems(ctx, &query)
if err != nil { if err != nil {
res.Error = err res.Error = err
} else { } else {
res.Frames = append(res.Frames, frames...) res.Frames = append(res.Frames, frames...)
} }
} else if query.QueryType == MODE_ITEMID {
frames, err := zabbixDS.queryItemIdData(ctx, &query)
if err != nil {
res.Error = err
} else {
res.Frames = append(res.Frames, frames...)
}
} else {
res.Error = ErrNonMetricQueryNotSupported
} }
qdr.Responses[q.RefID] = res qdr.Responses[q.RefID] = res
} }

View File

@@ -8,6 +8,15 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
) )
const (
MODE_METRICS = "0"
MODE_ITSERVICE = "1"
MODE_TEXT = "2"
MODE_ITEMID = "3"
MODE_TRIGGERS = "4"
MODE_PROBLEMS = "5"
)
// ZabbixDatasourceSettingsDTO model // ZabbixDatasourceSettingsDTO model
type ZabbixDatasourceSettingsDTO struct { type ZabbixDatasourceSettingsDTO struct {
Trends bool `json:"trends"` Trends bool `json:"trends"`
@@ -44,13 +53,19 @@ type ZabbixAPIResourceResponse struct {
// QueryModel model // QueryModel model
type QueryModel struct { type QueryModel struct {
Mode int64 `json:"mode"` // Deprecated `mode` field, use QueryType instead
Group QueryFilter `json:"group"` Mode int64 `json:"mode"`
Host QueryFilter `json:"host"`
Application QueryFilter `json:"application"` Group QueryFilter `json:"group"`
Item QueryFilter `json:"item"` Host QueryFilter `json:"host"`
Functions []QueryFunction `json:"functions,omitempty"` Application QueryFilter `json:"application"`
Options QueryOptions `json:"options"` Item QueryFilter `json:"item"`
// Item ID mode
ItemIDs string `json:"itemids,omitempty"`
Functions []QueryFunction `json:"functions,omitempty"`
Options QueryOptions `json:"options"`
// Direct from the gRPC interfaces // Direct from the gRPC interfaces
RefID string `json:"-"` RefID string `json:"-"`

View File

@@ -1,6 +1,7 @@
package datasource package datasource
import ( import (
"strings"
"time" "time"
"github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix" "github.com/alexanderzobnin/grafana-zabbix/pkg/zabbix"
@@ -60,6 +61,25 @@ func (ds *ZabbixDatasourceInstance) queryNumericItems(ctx context.Context, query
return frames, nil return frames, nil
} }
func (ds *ZabbixDatasourceInstance) queryItemIdData(ctx context.Context, query *QueryModel) ([]*data.Frame, error) {
itemids := strings.Split(query.ItemIDs, ",")
for i, id := range itemids {
itemids[i] = strings.Trim(id, " ")
}
items, err := ds.zabbix.GetItemsByIDs(ctx, itemids)
if err != nil {
return nil, err
}
frames, err := ds.queryNumericDataForItems(ctx, query, items)
if err != nil {
return nil, err
}
return frames, nil
}
func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, query *QueryModel, items []*zabbix.Item) ([]*data.Frame, error) { func (ds *ZabbixDatasourceInstance) queryNumericDataForItems(ctx context.Context, query *QueryModel, items []*zabbix.Item) ([]*data.Frame, error) {
trendValueType := ds.getTrendValueType(query) trendValueType := ds.getTrendValueType(query)
consolidateBy := ds.getConsolidateBy(query) consolidateBy := ds.getConsolidateBy(query)

View File

@@ -274,6 +274,29 @@ func (ds *Zabbix) GetAllItems(ctx context.Context, hostids []string, appids []st
return items, err return items, err
} }
func (ds *Zabbix) GetItemsByIDs(ctx context.Context, itemids []string) ([]*Item, error) {
params := ZabbixAPIParams{
"itemids": itemids,
"output": []string{"itemid", "name", "key_", "value_type", "hostid", "status", "state", "units", "valuemapid", "delay"},
"webitems": true,
"selectHosts": []string{"hostid", "name"},
}
result, err := ds.Request(ctx, &ZabbixAPIRequest{Method: "item.get", Params: params})
if err != nil {
return nil, err
}
var items []*Item
err = convertTo(result, &items)
if err != nil {
return nil, err
}
items = expandItems(items)
return items, err
}
func (ds *Zabbix) GetAllApps(ctx context.Context, hostids []string) ([]Application, error) { func (ds *Zabbix) GetAllApps(ctx context.Context, hostids []string) ([]Application, error) {
params := ZabbixAPIParams{ params := ZabbixAPIParams{
"output": "extend", "output": "extend",

View File

@@ -7,12 +7,12 @@ export const DATAPOINT_VALUE = 0;
export const DATAPOINT_TS = 1; export const DATAPOINT_TS = 1;
// Editor modes // Editor modes
export const MODE_METRICS = 0; export const MODE_METRICS = '0';
export const MODE_ITSERVICE = 1; export const MODE_ITSERVICE = '1';
export const MODE_TEXT = 2; export const MODE_TEXT = '2';
export const MODE_ITEMID = 3; export const MODE_ITEMID = '3';
export const MODE_TRIGGERS = 4; export const MODE_TRIGGERS = '4';
export const MODE_PROBLEMS = 5; export const MODE_PROBLEMS = '5';
// Triggers severity // Triggers severity
export const SEV_NOT_CLASSIFIED = 0; export const SEV_NOT_CLASSIFIED = 0;

View File

@@ -100,15 +100,21 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
* @return {Object} Grafana metrics object with timeseries data for each target. * @return {Object} Grafana metrics object with timeseries data for each target.
*/ */
query(request: DataQueryRequest<any>): Promise<DataQueryResponse> | Observable<DataQueryResponse> { query(request: DataQueryRequest<any>): Promise<DataQueryResponse> | Observable<DataQueryResponse> {
const isMetricQuery = request.targets.every(q => q.queryType === c.MODE_METRICS || q.mode === c.MODE_METRICS); // Migrate old targets
if (isMetricQuery) { request.targets = request.targets.map(t => {
// Prevent changes of original object
const target = _.cloneDeep(t);
return migrations.migrate(target);
});
if (isBackendQuery(request)) {
return this.backendQuery(request); return this.backendQuery(request);
} }
// Create request for each target // Create request for each target
const promises = _.map(request.targets, t => { const promises = _.map(request.targets, target => {
// Don't request for hidden targets // Don't request for hidden targets
if (t.hide) { if (target.hide) {
return []; return [];
} }
@@ -118,11 +124,6 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
// Add range variables // Add range variables
request.scopedVars = Object.assign({}, request.scopedVars, utils.getRangeScopedVars(request.range)); request.scopedVars = Object.assign({}, request.scopedVars, utils.getRangeScopedVars(request.range));
// Prevent changes of original object
let target = _.cloneDeep(t);
// Migrate old targets
target = migrations.migrate(target);
this.replaceTargetVariables(target, request); this.replaceTargetVariables(target, request);
// Apply Time-related functions (timeShift(), etc) // Apply Time-related functions (timeShift(), etc)
@@ -213,10 +214,6 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
target = migrations.migrate(target); target = migrations.migrate(target);
this.replaceTargetVariables(target, request); this.replaceTargetVariables(target, request);
if (target.queryType !== c.MODE_METRICS) {
return null;
}
return { return {
...target, ...target,
datasourceId, datasourceId,
@@ -839,6 +836,10 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars); target.textFilter = this.replaceTemplateVars(target.textFilter, options.scopedVars);
} }
if (target.itemids) {
target.itemids = this.templateSrv.replace(target.itemids, options.scopedVars, zabbixItemIdsTemplateFormat);
}
_.forEach(target.functions, func => { _.forEach(target.functions, func => {
func.params = _.map(func.params, param => { func.params = _.map(func.params, param => {
if (typeof param === 'number') { if (typeof param === 'number') {
@@ -969,3 +970,10 @@ function getRequestTarget(request: DataQueryRequest<any>, refId: string): any {
} }
return null; return null;
} }
function isBackendQuery(request: DataQueryRequest<any>): boolean {
return request.targets.every(q =>
q.queryType === c.MODE_METRICS ||
q.queryType === c.MODE_ITEMID
);
}

View File

@@ -49,6 +49,9 @@ function migrateQueryType(target) {
delete target.mode; delete target.mode;
} }
} }
// queryType is a string in query model
target.queryType = (target.queryType as number).toString();
} }
function migrateSLA(target) { function migrateSLA(target) {

View File

@@ -82,7 +82,7 @@ export class ZabbixQueryController extends QueryCtrl {
zabbix: any; zabbix: any;
replaceTemplateVars: any; replaceTemplateVars: any;
templateSrv: TemplateSrv; templateSrv: TemplateSrv;
editorModes: Array<{ value: string; text: string; queryType: number; }>; editorModes: Array<{ value: string; text: string; queryType: string; }>;
slaPropertyList: Array<{ name: string; property: string; }>; slaPropertyList: Array<{ name: string; property: string; }>;
slaIntervals: Array<{ text: string; value: string; }>; slaIntervals: Array<{ text: string; value: string; }>;
ackFilters: Array<{ text: string; value: number; }>; ackFilters: Array<{ text: string; value: number; }>;