Skip to content
This repository was archived by the owner on Aug 31, 2022. It is now read-only.

Commit 90ce4b5

Browse files
Willem BorgesiusWillem Borgesius
authored andcommitted
Add opensearch sink
1 parent 43dde85 commit 90ce4b5

File tree

7 files changed

+196
-0
lines changed

7 files changed

+196
-0
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,37 @@ receivers:
124124
serverName: # optional, the domain, the certificate was issued for, in case it doesn't match the hostname used for the connection
125125
caFile: # optional, path to the CA file of the trusted authority the cert was signed with
126126
```
127+
### OpenSsearch
128+
129+
[OpenSearch](https://opensearch.org/) is a community-driven, open source search and analytics suite derived from Apache 2.0 licensed Elasticsearch 7.10.2 & Kibana 7.10.2.
130+
OpenSearch enables people to easily ingest, secure, search, aggregate, view, and analyze data. These capabilities are popular for use cases such as application search, log analytics, and more.
131+
You may decide to push all events to OpenSearch and do some interesting queries over time to find out
132+
which images are pulled, how often pod schedules happen etc.
133+
134+
```yaml
135+
# ...
136+
receivers:
137+
- name: "dump"
138+
opensearch:
139+
hosts:
140+
- http://localhost:9200
141+
index: kube-events
142+
# Ca be used optionally for time based indices, accepts Go time formatting directives
143+
indexFormat: "kube-events-{2006-01-02}"
144+
username: # optional
145+
password: # optional
146+
# If set to true, it allows updating the same document in ES (might be useful handling count)
147+
useEventID: true|false
148+
# Type should be only used for clusters Version 6 and lower.
149+
# type: kube-event
150+
# If set to true, all dots in labels and annotation keys are replaced by underscores. Defaults false
151+
deDot: true|false
152+
layout: # Optional
153+
tls: # optional, advanced options for tls
154+
insecureSkipVerify: true|false # optional, if set to true, the tls cert won't be verified
155+
serverName: # optional, the domain, the certificate was issued for, in case it doesn't match the hostname used for the connection
156+
caFile: # optional, path to the CA file of the trusted authority the cert was signed with
157+
```
127158
128159
### Slack
129160

config.example.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ receivers:
2727
hosts:
2828
- "http://localhost:9200"
2929
indexFormat: "kube-events-{2006-01-02}"
30+
- name: "opensearch-dump"
31+
opensearch:
32+
hosts:
33+
- "http://localhost:9200"
34+
indexFormat: "kube-events-{2006-01-02}"
3035
- name: "alert"
3136
opsgenie:
3237
apiKey: ""

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/elastic/go-elasticsearch/v7 v7.4.1
1212
github.com/hashicorp/golang-lru v0.5.3
1313
github.com/linkedin/goavro/v2 v2.10.1
14+
github.com/opensearch-project/opensearch-go v1.0.0
1415
github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.3
1516
github.com/rs/zerolog v1.16.0
1617
github.com/slack-go/slack v0.9.1

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9k
245245
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
246246
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
247247
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
248+
github.com/opensearch-project/opensearch-go v1.0.0 h1:8Gh7B7Un5BxuxWAgmzleEF7lpOtC71pCgPp7lKr3ca8=
249+
github.com/opensearch-project/opensearch-go v1.0.0/go.mod h1:FrUl/52DBegRYvK7ISF278AXmjDV647lyTnsLGBR7J4=
248250
github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.3 h1:XAqJ0IIb/Q/mss3OMrXInA6KOQzGOrZRtJIY7qWpSxQ=
249251
github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.3/go.mod h1:f0ezb0R/mrB9Hpm5RrIS6EX3ydjsR2nAB88nYYXZcNY=
250252
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=

pkg/sinks/opensearch.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package sinks
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
opensearch "github.com/opensearch-project/opensearch-go"
9+
opensearchapi "github.com/opensearch-project/opensearch-go/opensearchapi"
10+
"github.com/opsgenie/kubernetes-event-exporter/pkg/kube"
11+
"github.com/rs/zerolog/log"
12+
"io/ioutil"
13+
"net/http"
14+
"regexp"
15+
"strings"
16+
"time"
17+
)
18+
19+
type OpenSearchConfig struct {
20+
// Connection specific
21+
Hosts []string `yaml:"hosts"`
22+
Username string `yaml:"username"`
23+
Password string `yaml:"password"`
24+
// Indexing preferences
25+
UseEventID bool `yaml:"useEventID"`
26+
// DeDot all labels and annotations in the event. For both the event and the involvedObject
27+
DeDot bool `yaml:"deDot"`
28+
Index string `yaml:"index"`
29+
IndexFormat string `yaml:"indexFormat"`
30+
Type string `yaml:"type"`
31+
TLS TLS `yaml:"tls"`
32+
Layout map[string]interface{} `yaml:"layout"`
33+
}
34+
35+
func NewOpenSearch(cfg *OpenSearchConfig) (*OpenSearch, error) {
36+
37+
tlsClientConfig, err := setupTLS(&cfg.TLS)
38+
if err != nil {
39+
return nil, fmt.Errorf("failed to setup TLS: %w", err)
40+
}
41+
42+
client, err := opensearch.NewClient(opensearch.Config{
43+
Addresses: cfg.Hosts,
44+
Username: cfg.Username,
45+
Password: cfg.Password,
46+
Transport: &http.Transport{
47+
TLSClientConfig: tlsClientConfig,
48+
},
49+
})
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
return &OpenSearch{
55+
client: client,
56+
cfg: cfg,
57+
}, nil
58+
}
59+
60+
type OpenSearch struct {
61+
client *opensearch.Client
62+
cfg *OpenSearchConfig
63+
}
64+
65+
var osRegex = regexp.MustCompile(`(?s){(.*)}`)
66+
67+
func osFormatIndexName(pattern string, when time.Time) string {
68+
m := osRegex.FindAllStringSubmatchIndex(pattern, -1)
69+
current := 0
70+
var builder strings.Builder
71+
72+
for i := 0; i < len(m); i++ {
73+
pair := m[i]
74+
75+
builder.WriteString(pattern[current:pair[0]])
76+
builder.WriteString(when.Format(pattern[pair[0]+1 : pair[1]-1]))
77+
current = pair[1]
78+
}
79+
80+
builder.WriteString(pattern[current:])
81+
82+
return builder.String()
83+
}
84+
85+
func (e *OpenSearch) Send(ctx context.Context, ev *kube.EnhancedEvent) error {
86+
var toSend []byte
87+
88+
if e.cfg.DeDot {
89+
de := ev.DeDot()
90+
ev = &de
91+
}
92+
if e.cfg.Layout != nil {
93+
res, err := convertLayoutTemplate(e.cfg.Layout, ev)
94+
if err != nil {
95+
return err
96+
}
97+
98+
toSend, err = json.Marshal(res)
99+
if err != nil {
100+
return err
101+
}
102+
} else {
103+
toSend = ev.ToJSON()
104+
}
105+
106+
var index string
107+
if len(e.cfg.IndexFormat) > 0 {
108+
now := time.Now()
109+
index = osFormatIndexName(e.cfg.IndexFormat, now)
110+
} else {
111+
index = e.cfg.Index
112+
}
113+
114+
req := opensearchapi.IndexRequest{
115+
Body: bytes.NewBuffer(toSend),
116+
Index: index,
117+
}
118+
119+
// This should not be used for clusters with ES8.0+.
120+
if len(e.cfg.Type) > 0 {
121+
req.DocumentType = e.cfg.Type
122+
}
123+
124+
if e.cfg.UseEventID {
125+
req.DocumentID = string(ev.UID)
126+
}
127+
128+
resp, err := req.Do(ctx, e.client)
129+
if err != nil {
130+
return err
131+
}
132+
133+
defer resp.Body.Close()
134+
if resp.StatusCode > 399 {
135+
rb, err := ioutil.ReadAll(resp.Body)
136+
if err != nil {
137+
return err
138+
}
139+
log.Error().Msgf("Indexing failed: %s", string(rb))
140+
}
141+
return nil
142+
}
143+
144+
func (e *OpenSearch) Close() {
145+
// No-op
146+
}

pkg/sinks/receiver.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type ReceiverConfig struct {
1313
Elasticsearch *ElasticsearchConfig `yaml:"elasticsearch"`
1414
Kinesis *KinesisConfig `yaml:"kinesis"`
1515
Firehose *FirehoseConfig `yaml:"firehose"`
16+
OpenSearch *OpenSearchConfig `yaml:"opensearch"`
1617
Opsgenie *OpsgenieConfig `yaml:"opsgenie"`
1718
SQS *SQSConfig `yaml:"sqs"`
1819
SNS *SNSConfig `yaml:"sns"`
@@ -72,6 +73,10 @@ func (r *ReceiverConfig) GetSink() (Sink, error) {
7273
return NewFirehoseSink(r.Firehose)
7374
}
7475

76+
if r.OpenSearch != nil {
77+
return NewOpenSearch(r.OpenSearch)
78+
}
79+
7580
if r.Opsgenie != nil {
7681
return NewOpsgenieSink(r.Opsgenie)
7782
}

vendor/modules.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,12 @@ github.com/modern-go/concurrent
206206
# github.com/modern-go/reflect2 v1.0.1
207207
## explicit
208208
github.com/modern-go/reflect2
209+
# github.com/opensearch-project/opensearch-go v1.0.0
210+
## explicit; go 1.11
211+
github.com/opensearch-project/opensearch-go
212+
github.com/opensearch-project/opensearch-go/internal/version
213+
github.com/opensearch-project/opensearch-go/opensearchapi
214+
github.com/opensearch-project/opensearch-go/opensearchtransport
209215
# github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.3
210216
## explicit; go 1.12
211217
github.com/opsgenie/opsgenie-go-sdk-v2/alert

0 commit comments

Comments
 (0)