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

Kubernetes metadata enhancements #22189

Merged
merged 16 commits into from
Nov 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,9 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d
- Add support for OpenStack SSL metadata APIs in `add_cloud_metadata`. {pull}21590[21590]
- Add cloud.account.id for GCP into add_cloud_metadata processor. {pull}21776[21776]
- Add proxy metricset for istio module. {pull}21751[21751]
- Add kubernetes.node.hostname metadata of Kubernetes node. {pull}22189[22189]
- Enable always add_resource_metadata for Pods and Services of kubernetes autodiscovery. {pull}22189[22189]
- Add add_resource_metadata option setting (always enabled) for add_kubernetes_metadata setting. {pull}22189[22189]
- Added Kafka version 2.2 to the list of supported versions. {pull}22328[22328]
- Add support for ephemeral containers in kubernetes autodiscover and `add_kubernetes_metadata`. {pull}22389[22389] {pull}22439[22439]

Expand Down
10 changes: 10 additions & 0 deletions auditbeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11460,6 +11460,16 @@ type: keyword
Kubernetes node name


type: keyword

--

*`kubernetes.node.hostname`*::
+
--
Kubernetes hostname as reported by the node’s kernel


type: keyword

--
Expand Down
2 changes: 1 addition & 1 deletion auditbeat/include/fields.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions filebeat/docs/autodiscover-hints.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ The above configuration would generate two input configurations. The first input
tokenizer. The second input handles everything but debug logs.

[float]
===== Configuring Namespace Defaults
===== Namespace Defaults

Hints can be configured on the Namespace's annotations as defaults to use when Pod level annotations are missing.
The resultant hints are a combination of Pod annotations and Namespace annotations with the Pod's taking precedence. To
Expand All @@ -186,7 +186,7 @@ filebeat.autodiscover:
hints.enabled: true
add_resource_metadata:
namespace:
enabled: true
include_annotations: ["nsannotation1"]
-------------------------------------------------------------------------------------


Expand Down
10 changes: 10 additions & 0 deletions filebeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -89343,6 +89343,16 @@ type: keyword
Kubernetes node name


type: keyword

--

*`kubernetes.node.hostname`*::
+
--
Kubernetes hostname as reported by the node’s kernel


type: keyword

--
Expand Down
2 changes: 1 addition & 1 deletion filebeat/include/fields.go

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions heartbeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -8957,6 +8957,16 @@ type: keyword
Kubernetes node name


type: keyword

--

*`kubernetes.node.hostname`*::
+
--
Kubernetes hostname as reported by the node’s kernel


type: keyword

--
Expand Down
2 changes: 1 addition & 1 deletion heartbeat/include/fields.go

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions journalbeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9303,6 +9303,16 @@ type: keyword
Kubernetes node name


type: keyword

--

*`kubernetes.node.hostname`*::
+
--
Kubernetes hostname as reported by the node’s kernel


type: keyword

--
Expand Down
2 changes: 1 addition & 1 deletion journalbeat/include/fields.go

Large diffs are not rendered by default.

