diff --git a/README.md b/README.md index 98cc951d..1505a639 100644 --- a/README.md +++ b/README.md @@ -186,8 +186,8 @@ receivers: hosts: - http://localhost:9200 index: kube-events - # Ca be used optionally for time based indices, accepts Go time formatting directives - indexFormat: "kube-events-{2006-01-02}" + # Can be used optionally for time based indices, accepts templates and Go time formatting directives + indexFormat: "kube-events-{{ .InvolvedObject.Namespace }}-{2006-01-02}" username: # optional password: # optional # If set to true, it allows updating the same document in ES (might be useful handling count) diff --git a/pkg/sinks/opensearch.go b/pkg/sinks/opensearch.go index 6f58507d..ff59f202 100644 --- a/pkg/sinks/opensearch.go +++ b/pkg/sinks/opensearch.go @@ -65,7 +65,14 @@ type OpenSearch struct { var osRegex = regexp.MustCompile(`(?s){(.*)}`) -func osFormatIndexName(pattern string, when time.Time) string { +func osFormatIndexName(newpattern string, when time.Time, ev *kube.EnhancedEvent) (string, error) { + // expand values from the event before adding the timestamps + pattern, err := GetString(ev, newpattern) + + if err != nil { + return "", err + } + m := osRegex.FindAllStringSubmatchIndex(pattern, -1) current := 0 var builder strings.Builder @@ -80,7 +87,7 @@ func osFormatIndexName(pattern string, when time.Time) string { builder.WriteString(pattern[current:]) - return builder.String() + return builder.String(), nil } func (e *OpenSearch) Send(ctx context.Context, ev *kube.EnhancedEvent) error { @@ -107,7 +114,11 @@ func (e *OpenSearch) Send(ctx context.Context, ev *kube.EnhancedEvent) error { var index string if len(e.cfg.IndexFormat) > 0 { now := time.Now() - index = osFormatIndexName(e.cfg.IndexFormat, now) + var err error + index, err = osFormatIndexName(e.cfg.IndexFormat, now, ev) + if err != nil { + return err + } } else { index = e.cfg.Index } diff --git a/pkg/sinks/opensearch_test.go b/pkg/sinks/opensearch_test.go new file mode 100644 index 00000000..e7771087 --- /dev/null +++ b/pkg/sinks/opensearch_test.go @@ -0,0 +1,63 @@ +package sinks + +import ( + "fmt" + "testing" + "time" + + "github.com/resmoio/kubernetes-event-exporter/pkg/kube" + "github.com/stretchr/testify/assert" +) + +func makeTestEvent() *kube.EnhancedEvent { + ev := &kube.EnhancedEvent{} + ev.Namespace = "default" + ev.Type = "Warning" + ev.InvolvedObject.Kind = "Pod" + ev.InvolvedObject.Name = "nginx-server-123abc-456def" + ev.Message = "Successfully pulled image \"nginx:latest\"" + return ev +} + +func TestOpenSearch_LegacyTime(t *testing.T) { + p := "legacy-time-pattern-{2006-01-02}" + ev := makeTestEvent() + w := time.Now() + + r, err := osFormatIndexName(p, w, ev) + + assert.Nil(t, err) + assert.Equal(t, fmt.Sprintf("legacy-time-pattern-%d-%02d-%02d", w.Year(), w.Month(), w.Day()), r) +} + +func TestOpenSearch_JustEventInfo(t *testing.T) { + p := "{{ .Namespace }}-{{ .InvolvedObject.Kind }}-static" + ev := makeTestEvent() + w := time.Now() + + r, err := osFormatIndexName(p, w, ev) + + assert.Nil(t, err) + assert.Equal(t, "default-Pod-static", r) +} + +func TestOpenSearch_EventAndTime(t *testing.T) { + p := "{{ .Namespace }}-{2006-01-02}-{{ .Type }}" + ev := makeTestEvent() + w := time.Now() + + r, err := osFormatIndexName(p, w, ev) + + assert.Nil(t, err) + assert.Equal(t, fmt.Sprintf("default-%d-%02d-%02d-Warning", w.Year(), w.Month(), w.Day()), r) +} + +func TestOpenSearch_InvalidEvent(t *testing.T) { + p := "{{ .NotPresent }}-{2006-01-02}" + ev := makeTestEvent() + w := time.Now() + + _, err := osFormatIndexName(p, w, ev) + + assert.ErrorContains(t, err, "can't evaluate field NotPresent") +}