From 50504ddc41ff1821cf5c3c66c7a25fa5dc30c3dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20Burzy=C5=84ski?= Date: Wed, 23 Oct 2024 09:01:01 +0200 Subject: [PATCH] fix(konnect): truncate tags and labels to max allowed length (#775) --- controller/konnect/ops/objects_metadata.go | 20 ++++- .../konnect/ops/objects_metadata_test.go | 81 ++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/controller/konnect/ops/objects_metadata.go b/controller/konnect/ops/objects_metadata.go index a4a590c65..57f4966bb 100644 --- a/controller/konnect/ops/objects_metadata.go +++ b/controller/konnect/ops/objects_metadata.go @@ -71,9 +71,12 @@ func generateKubernetesMetadataTags(obj ObjectWithMetadata) []string { if k8sNamespace := obj.GetNamespace(); k8sNamespace != "" { labels = append(labels, lo.Entry[string, string]{Key: KubernetesNamespaceLabelKey, Value: k8sNamespace}) } + + // The maximum length of a tag in Konnect is 128 characters. We truncate them to ensure they are within the limit. + const maxAllowedValueLength = 128 tags := make([]string, 0, len(labels)) for _, label := range labels { - tags = append(tags, fmt.Sprintf("%s:%s", label.Key, label.Value)) + tags = append(tags, truncate(fmt.Sprintf("%s:%s", label.Key, label.Value), maxAllowedValueLength)) } return tags } @@ -95,6 +98,14 @@ func WithKubernetesMetadataLabels(obj ObjectWithMetadata, userSetLabels map[stri for k, v := range userSetLabels { labels[k] = v } + + // The maximum length of a label value in Konnect is 63 characters. We truncate the values to ensure they are + // within the limit. + const maxAllowedValueLength = 63 + for k, v := range labels { + labels[k] = truncate(v, maxAllowedValueLength) + } + return labels } @@ -103,3 +114,10 @@ func WithKubernetesMetadataLabels(obj ObjectWithMetadata, userSetLabels map[stri func UIDLabelForObject(obj client.Object) string { return fmt.Sprintf("%s:%s", KubernetesUIDLabelKey, obj.GetUID()) } + +func truncate(s string, limit int) string { + if len(s) <= limit { + return s + } + return s[:limit] +} diff --git a/controller/konnect/ops/objects_metadata_test.go b/controller/konnect/ops/objects_metadata_test.go index fa0c0807b..91595a2c1 100644 --- a/controller/konnect/ops/objects_metadata_test.go +++ b/controller/konnect/ops/objects_metadata_test.go @@ -19,6 +19,7 @@ func TestWithKubernetesMetadataLabels(t *testing.T) { testCases := []struct { name string obj testObjectKind + userLabels map[string]string expectedLabels map[string]string }{ { @@ -67,11 +68,65 @@ func TestWithKubernetesMetadataLabels(t *testing.T) { ops.KubernetesGenerationLabelKey: "2", }, }, + { + name: "user-provided labels are added", + obj: testObjectKind{ + TypeMeta: metav1.TypeMeta{ + Kind: "TestObjectKind", + APIVersion: "test.objects.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-object", + Namespace: "test-namespace", + UID: "test-uid", + Generation: 2, + }, + }, + userLabels: map[string]string{ + "custom-label": "custom-value", + "another-label": "another-value", + }, + expectedLabels: map[string]string{ + ops.KubernetesKindLabelKey: "TestObjectKind", + ops.KubernetesGroupLabelKey: "test.objects.io", + ops.KubernetesVersionLabelKey: "v1", + ops.KubernetesNameLabelKey: "test-object", + ops.KubernetesNamespaceLabelKey: "test-namespace", + ops.KubernetesUIDLabelKey: "test-uid", + ops.KubernetesGenerationLabelKey: "2", + "custom-label": "custom-value", + "another-label": "another-value", + }, + }, + { + name: "too long kind, group, name, and namespace are truncated", + obj: testObjectKind{ + TypeMeta: metav1.TypeMeta{ + Kind: "TestObjectKindWithAVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName", + APIVersion: "testlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong.objects.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "testobjectverylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong", + Namespace: "testnamespaceverylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong", + UID: "test-uid", + Generation: 2, + }, + }, + expectedLabels: map[string]string{ + ops.KubernetesKindLabelKey: "TestObjectKindWithAVeryLongLongLongLongLongLongLongLongLongLong", + ops.KubernetesGroupLabelKey: "testlonglonglonglonglonglonglonglonglonglonglonglonglonglonglon", + ops.KubernetesVersionLabelKey: "v1", + ops.KubernetesNameLabelKey: "testobjectverylonglonglonglonglonglonglonglonglonglonglonglongl", + ops.KubernetesNamespaceLabelKey: "testnamespaceverylonglonglonglonglonglonglonglonglonglonglonglo", + ops.KubernetesUIDLabelKey: "test-uid", + ops.KubernetesGenerationLabelKey: "2", + }, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - labels := ops.WithKubernetesMetadataLabels(&tc.obj, tc.expectedLabels) + labels := ops.WithKubernetesMetadataLabels(&tc.obj, tc.userLabels) require.Equal(t, tc.expectedLabels, labels) }) } @@ -182,6 +237,30 @@ func TestGenerateTagsForObject(t *testing.T) { "tag3", }, }, + { + name: "too long kind, group, name, and namespace are truncated", + obj: testObjectKind{ + TypeMeta: metav1.TypeMeta{ + Kind: "TestObjectKindWithAVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongName", + APIVersion: "testlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong.objects.io/v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "testobjectverylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongname", + Namespace: "testnamespaceverylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongnamespace", + UID: "test-uid", + Generation: 2, + }, + }, + expectedTags: []string{ + "k8s-generation:2", + "k8s-group:testlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglo", + "k8s-kind:TestObjectKindWithAVeryLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLongLong", + "k8s-name:testobjectverylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongl", + "k8s-namespace:testnamespaceverylonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglongl", + "k8s-uid:test-uid", + "k8s-version:v1", + }, + }, } for _, tc := range testCases {