mirror of
https://github.com/block/buzz.git
synced 2026-10-27 12:40:30 +00:00
fix(chart): own the Datadog version label on every workload Pod (#7876)
## Summary
Every chart-managed Pod now carries a chart-owned
`tags.datadoghq.com/version` label derived from the deployed image,
instead of a value each wrapper restates once per workload.
Covered Pod templates:
- relay Deployment (`templates/deployment.yaml`)
- pairing relay (`templates/pairing-relay.yaml`)
- storage-accounting CronJob
(`templates/storage-accounting-cronjob.yaml`)
- operator jobs, including the deletion drain
(`templates/_operator-jobs.tpl`)
**Source order:** `image.tag`, then `image.digest`, then
`Chart.AppVersion` (`buzz.imageVersionSource`). Tag-first is deliberate:
- The rendered value matches the `sha-<commit>` pins wrappers already
carry, so upgrading to this chart does not roll any Pods.
- An image promotion only has to write `image.tag` + `image.digest`. No
per-workload label edit is needed.
Exact runtime identity stays exact in two places. The image reference is
`repository@digest` when a digest is pinned.
`BUZZ_STORAGE_SNAPSHOT_CODE_SHA` (persisted as `code_sha`) is still
digest-first.
**Label safety:** `buzz.imageVersionLabel` maps any OCI tag or digest to
a valid label value.
- Valid values already in Datadog's normal form (lowercase, no `__`)
pass through byte for byte, so `sha-<hex>` and `1.2.3-rc.4` are
unchanged. Datadog lowercases tag values and collapses `__`, so any
other value is hashed rather than allowed to report the same version as
a different revision.
- A digest keeps 63 hex characters.
- Anything else is replaced by the first 63 hex characters of its
SHA-256.
- Exactly 63 lowercase hex characters is reserved for the hashed and
digest forms, so a rendered label cannot be fed back as a tag to make
two revisions collide.
- When both tag and digest are set, the label names the tag even if they
disagree; the digest still pins what runs.
**Precedence:** a `tags.datadoghq.com/version` supplied through any
workload's `podLabels` is ignored. Every other label, including
`tags.datadoghq.com/env` and `/service`, passes through unchanged.
Overriding instead of failing means a wrapper with a stale pin is
corrected by the upgrade itself. The chart bump and the wrapper cleanup
don't have to land together.
**What got simpler:** one image identity instead of N. Wrappers delete
their per-workload version pins. Image promotion tooling no longer needs
a "mirror the tag into a label path" feature. One shared helper
(`buzz.podLabelsWithVersion`) replaces four `podLabels` passthroughs.
Chart `0.1.10 → 0.1.11`, with an `artifacthub.io/changes` entry.
Documented in the chart README ("Datadog version label") and
`docs/deployment-identity.md`.
Note: a vendor-namespaced label now renders unconditionally in an OSS
chart. This is in tension with
[VISION_SOVEREIGN.md](../blob/main/VISION_SOVEREIGN.md). The label is
inert without the operator-supplied `tags.datadoghq.com/service`/`env`,
and the chart already ships vendor-specific defaults (e.g.
`sidecar.istio.io/inject`).
### Testing
Run on a Blox (Linux) workstation at tree `41634b7ca` (helm v3.16.4,
helm-unittest 0.8.2, the CI versions):
- `helm lint deploy/charts/buzz`: 0 failed
- `helm unittest deploy/charts/buzz`: 12 suites, **85/85 passed**
New `tests/version_label_test.yaml` checks the relay, pairing relay, and
deletion drain: tag wins over a stale `podLabels` pin, the label is
stamped with no `podLabels`, and digest-only images get a label-safe
value. `tests/storage_accounting_test.yaml` covers the same cases for
the CronJob, plus the `Chart.AppVersion` fallback.
Mutation checks:
- Reverting any one template to the plain `podLabels` passthrough fails
tests.
- Switching the source order to digest-first fails tests.
- Restoring the case-insensitive passthrough fails the three
Datadog-normalization tests (uppercase, `__`, uppercased 63-hex).
No Rust, desktop, web, or mobile sources changed.
## Linear tracking
Related work: [BUZZ-215](https://linear.app/squareup/issue/BUZZ-215).
---------
Signed-off-by: tornquist <tornquist@squareup.com>
Signed-off-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Elrond <28d6302a099e5225b02c4155ac4236e4912603df2ab08dbfc2f4fef08ce598c8@buzz.block.builderlab.xyz>
This commit is contained in:
@@ -7,7 +7,7 @@ description: |
|
||||
PostgreSQL and Redis. Configurable for single-node evaluation
|
||||
(subcharts on) and HA production (external services, existingSecret).
|
||||
type: application
|
||||
version: 0.1.10
|
||||
version: 0.1.11
|
||||
appVersion: "0.1.0"
|
||||
home: https://github.com/block/buzz
|
||||
sources:
|
||||
@@ -23,8 +23,8 @@ maintainers:
|
||||
url: https://github.com/block
|
||||
annotations:
|
||||
artifacthub.io/changes: |
|
||||
- kind: added
|
||||
description: Optional typed deletion-drain operator CronJob using durable database leases.
|
||||
- kind: changed
|
||||
description: Chart-managed Pods derive tags.datadoghq.com/version from the deployed image identity instead of operator-supplied labels.
|
||||
artifacthub.io/license: Apache-2.0
|
||||
|
||||
# Optional eval-only subcharts. Production deploys disable both and point
|
||||
|
||||
@@ -460,6 +460,85 @@ volumes, and each init container must define an appropriate security context
|
||||
and resources. Empty `relay.command` and `relay.args` arrays preserve the image
|
||||
defaults; non-empty values override its entrypoint and arguments respectively.
|
||||
|
||||
## Storage accounting worker
|
||||
|
||||
`storageAccounting.enabled=true` adds a CronJob that runs
|
||||
`buzz-admin storage-snapshot` against the relay's S3 bucket and writes a
|
||||
durable snapshot row, keeping the expensive object walk off the relay Pods.
|
||||
|
||||
### Snapshot identity contract
|
||||
|
||||
Every snapshot row records the code that produced it in `code_sha`, taken from
|
||||
the `BUZZ_STORAGE_SNAPSHOT_CODE_SHA` environment variable the chart derives
|
||||
from the deployed image identity (`image.digest` when set, otherwise
|
||||
`image.tag`, otherwise `Chart.AppVersion`). The value is never hashed or
|
||||
sanitized.
|
||||
|
||||
## Datadog version label
|
||||
|
||||
Every Pod the chart renders — relay, pairing relay, storage accounting, and the
|
||||
deletion drain operator job — carries a chart-owned
|
||||
`tags.datadoghq.com/version` label derived from the deployed image:
|
||||
`image.tag` when set, otherwise `image.digest`, otherwise `Chart.AppVersion`.
|
||||
The tag is preferred because it is the readable build name (`sha-<commit>`)
|
||||
dashboards already use; promotion tooling writes it together with the digest
|
||||
that actually pins the image.
|
||||
|
||||
```yaml
|
||||
relay:
|
||||
podLabels:
|
||||
tags.datadoghq.com/env: production
|
||||
tags.datadoghq.com/service: buzz
|
||||
# tags.datadoghq.com/version: NOT set here — the chart owns it.
|
||||
```
|
||||
|
||||
Precedence is explicit: a `tags.datadoghq.com/version` supplied under any
|
||||
workload's `podLabels` is ignored. Every other label — including
|
||||
`tags.datadoghq.com/env` and `tags.datadoghq.com/service`, which describe the
|
||||
deployment rather than the image — passes through unchanged. Remove any
|
||||
wrapper-maintained version pins when upgrading; a pin equal to `image.tag`
|
||||
renders identically, so the upgrade does not roll Pods for that label.
|
||||
|
||||
A Kubernetes label value is capped at 63 bytes, must begin and end with an
|
||||
alphanumeric, and may otherwise contain only `[-._a-zA-Z0-9]` — a far narrower
|
||||
grammar than an OCI tag. `image.tag` is deliberately left unconstrained, so the
|
||||
label is derived through a total mapping rather than a check that could reject
|
||||
a tag the chart used to accept:
|
||||
|
||||
| Revision | Label |
|
||||
|---|---|
|
||||
| `sha256:<64 hex>` digest | the hex without `sha256:`, first 63 characters |
|
||||
| already a valid label value, lowercase, no `__`, and not exactly 63 lowercase hex characters | emitted byte for byte (e.g. `1.2.3-rc.4`, `sha-1a2b3c4`) |
|
||||
| anything else | the first 63 hex characters of the revision's SHA-256 |
|
||||
|
||||
The passthrough row requires Datadog's normal form because Datadog lowercases
|
||||
tag values and collapses `__`: passing `ReleaseA` and `releasea` through
|
||||
unchanged would report one version for two revisions. Every emitted label is
|
||||
therefore already normalized, so distinct labels stay distinct in Datadog.
|
||||
|
||||
When both `image.tag` and `image.digest` are set, the label names the tag —
|
||||
even if the tag and digest disagree. The digest still pins what actually runs
|
||||
(`repository@digest`), so keep the two in step when promoting.
|
||||
|
||||
Exactly 63 lowercase hex characters is a **reserved shape** — it is what the
|
||||
first and third rows emit, so the passthrough row must not be able to emit it
|
||||
too. A tag of that shape is hashed rather than preserved. Shorter hex tags and
|
||||
ordinary 40-character git SHAs are unaffected.
|
||||
|
||||
Arbitrary OCI revisions outnumber 63-byte label values, so **no mapping onto
|
||||
this grammar can be injective** and the chart does not claim one. What it does
|
||||
claim is collision *resistance*: every case retains 252 bits of SHA-256, the
|
||||
same margin the digest case has always relied on, and the reserved shape keeps
|
||||
that margin across cases rather than only within one. Two earlier iterations
|
||||
fell short of this — one kept a readable prefix with only 40 bits of hash (a
|
||||
colliding tag pair was brute-forced in about a second), and one let a
|
||||
passthrough tag reproduce a hashed label with no hash work at all, by copying a
|
||||
rendered label into `image.tag`.
|
||||
|
||||
The image reference in the Pod spec and `BUZZ_STORAGE_SNAPSHOT_CODE_SHA` always
|
||||
keep the exact revision; the label is the joinable telemetry key. See
|
||||
`docs/deployment-identity.md`.
|
||||
|
||||
## Device pairing relay
|
||||
|
||||
The chart can run Buzz's stateless pairing WebSocket relay as an independent
|
||||
|
||||
@@ -76,6 +76,94 @@ app.kubernetes.io/component: relay
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Datadog unified-service-tagging version for every chart-managed Pod (relay,
|
||||
pairing relay, storage accounting, operator jobs). It names the deployed image:
|
||||
image.tag when set — the readable build name operators and dashboards already
|
||||
use, which promotion tooling writes together with image.digest — otherwise the
|
||||
digest, otherwise Chart.AppVersion. The chart owns this label so a wrapper never
|
||||
has to pin a second copy of the image identity that silently drifts; the exact
|
||||
runtime identity stays in the image reference and in
|
||||
BUZZ_STORAGE_SNAPSHOT_CODE_SHA ("buzz.imageRevision").
|
||||
*/}}
|
||||
{{- define "buzz.imageVersionSource" -}}
|
||||
{{- if .Values.image.tag -}}
|
||||
{{- .Values.image.tag -}}
|
||||
{{- else if .Values.image.digest -}}
|
||||
{{- .Values.image.digest -}}
|
||||
{{- else -}}
|
||||
{{- .Chart.AppVersion -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Kubernetes-label-safe rendering of "buzz.imageVersionSource".
|
||||
|
||||
A label value is at most 63 bytes, must begin and end with an alphanumeric,
|
||||
and may otherwise contain only [-._a-zA-Z0-9]. image.tag is an unconstrained
|
||||
string, so the domain is larger than the codomain and no mapping can be
|
||||
injective; what the chart provides is a total mapping that is collision
|
||||
*resistant*, in three cases:
|
||||
|
||||
1. A "sha256:<64 hex>" digest drops its algorithm prefix and keeps 63 hex
|
||||
characters — the behaviour this chart has always had for digests.
|
||||
2. A revision that is already a valid label value *and* already in Datadog's
|
||||
normal form — no uppercase, no "__" — and is not of the reserved shape
|
||||
below, is emitted byte for byte, so ordinary tags like 1.2.3-rc.4 and
|
||||
sha-1a2b3c4 are preserved exactly.
|
||||
3. Anything else — a leading "_", an uppercase letter, a "__" run, a byte
|
||||
outside the label alphabet, or more than 63 bytes — is replaced by the
|
||||
first 63 hex characters of its SHA-256, the same shape and the same 252
|
||||
retained bits as case 1.
|
||||
|
||||
Case 2 is restricted to Datadog's normal form because the label's consumer is
|
||||
Datadog, which lowercases tag values and collapses runs of "_". A passthrough
|
||||
of "ReleaseA" would report the same version as "releasea", and "release__a"
|
||||
the same as "release_a"; an uppercased 63-hex value would also slip past the
|
||||
reserved-shape check below and then normalize onto a hashed or digest label.
|
||||
Hashing everything not already in normal form means every value this helper
|
||||
emits is a fixed point of Datadog's normalization, so distinct outputs stay
|
||||
distinct where they are read.
|
||||
|
||||
Exactly 63 lowercase hex characters is the reserved shape: it is what cases 1
|
||||
and 3 emit, so case 2 must not also be able to emit it. Without that exclusion
|
||||
the two namespaces overlap and colliding two revisions costs no hash work at
|
||||
all — render one, copy the label into image.tag, and the passthrough branch
|
||||
echoes it back. Reserving the shape keeps every cross-case collision behind a
|
||||
252-bit preimage, which is the same margin cases 1 and 3 already rely on. The
|
||||
cost is that a tag which is itself 63 lowercase hex characters is hashed rather
|
||||
than preserved; such a tag is not a form anything generates except this label.
|
||||
|
||||
Case 3 deliberately keeps no readable prefix. An earlier revision of this
|
||||
helper kept a sanitized prefix plus 10 hex characters of SHA-256, and that
|
||||
40-bit namespace was small enough to brute-force: the tags
|
||||
"b"x52 + "-collision-22356" and "b"x52 + "-collision-914141" both rendered
|
||||
"b"x52 + "-430be57931" (see tests/storage_accounting_test.yaml). Readability
|
||||
is not worth a forgeable telemetry identity when the exact revision is always
|
||||
available in the image reference itself.
|
||||
*/}}
|
||||
{{- define "buzz.imageVersionLabel" -}}
|
||||
{{- $revision := include "buzz.imageVersionSource" . -}}
|
||||
{{- if regexMatch "^sha256:[0-9a-f]{64}$" $revision -}}
|
||||
{{- $revision | trimPrefix "sha256:" | trunc 63 -}}
|
||||
{{- else if and (le (len $revision) 63) (regexMatch "^[a-z0-9]([-._a-z0-9]*[a-z0-9])?$" $revision) (not (contains "__" $revision)) (not (regexMatch "^[0-9a-f]{63}$" $revision)) -}}
|
||||
{{- $revision -}}
|
||||
{{- else -}}
|
||||
{{- sha256sum $revision | trunc 63 -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Pod-template labels for a chart-managed workload: the caller's podLabels with
|
||||
the chart-owned Datadog version merged on top. Every other key, including
|
||||
tags.datadoghq.com/env and tags.datadoghq.com/service, passes through.
|
||||
Usage: include "buzz.podLabelsWithVersion" (dict "root" $ "labels" $podLabels)
|
||||
*/}}
|
||||
{{- define "buzz.podLabelsWithVersion" -}}
|
||||
{{- $labels := merge (dict "tags.datadoghq.com/version" (include "buzz.imageVersionLabel" .root)) (.labels | default dict) -}}
|
||||
{{- toYaml $labels -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Name of the chart-managed Secret holding relay-identity material and any
|
||||
chart-composed connection strings.
|
||||
|
||||
@@ -30,9 +30,7 @@ spec:
|
||||
labels:
|
||||
{{- include "buzz.selectorLabels" $root | nindent 12 }}
|
||||
app.kubernetes.io/component: deletion-drain
|
||||
{{- with $job.podLabels }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "buzz.podLabelsWithVersion" (dict "root" $root "labels" $job.podLabels) | nindent 12 }}
|
||||
annotations:
|
||||
{{- toYaml $job.podAnnotations | nindent 12 }}
|
||||
spec:
|
||||
|
||||
@@ -21,9 +21,7 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "buzz.relaySelectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.relay.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- include "buzz.podLabelsWithVersion" (dict "root" . "labels" .Values.relay.podLabels) | nindent 8 }}
|
||||
annotations:
|
||||
# Roll pods when the chart-managed Secret changes.
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secret-chart.yaml") . | sha256sum }}
|
||||
|
||||
@@ -16,9 +16,7 @@ spec:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "buzz.pairingRelaySelectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.pairingRelay.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- include "buzz.podLabelsWithVersion" (dict "root" . "labels" .Values.pairingRelay.podLabels) | nindent 8 }}
|
||||
{{- with .Values.pairingRelay.podAnnotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
|
||||
@@ -20,9 +20,7 @@ spec:
|
||||
labels:
|
||||
{{- include "buzz.selectorLabels" . | nindent 12 }}
|
||||
app.kubernetes.io/component: storage-accounting
|
||||
{{- with .Values.storageAccounting.podLabels }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "buzz.podLabelsWithVersion" (dict "root" . "labels" .Values.storageAccounting.podLabels) | nindent 12 }}
|
||||
annotations:
|
||||
{{- toYaml .Values.storageAccounting.podAnnotations | nindent 12 }}
|
||||
spec:
|
||||
|
||||
@@ -44,6 +44,7 @@ tests:
|
||||
podLabels:
|
||||
tags.datadoghq.com/env: production
|
||||
tags.datadoghq.com/service: buzz-storage-accounting
|
||||
# Stale operator pin: the chart owns this key and overrides it.
|
||||
tags.datadoghq.com/version: test-sha
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
@@ -93,9 +94,11 @@ tests:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/env"]
|
||||
value: production
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# Image identity wins over the operator-supplied pin; default image.tag
|
||||
# falls back to Chart.AppVersion, the same value as the env var below.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: test-sha
|
||||
value: 0.1.0
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].args
|
||||
@@ -165,3 +168,360 @@ tests:
|
||||
path: metadata.name
|
||||
value: storage-accounting-fullname-that-storage-accounting
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# ── Datadog version tag is chart-owned, derived from image identity ────────
|
||||
# Regression: a wrapper chart pinned tags.datadoghq.com/version independently
|
||||
# of image.tag/image.digest, so the storage-accounting Pod reported one
|
||||
# version to Datadog while BUZZ_STORAGE_SNAPSHOT_CODE_SHA recorded another.
|
||||
- it: overrides a stale operator-pinned Datadog version label with the image tag
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: 1.2.3-rc.4
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
podLabels:
|
||||
tags.datadoghq.com/env: staging
|
||||
tags.datadoghq.com/service: buzz-storage-accounting
|
||||
tags.datadoghq.com/version: stale-operator-sha
|
||||
team: platform
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: 1.2.3-rc.4
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The telemetry tag and the recorded snapshot identity cannot disagree.
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: 1.2.3-rc.4
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# Every other operator label still passes through.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/env"]
|
||||
value: staging
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/service"]
|
||||
value: buzz-storage-accounting
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["team"]
|
||||
value: platform
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["app.kubernetes.io/component"]
|
||||
value: storage-accounting
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- it: stamps the version label with no operator podLabels at all
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: 2.0.0
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: 2.0.0
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# Promotion writes image.tag and image.digest together; the tag is the
|
||||
# readable build name Datadog already uses, the digest the runtime identity.
|
||||
- it: names the image tag in the version label while the digest pins the image
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: sha-1234567
|
||||
image.digest: sha256:1111111111111111111111111111111111111111111111111111111111111111
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
podLabels:
|
||||
tags.datadoghq.com/version: stale-operator-sha
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-1234567
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The snapshot row still records the exact digest that ran.
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: sha256:1111111111111111111111111111111111111111111111111111111111111111
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- it: renders a label-safe version from a digest when no tag is set
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.digest: sha256:1111111111111111111111111111111111111111111111111111111111111111
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
podLabels:
|
||||
tags.datadoghq.com/version: stale-operator-sha
|
||||
asserts:
|
||||
# 63 chars, no "sha256:" prefix — a label value the API server accepts,
|
||||
# still a unique prefix of the digest recorded in the env var below.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "111111111111111111111111111111111111111111111111111111111111111"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-z0-9A-Z]([-_.a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: sha256:1111111111111111111111111111111111111111111111111111111111111111
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# ── Label-safety of arbitrary OCI tags (PR #7876 review, P0) ───────────────
|
||||
# image.tag is an unconstrained string in values.schema.json, so any tag the
|
||||
# OCI grammar allows must still yield a valid Kubernetes label value. The
|
||||
# chart replaces any revision that is not already label-safe with the first
|
||||
# 63 hex characters of its SHA-256, the same shape it uses for digests.
|
||||
- it: sanitizes a leading underscore that OCI allows but Kubernetes labels do not
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "_foo"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
# Leading '_' is a valid OCI tag byte but an invalid first label byte.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "583da8894acbb7b121f9b85bc263859bd68c3a239f4934b62fc13f4f0beedc6"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The rendered label must satisfy the Kubernetes label-value grammar:
|
||||
# <=63 bytes, alphanumeric first and last byte, [-._a-zA-Z0-9] inside.
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The exact image revision still reaches the snapshot row unmodified.
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "_foo"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- it: keeps the label valid when truncation would land on mixed trailing delimiters
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-_.tail"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
# A one-pass '-'/'.'/'_' trim left a trailing '-' for a tag ending '-_.';
|
||||
# a hex label has no delimiters to trim.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "e4fb46fc85bd57715b5a11055e17387d439f906e568445c24d27ba91fc4995f"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The rendered label must satisfy the Kubernetes label-value grammar:
|
||||
# <=63 bytes, alphanumeric first and last byte, [-._a-zA-Z0-9] inside.
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The exact image revision still reaches the snapshot row unmodified.
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-_.tail"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- it: distinguishes the first of two >63-character tags sharing a 63-byte prefix
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-one"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
# Plain truncation collapses both tags to the same telemetry version.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "2aad1d5b65b546c6b4a5f4d46845078c7dfb91302d9824c884fff9f45f6398c"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The rendered label must satisfy the Kubernetes label-value grammar:
|
||||
# <=63 bytes, alphanumeric first and last byte, [-._a-zA-Z0-9] inside.
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The exact image revision still reaches the snapshot row unmodified.
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-one"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- it: distinguishes the second of two >63-character tags sharing a 63-byte prefix
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-two"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
# Same 63-byte tag prefix as the previous case, different SHA-256.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "86dde532eb8217d9ab8648f38f12cd3568983910e0e668489a66c036734ae9a"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The rendered label must satisfy the Kubernetes label-value grammar:
|
||||
# <=63 bytes, alphanumeric first and last byte, [-._a-zA-Z0-9] inside.
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# The exact image revision still reaches the snapshot row unmodified.
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-two"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# ── Known 40-bit collision pair (PR #7876 second review, P0) ───────────────
|
||||
# These two tags were found by brute force against the previous fallback,
|
||||
# which kept only 10 hex characters of SHA-256: both rendered
|
||||
# b*52-430be57931. They share a 40-bit SHA-256 prefix and diverge at the
|
||||
# 11th hex character, so they pin the width of the retained hash.
|
||||
- it: keeps the first tag of the known 40-bit collision pair distinct
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-collision-22356"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
# Shares its first 10 SHA-256 hex characters with the next case.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "430be579311332ea582db391704bd58601bcf0f3f5682d22bdabdac24a47169"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-collision-22356"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- it: keeps the second tag of the known 40-bit collision pair distinct
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-collision-914141"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
# Same 40-bit SHA-256 prefix as the previous case, different label.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "430be5793136081a42faa8d72f746af34f0b3bad1a5f65f22bac19e22bd71c5"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-collision-914141"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# ── Reserved hash shape is not reachable by a passthrough tag ──────────────
|
||||
# The hashed and digest branches both emit exactly 63 lowercase hex
|
||||
# characters. If a label-safe tag of that same shape were passed through, an
|
||||
# operator could collide two revisions with no hash work at all, by copying a
|
||||
# rendered label into image.tag. The label below is exactly what
|
||||
# "b"x52 + "-collision-22356" renders, so the chart must hash it rather than
|
||||
# echo it back.
|
||||
- it: hashes a tag that has the reserved 63-hex shape instead of passing it through
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "430be579311332ea582db391704bd58601bcf0f3f5682d22bdabdac24a47169"
|
||||
storageAccounting:
|
||||
enabled: true
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "9f615034d2fe14c5266fe5ca3eb7c26c4179eae8dce01f506def01a8cc6a77e"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
# Must not echo the tag back: that is the label of a different revision.
|
||||
- notEqual:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "430be579311332ea582db391704bd58601bcf0f3f5682d22bdabdac24a47169"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- matchRegex:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
pattern: ^[a-zA-Z0-9]([-._a-zA-Z0-9]{0,61}[a-zA-Z0-9])?$
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
- contains:
|
||||
path: spec.jobTemplate.spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: BUZZ_STORAGE_SNAPSHOT_CODE_SHA
|
||||
value: "430be579311332ea582db391704bd58601bcf0f3f5682d22bdabdac24a47169"
|
||||
template: templates/storage-accounting-cronjob.yaml
|
||||
|
||||
313
deploy/charts/buzz/tests/version_label_test.yaml
Normal file
313
deploy/charts/buzz/tests/version_label_test.yaml
Normal file
@@ -0,0 +1,313 @@
|
||||
suite: chart-owned Datadog version label on every workload
|
||||
# Regression: wrappers pinned tags.datadoghq.com/version beside image.tag on
|
||||
# each workload, so every image promotion had to edit several copies of one
|
||||
# identity and a missed copy reported the wrong version to Datadog. The chart
|
||||
# now owns the label everywhere it renders a Pod (storage accounting is covered
|
||||
# in storage_accounting_test.yaml).
|
||||
templates:
|
||||
- templates/deployment.yaml
|
||||
- templates/secret-chart.yaml
|
||||
- templates/pairing-relay.yaml
|
||||
- templates/deletion-drain-cronjob.yaml
|
||||
tests:
|
||||
- it: derives the relay version label from image.tag over a stale pin
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: sha-abcdef1
|
||||
image.digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
|
||||
relay.podLabels:
|
||||
tags.datadoghq.com/env: staging
|
||||
tags.datadoghq.com/service: buzz-example
|
||||
tags.datadoghq.com/version: sha-stale00
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-abcdef1
|
||||
template: templates/deployment.yaml
|
||||
# Deployment-describing labels still pass through.
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/env"]
|
||||
value: staging
|
||||
template: templates/deployment.yaml
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/service"]
|
||||
value: buzz-example
|
||||
template: templates/deployment.yaml
|
||||
- it: stamps the relay version label with no podLabels configured
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: sha-abcdef1
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-abcdef1
|
||||
template: templates/deployment.yaml
|
||||
- it: renders a label-safe relay version from a digest-only image
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "222222222222222222222222222222222222222222222222222222222222222"
|
||||
template: templates/deployment.yaml
|
||||
- it: derives the pairing relay version label from image.tag over a stale pin
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
pairingRelay.enabled: true
|
||||
pairingRelay.url: wss://pairing.buzz.xyz
|
||||
image.tag: sha-abcdef1
|
||||
image.digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
|
||||
pairingRelay.podLabels:
|
||||
tags.datadoghq.com/env: staging
|
||||
tags.datadoghq.com/service: buzz-example
|
||||
tags.datadoghq.com/version: sha-stale00
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-abcdef1
|
||||
template: templates/pairing-relay.yaml
|
||||
documentIndex: 0
|
||||
# Deployment-describing labels still pass through.
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/env"]
|
||||
value: staging
|
||||
template: templates/pairing-relay.yaml
|
||||
documentIndex: 0
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/service"]
|
||||
value: buzz-example
|
||||
template: templates/pairing-relay.yaml
|
||||
documentIndex: 0
|
||||
- it: stamps the pairing relay version label with no podLabels configured
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
pairingRelay.enabled: true
|
||||
pairingRelay.url: wss://pairing.buzz.xyz
|
||||
image.tag: sha-abcdef1
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-abcdef1
|
||||
template: templates/pairing-relay.yaml
|
||||
documentIndex: 0
|
||||
- it: renders a label-safe pairing relay version from a digest-only image
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
pairingRelay.enabled: true
|
||||
pairingRelay.url: wss://pairing.buzz.xyz
|
||||
image.digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "222222222222222222222222222222222222222222222222222222222222222"
|
||||
template: templates/pairing-relay.yaml
|
||||
documentIndex: 0
|
||||
- it: derives the deletion drain version label from image.tag over a stale pin
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
operatorJobs.deletionDrain.enabled: true
|
||||
image.tag: sha-abcdef1
|
||||
image.digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
|
||||
operatorJobs.deletionDrain.podLabels:
|
||||
tags.datadoghq.com/env: staging
|
||||
tags.datadoghq.com/service: buzz-example
|
||||
tags.datadoghq.com/version: sha-stale00
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-abcdef1
|
||||
template: templates/deletion-drain-cronjob.yaml
|
||||
# Deployment-describing labels still pass through.
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/env"]
|
||||
value: staging
|
||||
template: templates/deletion-drain-cronjob.yaml
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/service"]
|
||||
value: buzz-example
|
||||
template: templates/deletion-drain-cronjob.yaml
|
||||
- it: stamps the deletion drain version label with no podLabels configured
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
operatorJobs.deletionDrain.enabled: true
|
||||
image.tag: sha-abcdef1
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: sha-abcdef1
|
||||
template: templates/deletion-drain-cronjob.yaml
|
||||
- it: renders a label-safe deletion drain version from a digest-only image
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
operatorJobs.deletionDrain.enabled: true
|
||||
image.digest: sha256:2222222222222222222222222222222222222222222222222222222222222222
|
||||
asserts:
|
||||
- equal:
|
||||
path: spec.jobTemplate.spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "222222222222222222222222222222222222222222222222222222222222222"
|
||||
template: templates/deletion-drain-cronjob.yaml
|
||||
# ── Datadog normalization (PR #7876 review, P0) ───────────────────────────
|
||||
# Datadog lowercases tag values and collapses "__", so a passthrough of a
|
||||
# non-normal value would merge two revisions into one reported version. Each
|
||||
# pair below must render two labels that stay distinct after normalization.
|
||||
- it: hashes a tag with uppercase so it cannot merge with its lowercase twin
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "ReleaseA"
|
||||
asserts:
|
||||
# Passed through, Datadog would read this as "releasea".
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "4592ae6466f715bbba35c9e1931fe5cdd548a4355947759b1fcf7f2b6f0e727"
|
||||
template: templates/deployment.yaml
|
||||
- notEqual:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "releasea"
|
||||
template: templates/deployment.yaml
|
||||
- it: passes through the lowercase twin of a hashed uppercase tag
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "releasea"
|
||||
asserts:
|
||||
# Already in Datadog normal form, so preserved byte for byte.
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "releasea"
|
||||
template: templates/deployment.yaml
|
||||
- it: hashes a tag containing a double underscore
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "release__a"
|
||||
asserts:
|
||||
# Passed through, Datadog would collapse this to "release_a".
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "ab213bb0d3409388c915a5d3ef384cd6d812237d4aa712081edfc1c1473daa1"
|
||||
template: templates/deployment.yaml
|
||||
- notEqual:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "release_a"
|
||||
template: templates/deployment.yaml
|
||||
- it: passes through the single-underscore twin of a hashed double-underscore tag
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "release_a"
|
||||
asserts:
|
||||
# Already in Datadog normal form, so preserved byte for byte.
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "release_a"
|
||||
template: templates/deployment.yaml
|
||||
- it: hashes an uppercased 63-hex tag instead of letting it alias the reserved shape
|
||||
set:
|
||||
relayUrl: wss://buzz.example.com
|
||||
ownerPubkey: "0000000000000000000000000000000000000000000000000000000000000000"
|
||||
externalPostgresql.url: postgres://u:p@h:5432/d
|
||||
externalRedis.url: redis://h:6379
|
||||
s3.endpoint: https://s3.example.com
|
||||
s3.bucket: buzz-media-example
|
||||
s3.accessKey: test
|
||||
s3.secretKey: test
|
||||
image.tag: "ABCDEF000000000000000000000000000000000000000000000000000000000"
|
||||
asserts:
|
||||
# Passed through, Datadog would lowercase this onto the reserved 63-hex shape that digest-derived labels use.
|
||||
- equal:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "2435b36c0cdc7f75334db8b9151d18738e4358cd0fac9b260e98a84f0207b41"
|
||||
template: templates/deployment.yaml
|
||||
- notEqual:
|
||||
path: spec.template.metadata.labels["tags.datadoghq.com/version"]
|
||||
value: "abcdef000000000000000000000000000000000000000000000000000000000"
|
||||
template: templates/deployment.yaml
|
||||
@@ -229,7 +229,10 @@
|
||||
"failedJobsHistoryLimit": { "type": "integer", "minimum": 0 },
|
||||
"relayMode": { "type": "string", "enum": ["inline", "external", "off"] },
|
||||
"serviceAccountName": { "type": "string" },
|
||||
"podLabels": { "type": "object" },
|
||||
"podLabels": {
|
||||
"type": "object",
|
||||
"description": "Extra Pod labels. The chart owns tags.datadoghq.com/version and derives it from the deployed image identity, so a value supplied here for that one key is ignored."
|
||||
},
|
||||
"podAnnotations": { "type": "object" },
|
||||
"resources": { "type": "object" }
|
||||
}
|
||||
|
||||
@@ -172,6 +172,7 @@ relay:
|
||||
memory: "2Gi"
|
||||
|
||||
podAnnotations: {}
|
||||
# tags.datadoghq.com/version is chart-owned; see README "Datadog version label".
|
||||
podLabels: {}
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
@@ -222,6 +223,7 @@ pairingRelay:
|
||||
port: 5000
|
||||
annotations: {}
|
||||
podAnnotations: {}
|
||||
# tags.datadoghq.com/version is chart-owned; see README "Datadog version label".
|
||||
podLabels: {}
|
||||
resources:
|
||||
requests:
|
||||
@@ -380,6 +382,9 @@ storageAccounting:
|
||||
failedJobsHistoryLimit: 3
|
||||
relayMode: external # external | off; inline is a legacy alias
|
||||
serviceAccountName: "" # defaults to the main Buzz service account
|
||||
# Extra Pod labels, e.g. Datadog unified service tagging. The chart owns
|
||||
# `tags.datadoghq.com/version` on every workload (see README "Datadog version
|
||||
# label"); a value supplied here for that one key is ignored.
|
||||
podLabels: {}
|
||||
podAnnotations:
|
||||
sidecar.istio.io/inject: "false"
|
||||
@@ -405,6 +410,7 @@ operatorJobs:
|
||||
# Empty inherits the relay service account, and with it any cloud IAM
|
||||
# binding on that account. Name a dedicated account to narrow the executor.
|
||||
serviceAccountName: ""
|
||||
# tags.datadoghq.com/version is chart-owned; see README "Datadog version label".
|
||||
podLabels: {}
|
||||
podAnnotations:
|
||||
sidecar.istio.io/inject: "false"
|
||||
|
||||
@@ -85,3 +85,38 @@ image:
|
||||
|
||||
When `image.digest` is set, the chart renders `repository@digest` and ignores
|
||||
`image.tag`. Existing tag-only values remain backwards compatible.
|
||||
|
||||
## Derived deployment labels
|
||||
|
||||
Every chart-managed Pod — the relay, the pairing relay, the storage-accounting
|
||||
CronJob, and operator jobs such as the deletion drain — carries a
|
||||
chart-owned `tags.datadoghq.com/version` label derived from the deployed image,
|
||||
so a wrapper never restates the image identity once per workload. The label
|
||||
names `image.tag` when it is set (the readable `sha-<commit>` build name that
|
||||
promotion writes together with `image.digest`), otherwise `image.digest`,
|
||||
otherwise `Chart.AppVersion`.
|
||||
|
||||
The exact runtime identity stays exact elsewhere: the Pod's image reference is
|
||||
`repository@digest` when a digest is pinned, and the storage-accounting
|
||||
`BUZZ_STORAGE_SNAPSHOT_CODE_SHA` (persisted as `code_sha` on every snapshot
|
||||
row) is the digest when set, otherwise the tag, otherwise `Chart.AppVersion`.
|
||||
|
||||
The label value has to be sanitized: a
|
||||
label value is capped at 63 bytes, must begin and end with an alphanumeric, and
|
||||
may otherwise contain only `[-._a-zA-Z0-9]`, while `image.tag` accepts any OCI
|
||||
tag. Because that domain is larger than the label codomain, no mapping onto it
|
||||
is injective; the chart provides a deterministic, collision-resistant one. A
|
||||
digest keeps the first 63 characters of its hex, a revision that is already a
|
||||
valid label value in Datadog's normal form (lowercase, no `__`) is preserved
|
||||
byte for byte, and anything else (a leading `_`, an uppercase letter, a `__`
|
||||
run, a byte outside the label alphabet, more than 63 bytes) is replaced by the first
|
||||
63 hex characters of its SHA-256 — 252 retained bits, the same margin as the
|
||||
digest case, and no readable prefix.
|
||||
|
||||
Exactly 63 lowercase hex characters is reserved for those hashed and digest
|
||||
forms: a tag of that shape is hashed instead of preserved, so a rendered label
|
||||
cannot be copied into `image.tag` to make two revisions report one version.
|
||||
Shorter hex tags and 40-character git SHAs pass through unchanged.
|
||||
|
||||
Any `tags.datadoghq.com/version` supplied through a workload's `podLabels` is
|
||||
ignored; see the chart README's "Datadog version label" section.
|
||||
|
||||
Reference in New Issue
Block a user