1 package cmd
2
3 import (
4 "bytes"
5 "path/filepath"
6 "testing"
7
8 "github.com/linkerd/linkerd2/pkg/charts"
9 l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2"
10 "github.com/linkerd/linkerd2/pkg/charts/static"
11 "github.com/linkerd/linkerd2/pkg/k8s"
12 "github.com/linkerd/linkerd2/testutil"
13 "helm.sh/helm/v3/pkg/chart"
14 "helm.sh/helm/v3/pkg/chart/loader"
15 "helm.sh/helm/v3/pkg/chartutil"
16 "helm.sh/helm/v3/pkg/engine"
17 "sigs.k8s.io/yaml"
18 )
19
20 func TestRenderHelm(t *testing.T) {
21
22
23
24 t.Run("Non-HA mode", func(t *testing.T) {
25 chartCrds := chartCrds(t)
26 chartControlPlane := chartControlPlane(t, false, "", "111", "222")
27 testRenderHelm(t, chartCrds, "install_helm_crds_output.golden")
28 testRenderHelm(t, chartControlPlane, "install_helm_control_plane_output.golden")
29 })
30
31 t.Run("HA mode", func(t *testing.T) {
32 chartCrds := chartCrds(t)
33 chartControlPlane := chartControlPlane(t, true, "", "111", "222")
34 testRenderHelm(t, chartCrds, "install_helm_crds_output_ha.golden")
35 testRenderHelm(t, chartControlPlane, "install_helm_control_plane_output_ha.golden")
36 })
37
38 t.Run("HA mode with GID", func(t *testing.T) {
39 additionalConfig := `
40 controllerGID: 1324
41 proxy:
42 gid: 4231
43 `
44 chartControlPlane := chartControlPlane(t, true, additionalConfig, "111", "222")
45 testRenderHelm(t, chartControlPlane, "install_helm_control_plane_output_ha_with_gid.golden")
46 })
47
48 t.Run("HA mode with podLabels and podAnnotations", func(t *testing.T) {
49 additionalConfig := `
50 podLabels:
51 foo: bar
52 fiz: buz
53 podAnnotations:
54 bingo: bongo
55 asda: fasda
56 `
57 chartControlPlane := chartControlPlane(t, true, additionalConfig, "333", "444")
58 testRenderHelm(t, chartControlPlane, "install_helm_output_ha_labels.golden")
59 })
60
61 t.Run("HA mode with custom namespaceSelector", func(t *testing.T) {
62 additionalConfig := `
63 proxyInjector:
64 namespaceSelector:
65 matchExpressions:
66 - key: config.linkerd.io/admission-webhooks
67 operator: In
68 values:
69 - enabled
70 profileValidator:
71 namespaceSelector:
72 matchExpressions:
73 - key: config.linkerd.io/admission-webhooks
74 operator: In
75 values:
76 - enabled
77 `
78 chartControlPlane := chartControlPlane(t, true, additionalConfig, "111", "222")
79 testRenderHelm(t, chartControlPlane, "install_helm_output_ha_namespace_selector.golden")
80 })
81 }
82
83 func testRenderHelm(t *testing.T, linkerd2Chart *chart.Chart, goldenFileName string) {
84 var (
85 chartName = "linkerd2"
86 namespace = "linkerd-dev"
87 )
88
89
90 overrideJSON := `{
91 "cliVersion":"",
92 "linkerdVersion":"linkerd-version",
93 "identityTrustAnchorsPEM":"test-trust-anchor",
94 "identityTrustDomain":"test.trust.domain",
95 "proxy":{
96 "image":{
97 "version":"test-proxy-version"
98 }
99 },
100 "proxyInit":{
101 "image":{
102 "version":"test-proxy-init-version"
103 }
104 },
105 "identity":{
106 "issuer":{
107 "tls":{
108 "keyPEM":"test-key-pem",
109 "crtPEM":"test-crt-pem"
110 }
111 }
112 },
113 "configs": null,
114 "debugContainer":{
115 "image":{
116 "version":"test-debug-version"
117 }
118 },
119 "proxyInjector":{
120 "externalSecret": true,
121 "caBundle":"test-proxy-injector-ca-bundle"
122 },
123 "profileValidator":{
124 "externalSecret": true,
125 "caBundle":"test-profile-validator-ca-bundle"
126 },
127 "policyValidator":{
128 "externalSecret": true,
129 "caBundle":"test-profile-validator-ca-bundle"
130 },
131 "tap":{
132 "externalSecret": true,
133 "caBundle":"test-tap-ca-bundle"
134 }
135 }`
136
137 var overrideConfig chartutil.Values
138 err := yaml.Unmarshal([]byte(overrideJSON), &overrideConfig)
139 if err != nil {
140 t.Fatal("Unexpected error", err)
141 }
142
143 releaseOptions := chartutil.ReleaseOptions{
144 Name: chartName,
145 Namespace: namespace,
146 IsUpgrade: false,
147 IsInstall: true,
148 }
149
150 valuesToRender, err := chartutil.ToRenderValues(linkerd2Chart, overrideConfig, releaseOptions, nil)
151 if err != nil {
152 t.Fatal("Unexpected error", err)
153 }
154
155 rendered, err := engine.Render(linkerd2Chart, valuesToRender)
156 if err != nil {
157 t.Fatal("Unexpected error", err)
158 }
159
160 var buf bytes.Buffer
161 for _, template := range linkerd2Chart.Templates {
162 source := linkerd2Chart.Metadata.Name + "/" + template.Name
163 v, exists := rendered[source]
164 if !exists {
165
166 continue
167 }
168 buf.WriteString("---\n# Source: " + source + "\n")
169 buf.WriteString(v)
170 }
171
172 for _, dep := range linkerd2Chart.Dependencies() {
173 for _, template := range dep.Templates {
174 source := linkerd2Chart.Metadata.Name + "/charts" + "/" + dep.Metadata.Name + "/" + template.Name
175 v, exists := rendered[source]
176 if !exists {
177
178 continue
179 }
180 buf.WriteString("---\n# Source: " + source + "\n")
181 buf.WriteString(v)
182 }
183 }
184
185 if err := testDataDiffer.DiffTestYAML(goldenFileName, buf.String()); err != nil {
186 t.Error(err)
187 }
188 }
189
190 func chartCrds(t *testing.T) *chart.Chart {
191 partialPaths := []string{
192 "templates/_proxy.tpl",
193 "templates/_proxy-init.tpl",
194 "templates/_volumes.tpl",
195 "templates/_resources.tpl",
196 "templates/_metadata.tpl",
197 "templates/_debug.tpl",
198 "templates/_trace.tpl",
199 "templates/_capabilities.tpl",
200 "templates/_affinity.tpl",
201 "templates/_nodeselector.tpl",
202 "templates/_tolerations.tpl",
203 "templates/_validate.tpl",
204 "templates/_pull-secrets.tpl",
205 }
206
207 chartPartials := chartPartials(partialPaths)
208
209
210 valuesFile := &loader.BufferedFile{Name: l5dcharts.HelmChartDirCrds + "/values.yaml"}
211 if err := charts.ReadFile(static.Templates, "/", valuesFile); err != nil {
212 t.Fatal(err)
213 }
214 defaultValues := make(map[string]interface{})
215 err := yaml.Unmarshal(valuesFile.Data, &defaultValues)
216 if err != nil {
217 t.Fatal(err)
218 }
219 defaultValues["cliVersion"] = k8s.CreatedByAnnotationValue()
220
221 linkerd2Chart := &chart.Chart{
222 Metadata: &chart.Metadata{
223 Name: helmDefaultChartNameCrds,
224 Sources: []string{
225 filepath.Join("..", "..", "..", "charts", "linkerd-crds"),
226 },
227 },
228 Values: defaultValues,
229 }
230
231 linkerd2Chart.AddDependency(chartPartials)
232
233 for _, filepath := range TemplatesCrdFiles {
234 linkerd2Chart.Templates = append(linkerd2Chart.Templates, &chart.File{
235 Name: filepath,
236 })
237 }
238
239 for _, template := range linkerd2Chart.Templates {
240 filepath := filepath.Join(linkerd2Chart.Metadata.Sources[0], template.Name)
241 template.Data = []byte(testutil.ReadTestdata(filepath))
242 }
243
244 return linkerd2Chart
245 }
246
247 func chartControlPlane(t *testing.T, ha bool, additionalConfig string, ignoreOutboundPorts string, ignoreInboundPorts string) *chart.Chart {
248 values, err := readTestValues(ha, ignoreOutboundPorts, ignoreInboundPorts)
249 if err != nil {
250 t.Fatal("Unexpected error", err)
251 }
252
253 if additionalConfig != "" {
254 err := yaml.Unmarshal([]byte(additionalConfig), values)
255 if err != nil {
256 t.Fatal("Unexpected error", err)
257 }
258 }
259
260 partialPaths := []string{
261 "templates/_proxy.tpl",
262 "templates/_proxy-init.tpl",
263 "templates/_volumes.tpl",
264 "templates/_resources.tpl",
265 "templates/_metadata.tpl",
266 "templates/_debug.tpl",
267 "templates/_trace.tpl",
268 "templates/_capabilities.tpl",
269 "templates/_affinity.tpl",
270 "templates/_nodeselector.tpl",
271 "templates/_tolerations.tpl",
272 "templates/_validate.tpl",
273 "templates/_pull-secrets.tpl",
274 }
275
276 chartPartials := chartPartials(partialPaths)
277
278 rawValues, err := yaml.Marshal(values)
279 if err != nil {
280 t.Fatal("Unexpected error", err)
281 }
282
283 var mapValues chartutil.Values
284 err = yaml.Unmarshal(rawValues, &mapValues)
285 if err != nil {
286 t.Fatal("Unexpected error", err)
287 }
288 linkerd2Chart := &chart.Chart{
289 Metadata: &chart.Metadata{
290 Name: helmDefaultChartNameCP,
291 Sources: []string{
292 filepath.Join("..", "..", "..", "charts", "linkerd-control-plane"),
293 },
294 },
295 Values: mapValues,
296 }
297
298 linkerd2Chart.AddDependency(chartPartials)
299
300 for _, filepath := range TemplatesControlPlane {
301 linkerd2Chart.Templates = append(linkerd2Chart.Templates, &chart.File{
302 Name: filepath,
303 })
304 }
305
306 for _, template := range linkerd2Chart.Templates {
307 filepath := filepath.Join(linkerd2Chart.Metadata.Sources[0], template.Name)
308 template.Data = []byte(testutil.ReadTestdata(filepath))
309 }
310
311 return linkerd2Chart
312 }
313
314 func chartPartials(paths []string) *chart.Chart {
315 var partialTemplates []*chart.File
316 for _, path := range paths {
317 partialTemplates = append(partialTemplates, &chart.File{Name: path})
318 }
319
320 chart := &chart.Chart{
321 Metadata: &chart.Metadata{
322 Name: "partials",
323 Sources: []string{
324 filepath.Join("..", "..", "..", "charts", "partials"),
325 },
326 },
327 Templates: partialTemplates,
328 }
329
330 for _, template := range chart.Templates {
331 template := template
332 filepath := filepath.Join(chart.Metadata.Sources[0], template.Name)
333 template.Data = []byte(testutil.ReadTestdata(filepath))
334 }
335
336 return chart
337 }
338
339 func readTestValues(ha bool, ignoreOutboundPorts string, ignoreInboundPorts string) (*l5dcharts.Values, error) {
340 values, err := l5dcharts.NewValues()
341 if err != nil {
342 return nil, err
343 }
344 if ha {
345 if err = l5dcharts.MergeHAValues(values); err != nil {
346 return nil, err
347 }
348 }
349 values.ProxyInit.IgnoreOutboundPorts = ignoreOutboundPorts
350 values.ProxyInit.IgnoreInboundPorts = ignoreInboundPorts
351 values.HeartbeatSchedule = "1 2 3 4 5"
352
353 return values, nil
354 }
355
View as plain text