diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index ba954f02c7d..da6109796d5 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -124,6 +124,7 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...main[Check the HEAD dif - Extend documentation about `orchestrator.cluster` fields {pull}30518[30518] - Enhance Oracle Module: Change tablespace metricset collection period {issue}30948[30948] {pull}31259[#31259] - Add orchestrator cluster ECS fields in kubernetes events {pull}31341[31341] +- Add metadata for missing k8s resources/metricsets {pull}31590[31590] *Packetbeat* diff --git a/deploy/kubernetes/metricbeat-kubernetes.yaml b/deploy/kubernetes/metricbeat-kubernetes.yaml index 5cba6952a9a..398de8bcfac 100644 --- a/deploy/kubernetes/metricbeat-kubernetes.yaml +++ b/deploy/kubernetes/metricbeat-kubernetes.yaml @@ -279,6 +279,8 @@ rules: - events - pods - services + - persistentvolumes + - persistentvolumeclaims verbs: ["get", "list", "watch"] # Enable this rule only if planing to use Kubernetes keystore #- apiGroups: [""] @@ -294,6 +296,7 @@ rules: - statefulsets - deployments - replicasets + - daemonsets verbs: ["get", "list", "watch"] - apiGroups: ["batch"] resources: diff --git a/deploy/kubernetes/metricbeat/metricbeat-role.yaml b/deploy/kubernetes/metricbeat/metricbeat-role.yaml index 95824e5f06e..a9157a7e41d 100644 --- a/deploy/kubernetes/metricbeat/metricbeat-role.yaml +++ b/deploy/kubernetes/metricbeat/metricbeat-role.yaml @@ -12,6 +12,8 @@ rules: - events - pods - services + - persistentvolumes + - persistentvolumeclaims verbs: ["get", "list", "watch"] # Enable this rule only if planing to use Kubernetes keystore #- apiGroups: [""] @@ -27,6 +29,7 @@ rules: - statefulsets - deployments - replicasets + - daemonsets verbs: ["get", "list", "watch"] - apiGroups: ["batch"] resources: diff --git a/libbeat/common/kubernetes/informer.go b/libbeat/common/kubernetes/informer.go index fcd342b3c9c..1801a5e47ea 100644 --- a/libbeat/common/kubernetes/informer.go +++ b/libbeat/common/kubernetes/informer.go @@ -137,6 +137,18 @@ func NewInformer(client kubernetes.Interface, resource Resource, opts WatchOptio } objType = "statefulset" + case *DaemonSet: + ss := client.AppsV1().DaemonSets(opts.Namespace) + listwatch = &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return ss.List(ctx, options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return ss.Watch(ctx, options) + }, + } + + objType = "daemonset" case *Service: svc := client.CoreV1().Services(opts.Namespace) listwatch = &cache.ListWatch{ @@ -185,7 +197,30 @@ func NewInformer(client kubernetes.Interface, resource Resource, opts WatchOptio } objType = "job" + case *PersistentVolume: + ss := client.CoreV1().PersistentVolumes() + listwatch = &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return ss.List(ctx, options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return ss.Watch(ctx, options) + }, + } + + objType = "persistentvolume" + case *PersistentVolumeClaim: + ss := client.CoreV1().PersistentVolumeClaims(opts.Namespace) + listwatch = &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + return ss.List(ctx, options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + return ss.Watch(ctx, options) + }, + } + objType = "persistentvolumeclaim" case *Role: r := client.RbacV1().Roles(opts.Namespace) listwatch = &cache.ListWatch{ diff --git a/libbeat/common/kubernetes/types.go b/libbeat/common/kubernetes/types.go index 45bed196c95..fffcb234b02 100644 --- a/libbeat/common/kubernetes/types.go +++ b/libbeat/common/kubernetes/types.go @@ -73,6 +73,9 @@ type ReplicaSet = appsv1.ReplicaSet // StatefulSet data type StatefulSet = appsv1.StatefulSet +// DaemonSet data +type DaemonSet = appsv1.DaemonSet + // Service data type Service = v1.Service @@ -85,6 +88,12 @@ type Job = batchv1.Job // CronJob data type CronJob = batchv1.CronJob +// PersistentVolume data +type PersistentVolume = v1.PersistentVolume + +// PersistentVolumeClaim data +type PersistentVolumeClaim = v1.PersistentVolumeClaim + // Role data type Role = rbacv1.Role diff --git a/metricbeat/module/kubernetes/_meta/test/docs/01_playground/metricbeat.yaml b/metricbeat/module/kubernetes/_meta/test/docs/01_playground/metricbeat.yaml index ba304382637..e17b1c3a687 100644 --- a/metricbeat/module/kubernetes/_meta/test/docs/01_playground/metricbeat.yaml +++ b/metricbeat/module/kubernetes/_meta/test/docs/01_playground/metricbeat.yaml @@ -269,6 +269,8 @@ rules: - events - pods - services + - persistentvolumes + - persistentvolumeclaims verbs: ["get", "list", "watch"] # Enable this rule only if planing to use Kubernetes keystore #- apiGroups: [""] @@ -284,6 +286,12 @@ rules: - statefulsets - deployments - replicasets + - daemonsets + verbs: ["get", "list", "watch"] + - apiGroups: ["batch"] + resources: + - jobs + - cronjobs verbs: ["get", "list", "watch"] - apiGroups: - "" diff --git a/metricbeat/module/kubernetes/event/event.go b/metricbeat/module/kubernetes/event/event.go index 448714bb4c5..dac99a68f13 100644 --- a/metricbeat/module/kubernetes/event/event.go +++ b/metricbeat/module/kubernetes/event/event.go @@ -21,11 +21,8 @@ import ( "fmt" "time" - k8sclient "k8s.io/client-go/kubernetes" - "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/common/kubernetes" - "github.com/elastic/beats/v7/libbeat/common/kubernetes/metadata" "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/beats/v7/metricbeat/module/kubernetes/util" conf "github.com/elastic/elastic-agent-libs/config" @@ -101,7 +98,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { // add ECS orchestrator fields cfg, _ := conf.NewConfigFrom(&config) - ecsClusterMeta, err := getClusterECSMeta(cfg, client, ms.Logger()) + ecsClusterMeta, err := util.GetClusterECSMeta(cfg, client, ms.Logger()) if err != nil { ms.Logger().Debugf("could not retrieve cluster metadata: %w", err) } @@ -112,21 +109,6 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { return ms, nil } -func getClusterECSMeta(cfg *conf.C, client k8sclient.Interface, logger *logp.Logger) (mapstr.M, error) { - clusterInfo, err := metadata.GetKubernetesClusterIdentifier(cfg, client) - if err != nil { - return nil, fmt.Errorf("fail to get kubernetes cluster metadata: %w", err) - } - ecsClusterMeta := mapstr.M{} - if clusterInfo.Url != "" { - util.ShouldPut(ecsClusterMeta, "orchestrator.cluster.url", clusterInfo.Url, logger) - } - if clusterInfo.Name != "" { - util.ShouldPut(ecsClusterMeta, "orchestrator.cluster.name", clusterInfo.Name, logger) - } - return ecsClusterMeta, nil -} - // Run method provides the Kubernetes event watcher with a reporter with which events can be reported. func (m *MetricSet) Run(reporter mb.PushReporterV2) { now := time.Now() diff --git a/metricbeat/module/kubernetes/state_container/_meta/test/ksm.v2.0.0.expected b/metricbeat/module/kubernetes/state_container/_meta/test/ksm.v2.0.0.expected index f3d21d77a34..85ccf20ecad 100644 --- a/metricbeat/module/kubernetes/state_container/_meta/test/ksm.v2.0.0.expected +++ b/metricbeat/module/kubernetes/state_container/_meta/test/ksm.v2.0.0.expected @@ -2,9 +2,9 @@ { "RootFields": { "container": { - "id": "3101d1525d6133851881f4b7cd439033663daefeb4849e5322d1428f09620628", + "id": "ffdc200c097349d8ed96f5768387d276751497297730121e6335a31c2d3332a4", "image": { - "name": "k8s.gcr.io/coredns:1.6.2" + "name": "k8s.gcr.io/kube-apiserver:v1.16.15" }, "runtime": "containerd" } @@ -15,7 +15,51 @@ "name": "kind-control-plane" }, "pod": { - "name": "coredns-5644d7b6d9-zgdsx" + "name": "kube-apiserver-kind-control-plane" + } + }, + "MetricSetFields": { + "cpu": { + "request": { + "cores": 0.25 + } + }, + "id": "containerd://ffdc200c097349d8ed96f5768387d276751497297730121e6335a31c2d3332a4", + "name": "kube-apiserver", + "status": { + "phase": "running", + "ready": true, + "restarts": 0 + } + }, + "Index": "", + "ID": "", + "Namespace": "kubernetes.container", + "Timestamp": "0001-01-01T00:00:00Z", + "Error": null, + "Host": "", + "Service": "", + "Took": 0, + "Period": 0, + "DisableTimeSeries": false + }, + { + "RootFields": { + "container": { + "id": "d66f649ad0f6c1822039f1c4ea27b6f792f6a86029bf862e77afa2966042a1ce", + "image": { + "name": "docker.elastic.co/beats/metricbeat:7.15.0-SNAPSHOT" + }, + "runtime": "containerd" + } + }, + "ModuleFields": { + "namespace": "kube-system", + "node": { + "name": "kind-worker2" + }, + "pod": { + "name": "metricbeat-55fp7" } }, "MetricSetFields": { @@ -24,21 +68,21 @@ "cores": 0.1 } }, - "id": "containerd://3101d1525d6133851881f4b7cd439033663daefeb4849e5322d1428f09620628", + "id": "containerd://d66f649ad0f6c1822039f1c4ea27b6f792f6a86029bf862e77afa2966042a1ce", "memory": { "limit": { - "bytes": 178257920 + "bytes": 209715200 }, "request": { - "bytes": 73400320 + "bytes": 104857600 } }, - "name": "coredns", + "name": "metricbeat", "status": { "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 4 + "restarts": 1 } }, "Index": "", @@ -55,9 +99,9 @@ { "RootFields": { "container": { - "id": "ffdc200c097349d8ed96f5768387d276751497297730121e6335a31c2d3332a4", + "id": "9afadbf7fd5374d1849b008e8ad4287cdbfbbf499bab9740bf0c7a5cd6730ad9", "image": { - "name": "k8s.gcr.io/kube-apiserver:v1.16.15" + "name": "docker.io/kindest/kindnetd:v20210326-1e038dc5" }, "runtime": "containerd" } @@ -65,24 +109,36 @@ "ModuleFields": { "namespace": "kube-system", "node": { - "name": "kind-control-plane" + "name": "kind-worker" }, "pod": { - "name": "kube-apiserver-kind-control-plane" + "name": "kindnet-9fgst" } }, "MetricSetFields": { "cpu": { + "limit": { + "cores": 0.1 + }, "request": { - "cores": 0.25 + "cores": 0.1 } }, - "id": "containerd://ffdc200c097349d8ed96f5768387d276751497297730121e6335a31c2d3332a4", - "name": "kube-apiserver", + "id": "containerd://9afadbf7fd5374d1849b008e8ad4287cdbfbbf499bab9740bf0c7a5cd6730ad9", + "memory": { + "limit": { + "bytes": 52428800 + }, + "request": { + "bytes": 52428800 + } + }, + "name": "kindnet-cni", "status": { + "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 0 + "restarts": 4 } }, "Index": "", @@ -99,30 +155,38 @@ { "RootFields": { "container": { - "id": "f2926bdf120aa838838aa55640b5511291e7279eb07ee8c17e01bf23a8695c2c", + "id": "fae8ef6fa6ea716f5ce0a65a1b2407d1e4839b04452d6013cdb6d5be8db8ada0", "image": { - "name": "k8s.gcr.io/kube-proxy:v1.16.15" + "name": "docker.io/library/redis:5.0.4" }, "runtime": "containerd" } }, "ModuleFields": { - "namespace": "kube-system", + "namespace": "default", "node": { "name": "kind-worker2" }, "pod": { - "name": "kube-proxy-lf6md" + "name": "redis" } }, "MetricSetFields": { - "id": "containerd://f2926bdf120aa838838aa55640b5511291e7279eb07ee8c17e01bf23a8695c2c", - "name": "kube-proxy", + "cpu": { + "limit": { + "cores": 0.1 + }, + "request": { + "cores": 0.1 + } + }, + "id": "containerd://fae8ef6fa6ea716f5ce0a65a1b2407d1e4839b04452d6013cdb6d5be8db8ada0", + "name": "redis", "status": { "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 4 + "restarts": 1 } }, "Index": "", @@ -179,30 +243,30 @@ { "RootFields": { "container": { - "id": "02b0705f60dc6131a6b5d4e9a48e2510463f89a0f77e7e1bafa6b5f45cc595e8", + "id": "f2926bdf120aa838838aa55640b5511291e7279eb07ee8c17e01bf23a8695c2c", "image": { - "name": "docker.io/odise/busybox-python:latest" + "name": "k8s.gcr.io/kube-proxy:v1.16.15" }, "runtime": "containerd" } }, "ModuleFields": { - "namespace": "default", + "namespace": "kube-system", "node": { - "name": "kind-worker" + "name": "kind-worker2" }, "pod": { - "name": "hello-python-566b5479f5-ndwdl" + "name": "kube-proxy-lf6md" } }, "MetricSetFields": { - "id": "containerd://02b0705f60dc6131a6b5d4e9a48e2510463f89a0f77e7e1bafa6b5f45cc595e8", - "name": "hello-python", + "id": "containerd://f2926bdf120aa838838aa55640b5511291e7279eb07ee8c17e01bf23a8695c2c", + "name": "kube-proxy", "status": { "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 18 + "restarts": 4 } }, "Index": "", @@ -219,9 +283,9 @@ { "RootFields": { "container": { - "id": "09603a8146bd6aacb32d55a1e52e929143f003ea30c84052f765efca129fd90a", + "id": "3101d1525d6133851881f4b7cd439033663daefeb4849e5322d1428f09620628", "image": { - "name": "docker.io/kindest/kindnetd:v20210326-1e038dc5" + "name": "k8s.gcr.io/coredns:1.6.2" }, "runtime": "containerd" } @@ -232,28 +296,25 @@ "name": "kind-control-plane" }, "pod": { - "name": "kindnet-kch2v" + "name": "coredns-5644d7b6d9-zgdsx" } }, "MetricSetFields": { "cpu": { - "limit": { - "cores": 0.1 - }, "request": { "cores": 0.1 } }, - "id": "containerd://09603a8146bd6aacb32d55a1e52e929143f003ea30c84052f765efca129fd90a", + "id": "containerd://3101d1525d6133851881f4b7cd439033663daefeb4849e5322d1428f09620628", "memory": { "limit": { - "bytes": 52428800 + "bytes": 178257920 }, "request": { - "bytes": 52428800 + "bytes": 73400320 } }, - "name": "kindnet-cni", + "name": "coredns", "status": { "last_terminated_reason": "Unknown", "phase": "running", @@ -275,9 +336,9 @@ { "RootFields": { "container": { - "id": "cd368e1731c278b039642fab2fe90902e2cfa470fd70a7ccfd5c2549a552cea5", + "id": "90560da422742a41de53c281969942c25f24d7b6bf73af6e4f226ee62338f640", "image": { - "name": "k8s.gcr.io/kube-scheduler:v1.16.15" + "name": "docker.elastic.co/beats/metricbeat:7.15.0-SNAPSHOT" }, "runtime": "containerd" } @@ -285,10 +346,10 @@ "ModuleFields": { "namespace": "kube-system", "node": { - "name": "kind-control-plane" + "name": "kind-worker" }, "pod": { - "name": "kube-scheduler-kind-control-plane" + "name": "metricbeat-bvr2v" } }, "MetricSetFields": { @@ -297,13 +358,21 @@ "cores": 0.1 } }, - "id": "containerd://cd368e1731c278b039642fab2fe90902e2cfa470fd70a7ccfd5c2549a552cea5", - "name": "kube-scheduler", + "id": "containerd://90560da422742a41de53c281969942c25f24d7b6bf73af6e4f226ee62338f640", + "memory": { + "limit": { + "bytes": 209715200 + }, + "request": { + "bytes": 104857600 + } + }, + "name": "metricbeat", "status": { "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 4 + "restarts": 1 } }, "Index": "", @@ -320,30 +389,30 @@ { "RootFields": { "container": { - "id": "1a223dbb8b51a7404836789fd049701a9e4df7bb69878fb893ab10419ff4eb29", + "id": "a55ee307ef431d293c02a7eb96417963d7b81b298a8ebfac2f77fe4ca58e1461", "image": { - "name": "docker.io/rancher/local-path-provisioner:v0.0.14" + "name": "k8s.gcr.io/kube-proxy:v1.16.15" }, "runtime": "containerd" } }, "ModuleFields": { - "namespace": "local-path-storage", + "namespace": "kube-system", "node": { "name": "kind-control-plane" }, "pod": { - "name": "local-path-provisioner-5bf465b47d-h8hjn" + "name": "kube-proxy-cm525" } }, "MetricSetFields": { - "id": "containerd://1a223dbb8b51a7404836789fd049701a9e4df7bb69878fb893ab10419ff4eb29", - "name": "local-path-provisioner", + "id": "containerd://a55ee307ef431d293c02a7eb96417963d7b81b298a8ebfac2f77fe4ca58e1461", + "name": "kube-proxy", "status": { - "last_terminated_reason": "Error", + "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 8 + "restarts": 4 } }, "Index": "", @@ -360,43 +429,30 @@ { "RootFields": { "container": { - "id": "d66f649ad0f6c1822039f1c4ea27b6f792f6a86029bf862e77afa2966042a1ce", + "id": "1a223dbb8b51a7404836789fd049701a9e4df7bb69878fb893ab10419ff4eb29", "image": { - "name": "docker.elastic.co/beats/metricbeat:7.15.0-SNAPSHOT" + "name": "docker.io/rancher/local-path-provisioner:v0.0.14" }, "runtime": "containerd" } }, "ModuleFields": { - "namespace": "kube-system", + "namespace": "local-path-storage", "node": { - "name": "kind-worker2" + "name": "kind-control-plane" }, "pod": { - "name": "metricbeat-55fp7" + "name": "local-path-provisioner-5bf465b47d-h8hjn" } }, "MetricSetFields": { - "cpu": { - "request": { - "cores": 0.1 - } - }, - "id": "containerd://d66f649ad0f6c1822039f1c4ea27b6f792f6a86029bf862e77afa2966042a1ce", - "memory": { - "limit": { - "bytes": 209715200 - }, - "request": { - "bytes": 104857600 - } - }, - "name": "metricbeat", + "id": "containerd://1a223dbb8b51a7404836789fd049701a9e4df7bb69878fb893ab10419ff4eb29", + "name": "local-path-provisioner", "status": { - "last_terminated_reason": "Unknown", + "last_terminated_reason": "Error", "phase": "running", "ready": true, - "restarts": 1 + "restarts": 8 } }, "Index": "", @@ -466,38 +522,30 @@ { "RootFields": { "container": { - "id": "fae8ef6fa6ea716f5ce0a65a1b2407d1e4839b04452d6013cdb6d5be8db8ada0", + "id": "ae513b826459c9382984bea986eb3546aa45fd0e650051cb9591ab7a8efed6ea", "image": { - "name": "docker.io/library/redis:5.0.4" + "name": "k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.1.0" }, "runtime": "containerd" } }, "ModuleFields": { - "namespace": "default", + "namespace": "kube-system", "node": { - "name": "kind-worker2" + "name": "kind-worker" }, "pod": { - "name": "redis" + "name": "kube-state-metrics-f655d484d-hj69w" } }, "MetricSetFields": { - "cpu": { - "limit": { - "cores": 0.1 - }, - "request": { - "cores": 0.1 - } - }, - "id": "containerd://fae8ef6fa6ea716f5ce0a65a1b2407d1e4839b04452d6013cdb6d5be8db8ada0", - "name": "redis", + "id": "containerd://ae513b826459c9382984bea986eb3546aa45fd0e650051cb9591ab7a8efed6ea", + "name": "kube-state-metrics", "status": { - "last_terminated_reason": "Unknown", + "last_terminated_reason": "Error", "phase": "running", "ready": true, - "restarts": 1 + "restarts": 2 } }, "Index": "", @@ -514,7 +562,7 @@ { "RootFields": { "container": { - "id": "9afadbf7fd5374d1849b008e8ad4287cdbfbbf499bab9740bf0c7a5cd6730ad9", + "id": "09603a8146bd6aacb32d55a1e52e929143f003ea30c84052f765efca129fd90a", "image": { "name": "docker.io/kindest/kindnetd:v20210326-1e038dc5" }, @@ -524,10 +572,10 @@ "ModuleFields": { "namespace": "kube-system", "node": { - "name": "kind-worker" + "name": "kind-control-plane" }, "pod": { - "name": "kindnet-9fgst" + "name": "kindnet-kch2v" } }, "MetricSetFields": { @@ -539,7 +587,7 @@ "cores": 0.1 } }, - "id": "containerd://9afadbf7fd5374d1849b008e8ad4287cdbfbbf499bab9740bf0c7a5cd6730ad9", + "id": "containerd://09603a8146bd6aacb32d55a1e52e929143f003ea30c84052f765efca129fd90a", "memory": { "limit": { "bytes": 52428800 @@ -570,49 +618,9 @@ { "RootFields": { "container": { - "id": "ae513b826459c9382984bea986eb3546aa45fd0e650051cb9591ab7a8efed6ea", - "image": { - "name": "k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.1.0" - }, - "runtime": "containerd" - } - }, - "ModuleFields": { - "namespace": "kube-system", - "node": { - "name": "kind-worker" - }, - "pod": { - "name": "kube-state-metrics-f655d484d-hj69w" - } - }, - "MetricSetFields": { - "id": "containerd://ae513b826459c9382984bea986eb3546aa45fd0e650051cb9591ab7a8efed6ea", - "name": "kube-state-metrics", - "status": { - "last_terminated_reason": "Error", - "phase": "running", - "ready": true, - "restarts": 2 - } - }, - "Index": "", - "ID": "", - "Namespace": "kubernetes.container", - "Timestamp": "0001-01-01T00:00:00Z", - "Error": null, - "Host": "", - "Service": "", - "Took": 0, - "Period": 0, - "DisableTimeSeries": false - }, - { - "RootFields": { - "container": { - "id": "90560da422742a41de53c281969942c25f24d7b6bf73af6e4f226ee62338f640", + "id": "3037e577635e9cbcefe1f273e5b06784d36807af76158e4add887e840c42e1ef", "image": { - "name": "docker.elastic.co/beats/metricbeat:7.15.0-SNAPSHOT" + "name": "docker.io/kindest/kindnetd:v20210326-1e038dc5" }, "runtime": "containerd" } @@ -620,33 +628,36 @@ "ModuleFields": { "namespace": "kube-system", "node": { - "name": "kind-worker" + "name": "kind-worker2" }, "pod": { - "name": "metricbeat-bvr2v" + "name": "kindnet-tg7tl" } }, "MetricSetFields": { "cpu": { + "limit": { + "cores": 0.1 + }, "request": { "cores": 0.1 } }, - "id": "containerd://90560da422742a41de53c281969942c25f24d7b6bf73af6e4f226ee62338f640", + "id": "containerd://3037e577635e9cbcefe1f273e5b06784d36807af76158e4add887e840c42e1ef", "memory": { "limit": { - "bytes": 209715200 + "bytes": 52428800 }, "request": { - "bytes": 104857600 + "bytes": 52428800 } }, - "name": "metricbeat", + "name": "kindnet-cni", "status": { "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 1 + "restarts": 4 } }, "Index": "", @@ -703,9 +714,9 @@ { "RootFields": { "container": { - "id": "a55ee307ef431d293c02a7eb96417963d7b81b298a8ebfac2f77fe4ca58e1461", + "id": "1c1919c3b07bf3369b5e1a4bf187762f2724b3bc7eb113239af3919f12202337", "image": { - "name": "k8s.gcr.io/kube-proxy:v1.16.15" + "name": "k8s.gcr.io/kube-controller-manager:v1.16.15" }, "runtime": "containerd" } @@ -716,12 +727,17 @@ "name": "kind-control-plane" }, "pod": { - "name": "kube-proxy-cm525" + "name": "kube-controller-manager-kind-control-plane" } }, "MetricSetFields": { - "id": "containerd://a55ee307ef431d293c02a7eb96417963d7b81b298a8ebfac2f77fe4ca58e1461", - "name": "kube-proxy", + "cpu": { + "request": { + "cores": 0.2 + } + }, + "id": "containerd://1c1919c3b07bf3369b5e1a4bf187762f2724b3bc7eb113239af3919f12202337", + "name": "kube-controller-manager", "status": { "last_terminated_reason": "Unknown", "phase": "running", @@ -782,9 +798,9 @@ { "RootFields": { "container": { - "id": "3037e577635e9cbcefe1f273e5b06784d36807af76158e4add887e840c42e1ef", + "id": "cd368e1731c278b039642fab2fe90902e2cfa470fd70a7ccfd5c2549a552cea5", "image": { - "name": "docker.io/kindest/kindnetd:v20210326-1e038dc5" + "name": "k8s.gcr.io/kube-scheduler:v1.16.15" }, "runtime": "containerd" } @@ -792,31 +808,20 @@ "ModuleFields": { "namespace": "kube-system", "node": { - "name": "kind-worker2" + "name": "kind-control-plane" }, "pod": { - "name": "kindnet-tg7tl" + "name": "kube-scheduler-kind-control-plane" } }, "MetricSetFields": { "cpu": { - "limit": { - "cores": 0.1 - }, "request": { "cores": 0.1 } }, - "id": "containerd://3037e577635e9cbcefe1f273e5b06784d36807af76158e4add887e840c42e1ef", - "memory": { - "limit": { - "bytes": 52428800 - }, - "request": { - "bytes": 52428800 - } - }, - "name": "kindnet-cni", + "id": "containerd://cd368e1731c278b039642fab2fe90902e2cfa470fd70a7ccfd5c2549a552cea5", + "name": "kube-scheduler", "status": { "last_terminated_reason": "Unknown", "phase": "running", @@ -838,35 +843,30 @@ { "RootFields": { "container": { - "id": "1c1919c3b07bf3369b5e1a4bf187762f2724b3bc7eb113239af3919f12202337", + "id": "02b0705f60dc6131a6b5d4e9a48e2510463f89a0f77e7e1bafa6b5f45cc595e8", "image": { - "name": "k8s.gcr.io/kube-controller-manager:v1.16.15" + "name": "docker.io/odise/busybox-python:latest" }, "runtime": "containerd" } }, "ModuleFields": { - "namespace": "kube-system", + "namespace": "default", "node": { - "name": "kind-control-plane" + "name": "kind-worker" }, "pod": { - "name": "kube-controller-manager-kind-control-plane" + "name": "hello-python-566b5479f5-ndwdl" } }, "MetricSetFields": { - "cpu": { - "request": { - "cores": 0.2 - } - }, - "id": "containerd://1c1919c3b07bf3369b5e1a4bf187762f2724b3bc7eb113239af3919f12202337", - "name": "kube-controller-manager", + "id": "containerd://02b0705f60dc6131a6b5d4e9a48e2510463f89a0f77e7e1bafa6b5f45cc595e8", + "name": "hello-python", "status": { "last_terminated_reason": "Unknown", "phase": "running", "ready": true, - "restarts": 4 + "restarts": 18 } }, "Index": "", @@ -880,4 +880,4 @@ "Period": 0, "DisableTimeSeries": false } -] +] \ No newline at end of file diff --git a/metricbeat/module/kubernetes/state_daemonset/state_daemonset.go b/metricbeat/module/kubernetes/state_daemonset/state_daemonset.go index 1066afa2195..8d80fc3f176 100644 --- a/metricbeat/module/kubernetes/state_daemonset/state_daemonset.go +++ b/metricbeat/module/kubernetes/state_daemonset/state_daemonset.go @@ -89,7 +89,7 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { return &MetricSet{ BaseMetricSet: base, prometheus: prometheus, - enricher: util.NewResourceMetadataEnricher(base, &kubernetes.ReplicaSet{}, false), + enricher: util.NewResourceMetadataEnricher(base, &kubernetes.DaemonSet{}, false), mod: mod, }, nil } @@ -127,7 +127,6 @@ func (m *MetricSet) Fetch(reporter mb.ReporterV2) { } } - return } // Close stops this metricset diff --git a/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.unit.v1.8.0.expected b/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.unit.v1.8.0.expected index 1cf75352eb0..1621330f9fa 100644 --- a/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.unit.v1.8.0.expected +++ b/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.unit.v1.8.0.expected @@ -1,6 +1,6 @@ [ { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "name": "test-pv-bound", @@ -18,7 +18,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "capacity": { @@ -38,7 +38,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "name": "test-pv-pending", @@ -56,7 +56,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "name": "test-pv-available", @@ -74,7 +74,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "capacity": { @@ -95,7 +95,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "name": "test-pv-released", @@ -113,7 +113,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "name": "test-pv-failed", @@ -131,7 +131,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": { "labels": { "app": "mysql-server" diff --git a/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v1.8.0.expected b/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v1.8.0.expected index 3b84fe01ec4..a554df87517 100644 --- a/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v1.8.0.expected +++ b/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v1.8.0.expected @@ -1,6 +1,6 @@ [ { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "capacity": { @@ -22,7 +22,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "capacity": { diff --git a/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v2.0.0.expected b/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v2.0.0.expected index 95c51d19690..cac996ee049 100644 --- a/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v2.0.0.expected +++ b/metricbeat/module/kubernetes/state_persistentvolume/_meta/test/ksm.v2.0.0.expected @@ -1,6 +1,6 @@ [ { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "capacity": { diff --git a/metricbeat/module/kubernetes/state_persistentvolume/state_persistentvolume.go b/metricbeat/module/kubernetes/state_persistentvolume/state_persistentvolume.go index 90847c63137..774a6dcd94f 100644 --- a/metricbeat/module/kubernetes/state_persistentvolume/state_persistentvolume.go +++ b/metricbeat/module/kubernetes/state_persistentvolume/state_persistentvolume.go @@ -20,6 +20,9 @@ package state_persistentvolume import ( "fmt" + "github.com/elastic/beats/v7/libbeat/common/kubernetes" + "github.com/elastic/beats/v7/metricbeat/module/kubernetes/util" + p "github.com/elastic/beats/v7/metricbeat/helper/prometheus" "github.com/elastic/beats/v7/metricbeat/mb" k8smod "github.com/elastic/beats/v7/metricbeat/module/kubernetes" @@ -38,6 +41,7 @@ type PersistentVolumeMetricSet struct { prometheus p.Prometheus mapping *p.MetricsMapping mod k8smod.Module + enricher util.Enricher } // NewPersistentVolumeMetricSet returns a prometheus based metricset for Persistent Volumes @@ -54,6 +58,7 @@ func NewPersistentVolumeMetricSet(base mb.BaseMetricSet) (mb.MetricSet, error) { BaseMetricSet: base, prometheus: prometheus, mod: mod, + enricher: util.NewResourceMetadataEnricher(base, &kubernetes.PersistentVolume{}, false), mapping: &p.MetricsMapping{ Metrics: map[string]p.MetricMap{ "kube_persistentvolume_capacity_bytes": p.Metric("capacity.bytes"), @@ -77,6 +82,8 @@ func NewPersistentVolumeMetricSet(base mb.BaseMetricSet) (mb.MetricSet, error) { // Fetch prometheus metrics and treats those prefixed by mb.ModuleDataKey as // module rooted fields at the event that gets reported func (m *PersistentVolumeMetricSet) Fetch(reporter mb.ReporterV2) { + m.enricher.Start() + families, err := m.mod.GetStateMetricsFamilies(m.prometheus) if err != nil { m.Logger().Error(err) @@ -90,13 +97,24 @@ func (m *PersistentVolumeMetricSet) Fetch(reporter mb.ReporterV2) { return } + m.enricher.Enrich(events) for _, event := range events { - event[mb.NamespaceKey] = "persistentvolume" - reported := reporter.Event(mb.TransformMapStrToEvent("kubernetes", event, nil)) - if !reported { + + e, err := util.CreateEvent(event, "kubernetes.persistentvolume") + if err != nil { + m.Logger().Error(err) + } + + if reported := reporter.Event(e); !reported { m.Logger().Debug("error trying to emit event") return } } - return + +} + +// Close stops this metricset +func (m *PersistentVolumeMetricSet) Close() error { + m.enricher.Stop() + return nil } diff --git a/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.unit.v1.8.0.expected b/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.unit.v1.8.0.expected index 1bafc31a84c..a82bc80ad5f 100644 --- a/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.unit.v1.8.0.expected +++ b/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.unit.v1.8.0.expected @@ -1,6 +1,6 @@ [ { - "RootFields": {}, + "RootFields": null, "ModuleFields": { "labels": { "app": "mysql-server" @@ -29,7 +29,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": { "namespace": "default" }, @@ -52,7 +52,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": null, "MetricSetFields": { "access_mode": "ReadWriteOnce", diff --git a/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v1.8.0.expected b/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v1.8.0.expected index e5c4c21bd2f..baaefa60df9 100644 --- a/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v1.8.0.expected +++ b/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v1.8.0.expected @@ -1,6 +1,6 @@ [ { - "RootFields": {}, + "RootFields": null, "ModuleFields": { "labels": { "app": "nginx" @@ -29,7 +29,7 @@ "DisableTimeSeries": false }, { - "RootFields": {}, + "RootFields": null, "ModuleFields": { "labels": { "app": "nginx" diff --git a/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v2.0.0.expected b/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v2.0.0.expected index 09a2c61e789..c23e59c4514 100644 --- a/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v2.0.0.expected +++ b/metricbeat/module/kubernetes/state_persistentvolumeclaim/_meta/test/ksm.v2.0.0.expected @@ -1,6 +1,6 @@ [ { - "RootFields": {}, + "RootFields": null, "ModuleFields": { "namespace": "default" }, diff --git a/metricbeat/module/kubernetes/state_persistentvolumeclaim/state_persistentvolumeclaim.go b/metricbeat/module/kubernetes/state_persistentvolumeclaim/state_persistentvolumeclaim.go index 3cf414c498a..93aa3ccce3a 100644 --- a/metricbeat/module/kubernetes/state_persistentvolumeclaim/state_persistentvolumeclaim.go +++ b/metricbeat/module/kubernetes/state_persistentvolumeclaim/state_persistentvolumeclaim.go @@ -20,6 +20,9 @@ package state_persistentvolumeclaim import ( "fmt" + "github.com/elastic/beats/v7/libbeat/common/kubernetes" + "github.com/elastic/beats/v7/metricbeat/module/kubernetes/util" + p "github.com/elastic/beats/v7/metricbeat/helper/prometheus" "github.com/elastic/beats/v7/metricbeat/mb" k8smod "github.com/elastic/beats/v7/metricbeat/module/kubernetes" @@ -37,6 +40,7 @@ type persistentvolumeclaimMetricSet struct { mb.BaseMetricSet prometheus p.Prometheus mapping *p.MetricsMapping + enricher util.Enricher mod k8smod.Module } @@ -54,6 +58,7 @@ func NewpersistentvolumeclaimMetricSet(base mb.BaseMetricSet) (mb.MetricSet, err BaseMetricSet: base, prometheus: prometheus, mod: mod, + enricher: util.NewResourceMetadataEnricher(base, &kubernetes.PersistentVolumeClaim{}, false), mapping: &p.MetricsMapping{ Metrics: map[string]p.MetricMap{ @@ -80,23 +85,40 @@ func NewpersistentvolumeclaimMetricSet(base mb.BaseMetricSet) (mb.MetricSet, err // Fetch prometheus metrics and treats those prefixed by mb.ModuleDataKey as // module rooted fields at the event that gets reported -func (m *persistentvolumeclaimMetricSet) Fetch(reporter mb.ReporterV2) error { +func (m *persistentvolumeclaimMetricSet) Fetch(reporter mb.ReporterV2) { + m.enricher.Start() families, err := m.mod.GetStateMetricsFamilies(m.prometheus) if err != nil { - return err + m.Logger().Error(err) + reporter.Error(err) + return } events, err := m.prometheus.ProcessMetrics(families, m.mapping) if err != nil { - return err + m.Logger().Error(err) + reporter.Error(err) + return } + m.enricher.Enrich(events) for _, event := range events { - event[mb.NamespaceKey] = "persistentvolumeclaim" - reported := reporter.Event(mb.TransformMapStrToEvent("kubernetes", event, nil)) - if !reported { + + e, err := util.CreateEvent(event, "kubernetes.persistentvolumeclaim") + if err != nil { + m.Logger().Error(err) + } + + if reported := reporter.Event(e); !reported { m.Logger().Debug("error trying to emit event") + return } } + +} + +// Close stops this metricset +func (m *persistentvolumeclaimMetricSet) Close() error { + m.enricher.Stop() return nil } diff --git a/metricbeat/module/kubernetes/util/kubernetes.go b/metricbeat/module/kubernetes/util/kubernetes.go index 3e5a68927bf..c6f341090cb 100644 --- a/metricbeat/module/kubernetes/util/kubernetes.go +++ b/metricbeat/module/kubernetes/util/kubernetes.go @@ -23,6 +23,8 @@ import ( "sync" "time" + k8sclient "k8s.io/client-go/kubernetes" + "github.com/elastic/beats/v7/libbeat/common/kubernetes/metadata" "github.com/elastic/elastic-agent-libs/mapstr" @@ -81,7 +83,7 @@ func NewResourceMetadataEnricher( res kubernetes.Resource, nodeScope bool) Enricher { - config := validatedConfig(base) + config := ValidatedConfig(base) if config == nil { logp.Info("Kubernetes metricset enriching is disabled") return &nilEnricher{} @@ -146,6 +148,12 @@ func NewResourceMetadataEnricher( m[id] = metaGen.Generate("namespace", r) case *kubernetes.ReplicaSet: m[id] = metaGen.Generate("replicaset", r) + case *kubernetes.DaemonSet: + m[id] = metaGen.Generate("daemonset", r) + case *kubernetes.PersistentVolume: + m[id] = metaGen.Generate("persistentvolume", r) + case *kubernetes.PersistentVolumeClaim: + m[id] = metaGen.Generate("persistentvolumeclaim", r) default: m[id] = metaGen.Generate(r.GetObjectKind().GroupVersionKind().Kind, r) } @@ -176,7 +184,7 @@ func NewContainerMetadataEnricher( base mb.BaseMetricSet, nodeScope bool) Enricher { - config := validatedConfig(base) + config := ValidatedConfig(base) if config == nil { logp.Info("Kubernetes metricset enriching is disabled") return &nilEnricher{} @@ -322,7 +330,7 @@ func GetDefaultDisabledMetaConfig() *kubernetesConfig { } } -func validatedConfig(base mb.BaseMetricSet) *kubernetesConfig { +func ValidatedConfig(base mb.BaseMetricSet) *kubernetesConfig { config := kubernetesConfig{ AddMetadata: true, SyncPeriod: time.Minute * 10, @@ -523,3 +531,18 @@ func ShouldDelete(event mapstr.M, field string, logger *logp.Logger) { logger.Debugf("Failed to delete field '%s': %s", field, err) } } + +func GetClusterECSMeta(cfg *conf.C, client k8sclient.Interface, logger *logp.Logger) (mapstr.M, error) { + clusterInfo, err := metadata.GetKubernetesClusterIdentifier(cfg, client) + if err != nil { + return nil, fmt.Errorf("fail to get kubernetes cluster metadata: %w", err) + } + ecsClusterMeta := mapstr.M{} + if clusterInfo.Url != "" { + ShouldPut(ecsClusterMeta, "orchestrator.cluster.url", clusterInfo.Url, logger) + } + if clusterInfo.Name != "" { + ShouldPut(ecsClusterMeta, "orchestrator.cluster.name", clusterInfo.Name, logger) + } + return ecsClusterMeta, nil +} diff --git a/metricbeat/module/kubernetes/volume/volume.go b/metricbeat/module/kubernetes/volume/volume.go index 5616fb69c23..1b8da935889 100644 --- a/metricbeat/module/kubernetes/volume/volume.go +++ b/metricbeat/module/kubernetes/volume/volume.go @@ -20,11 +20,16 @@ package volume import ( "fmt" + conf "github.com/elastic/elastic-agent-libs/config" + + "github.com/elastic/beats/v7/libbeat/common/kubernetes" "github.com/elastic/beats/v7/metricbeat/helper" "github.com/elastic/beats/v7/metricbeat/mb" "github.com/elastic/beats/v7/metricbeat/mb/parse" k8smod "github.com/elastic/beats/v7/metricbeat/module/kubernetes" + "github.com/elastic/beats/v7/metricbeat/module/kubernetes/util" "github.com/elastic/elastic-agent-libs/logp" + "github.com/elastic/elastic-agent-libs/mapstr" ) const ( @@ -56,8 +61,9 @@ func init() { // multiple fetch calls. type MetricSet struct { mb.BaseMetricSet - http *helper.HTTP - mod k8smod.Module + http *helper.HTTP + mod k8smod.Module + clusterMeta mapstr.M } // New create a new instance of the MetricSet @@ -72,11 +78,32 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { if !ok { return nil, fmt.Errorf("must be child of kubernetes module") } - return &MetricSet{ + + ms := &MetricSet{ BaseMetricSet: base, http: http, mod: mod, - }, nil + } + + // add ECS orchestrator fields + config := util.ValidatedConfig(base) + if config == nil { + logp.Info("Kubernetes metricset enriching is disabled") + } else { + client, err := kubernetes.GetKubernetesClient(config.KubeConfig, config.KubeClientOptions) + if err != nil { + return nil, fmt.Errorf("fail to get kubernetes client: %w", err) + } + cfg, _ := conf.NewConfigFrom(&config) + ecsClusterMeta, err := util.GetClusterECSMeta(cfg, client, ms.Logger()) + if err != nil { + ms.Logger().Debugf("could not retrieve cluster metadata: %w", err) + } + if ecsClusterMeta != nil { + ms.clusterMeta = ecsClusterMeta + } + } + return ms, nil } // Fetch methods implements the data gathering and data conversion to the right @@ -93,7 +120,11 @@ func (m *MetricSet) Fetch(reporter mb.ReporterV2) error { return err } for _, e := range events { - isOpen := reporter.Event(mb.TransformMapStrToEvent("kubernetes", e, nil)) + event := mb.TransformMapStrToEvent("kubernetes", e, nil) + if m.clusterMeta != nil { + event.RootFields.DeepUpdate(m.clusterMeta) + } + isOpen := reporter.Event(event) if !isOpen { return nil }