Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions bundle/manifests/oadp-operator.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1461,9 +1461,9 @@ spec:
- name: RELATED_IMAGE_KUBEVIRT_VELERO_PLUGIN
value: quay.io/konveyor/kubevirt-velero-plugin:latest
- name: RELATED_IMAGE_HYPERSHIFT_VELERO_PLUGIN
value: quay.io/redhat-user-workloads/ocp-art-tenant/oadp-hypershift-oadp-plugin-main:main
value: quay.io/konveyor/hypershift-oadp-plugin:latest
- name: RELATED_IMAGE_MUSTGATHER
value: registry.redhat.io/oadp/oadp-mustgather-rhel8:v1.2
value: quay.io/konveyor/oadp-must-gather:latest
- name: RELATED_IMAGE_NON_ADMIN_CONTROLLER
value: quay.io/konveyor/oadp-non-admin:latest
- name: RELATED_IMAGE_VM_FILE_RESTORE_CONTROLLER
Expand All @@ -1480,6 +1480,8 @@ spec:
value: quay.io/konveyor/oadp-vmdp-binaries:latest
- name: RELATED_IMAGE_KUBEVIRT_DATAMOVER_CONTROLLER
value: quay.io/konveyor/kubevirt-datamover-controller:latest
- name: RELATED_IMAGE_KUBEVIRT_DATAMOVER_PLUGIN
value: quay.io/konveyor/kubevirt-datamover-plugin:latest
image: quay.io/konveyor/oadp-operator:latest
imagePullPolicy: Always
livenessProbe:
Expand Down Expand Up @@ -1702,9 +1704,9 @@ spec:
name: velero-plugin-for-gcp
- image: quay.io/konveyor/kubevirt-velero-plugin:latest
name: kubevirt-velero-plugin
- image: quay.io/redhat-user-workloads/ocp-art-tenant/oadp-hypershift-oadp-plugin-main:main
- image: quay.io/konveyor/hypershift-oadp-plugin:latest
name: hypershift-velero-plugin
- image: registry.redhat.io/oadp/oadp-mustgather-rhel8:v1.2
- image: quay.io/konveyor/oadp-must-gather:latest
name: mustgather
- image: quay.io/konveyor/oadp-non-admin:latest
name: non-admin-controller
Expand All @@ -1722,4 +1724,6 @@ spec:
name: vmdp-cli-download
- image: quay.io/konveyor/kubevirt-datamover-controller:latest
name: kubevirt-datamover-controller
- image: quay.io/konveyor/kubevirt-datamover-plugin:latest
name: kubevirt-datamover-plugin
version: 99.0.0
6 changes: 4 additions & 2 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ spec:
- name: RELATED_IMAGE_KUBEVIRT_VELERO_PLUGIN
value: quay.io/konveyor/kubevirt-velero-plugin:latest
- name: RELATED_IMAGE_HYPERSHIFT_VELERO_PLUGIN
value: quay.io/redhat-user-workloads/ocp-art-tenant/oadp-hypershift-oadp-plugin-main:main
value: quay.io/konveyor/hypershift-oadp-plugin:latest
- name: RELATED_IMAGE_MUSTGATHER
value: registry.redhat.io/oadp/oadp-mustgather-rhel8:v1.2
value: quay.io/konveyor/oadp-must-gather:latest
- name: RELATED_IMAGE_NON_ADMIN_CONTROLLER
value: quay.io/konveyor/oadp-non-admin:latest
- name: RELATED_IMAGE_VM_FILE_RESTORE_CONTROLLER
Expand All @@ -102,6 +102,8 @@ spec:
value: quay.io/konveyor/oadp-vmdp-binaries:latest
- name: RELATED_IMAGE_KUBEVIRT_DATAMOVER_CONTROLLER
value: quay.io/konveyor/kubevirt-datamover-controller:latest
- name: RELATED_IMAGE_KUBEVIRT_DATAMOVER_PLUGIN
value: quay.io/konveyor/kubevirt-datamover-plugin:latest
args:
- --leader-elect
image: controller:latest
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ require (
github.com/vmware-tanzu/velero v1.14.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
google.golang.org/api v0.256.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/klog/v2 v2.130.1
)

