diff --git a/client/templates/jobs-manager-deployment.yaml b/client/templates/jobs-manager-deployment.yaml index adc5f8e..054a0b0 100644 --- a/client/templates/jobs-manager-deployment.yaml +++ b/client/templates/jobs-manager-deployment.yaml @@ -1,3 +1,5 @@ +{{- /* #229: these env keys are owned by tracebloc.proxyEnv, which emits HTTP(S)_PROXY and a merged, cluster-safe NO_PROXY. Exclude them from the generic .Values.env passthrough below so a user-set NO_PROXY (or proxy var) is not re-emitted UNMERGED after proxyEnv — Kubernetes keeps the LAST duplicate env, which would drop the cluster-internal NO_PROXY entries and route in-cluster traffic through the proxy. */ -}} +{{- $proxyKeys := list "HTTP_PROXY_HOST" "HTTP_PROXY_PORT" "HTTP_PROXY_USERNAME" "HTTP_PROXY_PASSWORD" "NO_PROXY" "no_proxy" "HTTP_PROXY" "HTTPS_PROXY" "http_proxy" "https_proxy" -}} apiVersion: apps/v1 kind: Deployment metadata: @@ -149,7 +151,7 @@ spec: - name: SINGLE_NODE value: {{ if hasKey .Values.env "SINGLE_NODE" }}{{ .Values.env.SINGLE_NODE | quote }}{{ else }}{{ (default dict .Values.hostPath).enabled | default false | quote }}{{ end }} {{- range $key, $value := .Values.env }} - {{- if and (ne $key "CLIENT_ENV") (ne $key "RESOURCE_REQUESTS") (ne $key "RESOURCE_LIMITS") (ne $key "GPU_REQUESTS") (ne $key "GPU_LIMITS") (ne $key "RUNTIME_CLASS_NAME") (ne $key "SINGLE_NODE") (ne $key "CLIENT_ID") $value }} + {{- if and (ne $key "CLIENT_ENV") (ne $key "RESOURCE_REQUESTS") (ne $key "RESOURCE_LIMITS") (ne $key "GPU_REQUESTS") (ne $key "GPU_LIMITS") (ne $key "RUNTIME_CLASS_NAME") (ne $key "SINGLE_NODE") (ne $key "CLIENT_ID") (not (has $key $proxyKeys)) $value }} - name: {{ $key }} value: {{ $value | quote }} {{- end }} @@ -206,7 +208,7 @@ spec: - name: SINGLE_NODE value: {{ if hasKey .Values.env "SINGLE_NODE" }}{{ .Values.env.SINGLE_NODE | quote }}{{ else }}{{ (default dict .Values.hostPath).enabled | default false | quote }}{{ end }} {{- range $key, $value := .Values.env }} - {{- if and (ne $key "CLIENT_ENV") (ne $key "RESOURCE_REQUESTS") (ne $key "RESOURCE_LIMITS") (ne $key "GPU_REQUESTS") (ne $key "GPU_LIMITS") (ne $key "RUNTIME_CLASS_NAME") (ne $key "SINGLE_NODE") (ne $key "CLIENT_ID") $value }} + {{- if and (ne $key "CLIENT_ENV") (ne $key "RESOURCE_REQUESTS") (ne $key "RESOURCE_LIMITS") (ne $key "GPU_REQUESTS") (ne $key "GPU_LIMITS") (ne $key "RUNTIME_CLASS_NAME") (ne $key "SINGLE_NODE") (ne $key "CLIENT_ID") (not (has $key $proxyKeys)) $value }} - name: {{ $key }} value: {{ $value | quote }} {{- end }} diff --git a/client/tests/proxy_env_test.yaml b/client/tests/proxy_env_test.yaml index d24e02b..ba16e3c 100644 --- a/client/tests/proxy_env_test.yaml +++ b/client/tests/proxy_env_test.yaml @@ -95,3 +95,27 @@ tests: - contains: path: spec.template.spec.containers[0].env content: {name: HTTP_PROXY, value: "http://bob:pw@proxy.example.com:8080"} + # ===== #229 regression: a custom NO_PROXY must not be re-emitted UNMERGED ===== + # tracebloc.proxyEnv merges the user's NO_PROXY with the cluster-internal + # defaults. The generic .Values.env passthrough must NOT re-emit the bare + # user value afterwards — k8s keeps the LAST duplicate env, so an unmerged + # copy would win and route in-cluster traffic (mysql, requests-proxy) through + # the proxy. Guards both jobs-manager containers (api + pods-monitor). + - it: a custom NO_PROXY is merged once, never re-emitted unmerged (jobs-manager) + template: templates/jobs-manager-deployment.yaml + set: {env.HTTP_PROXY_HOST: proxy.example.com, env.HTTP_PROXY_PORT: "8080", env.NO_PROXY: "myinternal.example"} + asserts: + # api container: only the merged value (custom + cluster-internal) is present + - contains: + path: spec.template.spec.containers[0].env + content: {name: NO_PROXY, value: "myinternal.example,localhost,127.0.0.1,0.0.0.0,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.svc.cluster.local,.cluster.local,host.k3d.internal"} + - notContains: + path: spec.template.spec.containers[0].env + content: {name: NO_PROXY, value: "myinternal.example"} + # pods-monitor container: same guarantee + - contains: + path: spec.template.spec.containers[1].env + content: {name: NO_PROXY, value: "myinternal.example,localhost,127.0.0.1,0.0.0.0,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,.svc,.svc.cluster.local,.cluster.local,host.k3d.internal"} + - notContains: + path: spec.template.spec.containers[1].env + content: {name: NO_PROXY, value: "myinternal.example"}