Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion charts/radar-hub/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: radar-hub
description: Radar Cloud control plane for self-hosted deployments — Go API + React
web app + Postgres (bundled eval DB or bring-your-own).
type: application
version: 1.14.1
version: 1.15.0-rc.1
# The Hub release this chart installs. image.hub.tag and image.web.tag both
# default to it when unset. Deliberately independent of `version` above — see
# README.md. Rewritten by the release job in skyhook-dev/radar-hub; do not carry
Expand Down
25 changes: 25 additions & 0 deletions charts/radar-hub/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,31 @@ See [`values.yaml`](values.yaml) for the full set, and
[`values.schema.json`](values.schema.json) for the enforced schema. Invalid
values are rejected at install time rather than surfacing as a broken pod.

## Pod labels

`podLabels` adds labels to every pod the chart runs: hub, web and the bundled
Postgres. On Hub releases that support it, they also go on the AI
investigation Jobs the hub starts. `hub.installPodLabels` adds labels to the
Radar install commands the hub shows, so the agent in each connected cluster
carries them; older Hub releases ignore it.

If you bought Radar through Google Cloud Marketplace, set Google's
consumption-tracking label in both:

```yaml
podLabels:
goog-partner-solution: <value from the Radar docs>
hub:
installPodLabels:
goog-partner-solution: <value from the Radar docs>
```

Keys and values follow Kubernetes label syntax, which the schema enforces. The
chart's own selector labels (`app.kubernetes.io/name`,
`app.kubernetes.io/instance` and `app.kubernetes.io/component`) can't be set
through `podLabels`, nor the Radar agent chart's (`app.kubernetes.io/name` and
`app.kubernetes.io/instance`) through `hub.installPodLabels`.

## AI agent

Release prerequisite: this feature requires a Hub release with Anthropic provider
Expand Down
47 changes: 47 additions & 0 deletions charts/radar-hub/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,53 @@ app.kubernetes.io/name: {{ include "radar-hub.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
.Values.podLabels as YAML for a pod template's labels, or nothing. The chart's
own selector keys are refused: repeated in the same map they render a
duplicate key, and if a duplicate won it would detach the pod from its
Deployment or StatefulSet.
*/}}
{{- define "radar-hub.podLabels" -}}
{{- $reserved := list "app.kubernetes.io/name" "app.kubernetes.io/instance" "app.kubernetes.io/component" -}}
{{- range $k, $_ := .Values.podLabels -}}
{{- if has $k $reserved -}}
{{- fail (printf "podLabels: %s is one of the chart's own selector labels and can't be set" $k) -}}
{{- end -}}
{{- end -}}
{{- with .Values.podLabels -}}
{{- toYaml . -}}
{{- end -}}
{{- end }}

{{/*
.Values.hub.installPodLabels as key=value,key=value for HUB_INSTALL_POD_LABELS,
or nothing. The Radar agent chart's selector keys are refused: the hub puts
these labels on every agent's pod template, where either key would render a
duplicate or detach the pod from its Deployment.
*/}}
{{- define "radar-hub.installPodLabels" -}}
{{- $reserved := list "app.kubernetes.io/name" "app.kubernetes.io/instance" -}}
{{- range $k, $_ := .Values.hub.installPodLabels -}}
{{- if has $k $reserved -}}
{{- fail (printf "hub.installPodLabels: %s is one of the Radar chart's selector labels and can't be set" $k) -}}
{{- end -}}
{{- end -}}
{{- include "radar-hub.labelList" .Values.hub.installPodLabels -}}
{{- end }}

{{/*
A label map as key=value,key=value for an environment variable. Label syntax
(enforced by the schema) has no "," or "=" in keys or values, so the hub can
split it back unambiguously. Keys come out sorted.
*/}}
{{- define "radar-hub.labelList" -}}
{{- $pairs := list -}}
{{- range $k, $v := . -}}
{{- $pairs = append $pairs (printf "%s=%s" $k $v) -}}
{{- end -}}
{{- join "," $pairs -}}
{{- end }}

