99 "fmt"
1010 "io"
1111 "os"
12- "path"
12+ "path/filepath "
1313 "slices"
1414 "strings"
1515 "text/template"
@@ -20,6 +20,7 @@ import (
2020 corev1 "k8s.io/api/core/v1"
2121 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2222 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
23+ "k8s.io/apimachinery/pkg/runtime"
2324 "k8s.io/apimachinery/pkg/util/yaml"
2425 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2526)
@@ -30,10 +31,11 @@ const (
3031)
3132
3233type 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
3739}
3840
3941func main () {
@@ -47,9 +49,9 @@ func main() {
4749 flagSet .StringVar (& chartDirectory , "chart-directory" , "" ,
4850 "path to chart directory for CAREN" )
4951 flagSet .StringVar (& helmChartConfigMap , "helm-chart-configmap" , "" ,
50- "path to chart directory for CAREN" )
52+ "path to helm chart configmap for CAREN" )
5153 flagSet .StringVar (& carenVersion , "caren-version" , "" ,
52- "caren version for images override" )
54+ "CAREN version for images override" )
5355 err := flagSet .Parse (args [1 :])
5456 if err != nil {
5557 fmt .Println ("failed to parse args" , err .Error ())
@@ -66,7 +68,7 @@ func main() {
6668 os .Exit (1 )
6769 }
6870 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" )
7072 os .Exit (1 )
7173 }
7274 i := & ChartInfo {
@@ -97,15 +99,10 @@ func main() {
9799}
98100
99101func 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 )
104103 if err != nil {
105- return "" , fmt . Errorf ( "failed to get wd: %w" , err )
104+ return "" , err
106105 }
107- fullPath := path .Join (wd , filename )
108- fullPath = path .Clean (fullPath )
109106 _ , err = os .Stat (fullPath )
110107 if err != nil {
111108 return "" , err
@@ -129,7 +126,7 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
129126 if err != nil {
130127 return nil , fmt .Errorf ("failed to unmarshal configmap to object %w" , err )
131128 }
132- images := []string {}
129+ var images []string
133130 for _ , chartInfoRaw := range cm .Data {
134131 var settings HelmChartFromConfigMap
135132 err = yamlv2 .Unmarshal ([]byte (chartInfoRaw ), & settings )
@@ -140,19 +137,24 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
140137 name : settings .ChartName ,
141138 repo : settings .Repository ,
142139 }
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+ }
144144 if valuesFile != "" {
145145 info .valuesFile = valuesFile
146146 }
147- if settings .ChartName == "aws-cloud-controller-manager" {
147+
148+ switch settings .ChartName {
149+ case "aws-cloud-controller-manager" :
148150 values , err := getHelmValues (carenChartDirectory )
149151 if err != nil {
150152 return nil , err
151153 }
152154 awsImages , found , err := unstructured .NestedStringMap (values , "hooks" , "ccm" , "aws" , "k8sMinorVersionToCCMVersion" )
153155 if ! found {
154156 return images , fmt .Errorf ("failed to find k8sMinorVersionToCCMVersion from file %s" ,
155- path .Join (carenChartDirectory , "values.yaml" ))
157+ filepath .Join (carenChartDirectory , "values.yaml" ))
156158 }
157159 if err != nil {
158160 return images , fmt .Errorf ("failed to get map k8sMinorVersionToCCMVersion with error %w" ,
@@ -168,9 +170,33 @@ func getImagesForAddons(helmChartConfigMap, carenChartDirectory string) ([]strin
168170 }
169171 images = append (images , chartImages ... )
170172 }
171- // skip the to next addon because we got what we needed
173+ // skip to the next addon because we got what we needed
172174 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 ())
173198 }
199+
174200 chartImages , err := getImagesForChart (info )
175201 if err != nil {
176202 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
181207}
182208
183209func getHelmValues (carenChartDirectory string ) (map [string ]interface {}, error ) {
184- values := path .Join (carenChartDirectory , "values.yaml" )
210+ values := filepath .Join (carenChartDirectory , "values.yaml" )
185211 valuesFile , err := os .Open (values )
186212 if err != nil {
187213 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) {
195221 return m , nil
196222}
197223
198- func getValuesFileForChartIfNeeded (chartName , carenChartDirectory string ) string {
224+ func getValuesFileForChartIfNeeded (chartName , carenChartDirectory string ) ( string , error ) {
199225 switch chartName {
200226 case "nutanix-csi-storage" :
201- return path .Join (carenChartDirectory , "addons" , "csi" , "nutanix" , defaultHelmAddonFilename )
227+ return filepath .Join (carenChartDirectory , "addons" , "csi" , "nutanix" , defaultHelmAddonFilename ), nil
202228 case "node-feature-discovery" :
203- return path .Join (carenChartDirectory , "addons" , "nfd" , defaultHelmAddonFilename )
229+ return filepath .Join (carenChartDirectory , "addons" , "nfd" , defaultHelmAddonFilename ), nil
204230 case "snapshot-controller" :
205- return path .Join (carenChartDirectory , "addons" , "csi" , "snapshot-controller" , defaultHelmAddonFilename )
231+ return filepath .Join (carenChartDirectory , "addons" , "csi" , "snapshot-controller" , defaultHelmAddonFilename ), nil
206232 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
208262 // this uses the values from kustomize because the file at addons/cluster-autoscaler/values-template.yaml
209263 // is a file that is templated
210264 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+
213271 c := clusterv1.Cluster {
214272 ObjectMeta : metav1.ObjectMeta {
215273 Name : "tmplCluster" ,
@@ -227,25 +285,26 @@ func getValuesFileForChartIfNeeded(chartName, carenChartDirectory string) string
227285 Cluster : & c ,
228286 }
229287
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
232294 default :
233- return ""
295+ return "" , nil
234296 }
235297}
236298
237299func getImagesForChart (info * ChartInfo ) ([]string , error ) {
238300 images := pkg.Images {}
239301 images .SetChart (info .name )
240- if info .repo != "" {
241- images .RepoURL = info .repo
242- }
302+ images .RepoURL = info .repo
243303 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 )
248305 }
306+ images .StringValues = info .stringValues
307+ images .ExtraImagesFiles = info .extraImagesFiles
249308 // kubeVersion needs to be set for some addons
250309 images .KubeVersion = "v1.29.0"
251310 images .SetRelease ("sample" )
0 commit comments