Skip to content

Commit

Permalink
[7.17](backport #33763) Use NamespaceAwareResourceMetaGenerator for a…
Browse files Browse the repository at this point in the history
…ll generic kubernetes resources (#33984)

* Use NamespaceAwareResourceMetaGenerator for all generic kubernetes resources (#33763)

* update elastic-agent-autodiscover; use NamespaceAwareResourceMetaGenerator for all generic kubernetes resources

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* update configuration comments

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* add PR number; fix conflicts

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* run make notice

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* fix go.sum file after rebase

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* make update

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* clean up changelog

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* test llc

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* revert local test

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
(cherry picked from commit 951b244)

# Conflicts:
#	NOTICE.txt
#	go.mod
#	go.sum
#	metricbeat/docs/modules/kubernetes.asciidoc
#	metricbeat/metricbeat.reference.yml
#	metricbeat/module/kubernetes/_meta/config.reference.yml
#	metricbeat/module/kubernetes/_meta/config.yml
#	metricbeat/modules.d/kubernetes.yml.disabled
#	x-pack/metricbeat/metricbeat.reference.yml

* fix conflicts

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* rerun make notice

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* backport changes added in elastic/elastic-agent-autodiscover#33

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* fix linter

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* Use NamespaceAwareResourceMetaGenerator for all generic kubernetes resources (#33763)

* update elastic-agent-autodiscover; use NamespaceAwareResourceMetaGenerator for all generic kubernetes resources

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* update configuration comments

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* add PR number; fix conflicts

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* run make notice

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* fix go.sum file after rebase

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* make update

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* clean up changelog

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* test llc

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* revert local test

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
(cherry picked from commit 951b244)

# Conflicts:
#	NOTICE.txt
#	go.mod
#	go.sum
#	metricbeat/docs/modules/kubernetes.asciidoc
#	metricbeat/metricbeat.reference.yml
#	metricbeat/module/kubernetes/_meta/config.reference.yml
#	metricbeat/module/kubernetes/_meta/config.yml
#	metricbeat/modules.d/kubernetes.yml.disabled
#	x-pack/metricbeat/metricbeat.reference.yml

* fix conflicts

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* rerun make notice

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* backport changes added in elastic/elastic-agent-autodiscover#33

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* fix linter

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

* fix tests and changelog

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>

Signed-off-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
Co-authored-by: Tetiana Kravchenko <tetiana.kravchenko@elastic.co>
  • Loading branch information
mergify[bot] and tetianakravchenko authored Dec 21, 2022
1 parent 59fca54 commit 673233d
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 45 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d

*Metricbeat*

- Add namespace metadata to all namespaced kubernetes resources. {pull}33763[33763]

*Packetbeat*

Expand Down
23 changes: 7 additions & 16 deletions libbeat/common/kubernetes/metadata/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ type pod struct {
store cache.Store
client k8s.Interface
node MetaGen
namespace MetaGen
resource *Resource
addResourceMetadata *AddResourceMetadataConfig
}
Expand All @@ -50,21 +49,22 @@ func NewPodMetadataGenerator(
addResourceMetadata = GetDefaultResourceMetadataConfig()
}
return &pod{
resource: NewResourceMetadataGenerator(cfg, client),
resource: NewNamespaceAwareResourceMetadataGenerator(cfg, client, namespace),
store: pods,
node: node,
namespace: namespace,
client: client,
addResourceMetadata: addResourceMetadata,
}
}

// Generate generates pod metadata from a resource object
// Metadata map is in the following form:
// {
// "kubernetes": {},
// "some.ecs.field": "asdf"
// }
//
// {
// "kubernetes": {},
// "some.ecs.field": "asdf"
// }
//
// All Kubernetes fields that need to be stored under kubernetes. prefix are populated by
// GenerateK8s method while fields that are part of ECS are generated by GenerateECS method
func (p *pod) Generate(obj kubernetes.Resource, opts ...FieldOptions) common.MapStr {
Expand Down Expand Up @@ -110,15 +110,6 @@ func (p *pod) GenerateK8s(obj kubernetes.Resource, opts ...FieldOptions) common.
_, _ = out.Put("node.name", po.Spec.NodeName)
}

if p.namespace != nil {
meta := p.namespace.GenerateFromName(po.GetNamespace())
if meta != nil {
// Use this in 8.0
//out.Put("namespace", meta["namespace"])
out.DeepUpdate(meta)
}
}

if po.Status.PodIP != "" {
_, _ = out.Put("pod.ip", po.Status.PodIP)
}
Expand Down
30 changes: 26 additions & 4 deletions libbeat/common/kubernetes/metadata/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
type Resource struct {
config *Config
clusterInfo ClusterInfo
namespace MetaGen
}

// NewResourceMetadataGenerator creates a metadata generator for a generic resource
Expand All @@ -49,12 +50,21 @@ func NewResourceMetadataGenerator(cfg *common.Config, client k8s.Interface) *Res
return r
}

// NewNamespaceAwareResourceMetadataGenerator creates a metadata generator with informatuon about namespace
func NewNamespaceAwareResourceMetadataGenerator(cfg *common.Config, client k8s.Interface, namespace MetaGen) *Resource {
r := NewResourceMetadataGenerator(cfg, client)
r.namespace = namespace
return r
}

// Generate generates metadata from a resource object
// Generate method returns metadata in the following form:
// {
// "kubernetes": {},
// "ecs.a.field": 42,
// }
//
// {
// "kubernetes": {},
// "ecs.a.field": 42,
// }
//
// This method should be called in top level and not as part of other metadata generators.
// For retrieving metadata without kubernetes. prefix one should call GenerateK8s instead.
func (r *Resource) Generate(kind string, obj kubernetes.Resource, opts ...FieldOptions) common.MapStr {
Expand Down Expand Up @@ -106,6 +116,18 @@ func (r *Resource) GenerateK8s(kind string, obj kubernetes.Resource, options ...
},
}

namespaceName := accessor.GetNamespace()
if namespaceName != "" {
_ = safemapstr.Put(meta, "namespace", namespaceName)

if r.namespace != nil {
nsMeta := r.namespace.GenerateFromName(namespaceName)
if nsMeta != nil {
meta.DeepUpdate(nsMeta)
}
}
}

if accessor.GetNamespace() != "" {
// TODO make this namespace.name in 8.0
_ = safemapstr.Put(meta, "namespace", accessor.GetNamespace())
Expand Down
138 changes: 138 additions & 0 deletions libbeat/common/kubernetes/metadata/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,26 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
k8sfake "k8s.io/client-go/kubernetes/fake"
"k8s.io/client-go/tools/cache"

"github.com/elastic/go-ucfg"

"github.com/elastic/beats/v7/libbeat/common"
"github.com/elastic/beats/v7/libbeat/common/kubernetes"
)

const (
uid = "005f3b90-4b9d-12f8-acf0-31020a840133"
defaultNs = "default"
name = "obj"
)

func TestResource_Generate(t *testing.T) {
uid := "005f3b90-4b9d-12f8-acf0-31020a840133"
namespace := "default"
Expand Down Expand Up @@ -126,3 +136,131 @@ func TestResource_Generate(t *testing.T) {
})
}
}

