Skip to content

Commit 35ae71b

Browse files
committed
feat: Support elasticsearch data stream
Signed-off-by: zzzk1 <[email protected]>
1 parent 2ee8e4c commit 35ae71b

File tree

7 files changed

+233
-4
lines changed

7 files changed

+233
-4
lines changed

cmd/es-rollover/app/flags.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func AddFlags(flags *flag.FlagSet) {
4747
flags.Bool(archive, false, "Handle archive indices")
4848
flags.String(username, "", "The username required by storage")
4949
flags.String(password, "", "The password required by storage")
50-
flags.Bool(useILM, false, "Use ILM to manage jaeger indices")
50+
flags.Bool(useILM, true, "Use ILM to manage jaeger indices")
5151
flags.String(ilmPolicyName, "jaeger-ilm-policy", "The name of the ILM policy to use if ILM is active")
5252
flags.Int(timeout, 120, "Number of seconds to wait for master node response")
5353
flags.Bool(skipDependencies, false, "Disable rollover for dependencies index")

cmd/es-rollover/app/init/action.go

+64-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"net/http"
1111
"strings"
1212

13+
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
14+
1315
"github.com/jaegertracing/jaeger/cmd/es-rollover/app"
1416
"github.com/jaegertracing/jaeger/pkg/es"
1517
"github.com/jaegertracing/jaeger/pkg/es/client"
@@ -56,7 +58,10 @@ func (c Action) Do() error {
5658
return err
5759
}
5860
if !policyExist {
59-
return fmt.Errorf("ILM policy %s doesn't exist in Elasticsearch. Please create it and re-run init", c.Config.ILMPolicyName)
61+
err := createDefaultILMPolicy(c.ILMClient, c.Config.ILMPolicyName)
62+
if err != nil {
63+
return fmt.Errorf("ILM policy %s Create/Update failed %w", c.Config.ILMPolicyName, err)
64+
}
6065
}
6166
}
6267
rolloverIndices := app.RolloverIndices(c.Config.Archive, c.Config.SkipDependencies, c.Config.AdaptiveSampling, c.Config.Config.IndexPrefix)
@@ -68,6 +73,64 @@ func (c Action) Do() error {
6873
return nil
6974
}
7075

76+
const esILMPolicy = `
77+
{
78+
"policy": {
79+
"phases": {
80+
"hot": {
81+
"min_age": "9999ms",
82+
"actions": {
83+
"rollover": {
84+
"max_age": "1m"
85+
},
86+
"set_priority": {
87+
"priority": 9999
88+
}
89+
}
90+
},
91+
"delete": {
92+
"min_age": "9999m",
93+
"actions": {
94+
"delete": {}
95+
}
96+
}
97+
}
98+
}
99+
}
100+
`
101+
102+
func createDefaultILMPolicy(c client.IndexManagementLifecycleAPI, policy string) error {
103+
ilmPolicy := types.NewIlmPolicy()
104+
err := json.Unmarshal([]byte(esILMPolicy), ilmPolicy)
105+
if err != nil {
106+
return fmt.Errorf("error unmarshalling ILM policy: %w", err)
107+
}
108+
err = c.CreateOrUpdate(policy, client.Policy{ILMPolicy: *ilmPolicy})
109+
if err != nil {
110+
var esErr client.ResponseError
111+
if errors.As(err, &esErr) {
112+
if esErr.StatusCode != http.StatusBadRequest || esErr.Body == nil {
113+
return esErr.Err
114+
}
115+
// check for the reason of the error
116+
jsonError := map[string]any{}
117+
err := json.Unmarshal(esErr.Body, &jsonError)
118+
if err != nil {
119+
// return unmarshal error
120+
return err
121+
}
122+
errorMap := jsonError["error"].(map[string]any)
123+
// check for reason, ignore already exist error
124+
if strings.Contains(errorMap["type"].(string), "resource_already_exists_exception") {
125+
return nil
126+
}
127+
}
128+
// Return any other error unrelated to the response
129+
return err
130+
}
131+
return nil
132+
}
133+
71134
func createIndexIfNotExist(c client.IndexAPI, index string) error {
72135
err := c.CreateIndex(index)
73136
if err != nil {

pkg/es/client/ilm_client.go

+32
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
package client
55

66
import (
7+
"encoding/json"
78
"errors"
89
"fmt"
910
"net/http"
11+
12+
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
1013
)
1114

1215
var _ IndexManagementLifecycleAPI = (*ILMClient)(nil)
@@ -17,6 +20,35 @@ type ILMClient struct {
1720
MasterTimeoutSeconds int
1821
}
1922

23+
type Policy struct {
24+
ILMPolicy types.IlmPolicy `json:"policy"`
25+
}
26+
27+
// CreateOrUpdate Add or update a ILMPolicy
28+
func (i ILMClient) CreateOrUpdate(name string, ilmPolicy Policy) error {
29+
body, err := json.Marshal(ilmPolicy)
30+
if err != nil {
31+
return err
32+
}
33+
_, err = i.request(elasticRequest{
34+
endpoint: "_ilm/policy/" + name,
35+
body: body,
36+
method: http.MethodPut,
37+
})
38+
39+
var respError ResponseError
40+
if errors.As(err, &respError) {
41+
if respError.StatusCode == http.StatusNotFound {
42+
return nil
43+
}
44+
}
45+
46+
if err != nil {
47+
return fmt.Errorf("failed to create/update ILM policy: %s, %w", name, err)
48+
}
49+
return nil
50+
}
51+
2052
// Exists verify if a ILM policy exists
2153
func (i ILMClient) Exists(name string) (bool, error) {
2254
_, err := i.request(elasticRequest{

pkg/es/client/ilm_client_test.go

+77
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
package client
55

66
import (
7+
"encoding/json"
8+
"fmt"
79
"net/http"
810
"net/http/httptest"
911
"strings"
1012
"testing"
1113

14+
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
1215
"github.com/stretchr/testify/assert"
1316
"github.com/stretchr/testify/require"
1417
)
@@ -64,3 +67,77 @@ func TestExists(t *testing.T) {
6467
})
6568
}
6669
}
70+
71+
const esILMPolicy = `
72+
{
73+
"policy": {
74+
"phases": {
75+
"hot": {
76+
"min_age": "0ms",
77+
"actions": {
78+
"rollover": {
79+
"max_age": "1m"
80+
},
81+
"set_priority": {
82+
"priority": 100
83+
}
84+
}
85+
},
86+
"delete": {
87+
"min_age": "2m",
88+
"actions": {
89+
"delete": {}
90+
}
91+
}
92+
}
93+
}
94+
}
95+
`
96+
97+
func TestCreate(t *testing.T) {
98+
policy := "jaeger-ilm-policy"
99+
tests := []struct {
100+
name string
101+
responseCode int
102+
response string
103+
errContains string
104+
}{
105+
{
106+
name: "successful",
107+
responseCode: http.StatusOK,
108+
},
109+
{
110+
name: "client error",
111+
responseCode: http.StatusBadRequest,
112+
response: esErrResponse,
113+
errContains: "failed to create/update ILM policy: jaeger-ilm-policy",
114+
},
115+
}
116+
for _, test := range tests {
117+
t.Run(test.name, func(t *testing.T) {
118+
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
119+
assert.True(t, strings.HasSuffix(req.URL.String(), "_ilm/policy/jaeger-ilm-policy"))
120+
assert.Equal(t, http.MethodPut, req.Method)
121+
res.WriteHeader(test.responseCode)
122+
res.Write([]byte(test.response))
123+
}))
124+
defer testServer.Close()
125+
126+
c := &ILMClient{
127+
Client: Client{
128+
Client: testServer.Client(),
129+
Endpoint: testServer.URL,
130+
BasicAuth: "foobar",
131+
},
132+
}
133+
ilmPolicy := types.NewIlmPolicy()
134+
json.Unmarshal([]byte(esILMPolicy), ilmPolicy)
135+
fmt.Printf("%+v\n", *ilmPolicy)
136+
137+
err := c.CreateOrUpdate(policy, Policy{ILMPolicy: *ilmPolicy})
138+
if test.errContains != "" {
139+
require.ErrorContains(t, err, test.errContains)
140+
}
141+
})
142+
}
143+
}