26 changes: 17 additions & 9 deletions libbeat/autodiscover/providers/kubernetes/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ func TestEmitEvent_Node(t *testing.T) {
Type: v1.NodeInternalIP,
Address: "1.2.3.4",
},
{
Type: v1.NodeHostName,
Address: "node1",
},
},
},
},
Expand All @@ -161,16 +165,18 @@ func TestEmitEvent_Node(t *testing.T) {
"provider": UUID,
"kubernetes": common.MapStr{
"node": common.MapStr{
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"hostname": "node1",
},
"annotations": common.MapStr{},
},
"meta": common.MapStr{
"kubernetes": common.MapStr{
"node": common.MapStr{
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"hostname": "node1",
},
},
},
Expand Down Expand Up @@ -204,7 +210,7 @@ func TestEmitEvent_Node(t *testing.T) {
},
TypeMeta: typeMeta,
Status: v1.NodeStatus{
Addresses: []v1.NodeAddress{},
Addresses: []v1.NodeAddress{{Type: v1.NodeHostName, Address: "node1"}},
Conditions: []v1.NodeCondition{
{
Type: v1.NodeReady,
Expand All @@ -220,16 +226,18 @@ func TestEmitEvent_Node(t *testing.T) {
"provider": UUID,
"kubernetes": common.MapStr{
"node": common.MapStr{
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"hostname": "node1",
},
"annotations": common.MapStr{},
},
"meta": common.MapStr{
"kubernetes": common.MapStr{
"node": common.MapStr{
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"name": "metricbeat",
"uid": "005f3b90-4b9d-12f8-acf0-31020a840133",
"hostname": "node1",
},
},
},
Expand Down
51 changes: 21 additions & 30 deletions libbeat/autodiscover/providers/kubernetes/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,43 +75,34 @@ func NewPodEventer(uuid uuid.UUID, cfg *common.Config, client k8s.Interface, pub
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Pod{}, err)
}

var nodeMeta, namespaceMeta metadata.MetaGen
var nodeWatcher, namespaceWatcher kubernetes.Watcher
options := kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
Node: config.Node,
}
if config.Namespace != "" {
options.Namespace = config.Namespace
}
metaConf := config.AddResourceMetadata
if metaConf != nil {
if metaConf.Node != nil && metaConf.Node.Enabled() {
ChrsMark marked this conversation as resolved.
Show resolved Hide resolved
options := kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
Node: config.Node,
}
if config.Namespace != "" {
options.Namespace = config.Namespace
}
nodeWatcher, err = kubernetes.NewWatcher(client, &kubernetes.Node{}, options, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Node{}, err)
}

nodeMeta = metadata.NewNodeMetadataGenerator(metaConf.Node, nodeWatcher.Store())
}

if metaConf.Namespace != nil && metaConf.Namespace.Enabled() {
namespaceWatcher, err = kubernetes.NewWatcher(client, &kubernetes.Namespace{}, kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
}, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Namespace{}, err)
}

namespaceMeta = metadata.NewNamespaceMetadataGenerator(metaConf.Namespace, namespaceWatcher.Store())
}
if metaConf == nil {
metaConf = metadata.GetDefaultResourceMetadataConfig()
}
nodeWatcher, err := kubernetes.NewWatcher(client, &kubernetes.Node{}, options, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Node{}, err)
}
namespaceWatcher, err := kubernetes.NewWatcher(client, &kubernetes.Namespace{}, kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
}, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Namespace{}, err)
}
metaGen := metadata.GetPodMetaGen(cfg, watcher, nodeWatcher, namespaceWatcher, metaConf)

