diff --git a/processor/k8sattributesprocessor/README.md b/processor/k8sattributesprocessor/README.md index 35c8bfa53d9f..7bd4d917e951 100644 --- a/processor/k8sattributesprocessor/README.md +++ b/processor/k8sattributesprocessor/README.md @@ -168,7 +168,7 @@ spec: - --duration=10s - --rate=1 - --otlp-attributes=k8s.container.name="telemetrygen" - image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:latest + image: ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen:0.112.0@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096 name: telemetrygen status: podIP: 10.244.0.11 @@ -191,7 +191,8 @@ the processor associates the received trace to the pod, based on the connection "k8s.pod.name": "telemetrygen-pod", "k8s.pod.uid": "038e2267-b473-489b-b48c-46bafdb852eb", "container.image.name": "telemetrygen", - "container.image.tag": "latest" + "container.image.tag": "0.112.0", + "container.image.repo_digests": "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096" } } ``` diff --git a/processor/k8sattributesprocessor/documentation.md b/processor/k8sattributesprocessor/documentation.md index 67bcb77d2741..83e9ea366b3a 100644 --- a/processor/k8sattributesprocessor/documentation.md +++ b/processor/k8sattributesprocessor/documentation.md @@ -4,33 +4,33 @@ ## Resource Attributes -| Name | Description | Values | Enabled | -| ---- | ----------- | ------ | ------- | +| Name | Description | Values | Enabled | +| ---- |-------------------------------------------------------------------------------------------------------------------------------------------------------| ------ | ------- | | container.id | Container ID. Usually a UUID, as for example used to identify Docker containers. The UUID might be abbreviated. Requires k8s.container.restart_count. | Any Str | false | -| container.image.name | Name of the image the container was built on. Requires container.id or k8s.container.name. | Any Str | true | -| container.image.repo_digests | Repo digests of the container image as provided by the container runtime. | Any Slice | false | -| container.image.tag | Container image tag. Requires container.id or k8s.container.name. | Any Str | true | -| k8s.cluster.uid | Gives cluster uid identified with kube-system namespace | Any Str | false | -| k8s.container.name | The name of the Container in a Pod template. Requires container.id. | Any Str | false | -| k8s.cronjob.name | The name of the CronJob. | Any Str | false | -| k8s.daemonset.name | The name of the DaemonSet. | Any Str | false | -| k8s.daemonset.uid | The UID of the DaemonSet. | Any Str | false | -| k8s.deployment.name | The name of the Deployment. | Any Str | true | -| k8s.deployment.uid | The UID of the Deployment. | Any Str | false | -| k8s.job.name | The name of the Job. | Any Str | false | -| k8s.job.uid | The UID of the Job. | Any Str | false | -| k8s.namespace.name | The name of the namespace that the pod is running in. | Any Str | true | -| k8s.node.name | The name of the Node. | Any Str | true | -| k8s.node.uid | The UID of the Node. | Any Str | false | -| k8s.pod.hostname | The hostname of the Pod. | Any Str | false | -| k8s.pod.ip | The IP address of the Pod. | Any Str | false | -| k8s.pod.name | The name of the Pod. | Any Str | true | -| k8s.pod.start_time | The start time of the Pod. | Any Str | true | -| k8s.pod.uid | The UID of the Pod. | Any Str | true | -| k8s.replicaset.name | The name of the ReplicaSet. | Any Str | false | -| k8s.replicaset.uid | The UID of the ReplicaSet. | Any Str | false | -| k8s.statefulset.name | The name of the StatefulSet. | Any Str | false | -| k8s.statefulset.uid | The UID of the StatefulSet. | Any Str | false | +| container.image.name | Name of the image the container was built on. Requires container.id or k8s.container.name. | Any Str | true | +| container.image.repo_digests | Repo digests of the container image as provided by the container runtime. | Any Slice | false | +| container.image.tag | Container image tag. Defaults to "latest" if not provided (unless digest also in image path) Requires container.id or k8s.container.name. | Any Str | true | +| k8s.cluster.uid | Gives cluster uid identified with kube-system namespace | Any Str | false | +| k8s.container.name | The name of the Container in a Pod template. Requires container.id. | Any Str | false | +| k8s.cronjob.name | The name of the CronJob. | Any Str | false | +| k8s.daemonset.name | The name of the DaemonSet. | Any Str | false | +| k8s.daemonset.uid | The UID of the DaemonSet. | Any Str | false | +| k8s.deployment.name | The name of the Deployment. | Any Str | true | +| k8s.deployment.uid | The UID of the Deployment. | Any Str | false | +| k8s.job.name | The name of the Job. | Any Str | false | +| k8s.job.uid | The UID of the Job. | Any Str | false | +| k8s.namespace.name | The name of the namespace that the pod is running in. | Any Str | true | +| k8s.node.name | The name of the Node. | Any Str | true | +| k8s.node.uid | The UID of the Node. | Any Str | false | +| k8s.pod.hostname | The hostname of the Pod. | Any Str | false | +| k8s.pod.ip | The IP address of the Pod. | Any Str | false | +| k8s.pod.name | The name of the Pod. | Any Str | true | +| k8s.pod.start_time | The start time of the Pod. | Any Str | true | +| k8s.pod.uid | The UID of the Pod. | Any Str | true | +| k8s.replicaset.name | The name of the ReplicaSet. | Any Str | false | +| k8s.replicaset.uid | The UID of the ReplicaSet. | Any Str | false | +| k8s.statefulset.name | The name of the StatefulSet. | Any Str | false | +| k8s.statefulset.uid | The UID of the StatefulSet. | Any Str | false | ## Internal Telemetry diff --git a/processor/k8sattributesprocessor/e2e_test.go b/processor/k8sattributesprocessor/e2e_test.go index ddb81633cdf5..4f5227be01d2 100644 --- a/processor/k8sattributesprocessor/e2e_test.go +++ b/processor/k8sattributesprocessor/e2e_test.go @@ -504,7 +504,7 @@ func TestE2E_NamespacedRBAC(t *testing.T) { "k8s.labels.app": newExpectedValue(equal, "telemetrygen-"+testID+"-traces-deployment"), "k8s.container.name": newExpectedValue(equal, "telemetrygen"), "container.image.name": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen"), - "container.image.repo_digests": newExpectedValue(regex, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:[0-9a-fA-f]{64}"), + "container.image.repo_digests": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096"), "container.image.tag": newExpectedValue(shouldnotexist, ""), "container.id": newExpectedValue(exist, ""), }, @@ -528,7 +528,7 @@ func TestE2E_NamespacedRBAC(t *testing.T) { "k8s.labels.app": newExpectedValue(equal, "telemetrygen-"+testID+"-metrics-deployment"), "k8s.container.name": newExpectedValue(equal, "telemetrygen"), "container.image.name": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen"), - "container.image.repo_digests": newExpectedValue(regex, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:[0-9a-fA-f]{64}"), + "container.image.repo_digests": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096"), "container.image.tag": newExpectedValue(shouldnotexist, ""), "container.id": newExpectedValue(exist, ""), }, @@ -552,7 +552,7 @@ func TestE2E_NamespacedRBAC(t *testing.T) { "k8s.labels.app": newExpectedValue(equal, "telemetrygen-"+testID+"-logs-deployment"), "k8s.container.name": newExpectedValue(equal, "telemetrygen"), "container.image.name": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen"), - "container.image.repo_digests": newExpectedValue(regex, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:[0-9a-fA-f]{64}"), + "container.image.repo_digests": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096"), "container.image.tag": newExpectedValue(shouldnotexist, ""), "container.id": newExpectedValue(exist, ""), }, @@ -662,7 +662,7 @@ func TestE2E_MixRBAC(t *testing.T) { "k8s.labels.app": newExpectedValue(equal, "telemetrygen-"+testID+"-traces-deployment"), "k8s.container.name": newExpectedValue(equal, "telemetrygen"), "container.image.name": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen"), - "container.image.repo_digests": newExpectedValue(regex, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:[0-9a-fA-f]{64}"), + "container.image.repo_digests": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096"), "container.image.tag": newExpectedValue(equal, "0.112.0"), "container.id": newExpectedValue(exist, ""), "k8s.namespace.labels.foons": newExpectedValue(equal, "barns"), @@ -689,7 +689,7 @@ func TestE2E_MixRBAC(t *testing.T) { "k8s.labels.app": newExpectedValue(equal, "telemetrygen-"+testID+"-metrics-deployment"), "k8s.container.name": newExpectedValue(equal, "telemetrygen"), "container.image.name": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen"), - "container.image.repo_digests": newExpectedValue(regex, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:[0-9a-fA-f]{64}"), + "container.image.repo_digests": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096"), "container.image.tag": newExpectedValue(equal, "0.112.0"), "container.id": newExpectedValue(exist, ""), "k8s.namespace.labels.foons": newExpectedValue(equal, "barns"), @@ -716,7 +716,7 @@ func TestE2E_MixRBAC(t *testing.T) { "k8s.labels.app": newExpectedValue(equal, "telemetrygen-"+testID+"-logs-deployment"), "k8s.container.name": newExpectedValue(equal, "telemetrygen"), "container.image.name": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen"), - "container.image.repo_digests": newExpectedValue(regex, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:[0-9a-fA-f]{64}"), + "container.image.repo_digests": newExpectedValue(equal, "ghcr.io/open-telemetry/opentelemetry-collector-contrib/telemetrygen@sha256:b248ef911f93ae27cbbc85056d1ffacc87fd941bbdc2ffd951b6df8df72b8096"), "container.image.tag": newExpectedValue(equal, "0.112.0"), "container.id": newExpectedValue(exist, ""), "k8s.namespace.labels.foons": newExpectedValue(equal, "barns"), diff --git a/processor/k8sattributesprocessor/internal/kube/client.go b/processor/k8sattributesprocessor/internal/kube/client.go index 0631dc1699ab..f92a10465403 100644 --- a/processor/k8sattributesprocessor/internal/kube/client.go +++ b/processor/k8sattributesprocessor/internal/kube/client.go @@ -634,6 +634,8 @@ func removeUnnecessaryPodData(pod *api_v1.Pod, rules ExtractionRules) *api_v1.Po } // parseAttributesFromImage parses the image name and tag for differently-formatted image names. +// returns "latest" as the default if tag not present. also checks if the image contains a digest. +// if it does, no latest tag is assumed. func parseNameAndTagFromImage(image string) (name, tag string, err error) { ref, err := reference.Parse(image) if err != nil { @@ -647,6 +649,11 @@ func parseNameAndTagFromImage(image string) (name, tag string, err error) { if taggedRef, ok := namedRef.(reference.Tagged); ok { tag = taggedRef.Tag() } + if tag == "" { + if digestedRef, ok := namedRef.(reference.Digested); !ok || digestedRef.String() == "" { + tag = "latest" + } + } return } diff --git a/processor/k8sattributesprocessor/internal/kube/client_test.go b/processor/k8sattributesprocessor/internal/kube/client_test.go index f414aa93f63e..b4e26017aec6 100644 --- a/processor/k8sattributesprocessor/internal/kube/client_test.go +++ b/processor/k8sattributesprocessor/internal/kube/client_test.go @@ -1483,7 +1483,7 @@ func Test_extractPodContainersAttributes(t *testing.T) { InitContainers: []api_v1.Container{ { Name: "init_container", - Image: "test/init-image:1.0.2", + Image: "test/init-image", }, }, }, @@ -1722,7 +1722,7 @@ func Test_extractPodContainersAttributes(t *testing.T) { }, "init-container-id-789": { ImageName: "test/init-image", - ImageTag: "1.0.2", + ImageTag: "latest", Statuses: map[int]ContainerStatus{ 0: {ContainerID: "init-container-id-789", ImageRepoDigest: "ghcr.io/initimage1@sha256:42e8ba40f9f70d604684c3a2a0ed321206b7e2e3509fdb2c8836d34f2edfb57b"}, }, @@ -1751,7 +1751,7 @@ func Test_extractPodContainersAttributes(t *testing.T) { }, "init_container": { ImageName: "test/init-image", - ImageTag: "1.0.2", + ImageTag: "latest", Statuses: map[int]ContainerStatus{ 0: {ContainerID: "init-container-id-789", ImageRepoDigest: "ghcr.io/initimage1@sha256:42e8ba40f9f70d604684c3a2a0ed321206b7e2e3509fdb2c8836d34f2edfb57b"}, },