Skip to content

Commit 85fd592

Browse files
committed
fix(cozy-lib): make the cozyconfig helpers survive uninjected values
`_cluster` and `_namespace` reach a chart through valuesFrom on the cozystack-values Secret, so they are absent whenever a chart is rendered on its own: `helm lint`, a plain `helm template`, and any helm-unittest suite that does not set them. Twelve of the helpers in _cozyconfig.tpl read straight through the missing map and abort the render rather than returning their documented empty default. Two spellings, one cause. `index .Values._cluster "root-host"` raises `index of untyped nil`, and `.Values._namespace.host` raises `nil pointer evaluating interface {}.host`. In both cases the trailing `| default ""` never runs: it applies to the result, and there is no result, only an error. That default covered a key missing from a map that exists, never a missing map. Guard the map instead, which is what `cozy-lib.images-registry` in this same file already did: (index (.Values._cluster | default dict) "root-host") | default "" `index` on an empty map returns nil harmlessly, so the trailing default applies as it always read. With the map present, `| default dict` returns it untouched. This changes no rendered output. Every one of the 34 charts that symlink cozy-lib was rendered before and after, both with the injected values populated and with them set to empty maps, and every result is byte-identical. Eight charts differ between any two runs because they generate passwords; rendering the unchanged tree twice reproduces exactly those eight, which is how they are excluded. What this does not do is fix a chart that fails today. The charts that cannot render standalone read the injected values directly in their own templates rather than through these helpers, so they are unaffected by a change to the library and are being addressed where they live. Twelve of the thirteen helpers here have no callers anywhere in packages/ at present; only `cozy-lib.images-registry` is reached, from `cozy-lib.image`, and it was already guarded. The guard is still worth having on the rest: they are the library's public surface, they are what a chart author copies when reaching for cluster configuration, and the broken spelling propagates by being read. `cozy-lib.image` is called from four templates, so these helpers do get adopted once they exist. Add a suite in cozy-lib-tests, which is where library behaviour is pinned because a library chart renders nothing of its own. One case covers the uninjected state, which needs no mocking since neither key is in values.yaml, and one covers the injected state so the guard cannot quietly change what a populated map returns. The injected case includes `scheduling` and `branding` specifically: those two are the helpers whose body was restructured rather than wrapped, so they are the ones whose present-map behaviour most needs pinning. Against the unguarded helpers the first case fails with `index of untyped nil`. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
1 parent 605030b commit 85fd592

3 files changed

Lines changed: 115 additions & 14 deletions

File tree

‎packages/library/cozy-lib/templates/_cozyconfig.tpl‎

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ Get the root host for the cluster.
88
Usage: {{ include "cozy-lib.root-host" . }}
99
*/}}
1010
{{- define "cozy-lib.root-host" -}}
11-
{{- (index .Values._cluster "root-host") | default "" }}
11+
{{- (index (.Values._cluster | default dict) "root-host") | default "" }}
1212
{{- end }}
1313

1414
{{/*
1515
Get the bundle name for the cluster.
1616
Usage: {{ include "cozy-lib.bundle-name" . }}
1717
*/}}
1818
{{- define "cozy-lib.bundle-name" -}}
19-
{{- (index .Values._cluster "bundle-name") | default "" }}
19+
{{- (index (.Values._cluster | default dict) "bundle-name") | default "" }}
2020
{{- end }}
2121

2222
{{/*
@@ -53,23 +53,23 @@ Get the ipv4 cluster CIDR.
5353
Usage: {{ include "cozy-lib.ipv4-cluster-cidr" . }}
5454
*/}}
5555
{{- define "cozy-lib.ipv4-cluster-cidr" -}}
56-
{{- (index .Values._cluster "ipv4-cluster-cidr") | default "" }}
56+
{{- (index (.Values._cluster | default dict) "ipv4-cluster-cidr") | default "" }}
5757
{{- end }}
5858

5959
{{/*
6060
Get the ipv4 service CIDR.
6161
Usage: {{ include "cozy-lib.ipv4-service-cidr" . }}
6262
*/}}
6363
{{- define "cozy-lib.ipv4-service-cidr" -}}
64-
{{- (index .Values._cluster "ipv4-service-cidr") | default "" }}
64+
{{- (index (.Values._cluster | default dict) "ipv4-service-cidr") | default "" }}
6565
{{- end }}
6666

