diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go b/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go index 76d2613fe049..fb44453f61fb 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/accumulator_test.go @@ -41,7 +41,7 @@ func TestMetadataErrorCases(t *testing.T) { numMDs int numLogs int logMessages []string - detailedPVCLabelsSetterOverride func(volCacheID, volumeClaim, namespace string, labels map[string]string) error + detailedPVCLabelsSetterOverride func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) }{ { name: "Fails to get container metadata", @@ -178,9 +178,9 @@ func TestMetadataErrorCases(t *testing.T) { }, }, }, nil), - detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { + detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { // Mock failure cases. - return errors.New("") + return nil, errors.New("") }, testScenario: func(acc metricDataAccumulator) { podStats := stats.PodStats{ @@ -207,7 +207,7 @@ func TestMetadataErrorCases(t *testing.T) { observedLogger, logs := observer.New(zapcore.WarnLevel) logger := zap.New(observedLogger) - tt.metadata.DetailedPVCLabelsSetter = tt.detailedPVCLabelsSetterOverride + tt.metadata.DetailedPVCResourceGetter = tt.detailedPVCLabelsSetterOverride acc := metricDataAccumulator{ metadata: tt.metadata, logger: logger, diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go b/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go index 2288d5acd453..fdd74a5ec87e 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/metadata.go @@ -17,6 +17,7 @@ package kubelet // import "github.com/open-telemetry/opentelemetry-collector-con import ( "errors" "fmt" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver/internal/metadata" "regexp" conventions "go.opentelemetry.io/collector/semconv/v1.6.1" @@ -55,18 +56,18 @@ func ValidateMetadataLabelsConfig(labels []MetadataLabel) error { } type Metadata struct { - Labels map[MetadataLabel]bool - PodsMetadata *v1.PodList - DetailedPVCLabelsSetter func(volCacheID, volumeClaim, namespace string, labels map[string]string) error + Labels map[MetadataLabel]bool + PodsMetadata *v1.PodList + DetailedPVCResourceGetter func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) } func NewMetadata( labels []MetadataLabel, podsMetadata *v1.PodList, - detailedPVCLabelsSetter func(volCacheID, volumeClaim, namespace string, labels map[string]string) error) Metadata { + detailedPVCResourceGetter func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error)) Metadata { return Metadata{ - Labels: getLabelsMap(labels), - PodsMetadata: podsMetadata, - DetailedPVCLabelsSetter: detailedPVCLabelsSetter, + Labels: getLabelsMap(labels), + PodsMetadata: podsMetadata, + DetailedPVCResourceGetter: detailedPVCResourceGetter, } } @@ -78,45 +79,46 @@ func getLabelsMap(metadataLabels []MetadataLabel) map[MetadataLabel]bool { return out } -// setExtraLabels sets extra labels in `labels` map based on provided metadata label. -func (m *Metadata) setExtraLabels( - labels map[string]string, podRef stats.PodReference, - extraMetadataLabel MetadataLabel, extraMetadataFrom string) error { +// getExtraResources gets extra resources based on provided metadata label. +func (m *Metadata) getExtraResources(podRef stats.PodReference, extraMetadataLabel MetadataLabel, + extraMetadataFrom string) ([]metadata.ResourceOption, error) { // Ensure MetadataLabel exists before proceeding. if !m.Labels[extraMetadataLabel] || len(m.Labels) == 0 { - return nil + return nil, nil } // Cannot proceed, if metadata is unavailable. if m.PodsMetadata == nil { - return errors.New("pods metadata were not fetched") + return nil, errors.New("pods metadata were not fetched") } switch extraMetadataLabel { case MetadataLabelContainerID: containerID, err := m.getContainerID(podRef.UID, extraMetadataFrom) if err != nil { - return err + return nil, err } - labels[conventions.AttributeContainerID] = containerID + return []metadata.ResourceOption{metadata.WithContainerID(containerID)}, nil case MetadataLabelVolumeType: volume, err := m.getPodVolume(podRef.UID, extraMetadataFrom) if err != nil { - return err + return nil, err } - getLabelsFromVolume(volume, labels) + ro := getResourcesFromVolume(volume) // Get more labels from PersistentVolumeClaim volume type. if volume.PersistentVolumeClaim != nil { volCacheID := fmt.Sprintf("%s/%s", podRef.UID, extraMetadataFrom) - if err := m.DetailedPVCLabelsSetter(volCacheID, labels[labelPersistentVolumeClaimName], podRef.Namespace, - labels); err != nil { - return fmt.Errorf("failed to set labels from volume claim: %w", err) + pvcResources, err := m.DetailedPVCResourceGetter(volCacheID, volume.PersistentVolumeClaim.ClaimName, podRef.Namespace) + if err != nil { + return nil, fmt.Errorf("failed to set labels from volume claim: %w", err) } + ro = append(ro, pvcResources...) } + return ro, nil } - return nil + return nil, nil } // getContainerID retrieves container id from metadata for given pod UID and container name, diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/metadata_test.go b/receiver/kubeletstatsreceiver/internal/kubelet/metadata_test.go index 2021e6513f6a..38e415e0c3c7 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/metadata_test.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/metadata_test.go @@ -16,6 +16,7 @@ package kubelet import ( + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver/internal/metadata" "testing" "github.com/stretchr/testify/assert" @@ -23,6 +24,8 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1" + + "go.opentelemetry.io/collector/pdata/pcommon" ) func TestValidateMetadataLabelsConfig(t *testing.T) { @@ -75,13 +78,13 @@ func TestSetExtraLabels(t *testing.T) { metadata Metadata args []string wantError string - want map[string]string + want map[string]interface{} }{ { name: "no_labels", metadata: NewMetadata([]MetadataLabel{}, nil, nil), args: []string{"uid", "container.id", "container"}, - want: map[string]string{}, + want: map[string]interface{}{}, }, { name: "set_container_id_valid", @@ -103,7 +106,7 @@ func TestSetExtraLabels(t *testing.T) { }, }, nil), args: []string{"uid-1234", "container.id", "container1"}, - want: map[string]string{ + want: map[string]interface{}{ string(MetadataLabelContainerID): "test-container", }, }, @@ -166,11 +169,17 @@ func TestSetExtraLabels(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - fields := map[string]string{} - err := tt.metadata.setExtraLabels(fields, stats.PodReference{UID: tt.args[0]}, MetadataLabel(tt.args[1]), tt.args[2]) + ro, err := tt.metadata.getExtraResources(stats.PodReference{UID: tt.args[0]}, MetadataLabel(tt.args[1]), tt.args[2]) + + r := pcommon.NewResource() + for _, op := range ro { + op(r) + } + if tt.wantError == "" { require.NoError(t, err) - assert.EqualValues(t, tt.want, fields) + temp := r.Attributes().AsRaw() + assert.EqualValues(t, tt.want, temp) } else { assert.Equal(t, tt.wantError, err.Error()) } @@ -184,7 +193,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { name string vs v1.VolumeSource args []string - want map[string]string + want map[string]interface{} }{ { name: "hostPath", @@ -192,7 +201,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { HostPath: &v1.HostPathVolumeSource{}, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "hostPath", }, }, @@ -202,7 +211,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { ConfigMap: &v1.ConfigMapVolumeSource{}, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "configMap", }, }, @@ -212,7 +221,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { EmptyDir: &v1.EmptyDirVolumeSource{}, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "emptyDir", }, }, @@ -222,7 +231,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { Secret: &v1.SecretVolumeSource{}, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "secret", }, }, @@ -232,7 +241,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { DownwardAPI: &v1.DownwardAPIVolumeSource{}, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "downwardAPI", }, }, @@ -244,7 +253,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { }, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "persistentVolumeClaim", "k8s.persistentvolumeclaim.name": "claim-name", }, @@ -259,7 +268,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { }, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "awsElasticBlockStore", "aws.volume.id": "volume_id", "fs.type": "fs_type", @@ -276,7 +285,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { }, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "gcePersistentDisk", "gce.pd.name": "pd_name", "fs.type": "fs_type", @@ -292,7 +301,7 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { }, }, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{ + want: map[string]interface{}{ "k8s.volume.type": "glusterfs", "glusterfs.endpoints.name": "endspoints_name", "glusterfs.path": "path", @@ -302,12 +311,11 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { name: "unsupported type", vs: v1.VolumeSource{}, args: []string{"uid-1234", "k8s.volume.type"}, - want: map[string]string{}, + want: map[string]interface{}{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - fields := map[string]string{} volName := "volume0" metadata := NewMetadata([]MetadataLabel{MetadataLabelVolumeType}, &v1.PodList{ Items: []v1.Pod{ @@ -325,11 +333,17 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) { }, }, }, - }, func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { - return nil + }, func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { + return nil, nil }) - metadata.setExtraLabels(fields, stats.PodReference{UID: tt.args[0]}, MetadataLabel(tt.args[1]), volName) - assert.Equal(t, tt.want, fields) + ro, _ := metadata.getExtraResources(stats.PodReference{UID: tt.args[0]}, MetadataLabel(tt.args[1]), volName) + + r := pcommon.NewResource() + for _, op := range ro { + op(r) + } + + assert.Equal(t, tt.want, r.Attributes().AsRaw()) }) } } diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/resource.go b/receiver/kubeletstatsreceiver/internal/kubelet/resource.go index 83de0be16adc..53c7d57458a3 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/resource.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/resource.go @@ -16,52 +16,43 @@ package kubelet // import "github.com/open-telemetry/opentelemetry-collector-con import ( "fmt" + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver/internal/metadata" - "go.opentelemetry.io/collector/pdata/pcommon" - conventions "go.opentelemetry.io/collector/semconv/v1.6.1" stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1" ) -func fillNodeResource(dest pcommon.Resource, s stats.NodeStats) { - dest.Attributes().UpsertString(conventions.AttributeK8SNodeName, s.NodeName) -} - -func fillPodResource(dest pcommon.Resource, s stats.PodStats) { - dest.Attributes().UpsertString(conventions.AttributeK8SPodUID, s.PodRef.UID) - dest.Attributes().UpsertString(conventions.AttributeK8SPodName, s.PodRef.Name) - dest.Attributes().UpsertString(conventions.AttributeK8SNamespaceName, s.PodRef.Namespace) -} - -func fillContainerResource(dest pcommon.Resource, sPod stats.PodStats, sContainer stats.ContainerStats, metadata Metadata) error { - labels := map[string]string{ - conventions.AttributeK8SPodUID: sPod.PodRef.UID, - conventions.AttributeK8SPodName: sPod.PodRef.Name, - conventions.AttributeK8SNamespaceName: sPod.PodRef.Namespace, - conventions.AttributeK8SContainerName: sContainer.Name, - } - if err := metadata.setExtraLabels(labels, sPod.PodRef, MetadataLabelContainerID, sContainer.Name); err != nil { - return fmt.Errorf("failed to set extra labels from metadata: %w", err) +func getContainerResourceOptions(sPod stats.PodStats, sContainer stats.ContainerStats, k8sMetadata Metadata) ([]metadata.ResourceOption, error) { + ro := []metadata.ResourceOption{ + metadata.WithK8sPodUID(sPod.PodRef.UID), + metadata.WithK8sPodName(sPod.PodRef.Name), + metadata.WithK8sNamespaceName(sPod.PodRef.Namespace), + metadata.WithContainerName(sContainer.Name), } - for k, v := range labels { - dest.Attributes().UpsertString(k, v) + + extraResources, err := k8sMetadata.getExtraResources(sPod.PodRef, MetadataLabelContainerID, sContainer.Name) + if err != nil { + return nil, fmt.Errorf("failed to set extra labels from metadata: %w", err) } - return nil + + ro = append(ro, extraResources...) + + return ro, nil } -func fillVolumeResource(dest pcommon.Resource, sPod stats.PodStats, vs stats.VolumeStats, metadata Metadata) error { - labels := map[string]string{ - conventions.AttributeK8SPodUID: sPod.PodRef.UID, - conventions.AttributeK8SPodName: sPod.PodRef.Name, - conventions.AttributeK8SNamespaceName: sPod.PodRef.Namespace, - labelVolumeName: vs.Name, +func getVolumeResourceOptions(sPod stats.PodStats, vs stats.VolumeStats, k8sMetadata Metadata) ([]metadata.ResourceOption, error) { + ro := []metadata.ResourceOption{ + metadata.WithK8sPodUID(sPod.PodRef.UID), + metadata.WithK8sPodName(sPod.PodRef.Name), + metadata.WithK8sNamespaceName(sPod.PodRef.Namespace), + metadata.WithK8sVolumeName(vs.Name), } - if err := metadata.setExtraLabels(labels, sPod.PodRef, MetadataLabelVolumeType, vs.Name); err != nil { - return fmt.Errorf("failed to set extra labels from metadata: %w", err) + extraResources, err := k8sMetadata.getExtraResources(sPod.PodRef, MetadataLabelVolumeType, vs.Name) + if err != nil { + return nil, fmt.Errorf("failed to set extra labels from metadata: %w", err) } - for k, v := range labels { - dest.Attributes().UpsertString(k, v) - } - return nil + ro = append(ro, extraResources...) + + return ro, nil } diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/volume.go b/receiver/kubeletstatsreceiver/internal/kubelet/volume.go index 4cfe92002e22..a5bf353dc5e5 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/volume.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/volume.go @@ -31,72 +31,80 @@ func addVolumeMetrics(mb *metadata.MetricsBuilder, volumeMetrics metadata.Volume recordIntDataPoint(mb, volumeMetrics.InodesUsed, s.InodesUsed, currentTime) } -func getLabelsFromVolume(volume v1.Volume, labels map[string]string) { +func getResourcesFromVolume(volume v1.Volume) []metadata.ResourceOption { switch { // TODO: Support more types case volume.ConfigMap != nil: - labels[labelVolumeType] = labelValueConfigMapVolume + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValueConfigMapVolume)} case volume.DownwardAPI != nil: - labels[labelVolumeType] = labelValueDownwardAPIVolume + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValueDownwardAPIVolume)} case volume.EmptyDir != nil: - labels[labelVolumeType] = labelValueEmptyDirVolume + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValueEmptyDirVolume)} case volume.Secret != nil: - labels[labelVolumeType] = labelValueSecretVolume + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValueSecretVolume)} case volume.PersistentVolumeClaim != nil: - labels[labelVolumeType] = labelValuePersistentVolumeClaim - labels[labelPersistentVolumeClaimName] = volume.PersistentVolumeClaim.ClaimName + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValuePersistentVolumeClaim), + metadata.WithK8sPersistentvolumeclaimName(volume.PersistentVolumeClaim.ClaimName)} case volume.HostPath != nil: - labels[labelVolumeType] = labelValueHostPathVolume + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValueHostPathVolume)} case volume.AWSElasticBlockStore != nil: - awsElasticBlockStoreDims(*volume.AWSElasticBlockStore, labels) + return awsElasticBlockStoreDims(*volume.AWSElasticBlockStore) case volume.GCEPersistentDisk != nil: - gcePersistentDiskDims(*volume.GCEPersistentDisk, labels) + return gcePersistentDiskDims(*volume.GCEPersistentDisk) case volume.Glusterfs != nil: - glusterfsDims(*volume.Glusterfs, labels) + return glusterfsDims(*volume.Glusterfs) } + return nil } -func GetPersistentVolumeLabels(pv v1.PersistentVolumeSource, labels map[string]string) { +func GetPersistentVolumeLabels(pv v1.PersistentVolumeSource) []metadata.ResourceOption { // TODO: Support more types switch { case pv.Local != nil: - labels[labelVolumeType] = labelValueLocalVolume + return []metadata.ResourceOption{metadata.WithK8sVolumeType(labelValueLocalVolume)} case pv.AWSElasticBlockStore != nil: - awsElasticBlockStoreDims(*pv.AWSElasticBlockStore, labels) + return awsElasticBlockStoreDims(*pv.AWSElasticBlockStore) case pv.GCEPersistentDisk != nil: - gcePersistentDiskDims(*pv.GCEPersistentDisk, labels) + return gcePersistentDiskDims(*pv.GCEPersistentDisk) case pv.Glusterfs != nil: // pv.Glusterfs is a GlusterfsPersistentVolumeSource instead of GlusterfsVolumeSource, // convert to GlusterfsVolumeSource so a single method can handle both structs. This // can be broken out into separate methods if one is interested in different sets // of labels from the two structs in the future. - glusterfsDims(v1.GlusterfsVolumeSource{ + return glusterfsDims(v1.GlusterfsVolumeSource{ EndpointsName: pv.Glusterfs.EndpointsName, Path: pv.Glusterfs.Path, ReadOnly: pv.Glusterfs.ReadOnly, - }, labels) + }) } + return nil } -func awsElasticBlockStoreDims(vs v1.AWSElasticBlockStoreVolumeSource, labels map[string]string) { - labels[labelVolumeType] = labelValueAWSEBSVolume - // AWS specific labels. - labels[labelAwsVolumeID] = vs.VolumeID - labels[labelFsType] = vs.FSType - labels[labelPartition] = strconv.Itoa(int(vs.Partition)) +func awsElasticBlockStoreDims(vs v1.AWSElasticBlockStoreVolumeSource) []metadata.ResourceOption { + return []metadata.ResourceOption{ + metadata.WithK8sVolumeType(labelValueAWSEBSVolume), + // AWS specific labels. + metadata.WithAwsVolumeID(vs.VolumeID), + metadata.WithFsType(vs.FSType), + metadata.WithPartition(strconv.Itoa(int(vs.Partition))), + } } -func gcePersistentDiskDims(vs v1.GCEPersistentDiskVolumeSource, labels map[string]string) { - labels[labelVolumeType] = labelValueGCEPDVolume - // GCP specific labels. - labels[labelGcePdName] = vs.PDName - labels[labelFsType] = vs.FSType - labels[labelPartition] = strconv.Itoa(int(vs.Partition)) +func gcePersistentDiskDims(vs v1.GCEPersistentDiskVolumeSource) []metadata.ResourceOption { + return []metadata.ResourceOption{ + metadata.WithK8sVolumeType(labelValueGCEPDVolume), + // GCP specific labels. + metadata.WithGcePdName(vs.PDName), + metadata.WithFsType(vs.FSType), + metadata.WithPartition(strconv.Itoa(int(vs.Partition))), + } } -func glusterfsDims(vs v1.GlusterfsVolumeSource, labels map[string]string) { - labels[labelVolumeType] = labelValueGlusterFSVolume - // GlusterFS specific labels. - labels[labelGlusterfsEndpointsName] = vs.EndpointsName - labels[labelGlusterfsPath] = vs.Path +func glusterfsDims(vs v1.GlusterfsVolumeSource) []metadata.ResourceOption { + return []metadata.ResourceOption{ + metadata.WithK8sVolumeType(labelValueGlusterFSVolume), + // GlusterFS specific labels. + metadata.WithGlusterfsEndpointsName(vs.EndpointsName), + metadata.WithGlusterfsPath(vs.Path), + } } diff --git a/receiver/kubeletstatsreceiver/internal/kubelet/volume_test.go b/receiver/kubeletstatsreceiver/internal/kubelet/volume_test.go index 7bb8e6aacf68..64a038b29a4d 100644 --- a/receiver/kubeletstatsreceiver/internal/kubelet/volume_test.go +++ b/receiver/kubeletstatsreceiver/internal/kubelet/volume_test.go @@ -15,6 +15,7 @@ package kubelet import ( + "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/kubeletstatsreceiver/internal/metadata" "testing" "github.com/stretchr/testify/require" @@ -38,7 +39,7 @@ func TestDetailedPVCLabels(t *testing.T) { volumeName string volumeSource v1.VolumeSource pod pod - detailedPVCLabelsSetterOverride func(volCacheID, volumeClaim, namespace string, labels map[string]string) error + detailedPVCLabelsSetterOverride func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) want map[string]interface{} }{ { @@ -50,15 +51,15 @@ func TestDetailedPVCLabels(t *testing.T) { }, }, pod: pod{uid: "uid-1234", name: "pod-name", namespace: "pod-namespace"}, - detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { - GetPersistentVolumeLabels(v1.PersistentVolumeSource{ + detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { + ro := GetPersistentVolumeLabels(v1.PersistentVolumeSource{ AWSElasticBlockStore: &v1.AWSElasticBlockStoreVolumeSource{ VolumeID: "volume_id", FSType: "fs_type", Partition: 10, }, - }, labels) - return nil + }) + return ro, nil }, want: map[string]interface{}{ "k8s.volume.name": "volume0", @@ -81,15 +82,15 @@ func TestDetailedPVCLabels(t *testing.T) { }, }, pod: pod{uid: "uid-1234", name: "pod-name", namespace: "pod-namespace"}, - detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { - GetPersistentVolumeLabels(v1.PersistentVolumeSource{ + detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { + ro := GetPersistentVolumeLabels(v1.PersistentVolumeSource{ GCEPersistentDisk: &v1.GCEPersistentDiskVolumeSource{ PDName: "pd_name", FSType: "fs_type", Partition: 10, }, - }, labels) - return nil + }) + return ro, nil }, want: map[string]interface{}{ "k8s.volume.name": "volume0", @@ -112,14 +113,14 @@ func TestDetailedPVCLabels(t *testing.T) { }, }, pod: pod{uid: "uid-1234", name: "pod-name", namespace: "pod-namespace"}, - detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { - GetPersistentVolumeLabels(v1.PersistentVolumeSource{ + detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { + ro := GetPersistentVolumeLabels(v1.PersistentVolumeSource{ Glusterfs: &v1.GlusterfsPersistentVolumeSource{ EndpointsName: "endpoints_name", Path: "path", }, - }, labels) - return nil + }) + return ro, nil }, want: map[string]interface{}{ "k8s.volume.name": "volume0", @@ -141,13 +142,13 @@ func TestDetailedPVCLabels(t *testing.T) { }, }, pod: pod{uid: "uid-1234", name: "pod-name", namespace: "pod-namespace"}, - detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { - GetPersistentVolumeLabels(v1.PersistentVolumeSource{ + detailedPVCLabelsSetterOverride: func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { + ro := GetPersistentVolumeLabels(v1.PersistentVolumeSource{ Local: &v1.LocalVolumeSource{ Path: "path", }, - }, labels) - return nil + }) + return ro, nil }, want: map[string]interface{}{ "k8s.volume.name": "volume0", @@ -187,7 +188,7 @@ func TestDetailedPVCLabels(t *testing.T) { }, }, }, nil) - metadata.DetailedPVCLabelsSetter = tt.detailedPVCLabelsSetterOverride + metadata.DetailedPVCResourceGetter = tt.detailedPVCLabelsSetterOverride ro, err := getVolumeResourceOptions(podStats, stats.VolumeStats{Name: tt.volumeName}, metadata) require.NoError(t, err) diff --git a/receiver/kubeletstatsreceiver/scraper.go b/receiver/kubeletstatsreceiver/scraper.go index c97dd1e0d316..16ad22e4b5a3 100644 --- a/receiver/kubeletstatsreceiver/scraper.go +++ b/receiver/kubeletstatsreceiver/scraper.go @@ -47,7 +47,7 @@ type kubletScraper struct { extraMetadataLabels []kubelet.MetadataLabel metricGroupsToCollect map[kubelet.MetricGroup]bool k8sAPIClient kubernetes.Interface - cachedVolumeLabels map[string]map[string]string + cachedVolumeLabels map[string][]metadata.ResourceOption mb *metadata.MetricsBuilder } @@ -64,7 +64,7 @@ func newKubletScraper( extraMetadataLabels: rOptions.extraMetadataLabels, metricGroupsToCollect: rOptions.metricGroupsToCollect, k8sAPIClient: rOptions.k8sAPIClient, - cachedVolumeLabels: make(map[string]map[string]string), + cachedVolumeLabels: make(map[string][]metadata.ResourceOption), mb: metadata.NewMetricsBuilder(metricsConfig), } return scraperhelper.NewScraper(typeStr, ks.scrape) @@ -96,39 +96,34 @@ func (r *kubletScraper) scrape(context.Context) (pmetric.Metrics, error) { return md, nil } -func (r *kubletScraper) detailedPVCLabelsSetter() func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { - return func(volCacheID, volumeClaim, namespace string, labels map[string]string) error { +func (r *kubletScraper) detailedPVCLabelsSetter() func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { + return func(volCacheID, volumeClaim, namespace string) ([]metadata.ResourceOption, error) { if r.k8sAPIClient == nil { - return nil + return nil, nil } if r.cachedVolumeLabels[volCacheID] == nil { ctx := context.Background() pvc, err := r.k8sAPIClient.CoreV1().PersistentVolumeClaims(namespace).Get(ctx, volumeClaim, metav1.GetOptions{}) if err != nil { - return err + return nil, err } volName := pvc.Spec.VolumeName if volName == "" { - return fmt.Errorf("PersistentVolumeClaim %s does not have a volume name", pvc.Name) + return nil, fmt.Errorf("PersistentVolumeClaim %s does not have a volume name", pvc.Name) } pv, err := r.k8sAPIClient.CoreV1().PersistentVolumes().Get(ctx, volName, metav1.GetOptions{}) if err != nil { - return err + return nil, err } - labelsToCache := make(map[string]string) - kubelet.GetPersistentVolumeLabels(pv.Spec.PersistentVolumeSource, labelsToCache) + ro := kubelet.GetPersistentVolumeLabels(pv.Spec.PersistentVolumeSource) // Cache collected labels. - r.cachedVolumeLabels[volCacheID] = labelsToCache + r.cachedVolumeLabels[volCacheID] = ro } - - for k, v := range r.cachedVolumeLabels[volCacheID] { - labels[k] = v - } - return nil + return r.cachedVolumeLabels[volCacheID], nil } }