Expand Down Expand Up @@ -193,7 +194,6 @@ require (
google.golang.org/protobuf v1.36.10 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/cli-runtime v0.33.3 // indirect
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
Expand Down
4 changes: 1 addition & 3 deletions must-gather/pkg/templates/summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,6 @@ func ReplaceClusterInformationSection(
summaryTemplateReplaces["OCP_VERSION"] = clusterVersion.Status.Desired.Version
summaryTemplateReplaces["CLUSTER_VERSION"] = createYAML(outputPath, "cluster-scoped-resources/config.openshift.io/clusterversions.yaml", clusterVersion)
cloudProvider := ""


if infrastructureList != nil && len(infrastructureList.Items) != 0 {
cloudProvider = string(infrastructureList.Items[0].Spec.PlatformSpec.Type)
Expand Down Expand Up @@ -480,7 +479,6 @@ func humanizeDurationSince(t time.Time) string {
return time.Since(t).Round(time.Second).String()
}


func ReplaceCloudStoragesSection(outputPath string, cloudStorageList *oadpv1alpha1.CloudStorageList) {
if cloudStorageList != nil && len(cloudStorageList.Items) != 0 {
cloudStorageByNamespace := map[string][]oadpv1alpha1.CloudStorage{}
Expand Down Expand Up @@ -1668,7 +1666,7 @@ func ReplaceCustomResourceDefinitionsSection(outputPath string, clusterConfig *r
// CRD spec.names.plural : CRD spec.group
crds := map[string]string{
"dataprotectionapplications": gvk.DataProtectionApplicationGVK.Group,
"dataprotectiontests": gvk.DataProtectionTestGVK.Group,
"dataprotectiontests": gvk.DataProtectionTestGVK.Group,
"cloudstorages": gvk.CloudStorageGVK.Group,
"backupstoragelocations": gvk.BackupStorageLocationGVK.Group,
"volumesnapshotlocations": gvk.VolumeSnapshotLocationGVK.Group,
Expand Down
74 changes: 74 additions & 0 deletions tests/release/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package release

import (
"errors"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
)

func repoRoot(t *testing.T) string {
t.Helper()
_, filename, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("unable to determine test file path")
}
return filepath.Dir(filepath.Dir(filepath.Dir(filename)))
}

// branchVersion returns the oadp-X.Y version from the current branch.
// Checks PULL_BASE_REF first (set by Prow to the PR target branch),
// then falls back to the local git branch name.
func branchVersion(t *testing.T) string {
t.Helper()
if ref := os.Getenv("PULL_BASE_REF"); strings.HasPrefix(ref, oadpBranchPrefix) {
return ref
}
out, err := exec.Command("git", "rev-parse", "--abbrev-ref", "HEAD").Output()
if err != nil {
t.Fatalf("failed to get current branch: %v", err)
}
branch := strings.TrimSpace(string(out))
if !strings.HasPrefix(branch, oadpBranchPrefix) {
return ""
}
return branch
}
Comment thread
Joeavaikath marked this conversation as resolved.

func readBundleFile(t *testing.T, root, relPath string) []byte {
t.Helper()
path := filepath.Join(root, relPath)
data, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
t.Skipf("%s does not exist (only present on release branches)", relPath)
}
t.Fatalf("failed to read %s: %v", relPath, err)
}
return data
}

func reportErrors(t *testing.T, errs []error) {
t.Helper()
for _, err := range errs {
t.Error(err)
}
}

func assertErrors(t *testing.T, errs []error, wantErrs int, wantMsg string) {
t.Helper()
if len(errs) != wantErrs {
t.Fatalf("got %d errors, want %d: %v", len(errs), wantErrs, errs)
}
if wantMsg != "" {
for _, err := range errs {
if strings.Contains(err.Error(), wantMsg) {
return
}
}
t.Errorf("expected error containing %q, got %v", wantMsg, errs)
}
}
136 changes: 136 additions & 0 deletions tests/release/image_references.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package release

import (
"fmt"
"strings"

"gopkg.in/yaml.v3"
)

func parseImageReferences(data []byte) (*imageReferencesFile, error) {
var ir imageReferencesFile
if err := yaml.Unmarshal(data, &ir); err != nil {
return nil, fmt.Errorf("failed to parse image-references: %w", err)
}
if len(ir.Spec.Tags) == 0 {
return nil, fmt.Errorf("image-references has no tags")
}
return &ir, nil
}

func parseCSV(data []byte) (*csv, error) {
var c csv
if err := yaml.Unmarshal(data, &c); err != nil {
return nil, fmt.Errorf("failed to parse CSV: %w", err)
}
return &c, nil
}

// csvImages extracts RELATED_IMAGE_* env var values and container images
// from the CSV's deployment specs.
func csvImages(c *csv) (relatedImages, containerImages map[string]bool) {
relatedImages = make(map[string]bool)
containerImages = make(map[string]bool)
for _, dep := range c.Spec.Install.Spec.Deployments {
for _, container := range dep.Spec.Template.Spec.Containers {
containerImages[container.Image] = true
for _, env := range container.Env {
if strings.HasPrefix(env.Name, relatedImagePrefix) {
relatedImages[env.Value] = true
}
}
}
}
return
}

// irImages extracts the set of image references from image-references tags.
func irImages(ir *imageReferencesFile) map[string]bool {
images := make(map[string]bool, len(ir.Spec.Tags))
for _, tag := range ir.Spec.Tags {
images[tag.From.Name] = true
}
return images
}

// ValidateImageReferencesTagVersion checks that every image tag uses the
// expected release version (e.g. ":oadp-1.6"), preventing accidental use
// of tags from a different release stream.
func ValidateImageReferencesTagVersion(imageRefsData []byte, expectedVersion string, exceptions []string) []error {
ir, err := parseImageReferences(imageRefsData)
if err != nil {
return []error{err}
}

skip := make(map[string]bool, len(exceptions))
for _, name := range exceptions {
skip[name] = true
}

expectedSuffix := ":" + expectedVersion
var errs []error
for _, tag := range ir.Spec.Tags {
if skip[tag.Name] {
continue
}
if !strings.HasSuffix(tag.From.Name, expectedSuffix) {
errs = append(errs, fmt.Errorf("image-references tag %q has image %q which does not end with %q", tag.Name, tag.From.Name, expectedSuffix))
}
}
return errs
}

// ValidateImageReferencesMatchCSV ensures every image in image-references has
// a corresponding RELATED_IMAGE_* env var (or is a container image) in the CSV.
// This catches images added to image-references but not wired into the operator.
func ValidateImageReferencesMatchCSV(imageRefsData, csvData []byte) []error {
ir, err := parseImageReferences(imageRefsData)
if err != nil {
return []error{err}
}

c, err := parseCSV(csvData)
if err != nil {
return []error{err}
}

relatedImages, containerImages := csvImages(c)

var errs []error
for _, tag := range ir.Spec.Tags {
dockerImage := tag.From.Name
if containerImages[dockerImage] {
continue
}
if !relatedImages[dockerImage] {
errs = append(errs, fmt.Errorf("image-references tag %q has image %q which is not in CSV RELATED_IMAGE_* env vars", tag.Name, dockerImage))
}
}
return errs
}

// ValidateCSVMatchImageReferences ensures every RELATED_IMAGE_* env var in the
// CSV has a corresponding entry in image-references. This catches orphaned env
// vars that reference images no longer tracked in image-references.
func ValidateCSVMatchImageReferences(imageRefsData, csvData []byte) []error {
ir, err := parseImageReferences(imageRefsData)
if err != nil {
return []error{err}
}

c, err := parseCSV(csvData)
if err != nil {
return []error{err}
}

known := irImages(ir)
relatedImages, _ := csvImages(c)

var errs []error
for image := range relatedImages {
if !known[image] {
errs = append(errs, fmt.Errorf("CSV RELATED_IMAGE_* has image %q which is not in image-references", image))
}
}
return errs
}
Loading