Zipkin: Run health check through backend (#96031)
* Zipkin: Run health check through backend * Mark some errors as downstream * Update pkg/tsdb/zipkin/zipkin.go Co-authored-by: Will Browne <wbrowne@users.noreply.github.com> * Use errors.New where error formatting is not needed * Remove executable in plugin.json * Fix joining the path * Keep logger as global and then create from context * Close the res body --------- Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
This commit is contained in:
co-authored by
Will Browne
parent
21ba507bcb
commit
4d0a7637b2
@@ -50,7 +50,7 @@ func TestCallResource(t *testing.T) {
|
||||
cfg.Azure = &azsettings.AzureSettings{}
|
||||
|
||||
coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), nil, &cloudwatch.CloudWatchService{}, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, testdatasource.ProvideService(), nil, nil, nil, nil, nil, nil)
|
||||
nil, nil, nil, nil, testdatasource.ProvideService(), nil, nil, nil, nil, nil, nil, nil)
|
||||
|
||||
testCtx := pluginsintegration.CreateIntegrationTestCtx(t, cfg, coreRegistry)
|
||||
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ require (
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // @grafana/grafana-developer-enablement-squad
|
||||
github.com/aws/aws-sdk-go v1.55.5 // @grafana/aws-datasources
|
||||
github.com/docker/docker v27.3.1+incompatible // @grafana/grafana-developer-enablement-squad
|
||||
github.com/drone/drone-cli v1.6.1 // @grafana/grafana-developer-enablement-squad
|
||||
github.com/drone/drone-cli v1.8.0 // @grafana/grafana-developer-enablement-squad
|
||||
github.com/gogo/protobuf v1.3.2 // indirect; @grafana/alerting-backend
|
||||
github.com/google/go-cmp v0.6.0 // @grafana/grafana-backend-group
|
||||
github.com/google/go-github v17.0.0+incompatible // @grafana/grafana-developer-enablement-squad
|
||||
@@ -61,7 +61,7 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2 // indirect
|
||||
github.com/drone-runners/drone-runner-docker v1.8.3 // indirect
|
||||
github.com/drone/drone-go v1.7.1 // indirect
|
||||
github.com/drone/envsubst v1.0.3 // indirect
|
||||
github.com/drone/runner-go v1.12.0 // indirect
|
||||
|
||||
+4
-4
@@ -72,10 +72,10 @@ github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2 h1:F7+39FSyzEUqLXYMvTdTGBhCS79ODDIhw3DQeF5GYT8=
|
||||
github.com/drone-runners/drone-runner-docker v1.8.2/go.mod h1:JR3pZeVZKKpkbTajiq0YtAx9WutkODdVKZGNR83kEwE=
|
||||
github.com/drone/drone-cli v1.6.1 h1:Beh0opEGR5XYezOyOmiqWzTMBGHkGDrh2tIG1cY/5GY=
|
||||
github.com/drone/drone-cli v1.6.1/go.mod h1://HC780Gua3Nhob/I2VPL3nTqmleEE/HIhGhTcJb2ds=
|
||||
github.com/drone-runners/drone-runner-docker v1.8.3 h1:uUnC45C1JMSLW+9uy6RoKG5ugzeXWN89pygs9BMLObY=
|
||||
github.com/drone-runners/drone-runner-docker v1.8.3/go.mod h1:JR3pZeVZKKpkbTajiq0YtAx9WutkODdVKZGNR83kEwE=
|
||||
github.com/drone/drone-cli v1.8.0 h1:tpp+GPonS87IKMZCGbIoa+zfDwiuJDL3NIC6S7neNrU=
|
||||
github.com/drone/drone-cli v1.8.0/go.mod h1:zu6/7OpQjWBw/5VG0M3K4iJc6kSoTrjnY7CRLBrGH84=
|
||||
github.com/drone/drone-go v1.7.1 h1:ZX+3Rs8YHUSUQ5mkuMLmm1zr1ttiiE2YGNxF3AnyDKw=
|
||||
github.com/drone/drone-go v1.7.1/go.mod h1:fxCf9jAnXDZV1yDr0ckTuWd1intvcQwfJmTRpTZ1mXg=
|
||||
github.com/drone/envsubst v1.0.2/go.mod h1:bkZbnc/2vh1M12Ecn7EYScpI4YGYU0etwLJICOWi8Z0=
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb/parca"
|
||||
"github.com/grafana/grafana/pkg/tsdb/prometheus"
|
||||
"github.com/grafana/grafana/pkg/tsdb/tempo"
|
||||
"github.com/grafana/grafana/pkg/tsdb/zipkin"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -55,6 +56,7 @@ const (
|
||||
Grafana = "grafana"
|
||||
Pyroscope = "grafana-pyroscope-datasource"
|
||||
Parca = "parca"
|
||||
Zipkin = "zipkin"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -93,7 +95,7 @@ func NewRegistry(store map[string]backendplugin.PluginFactoryFunc) *Registry {
|
||||
func ProvideCoreRegistry(tracer tracing.Tracer, am *azuremonitor.Service, cw *cloudwatch.CloudWatchService, cm *cloudmonitoring.Service,
|
||||
es *elasticsearch.Service, grap *graphite.Service, idb *influxdb.Service, lk *loki.Service, otsdb *opentsdb.Service,
|
||||
pr *prometheus.Service, t *tempo.Service, td *testdatasource.Service, pg *postgres.Service, my *mysql.Service,
|
||||
ms *mssql.Service, graf *grafanads.Service, pyroscope *pyroscope.Service, parca *parca.Service) *Registry {
|
||||
ms *mssql.Service, graf *grafanads.Service, pyroscope *pyroscope.Service, parca *parca.Service, zipkin *zipkin.Service) *Registry {
|
||||
// Non-optimal global solution to replace plugin SDK default tracer for core plugins.
|
||||
sdktracing.InitDefaultTracer(tracer)
|
||||
|
||||
@@ -115,6 +117,7 @@ func ProvideCoreRegistry(tracer tracing.Tracer, am *azuremonitor.Service, cw *cl
|
||||
Grafana: asBackendPlugin(graf),
|
||||
Pyroscope: asBackendPlugin(pyroscope),
|
||||
Parca: asBackendPlugin(parca),
|
||||
Zipkin: asBackendPlugin(zipkin),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -239,6 +242,8 @@ func NewPlugin(pluginID string, cfg *setting.Cfg, httpClientProvider *httpclient
|
||||
svc = pyroscope.ProvideService(httpClientProvider)
|
||||
case Parca:
|
||||
svc = parca.ProvideService(httpClientProvider)
|
||||
case Zipkin:
|
||||
svc = zipkin.ProvideService(httpClientProvider)
|
||||
default:
|
||||
return nil, ErrCorePluginNotFound
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ func TestNewPlugin(t *testing.T) {
|
||||
{ID: Tempo},
|
||||
{ID: TestData, ExpectedAlias: TestDataAlias},
|
||||
{ID: TestDataAlias, ExpectedID: TestData, ExpectedAlias: TestDataAlias},
|
||||
{ID: Zipkin},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
|
||||
@@ -173,6 +173,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb/parca"
|
||||
"github.com/grafana/grafana/pkg/tsdb/prometheus"
|
||||
"github.com/grafana/grafana/pkg/tsdb/tempo"
|
||||
"github.com/grafana/grafana/pkg/tsdb/zipkin"
|
||||
)
|
||||
|
||||
var wireBasicSet = wire.NewSet(
|
||||
@@ -267,6 +268,7 @@ var wireBasicSet = wire.NewSet(
|
||||
elasticsearch.ProvideService,
|
||||
pyroscope.ProvideService,
|
||||
parca.ProvideService,
|
||||
zipkin.ProvideService,
|
||||
datasourceservice.ProvideCacheService,
|
||||
wire.Bind(new(datasources.CacheService), new(*datasourceservice.CacheServiceImpl)),
|
||||
encryptionservice.ProvideEncryptionService,
|
||||
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb/parca"
|
||||
"github.com/grafana/grafana/pkg/tsdb/prometheus"
|
||||
"github.com/grafana/grafana/pkg/tsdb/tempo"
|
||||
"github.com/grafana/grafana/pkg/tsdb/zipkin"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -94,7 +95,8 @@ func TestIntegrationPluginManager(t *testing.T) {
|
||||
graf := grafanads.ProvideService(sv2, nil, nil, features)
|
||||
pyroscope := pyroscope.ProvideService(hcp)
|
||||
parca := parca.ProvideService(hcp)
|
||||
coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, pyroscope, parca)
|
||||
zipkin := zipkin.ProvideService(hcp)
|
||||
coreRegistry := coreplugin.ProvideCoreRegistry(tracing.InitializeTracerForTest(), am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf, pyroscope, parca, zipkin)
|
||||
|
||||
testCtx := CreateIntegrationTestCtx(t, cfg, coreRegistry)
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package zipkin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
)
|
||||
|
||||
type ZipkinClient struct {
|
||||
logger log.Logger
|
||||
url string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func New(url string, hc *http.Client, logger log.Logger) (ZipkinClient, error) {
|
||||
client := ZipkinClient{
|
||||
logger: logger,
|
||||
url: url,
|
||||
httpClient: hc,
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Services returns list of services
|
||||
// https://zipkin.io/zipkin-api/#/default/get_services
|
||||
func (z *ZipkinClient) Services() ([]string, error) {
|
||||
services := []string{}
|
||||
u, err := url.JoinPath(z.url, "/api/v2/services")
|
||||
if err != nil {
|
||||
return services, backend.DownstreamError(fmt.Errorf("failed to join url: %w", err))
|
||||
}
|
||||
res, err := z.httpClient.Get(u)
|
||||
if err != nil {
|
||||
return services, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err = res.Body.Close(); err != nil {
|
||||
z.logger.Error("Failed to close response body", "error", err)
|
||||
}
|
||||
}()
|
||||
if err := json.NewDecoder(res.Body).Decode(&services); err != nil {
|
||||
return services, err
|
||||
}
|
||||
return services, err
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package zipkin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"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/instancemgmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
)
|
||||
|
||||
var logger = backend.NewLoggerWith("logger", "tsdb.zipkin")
|
||||
|
||||
type Service struct {
|
||||
im instancemgmt.InstanceManager
|
||||
}
|
||||
|
||||
func ProvideService(httpClientProvider httpclient.Provider) *Service {
|
||||
return &Service{
|
||||
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
||||
}
|
||||
}
|
||||
|
||||
type datasourceInfo struct {
|
||||
ZipkinClient ZipkinClient
|
||||
}
|
||||
|
||||
func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
httpClientOptions, err := settings.HTTPClientOptions(ctx)
|
||||
if err != nil {
|
||||
return nil, backend.DownstreamError(fmt.Errorf("error reading settings: %w", err))
|
||||
}
|
||||
|
||||
httpClient, err := httpClientProvider.New(httpClientOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating http client: %w", err)
|
||||
}
|
||||
|
||||
if settings.URL == "" {
|
||||
return nil, backend.DownstreamError(errors.New("error reading settings: url is empty"))
|
||||
}
|
||||
|
||||
logger := logger.FromContext(ctx)
|
||||
zipkinClient, err := New(settings.URL, httpClient, logger)
|
||||
return &datasourceInfo{ZipkinClient: zipkinClient}, err
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) getDSInfo(ctx context.Context, pluginCtx backend.PluginContext) (*datasourceInfo, error) {
|
||||
i, err := s.im.Get(ctx, pluginCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
instance, ok := i.(*datasourceInfo)
|
||||
if !ok {
|
||||
return nil, errors.New("failed to cast datasource info")
|
||||
}
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||
client, err := s.getDSInfo(ctx, backend.PluginConfigFromContext(ctx))
|
||||
if err != nil {
|
||||
return &backend.CheckHealthResult{
|
||||
Status: backend.HealthStatusError,
|
||||
Message: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
if _, err = client.ZipkinClient.Services(); err != nil {
|
||||
return &backend.CheckHealthResult{
|
||||
Status: backend.HealthStatusError,
|
||||
Message: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
return &backend.CheckHealthResult{
|
||||
Status: backend.HealthStatusOk,
|
||||
Message: "Data source is working",
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user