diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 68190008693..ccd4c3e8f58 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -30,6 +30,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d - `include_matches` option of `journald` input no longer accepts a list of string. {pull}29294[29294] - Add job.name in pods controlled by Jobs {pull}28954[28954] - Change Docker base image from CentOS 7 to Ubuntu 20.04 {pull}29681[29681] +- Enrich kubernetes metadata with node annotations. {pull}29605[29605] *Auditbeat* diff --git a/libbeat/common/kubernetes/metadata/metadata.go b/libbeat/common/kubernetes/metadata/metadata.go index eb55856081b..618a914ab69 100644 --- a/libbeat/common/kubernetes/metadata/metadata.go +++ b/libbeat/common/kubernetes/metadata/metadata.go @@ -72,11 +72,16 @@ func WithFields(key string, value interface{}) FieldOptions { } } -// WithLabels FieldOption allows adding labels under sub-resource(kind) +// WithMetadata FieldOption allows adding labels and annotations under sub-resource(kind) // example if kind=namespace namespace.labels key will be added -func WithLabels(kind string) FieldOptions { +func WithMetadata(kind string) FieldOptions { return func(meta common.MapStr) { - safemapstr.Put(meta, strings.ToLower(kind)+".labels", meta["labels"]) + if meta["labels"] != nil { + safemapstr.Put(meta, strings.ToLower(kind)+".labels", meta["labels"]) + } + if meta["annotations"] != nil { + safemapstr.Put(meta, strings.ToLower(kind)+".annotations", meta["annotations"]) + } } } diff --git a/libbeat/common/kubernetes/metadata/node_test.go b/libbeat/common/kubernetes/metadata/node_test.go index a739c66fa94..b0e9423c9e6 100644 --- a/libbeat/common/kubernetes/metadata/node_test.go +++ b/libbeat/common/kubernetes/metadata/node_test.go @@ -52,7 +52,10 @@ func TestNode_Generate(t *testing.T) { Labels: map[string]string{ "foo": "bar", }, - Annotations: map[string]string{}, + Annotations: map[string]string{ + "key1": "value1", + "key2": "value2", + }, }, TypeMeta: metav1.TypeMeta{ Kind: "Node", @@ -71,11 +74,16 @@ func TestNode_Generate(t *testing.T) { "labels": common.MapStr{ "foo": "bar", }, + "annotations": common.MapStr{ + "key2": "value2", + }, }}, }, } - cfg := common.NewConfig() + cfg, _ := common.NewConfigFrom(Config{ + IncludeAnnotations: []string{"key2"}, + }) metagen := NewNodeMetadataGenerator(cfg, nil, client) for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -102,7 +110,9 @@ func TestNode_GenerateFromName(t *testing.T) { Labels: map[string]string{ "foo": "bar", }, - Annotations: map[string]string{}, + Annotations: map[string]string{ + "key": "value", + }, }, TypeMeta: metav1.TypeMeta{ Kind: "Node", @@ -121,12 +131,17 @@ func TestNode_GenerateFromName(t *testing.T) { "labels": common.MapStr{ "foo": "bar", }, + "annotations": common.MapStr{ + "key": "value", + }, }, }, } for _, test := range tests { - cfg := common.NewConfig() + cfg, _ := common.NewConfigFrom(Config{ + IncludeAnnotations: []string{"key"}, + }) nodes := cache.NewStore(cache.MetaNamespaceKeyFunc) nodes.Add(test.input) metagen := NewNodeMetadataGenerator(cfg, nodes, client) diff --git a/libbeat/common/kubernetes/metadata/pod.go b/libbeat/common/kubernetes/metadata/pod.go index 6debd974260..49bd51309a9 100644 --- a/libbeat/common/kubernetes/metadata/pod.go +++ b/libbeat/common/kubernetes/metadata/pod.go @@ -100,7 +100,7 @@ func (p *pod) GenerateK8s(obj kubernetes.Resource, opts ...FieldOptions) common. } if p.node != nil { - meta := p.node.GenerateFromName(po.Spec.NodeName, WithLabels("node")) + meta := p.node.GenerateFromName(po.Spec.NodeName, WithMetadata("node")) if meta != nil { out.Put("node", meta["node"]) } else { diff --git a/libbeat/common/kubernetes/metadata/pod_test.go b/libbeat/common/kubernetes/metadata/pod_test.go index ac810692693..97a02c55f0c 100644 --- a/libbeat/common/kubernetes/metadata/pod_test.go +++ b/libbeat/common/kubernetes/metadata/pod_test.go @@ -737,7 +737,9 @@ func TestPod_GenerateWithNodeNamespaceWithAddResourceConfig(t *testing.T) { "nodekey": "nodevalue", "nodekey2": "nodevalue2", }, - Annotations: map[string]string{}, + Annotations: map[string]string{ + "node.annotation": "node.value", + }, }, TypeMeta: metav1.TypeMeta{ Kind: "Node", @@ -755,7 +757,9 @@ func TestPod_GenerateWithNodeNamespaceWithAddResourceConfig(t *testing.T) { "app.kubernetes.io/name": "kube-state-metrics", "nskey2": "nsvalue2", }, - Annotations: map[string]string{}, + Annotations: map[string]string{ + "ns.annotation": "ns.value", + }, }, TypeMeta: metav1.TypeMeta{ Kind: "Namespace", @@ -773,6 +777,9 @@ func TestPod_GenerateWithNodeNamespaceWithAddResourceConfig(t *testing.T) { "namespace_labels": common.MapStr{ "app_kubernetes_io/name": "kube-state-metrics", }, + "namespace_annotations": common.MapStr{ + "ns_annotation": "ns.value", + }, "node": common.MapStr{ "name": "testnode", "uid": uid, @@ -780,6 +787,9 @@ func TestPod_GenerateWithNodeNamespaceWithAddResourceConfig(t *testing.T) { "nodekey2": "nodevalue2", }, "hostname": "node1", + "annotations": common.MapStr{ + "node_annotation": "node.value", + }, }, "labels": common.MapStr{ "app_kubernetes_io/component": "exporter", @@ -802,10 +812,12 @@ func TestPod_GenerateWithNodeNamespaceWithAddResourceConfig(t *testing.T) { assert.NoError(t, err) namespaceConfig, _ := common.NewConfigFrom(map[string]interface{}{ - "include_labels": []string{"app.kubernetes.io/name"}, + "include_labels": []string{"app.kubernetes.io/name"}, + "include_annotations": []string{"ns.annotation"}, }) nodeConfig, _ := common.NewConfigFrom(map[string]interface{}{ - "include_labels": []string{"nodekey2"}, + "include_labels": []string{"nodekey2"}, + "include_annotations": []string{"node.annotation"}, }) metaConfig := AddResourceMetadataConfig{ Namespace: namespaceConfig, diff --git a/libbeat/common/kubernetes/metadata/service_test.go b/libbeat/common/kubernetes/metadata/service_test.go index a4b070b55a2..29aaaa4d8d5 100644 --- a/libbeat/common/kubernetes/metadata/service_test.go +++ b/libbeat/common/kubernetes/metadata/service_test.go @@ -279,7 +279,9 @@ func TestService_GenerateWithNamespace(t *testing.T) { Labels: map[string]string{ "nskey": "nsvalue", }, - Annotations: map[string]string{}, + Annotations: map[string]string{ + "ns.annotation": "value", + }, }, TypeMeta: metav1.TypeMeta{ Kind: "Namespace", @@ -300,21 +302,26 @@ func TestService_GenerateWithNamespace(t *testing.T) { "namespace_labels": common.MapStr{ "nskey": "nsvalue", }, + "namespace_annotations": common.MapStr{ + "ns_annotation": "value", + }, }, }, }, } for _, test := range tests { - cfg := common.NewConfig() + nsConfig, _ := common.NewConfigFrom(map[string]interface{}{ + "include_annotations": []string{"ns.annotation"}, + }) services := cache.NewStore(cache.MetaNamespaceKeyFunc) services.Add(test.input) namespaces := cache.NewStore(cache.MetaNamespaceKeyFunc) namespaces.Add(test.namespace) - nsMeta := NewNamespaceMetadataGenerator(cfg, namespaces, client) + nsMeta := NewNamespaceMetadataGenerator(nsConfig, namespaces, client) - metagen := NewServiceMetadataGenerator(cfg, services, nsMeta, client) + metagen := NewServiceMetadataGenerator(nsConfig, services, nsMeta, client) t.Run(test.name, func(t *testing.T) { assert.Equal(t, test.output, metagen.Generate(test.input)) })