From 20d0127df2773c959fcf19b87c398bcf31efb255 Mon Sep 17 00:00:00 2001 From: Dmitrii Anoshin Date: Fri, 16 Jun 2023 15:00:42 -0700 Subject: [PATCH] [receiver/k8s_cluster] Do not store unused data in k8s API cache (part 2) (#23432) Do not store unused data for deployments, statefulsets and daemonsets in k8s API cache to reduce RAM usage. Updates https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/23433 --- ...scluster-dont-store-unused-data-cache.yaml | 2 +- .../k8sclusterreceiver/informer_transform.go | 9 +++ .../informer_transform_test.go | 35 +++++++++ .../internal/demonset/daemonsets.go | 14 ++++ .../internal/demonset/daemonsets_test.go | 74 ++++++++++++++++++ .../internal/deployment/deployments.go | 14 ++++ .../internal/deployment/deployments_test.go | 75 +++++++++++++++++++ .../k8sclusterreceiver/internal/jobs/jobs.go | 10 +-- .../internal/metadata/metadata.go | 18 +++++ .../internal/metadata/metadata_test.go | 39 ++++++++++ .../k8sclusterreceiver/internal/node/nodes.go | 9 +-- .../k8sclusterreceiver/internal/pod/pods.go | 9 +-- .../internal/replicaset/replicasets.go | 21 +----- .../internal/statefulset/statefulsets.go | 16 ++++ .../internal/statefulset/statefulsets_test.go | 74 ++++++++++++++++++ 15 files changed, 378 insertions(+), 41 deletions(-) diff --git a/.chloggen/k8scluster-dont-store-unused-data-cache.yaml b/.chloggen/k8scluster-dont-store-unused-data-cache.yaml index 9fc00db38eac..dac2e9ead4d9 100644 --- a/.chloggen/k8scluster-dont-store-unused-data-cache.yaml +++ b/.chloggen/k8scluster-dont-store-unused-data-cache.yaml @@ -12,4 +12,4 @@ component: receiver/k8s_cluster note: Do not store unused data in the k8s API cache to reduce RAM usage # Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. -issues: [23417] +issues: [23433] diff --git a/receiver/k8sclusterreceiver/informer_transform.go b/receiver/k8sclusterreceiver/informer_transform.go index 26797bdf9962..d89b79314147 100644 --- a/receiver/k8sclusterreceiver/informer_transform.go +++ b/receiver/k8sclusterreceiver/informer_transform.go @@ -8,10 +8,13 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/demonset" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/deployment" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/jobs" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/node" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/pod" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/replicaset" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/statefulset" ) // transformObject transforms the k8s object by removing the data that is not utilized by the receiver. @@ -26,6 +29,12 @@ func transformObject(object interface{}) (interface{}, error) { return replicaset.Transform(o), nil case *batchv1.Job: return jobs.Transform(o), nil + case *appsv1.Deployment: + return deployment.Transform(o), nil + case *appsv1.DaemonSet: + return demonset.Transform(o), nil + case *appsv1.StatefulSet: + return statefulset.Transform(o), nil } return object, nil } diff --git a/receiver/k8sclusterreceiver/informer_transform_test.go b/receiver/k8sclusterreceiver/informer_transform_test.go index d47f18075d5e..fa87b4281a17 100644 --- a/receiver/k8sclusterreceiver/informer_transform_test.go +++ b/receiver/k8sclusterreceiver/informer_transform_test.go @@ -7,7 +7,9 @@ import ( "testing" "github.com/stretchr/testify/assert" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/testutils" ) @@ -58,6 +60,39 @@ func TestTransformObject(t *testing.T) { want: testutils.NewJob("1"), same: false, }, + { + name: "deployment", + object: testutils.NewDeployment("1"), + want: testutils.NewDeployment("1"), + same: false, + }, + { + name: "daemonset", + object: testutils.NewDaemonset("1"), + want: testutils.NewDaemonset("1"), + same: false, + }, + { + name: "statefulset", + object: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Replicas: func() *int32 { i := int32(3); return &i }(), + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "my-app", + }, + }, + }, + }, + }, + want: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Replicas: func() *int32 { i := int32(3); return &i }(), + }, + }, + same: false, + }, { // This is a case where we don't transform the object. name: "hpa", diff --git a/receiver/k8sclusterreceiver/internal/demonset/daemonsets.go b/receiver/k8sclusterreceiver/internal/demonset/daemonsets.go index 53cb226d7c27..4b5208e8e716 100644 --- a/receiver/k8sclusterreceiver/internal/demonset/daemonsets.go +++ b/receiver/k8sclusterreceiver/internal/demonset/daemonsets.go @@ -44,6 +44,20 @@ var daemonSetReadyMetric = &metricspb.MetricDescriptor{ Type: metricspb.MetricDescriptor_GAUGE_INT64, } +// Transform transforms the pod to remove the fields that we don't use to reduce RAM utilization. +// IMPORTANT: Make sure to update this function before using new daemonset fields. +func Transform(ds *appsv1.DaemonSet) *appsv1.DaemonSet { + return &appsv1.DaemonSet{ + ObjectMeta: metadata.TransformObjectMeta(ds.ObjectMeta), + Status: appsv1.DaemonSetStatus{ + CurrentNumberScheduled: ds.Status.CurrentNumberScheduled, + DesiredNumberScheduled: ds.Status.DesiredNumberScheduled, + NumberMisscheduled: ds.Status.NumberMisscheduled, + NumberReady: ds.Status.NumberReady, + }, + } +} + func GetMetrics(ds *appsv1.DaemonSet) []*agentmetricspb.ExportMetricsServiceRequest { metrics := []*metricspb.Metric{ { diff --git a/receiver/k8sclusterreceiver/internal/demonset/daemonsets_test.go b/receiver/k8sclusterreceiver/internal/demonset/daemonsets_test.go index d35a1f45d5f1..5dd869f9e6b0 100644 --- a/receiver/k8sclusterreceiver/internal/demonset/daemonsets_test.go +++ b/receiver/k8sclusterreceiver/internal/demonset/daemonsets_test.go @@ -7,7 +7,11 @@ import ( "testing" metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/constants" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/testutils" @@ -42,3 +46,73 @@ func TestDaemonsetMetrics(t *testing.T) { testutils.AssertMetricsInt(t, rm.Metrics[3], "k8s.daemonset.ready_nodes", metricspb.MetricDescriptor_GAUGE_INT64, 2) } + +func TestTransform(t *testing.T) { + originalDS := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-daemonset", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: appsv1.DaemonSetSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "my-app", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "my-container", + Image: "nginx:latest", + ImagePullPolicy: corev1.PullAlways, + Ports: []corev1.ContainerPort{ + { + Name: "http", + ContainerPort: 80, + Protocol: corev1.ProtocolTCP, + }, + }, + }, + }, + }, + }, + }, + Status: appsv1.DaemonSetStatus{ + CurrentNumberScheduled: 3, + NumberReady: 3, + DesiredNumberScheduled: 3, + NumberMisscheduled: 0, + Conditions: []appsv1.DaemonSetCondition{ + { + Type: "Available", + Status: corev1.ConditionTrue, + }, + }, + }, + } + wantDS := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-daemonset", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + }, + Status: appsv1.DaemonSetStatus{ + CurrentNumberScheduled: 3, + NumberReady: 3, + DesiredNumberScheduled: 3, + NumberMisscheduled: 0, + }, + } + assert.Equal(t, wantDS, Transform(originalDS)) +} diff --git a/receiver/k8sclusterreceiver/internal/deployment/deployments.go b/receiver/k8sclusterreceiver/internal/deployment/deployments.go index f4dd7e1e95af..daef5f5ab3e6 100644 --- a/receiver/k8sclusterreceiver/internal/deployment/deployments.go +++ b/receiver/k8sclusterreceiver/internal/deployment/deployments.go @@ -18,6 +18,20 @@ import ( "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/metadata" ) +// Transform transforms the pod to remove the fields that we don't use to reduce RAM utilization. +// IMPORTANT: Make sure to update this function before using new deployment fields. +func Transform(deployment *appsv1.Deployment) *appsv1.Deployment { + return &appsv1.Deployment{ + ObjectMeta: metadata.TransformObjectMeta(deployment.ObjectMeta), + Spec: appsv1.DeploymentSpec{ + Replicas: deployment.Spec.Replicas, + }, + Status: appsv1.DeploymentStatus{ + AvailableReplicas: deployment.Status.AvailableReplicas, + }, + } +} + func GetMetrics(set receiver.CreateSettings, dep *appsv1.Deployment) pmetric.Metrics { mb := imetadata.NewMetricsBuilder(imetadata.DefaultMetricsBuilderConfig(), set) ts := pcommon.NewTimestampFromTime(time.Now()) diff --git a/receiver/k8sclusterreceiver/internal/deployment/deployments_test.go b/receiver/k8sclusterreceiver/internal/deployment/deployments_test.go index 71677e588e67..f9cc2d8aa411 100644 --- a/receiver/k8sclusterreceiver/internal/deployment/deployments_test.go +++ b/receiver/k8sclusterreceiver/internal/deployment/deployments_test.go @@ -11,6 +11,9 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receivertest" + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal/golden" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest/pmetrictest" @@ -61,3 +64,75 @@ func TestGoldenFile(t *testing.T) { ), ) } + +func TestTransform(t *testing.T) { + origDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment", + UID: "my-deployment-uid", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: func() *int32 { replicas := int32(3); return &replicas }(), + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "my-app", + }, + }, + Template: v1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "my-container", + Image: "nginx:latest", + ImagePullPolicy: v1.PullAlways, + Ports: []v1.ContainerPort{ + { + Name: "http", + ContainerPort: 80, + Protocol: v1.ProtocolTCP, + }, + }, + }, + }, + }, + }, + }, + Status: appsv1.DeploymentStatus{ + Replicas: 3, + ReadyReplicas: 3, + AvailableReplicas: 3, + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: v1.ConditionTrue, + }, + }, + }, + } + wantDeployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-deployment", + UID: "my-deployment-uid", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: appsv1.DeploymentSpec{ + Replicas: func() *int32 { replicas := int32(3); return &replicas }(), + }, + Status: appsv1.DeploymentStatus{ + AvailableReplicas: 3, + }, + } + assert.Equal(t, wantDeployment, Transform(origDeployment)) +} diff --git a/receiver/k8sclusterreceiver/internal/jobs/jobs.go b/receiver/k8sclusterreceiver/internal/jobs/jobs.go index 7619110d779b..7bca1edea305 100644 --- a/receiver/k8sclusterreceiver/internal/jobs/jobs.go +++ b/receiver/k8sclusterreceiver/internal/jobs/jobs.go @@ -9,7 +9,6 @@ import ( resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1" conventions "go.opentelemetry.io/collector/semconv/v1.6.1" batchv1 "k8s.io/api/batch/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/constants" @@ -53,15 +52,10 @@ var podsSuccessfulMetric = &metricspb.MetricDescriptor{ } // Transform transforms the job to remove the fields that we don't use to reduce RAM utilization. -// IMPORTANT: Make sure to update this function when using a new job fields. +// IMPORTANT: Make sure to update this function before using new job fields. func Transform(job *batchv1.Job) *batchv1.Job { return &batchv1.Job{ - ObjectMeta: metav1.ObjectMeta{ - Name: job.ObjectMeta.Name, - Namespace: job.ObjectMeta.Namespace, - UID: job.ObjectMeta.UID, - Labels: job.ObjectMeta.Labels, - }, + ObjectMeta: metadata.TransformObjectMeta(job.ObjectMeta), Spec: batchv1.JobSpec{ Completions: job.Spec.Completions, Parallelism: job.Spec.Parallelism, diff --git a/receiver/k8sclusterreceiver/internal/metadata/metadata.go b/receiver/k8sclusterreceiver/internal/metadata/metadata.go index e81c8d26205c..6555713c6b24 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/metadata.go +++ b/receiver/k8sclusterreceiver/internal/metadata/metadata.go @@ -26,6 +26,24 @@ type KubernetesMetadata struct { Metadata map[string]string } +func TransformObjectMeta(om v1.ObjectMeta) v1.ObjectMeta { + newOM := v1.ObjectMeta{ + Name: om.Name, + Namespace: om.Namespace, + UID: om.UID, + CreationTimestamp: om.CreationTimestamp, + Labels: om.Labels, + } + for _, or := range om.OwnerReferences { + newOM.OwnerReferences = append(newOM.OwnerReferences, v1.OwnerReference{ + Kind: or.Kind, + Name: or.Name, + UID: or.UID, + }) + } + return newOM +} + // GetGenericMetadata is responsible for collecting metadata from K8s resources that // live on v1.ObjectMeta. func GetGenericMetadata(om *v1.ObjectMeta, resourceType string) *KubernetesMetadata { diff --git a/receiver/k8sclusterreceiver/internal/metadata/metadata_test.go b/receiver/k8sclusterreceiver/internal/metadata/metadata_test.go index 27f3ecd52d64..cbc8fb72720e 100644 --- a/receiver/k8sclusterreceiver/internal/metadata/metadata_test.go +++ b/receiver/k8sclusterreceiver/internal/metadata/metadata_test.go @@ -224,3 +224,42 @@ func TestGetMetadataUpdate(t *testing.T) { }) } } + +func TestTransformObjectMeta(t *testing.T) { + in := v1.ObjectMeta{ + Name: "my-pod", + UID: "12345678-1234-1234-1234-123456789011", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + Annotations: map[string]string{ + "version": "1.0", + "description": "Sample resource", + }, + OwnerReferences: []v1.OwnerReference{ + { + APIVersion: "apps/v1", + Kind: "ReplicaSet", + Name: "my-replicaset-1", + UID: "12345678-1234-1234-1234-123456789012", + }, + }, + } + want := v1.ObjectMeta{ + Name: "my-pod", + UID: "12345678-1234-1234-1234-123456789011", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + OwnerReferences: []v1.OwnerReference{ + { + Kind: "ReplicaSet", + Name: "my-replicaset-1", + UID: "12345678-1234-1234-1234-123456789012", + }, + }, + } + assert.Equal(t, want, TransformObjectMeta(in)) +} diff --git a/receiver/k8sclusterreceiver/internal/node/nodes.go b/receiver/k8sclusterreceiver/internal/node/nodes.go index 90c0411268ab..62dee34d8597 100644 --- a/receiver/k8sclusterreceiver/internal/node/nodes.go +++ b/receiver/k8sclusterreceiver/internal/node/nodes.go @@ -14,7 +14,6 @@ import ( conventions "go.opentelemetry.io/collector/semconv/v1.6.1" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/maps" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata" @@ -36,14 +35,10 @@ var allocatableDesciption = map[string]string{ } // Transform transforms the node to remove the fields that we don't use to reduce RAM utilization. -// IMPORTANT: Make sure to update this function when using a new node fields. +// IMPORTANT: Make sure to update this function before using new node fields. func Transform(node *corev1.Node) *corev1.Node { newNode := &corev1.Node{ - ObjectMeta: metav1.ObjectMeta{ - Name: node.ObjectMeta.Name, - UID: node.ObjectMeta.UID, - Labels: node.ObjectMeta.Labels, - }, + ObjectMeta: metadata.TransformObjectMeta(node.ObjectMeta), Status: corev1.NodeStatus{ Allocatable: node.Status.Allocatable, }, diff --git a/receiver/k8sclusterreceiver/internal/pod/pods.go b/receiver/k8sclusterreceiver/internal/pod/pods.go index c675478bd4b2..fff0b278047a 100644 --- a/receiver/k8sclusterreceiver/internal/pod/pods.go +++ b/receiver/k8sclusterreceiver/internal/pod/pods.go @@ -41,15 +41,10 @@ var podPhaseMetric = &metricspb.MetricDescriptor{ } // Transform transforms the pod to remove the fields that we don't use to reduce RAM utilization. -// IMPORTANT: Make sure to update this function when using a new pod fields. +// IMPORTANT: Make sure to update this function before using new pod fields. func Transform(pod *corev1.Pod) *corev1.Pod { newPod := &corev1.Pod{ - ObjectMeta: v1.ObjectMeta{ - UID: pod.ObjectMeta.UID, - Name: pod.ObjectMeta.Name, - Namespace: pod.ObjectMeta.Namespace, - Labels: pod.ObjectMeta.Labels, - }, + ObjectMeta: metadata.TransformObjectMeta(pod.ObjectMeta), Spec: corev1.PodSpec{ NodeName: pod.Spec.NodeName, }, diff --git a/receiver/k8sclusterreceiver/internal/replicaset/replicasets.go b/receiver/k8sclusterreceiver/internal/replicaset/replicasets.go index f1e606e5a7b4..fd77b5f80ccf 100644 --- a/receiver/k8sclusterreceiver/internal/replicaset/replicasets.go +++ b/receiver/k8sclusterreceiver/internal/replicaset/replicasets.go @@ -8,7 +8,6 @@ import ( resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1" conventions "go.opentelemetry.io/collector/semconv/v1.6.1" appsv1 "k8s.io/api/apps/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata" "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/constants" @@ -17,16 +16,10 @@ import ( ) // Transform transforms the replica set to remove the fields that we don't use to reduce RAM utilization. -// IMPORTANT: Make sure to update this function when using new replicaset fields. +// IMPORTANT: Make sure to update this function before using new replicaset fields. func Transform(rs *appsv1.ReplicaSet) *appsv1.ReplicaSet { - newRS := &appsv1.ReplicaSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: rs.ObjectMeta.Name, - Namespace: rs.ObjectMeta.Namespace, - UID: rs.ObjectMeta.UID, - CreationTimestamp: rs.ObjectMeta.CreationTimestamp, - Labels: rs.ObjectMeta.Labels, - }, + return &appsv1.ReplicaSet{ + ObjectMeta: metadata.TransformObjectMeta(rs.ObjectMeta), Spec: appsv1.ReplicaSetSpec{ Replicas: rs.Spec.Replicas, }, @@ -34,14 +27,6 @@ func Transform(rs *appsv1.ReplicaSet) *appsv1.ReplicaSet { AvailableReplicas: rs.Status.AvailableReplicas, }, } - for _, or := range rs.ObjectMeta.OwnerReferences { - newRS.ObjectMeta.OwnerReferences = append(newRS.ObjectMeta.OwnerReferences, metav1.OwnerReference{ - Name: or.Name, - UID: or.UID, - Kind: or.Kind, - }) - } - return newRS } func GetMetrics(rs *appsv1.ReplicaSet) []*agentmetricspb.ExportMetricsServiceRequest { diff --git a/receiver/k8sclusterreceiver/internal/statefulset/statefulsets.go b/receiver/k8sclusterreceiver/internal/statefulset/statefulsets.go index cf77e4279e3d..84ed8b6c515a 100644 --- a/receiver/k8sclusterreceiver/internal/statefulset/statefulsets.go +++ b/receiver/k8sclusterreceiver/internal/statefulset/statefulsets.go @@ -23,6 +23,22 @@ const ( statefulSetUpdateVersion = "update_revision" ) +// Transform transforms the pod to remove the fields that we don't use to reduce RAM utilization. +// IMPORTANT: Make sure to update this function before using new statefulset fields. +func Transform(statefulset *appsv1.StatefulSet) *appsv1.StatefulSet { + return &appsv1.StatefulSet{ + ObjectMeta: metadata.TransformObjectMeta(statefulset.ObjectMeta), + Spec: appsv1.StatefulSetSpec{ + Replicas: statefulset.Spec.Replicas, + }, + Status: appsv1.StatefulSetStatus{ + ReadyReplicas: statefulset.Status.ReadyReplicas, + CurrentReplicas: statefulset.Status.CurrentReplicas, + UpdatedReplicas: statefulset.Status.UpdatedReplicas, + }, + } +} + func GetMetrics(set receiver.CreateSettings, ss *appsv1.StatefulSet) pmetric.Metrics { if ss.Spec.Replicas == nil { return pmetric.NewMetrics() diff --git a/receiver/k8sclusterreceiver/internal/statefulset/statefulsets_test.go b/receiver/k8sclusterreceiver/internal/statefulset/statefulsets_test.go index 2374f50e1753..79f57231e7e6 100644 --- a/receiver/k8sclusterreceiver/internal/statefulset/statefulsets_test.go +++ b/receiver/k8sclusterreceiver/internal/statefulset/statefulsets_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/receiver/receivertest" appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -95,3 +96,76 @@ func newStatefulset(id string) *appsv1.StatefulSet { }, } } + +func TestTransform(t *testing.T) { + orig := &appsv1.StatefulSet{ + ObjectMeta: v1.ObjectMeta{ + Name: "my-statefulset", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: func() *int32 { i := int32(3); return &i }(), + Selector: &v1.LabelSelector{ + MatchLabels: map[string]string{ + "app": "my-app", + }, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: v1.ObjectMeta{ + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "my-container", + Image: "nginx:latest", + ImagePullPolicy: corev1.PullAlways, + Ports: []corev1.ContainerPort{ + { + Name: "http", + ContainerPort: 80, + Protocol: corev1.ProtocolTCP, + }, + }, + }, + }, + }, + }, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: 3, + ReadyReplicas: 3, + CurrentReplicas: 3, + UpdatedReplicas: 3, + Conditions: []appsv1.StatefulSetCondition{ + { + Type: "Ready", + Status: corev1.ConditionTrue, + }, + }, + }, + } + want := &appsv1.StatefulSet{ + ObjectMeta: v1.ObjectMeta{ + Name: "my-statefulset", + Namespace: "default", + Labels: map[string]string{ + "app": "my-app", + }, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: func() *int32 { i := int32(3); return &i }(), + }, + Status: appsv1.StatefulSetStatus{ + ReadyReplicas: 3, + CurrentReplicas: 3, + UpdatedReplicas: 3, + }, + } + assert.Equal(t, want, Transform(orig)) +}