pkg/es/client/interfaces.go

+1
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ type ClusterAPI interface {
1919

2020
type IndexManagementLifecycleAPI interface {
2121
Exists(name string) (bool, error)
22+
CreateOrUpdate(policy string, ilmPolicy Policy) error
2223
}

pkg/es/client/mocks/IndexManagementLifecycleAPI.go

+22-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugin/storage/integration/elasticsearch_test.go

+36-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const (
4444
dependenciesTemplateName = "jaeger-dependencies"
4545
primaryNamespace = "es"
4646
archiveNamespace = "es-archive"
47+
ilmPolicy = "jaeger-ilm-policy"
4748
)
4849

4950
type ESStorageIntegration struct {
@@ -110,7 +111,7 @@ func (*ESStorageIntegration) initializeESFactory(t *testing.T, allTagsAsFields b
110111
fmt.Sprintf("--es.num-shards=%v", 5),
111112
fmt.Sprintf("--es.num-replicas=%v", 1),
112113
fmt.Sprintf("--es.index-prefix=%v", indexPrefix),
113-
fmt.Sprintf("--es.use-ilm=%v", false),
114+
fmt.Sprintf("--es.use-ilm=%v", true),
114115
fmt.Sprintf("--es.service-cache-ttl=%v", 1*time.Second),
115116
fmt.Sprintf("--es.tags-as-fields.all=%v", allTagsAsFields),
116117
fmt.Sprintf("--es.bulk.actions=%v", 1),
@@ -245,3 +246,37 @@ func (s *ESStorageIntegration) cleanESIndexTemplates(t *testing.T, prefix string
245246
}
246247
return nil
247248
}
249+
250+
func TestElasticsearchStorage_ILMPolicy(t *testing.T) {
251+
SkipUnlessEnv(t, "elasticsearch", "opensearch")
252+
t.Cleanup(func() {
253+
testutils.VerifyGoLeaksOnceForES(t)
254+
})
255+
c := getESHttpClient(t)
256+
require.NoError(t, healthCheck(c))
257+
s := &ESStorageIntegration{}
258+
s.initializeES(t, c, true)
259+
esVersion, err := s.getVersion()
260+
require.NoError(t, err)
261+
if esVersion == 8 {
262+
request := s.v8Client.ILM.GetLifecycle.WithPolicy(ilmPolicy)
263+
ilmPolicyExistsResponse, err := s.v8Client.ILM.GetLifecycle(request)
264+
require.NoError(t, err)
265+
assert.Equal(t, 200, ilmPolicyExistsResponse.StatusCode)
266+
} else {
267+
// nothing
268+
}
269+
s.cleanEsILMPolicy(t, ilmPolicy)
270+
}
271+
272+
func (s *ESStorageIntegration) cleanEsILMPolicy(t *testing.T, policy string) error {
273+
version, err := s.getVersion()
274+
require.NoError(t, err)
275+
if version == 8 {
276+
_, err := s.v8Client.ILM.RemovePolicy(ilmPolicy)
277+
require.NoError(t, err)
278+
} else {
279+
// nothing
280+
}
281+
return nil
282+
}

0 commit comments

Comments
 (0)