Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Dedot for Kubernetes labels and annotations #9939

Merged
merged 31 commits into from
Jan 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
aed6cc6
Never default to a qualifier when none of them are set. (#9148)
ph Nov 19, 2018
07c4fa5
Merge branch 'master' of github.com:kaiyan-sheng/beats
kaiyan-sheng Nov 27, 2018
ff52365
Merge branch 'master' of github.com:kaiyan-sheng/beats
kaiyan-sheng Dec 10, 2018
5f9f575
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 10, 2018
09d8b97
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 10, 2018
141277e
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 13, 2018
276a1de
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 14, 2018
19a705a
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 17, 2018
e54a566
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 18, 2018
edd4488
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 26, 2018
b0d2e22
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 27, 2018
378b4f9
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 28, 2018
1996739
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Dec 28, 2018
1e05766
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 2, 2019
33c130c
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 2, 2019
513bbd0
Merge branch 'master' of github.com:elastic/beats
kaiyan-sheng Jan 3, 2019
c618fd0
Merge branch 'master' of github.com:elastic/beats
kaiyan-sheng Jan 3, 2019
40c8368
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 3, 2019
042c89b
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 3, 2019
97393f4
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 4, 2019
5b300c8
Merge branch 'master' of github.com:elastic/beats
kaiyan-sheng Jan 4, 2019
be995ca
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 7, 2019
b9461c2
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 9, 2019
89f5158
Merge remote-tracking branch 'upstream/master'
kaiyan-sheng Jan 10, 2019
33e4393
Add Dedot for Kubernetes labels and annotations
kaiyan-sheng Jan 8, 2019
23ccfa9
Add dedot options in libbeat kubernetes metadata
kaiyan-sheng Jan 8, 2019
da6aafc
Update changelog
kaiyan-sheng Jan 8, 2019
6e22ef2
Refactor TestGenerateMapStrFromEvent
kaiyan-sheng Jan 8, 2019
0a4a5df
Update shared-autodiscover.asciidoc with dedot params
kaiyan-sheng Jan 9, 2019
3e51fd8
Add names for each unit test case in event_test.go
kaiyan-sheng Jan 9, 2019
da933d8
Fix rebase errors
kaiyan-sheng Jan 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Add `socket_summary` metricset to system defaults, removing experimental tag and supporting Windows {pull}9709[9709]
- Add docker `event` metricset. {pull}9856[9856]
- Add 'performance' metricset to x-pack mssql module {pull}9826[9826]
- Add DeDot for kubernetes labels and annotations. {issue}9860[9860] {pull}9939[9939]

*Packetbeat*

Expand Down
24 changes: 19 additions & 5 deletions libbeat/common/kubernetes/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ type MetaGeneratorConfig struct {

// Undocumented settings, to be deprecated in favor of `drop_fields` processor:
IncludeCreatorMetadata bool `config:"include_creator_metadata"`
LabelsDedot bool `config:"labels.dedot"`
AnnotationsDedot bool `config:"annotations.dedot"`
}

type metaGenerator = MetaGeneratorConfig
Expand All @@ -53,6 +55,8 @@ func NewMetaGenerator(cfg *common.Config) (MetaGenerator, error) {
// default settings:
generator := metaGenerator{
IncludeCreatorMetadata: true,
LabelsDedot: false,
AnnotationsDedot: false,
}

err := cfg.Unpack(&generator)
Expand All @@ -70,18 +74,23 @@ func (g *metaGenerator) ResourceMetadata(obj Resource) common.MapStr {
labelMap := common.MapStr{}
if len(g.IncludeLabels) == 0 {
for k, v := range obj.GetMetadata().Labels {
safemapstr.Put(labelMap, k, v)
if g.LabelsDedot {
label := common.DeDot(k)
labelMap.Put(label, v)
} else {
safemapstr.Put(labelMap, k, v)
}
}
} else {
labelMap = generateMapSubset(objMeta.Labels, g.IncludeLabels)
labelMap = generateMapSubset(objMeta.Labels, g.IncludeLabels, g.LabelsDedot)
}

// Exclude any labels that are present in the exclude_labels config
for _, label := range g.ExcludeLabels {
delete(labelMap, label)
}

annotationsMap := generateMapSubset(objMeta.Annotations, g.IncludeAnnotations)
annotationsMap := generateMapSubset(objMeta.Annotations, g.IncludeAnnotations, g.AnnotationsDedot)
meta := common.MapStr{}
if objMeta.GetNamespace() != "" {
meta["namespace"] = objMeta.GetNamespace()
Expand Down Expand Up @@ -136,7 +145,7 @@ func (g *metaGenerator) ContainerMetadata(pod *Pod, container string) common.Map
return podMeta
}

func generateMapSubset(input map[string]string, keys []string) common.MapStr {
func generateMapSubset(input map[string]string, keys []string, dedot bool) common.MapStr {
output := common.MapStr{}
if input == nil {
return output
Expand All @@ -145,7 +154,12 @@ func generateMapSubset(input map[string]string, keys []string) common.MapStr {
for _, key := range keys {
value, ok := input[key]
if ok {
safemapstr.Put(output, key, value)
if dedot {
dedotKey := common.DeDot(key)
output.Put(dedotKey, value)
} else {
safemapstr.Put(output, key, value)
}
}
}

Expand Down
87 changes: 86 additions & 1 deletion libbeat/common/kubernetes/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"github.com/elastic/beats/libbeat/common"
)

func TestPodMetadataDeDot(t *testing.T) {
func TestPodMetadata(t *testing.T) {
UID := "005f3b90-4b9d-12f8-acf0-31020a840133"
Deployment := "Deployment"
test := "test"
Expand Down Expand Up @@ -104,3 +104,88 @@ func TestPodMetadataDeDot(t *testing.T) {
assert.Equal(t, metaGen.PodMetadata(test.pod), test.meta)
}
}

func TestPodMetadataDeDot(t *testing.T) {
UID := "005f3b90-4b9d-12f8-acf0-31020a840133"
Deployment := "Deployment"
test := "test"
ReplicaSet := "ReplicaSet"
True := true
False := false
tests := []struct {
pod *Pod
meta common.MapStr
config *common.Config
}{
{
pod: &Pod{
Metadata: &metav1.ObjectMeta{
Labels: map[string]string{"a.key": "foo", "a": "bar"},
Uid: &UID,
Namespace: &test,
Annotations: map[string]string{"b.key": "foo", "b": "bar"},
},
Spec: &v1.PodSpec{
NodeName: &test,
},
},
meta: common.MapStr{
"pod": common.MapStr{
"name": "",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
},
"node": common.MapStr{"name": "test"},
"namespace": "test",
"labels": common.MapStr{"a": "bar", "a_key": "foo"},
"annotations": common.MapStr{"b": "bar", "b_key": "foo"},
},
config: common.NewConfig(),
},
{
pod: &Pod{
Metadata: &metav1.ObjectMeta{
Labels: map[string]string{"a.key": "foo", "a": "bar"},
Uid: &UID,
OwnerReferences: []*metav1.OwnerReference{
{
Kind: &Deployment,
Name: &test,
Controller: &True,
},
{
Kind: &ReplicaSet,
Name: &ReplicaSet,
Controller: &False,
},
},
},
Spec: &v1.PodSpec{
NodeName: &test,
},
},
meta: common.MapStr{
"pod": common.MapStr{
"name": "",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
},
"node": common.MapStr{"name": "test"},
"labels": common.MapStr{"a": "bar", "a_key": "foo"},
"deployment": common.MapStr{"name": "test"},
},
config: common.NewConfig(),
},
}

for _, test := range tests {
config, err := common.NewConfigFrom(map[string]interface{}{
"labels.dedot": true,
"annotations.dedot": true,
"include_annotations": []string{"b", "b.key"},
})
metaGen, err := NewMetaGenerator(config)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, metaGen.PodMetadata(test.pod), test.meta)
}
}
12 changes: 12 additions & 0 deletions libbeat/docs/shared-autodiscover.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,18 @@ event:
If the `include_annotations` config is added to the provider config, then the list of annotations present in the config
are added to the event.

If the `include_labels` config is added to the provider config, then the list of labels present in the config
will be added to the event.

If the `exclude_labels` config is added to the provider config, then the list of labels present in the config
will be excluded from the event.

if the `labels.dedot` config is set to be `true` in the provider config, then `.` in labels will be replaced with `_`.

if the `annotations.dedot` config is set to be `true` in the provider config, then `.` in annotations will be replaced
with `_`.


For example:

[source,yaml]
Expand Down
2 changes: 2 additions & 0 deletions metricbeat/module/kubernetes/_meta/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
# Enriching parameters:
#add_metadata: true
#in_cluster: true
#labels.dedot: false
#annotations.dedot: false
# When used outside the cluster:
#in_cluster: false
#host: node_name
Expand Down
16 changes: 10 additions & 6 deletions metricbeat/module/kubernetes/event/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ import (
)

type kubeEventsConfig struct {
InCluster bool `config:"in_cluster"`
KubeConfig string `config:"kube_config"`
Namespace string `config:"namespace"`
SyncPeriod time.Duration `config:"sync_period"`
InCluster bool `config:"in_cluster"`
KubeConfig string `config:"kube_config"`
Namespace string `config:"namespace"`
SyncPeriod time.Duration `config:"sync_period"`
LabelsDedot bool `config:"labels.dedot"`
AnnotationsDedot bool `config:"annotations.dedot"`
}

type Enabled struct {
Expand All @@ -35,8 +37,10 @@ type Enabled struct {

func defaultKubernetesEventsConfig() kubeEventsConfig {
return kubeEventsConfig{
InCluster: true,
SyncPeriod: 1 * time.Second,
InCluster: true,
SyncPeriod: 1 * time.Second,
LabelsDedot: false,
AnnotationsDedot: false,
}
}

Expand Down
44 changes: 36 additions & 8 deletions metricbeat/module/kubernetes/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,16 @@ func init() {
// MetricSet implements the mb.PushMetricSet interface, and therefore does not rely on polling.
type MetricSet struct {
mb.BaseMetricSet
watcher kubernetes.Watcher
watcher kubernetes.Watcher
watchOptions kubernetes.WatchOptions
dedotConfig dedotConfig
}

// dedotConfig defines LabelsDedot and AnnotationsDedot.
// Default to be false. If set to true, replace dots in labels with `_`.
type dedotConfig struct {
LabelsDedot bool `config:"labels.dedot"`
AnnotationsDedot bool `config:"annotations.dedot"`
}

// New create a new instance of the MetricSet
Expand All @@ -62,17 +71,26 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
return nil, fmt.Errorf("fail to get kubernetes client: %s", err.Error())
}

watcher, err := kubernetes.NewWatcher(client, &kubernetes.Event{}, kubernetes.WatchOptions{
watchOptions := kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
Namespace: config.Namespace,
})
}

watcher, err := kubernetes.NewWatcher(client, &kubernetes.Event{}, watchOptions)
if err != nil {
return nil, fmt.Errorf("fail to init kubernetes watcher: %s", err.Error())
}

dedotConfig := dedotConfig{
LabelsDedot: config.LabelsDedot,
AnnotationsDedot: config.AnnotationsDedot,
}

return &MetricSet{
BaseMetricSet: base,
dedotConfig: dedotConfig,
watcher: watcher,
watchOptions: watchOptions,
}, nil
}

Expand All @@ -81,10 +99,10 @@ func (m *MetricSet) Run(reporter mb.PushReporter) {
now := time.Now()
handler := kubernetes.ResourceEventHandlerFuncs{
AddFunc: func(obj kubernetes.Resource) {
reporter.Event(generateMapStrFromEvent(obj.(*kubernetes.Event)))
reporter.Event(generateMapStrFromEvent(obj.(*kubernetes.Event), m.dedotConfig))
},
UpdateFunc: func(obj kubernetes.Resource) {
reporter.Event(generateMapStrFromEvent(obj.(*kubernetes.Event)))
reporter.Event(generateMapStrFromEvent(obj.(*kubernetes.Event), m.dedotConfig))
},
// ignore events that are deleted
DeleteFunc: nil,
Expand All @@ -107,7 +125,7 @@ func (m *MetricSet) Run(reporter mb.PushReporter) {
return
}

func generateMapStrFromEvent(eve *kubernetes.Event) common.MapStr {
func generateMapStrFromEvent(eve *kubernetes.Event, dedotConfig dedotConfig) common.MapStr {
eventMeta := common.MapStr{
"timestamp": common.MapStr{
"created": kubernetes.Time(eve.Metadata.CreationTimestamp).UTC(),
Expand All @@ -123,7 +141,12 @@ func generateMapStrFromEvent(eve *kubernetes.Event) common.MapStr {
if len(eve.Metadata.Labels) != 0 {
labels := make(common.MapStr, len(eve.Metadata.Labels))
for k, v := range eve.Metadata.Labels {
safemapstr.Put(labels, k, v)
if dedotConfig.LabelsDedot {
label := common.DeDot(k)
labels.Put(label, v)
} else {
safemapstr.Put(labels, k, v)
}
}

eventMeta["labels"] = labels
Expand All @@ -132,7 +155,12 @@ func generateMapStrFromEvent(eve *kubernetes.Event) common.MapStr {
if len(eve.Metadata.Annotations) != 0 {
annotations := make(common.MapStr, len(eve.Metadata.Annotations))
for k, v := range eve.Metadata.Annotations {
safemapstr.Put(annotations, k, v)
if dedotConfig.AnnotationsDedot {
annotation := common.DeDot(k)
annotations.Put(annotation, v)
} else {
safemapstr.Put(annotations, k, v)
}
}

eventMeta["annotations"] = annotations
Expand Down
Loading