6767
{{/*
6868
Get the ipv4 join CIDR.
6969
Usage: {{ include "cozy-lib.ipv4-join-cidr" . }}
7070
*/}}
7171
{{- define "cozy-lib.ipv4-join-cidr" -}}
72-
{{- (index .Values._cluster "ipv4-join-cidr") | default "" }}
72+
{{- (index (.Values._cluster | default dict) "ipv4-join-cidr") | default "" }}
7373
{{- end }}
7474

7575
{{/*
@@ -78,8 +78,9 @@ Usage: {{ include "cozy-lib.scheduling" . }}
7878
Returns: YAML string of scheduling configuration
7979
*/}}
8080
{{- define "cozy-lib.scheduling" -}}
81-
{{- if .Values._cluster.scheduling }}
82-
{{- .Values._cluster.scheduling | toYaml }}
81+
{{- $scheduling := (.Values._cluster | default dict).scheduling }}
82+
{{- if $scheduling }}
83+
{{- $scheduling | toYaml }}
8384
{{- end }}
8485
{{- end }}
8586

@@ -89,8 +90,9 @@ Usage: {{ include "cozy-lib.branding" . }}
8990
Returns: YAML string of branding configuration
9091
*/}}
9192
{{- define "cozy-lib.branding" -}}
92-
{{- if .Values._cluster.branding }}
93-
{{- .Values._cluster.branding | toYaml }}
93+
{{- $branding := (.Values._cluster | default dict).branding }}
94+
{{- if $branding }}
95+
{{- $branding | toYaml }}
9496
{{- end }}
9597
{{- end }}
9698

@@ -104,39 +106,39 @@ Get the host for this namespace.
104106
Usage: {{ include "cozy-lib.ns-host" . }}
105107
*/}}
106108
{{- define "cozy-lib.ns-host" -}}
107-
{{- .Values._namespace.host | default "" }}
109+
{{- (.Values._namespace | default dict).host | default "" }}
108110
{{- end }}
109111

110112
{{/*
111113
Get the etcd namespace reference.
112114
Usage: {{ include "cozy-lib.ns-etcd" . }}
113115
*/}}
114116
{{- define "cozy-lib.ns-etcd" -}}
115-
{{- .Values._namespace.etcd | default "" }}
117+
{{- (.Values._namespace | default dict).etcd | default "" }}
116118
{{- end }}
117119

118120
{{/*
119121
Get the ingress namespace reference.
120122
Usage: {{ include "cozy-lib.ns-ingress" . }}
121123
*/}}
122124
{{- define "cozy-lib.ns-ingress" -}}
123-
{{- .Values._namespace.ingress | default "" }}
125+
{{- (.Values._namespace | default dict).ingress | default "" }}
124126
{{- end }}
125127

126128
{{/*
127129
Get the monitoring namespace reference.
128130
Usage: {{ include "cozy-lib.ns-monitoring" . }}
129131
*/}}
130132
{{- define "cozy-lib.ns-monitoring" -}}
131-
{{- .Values._namespace.monitoring | default "" }}
133+
{{- (.Values._namespace | default dict).monitoring | default "" }}
132134
{{- end }}
133135

134136
{{/*
135137
Get the seaweedfs namespace reference.
136138
Usage: {{ include "cozy-lib.ns-seaweedfs" . }}
137139
*/}}
138140
{{- define "cozy-lib.ns-seaweedfs" -}}
139-
{{- .Values._namespace.seaweedfs | default "" }}
141+
{{- (.Values._namespace | default dict).seaweedfs | default "" }}
140142
{{- end }}
141143

