Skip to content

Commit

Permalink
chore: add DOCA driver matrix validation
Browse files Browse the repository at this point in the history
Signed-off-by: Fred Rolland <[email protected]>
  • Loading branch information
rollandf committed Jan 16, 2025
1 parent b2eab78 commit 4ef5594
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 40 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/checks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,20 @@ jobs:
uses: actions/checkout@v4
- name: check release-build
run: make check-release-build
check-doca-drivers:
name: check doca-drivers
runs-on: ubuntu-22.04
permissions:
contents: read
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v5
with:
go-version: '1.23'
- name: checkout
uses: actions/checkout@v4
- name: check doca-drivers
run: make check-doca-drivers
unit-tests:
name: Unit-tests
runs-on: ubuntu-22.04
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ testbin
test
build
hack/manifests
hack/tmp
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ REPO_PATH=$(ORG_PATH)/$(PACKAGE)
CHART_PATH=$(CURDIR)/deployment/$(PACKAGE)
TOOLSDIR=$(CURDIR)/hack/tools/bin
MANIFESTDIR=$(CURDIR)/hack/manifests
HACKTMPDIR=$(CURDIR)/hack/tmp
BUILDDIR=$(CURDIR)/build/_output
GOFILES=$(shell find . -name "*.go" | grep -vE "(\/vendor\/)|(_test.go)")
TESTPKGS=./...
Expand All @@ -37,6 +38,7 @@ BUILD_VERSION := $(strip $(shell [ -d .git ] && git describe --always --tags --d
BUILD_TIMESTAMP := $(shell date -u +"%Y-%m-%dT%H:%M:%S%Z")
VCS_BRANCH := $(strip $(shell git rev-parse --abbrev-ref HEAD))
VCS_REF := $(strip $(shell [ -d .git ] && git rev-parse --short HEAD))
DOCA_DRIVER_RELEASE_URL := https://raw.githubusercontent.com/Mellanox/doca-driver-build/refs/heads/main/release_manifests/

# Docker
IMAGE_BUILDER?=docker
Expand Down Expand Up @@ -109,6 +111,9 @@ $(MANIFESTDIR):
$(BUILDDIR): ; $(info Creating build directory...)
mkdir -p $@

$(HACKTMPDIR):
@mkdir -p $@

build: generate $(BUILDDIR)/$(BINARY_NAME) ; $(info Building $(BINARY_NAME)...) @ ## Build executable file
$(info Done!)

Expand Down Expand Up @@ -356,6 +361,7 @@ clean: ; $(info Cleaning...) @ ## Cleanup everything
@rm -rf $(BUILDDIR)
@rm -rf $(TOOLSDIR)
@rm -rf $(MANIFESTDIR)
@rm -rf $(HACKTMPDIR)

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

.PHONY: check-doca-drivers
check-doca-drivers: $(HACKTMPDIR)
$(eval DRIVERVERSION := $(shell yq '.Mofed.version' hack/release.yaml | cut -d'-' -f1))
wget $(DOCA_DRIVER_RELEASE_URL)$(DRIVERVERSION).yaml -O $(HACKTMPDIR)/doca-driver-matrix.yaml
cd hack && $(GO) run release.go --doca-driver-check --doca-driver-matrix $(HACKTMPDIR)/doca-driver-matrix.yaml

# dev environment

MINIKUBE_CLUSTER_NAME = net-op-dev
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.10.0
github.com/xeipuuv/gojsonschema v1.2.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.31.4
k8s.io/apimachinery v0.31.4
k8s.io/client-go v0.31.4
Expand Down Expand Up @@ -112,7 +113,6 @@ require (
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.31.1 // indirect
k8s.io/cli-runtime v0.31.2 // indirect
k8s.io/component-base v0.31.2 // indirect
Expand Down
154 changes: 115 additions & 39 deletions hack/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (

"sigs.k8s.io/yaml"

yamlflow "gopkg.in/yaml.v3"

mellanoxv1alpha1 "github.com/Mellanox/network-operator/api/v1alpha1"

"github.com/google/go-containerregistry/pkg/authn"
Expand Down Expand Up @@ -80,6 +82,19 @@ type Release struct {
MaintenanceOperator *ReleaseImageSpec
}

// DocaDriverMatrix represent the expected DOCA-Driver OS/arch combinations
type DocaDriverMatrix struct {
Precompiled []struct {
OS string `yaml:"os"`
Arch []string `yaml:"archs,flow"`
Kernels []string `yaml:"kernels,flow"`
} `yaml:"precompiled"`
DynamicallyCompiled []struct {
OS string `yaml:"os,flow"`
Arch []string `yaml:"archs,flow"`
} `yaml:"dynamically_compiled"`
}

func readDefaults(releaseDefaults string) Release {
f, err := os.ReadFile(filepath.Clean(releaseDefaults))
if err != nil {
Expand Down Expand Up @@ -136,11 +151,87 @@ func main() {
outputDir := flag.String("outputDir", ".", "Destination directory to render templates to")
releaseDefaults := flag.String("releaseDefaults", "release.yaml", "Destination of the release defaults definition")
retrieveSha := flag.Bool("with-sha256", false, "retrieve SHA256 for container images references")
docaDriverCheck := flag.Bool("doca-driver-check", false, "Verify DOCA Driver tags")
docaDriverMatrix := flag.String("doca-driver-matrix", "tmp/doca-driver-matrix.yaml", "DOCA Driver tags matrix")
flag.Parse()
release := readDefaults(*releaseDefaults)
readEnvironmentVariables(&release)

if !*docaDriverCheck {
renderTemplates(&release, templateDir, outputDir, retrieveSha)
} else {
docaDriverTagsCheck(&release, docaDriverMatrix)
}
}

func docaDriverTagsCheck(release *Release, docaDriverMatrix *string) {
f, err := os.ReadFile(filepath.Clean(*docaDriverMatrix))
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
var config DocaDriverMatrix
if err := yamlflow.Unmarshal(f, &config); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
tags, err := resolveTags(release.Mofed.Repository, release.Mofed.Image)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
if err := validateTags(config, tags, release.Mofed.Version); err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}

func validateTags(config DocaDriverMatrix, tags []string, version string) error {
// Build expected OS-arch combinations
expectedCombinations := make(map[string]struct{})
for _, entry := range config.DynamicallyCompiled {
for _, arch := range entry.Arch {
key := fmt.Sprintf("%s-%s", entry.OS, arch)
expectedCombinations[key] = struct{}{}
}
}

// Filter tags based on version prefix
filteredTags := []string{}
for _, tag := range tags {
if strings.HasPrefix(tag, version) {
filteredTags = append(filteredTags, tag)
}
}

unfound := make([]string, 0)
// Validate if each expected combination exists in the filtered tags
for combo := range expectedCombinations {
found := false
for _, tag := range filteredTags {
if strings.Contains(tag, combo) {
found = true
break
}
}
if !found {
unfound = append(unfound, combo)
}
}
if len(unfound) > 0 {
return fmt.Errorf("missing os-arch combinations: %v", unfound)
}

return nil
}

func renderTemplates(release *Release, templateDir, outputDir *string, retrieveSha *bool) {
if *retrieveSha {
err := resolveImagesSha(&release)
err := resolveImagesSha(release)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
Expand Down Expand Up @@ -199,22 +290,15 @@ func main() {
}

func resolveImagesSha(release *Release) error {

Check failure on line 292 in hack/release.go

View workflow job for this annotation

GitHub Actions / golangci-lint

unnecessary leading newline (whitespace)
nvcrToken := os.Getenv("NGC_CLI_API_KEY")
if nvcrToken == "" {
return fmt.Errorf("NGC_CLI_API_KEY is unset")
}
auth := &authn.Basic{
Username: "$oauthtoken",
Password: nvcrToken,
}

v := reflect.ValueOf(*release)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
if !field.IsNil() {
releaseImageSpec := field.Interface().(*ReleaseImageSpec)
if strings.Contains(releaseImageSpec.Image, "doca-driver") {
digests, err := resolveDocaDriversShas(releaseImageSpec.Repository, releaseImageSpec.Image,
releaseImageSpec.Version, auth)
releaseImageSpec.Version)
if err != nil {
return err
}
Expand All @@ -225,7 +309,7 @@ func resolveImagesSha(release *Release) error {
}
} else {
digest, err := resolveImageSha(releaseImageSpec.Repository, releaseImageSpec.Image,
releaseImageSpec.Version, auth)
releaseImageSpec.Version)
if err != nil {
return err
}
Expand All @@ -238,23 +322,15 @@ func resolveImagesSha(release *Release) error {
return nil
}

func resolveImageSha(repo, image, tag string, auth *authn.Basic) (string, error) {
func resolveImageSha(repo, image, tag string) (string, error) {
ref, err := containerregistryname.ParseReference(fmt.Sprintf("%s/%s:%s", repo, image, tag))
if err != nil {
return "", err
}
var desc *remote.Descriptor
if strings.Contains(repo, "nvstaging") {
desc, err = remote.Get(ref, remote.WithAuth(auth))
if err != nil {
return "", err
}
} else {
// Container registry might fail if providing unneeded auth
desc, err = remote.Get(ref)
if err != nil {
return "", err
}
desc, err = remote.Get(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
return "", err
}
digest, err := containerregistryv1.NewHash(desc.Descriptor.Digest.String())
if err != nil {
Expand All @@ -263,31 +339,31 @@ func resolveImageSha(repo, image, tag string, auth *authn.Basic) (string, error)
return digest.String(), nil
}

func resolveDocaDriversShas(repoName, imageName, ver string, auth *authn.Basic) ([]string, error) {
shaArray := make([]string, 0)
func resolveTags(repoName, imageName string) ([]string, error) {
tags := make([]string, 0)
image := fmt.Sprintf("%s/%s", repoName, imageName)
repo, err := containerregistryname.NewRepository(image)
if err != nil {
return shaArray, err
return tags, err
}
var tags []string
if strings.Contains(repoName, "nvstaging") {
tags, err = remote.List(repo, remote.WithAuth(auth))
if err != nil {
return shaArray, err
}
} else {
// Container registry might fail if providing unneeded auth
tags, err = remote.List(repo)
if err != nil {
return shaArray, err
}
tags, err = remote.List(repo, remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
return tags, err
}
sort.Strings(tags)
return tags, nil
}

func resolveDocaDriversShas(repoName, imageName, ver string) ([]string, error) {
shaArray := make([]string, 0)
tags, err := resolveTags(repoName, imageName)
if err != nil {
return shaArray, err
}
shaSet := make(map[string]interface{})
for _, tag := range tags {
if strings.Contains(tag, ver) && (strings.Contains(tag, "rhcos") || strings.Contains(tag, "rhel")) {
digest, err := resolveImageSha(repoName, imageName, tag, auth)
digest, err := resolveImageSha(repoName, imageName, tag)
if err != nil {
return shaArray, err
}
Expand Down

0 comments on commit 4ef5594

Please sign in to comment.