func TestNamespaceAwareResource_GenerateWithNamespace(t *testing.T) {
client := k8sfake.NewSimpleClientset()
tests := []struct {
resourceName string
input kubernetes.Resource
namespace kubernetes.Resource
output common.MapStr
name string
}{
{
name: "test not namespaced kubernetes resource - PersistentVolume",
resourceName: "persistentvolume",
input: &v1.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "pvc-18705cfb-9fb8-441f-9b32-0d67a21af839",
UID: "020fd954-3674-496a-9e77-c25f0f2257ea",
Labels: map[string]string{
"foo": "bar",
},
Annotations: map[string]string{},
},
TypeMeta: metav1.TypeMeta{
Kind: "PersistentVolume",
APIVersion: "v1",
},
},
namespace: &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: defaultNs,
UID: types.UID(uid),
Labels: map[string]string{
"nskey": "nsvalue",
},
Annotations: map[string]string{
"ns.annotation": "value",
},
},
TypeMeta: metav1.TypeMeta{
Kind: "Namespace",
APIVersion: "v1",
},
},
output: common.MapStr{
"kubernetes": common.MapStr{
"persistentvolume": common.MapStr{
"name": "pvc-18705cfb-9fb8-441f-9b32-0d67a21af839",
"uid": "020fd954-3674-496a-9e77-c25f0f2257ea",
},
"labels": common.MapStr{
"foo": "bar",
},
},
},
},
{
name: "test namespaced kubernetes resource",
resourceName: "deployment",
input: &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "default",
UID: "f33ca314-8cc5-48ea-90b7-3102c7430f75",
Labels: map[string]string{
"foo": "bar",
},
Annotations: map[string]string{},
},
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
},
namespace: &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: defaultNs,
UID: types.UID(uid),
Labels: map[string]string{
"nskey": "nsvalue",
},
Annotations: map[string]string{
"ns.annotation": "value",
},
},
TypeMeta: metav1.TypeMeta{
Kind: "Namespace",
APIVersion: "v1",
},
},
output: common.MapStr{
"kubernetes": common.MapStr{
"deployment": common.MapStr{
"name": name,
"uid": "f33ca314-8cc5-48ea-90b7-3102c7430f75",
},
"labels": common.MapStr{
"foo": "bar",
},
"namespace": "default",
"namespace_uid": uid,
"namespace_labels": common.MapStr{
"nskey": "nsvalue",
},
"namespace_annotations": common.MapStr{
"ns_annotation": "value",
},
},
},
},
}