p := &pod{
config: config,
uuid: uuid,
publish: publish,
metagen: metadata.NewPodMetadataGenerator(cfg, watcher.Store(), nodeMeta, namespaceMeta),
metagen: metaGen,
logger: logger,
watcher: watcher,
nodeWatcher: nodeWatcher,
Expand Down
21 changes: 9 additions & 12 deletions libbeat/autodiscover/providers/kubernetes/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,18 @@ func NewServiceEventer(uuid uuid.UUID, cfg *common.Config, client k8s.Interface,

var namespaceMeta metadata.MetaGen
var namespaceWatcher kubernetes.Watcher
metaConf := config.AddResourceMetadata
if metaConf != nil {
if metaConf.Namespace != nil && metaConf.Namespace.Enabled() {
namespaceWatcher, err = kubernetes.NewWatcher(client, &kubernetes.Namespace{}, kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
Namespace: config.Namespace,
}, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Namespace{}, err)
}

namespaceMeta = metadata.NewNamespaceMetadataGenerator(metaConf.Namespace, namespaceWatcher.Store())
}
metaConf := metadata.GetDefaultResourceMetadataConfig()
namespaceWatcher, err = kubernetes.NewWatcher(client, &kubernetes.Namespace{}, kubernetes.WatchOptions{
SyncTimeout: config.SyncPeriod,
Namespace: config.Namespace,
}, nil)
if err != nil {
return nil, fmt.Errorf("couldn't create watcher for %T due to error %+v", &kubernetes.Namespace{}, err)
}

namespaceMeta = metadata.NewNamespaceMetadataGenerator(metaConf.Namespace, namespaceWatcher.Store())

p := &service{
config: config,
uuid: uuid,
Expand Down
10 changes: 10 additions & 0 deletions libbeat/common/kubernetes/metadata/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,13 @@ func (c *Config) InitDefaults() {
func (c *Config) Unmarshal(cfg *common.Config) error {
return cfg.Unpack(c)
}

func GetDefaultResourceMetadataConfig() *AddResourceMetadataConfig {
metaConfig := Config{}
metaConfig.InitDefaults()
metaCfg, _ := common.NewConfigFrom(&metaConfig)
return &AddResourceMetadataConfig{
Node: metaCfg,
Namespace: metaCfg,
}
}
16 changes: 16 additions & 0 deletions libbeat/common/kubernetes/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,19 @@ func WithLabels(kind string) FieldOptions {
safemapstr.Put(meta, strings.ToLower(kind)+".labels", meta["labels"])
}
}

// GetPodMetaGen is a wrapper function that creates a metaGen for pod resource and has embeeded
// nodeMetaGen and namespaceMetaGen
func GetPodMetaGen(
cfg *common.Config,
podWatcher kubernetes.Watcher,
nodeWatcher kubernetes.Watcher,
namespaceWatcher kubernetes.Watcher,
metaConf *AddResourceMetadataConfig) MetaGen {

nodeMetaGen := NewNodeMetadataGenerator(metaConf.Node, nodeWatcher.Store())
namespaceMetaGen := NewNamespaceMetadataGenerator(metaConf.Namespace, namespaceWatcher.Store())
metaGen := NewPodMetadataGenerator(cfg, podWatcher.Store(), nodeMetaGen, namespaceMetaGen)

return metaGen
}
17 changes: 16 additions & 1 deletion libbeat/common/kubernetes/metadata/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package metadata

import (
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/tools/cache"

"github.com/elastic/beats/v7/libbeat/common"
Expand All @@ -39,13 +40,17 @@ func NewNodeMetadataGenerator(cfg *common.Config, nodes cache.Store) MetaGen {

// Generate generates service metadata from a resource object
func (n *node) Generate(obj kubernetes.Resource, opts ...FieldOptions) common.MapStr {
_, ok := obj.(*kubernetes.Node)
node, ok := obj.(*kubernetes.Node)
if !ok {
return nil
}

meta := n.resource.Generate("node", obj, opts...)
// TODO: Add extra fields in here if need be
hostname := getHostName(node)
if hostname != "" {
meta.Put("node.hostname", getHostName(node))
}
return meta
}

Expand All @@ -66,3 +71,13 @@ func (n *node) GenerateFromName(name string, opts ...FieldOptions) common.MapStr

return nil
}

// getHostName returns the HostName address of the node
func getHostName(node *v1.Node) string {
for _, adr := range node.Status.Addresses {
if adr.Type == v1.NodeHostName {
return adr.Address
}
}
return ""
}
16 changes: 12 additions & 4 deletions libbeat/common/kubernetes/metadata/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,15 @@ func TestNode_Generate(t *testing.T) {
Kind: "Node",
APIVersion: "v1",
},
Status: v1.NodeStatus{
Addresses: []v1.NodeAddress{{Type: v1.NodeHostName, Address: "node1"}},
},
},
output: common.MapStr{
"node": common.MapStr{
"name": "obj",
"uid": uid,
"name": "obj",
"uid": uid,
"hostname": "node1",
},
"labels": common.MapStr{
"foo": "bar",
Expand Down Expand Up @@ -101,11 +105,15 @@ func TestNode_GenerateFromName(t *testing.T) {
Kind: "Node",
APIVersion: "v1",
},
Status: v1.NodeStatus{
Addresses: []v1.NodeAddress{{Type: v1.NodeHostName, Address: "node1"}},
},
},
output: common.MapStr{
"node": common.MapStr{
"name": "obj",
"uid": uid,
"name": "obj",
"uid": uid,
"hostname": "node1",
},
"labels": common.MapStr{
"foo": "bar",
Expand Down
4 changes: 4 additions & 0 deletions libbeat/common/kubernetes/metadata/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,9 @@ func TestPod_GenerateWithNodeNamespace(t *testing.T) {
Kind: "Node",
APIVersion: "v1",
},
Status: v1.NodeStatus{
Addresses: []v1.NodeAddress{{Type: v1.NodeHostName, Address: "node1"}},
},
},
namespace: &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -345,6 +348,7 @@ func TestPod_GenerateWithNodeNamespace(t *testing.T) {
"labels": common.MapStr{
"nodekey": "nodevalue",
},
"hostname": "node1",
},
"labels": common.MapStr{
"foo": "bar",
Expand Down
Loading