9
9
"fmt"
10
10
"io"
11
11
"os"
12
- "path"
12
+ "path/filepath "
13
13
"slices"
14
14
"strings"
15
15
"text/template"
@@ -20,6 +20,7 @@ import (
20
20
corev1 "k8s.io/api/core/v1"
21
21
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22
22
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23
+ "k8s.io/apimachinery/pkg/runtime"
23
24
"k8s.io/apimachinery/pkg/util/yaml"
24
25
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
25
26
)
@@ -30,10 +31,11 @@ const (
30
31
)
31
32
32
33
type ChartInfo struct {
33
- repo string
34
- name string
35
- valuesFile string
36
- stringValues []string
34
+ repo string
35
+ name string
36
+ valuesFile string
37
+ stringValues []string
38
+ extraImagesFiles []string
37
39
}
38
40
39
41
func main () {
@@ -47,9 +49,9 @@ func main() {
47
49
flagSet .StringVar (& chartDirectory , "chart-directory" , "" ,
48
50
"path to chart directory for CAREN" )
49
51
flagSet .StringVar (& helmChartConfigMap , "helm-chart-configmap" , "" ,
50
- "path to chart directory for CAREN" )
52
+ "path to helm chart configmap for CAREN" )
51
53
flagSet .StringVar (& carenVersion , "caren-version" , "" ,
52
- "caren version for images override" )
54
+ "CAREN version for images override" )
53
55
err := flagSet .Parse (args [1 :])
54
56
if err != nil {
55
57
fmt .Println ("failed to parse args" , err .Error ())
@@ -66,7 +68,7 @@ func main() {
66
68
os .Exit (1 )
67
69
}
68
70
if chartDirectory == "" || helmChartConfigMap == "" {
69
- fmt .Println ("chart-directory helm-chart-configmap must be set" )
71
+ fmt .Println ("chart-directory and helm-chart-configmap must be set" )
70
72
os .Exit (1 )
71
73
}
72
74
i := & ChartInfo {
@@ -97,15 +99,10 @@ func main() {
97
99
}
98
100
99
101
func EnsureFullPath (filename string ) (string , error ) {
100
- if path .IsAbs (filename ) {
101
- return filename , nil
102
- }
103
- wd , err := os .Getwd ()
102
+ fullPath , err := filepath .Abs (filename )
104
103
if err != nil {
105
- return "" , fmt . Errorf ( "failed to get wd: %w" , err )
104
+ return "" , err
106
105
}
107
- fullPath := path .Join (wd , filename )
108
- fullPath = path .Clean (fullPath )
109
106
_ , err = os .Stat (fullPath )
110
107
if err != nil {
111
108
return "" , err
@@ -129,7 +126,7 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
129
126
if err != nil {
130
127
return nil , fmt .Errorf ("failed to unmarshal configmap to object %w" , err )
131
128
}
132
- images := []string {}
129
+ var images []string
133
130
for _ , chartInfoRaw := range cm .Data {
134
131
var settings HelmChartFromConfigMap
135
132
err = yamlv2 .Unmarshal ([]byte (chartInfoRaw ), & settings )
@@ -140,19 +137,24 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
140
137
name : settings .ChartName ,
141
138
repo : settings .Repository ,
142
139
}
143
- valuesFile := getValuesFileForChartIfNeeded (settings .ChartName , carenChartDirectory )
140
+ valuesFile , err := getValuesFileForChartIfNeeded (settings .ChartName , carenChartDirectory )
141
+ if err != nil {
142
+ return nil , fmt .Errorf ("failed to get values file for %s: %w" , settings .ChartName , err )
143
+ }
144
144
if valuesFile != "" {
145
145
info .valuesFile = valuesFile
146
146
}
147
- if settings .ChartName == "aws-cloud-controller-manager" {
147
+
148
+ switch settings .ChartName {
149
+ case "aws-cloud-controller-manager" :
148
150
values , err := getHelmValues (carenChartDirectory )
149
151
if err != nil {
150
152
return nil , err
151
153
}
152
154
awsImages , found , err := unstructured .NestedStringMap (values , "hooks" , "ccm" , "aws" , "k8sMinorVersionToCCMVersion" )
153
155
if ! found {
154
156
return images , fmt .Errorf ("failed to find k8sMinorVersionToCCMVersion from file %s" ,
155
- path .Join (carenChartDirectory , "values.yaml" ))
157
+ filepath .Join (carenChartDirectory , "values.yaml" ))
156
158
}
157
159
if err != nil {
158
160
return images , fmt .Errorf ("failed to get map k8sMinorVersionToCCMVersion with error %w" ,
@@ -168,9 +170,33 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
168
170
}
169
171
images = append (images , chartImages ... )
170
172
}
171
- // skip the to next addon because we got what we needed
173
+ // skip to the next addon because we got what we needed
172
174
continue
175
+ case "tigera-operator" :
176
+ extraImagesFile , err := os .CreateTemp ("" , "" )
177
+ if err != nil {
178
+ return nil , fmt .Errorf ("failed to create temp file for extra Calico images: %w" , err )
179
+ }
180
+ defer os .Remove (extraImagesFile .Name ()) //nolint:gocritic // Won't be leaked.
181
+ _ , err = extraImagesFile .WriteString (`
182
+ {{default "docker.io/" .Values.installation.registry }}calico/cni:{{ .Chart.Version }}
183
+ {{default "docker.io/" .Values.installation.registry }}calico/kube-controllers:{{ .Chart.Version }}
184
+ {{default "docker.io/" .Values.installation.registry }}calico/node:{{ .Chart.Version }}
185
+ {{default "docker.io/" .Values.installation.registry }}calico/apiserver:{{ .Chart.Version }}
186
+ {{default "docker.io/" .Values.installation.registry }}calico/pod2daemon-flexvol:{{ .Chart.Version }}
187
+ {{default "docker.io/" .Values.installation.registry }}calico/typha:{{ .Chart.Version }}
188
+ {{default "docker.io/" .Values.installation.registry }}calico/csi:{{ .Chart.Version }}
189
+ {{default "docker.io/" .Values.installation.registry }}calico/node-driver-registrar:{{ .Chart.Version }}
190
+ {{default "docker.io/" .Values.installation.registry }}calico/ctl:{{ .Chart.Version }}
191
+ ` )
192
+ _ = extraImagesFile .Close ()
193
+ if err != nil {
194
+ return nil , fmt .Errorf ("failed to write to temp file for extra Calico images: %w" , err )
195
+ }
196
+
197
+ info .extraImagesFiles = append (info .extraImagesFiles , extraImagesFile .Name ())
173
198
}
199
+
174
200
chartImages , err := getImagesForChart (info )
175
201
if err != nil {
176
202
return nil , fmt .Errorf ("failed to get images for %s with error %w" , info .name , err )
@@ -181,7 +207,7 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
181
207
}
182
208
183
209
func getHelmValues (carenChartDirectory string ) (map [string ]interface {}, error ) {
184
- values := path .Join (carenChartDirectory , "values.yaml" )
210
+ values := filepath .Join (carenChartDirectory , "values.yaml" )
185
211
valuesFile , err := os .Open (values )
186
212
if err != nil {
187
213
return nil , fmt .Errorf ("failed to open file %s with %w" , values , err )
@@ -195,21 +221,53 @@ func getHelmValues(carenChartDirectory string) (map[string]interface{}, error) {
195
221
return m , nil
196
222
}
197
223
198
- func getValuesFileForChartIfNeeded (chartName , carenChartDirectory string ) string {
224
+ func getValuesFileForChartIfNeeded (chartName , carenChartDirectory string ) ( string , error ) {
199
225
switch chartName {
200
226
case "nutanix-csi-storage" :
201
- return path .Join (carenChartDirectory , "addons" , "csi" , "nutanix" , defaultHelmAddonFilename )
227
+ return filepath .Join (carenChartDirectory , "addons" , "csi" , "nutanix" , defaultHelmAddonFilename ), nil
202
228
case "node-feature-discovery" :
203
- return path .Join (carenChartDirectory , "addons" , "nfd" , defaultHelmAddonFilename )
229
+ return filepath .Join (carenChartDirectory , "addons" , "nfd" , defaultHelmAddonFilename ), nil
204
230
case "snapshot-controller" :
205
- return path .Join (carenChartDirectory , "addons" , "csi" , "snapshot-controller" , defaultHelmAddonFilename )
231
+ return filepath .Join (carenChartDirectory , "addons" , "csi" , "snapshot-controller" , defaultHelmAddonFilename ), nil
206
232
case "cilium" :
207
- return path .Join (carenChartDirectory , "addons" , "cni" , "cilium" , defaultHelmAddonFilename )
233
+ return filepath .Join (carenChartDirectory , "addons" , "cni" , "cilium" , defaultHelmAddonFilename ), nil
234
+ // Calico values differ slightly per provider, but that does not have a material imapct on the images required
235
+ // so we can use the default values file for AWS provider.
236
+ case "tigera-operator" :
237
+ f := filepath .Join (carenChartDirectory , "addons" , "cni" , "calico" , "aws" , defaultHelmAddonFilename )
238
+ tempFile , err := os .CreateTemp ("" , "" )
239
+ if err != nil {
240
+ return "" , fmt .Errorf ("failed to create temp file: %w" , err )
241
+ }
242
+
243
+ // CAAPH uses unstructured internally, so we need to create an unstructured copy of a cluster
244
+ // to pass to the CAAPH values template.
245
+ c , err := runtime .DefaultUnstructuredConverter .ToUnstructured (& clusterv1.Cluster {})
246
+ if err != nil {
247
+ return "" , fmt .Errorf ("failed to convert cluster to unstructured %w" , err )
248
+ }
249
+
250
+ templateInput := struct {
251
+ Cluster map [string ]interface {}
252
+ }{
253
+ Cluster : c ,
254
+ }
255
+
256
+ err = template .Must (template .New (defaultHelmAddonFilename ).ParseFiles (f )).Execute (tempFile , & templateInput )
257
+ if err != nil {
258
+ return "" , fmt .Errorf ("failed to execute helm values template %w" , err )
259
+ }
260
+
261
+ return tempFile .Name (), nil
208
262
// this uses the values from kustomize because the file at addons/cluster-autoscaler/values-template.yaml
209
263
// is a file that is templated
210
264
case "cluster-autoscaler" :
211
- f := path .Join (carenChartDirectory , "addons" , "cluster-autoscaler" , defaultHelmAddonFilename )
212
- tempFile , _ := os .CreateTemp ("" , "" )
265
+ f := filepath .Join (carenChartDirectory , "addons" , "cluster-autoscaler" , defaultHelmAddonFilename )
266
+ tempFile , err := os .CreateTemp ("" , "" )
267
+ if err != nil {
268
+ return "" , fmt .Errorf ("failed to create temp file: %w" , err )
269
+ }
270
+
213
271
c := clusterv1.Cluster {
214
272
ObjectMeta : metav1.ObjectMeta {
215
273
Name : "tmplCluster" ,
@@ -227,25 +285,26 @@ func getValuesFileForChartIfNeeded(chartName, carenChartDirectory string) string
227
285
Cluster : & c ,
228
286
}
229
287
230
- template .Must (template .New (defaultHelmAddonFilename ).ParseFiles (f )).Execute (tempFile , & templateInput )
231
- return tempFile .Name ()
288
+ err = template .Must (template .New (defaultHelmAddonFilename ).ParseFiles (f )).Execute (tempFile , & templateInput )
289
+ if err != nil {
290
+ return "" , fmt .Errorf ("failed to execute helm values template %w" , err )
291
+ }
292
+
293
+ return tempFile .Name (), nil
232
294
default :
233
- return ""
295
+ return "" , nil
234
296
}
235
297
}
236
298
237
299
func getImagesForChart (info * ChartInfo ) ([]string , error ) {
238
300
images := pkg.Images {}
239
301
images .SetChart (info .name )
240
- if info .repo != "" {
241
- images .RepoURL = info .repo
242
- }
302
+ images .RepoURL = info .repo
243
303
if info .valuesFile != "" {
244
- images .ValueFiles .Set (info .valuesFile )
245
- }
246
- if len (info .stringValues ) > 0 {
247
- images .StringValues = info .stringValues
304
+ _ = images .ValueFiles .Set (info .valuesFile )
248
305
}
306
+ images .StringValues = info .stringValues
307
+ images .ExtraImagesFiles = info .extraImagesFiles
249
308
// kubeVersion needs to be set for some addons
250
309
images .KubeVersion = "v1.29.0"
251
310
images .SetRelease ("sample" )
0 commit comments