for _, test := range tests {
nsConfig, err := common.NewConfigFrom(map[string]interface{}{
"include_annotations": []string{"ns.annotation"},
})
require.NoError(t, err)

namespaces := cache.NewStore(cache.MetaNamespaceKeyFunc)
err = namespaces.Add(test.namespace)
require.NoError(t, err)
nsMeta := NewNamespaceMetadataGenerator(nsConfig, namespaces, client)

metagen := NewNamespaceAwareResourceMetadataGenerator(nsConfig, client, nsMeta)
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, test.output, metagen.Generate(test.resourceName, test.input))
})
}
}
31 changes: 11 additions & 20 deletions libbeat/common/kubernetes/metadata/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,26 +27,26 @@ import (
)

type service struct {
store cache.Store
namespace MetaGen
resource *Resource
store cache.Store
resource *Resource
}

// NewServiceMetadataGenerator creates a metagen for service resources
func NewServiceMetadataGenerator(cfg *common.Config, services cache.Store, namespace MetaGen, client k8s.Interface) MetaGen {
return &service{
resource: NewResourceMetadataGenerator(cfg, client),
store: services,
namespace: namespace,
resource: NewNamespaceAwareResourceMetadataGenerator(cfg, client, namespace),
store: services,
}
}

// Generate generates service metadata from a resource object
// Metadata map is in the following form:
// {
// "kubernetes": {},
// "some.ecs.field": "asdf"
// }
//
// {
// "kubernetes": {},
// "some.ecs.field": "asdf"
// }
//
// All Kubernetes fields that need to be stored under kuberentes. prefix are populetad by
// GenerateK8s method while fields that are part of ECS are generated by GenerateECS method
func (s *service) Generate(obj kubernetes.Resource, opts ...FieldOptions) common.MapStr {
Expand All @@ -72,22 +72,13 @@ func (s *service) GenerateK8s(obj kubernetes.Resource, opts ...FieldOptions) com

out := s.resource.GenerateK8s("service", obj, opts...)

if s.namespace != nil {
meta := s.namespace.GenerateFromName(svc.GetNamespace())
if meta != nil {
// Use this in 8.0
//out.Put("namespace", meta["namespace"])
out.DeepUpdate(meta)
}
}

selectors := svc.Spec.Selector
if len(selectors) == 0 {
return out
}
svcMap := GenerateMap(selectors, s.resource.config.LabelsDedot)
if len(svcMap) != 0 {
safemapstr.Put(out, "selectors", svcMap)
_ = safemapstr.Put(out, "selectors", svcMap)
}

return out
Expand Down
3 changes: 1 addition & 2 deletions metricbeat/module/kubernetes/_meta/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
# If kube_config is not set, KUBECONFIG environment variable will be checked
# and if not present it will fall back to InCluster
#kube_config: ~/.kube/config
# To configure additionally node and namespace metadata, added to pod, service and container resource types,
# `add_resource_metadata` can be defined.
# To configure additionally node and namespace metadata `add_resource_metadata` can be defined.
# By default all labels will be included while annotations are not added by default.
# add_resource_metadata:
# namespace:
Expand Down
4 changes: 3 additions & 1 deletion metricbeat/module/kubernetes/util/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,12 @@ func NewResourceMetadataEnricher(

cfg, _ := common.NewConfigFrom(&commonMetaConfig)

metaGen := metadata.NewResourceMetadataGenerator(cfg, watcher.Client())
podMetaGen := metadata.GetPodMetaGen(cfg, watcher, nodeWatcher, namespaceWatcher, config.AddResourceMetadata)
namespaceMeta := metadata.NewNamespaceMetadataGenerator(config.AddResourceMetadata.Namespace, namespaceWatcher.Store(), watcher.Client())
serviceMetaGen := metadata.NewServiceMetadataGenerator(cfg, watcher.Store(), namespaceMeta, watcher.Client())

metaGen := metadata.NewNamespaceAwareResourceMetadataGenerator(cfg, watcher.Client(), namespaceMeta)

enricher := buildMetadataEnricher(watcher, nodeWatcher, namespaceWatcher,
// update
func(m map[string]common.MapStr, r kubernetes.Resource) {
Expand Down
3 changes: 1 addition & 2 deletions metricbeat/modules.d/kubernetes.yml.disabled
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
# If kube_config is not set, KUBECONFIG environment variable will be checked
# and if not present it will fall back to InCluster
#kube_config: ~/.kube/config
# To configure additionally node and namespace metadata, added to pod, service and container resource types,
# `add_resource_metadata` can be defined.
# To configure additionally node and namespace metadata `add_resource_metadata` can be defined.
# By default all labels will be included while annotations are not added by default.
# add_resource_metadata:
# namespace:
Expand Down

0 comments on commit 673233d

Please sign in to comment.