Skip to content

Commit 5103776

Browse files
committed
add tests
1 parent 3f5af2b commit 5103776

File tree

2 files changed

+114
-24
lines changed

2 files changed

+114
-24
lines changed

pkg/instrumentation/sdk.go

+40-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package instrumentation
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"sort"
1011
"strings"
@@ -24,6 +25,7 @@ import (
2425
"k8s.io/client-go/util/retry"
2526
"sigs.k8s.io/controller-runtime/pkg/client"
2627

28+
"github.com/distribution/reference"
2729
"github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1"
2830
"github.com/open-telemetry/opentelemetry-operator/internal/config"
2931
"github.com/open-telemetry/opentelemetry-operator/pkg/constants"
@@ -454,13 +456,46 @@ func chooseServiceVersion(pod corev1.Pod, useLabelsForResourceAttributes bool, i
454456
if v != "" {
455457
return v
456458
}
457-
parts := strings.Split(pod.Spec.Containers[index].Image, ":")
458-
tag := parts[len(parts)-1]
459-
//guard statement to handle case where image name has a port number
460-
if strings.Contains(tag, "/") {
459+
var err error
460+
v, err = parseServiceVersionFromImage(pod.Spec.Containers[index].Image)
461+
if err != nil {
461462
return ""
462463
}
463-
return tag
464+
return v
465+
}
466+
467+
var cannotRetrieveImage = errors.New("cannot retrieve image name")
468+
469+
// parseServiceVersionFromImage parses the service version for differently-formatted image names
470+
// according to https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/k8s-attributes.md#how-serviceversion-should-be-calculated
471+
func parseServiceVersionFromImage(image string) (string, error) {
472+
ref, err := reference.Parse(image)
473+
if err != nil {
474+
return "", err
475+
}
476+
477+
namedRef, ok := ref.(reference.Named)
478+
if !ok {
479+
return "", cannotRetrieveImage
480+
}
481+
var tag, digest string
482+
if taggedRef, ok := namedRef.(reference.Tagged); ok {
483+
tag = taggedRef.Tag()
484+
}
485+
if digestedRef, ok := namedRef.(reference.Digested); ok {
486+
digest = digestedRef.Digest().String()
487+
}
488+
if digest != "" {
489+
if tag != "" {
490+
return fmt.Sprintf("%s@%s", tag, digest), nil
491+
}
492+
return digest, nil
493+
}
494+
if tag != "" {
495+
return tag, nil
496+
}
497+
498+
return "", cannotRetrieveImage
464499
}
465500

466501
// chooseServiceInstanceId returns the service.instance.id to be used in the instrumentation.

pkg/instrumentation/sdk_test.go

+74-19
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ func TestSDKInjection(t *testing.T) {
147147
Labels: map[string]string{
148148
"app.kubernetes.io/name": "app-name",
149149
"app.kubernetes.io/version": "v1",
150-
"app.kubernetes.io/part-of": "shop",
151150
},
152151
Annotations: map[string]string{
153152
"resource.opentelemetry.io/foo": "bar",
@@ -157,7 +156,7 @@ func TestSDKInjection(t *testing.T) {
157156
Containers: []corev1.Container{
158157
{
159158
Name: "application-name",
160-
Image: "app:latest",
159+
Image: "app:v1@sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
161160
},
162161
},
163162
},
@@ -170,7 +169,6 @@ func TestSDKInjection(t *testing.T) {
170169
Labels: map[string]string{
171170
"app.kubernetes.io/name": "app-name",
172171
"app.kubernetes.io/version": "v1",
173-
"app.kubernetes.io/part-of": "shop",
174172
},
175173
Annotations: map[string]string{
176174
"resource.opentelemetry.io/foo": "bar",
@@ -188,7 +186,7 @@ func TestSDKInjection(t *testing.T) {
188186
Containers: []corev1.Container{
189187
{
190188
Name: "application-name",
191-
Image: "app:latest",
189+
Image: "app:v1@sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
192190
Env: []corev1.EnvVar{
193191
{
194192
Name: "OTEL_SERVICE_NAME",
@@ -228,7 +226,7 @@ func TestSDKInjection(t *testing.T) {
228226
},
229227
{
230228
Name: "OTEL_RESOURCE_ATTRIBUTES",
231-
Value: "foo=bar,k8s.container.name=application-name,k8s.deployment.name=my-deployment,k8s.deployment.uid=depuid,k8s.namespace.name=project1,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.pod.uid=pod-uid,k8s.replicaset.name=my-replicaset,k8s.replicaset.uid=rsuid,service.instance.id=project1.$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME).application-name,service.version=latest",
229+
Value: "foo=bar,k8s.container.name=application-name,k8s.deployment.name=my-deployment,k8s.deployment.uid=depuid,k8s.namespace.name=project1,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.pod.uid=pod-uid,k8s.replicaset.name=my-replicaset,k8s.replicaset.uid=rsuid,service.instance.id=project1.$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME).application-name,service.version=v1@sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
232230
},
233231
},
234232
},
@@ -385,7 +383,6 @@ func TestSDKInjection(t *testing.T) {
385383
Labels: map[string]string{
386384
"app.kubernetes.io/name": "app-name",
387385
"app.kubernetes.io/version": "v1",
388-
"app.kubernetes.io/part-of": "shop",
389386
},
390387
Annotations: map[string]string{
391388
"resource.opentelemetry.io/foo": "bar",
@@ -408,7 +405,6 @@ func TestSDKInjection(t *testing.T) {
408405
Labels: map[string]string{
409406
"app.kubernetes.io/name": "app-name",
410407
"app.kubernetes.io/version": "v1",
411-
"app.kubernetes.io/part-of": "shop",
412408
},
413409
Annotations: map[string]string{
414410
"resource.opentelemetry.io/foo": "bar",
@@ -466,7 +462,7 @@ func TestSDKInjection(t *testing.T) {
466462
},
467463
{
468464
Name: "OTEL_RESOURCE_ATTRIBUTES",
469-
Value: "foo=bar,k8s.container.name=application-name,k8s.deployment.name=my-deployment,k8s.deployment.uid=depuid,k8s.namespace.name=project1,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.pod.uid=pod-uid,k8s.replicaset.name=my-replicaset,k8s.replicaset.uid=rsuid,service.instance.id=project1.$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME).application-name,service.namespace=shop,service.version=v1",
465+
Value: "foo=bar,k8s.container.name=application-name,k8s.deployment.name=my-deployment,k8s.deployment.uid=depuid,k8s.namespace.name=project1,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.pod.uid=pod-uid,k8s.replicaset.name=my-replicaset,k8s.replicaset.uid=rsuid,service.instance.id=project1.$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME).application-name,service.version=v1",
470466
},
471467
},
472468
},
@@ -503,7 +499,6 @@ func TestSDKInjection(t *testing.T) {
503499
Labels: map[string]string{
504500
"app.kubernetes.io/name": "not-used",
505501
"app.kubernetes.io/version": "not-used",
506-
"app.kubernetes.io/part-of": "not-used",
507502
},
508503
},
509504
Spec: corev1.PodSpec{
@@ -543,7 +538,6 @@ func TestSDKInjection(t *testing.T) {
543538
Labels: map[string]string{
544539
"app.kubernetes.io/name": "not-used",
545540
"app.kubernetes.io/version": "not-used",
546-
"app.kubernetes.io/part-of": "not-used",
547541
},
548542
},
549543
Spec: corev1.PodSpec{
@@ -2407,7 +2401,7 @@ func TestChooseServiceName(t *testing.T) {
24072401
index int
24082402
expectedServiceName string
24092403
useLabelsForResourceAttributes bool
2410-
labelValue string
2404+
labelValue map[string]string
24112405
annotationValue string
24122406
}{
24132407
{
@@ -2436,7 +2430,7 @@ func TestChooseServiceName(t *testing.T) {
24362430
string(semconv.K8SPodNameKey): "my-pod",
24372431
},
24382432
index: 0,
2439-
labelValue: "annotation",
2433+
labelValue: map[string]string{"app.kubernetes.io/name": "annotation"},
24402434
useLabelsForResourceAttributes: false,
24412435
expectedServiceName: "my-pod",
24422436
},
@@ -2445,8 +2439,23 @@ func TestChooseServiceName(t *testing.T) {
24452439
resources: map[string]string{
24462440
string(semconv.K8SPodNameKey): "my-pod",
24472441
},
2448-
index: 0,
2449-
labelValue: "label",
2442+
index: 0,
2443+
labelValue: map[string]string{
2444+
"app.kubernetes.io/name": "label",
2445+
},
2446+
useLabelsForResourceAttributes: true,
2447+
expectedServiceName: "label",
2448+
},
2449+
{
2450+
name: "from pod label - useLabelsForResourceAttributes=true",
2451+
resources: map[string]string{
2452+
string(semconv.K8SPodNameKey): "my-pod",
2453+
},
2454+
index: 0,
2455+
labelValue: map[string]string{
2456+
"app.kubernetes.io/instance": "label",
2457+
"app.kubernetes.io/name": "secondary-label",
2458+
},
24502459
useLabelsForResourceAttributes: true,
24512460
expectedServiceName: "label",
24522461
},
@@ -2457,7 +2466,7 @@ func TestChooseServiceName(t *testing.T) {
24572466
},
24582467
index: 0,
24592468
annotationValue: "annotation",
2460-
labelValue: "label",
2469+
labelValue: map[string]string{"app.kubernetes.io/name": "label"},
24612470
useLabelsForResourceAttributes: false,
24622471
expectedServiceName: "annotation",
24632472
},
@@ -2468,7 +2477,7 @@ func TestChooseServiceName(t *testing.T) {
24682477
},
24692478
index: 0,
24702479
annotationValue: "annotation",
2471-
labelValue: "label",
2480+
labelValue: map[string]string{"app.kubernetes.io/name": "label"},
24722481
useLabelsForResourceAttributes: true,
24732482
expectedServiceName: "annotation",
24742483
},
@@ -2533,9 +2542,7 @@ func TestChooseServiceName(t *testing.T) {
25332542
t.Run(test.name, func(t *testing.T) {
25342543
serviceName := chooseServiceName(corev1.Pod{
25352544
ObjectMeta: metav1.ObjectMeta{
2536-
Labels: map[string]string{
2537-
"app.kubernetes.io/name": test.labelValue,
2538-
},
2545+
Labels: test.labelValue,
25392546
Annotations: map[string]string{
25402547
"resource.opentelemetry.io/service.name": test.annotationValue,
25412548
},
@@ -2634,3 +2641,51 @@ func TestAppendIfNotSet(t *testing.T) {
26342641
})
26352642
}
26362643
}
2644+
2645+
func Test_parseServiceVersionFromImage(t *testing.T) {
2646+
tests := []struct {
2647+
name string
2648+
image string
2649+
want string
2650+
}{
2651+
{
2652+
name: "no version",
2653+
image: "img",
2654+
},
2655+
{
2656+
name: "with tag",
2657+
image: "img:1",
2658+
want: "1",
2659+
},
2660+
{
2661+
name: "with tag and digest",
2662+
image: "img:1@sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
2663+
want: "1@sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
2664+
},
2665+
{
2666+
name: "with digest",
2667+
image: "img@sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
2668+
want: "sha256:232a180dbcbcfa7250917507f3827d88a9ae89bb1cdd8fe3ac4db7b764ebb25a",
2669+
},
2670+
{
2671+
name: "with registry",
2672+
image: "registry.io/img",
2673+
},
2674+
{
2675+
name: "with port",
2676+
image: "registry.io:8080/img",
2677+
},
2678+
{
2679+
name: "latest",
2680+
image: "img:latest",
2681+
want: "latest",
2682+
},
2683+
}
2684+
for _, tt := range tests {
2685+
t.Run(tt.name, func(t *testing.T) {
2686+
got, _ := parseServiceVersionFromImage(tt.image)
2687+
// error is just for debugging
2688+
assert.Equalf(t, tt.want, got, "parseServiceVersionFromImage(%v)", tt.image)
2689+
})
2690+
}
2691+
}

0 commit comments

Comments
 (0)