From 74da9e26a01eaeee753b366da22d21ceaa2f9397 Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Thu, 29 Jun 2023 18:17:57 -0700 Subject: [PATCH 1/2] [receiver/k8s_cluster] Add back all other vendor-specific node conditions --- ...-conditions-and-allocatable-resources.yaml | 20 ++++++++++ receiver/k8sclusterreceiver/go.mod | 1 + receiver/k8sclusterreceiver/go.sum | 2 + .../k8sclusterreceiver/internal/node/nodes.go | 40 ++++++++++++++----- .../internal/node/nodes_test.go | 21 +++++++++- .../internal/node/testdata/expected.yaml | 12 ++++++ .../internal/testutils/objects.go | 3 ++ 7 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 .chloggen/add-back-other-node-conditions-and-allocatable-resources.yaml diff --git a/.chloggen/add-back-other-node-conditions-and-allocatable-resources.yaml b/.chloggen/add-back-other-node-conditions-and-allocatable-resources.yaml new file mode 100644 index 000000000000..a1b078a11be6 --- /dev/null +++ b/.chloggen/add-back-other-node-conditions-and-allocatable-resources.yaml @@ -0,0 +1,20 @@ +# Use this changelog template to create an entry for release notes. +# If your change doesn't affect end users, such as a test fix or a tooling change, +# you should instead start your pull request title with [chore] or use the "Skip Changelog" label. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver) +component: k8sclusterreceiver + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Add back all other vendor-specific node conditions, and report them even if missing, as well as all allocatable node metrics if present, to the list of Kubernetes node metrics available, which went missing during the pdata translation + +# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists. +issues: [23839] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: diff --git a/receiver/k8sclusterreceiver/go.mod b/receiver/k8sclusterreceiver/go.mod index b2c943cdf277..744fb88033cd 100644 --- a/receiver/k8sclusterreceiver/go.mod +++ b/receiver/k8sclusterreceiver/go.mod @@ -6,6 +6,7 @@ require ( github.com/census-instrumentation/opencensus-proto v0.4.1 github.com/google/go-cmp v0.5.9 github.com/google/uuid v1.3.0 + github.com/iancoleman/strcase v0.2.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.80.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/coreinternal v0.80.0 github.com/open-telemetry/opentelemetry-collector-contrib/internal/k8sconfig v0.80.0 diff --git a/receiver/k8sclusterreceiver/go.sum b/receiver/k8sclusterreceiver/go.sum index 355c37aea88a..32e18c4beb61 100644 --- a/receiver/k8sclusterreceiver/go.sum +++ b/receiver/k8sclusterreceiver/go.sum @@ -299,6 +299,8 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= diff --git a/receiver/k8sclusterreceiver/internal/node/nodes.go b/receiver/k8sclusterreceiver/internal/node/nodes.go index 220591c40e61..e62c3b6078bf 100644 --- a/receiver/k8sclusterreceiver/internal/node/nodes.go +++ b/receiver/k8sclusterreceiver/internal/node/nodes.go @@ -7,11 +7,11 @@ import ( "fmt" "time" + "github.com/iancoleman/strcase" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver" conventions "go.opentelemetry.io/collector/semconv/v1.6.1" - "go.uber.org/zap" corev1 "k8s.io/api/core/v1" "github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/maps" @@ -46,23 +46,30 @@ func Transform(node *corev1.Node) *corev1.Node { func GetMetrics(set receiver.CreateSettings, node *corev1.Node, nodeConditionTypesToReport, allocatableTypesToReport []string) pmetric.Metrics { mb := imetadata.NewMetricsBuilder(imetadata.DefaultMetricsBuilderConfig(), set) ts := pcommon.NewTimestampFromTime(time.Now()) + customScopeMetrics := pmetric.NewMetrics().ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty() // Adding 'node condition type' metrics for _, nodeConditionTypeValue := range nodeConditionTypesToReport { v1NodeConditionTypeValue := corev1.NodeConditionType(nodeConditionTypeValue) + v := nodeConditionValue(node, v1NodeConditionTypeValue) switch v1NodeConditionTypeValue { case corev1.NodeReady: - mb.RecordK8sNodeConditionReadyDataPoint(ts, nodeConditionValue(node, v1NodeConditionTypeValue)) + mb.RecordK8sNodeConditionReadyDataPoint(ts, v) case corev1.NodeMemoryPressure: - mb.RecordK8sNodeConditionMemoryPressureDataPoint(ts, nodeConditionValue(node, v1NodeConditionTypeValue)) + mb.RecordK8sNodeConditionMemoryPressureDataPoint(ts, v) case corev1.NodeDiskPressure: - mb.RecordK8sNodeConditionDiskPressureDataPoint(ts, nodeConditionValue(node, v1NodeConditionTypeValue)) + mb.RecordK8sNodeConditionDiskPressureDataPoint(ts, v) case corev1.NodeNetworkUnavailable: - mb.RecordK8sNodeConditionNetworkUnavailableDataPoint(ts, nodeConditionValue(node, v1NodeConditionTypeValue)) + mb.RecordK8sNodeConditionNetworkUnavailableDataPoint(ts, v) case corev1.NodePIDPressure: - mb.RecordK8sNodeConditionPidPressureDataPoint(ts, nodeConditionValue(node, v1NodeConditionTypeValue)) + mb.RecordK8sNodeConditionPidPressureDataPoint(ts, v) default: - set.Logger.Warn("unknown node condition type", zap.String("conditionType", nodeConditionTypeValue)) + customMetric := customScopeMetrics.Metrics().AppendEmpty() + customMetric.SetName(getNodeConditionMetric(nodeConditionTypeValue)) + g := customMetric.SetEmptyGauge() + dp := g.DataPoints().AppendEmpty() + dp.SetIntValue(v) + dp.SetTimestamp(ts) } } @@ -89,10 +96,17 @@ func GetMetrics(set receiver.CreateSettings, node *corev1.Node, nodeConditionTyp case corev1.ResourcePods: mb.RecordK8sNodeAllocatablePodsDataPoint(ts, quantity.Value()) default: - set.Logger.Warn("unknown node condition type", zap.Any("conditionType", v1NodeAllocatableTypeValue)) + customMetric := customScopeMetrics.Metrics().AppendEmpty() + customMetric.SetName(getNodeAllocatableMetric(nodeAllocatableTypeValue)) + g := customMetric.SetEmptyGauge() + dp := g.DataPoints().AppendEmpty() + dp.SetIntValue(quantity.Value()) + dp.SetTimestamp(ts) } } - return mb.Emit(imetadata.WithK8sNodeUID(string(node.UID)), imetadata.WithK8sNodeName(node.Name), imetadata.WithOpencensusResourcetype("k8s")) + m := mb.Emit(imetadata.WithK8sNodeUID(string(node.UID)), imetadata.WithK8sNodeName(node.Name), imetadata.WithOpencensusResourcetype("k8s")) + customScopeMetrics.Metrics().MoveAndAppendTo(m.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics()) + return m } @@ -128,3 +142,11 @@ func GetMetadata(node *corev1.Node) map[experimentalmetricmetadata.ResourceID]*m }, } } + +func getNodeConditionMetric(nodeConditionTypeValue string) string { + return fmt.Sprintf("k8s.node.condition_%s", strcase.ToSnake(nodeConditionTypeValue)) +} + +func getNodeAllocatableMetric(nodeAllocatableTypeValue string) string { + return fmt.Sprintf("k8s.node.allocatable_%s", strcase.ToSnake(nodeAllocatableTypeValue)) +} diff --git a/receiver/k8sclusterreceiver/internal/node/nodes_test.go b/receiver/k8sclusterreceiver/internal/node/nodes_test.go index 47f2f64c6cc2..1adb61511e0f 100644 --- a/receiver/k8sclusterreceiver/internal/node/nodes_test.go +++ b/receiver/k8sclusterreceiver/internal/node/nodes_test.go @@ -21,7 +21,26 @@ import ( func TestNodeMetricsReportCPUMetrics(t *testing.T) { n := testutils.NewNode("1") - m := GetMetrics(receivertest.NewNopCreateSettings(), n, []string{"Ready", "MemoryPressure", "DiskPressure", "NetworkUnavailable", "PIDPressure", "OutOfDisk"}, []string{"cpu", "memory", "ephemeral-storage", "storage", "pods", "hugepages-1Gi", "hugepages-2Mi"}) + m := GetMetrics(receivertest.NewNopCreateSettings(), n, + []string{ + "Ready", + "MemoryPressure", + "DiskPressure", + "NetworkUnavailable", + "PIDPressure", + "OutOfDisk", + }, + []string{ + "cpu", + "memory", + "ephemeral-storage", + "storage", + "pods", + "hugepages-1Gi", + "hugepages-2Mi", + "not-present", + }, + ) expected, err := golden.ReadMetrics(filepath.Join("testdata", "expected.yaml")) require.NoError(t, err) require.NoError(t, pmetrictest.CompareMetrics(expected, m, diff --git a/receiver/k8sclusterreceiver/internal/node/testdata/expected.yaml b/receiver/k8sclusterreceiver/internal/node/testdata/expected.yaml index 8d9b1822f2e9..107c833cc90a 100644 --- a/receiver/k8sclusterreceiver/internal/node/testdata/expected.yaml +++ b/receiver/k8sclusterreceiver/internal/node/testdata/expected.yaml @@ -67,6 +67,18 @@ resourceMetrics: - asInt: "1" name: k8s.node.condition_ready unit: "1" + - gauge: + dataPoints: + - asInt: "-1" + name: k8s.node.condition_out_of_disk + - gauge: + dataPoints: + - asInt: "2" + name: k8s.node.allocatable_hugepages_1_gi + - gauge: + dataPoints: + - asInt: "2048" + name: k8s.node.allocatable_hugepages_2_mi scope: name: otelcol/k8sclusterreceiver version: latest \ No newline at end of file diff --git a/receiver/k8sclusterreceiver/internal/testutils/objects.go b/receiver/k8sclusterreceiver/internal/testutils/objects.go index 7e753c3648f3..17c33651a48f 100644 --- a/receiver/k8sclusterreceiver/internal/testutils/objects.go +++ b/receiver/k8sclusterreceiver/internal/testutils/objects.go @@ -171,6 +171,9 @@ func NewNode(id string) *corev1.Node { corev1.ResourceMemory: *resource.NewQuantity(456, resource.DecimalSI), corev1.ResourceEphemeralStorage: *resource.NewQuantity(1234, resource.DecimalSI), corev1.ResourcePods: *resource.NewQuantity(12, resource.DecimalSI), + "hugepages-1Gi": *resource.NewQuantity(2, resource.DecimalSI), + "hugepages-2Mi": *resource.NewQuantity(2048, resource.DecimalSI), + "hugepages-5Mi": *resource.NewQuantity(2048, resource.DecimalSI), }, }, } From 5f9c2b3dd4a496fdcbf8220abfbdab2732bd388e Mon Sep 17 00:00:00 2001 From: Antoine Toulme Date: Thu, 29 Jun 2023 23:21:35 -0700 Subject: [PATCH 2/2] code review --- receiver/k8sclusterreceiver/internal/node/nodes.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/receiver/k8sclusterreceiver/internal/node/nodes.go b/receiver/k8sclusterreceiver/internal/node/nodes.go index e62c3b6078bf..b02ee8ee5265 100644 --- a/receiver/k8sclusterreceiver/internal/node/nodes.go +++ b/receiver/k8sclusterreceiver/internal/node/nodes.go @@ -46,7 +46,7 @@ func Transform(node *corev1.Node) *corev1.Node { func GetMetrics(set receiver.CreateSettings, node *corev1.Node, nodeConditionTypesToReport, allocatableTypesToReport []string) pmetric.Metrics { mb := imetadata.NewMetricsBuilder(imetadata.DefaultMetricsBuilderConfig(), set) ts := pcommon.NewTimestampFromTime(time.Now()) - customScopeMetrics := pmetric.NewMetrics().ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty() + customMetrics := pmetric.NewMetricSlice() // Adding 'node condition type' metrics for _, nodeConditionTypeValue := range nodeConditionTypesToReport { @@ -64,7 +64,7 @@ func GetMetrics(set receiver.CreateSettings, node *corev1.Node, nodeConditionTyp case corev1.NodePIDPressure: mb.RecordK8sNodeConditionPidPressureDataPoint(ts, v) default: - customMetric := customScopeMetrics.Metrics().AppendEmpty() + customMetric := customMetrics.AppendEmpty() customMetric.SetName(getNodeConditionMetric(nodeConditionTypeValue)) g := customMetric.SetEmptyGauge() dp := g.DataPoints().AppendEmpty() @@ -96,7 +96,7 @@ func GetMetrics(set receiver.CreateSettings, node *corev1.Node, nodeConditionTyp case corev1.ResourcePods: mb.RecordK8sNodeAllocatablePodsDataPoint(ts, quantity.Value()) default: - customMetric := customScopeMetrics.Metrics().AppendEmpty() + customMetric := customMetrics.AppendEmpty() customMetric.SetName(getNodeAllocatableMetric(nodeAllocatableTypeValue)) g := customMetric.SetEmptyGauge() dp := g.DataPoints().AppendEmpty() @@ -105,7 +105,7 @@ func GetMetrics(set receiver.CreateSettings, node *corev1.Node, nodeConditionTyp } } m := mb.Emit(imetadata.WithK8sNodeUID(string(node.UID)), imetadata.WithK8sNodeName(node.Name), imetadata.WithOpencensusResourcetype("k8s")) - customScopeMetrics.Metrics().MoveAndAppendTo(m.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics()) + customMetrics.MoveAndAppendTo(m.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics()) return m }