Skip to content

Commit ad53207

Browse files
authored
chore: add DOCA driver matrix validation (Mellanox#1251)
2 parents f7f4ac8 + 3fde81c commit ad53207

File tree

5 files changed

+158
-41
lines changed

5 files changed

+158
-41
lines changed

.github/workflows/checks.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ jobs:
7878
uses: actions/checkout@v4
7979
- name: check release-build
8080
run: make check-release-build
81+
check-doca-drivers:
82+
name: check doca-drivers
83+
runs-on: ubuntu-22.04
84+
permissions:
85+
contents: read
86+
steps:
87+
- name: Set up Go 1.x
88+
uses: actions/setup-go@v5
89+
with:
90+
go-version: '1.23'
91+
- name: checkout
92+
uses: actions/checkout@v4
93+
- name: check doca-drivers
94+
env:
95+
NGC_CLI_API_KEY: ${{ secrets.NVCR_TOKEN }}
96+
run: make check-doca-drivers
8197
unit-tests:
8298
name: Unit-tests
8399
runs-on: ubuntu-22.04

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ testbin
3030
test
3131
build
3232
hack/manifests
33+
hack/tmp

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ REPO_PATH=$(ORG_PATH)/$(PACKAGE)
2020
CHART_PATH=$(CURDIR)/deployment/$(PACKAGE)
2121
TOOLSDIR=$(CURDIR)/hack/tools/bin
2222
MANIFESTDIR=$(CURDIR)/hack/manifests
23+
HACKTMPDIR=$(CURDIR)/hack/tmp
2324
BUILDDIR=$(CURDIR)/build/_output
2425
GOFILES=$(shell find . -name "*.go" | grep -vE "(\/vendor\/)|(_test.go)")
2526
TESTPKGS=./...
@@ -37,6 +38,7 @@ BUILD_VERSION := $(strip $(shell [ -d .git ] && git describe --always --tags --d
3738
BUILD_TIMESTAMP := $(shell date -u +"%Y-%m-%dT%H:%M:%S%Z")
3839
VCS_BRANCH := $(strip $(shell git rev-parse --abbrev-ref HEAD))
3940
VCS_REF := $(strip $(shell [ -d .git ] && git rev-parse --short HEAD))
41+
DOCA_DRIVER_RELEASE_URL := https://raw.githubusercontent.com/Mellanox/doca-driver-build/refs/heads/main/release_manifests/
4042

4143
# Docker
4244
IMAGE_BUILDER?=docker
@@ -109,6 +111,9 @@ $(MANIFESTDIR):
109111
$(BUILDDIR): ; $(info Creating build directory...)
110112
mkdir -p $@
111113

114+
$(HACKTMPDIR):
115+
@mkdir -p $@
116+
112117
build: generate $(BUILDDIR)/$(BINARY_NAME) ; $(info Building $(BINARY_NAME)...) @ ## Build executable file
113118
$(info Done!)
114119

@@ -356,6 +361,7 @@ clean: ; $(info Cleaning...) @ ## Cleanup everything
356361
@rm -rf $(BUILDDIR)
357362
@rm -rf $(TOOLSDIR)
358363
@rm -rf $(MANIFESTDIR)
364+
@rm -rf $(HACKTMPDIR)
359365

360366
.PHONY: help
361367
help: ## Show this message
@@ -414,6 +420,12 @@ release-build:
414420
cd hack && $(GO) run release.go --templateDir ./templates/crs/ --outputDir ../example/crs
415421
cd hack && $(GO) run release.go --templateDir ./templates/values/ --outputDir ../deployment/network-operator/
416422

423+
.PHONY: check-doca-drivers
424+
check-doca-drivers: $(HACKTMPDIR)
425+
$(eval DRIVERVERSION := $(shell yq '.Mofed.version' hack/release.yaml | cut -d'-' -f1))
426+
wget $(DOCA_DRIVER_RELEASE_URL)$(DRIVERVERSION).yaml -O $(HACKTMPDIR)/doca-driver-matrix.yaml
427+
cd hack && $(GO) run release.go --doca-driver-check --doca-driver-matrix $(HACKTMPDIR)/doca-driver-matrix.yaml
428+
417429
# dev environment
418430

419431
MINIKUBE_CLUSTER_NAME = net-op-dev

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/pkg/errors v0.9.1
1818
github.com/stretchr/testify v1.10.0
1919
github.com/xeipuuv/gojsonschema v1.2.0
20+
gopkg.in/yaml.v3 v3.0.1
2021
k8s.io/api v0.31.5
2122
k8s.io/apimachinery v0.31.5
2223
k8s.io/client-go v0.31.5
@@ -112,7 +113,6 @@ require (
112113
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
113114
gopkg.in/inf.v0 v0.9.1 // indirect
114115
gopkg.in/yaml.v2 v2.4.0 // indirect
115-
gopkg.in/yaml.v3 v3.0.1 // indirect
116116
k8s.io/apiextensions-apiserver v0.31.1 // indirect
117117
k8s.io/cli-runtime v0.31.2 // indirect
118118
k8s.io/component-base v0.31.2 // indirect

hack/release.go

Lines changed: 128 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
85100
func 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

Comments
 (0)