{{- define "radar-hub.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "radar-hub.fullname" .) .Values.serviceAccount.name }}
Expand Down
16 changes: 16 additions & 0 deletions charts/radar-hub/templates/deployment-hub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ spec:
labels:
{{- include "radar-hub.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: hub
{{- with include "radar-hub.podLabels" . }}
{{- . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "radar-hub.serviceAccountName" . }}
{{- with .Values.imagePullSecrets }}
Expand Down Expand Up @@ -389,6 +392,13 @@ spec:
- name: HUB_ENROLLMENT_APPROVAL
value: "manual"
{{- end }}
{{- /* Labels for the Radar install commands the hub shows.
Emitted only when set, so an install that sets nothing
renders the same env as before. */}}
{{- with include "radar-hub.installPodLabels" . }}
- name: HUB_INSTALL_POD_LABELS
value: {{ . | quote }}
{{- end }}
{{- if include "radar-hub.webTLSIsPublic" . }}
{{- /* The certificate that serves the hub's public address,
public half only, so the hub can hand it to agents that
Expand Down Expand Up @@ -452,6 +462,12 @@ spec:
- name: HUB_AGENT_ENGINE_LABEL
value: {{ . | quote }}
{{- end }}
{{- /* podLabels go on the investigation Jobs too, so every pod
the release causes carries them. */}}
{{- with include "radar-hub.labelList" .Values.podLabels }}
- name: HUB_AGENT_JOB_POD_LABELS
value: {{ . | quote }}
{{- end }}
{{- /* Fleet-wide kill switch for the AI analysis alert rules can
attach to the issues they match. Emitted only when on: the
hub defaults it off, so an absent variable is the same
Expand Down
3 changes: 3 additions & 0 deletions charts/radar-hub/templates/deployment-web.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ spec:
labels:
{{- include "radar-hub.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: web
{{- with include "radar-hub.podLabels" . }}
{{- . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "radar-hub.serviceAccountName" . }}
{{- with .Values.imagePullSecrets }}
Expand Down
3 changes: 3 additions & 0 deletions charts/radar-hub/templates/postgres-bundled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ spec:
labels:
{{- include "radar-hub.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: postgres
{{- with include "radar-hub.podLabels" . }}
{{- . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
Expand Down
25 changes: 25 additions & 0 deletions charts/radar-hub/tests/render-matrix.sh
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,31 @@ if notes "${ING[@]}" | grep -qF "In-cluster agent address"; then printf ' FAIL
else printf ' ok %-46s absent\n' "no in-cluster address without a listener"; fi
rm -rf "$scratch"

echo "pod labels"
PL=(--set-string podLabels.goog-partner-solution=isol_plb32_0123abc)
# 8 spaces: under spec.template.metadata.labels, not the Deployment's own labels.
PLRE='^ {8}goog-partner-solution: isol_plb32_0123abc$'
has "hub pod carries podLabels" "$PLRE" "${PL[@]}" --show-only templates/deployment-hub.yaml
has "web pod carries podLabels" "$PLRE" "${PL[@]}" --show-only templates/deployment-web.yaml
has "bundled Postgres pod carries podLabels" "$PLRE" "${PL[@]}" --show-only templates/postgres-bundled.yaml
lacks "no podLabels by default" 'goog-partner-solution'
check "a selector key in podLabels" refuse --set-string 'podLabels.app\.kubernetes\.io/component=x'
check "a non-string podLabels value" refuse --set podLabels.team=1
check "a podLabels value with a space" refuse --set-string 'podLabels.team=a b'
check "a podLabels key with a space" refuse --set-string 'podLabels.bad key=x'
check "a 64-character install label value" refuse --set-string "hub.installPodLabels.x=$(printf 'a%.0s' $(seq 64))"
check "a prefixed label key" render --set-string 'podLabels.example\.com/team=platform'
check "a 253-character label prefix" render --set-string "podLabels.$(printf 'a%.0s' $(seq 253))/team=x"
check "a 254-character label prefix" refuse --set-string "podLabels.$(printf 'a%.0s' $(seq 254))/team=x"
check "an agent selector key in installPodLabels" refuse --set-string 'hub.installPodLabels.app\.kubernetes\.io/name=x'
check "the other agent selector key" refuse --set-string 'hub.installPodLabels.app\.kubernetes\.io/instance=x'
envis "installPodLabels reach the hub" HUB_INSTALL_POD_LABELS 'a=1,goog-partner-solution=isol_x' --set-string hub.installPodLabels.goog-partner-solution=isol_x --set-string hub.installPodLabels.a=1
lacks "no install-labels env by default" 'name: HUB_INSTALL_POD_LABELS'
AGF=(-f ci/agent-anthropic-values.yaml)
envis "podLabels reach the AI investigation Jobs" HUB_AGENT_JOB_POD_LABELS 'goog-partner-solution=isol_plb32_0123abc' "${AGF[@]}" "${PL[@]}"
lacks "no Job-labels env without podLabels" 'name: HUB_AGENT_JOB_POD_LABELS' "${AGF[@]}"
lacks "no Job-labels env with the agent off" 'name: HUB_AGENT_JOB_POD_LABELS' "${PL[@]}"

echo
if [ $fails -eq 0 ]; then echo "all checks passed"; else echo "$fails check(s) failed"; fi
exit $fails
Expand Down
24 changes: 23 additions & 1 deletion charts/radar-hub/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@
"podAnnotations": {
"type": "object"
},
"installPodLabels": {
"$ref": "#/definitions/labels"
},
Comment thread
qodo-free-for-open-source-projects[bot] marked this conversation as resolved.
Resolved
"nodeSelector": {
"type": "object"
},
Expand Down Expand Up @@ -808,12 +811,31 @@
"securityContext": {
"type": "object"
},
"podLabels": {
"$ref": "#/definitions/labels"
},
"nameOverride": {
"type": "string"
},
"fullnameOverride": {
"type": "string"
}
},
"additionalProperties": false
"additionalProperties": false,
"definitions": {
"labels": {
"description": "Kubernetes labels: keys are an optional DNS-subdomain prefix (at most 253 characters) and a name of at most 63 characters; values are strings of at most 63 letters, digits, '-', '_' or '.', starting and ending with a letter or digit.",
"type": "object",
"propertyNames": {
"pattern": "^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?[A-Za-z0-9]([-A-Za-z0-9_.]{0,61}[A-Za-z0-9])?$",
"not": {
"pattern": "^[^/]{254,}/"
}
},
"additionalProperties": {
"type": "string",
"pattern": "^(([A-Za-z0-9][-A-Za-z0-9_.]{0,61})?[A-Za-z0-9])?$"
}
}
}
}
16 changes: 16 additions & 0 deletions charts/radar-hub/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,11 @@ hub:
memory: 1Gi

podAnnotations: {}
# Labels the hub adds to the Radar install commands it shows for connecting
# a cluster, so the Radar agent in each cluster carries them. Bought through
# Google Cloud Marketplace? Set the same label as podLabels. Needs a Hub
# release that supports it; older ones ignore it.
installPodLabels: {}
# Official images are published for linux/amd64 and linux/arm64, so only the
# OS is pinned by default. Add kubernetes.io/arch: <amd64|arm64> to constrain
# it; Helm merges that key with this default selector.
Expand Down Expand Up @@ -819,6 +824,17 @@ securityContext:
drop: ["ALL"]
readOnlyRootFilesystem: false # web image needs writable /var/cache/nginx + /tmp/run

# Extra labels on every pod this chart runs (hub, web and the bundled
# Postgres) and, on Hub releases that support it, on the AI investigation Jobs
# the hub starts. Bought through Google Cloud Marketplace? Set Google's
# consumption-tracking label here, and in hub.installPodLabels:
# podLabels:
# goog-partner-solution: <the value in the Radar docs>
# Kubernetes label syntax. The chart's own selector labels
# (app.kubernetes.io/name, app.kubernetes.io/instance and
# app.kubernetes.io/component) can't be set here.
podLabels: {}

# ---------------------------------------------------------------------------
# Names
# ---------------------------------------------------------------------------
Expand Down
Loading