mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Elasticsearch: Health endpoint should handle http errors (#96803)
Elasticsearch: health endpoint should handle http errors
This commit is contained in:
parent
5c2cda7abb
commit
91bdf733fb
@ -3,6 +3,7 @@ package elasticsearch
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -10,6 +11,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
|
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||||
@ -51,6 +53,9 @@ func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthReque
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("Failed to do healthcheck request", "error", err, "url", esUrl.String())
|
logger.Error("Failed to do healthcheck request", "error", err, "url", esUrl.String())
|
||||||
|
if backend.IsDownstreamHTTPError(err) {
|
||||||
|
err = errorsource.DownstreamError(err, false)
|
||||||
|
}
|
||||||
return &backend.CheckHealthResult{
|
return &backend.CheckHealthResult{
|
||||||
Status: backend.HealthStatusUnknown,
|
Status: backend.HealthStatusUnknown,
|
||||||
Message: "Failed to do healthcheck request",
|
Message: "Failed to do healthcheck request",
|
||||||
@ -64,6 +69,14 @@ func (s *Service) CheckHealth(ctx context.Context, req *backend.CheckHealthReque
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if response.StatusCode >= 400 {
|
||||||
|
errWithSource := errorsource.SourceError(backend.ErrorSourceFromHTTPStatus(response.StatusCode), fmt.Errorf("unexpected status code: %d", response.StatusCode), false)
|
||||||
|
return &backend.CheckHealthResult{
|
||||||
|
Status: backend.HealthStatusError,
|
||||||
|
Message: fmt.Sprintf("Elasticsearch data source is not healthy. Status: %s", response.Status),
|
||||||
|
}, errWithSource
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info("Response received from Elasticsearch", "statusCode", response.StatusCode, "status", "ok", "duration", time.Since(start))
|
logger.Info("Response received from Elasticsearch", "statusCode", response.StatusCode, "status", "ok", "duration", time.Since(start))
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Test_Healthcheck_OK(t *testing.T) {
|
func Test_Healthcheck_OK(t *testing.T) {
|
||||||
service := GetMockService(true)
|
service := GetMockService(http.StatusOK, "200 OK")
|
||||||
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
|
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
|
||||||
PluginContext: backend.PluginContext{},
|
PluginContext: backend.PluginContext{},
|
||||||
Headers: nil,
|
Headers: nil,
|
||||||
@ -26,7 +26,7 @@ func Test_Healthcheck_OK(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_Healthcheck_Timeout(t *testing.T) {
|
func Test_Healthcheck_Timeout(t *testing.T) {
|
||||||
service := GetMockService(false)
|
service := GetMockService(http.StatusRequestTimeout, "408 Request Timeout")
|
||||||
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
|
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
|
||||||
PluginContext: backend.PluginContext{},
|
PluginContext: backend.PluginContext{},
|
||||||
Headers: nil,
|
Headers: nil,
|
||||||
@ -35,13 +35,24 @@ func Test_Healthcheck_Timeout(t *testing.T) {
|
|||||||
assert.Equal(t, "Elasticsearch data source is not healthy", res.Message)
|
assert.Equal(t, "Elasticsearch data source is not healthy", res.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Healthcheck_Error(t *testing.T) {
|
||||||
|
service := GetMockService(http.StatusBadGateway, "502 Bad Gateway")
|
||||||
|
res, _ := service.CheckHealth(context.Background(), &backend.CheckHealthRequest{
|
||||||
|
PluginContext: backend.PluginContext{},
|
||||||
|
Headers: nil,
|
||||||
|
})
|
||||||
|
assert.Equal(t, backend.HealthStatusError, res.Status)
|
||||||
|
assert.Equal(t, "Elasticsearch data source is not healthy. Status: 502 Bad Gateway", res.Message)
|
||||||
|
}
|
||||||
|
|
||||||
type FakeRoundTripper struct {
|
type FakeRoundTripper struct {
|
||||||
isDsHealthy bool
|
statusCode int
|
||||||
|
status string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeRoundTripper *FakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
func (fakeRoundTripper *FakeRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
var res *http.Response
|
var res *http.Response
|
||||||
if fakeRoundTripper.isDsHealthy {
|
if fakeRoundTripper.statusCode == http.StatusOK {
|
||||||
res = &http.Response{
|
res = &http.Response{
|
||||||
StatusCode: http.StatusOK,
|
StatusCode: http.StatusOK,
|
||||||
Status: "200 OK",
|
Status: "200 OK",
|
||||||
@ -49,8 +60,8 @@ func (fakeRoundTripper *FakeRoundTripper) RoundTrip(req *http.Request) (*http.Re
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = &http.Response{
|
res = &http.Response{
|
||||||
StatusCode: http.StatusRequestTimeout,
|
StatusCode: fakeRoundTripper.statusCode,
|
||||||
Status: "408 Request Timeout",
|
Status: fakeRoundTripper.status,
|
||||||
Body: io.NopCloser(bytes.NewBufferString("{\"status\":\"red\"}")),
|
Body: io.NopCloser(bytes.NewBufferString("{\"status\":\"red\"}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,12 +69,13 @@ func (fakeRoundTripper *FakeRoundTripper) RoundTrip(req *http.Request) (*http.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FakeInstanceManager struct {
|
type FakeInstanceManager struct {
|
||||||
isDsHealthy bool
|
statusCode int
|
||||||
|
status string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fakeInstanceManager *FakeInstanceManager) Get(tx context.Context, pluginContext backend.PluginContext) (instancemgmt.Instance, error) {
|
func (fakeInstanceManager *FakeInstanceManager) Get(tx context.Context, pluginContext backend.PluginContext) (instancemgmt.Instance, error) {
|
||||||
httpClient, _ := httpclient.New(httpclient.Options{})
|
httpClient, _ := httpclient.New(httpclient.Options{})
|
||||||
httpClient.Transport = &FakeRoundTripper{isDsHealthy: fakeInstanceManager.isDsHealthy}
|
httpClient.Transport = &FakeRoundTripper{statusCode: fakeInstanceManager.statusCode, status: fakeInstanceManager.status}
|
||||||
|
|
||||||
return es.DatasourceInfo{
|
return es.DatasourceInfo{
|
||||||
HTTPClient: httpClient,
|
HTTPClient: httpClient,
|
||||||
@ -74,9 +86,9 @@ func (*FakeInstanceManager) Do(_ context.Context, _ backend.PluginContext, _ ins
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMockService(isDsHealthy bool) *Service {
|
func GetMockService(statusCode int, status string) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
im: &FakeInstanceManager{isDsHealthy: isDsHealthy},
|
im: &FakeInstanceManager{statusCode: statusCode, status: status},
|
||||||
logger: log.New(),
|
logger: log.New(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user