Skip to content

Commit 528476f

Browse files
Handle ES ping failures more gracefully (#7626)
## Which problem is this PR solving? - Resolves #7625 ## Description of the changes - Added test cases for the changes done in the #7422 ## How was this change tested? - `/usr/bin/go test -timeout 30s -coverprofile=/tmp/vscode-gokdhNQo/go-code-cover github.com/jaegertracing/jaeger/internal/storage/elasticsearch/config` ## Checklist - [x] I have read https://github.com/jaegertracing/jaeger/blob/master/CONTRIBUTING_GUIDELINES.md - [x] I have signed all commits - [x] I have added unit tests for the new functionality - [x] I have run lint and test steps successfully - for `jaeger`: `make lint test` - for `jaeger-ui`: `npm run lint` and `npm run test` --------- Signed-off-by: Jakub Stasiak <[email protected]> Signed-off-by: Tushar Anand <[email protected]> Co-authored-by: Jakub Stasiak <[email protected]>
1 parent 506966d commit 528476f

File tree

2 files changed

+157
-1
lines changed

2 files changed

+157
-1
lines changed

internal/storage/elasticsearch/config/config.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,23 @@ func NewClient(ctx context.Context, c *Configuration, logger *zap.Logger, metric
252252

253253
if c.Version == 0 {
254254
// Determine ElasticSearch Version
255-
pingResult, _, err := rawClient.Ping(c.Servers[0]).Do(ctx)
255+
pingResult, pingStatus, err := rawClient.Ping(c.Servers[0]).Do(ctx)
256256
if err != nil {
257257
return nil, err
258258
}
259+
260+
// Non-2xx responses aren't reported as errors by the ping code (7.0.32 version of
261+
// the elastic client).
262+
if pingStatus < 200 || pingStatus >= 300 {
263+
return nil, fmt.Errorf("ElasticSearch server %s returned HTTP %d, expected 2xx", c.Servers[0], pingStatus)
264+
}
265+
266+
// The deserialization in the ping implementation may succeed even if the response
267+
// contains no relevant properties and we may get empty values in that case.
268+
if pingResult.Version.Number == "" {
269+
return nil, fmt.Errorf("ElasticSearch server %s returned invalid ping response", c.Servers[0])
270+
}
271+
259272
esVersion, err := strconv.Atoi(string(pingResult.Version.Number[0]))
260273
if err != nil {
261274
return nil, err

internal/storage/elasticsearch/config/config_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,149 @@ func TestNewClient(t *testing.T) {
507507
}
508508
}
509509

510+
func TestNewClientPingErrorHandling(t *testing.T) {
511+
tests := []struct {
512+
name string
513+
serverResponse []byte
514+
statusCode int
515+
expectedError string
516+
}{
517+
{
518+
name: "ping returns 404 status",
519+
serverResponse: mockEsServerResponseWithVersion0,
520+
statusCode: 404,
521+
expectedError: "ElasticSearch server",
522+
},
523+
{
524+
name: "ping returns 500 status",
525+
serverResponse: mockEsServerResponseWithVersion0,
526+
statusCode: 500,
527+
expectedError: "ElasticSearch server",
528+
},
529+
{
530+
name: "ping returns 300 status",
531+
serverResponse: mockEsServerResponseWithVersion0,
532+
statusCode: 300,
533+
expectedError: "ElasticSearch server",
534+
},
535+
{
536+
name: "ping returns empty version number",
537+
serverResponse: []byte(`{"Version": {"Number": ""}}`),
538+
statusCode: 200,
539+
expectedError: "invalid ping response",
540+
},
541+
542+
{
543+
name: "ping returns valid 200 status with version",
544+
serverResponse: mockEsServerResponseWithVersion0,
545+
statusCode: 200,
546+
expectedError: "",
547+
},
548+
}
549+
550+
for _, test := range tests {
551+
t.Run(test.name, func(t *testing.T) {
552+
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
553+
assert.Contains(t, []string{http.MethodGet, http.MethodHead}, req.Method)
554+
res.WriteHeader(test.statusCode)
555+
res.Write(test.serverResponse)
556+
}))
557+
defer testServer.Close()
558+
559+
config := &Configuration{
560+
Servers: []string{testServer.URL},
561+
LogLevel: "error",
562+
DisableHealthCheck: true,
563+
}
564+
565+
logger := zap.NewNop()
566+
metricsFactory := metrics.NullFactory
567+
client, err := NewClient(context.Background(), config, logger, metricsFactory)
568+
569+
if test.expectedError != "" {
570+
require.Error(t, err)
571+
assert.Contains(t, err.Error(), test.expectedError)
572+
require.Nil(t, client)
573+
} else {
574+
require.NoError(t, err)
575+
require.NotNil(t, client)
576+
err = client.Close()
577+
require.NoError(t, err)
578+
}
579+
})
580+
}
581+
}
582+
583+
func TestNewClientVersionDetection(t *testing.T) {
584+
tests := []struct {
585+
name string
586+
serverResponse []byte
587+
expectedVersion uint
588+
expectedError string
589+
}{
590+
{
591+
name: "version number with letters",
592+
serverResponse: []byte(`{
593+
"Version": {
594+
"Number": "7.x.1"
595+
}
596+
}`),
597+
expectedVersion: 7,
598+
expectedError: "",
599+
},
600+
{
601+
name: "empty version number should fail validation",
602+
serverResponse: []byte(`{
603+
"Version": {
604+
"Number": ""
605+
}
606+
}`),
607+
expectedError: "invalid ping response",
608+
},
609+
{
610+
name: "version number as numeric should fail JSON parsing",
611+
serverResponse: []byte(`{
612+
"Version": {
613+
"Number": 7
614+
}
615+
}`),
616+
expectedError: "cannot unmarshal number",
617+
},
618+
}
619+
620+
for _, test := range tests {
621+
t.Run(test.name, func(t *testing.T) {
622+
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, _ *http.Request) {
623+
res.WriteHeader(http.StatusOK)
624+
res.Write(test.serverResponse)
625+
}))
626+
defer testServer.Close()
627+
628+
config := &Configuration{
629+
Servers: []string{testServer.URL},
630+
LogLevel: "error",
631+
DisableHealthCheck: true,
632+
}
633+
634+
logger := zap.NewNop()
635+
metricsFactory := metrics.NullFactory
636+
client, err := NewClient(context.Background(), config, logger, metricsFactory)
637+
638+
if test.expectedError != "" {
639+
require.Error(t, err)
640+
assert.Contains(t, err.Error(), test.expectedError)
641+
require.Nil(t, client)
642+
} else {
643+
require.NoError(t, err)
644+
require.NotNil(t, client)
645+
assert.Equal(t, test.expectedVersion, config.Version)
646+
err = client.Close()
647+
require.NoError(t, err)
648+
}
649+
})
650+
}
651+
}
652+
510653
func TestApplyDefaults(t *testing.T) {
511654
source := &Configuration{
512655
RemoteReadClusters: []string{"cluster1", "cluster2"},

0 commit comments

Comments
 (0)