decouple the opentsdb data source from core (#113588)
* enable linting rules for opentsdb * remove core imports * update plugin.json * write backend standalone files * remove frontend core imports * add yarn workspace * remove core import for the plugin * update grafana dependency * update package.json * add jest config
This commit is contained in:
@@ -105,6 +105,8 @@ linters:
|
||||
- '**/pkg/tsdb/graphite/**/*'
|
||||
- '**/pkg/tsdb/mysql/*'
|
||||
- '**/pkg/tsdb/mysql/**/*'
|
||||
- '**/pkg/tsdb/opentsdb/*'
|
||||
- '**/pkg/tsdb/opentsdb/**/*'
|
||||
- '**/pkg/tsdb/parca/*'
|
||||
- '**/pkg/tsdb/parca/**/*'
|
||||
- '**/pkg/tsdb/tempo/*'
|
||||
|
||||
@@ -434,6 +434,7 @@ module.exports = [
|
||||
'public/app/plugins/datasource/loki/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/loki/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/mysql/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/opentsdb/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/parca/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/tempo/**/*.{ts,tsx}',
|
||||
'public/app/plugins/datasource/zipkin/**/*.{ts,tsx}',
|
||||
|
||||
@@ -1580,7 +1580,7 @@
|
||||
"keywords": null
|
||||
},
|
||||
"dependencies": {
|
||||
"grafanaDependency": "",
|
||||
"grafanaDependency": "\u003e=10.3.0-0",
|
||||
"grafanaVersion": "*",
|
||||
"plugins": [],
|
||||
"extensions": {
|
||||
|
||||
@@ -15,22 +15,19 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var logger = log.New("tsdb.opentsdb")
|
||||
var logger = backend.NewLoggerWith("tsdb.opentsdb")
|
||||
|
||||
type Service struct {
|
||||
im instancemgmt.InstanceManager
|
||||
}
|
||||
|
||||
func ProvideService(httpClientProvider httpclient.Provider) *Service {
|
||||
func ProvideService(httpClientProvider *httpclient.Provider) *Service {
|
||||
return &Service{
|
||||
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
||||
}
|
||||
@@ -52,7 +49,22 @@ type JSONData struct {
|
||||
LookupLimit int32 `json:"lookupLimit"`
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
type QueryModel struct {
|
||||
Metric string `json:"metric"`
|
||||
Aggregator string `json:"aggregator"`
|
||||
DownsampleInterval string `json:"downsampleInterval"`
|
||||
DownsampleAggregator string `json:"downsampleAggregator"`
|
||||
DownsampleFillPolicy string `json:"downsampleFillPolicy"`
|
||||
DisableDownsampling bool `json:"disableDownsampling"`
|
||||
Filters []any `json:"filters"`
|
||||
Tags map[string]interface{} `json:"tags"`
|
||||
ShouldComputeRate bool `json:"shouldComputeRate"`
|
||||
IsCounter bool `json:"isCounter"`
|
||||
CounterMax float64 `json:"counterMax"`
|
||||
CounterResetValue float64 `json:"counterResetValue"`
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider *httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions(ctx)
|
||||
if err != nil {
|
||||
@@ -102,10 +114,6 @@ func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest)
|
||||
},
|
||||
}
|
||||
|
||||
if setting.Env == setting.Dev {
|
||||
logger.Debug("OpenTsdb request", "refId", query.RefID, "params", tsdbQuery)
|
||||
}
|
||||
|
||||
httpReq, err := s.createRequest(ctx, logger, dsInfo, tsdbQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -274,47 +282,44 @@ func (s *Service) parseResponse(logger log.Logger, res *http.Response, refID str
|
||||
func (s *Service) buildMetric(query backend.DataQuery) map[string]any {
|
||||
metric := make(map[string]any)
|
||||
|
||||
model, err := simplejson.NewJson(query.JSON)
|
||||
if err != nil {
|
||||
var model QueryModel
|
||||
if err := json.Unmarshal(query.JSON, &model); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setting metric and aggregator
|
||||
metric["metric"] = model.Get("metric").MustString()
|
||||
metric["aggregator"] = model.Get("aggregator").MustString()
|
||||
metric["metric"] = model.Metric
|
||||
metric["aggregator"] = model.Aggregator
|
||||
|
||||
// Setting downsampling options
|
||||
disableDownsampling := model.Get("disableDownsampling").MustBool()
|
||||
if !disableDownsampling {
|
||||
downsampleInterval := model.Get("downsampleInterval").MustString()
|
||||
if !model.DisableDownsampling {
|
||||
downsampleInterval := model.DownsampleInterval
|
||||
if downsampleInterval == "" {
|
||||
downsampleInterval = "1m" // default value for blank
|
||||
}
|
||||
downsample := downsampleInterval + "-" + model.Get("downsampleAggregator").MustString()
|
||||
if model.Get("downsampleFillPolicy").MustString() != "none" {
|
||||
metric["downsample"] = downsample + "-" + model.Get("downsampleFillPolicy").MustString()
|
||||
downsample := downsampleInterval + "-" + model.DownsampleAggregator
|
||||
if model.DownsampleFillPolicy != "none" {
|
||||
metric["downsample"] = downsample + "-" + model.DownsampleFillPolicy
|
||||
} else {
|
||||
metric["downsample"] = downsample
|
||||
}
|
||||
}
|
||||
|
||||
// Setting rate options
|
||||
if model.Get("shouldComputeRate").MustBool() {
|
||||
if model.ShouldComputeRate {
|
||||
metric["rate"] = true
|
||||
rateOptions := make(map[string]any)
|
||||
rateOptions["counter"] = model.Get("isCounter").MustBool()
|
||||
rateOptions["counter"] = model.IsCounter
|
||||
|
||||
counterMax, counterMaxCheck := model.CheckGet("counterMax")
|
||||
if counterMaxCheck {
|
||||
rateOptions["counterMax"] = counterMax.MustFloat64()
|
||||
if model.CounterMax != 0 {
|
||||
rateOptions["counterMax"] = model.CounterMax
|
||||
}
|
||||
|
||||
resetValue, resetValueCheck := model.CheckGet("counterResetValue")
|
||||
if resetValueCheck {
|
||||
rateOptions["resetValue"] = resetValue.MustFloat64()
|
||||
if model.CounterResetValue != 0 {
|
||||
rateOptions["resetValue"] = model.CounterResetValue
|
||||
}
|
||||
|
||||
if !counterMaxCheck && (!resetValueCheck || resetValue.MustFloat64() == 0) {
|
||||
if model.CounterMax == 0 && (model.CounterResetValue == 0) {
|
||||
rateOptions["dropResets"] = true
|
||||
}
|
||||
|
||||
@@ -322,15 +327,13 @@ func (s *Service) buildMetric(query backend.DataQuery) map[string]any {
|
||||
}
|
||||
|
||||
// Setting tags
|
||||
tags, tagsCheck := model.CheckGet("tags")
|
||||
if tagsCheck && len(tags.MustMap()) > 0 {
|
||||
metric["tags"] = tags.MustMap()
|
||||
if len(model.Tags) > 0 {
|
||||
metric["tags"] = model.Tags
|
||||
}
|
||||
|
||||
// Setting filters
|
||||
filters, filtersCheck := model.CheckGet("filters")
|
||||
if filtersCheck && len(filters.MustArray()) > 0 {
|
||||
metric["filters"] = filters.MustArray()
|
||||
if len(model.Filters) > 0 {
|
||||
metric["filters"] = model.Filters
|
||||
}
|
||||
|
||||
return metric
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||
opentsdb "github.com/grafana/grafana/pkg/tsdb/opentsdb"
|
||||
)
|
||||
|
||||
var (
|
||||
_ backend.QueryDataHandler = (*Datasource)(nil)
|
||||
)
|
||||
|
||||
type Datasource struct {
|
||||
Service *opentsdb.Service
|
||||
}
|
||||
|
||||
func NewDatasource(context.Context, backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return &Datasource{
|
||||
Service: opentsdb.ProvideService(httpclient.NewProvider()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
return d.Service.QueryData(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if err := datasource.Manage("opentsdb", NewDatasource, datasource.ManageOpts{}); err != nil {
|
||||
log.DefaultLogger.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,6 @@ const dashboardDSPlugin = async () =>
|
||||
await import(/* webpackChunkName "dashboardDSPlugin" */ 'app/plugins/datasource/dashboard/module');
|
||||
const elasticsearchPlugin = async () =>
|
||||
await import(/* webpackChunkName: "elasticsearchPlugin" */ 'app/plugins/datasource/elasticsearch/module');
|
||||
const opentsdbPlugin = async () =>
|
||||
await import(/* webpackChunkName: "opentsdbPlugin" */ 'app/plugins/datasource/opentsdb/module');
|
||||
const grafanaPlugin = async () =>
|
||||
await import(/* webpackChunkName: "grafanaPlugin" */ 'app/plugins/datasource/grafana/module');
|
||||
const influxdbPlugin = async () =>
|
||||
@@ -78,7 +76,6 @@ const builtInPlugins: Record<string, System.Module | (() => Promise<System.Modul
|
||||
'core:plugin/cloudwatch': cloudwatchPlugin,
|
||||
'core:plugin/dashboard': dashboardDSPlugin,
|
||||
'core:plugin/elasticsearch': elasticsearchPlugin,
|
||||
'core:plugin/opentsdb': opentsdbPlugin,
|
||||
'core:plugin/grafana': grafanaPlugin,
|
||||
'core:plugin/influxdb': influxdbPlugin,
|
||||
'core:plugin/mixed': mixedPlugin,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
# Changelog
|
||||
@@ -26,8 +26,7 @@ import {
|
||||
ScopedVars,
|
||||
toDataFrame,
|
||||
} from '@grafana/data';
|
||||
import { FetchResponse, getBackendSrv } from '@grafana/runtime';
|
||||
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { FetchResponse, getBackendSrv, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
|
||||
|
||||
import { AnnotationEditor } from './components/AnnotationEditor';
|
||||
import { prepareAnnotation } from './migrations';
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
import '@grafana/plugin-configs/jest/jest-setup';
|
||||
@@ -0,0 +1,3 @@
|
||||
import defaultConfig from '@grafana/plugin-configs/jest/jest.config.js';
|
||||
|
||||
export default defaultConfig;
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "@grafana-plugins/opentsdb",
|
||||
"description": "OpenTSDB plugin for Grafana",
|
||||
"private": true,
|
||||
"version": "12.4.0-pre",
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.13.5",
|
||||
"@grafana/data": "workspace:*",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
"debounce-promise": "3.1.2",
|
||||
"lodash": "4.17.21",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
"react-select": "5.10.2",
|
||||
"react-use": "17.6.0",
|
||||
"rxjs": "7.8.2",
|
||||
"tslib": "2.8.1",
|
||||
"uuid": "11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@grafana/e2e-selectors": "workspace:*",
|
||||
"@grafana/plugin-configs": "workspace:*",
|
||||
"@testing-library/dom": "10.4.1",
|
||||
"@testing-library/jest-dom": "6.6.4",
|
||||
"@testing-library/react": "16.3.0",
|
||||
"@testing-library/user-event": "14.6.1",
|
||||
"@types/debounce-promise": "3.1.9",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/lodash": "4.17.20",
|
||||
"@types/node": "22.17.0",
|
||||
"@types/react": "18.3.18",
|
||||
"@types/react-dom": "18.3.5",
|
||||
"@types/uuid": "10.0.0",
|
||||
"jest": "29.7.0",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.2",
|
||||
"webpack": "5.101.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@grafana/runtime": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production",
|
||||
"build:commit": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)",
|
||||
"dev": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -w -c ./webpack.config.ts --env development",
|
||||
"test": "jest --watch --onlyChanged",
|
||||
"test:ci": "jest --maxWorkers 4"
|
||||
},
|
||||
"packageManager": "yarn@4.9.4"
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
"name": "OpenTSDB",
|
||||
"id": "opentsdb",
|
||||
"category": "tsdb",
|
||||
"executable": "gpx_opentsdb",
|
||||
|
||||
"metrics": true,
|
||||
"defaultMatchFormat": "pipe",
|
||||
@@ -23,6 +24,10 @@
|
||||
"links": [
|
||||
{ "name": "Raise issue", "url": "https://github.com/grafana/grafana/issues/new" },
|
||||
{ "name": "Documentation", "url": "https://grafana.com/docs/grafana/latest/datasources/opentsdb/" }
|
||||
]
|
||||
],
|
||||
"version": "%VERSION%"
|
||||
},
|
||||
"dependencies": {
|
||||
"grafanaDependency": ">=10.3.0-0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "../../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:plugin", "type:datasource"],
|
||||
"targets": {
|
||||
"build": {},
|
||||
"dev": {}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,32 @@
|
||||
import { of } from 'rxjs';
|
||||
|
||||
import { DataQueryRequest, dateTime } from '@grafana/data';
|
||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||
import { BackendSrv, FetchResponse, TemplateSrv } from '@grafana/runtime';
|
||||
|
||||
import { createFetchResponse } from '../../../../../test/helpers/createFetchResponse';
|
||||
import OpenTsDatasource from '../datasource';
|
||||
import { OpenTsdbQuery } from '../types';
|
||||
|
||||
export function createFetchResponse<T>(data: T): FetchResponse<T> {
|
||||
return {
|
||||
data,
|
||||
status: 200,
|
||||
url: 'http://localhost:3000/api/ds/query',
|
||||
config: { url: 'http://localhost:3000/api/ds/query' },
|
||||
type: 'basic',
|
||||
statusText: 'Ok',
|
||||
redirected: false,
|
||||
headers: new Headers(),
|
||||
ok: true,
|
||||
};
|
||||
}
|
||||
|
||||
const mockBackendSrv = {
|
||||
fetch: jest.fn(),
|
||||
} as unknown as BackendSrv;
|
||||
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
getBackendSrv: () => backendSrv,
|
||||
getBackendSrv: () => mockBackendSrv,
|
||||
}));
|
||||
|
||||
const metricFindQueryData = [
|
||||
@@ -26,7 +42,7 @@ const metricFindQueryData = [
|
||||
describe('opentsdb', () => {
|
||||
function getTestcontext({ data = metricFindQueryData }: { data?: unknown } = {}) {
|
||||
jest.clearAllMocks();
|
||||
const fetchMock = jest.spyOn(backendSrv, 'fetch');
|
||||
const fetchMock = jest.spyOn(mockBackendSrv, 'fetch');
|
||||
fetchMock.mockImplementation(() => of(createFetchResponse(data)));
|
||||
|
||||
const instanceSettings = { url: '', jsonData: { tsdbVersion: 1 } };
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"types": ["node", "jest", "@testing-library/jest-dom"]
|
||||
},
|
||||
"extends": "@grafana/plugin-configs/tsconfig.json",
|
||||
"include": ["."]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import config from '@grafana/plugin-configs/webpack.config.ts';
|
||||
|
||||
// eslint-disable-next-line no-barrel-files/no-barrel-files
|
||||
export default config;
|
||||
@@ -2784,6 +2784,46 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana-plugins/opentsdb@workspace:public/app/plugins/datasource/opentsdb":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@grafana-plugins/opentsdb@workspace:public/app/plugins/datasource/opentsdb"
|
||||
dependencies:
|
||||
"@emotion/css": "npm:11.13.5"
|
||||
"@grafana/data": "workspace:*"
|
||||
"@grafana/e2e-selectors": "workspace:*"
|
||||
"@grafana/plugin-configs": "workspace:*"
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/ui": "workspace:*"
|
||||
"@testing-library/dom": "npm:10.4.1"
|
||||
"@testing-library/jest-dom": "npm:6.6.4"
|
||||
"@testing-library/react": "npm:16.3.0"
|
||||
"@testing-library/user-event": "npm:14.6.1"
|
||||
"@types/debounce-promise": "npm:3.1.9"
|
||||
"@types/jest": "npm:29.5.14"
|
||||
"@types/lodash": "npm:4.17.20"
|
||||
"@types/node": "npm:22.17.0"
|
||||
"@types/react": "npm:18.3.18"
|
||||
"@types/react-dom": "npm:18.3.5"
|
||||
"@types/uuid": "npm:10.0.0"
|
||||
debounce-promise: "npm:3.1.2"
|
||||
jest: "npm:29.7.0"
|
||||
lodash: "npm:4.17.21"
|
||||
react: "npm:18.3.1"
|
||||
react-dom: "npm:18.3.1"
|
||||
react-select: "npm:5.10.2"
|
||||
react-use: "npm:17.6.0"
|
||||
rxjs: "npm:7.8.2"
|
||||
ts-node: "npm:10.9.2"
|
||||
tslib: "npm:2.8.1"
|
||||
typescript: "npm:5.9.2"
|
||||
uuid: "npm:11.1.0"
|
||||
webpack: "npm:5.101.0"
|
||||
peerDependencies:
|
||||
"@grafana/runtime": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana-plugins/parca@workspace:public/app/plugins/datasource/parca":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@grafana-plugins/parca@workspace:public/app/plugins/datasource/parca"
|
||||
@@ -10234,7 +10274,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:*, @types/node@npm:>=10.0.0, @types/node@npm:>=13.7.0, @types/node@npm:>=13.7.4":
|
||||
"@types/node@npm:*, @types/node@npm:22.17.0, @types/node@npm:>=10.0.0, @types/node@npm:>=13.7.0, @types/node@npm:>=13.7.4":
|
||||
version: 22.17.0
|
||||
resolution: "@types/node@npm:22.17.0"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user