diff --git a/cmd/es-rollover/app/init/action.go b/cmd/es-rollover/app/init/action.go index b7a1b2df0b13..e57344ff7b33 100644 --- a/cmd/es-rollover/app/init/action.go +++ b/cmd/es-rollover/app/init/action.go @@ -79,6 +79,32 @@ func (c Action) Do() error { return nil } +func createIndexIfNotExist(c client.IndexAPI, index string) error { + err := c.CreateIndex(index) + if err != nil { + if esErr, ok := err.(client.ResponseError); ok { + if esErr.StatusCode != http.StatusBadRequest || esErr.Body == nil { + return err + } + // check for the reason of the error + jsonError := map[string]interface{}{} + err := json.Unmarshal(esErr.Body, &jsonError) + if err != nil { + // return unmarshal error + return err + } + errorMap := jsonError["error"].(map[string]interface{}) + // check for reason, ignore already exist error + if strings.Contains("resource_already_exists_exception", errorMap["type"].(string)) { + return nil + } + } + // Return any other error unrelated the he response + return err + } + return nil +} + func (c Action) init(version uint, indexset app.IndexOption) error { mapping, err := c.getMapping(version, indexset.TemplateName) if err != nil { @@ -89,22 +115,11 @@ func (c Action) init(version uint, indexset app.IndexOption) error { if err != nil { return err } - index := indexset.InitialRolloverIndex() - err = c.IndicesClient.CreateIndex(index) - if esErr, ok := err.(client.ResponseError); ok { - if esErr.StatusCode == http.StatusBadRequest && esErr.Body != nil { - jsonError := map[string]interface{}{} - err := json.Unmarshal(esErr.Body, &jsonError) - if err != nil { - return err - } - errorMap := jsonError["error"].(map[string]interface{}) - // Ignore already exist error - if !strings.Contains("resource_already_exists_exception", errorMap["type"].(string)) { - return err - } - } + index := indexset.InitialRolloverIndex() + err = createIndexIfNotExist(c.IndicesClient, index) + if err != nil { + return err } jaegerIndices, err := c.IndicesClient.GetJaegerIndices(c.Config.IndexPrefix) diff --git a/cmd/es-rollover/app/init/action_test.go b/cmd/es-rollover/app/init/action_test.go new file mode 100644 index 000000000000..7ff9bb17d705 --- /dev/null +++ b/cmd/es-rollover/app/init/action_test.go @@ -0,0 +1,191 @@ +// Copyright (c) 2021 The Jaeger Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package init + +import ( + "errors" + "testing" + + "github.com/crossdock/crossdock-go/assert" + "github.com/stretchr/testify/mock" + + "github.com/jaegertracing/jaeger/cmd/es-rollover/app" + "github.com/jaegertracing/jaeger/pkg/es/client" + "github.com/jaegertracing/jaeger/pkg/es/client/mocks" +) + +func TestRolloverAction(t *testing.T) { + tests := []struct { + name string + setupCallExpectations func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) + config Config + expectedErr error + }{ + + { + name: "Unsupported version", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(5), nil) + }, + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: true, + }, + }, + expectedErr: errors.New("ILM is supported only for ES version 7+"), + }, + { + name: "error getting version", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(0), errors.New("version error")) + }, + expectedErr: errors.New("version error"), + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: true, + }, + }, + }, + { + name: "ilm doesnt exist", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(7), nil) + ilmClient.On("Exists", "myilmpolicy").Return(false, nil) + }, + expectedErr: errors.New("ILM policy myilmpolicy doesn't exist in Elasticsearch. Please create it and re-run init"), + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: true, + ILMPolicyName: "myilmpolicy", + }, + }, + }, + { + name: "fail get ilm policy", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(7), nil) + ilmClient.On("Exists", "myilmpolicy").Return(false, errors.New("error getting ilm policy")) + }, + expectedErr: errors.New("error getting ilm policy"), + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: true, + ILMPolicyName: "myilmpolicy", + }, + }, + }, + { + name: "fail to create template", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(7), nil) + indexClient.On("CreateTemplate", mock.Anything, "jaeger-span").Return(errors.New("error creating template")) + }, + expectedErr: errors.New("error creating template"), + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: false, + }, + }, + }, + { + name: "fail to get jaeger indices", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(7), nil) + indexClient.On("CreateTemplate", mock.Anything, "jaeger-span").Return(nil) + indexClient.On("CreateIndex", "jaeger-span-archive-000001").Return(nil) + indexClient.On("GetJaegerIndices", "").Return([]client.Index{}, errors.New("error getting jaeger indices")) + }, + expectedErr: errors.New("error getting jaeger indices"), + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: false, + }, + }, + }, + { + name: "fail to create alias", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(7), nil) + indexClient.On("CreateTemplate", mock.Anything, "jaeger-span").Return(nil) + indexClient.On("CreateIndex", "jaeger-span-archive-000001").Return(nil) + indexClient.On("GetJaegerIndices", "").Return([]client.Index{}, nil) + indexClient.On("CreateAlias", []client.Alias{ + {Index: "jaeger-span-archive-000001", Name: "jaeger-span-archive-read", IsWriteIndex: false}, + {Index: "jaeger-span-archive-000001", Name: "jaeger-span-archive-write", IsWriteIndex: true}, + }).Return(errors.New("error creating aliases")) + }, + expectedErr: errors.New("error creating aliases"), + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: false, + }, + }, + }, + { + name: "create rollover index", + setupCallExpectations: func(indexClient *mocks.MockIndexAPI, clusterClient *mocks.MockClusterAPI, ilmClient *mocks.MockILMAPI) { + clusterClient.On("Version").Return(uint(7), nil) + indexClient.On("CreateTemplate", mock.Anything, "jaeger-span").Return(nil) + indexClient.On("CreateIndex", "jaeger-span-archive-000001").Return(nil) + indexClient.On("GetJaegerIndices", "").Return([]client.Index{}, nil) + indexClient.On("CreateAlias", []client.Alias{ + {Index: "jaeger-span-archive-000001", Name: "jaeger-span-archive-read", IsWriteIndex: false}, + {Index: "jaeger-span-archive-000001", Name: "jaeger-span-archive-write", IsWriteIndex: true}, + }).Return(nil) + + }, + expectedErr: nil, + config: Config{ + Config: app.Config{ + Archive: true, + UseILM: false, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + indexClient := &mocks.MockIndexAPI{} + clusterClient := &mocks.MockClusterAPI{} + ilmClient := &mocks.MockILMAPI{} + initAction := Action{ + Config: test.config, + IndicesClient: indexClient, + ClusterClient: clusterClient, + ILMClient: ilmClient, + } + + test.setupCallExpectations(indexClient, clusterClient, ilmClient) + + err := initAction.Do() + if test.expectedErr != nil { + assert.Error(t, err) + assert.Equal(t, test.expectedErr, err) + } + + indexClient.AssertExpectations(t) + clusterClient.AssertExpectations(t) + ilmClient.AssertExpectations(t) + }) + } +} diff --git a/cmd/es-rollover/app/rollover/action_test.go b/cmd/es-rollover/app/rollover/action_test.go index c2303974d921..e8724f6d63f4 100644 --- a/cmd/es-rollover/app/rollover/action_test.go +++ b/cmd/es-rollover/app/rollover/action_test.go @@ -19,6 +19,7 @@ import ( "testing" "github.com/crossdock/crossdock-go/assert" + "github.com/jaegertracing/jaeger/cmd/es-rollover/app" "github.com/jaegertracing/jaeger/pkg/es/client" "github.com/jaegertracing/jaeger/pkg/es/client/mocks" diff --git a/pkg/es/client/interfaces.go b/pkg/es/client/interfaces.go index 93e5f221781b..9ea6fcff31f0 100644 --- a/pkg/es/client/interfaces.go +++ b/pkg/es/client/interfaces.go @@ -1,3 +1,17 @@ +// Copyright (c) 2021 The Jaeger Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package client type IndexAPI interface { diff --git a/pkg/es/client/mocks/cluter_client.go b/pkg/es/client/mocks/cluter_client.go new file mode 100644 index 000000000000..37137b8ffde0 --- /dev/null +++ b/pkg/es/client/mocks/cluter_client.go @@ -0,0 +1,28 @@ +// Copyright (c) 2021 The Jaeger Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mocks + +import ( + "github.com/stretchr/testify/mock" +) + +type MockClusterAPI struct { + mock.Mock +} + +func (c *MockClusterAPI) Version() (uint, error) { + ret := c.Called() + return ret.Get(0).(uint), ret.Error(1) +} diff --git a/pkg/es/client/mocks/ilm_client.go b/pkg/es/client/mocks/ilm_client.go new file mode 100644 index 000000000000..0602f13a1bcb --- /dev/null +++ b/pkg/es/client/mocks/ilm_client.go @@ -0,0 +1,26 @@ +// Copyright (c) 2021 The Jaeger Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mocks + +import "github.com/stretchr/testify/mock" + +type MockILMAPI struct { + mock.Mock +} + +func (c *MockILMAPI) Exists(name string) (bool, error) { + ret := c.Called(name) + return ret.Get(0).(bool), ret.Error(1) +} diff --git a/pkg/es/client/mocks/index_client.go b/pkg/es/client/mocks/index_client.go index 51fbf6ef583c..1382b3e7f89a 100644 --- a/pkg/es/client/mocks/index_client.go +++ b/pkg/es/client/mocks/index_client.go @@ -15,8 +15,9 @@ package mocks import ( - "github.com/jaegertracing/jaeger/pkg/es/client" "github.com/stretchr/testify/mock" + + "github.com/jaegertracing/jaeger/pkg/es/client" ) type MockIndexAPI struct {