diff --git a/app/functions/helmless/default-values.yaml b/app/functions/helmless/default-values.yaml index 09ef7229..f2da2984 100644 --- a/app/functions/helmless/default-values.yaml +++ b/app/functions/helmless/default-values.yaml @@ -52,6 +52,26 @@ defaults: image: pullPolicy: IfNotPresent pullSecrets: + + # Additional environment variables to inject into every container the chart + # manages. Each entry follows the Kubernetes EnvVar schema — `name` plus + # either a literal `value` or a `valueFrom` (fieldRef, configMapKeyRef, + # secretKeyRef, etc.). See: + # https://kubernetes.io/docs/reference/kubernetes-api/core/pod-v1/#EnvVar + # + # `defaults.env` is the lowest-priority env source — chart-emitted entries + # (validatorEnv, hardcoded `HOSTNAME` / `NODE_NAME` / `SERVER_PORT` + # fieldRefs) and component-specific user env (e.g., `.Values.server.env` on + # the Prometheus container) override it on `name` collision. + # + # To route chart traffic through an HTTP(S) proxy, set HTTP_PROXY / + # HTTPS_PROXY / NO_PROXY here, see `helm/docs/egress-proxy.md` for the full + # walkthrough — what NO_PROXY must cover, per-cloud examples, and discovery + # commands. + # + # Default: [] (no extra env vars). + env: [] + # If set, these DNS settings will be attached to resources which support it. dns: # DNS policy to use on all pods. diff --git a/helm/README.md b/helm/README.md index 40084a97..dae70a97 100644 --- a/helm/README.md +++ b/helm/README.md @@ -323,6 +323,7 @@ To receive a notification when a new version of the chart is [released](https:// - [Memory Sizing Guide](./docs/sizing-guide.md) - [Deployment Validation Guide](./docs/deploy-validation.md) - Using istio? [Read on here](./docs/istio.md) +- Behind an egress proxy? [Read on here](./docs/egress-proxy.md) - [Chart release notes](./docs/releases/) --- diff --git a/helm/docs/egress-proxy.md b/helm/docs/egress-proxy.md new file mode 100644 index 00000000..bdfdbe84 --- /dev/null +++ b/helm/docs/egress-proxy.md @@ -0,0 +1,321 @@ +# Routing Agent Traffic Through an HTTP(S) Proxy + +Some Kubernetes clusters cannot reach the public internet directly — +egress goes through a forward HTTP(S) proxy, usually paired with a +firewall that denies everything else. To run the CloudZero Agent in +such a cluster, you have to tell each of the agent's containers: + +1. **The proxy to use** for traffic destined for `api.cloudzero.com`. +2. **Which destinations to bypass** the proxy for: in-cluster Services, + the kube-apiserver, the pod CIDR Prometheus scrapes against, cloud + instance metadata, and so on. + +The chart's `defaults.env` value injects environment variables into +every chart-managed container. This document covers how to use it for +proxy configuration. The same mechanism works for any other env you +need to push to every container. + +> [!IMPORTANT] +> The chart cannot auto-discover your proxy URL, pod CIDR, service +> CIDR, or apiserver IP — those vary per cluster. You have to inspect +> your own cluster to assemble `NO_PROXY`. Discovery commands are in +> the [Finding your cluster's values](#finding-your-clusters-values) +> section. + +## How the chart picks up proxy settings + +Every binary the chart ships is built in Go (this includes the bundled +Prometheus, taken unmodified from upstream releases, and Alloy, our +fork of Grafana Alloy). All of them honor three environment variables +via Go's standard +[`http.ProxyFromEnvironment`](https://pkg.go.dev/net/http#ProxyFromEnvironment): + +| Variable | Effect | +| ------------- | --------------------------------------------------------- | +| `HTTPS_PROXY` | Proxy URL for HTTPS destinations. | +| `HTTP_PROXY` | Proxy URL for HTTP destinations. | +| `NO_PROXY` | Comma-separated list of destinations to bypass the proxy. | + +There is no separate "proxy URL" knob in the chart — setting these +three env vars is the entire interface. + +To set them, list them under `defaults.env`: + +```yaml +defaults: + env: + - name: HTTPS_PROXY + value: "http://proxy.example.com:8080" + - name: HTTP_PROXY + value: "http://proxy.example.com:8080" + - name: NO_PROXY + value: "localhost,127.0.0.1,169.254.169.254,cluster.local,10.0.0.0/8" +``` + +### Precedence + +`defaults.env` is the **lowest**-priority env source. The chart's +[`generateEnv`](../templates/_helpers.tpl) helper iterates sources in +order, and later sources overwrite earlier ones by `name`. The order +used at every call site is: + +1. `.Values.defaults.env` (this value) +2. `.Values.server.env` (Prometheus-only) +3. Validator-lifecycle env (`K8S_NAMESPACE`, `K8S_POD_NAME`, `ISTIO_*`, + etc.) +4. Hardcoded literals (`HOSTNAME`, `NODE_NAME`, `SERVER_PORT`, + fieldRefs) + +In practice you will never collide with `HTTPS_PROXY` / `HTTP_PROXY` / +`NO_PROXY` — the chart never sets those itself — so the precedence +question only matters if you try to use `defaults.env` to override a +chart-emitted name. Don't. + +## NO_PROXY syntax + +`NO_PROXY` is parsed by +[`golang.org/x/net/http/httpproxy`](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config), +which `net/http` delegates to. The package's +[`Config.NoProxy` doc comment](https://pkg.go.dev/golang.org/x/net/http/httpproxy#Config) +is the authoritative reference. The notable points: + +- **Comma-separated.** Whitespace around values is stripped — `"a, b"` + works the same as `"a,b"`. +- **Case-insensitive.** Both the request host and each entry are + lowercased before matching. +- **Plain hostname** (`foo.com`) matches the bare domain **and** all + subdomains (`foo.com`, `bar.foo.com`, `a.b.foo.com`). +- **Leading-dot hostname** (`.foo.com`) matches subdomains **only**, not + the bare domain. +- **`*.foo.com`** is normalized to `.foo.com` — same semantics as the + leading-dot form. +- **CIDR blocks** (`10.0.0.0/16`, `2001:db8::/64`) match any IP in + range. +- **Single IPs** match exactly. +- **`:port` suffix** on an entry restricts it to that port; an entry + without a port matches any port. +- **`*` alone** disables the proxy entirely. + +Note in particular that `cluster.local` covers `foo.svc.cluster.local`, +`bar.cluster.local`, and the bare `cluster.local` — you don't need to +list `.svc.cluster.local` or `.svc` separately. (`.svc` on its own +would only match strings ending in `.svc`, e.g. `foo.svc`, which is +not what cluster DNS produces.) + +## What you have to cover + +The agent's components talk to several categories of destination. +Anything not in `NO_PROXY` goes through the proxy — which usually means +either an outright failure (the proxy rejects in-cluster destinations) +or an expensive hairpin out to your egress edge and back. + +### Loopback + +```text +localhost,127.0.0.1 +``` + +Containers talk to themselves for health checks and pprof endpoints. + +### Cluster DNS suffix + +```text +cluster.local +``` + +The aggregator, webhook server, and Prometheus federation endpoint are +reached by Service DNS names like +`cloudzero-agent-server.cloudzero-agent.svc.cluster.local`. The bare +`cluster.local` entry suffix-matches all of those. + +If your cluster uses a non-default DNS domain (configured via +`--cluster-domain` on kubelet), use that instead. + +### kube-apiserver ClusterIP + +```text +10.96.0.1 +``` + +The agent calls the API server for pod, node, and namespace metadata. +`kubernetes.default.svc.cluster.local` is covered by the entry above, +but the apiserver's **ClusterIP is a routed IP, not a name** — and +client libraries often connect by IP. List it explicitly. + +The default ClusterIP for kubeadm clusters is `10.96.0.1`, but +cloud-managed clusters use different ranges (`172.20.0.1` is common on +EKS, GKE uses an IP from `34.118.224.0/20` on this author's test +cluster, etc.). + +### Pod CIDR (critical for Prometheus) + +```text +10.244.0.0/16 +``` + +This is the one that bites. Prometheus's +[`endpointslice` SD](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config) +resolves each target to its **pod IP**, not the Service DNS name. So +even with `cluster.local` in `NO_PROXY`, scrape requests still go to +addresses like `10.244.5.32:9090`. + +Add your cluster's pod CIDR. + +### Service CIDR + +```text +10.96.0.0/12 +``` + +Some clients address Services via their ClusterIP directly. Listing +the whole service CIDR makes those bypass the proxy and also covers +the apiserver ClusterIP, so you can drop the explicit apiserver entry +if you list the full range. + +### Cloud instance metadata + +```text +169.254.169.254,metadata.google.internal +``` + +The agent's +[Scout](https://github.com/Cloudzero/cloudzero-agent/tree/develop/app/utils/scout) +component queries cloud-provider metadata to identify the cluster +(account/project/subscription ID, region). On AWS, Azure, and GCP the +endpoint is link-local at `169.254.169.254`. GCP also accepts the DNS +name `metadata.google.internal` (which resolves to the same address). + +If `169.254.169.254` goes through the proxy, the metadata call will +hang or 4xx and the validator will refuse to start past the +"cloud provider detection failed" stage unless your values set the +relevant identity fields explicitly. + +## Finding your cluster's values + +The values above are placeholders — you have to look up the real +numbers. The commands below were tested against a GKE test cluster +unless otherwise noted. + +### apiserver ClusterIP + +```sh +kubectl get svc kubernetes -n default -o jsonpath='{.spec.clusterIP}' +``` + +Returns a single IP. + +### Pod CIDR (cluster-wide) + +`kubectl get nodes -o jsonpath='{.items[*].spec.podCIDR}'` returns the +**per-node** slice (a `/24` per node on most platforms), not the +cluster-wide parent. For the parent CIDR, prefer your cloud provider's +CLI: + +```sh +# GKE (works for both zonal and regional clusters via --location): +gcloud container clusters describe CLUSTER --location LOCATION \ + --format='value(clusterIpv4Cidr,servicesIpv4Cidr)' + +# EKS (pod IPs come from VPC subnets when using the AWS VPC CNI): +aws eks describe-cluster --name CLUSTER \ + --query 'cluster.{podCidr:resourcesVpcConfig.cidrs,svcCidr:kubernetesNetworkConfig.serviceIpv4Cidr}' + +# AKS: +az aks show -n CLUSTER -g RESOURCE_GROUP \ + --query 'networkProfile.{podCidr:podCidr,svcCidr:serviceCidr}' -o tsv +``` + +On many self-managed clusters the kube-proxy `--cluster-cidr` flag is +visible in `kubectl cluster-info dump`: + +```sh +kubectl cluster-info dump | grep -m1 cluster-cidr +``` + +The cloud CLI invocations above were not exhaustively tested across +account types — confirm against your cloud-provider documentation if +the values look off. + +### Service CIDR (via cloud CLI) + +The cloud CLIs above also return the service CIDR. On clusters where +the control plane is visible to `kubectl cluster-info dump`, +`grep service-cluster-ip-range` will pull it out; on cloud-managed +clusters the control plane is hidden and that doesn't work, so use the +cloud CLI. + +## Worked examples + +These are **starting points**, not finished configurations. The CIDRs +came from this author's recollection of typical defaults — verify each +value against your cluster before deploying. + +### AWS EKS + +```yaml +defaults: + env: + - name: HTTPS_PROXY + value: "http://proxy.internal.example.com:3128" + - name: HTTP_PROXY + value: "http://proxy.internal.example.com:3128" + - name: NO_PROXY + value: "localhost,127.0.0.1,169.254.169.254,cluster.local,10.0.0.0/8,172.20.0.0/16" +``` + +`10.0.0.0/8` is a typical VPC CIDR (EKS pod IPs live in your VPC under +the AWS VPC CNI). `172.20.0.0/16` is the EKS default service CIDR. +Both vary by cluster. + +### GKE + +```yaml +defaults: + env: + - name: HTTPS_PROXY + value: "http://proxy.internal.example.com:3128" + - name: HTTP_PROXY + value: "http://proxy.internal.example.com:3128" + - name: NO_PROXY + value: "localhost,127.0.0.1,169.254.169.254,metadata.google.internal,cluster.local,10.0.0.0/14,10.4.0.0/19" +``` + +`10.0.0.0/14` is the GKE default pod CIDR, `10.4.0.0/19` the default +service CIDR. Confirm with `gcloud container clusters describe`. + +### Azure AKS + +```yaml +defaults: + env: + - name: HTTPS_PROXY + value: "http://proxy.internal.example.com:3128" + - name: HTTP_PROXY + value: "http://proxy.internal.example.com:3128" + - name: NO_PROXY + value: "localhost,127.0.0.1,169.254.169.254,cluster.local,10.244.0.0/16,10.0.0.0/16" +``` + +`10.244.0.0/16` is the AKS kubenet pod CIDR. With Azure CNI the pod +CIDR is your subnet, often much smaller than `/16`. `10.0.0.0/16` is +a typical service CIDR default. + +## Validating the configuration + +After deploying, spot-check that the env vars reached the containers: + +```sh +kubectl exec -n cloudzero-agent deploy/cloudzero-agent-server \ + -c server -- env | grep -i proxy +``` + +…and, if you control the proxy, watch its access log while the agent +starts. Expected behavior: + +- Calls to `api.cloudzero.com` (and `app.cloudzero.com` for Replicated + installs) appear in the proxy log. +- Calls to your apiserver, in-cluster Services, pod IPs, and the + metadata endpoint do **not** appear. + +If you see in-cluster destinations in the proxy log, your `NO_PROXY` +is incomplete — find the missing entry and reinstall. diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl index 799d5238..eb5526ba 100644 --- a/helm/templates/_helpers.tpl +++ b/helm/templates/_helpers.tpl @@ -1015,6 +1015,76 @@ annotations: {{- end -}} {{- end -}} +{{/* +Generate a container env block by merging a list of env-entry sources. + +Parameters (dict): +- env: List of env-entry lists to merge (required). + +Each list element is itself a list of env-entry dicts ({name, value} or +{name, valueFrom}). Sources can come from: + - an inline list of dicts built with `(list (dict "name" "..." "value" ...))` + - the output of an env-emitting helper, parsed via `fromYamlArray`: + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + - a list value from values.yaml: `.Values.defaults.env` + +Merge behavior: +- Later sources override earlier sources by `name` (last wins). +- First-seen wins for ordering; overrides retain the entry's original position. +- Nil/empty sources are skipped. +- Entries without a `name` field are skipped (defensive only — the + `.Values.defaults.env` schema rejects them at render time via the + io.k8s.api.core.v1.EnvVar ref). + +Output: +- If at least one entry survives the merge, emits an `env:` key followed by + the merged list as YAML. +- If the merged list is empty, emits nothing — caller's container ends up + with no env block, preserving the chart's default rendering. + +Source-list precedence convention (lowest → highest): + 1. `.Values.defaults.env` — chart-wide user override; lowest priority. + 2. Component-specific user env (e.g. `.Values.server.env`) — overrides + chart-wide user env on collision but loses to chart-emitted entries. + 3. Chart-emitted helper output (`validatorEnv` etc.). + 4. Chart-emitted hardcoded literals (`SERVER_PORT`, `NODE_NAME`, + `HOSTNAME`) — highest priority; these are load-bearing for the + chart's correctness and must not be overridable. + +Example: + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + .Values.server.env + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + (list (dict "name" "SERVER_PORT" "value" (printf "%d" (int .Values.aggregator.shipper.port)))) + ) + ) | nindent 10 }} +*/}} +{{- define "cloudzero-agent.generateEnv" -}} +{{- $sources := .env | default (list) -}} +{{- $byName := dict -}} +{{- $order := list -}} +{{- range $list := $sources -}} + {{- range $entry := $list -}} + {{- if and $entry $entry.name -}} + {{- if not (hasKey $byName $entry.name) -}} + {{- $order = append $order $entry.name -}} + {{- end -}} + {{- $_ := set $byName $entry.name $entry -}} + {{- end -}} + {{- end -}} +{{- end -}} +{{- if $order -}} +{{- $result := list -}} +{{- range $name := $order -}} + {{- $result = append $result (index $byName $name) -}} +{{- end -}} +env: +{{- $result | toYaml | nindent 2 -}} +{{- end -}} +{{- end -}} + {{/* Generate affinity sections */}} @@ -1530,6 +1600,7 @@ Returns: The Istio cluster ID string (explicit or fallback to clusterName) {{- .Values.integrations.istio.clusterID | default .Values.clusterName -}} {{- end -}} + {{/* Validator Stage Helper diff --git a/helm/templates/agent-daemonset.yaml b/helm/templates/agent-daemonset.yaml index f4756107..f9283c93 100644 --- a/helm/templates/agent-daemonset.yaml +++ b/helm/templates/agent-daemonset.yaml @@ -65,11 +65,12 @@ spec: - /bin/sh - -c - sed "s/\${NODE_NAME}/$NODE_NAME/g" /etc/config/prometheus/configmaps/unprocessed/prometheus.yml.in > /etc/config/prometheus/configmaps/processed/prometheus.yml - env: - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (list (dict "name" "NODE_NAME" "valueFrom" (dict "fieldRef" (dict "fieldPath" "spec.nodeName")))) + ) + ) | nindent 10 }} {{- include "cloudzero-agent.generateResources" (include "cloudzero-agent.mergeStringOverwrite" (list (.Values.components.agent.reloader.resources | default (dict)) (.Values.configmapReload.prometheus.resources | default (dict)) @@ -91,6 +92,11 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + ) + ) | nindent 10 }} ports: - containerPort: 8080 livenessProbe: @@ -128,14 +134,13 @@ spec: {{- end }} - name: {{ template "cloudzero-agent.name" . }}-server {{- include "cloudzero-agent.generateImage" (dict "defaults" .Values.defaults.image "image" .Values.components.prometheus.image "compat" (dict "repository" .Values.server.image.repository "tag" (include "cloudzero-agent.Values.components.prometheus.image.tag" .) "digest" .Values.server.image.digest "pullPolicy" .Values.server.image.pullPolicy)) | nindent 10 }} - env: - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - {{- if .Values.server.env }} - {{- toYaml .Values.server.env | indent 12}} - {{- end }} + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + .Values.server.env + (list (dict "name" "NODE_NAME" "valueFrom" (dict "fieldRef" (dict "fieldPath" "spec.nodeName")))) + ) + ) | nindent 10 }} args: - --config.file=/etc/config/prometheus.yml - --web.enable-lifecycle diff --git a/helm/templates/agent-deploy.yaml b/helm/templates/agent-deploy.yaml index 2f137083..ea4a515d 100644 --- a/helm/templates/agent-deploy.yaml +++ b/helm/templates/agent-deploy.yaml @@ -61,8 +61,12 @@ spec: initContainers: - name: {{ .Values.validator.name }}-copy {{- include "cloudzero-agent.generateImage" (dict "defaults" .Values.defaults.image "image" .Values.components.agent.image "compat" .Values.validator.image) | nindent 10 }} - env: - {{- include "cloudzero-agent.validatorEnv" . | nindent 12 }} + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + ) + ) | nindent 10 }} command: - /app/cloudzero-agent-validator - install @@ -84,8 +88,12 @@ spec: mountPath: /checks/config/ - name: {{ .Values.validator.name }}-run {{- include "cloudzero-agent.generateImage" (dict "defaults" .Values.defaults.image "image" .Values.components.agent.image "compat" .Values.validator.image) | nindent 10 }} - env: - {{- include "cloudzero-agent.validatorEnv" . | nindent 12 }} + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + ) + ) | nindent 10 }} command: - /checks/bin/cloudzero-agent-validator - diagnose @@ -115,6 +123,11 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + ) + ) | nindent 10 }} ports: - containerPort: 8080 livenessProbe: @@ -161,11 +174,13 @@ spec: "tag" (include "cloudzero-agent.Values.components.prometheus.image.tag" .) "digest" .Values.server.image.digest "pullPolicy" .Values.server.image.pullPolicy)) | nindent 10 }} - {{- if .Values.server.env }} - env: -{{ toYaml .Values.server.env | indent 12}} - {{- include "cloudzero-agent.validatorEnv" . | nindent 12 }} - {{- end }} + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + .Values.server.env + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + ) + ) | nindent 10 }} lifecycle: postStart: exec: @@ -252,12 +267,13 @@ spec: - --cluster.enabled=true - --cluster.name={{ .Values.clusterName }} {{- end }} - env: - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: metadata.name - {{- include "cloudzero-agent.validatorEnv" . | nindent 12 }} + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + (list (dict "name" "HOSTNAME" "valueFrom" (dict "fieldRef" (dict "fieldPath" "metadata.name")))) + ) + ) | nindent 10 }} lifecycle: postStart: exec: diff --git a/helm/templates/aggregator-deploy.yaml b/helm/templates/aggregator-deploy.yaml index 4f5041ed..a8a599ee 100644 --- a/helm/templates/aggregator-deploy.yaml +++ b/helm/templates/aggregator-deploy.yaml @@ -80,9 +80,12 @@ spec: - name: port-collector containerPort: {{ .Values.aggregator.collector.port }} command: ["/app/cloudzero-collector", "-config", "{{ .Values.aggregator.mountRoot }}/config/config.yml"] - env: - - name: SERVER_PORT - value: "{{ .Values.aggregator.collector.port }}" + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (list (dict "name" "SERVER_PORT" "value" (printf "%d" (int .Values.aggregator.collector.port)))) + ) + ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - name: aggregator-config-volume @@ -126,9 +129,12 @@ spec: - name: port-shipper containerPort: {{ .Values.aggregator.shipper.port }} command: ["/app/cloudzero-shipper", "-config", "{{ .Values.aggregator.mountRoot }}/config/config.yml"] - env: - - name: SERVER_PORT - value: "{{ .Values.aggregator.shipper.port }}" + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (list (dict "name" "SERVER_PORT" "value" (printf "%d" (int .Values.aggregator.shipper.port)))) + ) + ) | nindent 10 }} volumeMounts: {{- include "cloudzero-agent.apiKeyVolumeMount" . | nindent 12 }} - name: aggregator-config-volume diff --git a/helm/templates/backfill-job.yaml b/helm/templates/backfill-job.yaml index 32ea53c2..53aeeae9 100644 --- a/helm/templates/backfill-job.yaml +++ b/helm/templates/backfill-job.yaml @@ -155,6 +155,11 @@ spec: - -config - "{{ include "cloudzero-agent.insightsController.configurationMountPath" $ }}/server-config.yaml" - -backfill + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + $.Values.defaults.env + ) + ) | nindent 14 }} {{- include "cloudzero-agent.generateResources" (include "cloudzero-agent.mergeStringOverwrite" (list ($.Values.components.webhookServer.backfill.resources | default (dict)) ($.Values.insightsController.resources | default (dict)) diff --git a/helm/templates/config-loader-job.yaml b/helm/templates/config-loader-job.yaml index 00c0c4c9..5d94949c 100644 --- a/helm/templates/config-loader-job.yaml +++ b/helm/templates/config-loader-job.yaml @@ -56,8 +56,12 @@ spec: containers: - name: run-validator {{- include "cloudzero-agent.generateImage" (dict "defaults" .Values.defaults.image "image" .Values.components.agent.image "compat" .Values.validator.image) | nindent 10 }} - env: - {{- include "cloudzero-agent.validatorEnv" . | nindent 12 }} + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + (include "cloudzero-agent.validatorEnv" . | fromYamlArray) + ) + ) | nindent 10 }} command: - /app/cloudzero-cluster-config - load diff --git a/helm/templates/helmless-job.yaml b/helm/templates/helmless-job.yaml index 511b3efd..63c50862 100644 --- a/helm/templates/helmless-job.yaml +++ b/helm/templates/helmless-job.yaml @@ -61,6 +61,11 @@ spec: - /etc/config/values/values.yaml - --output - "-" + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + ) + ) | nindent 10 }} {{- include "cloudzero-agent.generateResources" .Values.components.miscellaneous.helmless.resources | nindent 10 }} {{- include "cloudzero-agent.generateContainerSecurityContext" (mergeOverwrite (.Values.defaults.securityContext | default (dict)) diff --git a/helm/templates/init-cert-job.yaml b/helm/templates/init-cert-job.yaml index b6408a41..71ca2d7e 100644 --- a/helm/templates/init-cert-job.yaml +++ b/helm/templates/init-cert-job.yaml @@ -62,6 +62,11 @@ spec: {{- include "cloudzero-agent.generateImage" (dict "defaults" .Values.defaults.image "image" .Values.components.agent.image "compat" .Values.initCertJob.image) | nindent 10 }} command: ["/app/cloudzero-certifik8s"] workingDir: /var/tmp + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + ) + ) | nindent 10 }} {{- include "cloudzero-agent.generateResources" .Values.components.miscellaneous.initCert.resources | nindent 10 }} {{- include "cloudzero-agent.generateContainerSecurityContext" (mergeOverwrite (.Values.defaults.securityContext | default (dict)) diff --git a/helm/templates/webhook-deploy.yaml b/helm/templates/webhook-deploy.yaml index 0afd024b..e6c6eb1c 100644 --- a/helm/templates/webhook-deploy.yaml +++ b/helm/templates/webhook-deploy.yaml @@ -118,6 +118,11 @@ spec: args: - -config - "{{ include "cloudzero-agent.insightsController.configurationMountPath" . }}/server-config.yaml" + {{- include "cloudzero-agent.generateEnv" (dict + "env" (list + .Values.defaults.env + ) + ) | nindent 10 }} ports: - containerPort: 8443 {{- include "cloudzero-agent.generateResources" (include "cloudzero-agent.mergeStringOverwrite" (list diff --git a/helm/tests/defaults_env_test.yaml b/helm/tests/defaults_env_test.yaml new file mode 100644 index 00000000..5b69e8a8 --- /dev/null +++ b/helm/tests/defaults_env_test.yaml @@ -0,0 +1,382 @@ +# Tests for `defaults.env` propagation and the `generateEnv` merge helper. +# +# `defaults.env` is the chart-wide env-injection mechanism. Behavior under +# test: +# +# 1. Every chart-managed container picks up every entry from +# `defaults.env`. There's no per-container opt-in/opt-out. +# +# 2. Entries are merged by `name` with a last-wins rule. `defaults.env` +# is the LOWEST-priority source — chart-emitted entries (validatorEnv, +# hardcoded SERVER_PORT/NODE_NAME/HOSTNAME fieldRefs) win over it, +# and component-specific user env (e.g. `.Values.server.env` on the +# Prometheus container) sits in between. +# +# 3. When `defaults.env` is unset (or empty), no env block is emitted on +# containers that have no other env sources — preserving the chart's +# "no env block when nothing to emit" default. +# +# 4. valueFrom entries are preserved as deep dicts (not flattened). +# +# The set of containers exercised here is intentionally broad — the helper +# refactor touches every container in the chart, so the propagation tests +# act as a guard against regressions where someone forgets to wire +# generateEnv into a new container. +suite: defaults.env propagation and generateEnv merge semantics +templates: + - templates/aggregator-deploy.yaml + - templates/agent-deploy.yaml + - templates/agent-daemonset.yaml + - templates/config-loader-job.yaml + - templates/webhook-deploy.yaml + - templates/backfill-job.yaml + - templates/helmless-job.yaml + - templates/init-cert-job.yaml +tests: + # ============================================================================ + # Baseline: no defaults.env, no other env source -> no env block emitted. + # ============================================================================ + - it: should emit no env block on containers with no other sources when defaults.env unset + asserts: + - isNull: + path: spec.template.spec.containers[0].env + template: templates/helmless-job.yaml + - isNull: + path: spec.template.spec.containers[0].env + template: templates/init-cert-job.yaml + - isNull: + path: spec.template.spec.containers[0].env + template: templates/webhook-deploy.yaml + - isNull: + path: spec.template.spec.containers[0].env + template: templates/backfill-job.yaml + documentIndex: 1 + - isNull: + # configmap-reload sidecar in agent-deploy + path: spec.template.spec.containers[0].env + template: templates/agent-deploy.yaml + + # ============================================================================ + # Propagation: a single defaults.env entry reaches every chart container. + # ============================================================================ + - it: should propagate defaults.env into the aggregator collector + shipper + set: + defaults.env: + - name: FOO + value: bar + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: FOO + value: bar + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[1].env + content: + name: FOO + value: bar + template: templates/aggregator-deploy.yaml + + - it: should propagate defaults.env into agent-deploy server-mode containers + set: + components.agent.mode: agent + defaults.env: + - name: FOO + value: bar + asserts: + # containers[0] = configmap-reload, containers[1] = prometheus-server + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/agent-deploy.yaml + - contains: + path: spec.template.spec.containers[1].env + content: { name: FOO, value: bar } + template: templates/agent-deploy.yaml + # initContainers[0] = validator-copy, [1] = validator-run + - contains: + path: spec.template.spec.initContainers[0].env + content: { name: FOO, value: bar } + template: templates/agent-deploy.yaml + - contains: + path: spec.template.spec.initContainers[1].env + content: { name: FOO, value: bar } + template: templates/agent-deploy.yaml + + - it: should propagate defaults.env into alloy in clustered mode + set: + components.agent.mode: clustered + defaults.env: + - name: FOO + value: bar + asserts: + # containers[1] = alloy in clustered mode + - contains: + path: spec.template.spec.containers[1].env + content: { name: FOO, value: bar } + template: templates/agent-deploy.yaml + + - it: should propagate defaults.env into agent-daemonset containers (federated mode) + set: + components.agent.mode: federated + defaults.env: + - name: FOO + value: bar + asserts: + - contains: + path: spec.template.spec.initContainers[0].env + content: { name: FOO, value: bar } + template: templates/agent-daemonset.yaml + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/agent-daemonset.yaml + - contains: + path: spec.template.spec.containers[1].env + content: { name: FOO, value: bar } + template: templates/agent-daemonset.yaml + + - it: should propagate defaults.env into config-loader, webhook, helmless, init-cert + set: + defaults.env: + - name: FOO + value: bar + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/config-loader-job.yaml + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/webhook-deploy.yaml + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/helmless-job.yaml + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/init-cert-job.yaml + # backfill-job ranges over [CronJob, Job]; documentIndex 0 is the + # CronJob (jobTemplate-nested spec) and 1 is the one-time Job (flat + # spec). Both should pick up defaults.env. + - contains: + path: spec.jobTemplate.spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/backfill-job.yaml + documentIndex: 0 + - contains: + path: spec.template.spec.containers[0].env + content: { name: FOO, value: bar } + template: templates/backfill-job.yaml + documentIndex: 1 + + # ============================================================================ + # Merge semantics: chart-emitted entries live alongside defaults.env. + # ============================================================================ + - it: should preserve chart-emitted SERVER_PORT alongside defaults.env on aggregator + set: + defaults.env: + - name: FOO + value: bar + asserts: + - contains: + path: spec.template.spec.containers[1].env + content: { name: SERVER_PORT, value: "8081" } + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[1].env + content: { name: FOO, value: bar } + template: templates/aggregator-deploy.yaml + + - it: should preserve chart-emitted validatorEnv alongside defaults.env on validator init + set: + components.agent.mode: agent + defaults.env: + - name: FOO + value: bar + asserts: + # K8S_POD_NAME uses a valueFrom fieldRef — pin the structure so we know + # the deep dict survives the merge unchanged. + - contains: + path: spec.template.spec.initContainers[1].env + content: + name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + template: templates/agent-deploy.yaml + - contains: + path: spec.template.spec.initContainers[1].env + content: { name: FOO, value: bar } + template: templates/agent-deploy.yaml + + # ============================================================================ + # Merge precedence — `defaults.env` is the LOWEST-priority source. + # Chart-emitted literals must win on collision (they're load-bearing). + # ============================================================================ + - it: should NOT let defaults.env override the chart-emitted SERVER_PORT literal + set: + defaults.env: + - name: SERVER_PORT + value: "9999" + asserts: + # collector's port is 8080, shipper's is 8081 — the chart values must + # win, not the user's defaults.env "9999". + - contains: + path: spec.template.spec.containers[0].env + content: { name: SERVER_PORT, value: "8080" } + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[1].env + content: { name: SERVER_PORT, value: "8081" } + template: templates/aggregator-deploy.yaml + - notContains: + path: spec.template.spec.containers[0].env + content: { name: SERVER_PORT, value: "9999" } + template: templates/aggregator-deploy.yaml + + # `.Values.server.env` is the middle tier — wins over defaults.env but + # still loses to chart-emitted entries. + - it: should let .Values.server.env override defaults.env on the prometheus-server container + set: + components.agent.mode: agent + defaults.env: + - name: SHARED + value: from-defaults + server.env: + - name: SHARED + value: from-server-env + asserts: + - contains: + path: spec.template.spec.containers[1].env + content: { name: SHARED, value: from-server-env } + template: templates/agent-deploy.yaml + # And the override is scoped to prometheus-server: other containers + # still see the defaults.env value. + - contains: + path: spec.template.spec.containers[0].env + content: { name: SHARED, value: from-defaults } + template: templates/aggregator-deploy.yaml + + # ============================================================================ + # valueFrom entries pass through intact. + # ============================================================================ + - it: should preserve valueFrom entries from defaults.env + set: + defaults.env: + - name: MY_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: MY_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + template: templates/webhook-deploy.yaml + + # ============================================================================ + # Realistic proxy-config use case. + # ============================================================================ + - it: should inject HTTPS_PROXY+NO_PROXY into every container when set via defaults.env + set: + defaults.env: + - name: HTTPS_PROXY + value: "http://proxy.example.com:8080" + - name: NO_PROXY + value: "localhost,127.0.0.1,.svc.cluster.local" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: { name: HTTPS_PROXY, value: "http://proxy.example.com:8080" } + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[1].env + content: { name: HTTPS_PROXY, value: "http://proxy.example.com:8080" } + template: templates/aggregator-deploy.yaml + - contains: + path: spec.template.spec.containers[0].env + content: { name: HTTPS_PROXY, value: "http://proxy.example.com:8080" } + template: templates/config-loader-job.yaml + - contains: + path: spec.template.spec.containers[0].env + content: { name: HTTPS_PROXY, value: "http://proxy.example.com:8080" } + template: templates/webhook-deploy.yaml + - contains: + path: spec.template.spec.containers[0].env + content: + { name: NO_PROXY, value: "localhost,127.0.0.1,.svc.cluster.local" } + template: templates/webhook-deploy.yaml + + # ============================================================================ + # Generic merge-helper edge cases. These pin behavior the helper docstring + # promises (`cloudzero-agent.generateEnv` in _helpers.tpl). + # ============================================================================ + - it: should always emit validatorEnv on prometheus-server even with empty server.env and defaults.env + set: + components.agent.mode: agent + asserts: + # containers[1] = prometheus-server in agent mode. validatorEnv must + # render unconditionally — the lifecycle hooks invoked by the + # prometheus-server container rely on K8S_NAMESPACE / K8S_POD_NAME. + - contains: + path: spec.template.spec.containers[1].env + content: + name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + template: templates/agent-deploy.yaml + + # NOTE: the "entries without a name are dropped" behavior the helper + # documents is unreachable through normal use — the values schema for + # `defaults.env` references `io.k8s.api.core.v1.EnvVar`, which requires + # `name` and rejects entries without it at chart-render time. The + # defensive check inside the helper is internal armor only. + + - it: should preserve first-source position when a later source overrides by name + set: + defaults.env: + - name: SERVER_PORT # collides with chart literal; defaults.env comes + value: "9999" # first in the source list, so position 0 is its + - name: SECOND # slot — but the chart literal's value wins. + value: two + asserts: + - equal: + path: spec.template.spec.containers[0].env[0].name + value: SERVER_PORT + template: templates/aggregator-deploy.yaml + - equal: + path: spec.template.spec.containers[0].env[0].value + value: "8080" # chart literal wins on value; collector port + template: templates/aggregator-deploy.yaml + + - it: should NOT let defaults.env override a validatorEnv-emitted variable + set: + components.agent.mode: agent + defaults.env: + - name: K8S_POD_NAME + value: from-defaults-env + asserts: + # K8S_POD_NAME is set via validatorEnv (fieldRef metadata.name) — that + # chart-emitted value must win over the user's defaults.env attempt. + - contains: + path: spec.template.spec.initContainers[1].env + content: + name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + template: templates/agent-deploy.yaml + - notContains: + path: spec.template.spec.initContainers[1].env + content: + name: K8S_POD_NAME + value: from-defaults-env + template: templates/agent-deploy.yaml diff --git a/helm/values.schema.json b/helm/values.schema.json index 0f8afc47..81e6318f 100644 --- a/helm/values.schema.json +++ b/helm/values.schema.json @@ -6488,6 +6488,12 @@ "dns": { "$ref": "#/$defs/com.cloudzero.agent.dns" }, + "env": { + "items": { + "$ref": "#/$defs/io.k8s.api.core.v1.EnvVar" + }, + "type": "array" + }, "federation": { "additionalProperties": false, "properties": { diff --git a/helm/values.schema.yaml b/helm/values.schema.yaml index 4e1ee8b4..cb3d5ca0 100644 --- a/helm/values.schema.yaml +++ b/helm/values.schema.yaml @@ -461,6 +461,16 @@ properties: description: | Annotations to be added to all resources. $ref: "#/$defs/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta/properties/annotations" + env: + description: | + Additional environment variables to inject into every container the + chart manages. Merged with the chart's per-container env on a + last-wins-by-name basis. Canonical knob for routing chart traffic + through an HTTP(S) proxy (set HTTP_PROXY / HTTPS_PROXY / NO_PROXY + here) — also usable for any other env var needed across the chart. + type: array + items: + $ref: "#/$defs/io.k8s.api.core.v1.EnvVar" affinity: description: | Affinity settings to be added to all resources. diff --git a/helm/values.yaml b/helm/values.yaml index 47e1ad8b..c2cef070 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -52,6 +52,26 @@ defaults: image: pullPolicy: IfNotPresent pullSecrets: + + # Additional environment variables to inject into every container the chart + # manages. Each entry follows the Kubernetes EnvVar schema — `name` plus + # either a literal `value` or a `valueFrom` (fieldRef, configMapKeyRef, + # secretKeyRef, etc.). See: + # https://kubernetes.io/docs/reference/kubernetes-api/core/pod-v1/#EnvVar + # + # `defaults.env` is the lowest-priority env source — chart-emitted entries + # (validatorEnv, hardcoded `HOSTNAME` / `NODE_NAME` / `SERVER_PORT` + # fieldRefs) and component-specific user env (e.g., `.Values.server.env` on + # the Prometheus container) override it on `name` collision. + # + # To route chart traffic through an HTTP(S) proxy, set HTTP_PROXY / + # HTTPS_PROXY / NO_PROXY here, see `helm/docs/egress-proxy.md` for the full + # walkthrough — what NO_PROXY must cover, per-cloud examples, and discovery + # commands. + # + # Default: [] (no extra env vars). + env: [] + # If set, these DNS settings will be attached to resources which support it. dns: # DNS policy to use on all pods. diff --git a/tests/helm/schema/defaults.env.invalid.fail.yaml b/tests/helm/schema/defaults.env.invalid.fail.yaml new file mode 100644 index 00000000..6b89696f --- /dev/null +++ b/tests/helm/schema/defaults.env.invalid.fail.yaml @@ -0,0 +1,3 @@ +# Test for invalid defaults.env (should fail) +defaults: + env: "not-an-array" # Should be array, not string diff --git a/tests/helm/schema/defaults.env.valid.pass.yaml b/tests/helm/schema/defaults.env.valid.pass.yaml new file mode 100644 index 00000000..3658e2dc --- /dev/null +++ b/tests/helm/schema/defaults.env.valid.pass.yaml @@ -0,0 +1,14 @@ +# Test for valid defaults.env +defaults: + env: + - name: "HTTPS_PROXY" + value: "http://proxy.example.com:8080" + - name: "MY_SECRET" + valueFrom: + secretKeyRef: + name: "my-secret" + key: "secret-key" + - name: "POD_NAME" + valueFrom: + fieldRef: + fieldPath: metadata.name diff --git a/tests/helm/template/alloy.yaml b/tests/helm/template/alloy.yaml index 8ed6edc7..ecff2208 100644 --- a/tests/helm/template/alloy.yaml +++ b/tests/helm/template/alloy.yaml @@ -1199,6 +1199,7 @@ data: dns: config: {} policy: null + env: [] image: pullPolicy: IfNotPresent pullSecrets: null @@ -2630,6 +2631,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2679,10 +2681,6 @@ spec: - --server.http.listen-addr=0.0.0.0:9090 - --storage.path=/tmp/alloy env: - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: metadata.name - name: K8S_NAMESPACE value: cz-agent - name: K8S_POD_NAME @@ -2697,6 +2695,10 @@ spec: valueFrom: fieldRef: fieldPath: metadata.labels['topology.istio.io/cluster'] + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name lifecycle: postStart: exec: @@ -3024,6 +3026,7 @@ spec: args: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" + ports: - containerPort: 8443 resources: @@ -3130,6 +3133,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m @@ -3338,6 +3342,7 @@ spec: - /etc/config/values/values.yaml - --output - "-" + resources: limits: cpu: 200m @@ -3404,6 +3409,7 @@ spec: imagePullPolicy: "IfNotPresent" command: ["/app/cloudzero-certifik8s"] workingDir: /var/tmp + resources: limits: cpu: 200m @@ -3481,6 +3487,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m diff --git a/tests/helm/template/cert-manager.yaml b/tests/helm/template/cert-manager.yaml index ded942b3..f5eb8765 100644 --- a/tests/helm/template/cert-manager.yaml +++ b/tests/helm/template/cert-manager.yaml @@ -1114,6 +1114,7 @@ data: dns: config: {} policy: null + env: [] image: pullPolicy: IfNotPresent pullSecrets: null @@ -2545,6 +2546,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2586,6 +2588,21 @@ spec: - name: cloudzero-agent-server image: "quay.io/prometheus/prometheus:v3.10.0-distroless" imagePullPolicy: "IfNotPresent" + env: + - name: K8S_NAMESPACE + value: cz-agent + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_AMBIENT_REDIRECTION + valueFrom: + fieldRef: + fieldPath: metadata.annotations['ambient.istio.io/redirection'] + - name: ISTIO_TOPOLOGY_CLUSTER + valueFrom: + fieldRef: + fieldPath: metadata.labels['topology.istio.io/cluster'] lifecycle: postStart: exec: @@ -2918,6 +2935,7 @@ spec: args: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" + ports: - containerPort: 8443 resources: @@ -3024,6 +3042,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m @@ -3232,6 +3251,7 @@ spec: - /etc/config/values/values.yaml - --output - "-" + resources: limits: cpu: 200m @@ -3310,6 +3330,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m diff --git a/tests/helm/template/federated.yaml b/tests/helm/template/federated.yaml index 3bf4a278..7a38a0fe 100644 --- a/tests/helm/template/federated.yaml +++ b/tests/helm/template/federated.yaml @@ -1202,6 +1202,7 @@ data: dns: config: {} policy: null + env: [] image: pullPolicy: IfNotPresent pullSecrets: null @@ -2485,6 +2486,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2828,6 +2830,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2869,6 +2872,21 @@ spec: - name: cloudzero-agent-server image: "quay.io/prometheus/prometheus:v3.10.0-distroless" imagePullPolicy: "IfNotPresent" + env: + - name: K8S_NAMESPACE + value: cz-agent + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_AMBIENT_REDIRECTION + valueFrom: + fieldRef: + fieldPath: metadata.annotations['ambient.istio.io/redirection'] + - name: ISTIO_TOPOLOGY_CLUSTER + valueFrom: + fieldRef: + fieldPath: metadata.labels['topology.istio.io/cluster'] lifecycle: postStart: exec: @@ -3201,6 +3219,7 @@ spec: args: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" + ports: - containerPort: 8443 resources: @@ -3307,6 +3326,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m @@ -3515,6 +3535,7 @@ spec: - /etc/config/values/values.yaml - --output - "-" + resources: limits: cpu: 200m @@ -3581,6 +3602,7 @@ spec: imagePullPolicy: "IfNotPresent" command: ["/app/cloudzero-certifik8s"] workingDir: /var/tmp + resources: limits: cpu: 200m @@ -3658,6 +3680,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m diff --git a/tests/helm/template/istio.yaml b/tests/helm/template/istio.yaml index df4965bf..888ccf48 100644 --- a/tests/helm/template/istio.yaml +++ b/tests/helm/template/istio.yaml @@ -1129,6 +1129,7 @@ data: dns: config: {} policy: null + env: [] image: pullPolicy: IfNotPresent pullSecrets: null @@ -2560,6 +2561,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2601,6 +2603,21 @@ spec: - name: cloudzero-agent-server image: "quay.io/prometheus/prometheus:v3.10.0-distroless" imagePullPolicy: "IfNotPresent" + env: + - name: K8S_NAMESPACE + value: cz-agent + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_AMBIENT_REDIRECTION + valueFrom: + fieldRef: + fieldPath: metadata.annotations['ambient.istio.io/redirection'] + - name: ISTIO_TOPOLOGY_CLUSTER + valueFrom: + fieldRef: + fieldPath: metadata.labels['topology.istio.io/cluster'] lifecycle: postStart: exec: @@ -2934,6 +2951,7 @@ spec: args: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" + ports: - containerPort: 8443 resources: @@ -3041,6 +3059,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m @@ -3249,6 +3268,7 @@ spec: - /etc/config/values/values.yaml - --output - "-" + resources: limits: cpu: 200m @@ -3315,6 +3335,7 @@ spec: imagePullPolicy: "IfNotPresent" command: ["/app/cloudzero-certifik8s"] workingDir: /var/tmp + resources: limits: cpu: 200m @@ -3393,6 +3414,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m diff --git a/tests/helm/template/kubestate.yaml b/tests/helm/template/kubestate.yaml index 57b6e7ba..24fe0cac 100644 --- a/tests/helm/template/kubestate.yaml +++ b/tests/helm/template/kubestate.yaml @@ -1166,6 +1166,7 @@ data: dns: config: {} policy: null + env: [] image: pullPolicy: IfNotPresent pullSecrets: null @@ -2079,6 +2080,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2129,10 +2131,6 @@ spec: - --storage.path=/tmp/alloy - --stability.level=public-preview env: - - name: HOSTNAME - valueFrom: - fieldRef: - fieldPath: metadata.name - name: K8S_NAMESPACE value: cz-agent - name: K8S_POD_NAME @@ -2147,6 +2145,10 @@ spec: valueFrom: fieldRef: fieldPath: metadata.labels['topology.istio.io/cluster'] + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name lifecycle: postStart: exec: @@ -2474,6 +2476,7 @@ spec: args: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" + ports: - containerPort: 8443 resources: @@ -2580,6 +2583,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m @@ -2788,6 +2792,7 @@ spec: - /etc/config/values/values.yaml - --output - "-" + resources: limits: cpu: 200m @@ -2854,6 +2859,7 @@ spec: imagePullPolicy: "IfNotPresent" command: ["/app/cloudzero-certifik8s"] workingDir: /var/tmp + resources: limits: cpu: 200m @@ -2931,6 +2937,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m diff --git a/tests/helm/template/manifest.yaml b/tests/helm/template/manifest.yaml index 16ef82b4..b5ebe460 100644 --- a/tests/helm/template/manifest.yaml +++ b/tests/helm/template/manifest.yaml @@ -1129,6 +1129,7 @@ data: dns: config: {} policy: null + env: [] image: pullPolicy: IfNotPresent pullSecrets: null @@ -2560,6 +2561,7 @@ spec: - --watched-dir=/etc/config - --reload-url=http://127.0.0.1:9090/-/reload - --listen-address=:8080 + ports: - containerPort: 8080 livenessProbe: @@ -2601,6 +2603,21 @@ spec: - name: cloudzero-agent-server image: "quay.io/prometheus/prometheus:v3.10.0-distroless" imagePullPolicy: "IfNotPresent" + env: + - name: K8S_NAMESPACE + value: cz-agent + - name: K8S_POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: ISTIO_AMBIENT_REDIRECTION + valueFrom: + fieldRef: + fieldPath: metadata.annotations['ambient.istio.io/redirection'] + - name: ISTIO_TOPOLOGY_CLUSTER + valueFrom: + fieldRef: + fieldPath: metadata.labels['topology.istio.io/cluster'] lifecycle: postStart: exec: @@ -2933,6 +2950,7 @@ spec: args: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" + ports: - containerPort: 8443 resources: @@ -3039,6 +3057,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m @@ -3247,6 +3266,7 @@ spec: - /etc/config/values/values.yaml - --output - "-" + resources: limits: cpu: 200m @@ -3313,6 +3333,7 @@ spec: imagePullPolicy: "IfNotPresent" command: ["/app/cloudzero-certifik8s"] workingDir: /var/tmp + resources: limits: cpu: 200m @@ -3390,6 +3411,7 @@ spec: - -config - "/etc/cloudzero-agent-insights/server-config.yaml" - -backfill + resources: limits: cpu: 500m