@@ -30,6 +30,8 @@ import (
3030
3131 "sigs.k8s.io/yaml"
3232
33+ yamlflow "gopkg.in/yaml.v3"
34+
3335 mellanoxv1alpha1 "github.com/Mellanox/network-operator/api/v1alpha1"
3436
3537 "github.com/google/go-containerregistry/pkg/authn"
@@ -82,6 +84,19 @@ type Release struct {
8284 MaintenanceOperator * ReleaseImageSpec
8385}
8486
87+ // DocaDriverMatrix represent the expected DOCA-Driver OS/arch combinations
88+ type DocaDriverMatrix struct {
89+ Precompiled []struct {
90+ OS string `yaml:"os"`
91+ Arch []string `yaml:"archs,flow"`
92+ Kernels []string `yaml:"kernels,flow"`
93+ } `yaml:"precompiled"`
94+ DynamicallyCompiled []struct {
95+ OS string `yaml:"os,flow"`
96+ Arches []string `yaml:"archs,flow"`
97+ } `yaml:"dynamically_compiled"`
98+ }
99+
85100func readDefaults (releaseDefaults string ) Release {
86101 f , err := os .ReadFile (filepath .Clean (releaseDefaults ))
87102 if err != nil {
@@ -138,11 +153,83 @@ func main() {
138153 outputDir := flag .String ("outputDir" , "." , "Destination directory to render templates to" )
139154 releaseDefaults := flag .String ("releaseDefaults" , "release.yaml" , "Destination of the release defaults definition" )
140155 retrieveSha := flag .Bool ("with-sha256" , false , "retrieve SHA256 for container images references" )
156+ docaDriverCheck := flag .Bool ("doca-driver-check" , false , "Verify DOCA Driver tags" )
157+ docaDriverMatrix := flag .String ("doca-driver-matrix" , "tmp/doca-driver-matrix.yaml" , "DOCA Driver tags matrix" )
141158 flag .Parse ()
142159 release := readDefaults (* releaseDefaults )
143160 readEnvironmentVariables (& release )
161+
162+ if * docaDriverCheck {
163+ docaDriverTagsCheck (& release , docaDriverMatrix )
164+ } else {
165+ renderTemplates (& release , templateDir , outputDir , retrieveSha )
166+ }
167+ }
168+
169+ func docaDriverTagsCheck (release * Release , docaDriverMatrix * string ) {
170+ f , err := os .ReadFile (filepath .Clean (* docaDriverMatrix ))
171+ if err != nil {
172+ fmt .Printf ("Error: %v\n " , err )
173+ os .Exit (1 )
174+ }
175+ var config DocaDriverMatrix
176+ if err := yamlflow .Unmarshal (f , & config ); err != nil {
177+ fmt .Printf ("Error: %v\n " , err )
178+ os .Exit (1 )
179+ }
180+ tags , err := listTags (release .Mofed .Repository , release .Mofed .Image )
181+ if err != nil {
182+ fmt .Printf ("Error: %v\n " , err )
183+ os .Exit (1 )
184+ }
185+ if err := validateTags (config , tags , release .Mofed .Version ); err != nil {
186+ fmt .Printf ("Error: %v\n " , err )
187+ os .Exit (1 )
188+ }
189+ }
190+
191+ func validateTags (config DocaDriverMatrix , tags []string , version string ) error {
192+ // Build expected OS-arch combinations
193+ expectedCombinations := make (map [string ]struct {})
194+ for _ , entry := range config .DynamicallyCompiled {
195+ for _ , arch := range entry .Arches {
196+ key := fmt .Sprintf ("%s-%s" , entry .OS , arch )
197+ expectedCombinations [key ] = struct {}{}
198+ }
199+ }
200+
201+ // Filter tags based on version prefix
202+ filteredTags := []string {}
203+ for _ , tag := range tags {
204+ if strings .HasPrefix (tag , version ) {
205+ filteredTags = append (filteredTags , tag )
206+ }
207+ }
208+
209+ unfound := make ([]string , 0 )
210+ // Validate if each expected combination exists in the filtered tags
211+ for combo := range expectedCombinations {
212+ found := false
213+ for _ , tag := range filteredTags {
214+ if strings .Contains (tag , combo ) {
215+ found = true
216+ break
217+ }
218+ }
219+ if ! found {
220+ unfound = append (unfound , combo )
221+ }
222+ }
223+ if len (unfound ) > 0 {
224+ return fmt .Errorf ("missing os-arch combinations: %v" , unfound )
225+ }
226+
227+ return nil
228+ }
229+
230+ func renderTemplates (release * Release , templateDir , outputDir * string , retrieveSha * bool ) {
144231 if * retrieveSha {
145- err := resolveImagesSha (& release )
232+ err := resolveImagesSha (release )
146233 if err != nil {
147234 fmt .Printf ("Error: %v\n " , err )
148235 os .Exit (1 )
@@ -204,23 +291,30 @@ func main() {
204291 }
205292}
206293
207- func resolveImagesSha (release * Release ) error {
208- nvcrToken := os .Getenv ("NGC_CLI_API_KEY" )
209- if nvcrToken == "" {
210- return fmt .Errorf ("NGC_CLI_API_KEY is unset" )
211- }
212- auth := & authn.Basic {
213- Username : "$oauthtoken" ,
214- Password : nvcrToken ,
294+ func getAuth (repo string ) remote.Option {
295+ if strings .Contains (repo , "nvstaging" ) {
296+ nvcrToken := os .Getenv ("NGC_CLI_API_KEY" )
297+ if nvcrToken == "" {
298+ log .Fatalf ("NGC_CLI_API_KEY is unset" )
299+ }
300+ authNvcr := & authn.Basic {
301+ Username : "$oauthtoken" ,
302+ Password : nvcrToken ,
303+ }
304+ return remote .WithAuth (authNvcr )
215305 }
306+ return remote .WithAuthFromKeychain (authn .DefaultKeychain )
307+ }
308+
309+ func resolveImagesSha (release * Release ) error {
216310 v := reflect .ValueOf (* release )
217311 for i := 0 ; i < v .NumField (); i ++ {
218312 field := v .Field (i )
219313 if ! field .IsNil () {
220314 releaseImageSpec := field .Interface ().(* ReleaseImageSpec )
221315 if strings .Contains (releaseImageSpec .Image , "doca-driver" ) {
222316 digests , err := resolveDocaDriversShas (releaseImageSpec .Repository , releaseImageSpec .Image ,
223- releaseImageSpec .Version , auth )
317+ releaseImageSpec .Version )
224318 if err != nil {
225319 return err
226320 }
@@ -231,7 +325,7 @@ func resolveImagesSha(release *Release) error {
231325 }
232326 } else {
233327 digest , err := resolveImageSha (releaseImageSpec .Repository , releaseImageSpec .Image ,
234- releaseImageSpec .Version , auth )
328+ releaseImageSpec .Version )
235329 if err != nil {
236330 return err
237331 }
@@ -244,56 +338,50 @@ func resolveImagesSha(release *Release) error {
244338 return nil
245339}
246340
247- func resolveImageSha (repo , image , tag string , auth * authn. Basic ) (string , error ) {
341+ func resolveImageSha (repo , image , tag string ) (string , error ) {
248342 ref , err := containerregistryname .ParseReference (fmt .Sprintf ("%s/%s:%s" , repo , image , tag ))
249343 if err != nil {
250344 return "" , err
251345 }
252- var desc * remote.Descriptor
253- if strings .Contains (repo , "nvstaging" ) {
254- desc , err = remote .Get (ref , remote .WithAuth (auth ))
255- if err != nil {
256- return "" , err
257- }
258- } else {
259- // Container registry might fail if providing unneeded auth
260- desc , err = remote .Get (ref )
261- if err != nil {
262- return "" , err
263- }
346+ auth := getAuth (repo )
347+ desc , err := remote .Get (ref , auth )
348+ if err != nil {
349+ return "" , err
264350 }
351+
265352 digest , err := containerregistryv1 .NewHash (desc .Descriptor .Digest .String ())
266353 if err != nil {
267354 return "" , err
268355 }
269356 return digest .String (), nil
270357}
271358
272- func resolveDocaDriversShas (repoName , imageName , ver string , auth * authn. Basic ) ([]string , error ) {
273- shaArray := make ([]string , 0 )
359+ func listTags (repoName , imageName string ) ([]string , error ) {
360+ tags := make ([]string , 0 )
274361 image := fmt .Sprintf ("%s/%s" , repoName , imageName )
275362 repo , err := containerregistryname .NewRepository (image )
276363 if err != nil {
277- return shaArray , err
364+ return tags , err
278365 }
279- var tags []string
280- if strings .Contains (repoName , "nvstaging" ) {
281- tags , err = remote .List (repo , remote .WithAuth (auth ))
282- if err != nil {
283- return shaArray , err
284- }
285- } else {
286- // Container registry might fail if providing unneeded auth
287- tags , err = remote .List (repo )
288- if err != nil {
289- return shaArray , err
290- }
366+ auth := getAuth (repoName )
367+ tags , err = remote .List (repo , auth )
368+ if err != nil {
369+ return tags , err
291370 }
292371 sort .Strings (tags )
372+ return tags , nil
373+ }
374+
375+ func resolveDocaDriversShas (repoName , imageName , ver string ) ([]string , error ) {
376+ shaArray := make ([]string , 0 )
377+ tags , err := listTags (repoName , imageName )
378+ if err != nil {
379+ return shaArray , err
380+ }
293381 shaSet := make (map [string ]interface {})
294382 for _ , tag := range tags {
295383 if strings .Contains (tag , ver ) && (strings .Contains (tag , "rhcos" ) || strings .Contains (tag , "rhel" )) {
296- digest , err := resolveImageSha (repoName , imageName , tag , auth )
384+ digest , err := resolveImageSha (repoName , imageName , tag )
297385 if err != nil {
298386 return shaArray , err
299387 }
0 commit comments