142144
{{/*
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
name: {{ .Release.Name }}-cozyconfig
5+
data:
6+
root-host: {{ include "cozy-lib.root-host" . | quote }}
7+
bundle-name: {{ include "cozy-lib.bundle-name" . | quote }}
8+
images-registry: {{ include "cozy-lib.images-registry" . | quote }}
9+
ipv4-cluster-cidr: {{ include "cozy-lib.ipv4-cluster-cidr" . | quote }}
10+
ipv4-service-cidr: {{ include "cozy-lib.ipv4-service-cidr" . | quote }}
11+
ipv4-join-cidr: {{ include "cozy-lib.ipv4-join-cidr" . | quote }}
12+
scheduling: {{ include "cozy-lib.scheduling" . | quote }}
13+
branding: {{ include "cozy-lib.branding" . | quote }}
14+
ns-host: {{ include "cozy-lib.ns-host" . | quote }}
15+
ns-etcd: {{ include "cozy-lib.ns-etcd" . | quote }}
16+
ns-ingress: {{ include "cozy-lib.ns-ingress" . | quote }}
17+
ns-monitoring: {{ include "cozy-lib.ns-monitoring" . | quote }}
18+
ns-seaweedfs: {{ include "cozy-lib.ns-seaweedfs" . | quote }}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# ./tests/cozyconfig_test.yaml
2+
suite: cozyconfig helpers survive an uninjected _cluster and _namespace
3+
4+
templates:
5+
- templates/tests/cozyconfig.yaml
6+
7+
# `_cluster` and `_namespace` are injected by the platform through valuesFrom on
8+
# the cozystack-values Secret. A chart rendered on its own therefore has neither,
9+
# which is the state of `helm lint`, a plain `helm template`, and any suite that
10+
# does not set them. These helpers must degrade to their empty defaults there
11+
# rather than abort the render, because every consumer of this library inherits
12+
# whatever they do.
13+
14+
tests:
15+
- it: returns empty defaults when the platform injected nothing
16+
# No `set:` at all: this is the uninjected state, and it needs no mocking.
17+
asserts:
18+
- equal: {path: 'data["root-host"]', value: ""}
19+
- equal: {path: 'data["bundle-name"]', value: ""}
20+
- equal: {path: 'data["images-registry"]', value: ""}
21+
- equal: {path: 'data["ipv4-cluster-cidr"]', value: ""}
22+
- equal: {path: 'data["ipv4-service-cidr"]', value: ""}
23+
- equal: {path: 'data["ipv4-join-cidr"]', value: ""}
24+
- equal: {path: 'data["scheduling"]', value: ""}
25+
- equal: {path: 'data["branding"]', value: ""}
26+
- equal: {path: 'data["ns-host"]', value: ""}
27+
- equal: {path: 'data["ns-etcd"]', value: ""}
28+
- equal: {path: 'data["ns-ingress"]', value: ""}
29+
- equal: {path: 'data["ns-monitoring"]', value: ""}
30+
- equal: {path: 'data["ns-seaweedfs"]', value: ""}
31+
32+
- it: returns the injected values unchanged when the platform did inject them
33+
# The other half of the guard: making the helpers survive an absent map must
34+
# not change what they return when the map is present.
35+
set:
36+
_cluster:
37+
root-host: example.com
38+
bundle-name: paas-full
39+
images-registry: registry.example.com
40+
ipv4-cluster-cidr: 10.244.0.0/16
41+
ipv4-service-cidr: 10.96.0.0/16
42+
ipv4-join-cidr: 100.64.0.0/16
43+
scheduling:
44+
nodeSelector:
45+
node-role.kubernetes.io/worker: ""
46+
branding:
47+
logo:
48+
light: /logos/light.svg
49+
_namespace:
50+
host: tenant.example.com
51+
etcd: etcd-ns
52+
ingress: ingress-ns
53+
monitoring: monitoring-ns
54+
seaweedfs: seaweedfs-ns
55+
asserts:
56+
- equal: {path: 'data["root-host"]', value: "example.com"}
57+
- equal: {path: 'data["bundle-name"]', value: "paas-full"}
58+
- equal: {path: 'data["images-registry"]', value: "registry.example.com"}
59+
- equal: {path: 'data["ipv4-cluster-cidr"]', value: "10.244.0.0/16"}
60+
- equal: {path: 'data["ipv4-service-cidr"]', value: "10.96.0.0/16"}
61+
- equal: {path: 'data["ipv4-join-cidr"]', value: "100.64.0.0/16"}
62+
- equal: {path: 'data["ns-host"]', value: "tenant.example.com"}
63+
- equal: {path: 'data["ns-etcd"]', value: "etcd-ns"}
64+
- equal: {path: 'data["ns-ingress"]', value: "ingress-ns"}
65+
- equal: {path: 'data["ns-monitoring"]', value: "monitoring-ns"}
66+
- equal: {path: 'data["ns-seaweedfs"]', value: "seaweedfs-ns"}
67+
# scheduling and branding are the two helpers whose body was rewritten
68+
# rather than wrapped, so they need the present-map half most. Their
69+
# value is a whole YAML document, and it is pinned as one: a substring
70+
# match here would survive the loss of the `toYaml` that produces it,
71+
# because the key name also appears in Go's default map formatting.
72+
- equal:
73+
path: 'data["scheduling"]'
74+
value: |-
75+
nodeSelector:
76+
node-role.kubernetes.io/worker: ""
77+
- equal:
78+
path: 'data["branding"]'
79+
value: |-
80+
logo:
81+
light: /logos/light.svg

0 commit comments

Comments
 (0)