From 186b8209bd439c8d7dee37c027f52ce3a3347d08 Mon Sep 17 00:00:00 2001 From: Andrew Pantuso Date: Wed, 28 Sep 2022 14:12:57 -0400 Subject: [PATCH] fix: quarantine opm apis --- cmd/mtcli/list/bundles/cmd.go | 8 +- pkg/extractor/bundle.go | 85 ++---- pkg/extractor/bundle_cache.go | 8 +- pkg/extractor/bundle_test.go | 17 +- pkg/extractor/bundles_benchmark_test.go | 90 ------- pkg/extractor/extractor.go | 10 +- pkg/extractor/extractor_test.go | 4 +- pkg/extractor/interfaces.go | 8 +- pkg/operator/bundle.go | 241 ++++++++++++++++++ pkg/types/extractor.go | 6 - pkg/types/validators.go | 6 +- pkg/utils/bundle_utils.go | 16 -- pkg/utils/csvutils/csv_rbac_utils.go | 30 +-- pkg/validator/am0001/default_channel.go | 18 +- pkg/validator/am0001/default_channel_test.go | 20 +- pkg/validator/am0003/operator_name.go | 23 +- pkg/validator/am0003/operator_name_test.go | 12 +- pkg/validator/am0007/csv_install_modes.go | 31 +-- .../am0007/csv_install_modes_test.go | 12 +- pkg/validator/am0012/csv_rbac.go | 15 +- pkg/validator/am0015/csv_deployments.go | 24 +- pkg/validator/am0015/csv_deployments_test.go | 12 +- pkg/validator/latest_bundle.go | 49 ---- pkg/validator/testutils/bundle_loader.go | 11 +- 24 files changed, 358 insertions(+), 398 deletions(-) delete mode 100644 pkg/extractor/bundles_benchmark_test.go create mode 100644 pkg/operator/bundle.go delete mode 100644 pkg/utils/bundle_utils.go delete mode 100644 pkg/validator/latest_bundle.go diff --git a/cmd/mtcli/list/bundles/cmd.go b/cmd/mtcli/list/bundles/cmd.go index ac0c2301..e15a9fb8 100644 --- a/cmd/mtcli/list/bundles/cmd.go +++ b/cmd/mtcli/list/bundles/cmd.go @@ -38,11 +38,9 @@ func run(cmd *cobra.Command, args []string) error { var operatorVersionedNames []string for _, bundle := range allBundles { - csv, err := bundle.ClusterServiceVersion() - if err != nil { - return fmt.Errorf("extracting version info for bundle %q: %w", bundle.Name, err) - } - operatorVersionedNames = append(operatorVersionedNames, csv.GetName()) + csv := bundle.ClusterServiceVersion + + operatorVersionedNames = append(operatorVersionedNames, csv.Name) } fmt.Fprintln(os.Stdout, strings.Join(operatorVersionedNames, "\n")) diff --git a/pkg/extractor/bundle.go b/pkg/extractor/bundle.go index 831d95e5..7ff4702a 100644 --- a/pkg/extractor/bundle.go +++ b/pkg/extractor/bundle.go @@ -10,14 +10,11 @@ import ( "strings" "time" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/operator-framework/operator-registry/pkg/image" "github.com/operator-framework/operator-registry/pkg/image/containerdregistry" opmbundle "github.com/operator-framework/operator-registry/pkg/lib/bundle" - "github.com/operator-framework/operator-registry/pkg/registry" "github.com/sirupsen/logrus" - "gopkg.in/yaml.v2" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - k8syaml "k8s.io/apimachinery/pkg/util/yaml" ) // BundleCache provides a cache of OPM bundles which are referenced by @@ -26,10 +23,10 @@ type BundleCache interface { // GetBundle returns a bundle for the given image. An error is // returned if the bundle cannot be retrieved or the data is // corrupted. - GetBundle(img string) (*registry.Bundle, error) + GetBundle(img string) (*operator.Bundle, error) // SetBundle caches a bundle for the given image. An error // is returned if the bundle cannot be cached. - SetBundle(img string, bundle registry.Bundle) error + SetBundle(img string, bundle operator.Bundle) error } type DefaultBundleExtractor struct { @@ -80,39 +77,40 @@ func WithBundleTimeout(timeout time.Duration) BundleExtractorOpt { } } -func (e *DefaultBundleExtractor) Extract(ctx context.Context, bundleImage string) (*registry.Bundle, error) { - bundle, err := e.Cache.GetBundle(bundleImage) +func (e *DefaultBundleExtractor) Extract(ctx context.Context, bundleImage string) (operator.Bundle, error) { + cachedBundle, err := e.Cache.GetBundle(bundleImage) if err != nil { e.Log.Warnf("retrieving bundle %q from cache: %w", bundleImage, err) } - if bundle != nil { - e.Log.Debugf("cache hit for '%s'", bundleImage) - return bundle, nil + if cachedBundle != nil { + e.Log.Debugf("cache hit for %q", bundleImage) + return *cachedBundle, nil } e.Log.Debugf("cache miss for '%s'", bundleImage) tmpDirs, err := createTempDirs() if err != nil { - return nil, err + return operator.Bundle{}, err } defer func() { if err := tmpDirs.CleanUp(); err != nil { - e.Log.Errorf("failed to cleanup tmpDirs: %w", err) + e.Log.Errorf("cleaning up tmpDirs: %w", err) } }() if err := e.unpackAndValidateBundle(ctx, bundleImage, tmpDirs); err != nil { - return nil, fmt.Errorf("failed to unpack and validate bundle: %w", err) + return operator.Bundle{}, fmt.Errorf("unpacking and validating bundle: %w", err) } - bundle, err = e.loadBundle(tmpDirs["bundle"]) + bundle, err := operator.NewBundleFromDirectory(tmpDirs["bundle"]) if err != nil { - return nil, err + return operator.Bundle{}, err } + bundle.BundleImage = bundleImage // not set by OPM - if err := e.Cache.SetBundle(bundleImage, *bundle); err != nil { + if err := e.Cache.SetBundle(bundleImage, bundle); err != nil { e.Log.Warnf("caching bundle %q: %w", bundleImage, err) } @@ -173,59 +171,6 @@ func (e *DefaultBundleExtractor) ValidateBundle(registry *containerdregistry.Reg return nil } -func (e *DefaultBundleExtractor) loadBundle(tmpDir string) (*registry.Bundle, error) { - e.Log.Debugf("loading the bundle from tmpDir: %s", tmpDir) - unstObjs, err := readAllManifests(filepath.Join(tmpDir, opmbundle.ManifestsDir)) - if err != nil { - return nil, err - } - annotations, err := readAnnotations(filepath.Join(tmpDir, opmbundle.MetadataDir)) - if err != nil { - return nil, err - } - return registry.NewBundle(annotations.PackageName, annotations, unstObjs...), nil -} - -func readAllManifests(manifestsDir string) ([]*unstructured.Unstructured, error) { - unstObjs := []*unstructured.Unstructured{} - items, err := ioutil.ReadDir(manifestsDir) - if err != nil { - return nil, err - } - - for _, item := range items { - path := filepath.Join(manifestsDir, item.Name()) - data, err := ioutil.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("unable to read file %s, got %w", path, err) - } - - dec := k8syaml.NewYAMLOrJSONDecoder(strings.NewReader(string(data)), 30) - k8sFile := &unstructured.Unstructured{} - if err = dec.Decode(k8sFile); err != nil { - return nil, fmt.Errorf("unable to decode file %s, got %w", path, err) - } - - unstObjs = append(unstObjs, k8sFile) - } - return unstObjs, nil -} - -func readAnnotations(metadataDir string) (*registry.Annotations, error) { - path := filepath.Join(metadataDir, opmbundle.AnnotationsFile) - content, err := ioutil.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("unable to read file '%s': %w", path, err) - } - - var annotationsFile registry.AnnotationsFile - if err = yaml.Unmarshal(content, &annotationsFile); err != nil { - return nil, fmt.Errorf("unable to unmarshal file '%s': %w", path, err) - } - - return &annotationsFile.Annotations, nil -} - type tempDirs map[string]string func createTempDirs() (tempDirs, error) { diff --git a/pkg/extractor/bundle_cache.go b/pkg/extractor/bundle_cache.go index 04edaa50..b6f988fc 100644 --- a/pkg/extractor/bundle_cache.go +++ b/pkg/extractor/bundle_cache.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" ) // NewBundleCacheImpl returns an initialized BundleCacheImpl. A @@ -27,13 +27,13 @@ type BundleCacheImpl struct { var ErrInvalidBundleData = errors.New("invalid bundle data") -func (c *BundleCacheImpl) GetBundle(img string) (*registry.Bundle, error) { +func (c *BundleCacheImpl) GetBundle(img string) (*operator.Bundle, error) { data, ok := c.cfg.Store.Read(img) if !ok { return nil, nil } - bundle, ok := data.(registry.Bundle) + bundle, ok := data.(operator.Bundle) if !ok { return nil, ErrInvalidBundleData } @@ -41,7 +41,7 @@ func (c *BundleCacheImpl) GetBundle(img string) (*registry.Bundle, error) { return &bundle, nil } -func (c *BundleCacheImpl) SetBundle(img string, bundle registry.Bundle) error { +func (c *BundleCacheImpl) SetBundle(img string, bundle operator.Bundle) error { if err := c.cfg.Store.Write(img, bundle); err != nil { return fmt.Errorf("writing bundle data: %w", err) } diff --git a/pkg/extractor/bundle_test.go b/pkg/extractor/bundle_test.go index fdbea74b..7a36d4ed 100644 --- a/pkg/extractor/bundle_test.go +++ b/pkg/extractor/bundle_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -55,7 +55,7 @@ func TestDefaultBundleExtractor(t *testing.T) { cachedBundle, err := cache.GetBundle(tc.BundleImage) require.NoError(t, err) - tc.AssertExpectations(t, cachedBundle) + tc.AssertExpectations(t, *cachedBundle) }) } } @@ -67,7 +67,7 @@ type testCase struct { ExpectedCSVVersion string } -func (tc testCase) AssertExpectations(t *testing.T, b *registry.Bundle) { +func (tc testCase) AssertExpectations(t *testing.T, b operator.Bundle) { t.Helper() assert.Equal(t, b.Name, tc.ExpectedPackageName) @@ -75,14 +75,7 @@ func (tc testCase) AssertExpectations(t *testing.T, b *registry.Bundle) { assert.NotNil(t, b.Annotations) assert.Equal(t, b.Annotations.PackageName, tc.ExpectedPackageName) - csv, err := b.ClusterServiceVersion() - require.NoError(t, err) - require.NotNil(t, csv) + assert.Equal(t, b.ClusterServiceVersion.Name, tc.ExpectedCSVName) - assert.Equal(t, csv.Name, tc.ExpectedCSVName) - - version, err := csv.GetVersion() - require.NoError(t, err) - - assert.Equal(t, version, tc.ExpectedCSVVersion) + assert.Equal(t, b.Version, tc.ExpectedCSVVersion) } diff --git a/pkg/extractor/bundles_benchmark_test.go b/pkg/extractor/bundles_benchmark_test.go deleted file mode 100644 index 74d6f070..00000000 --- a/pkg/extractor/bundles_benchmark_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package extractor_test - -import ( - "path" - "testing" - - "github.com/mt-sre/addon-metadata-operator/internal/testutils" - "github.com/operator-framework/operator-registry/pkg/registry" - "github.com/stretchr/testify/require" -) - -/* - This is to experiment what is most efficient between []*registry.Bundle and - []registry.Bundle. As the registry.Bundle struct is massive, it is important - to benchmark our various use cases. -*/ - -const ( - benchmarkBundleName = "benchmarkBundle" - nBundles = 10 -) - -var bundlePath = path.Join( - testutils.RootDir().TestData().Bundles(), "reference-addon", - "main", "0.1.6", "manifests", "reference-addon.csv.yaml", -) - -type metaBundleByReference struct { - Bundles []*registry.Bundle -} - -// benchmark bundles workflow using *registry.Bundle{} -func BenchmarkBundlesByReference(b *testing.B) { - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - bundles := make([]*registry.Bundle, nBundles) // pre-allocate - for j := 0; j < nBundles; j++ { - bundle, err := testutils.NewBundle(benchmarkBundleName, bundlePath) - require.NoError(b, err) - bundles[j] = bundle - } - require.Equal(b, len(bundles), nBundles) - mb := &metaBundleByReference{Bundles: bundles} - handleBundlesByReference(b, mb) - } -} - -func handleBundlesByReference(b *testing.B, mb *metaBundleByReference) { - for _, bundle := range mb.Bundles { - bundleName := getBundleNameByReference(bundle) - require.Equal(b, bundleName, benchmarkBundleName) - } -} - -func getBundleNameByReference(bundle *registry.Bundle) string { - return bundle.Name -} - -type metaBundleByValue struct { - Bundles []registry.Bundle -} - -// benchmark bundles workflow using registry.Bundle{} -func BenchmarkBundlesByValue(b *testing.B) { - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - bundles := make([]registry.Bundle, nBundles) // pre-allocate - for j := 0; j < nBundles; j++ { - bundle, err := testutils.NewBundle(benchmarkBundleName, bundlePath) - require.NoError(b, err) - bundles[j] = *bundle - } - require.Equal(b, len(bundles), nBundles) - mb := &metaBundleByValue{Bundles: bundles} - handleBundlesByValue(b, mb) - } -} - -func handleBundlesByValue(b *testing.B, mb *metaBundleByValue) { - for _, bundle := range mb.Bundles { - bundleName := getBundleNameByValue(bundle) - require.Equal(b, bundleName, benchmarkBundleName) - } -} - -func getBundleNameByValue(bundle registry.Bundle) string { - return bundle.Name -} diff --git a/pkg/extractor/extractor.go b/pkg/extractor/extractor.go index 3333e893..afb6b03c 100644 --- a/pkg/extractor/extractor.go +++ b/pkg/extractor/extractor.go @@ -6,8 +6,8 @@ import ( "fmt" "strings" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" imageparser "github.com/novln/docker-parser" - "github.com/operator-framework/operator-registry/pkg/registry" "github.com/sirupsen/logrus" "golang.org/x/sync/errgroup" ) @@ -66,7 +66,7 @@ func WithLog(log logrus.FieldLogger) MainExtractorOpt { } // ExtractBundles - extract bundles from indexImage matching pkgName -func (e *MainExtractor) ExtractBundles(indexImage string, pkgName string) ([]*registry.Bundle, error) { +func (e *MainExtractor) ExtractBundles(indexImage string, pkgName string) ([]operator.Bundle, error) { if err := validateIndexImage(indexImage); err != nil { if errors.Is(err, ErrTaglessImage) { e.Log.Info("skipping tagless image, nothing to extract") @@ -92,7 +92,7 @@ func (e *MainExtractor) ExtractBundles(indexImage string, pkgName string) ([]*re } // ExtractAllBundles - extract bundles for all packages from indexImage -func (e *MainExtractor) ExtractAllBundles(indexImage string) ([]*registry.Bundle, error) { +func (e *MainExtractor) ExtractAllBundles(indexImage string) ([]operator.Bundle, error) { if err := validateIndexImage(indexImage); err != nil { if errors.Is(err, ErrTaglessImage) { e.Log.Info("skipping tagless image, nothing to extract") @@ -111,8 +111,8 @@ func (e *MainExtractor) ExtractAllBundles(indexImage string) ([]*registry.Bundle return e.extractBundlesConcurrent(bundleImages) } -func (e *MainExtractor) extractBundlesConcurrent(bundleImages []string) ([]*registry.Bundle, error) { - res := make([]*registry.Bundle, len(bundleImages)) +func (e *MainExtractor) extractBundlesConcurrent(bundleImages []string) ([]operator.Bundle, error) { + res := make([]operator.Bundle, len(bundleImages)) g := new(errgroup.Group) // we need the global context to be able to cancel all goroutines diff --git a/pkg/extractor/extractor_test.go b/pkg/extractor/extractor_test.go index 5931b1a9..45798cdb 100644 --- a/pkg/extractor/extractor_test.go +++ b/pkg/extractor/extractor_test.go @@ -3,7 +3,7 @@ package extractor import ( "testing" - "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/stretchr/testify/require" ) @@ -45,7 +45,7 @@ func TestMainExtractorWithDefaultValues(t *testing.T) { t.Run(tc.indexImage, func(t *testing.T) { t.Parallel() - var bundles []*registry.Bundle + var bundles []operator.Bundle var err error if tc.pkgName == "" { diff --git a/pkg/extractor/interfaces.go b/pkg/extractor/interfaces.go index 38a8264f..3677301a 100644 --- a/pkg/extractor/interfaces.go +++ b/pkg/extractor/interfaces.go @@ -3,7 +3,7 @@ package extractor import ( "context" - "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" ) // Extractor - utilizes both the indexExtractor and bundleExtractor to first extract @@ -11,9 +11,9 @@ import ( // bundles from those underlying bundleImages. type Extractor interface { // extract all bundles from indexImage matching pkgName - ExtractBundles(indexImage string, pkgName string) ([]*registry.Bundle, error) + ExtractBundles(indexImage string, pkgName string) ([]operator.Bundle, error) // extract all bundles from indexImage, for all packages - ExtractAllBundles(indexImage string) ([]*registry.Bundle, error) + ExtractAllBundles(indexImage string) ([]operator.Bundle, error) } // Choosing to list explicitly that the indexExtractor works with BundleImages @@ -34,5 +34,5 @@ type IndexExtractor interface { // format by OPM. // Bundle format: https://docs.openshift.com/container-platform/4.9/operators/understanding/olm-packaging-format.html#olm-bundle-format_olm-packaging-format type BundleExtractor interface { - Extract(ctx context.Context, bundleImage string) (*registry.Bundle, error) + Extract(ctx context.Context, bundleImage string) (operator.Bundle, error) } diff --git a/pkg/operator/bundle.go b/pkg/operator/bundle.go new file mode 100644 index 00000000..deb23af1 --- /dev/null +++ b/pkg/operator/bundle.go @@ -0,0 +1,241 @@ +package operator + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/blang/semver/v4" + opsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + opmbundle "github.com/operator-framework/operator-registry/pkg/lib/bundle" + "github.com/operator-framework/operator-registry/pkg/registry" + "gopkg.in/yaml.v2" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + k8syaml "k8s.io/apimachinery/pkg/util/yaml" +) + +func NewBundleFromDirectory(path string) (Bundle, error) { + unstObjs, err := readAllManifests(filepath.Join(path, opmbundle.ManifestsDir)) + if err != nil { + return Bundle{}, fmt.Errorf("reading manifests: %w", err) + } + + annotations, err := readAnnotations(filepath.Join(path, opmbundle.MetadataDir)) + if err != nil { + return Bundle{}, fmt.Errorf("reading annotations: %w", err) + } + + regBundle := registry.NewBundle(annotations.PackageName, annotations, unstObjs...) + bundle, err := NewBundleFromRegistryBundle(*regBundle) + if err != nil { + return Bundle{}, fmt.Errorf("generating bundle: %w", err) + } + + return bundle, nil +} + +func readAllManifests(manifestsDir string) ([]*unstructured.Unstructured, error) { + var objs []*unstructured.Unstructured + + items, err := os.ReadDir(manifestsDir) + if err != nil { + return nil, fmt.Errorf("reading manifests dir: %w", err) + } + + for _, item := range items { + path := filepath.Join(manifestsDir, item.Name()) + + manifest, err := readManifest(path) + if err != nil { + return nil, fmt.Errorf("reading manifest %q: %w", path, err) + } + + objs = append(objs, manifest) + } + return objs, nil +} + +func readManifest(path string) (*unstructured.Unstructured, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("reading file: %w", err) + } + + dec := k8syaml.NewYAMLOrJSONDecoder(strings.NewReader(string(data)), 30) + + var manifest unstructured.Unstructured + + if err = dec.Decode(&manifest); err != nil { + return nil, fmt.Errorf("decoding manifest: %w", err) + } + + return &manifest, nil +} + +func readAnnotations(metadataDir string) (*registry.Annotations, error) { + path := filepath.Join(metadataDir, opmbundle.AnnotationsFile) + + content, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("reading file %q: %w", path, err) + } + + var annotationsFile registry.AnnotationsFile + if err := yaml.Unmarshal(content, &annotationsFile); err != nil { + return nil, fmt.Errorf("unmarshalling file %q: %w", path, err) + } + + return &annotationsFile.Annotations, nil +} + +func NewBundleFromRegistryBundle(b registry.Bundle) (Bundle, error) { + var annotations Annotations + if as := b.Annotations; as != nil { + annotations = NewAnnotationsFromRegistryAnnotations(*as) + } + + ver, err := b.Version() + if err != nil { + return Bundle{}, fmt.Errorf("getting bundle version: %w", err) + } + + regCSV, err := b.ClusterServiceVersion() + if err != nil { + return Bundle{}, fmt.Errorf("getting bundle ClusterServiceVersion: %w", err) + } + + var csv ClusterServiceVersion + + if regCSV != nil { + csv, err = NewClusterServiceVersionfromRegistryCSV(*regCSV) + if err != nil { + return Bundle{}, fmt.Errorf("setting ClusterServiceVersion values: %w", err) + } + } + + return Bundle{ + Annotations: annotations, + Name: b.Name, + Package: b.Package, + Channels: b.Channels, + BundleImage: b.BundleImage, + Version: ver, + ClusterServiceVersion: csv, + }, nil +} + +type Bundle struct { + Annotations Annotations + ClusterServiceVersion ClusterServiceVersion + BundleImage string + Channels []string + Name string + Package string + Version string +} + +func (b *Bundle) GetNameVersion() string { + return fmt.Sprintf("%s:%s", b.Name, b.Version) +} + +func NewAnnotationsFromRegistryAnnotations(as registry.Annotations) Annotations { + return Annotations{ + PackageName: as.PackageName, + Channels: strings.Split(as.Channels, ","), + DefaultChannelName: as.DefaultChannelName, + } +} + +type Annotations struct { + PackageName string + Channels []string + DefaultChannelName string +} + +func NewClusterServiceVersionfromRegistryCSV(csv registry.ClusterServiceVersion) (ClusterServiceVersion, error) { + var spec opsv1alpha1.ClusterServiceVersionSpec + if err := json.Unmarshal(csv.Spec, &spec); err != nil { + return ClusterServiceVersion{}, fmt.Errorf("unmarshalling csv spec: %w", err) + } + + owned, required, err := csv.GetCustomResourceDefintions() + if err != nil { + return ClusterServiceVersion{}, fmt.Errorf("getting CustomResourceDefinitions: %w", err) + } + + ownedCRDs := make([]CustomResourceDefinition, 0, len(owned)) + for _, key := range owned { + if key == nil { + continue + } + + ownedCRDs = append(ownedCRDs, NewCustomeResourceDefinitionFromRegistryDefinitionKey(*key)) + } + + requiredCRDs := make([]CustomResourceDefinition, 0, len(required)) + for _, key := range required { + if key == nil { + continue + } + + requiredCRDs = append(requiredCRDs, NewCustomeResourceDefinitionFromRegistryDefinitionKey(*key)) + } + + return ClusterServiceVersion{ + Name: csv.Name, + OwnedCustomResourceDefinitions: ownedCRDs, + RequiredCustomResourceDefinitions: requiredCRDs, + Spec: spec, + }, nil +} + +type ClusterServiceVersion struct { + Name string + OwnedCustomResourceDefinitions []CustomResourceDefinition + RequiredCustomResourceDefinitions []CustomResourceDefinition + Spec opsv1alpha1.ClusterServiceVersionSpec +} + +func NewCustomeResourceDefinitionFromRegistryDefinitionKey(key registry.DefinitionKey) CustomResourceDefinition { + return CustomResourceDefinition{ + Name: key.Name, + Group: key.Group, + Kind: key.Kind, + Version: key.Version, + } +} + +type CustomResourceDefinition struct { + Name string + Group, Kind, Version string +} + +func HeadBundle(bundles ...Bundle) (Bundle, bool) { + if len(bundles) < 1 { + return Bundle{}, false + } + + if len(bundles) == 1 { + return bundles[0], true + } + + ordered := OrderedBundles(bundles) + + sort.Sort(ordered) + + return ordered[0], true +} + +type OrderedBundles []Bundle + +func (l OrderedBundles) Len() int { return len(l) } +func (l OrderedBundles) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l OrderedBundles) Less(i, j int) bool { + iVer, _ := semver.ParseTolerant(l[i].Version) + jVer, _ := semver.ParseTolerant(l[j].Version) + + return jVer.LE(iVer) // reverse sort +} diff --git a/pkg/types/extractor.go b/pkg/types/extractor.go index 19a4d698..d5abb4ba 100644 --- a/pkg/types/extractor.go +++ b/pkg/types/extractor.go @@ -1,7 +1,5 @@ package types -import "github.com/operator-framework/operator-registry/pkg/registry" - type IndexImageExtractor interface { ExtractBundlesFromImage(indexImage string, extractTo string) error CacheKey(indexImage, addonName string) string @@ -11,7 +9,3 @@ type IndexImageExtractor interface { CacheLocation() string WriteToCache(value string) error } - -type BundleParser interface { - ParseBundles(addonName string, manifestsPath string) ([]registry.Bundle, error) -} diff --git a/pkg/types/validators.go b/pkg/types/validators.go index c2af7f12..397c96c7 100644 --- a/pkg/types/validators.go +++ b/pkg/types/validators.go @@ -2,15 +2,15 @@ package types import ( "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" - "github.com/operator-framework/operator-registry/pkg/registry" + op "github.com/mt-sre/addon-metadata-operator/pkg/operator" ) type MetaBundle struct { AddonMeta *v1alpha1.AddonMetadataSpec - Bundles []*registry.Bundle + Bundles []op.Bundle } -func NewMetaBundle(addonMeta *v1alpha1.AddonMetadataSpec, bundles []*registry.Bundle) *MetaBundle { +func NewMetaBundle(addonMeta *v1alpha1.AddonMetadataSpec, bundles []op.Bundle) *MetaBundle { return &MetaBundle{ AddonMeta: addonMeta, Bundles: bundles, diff --git a/pkg/utils/bundle_utils.go b/pkg/utils/bundle_utils.go deleted file mode 100644 index 191c8240..00000000 --- a/pkg/utils/bundle_utils.go +++ /dev/null @@ -1,16 +0,0 @@ -package utils - -import ( - "fmt" - - "github.com/operator-framework/operator-registry/pkg/registry" -) - -// GetBundleNameVersion - useful for validation error reporting -func GetBundleNameVersion(b *registry.Bundle) (string, error) { - version, err := b.Version() - if err != nil { - return "", err - } - return fmt.Sprintf("%v:%v", b.Name, version), nil -} diff --git a/pkg/utils/csvutils/csv_rbac_utils.go b/pkg/utils/csvutils/csv_rbac_utils.go index bd338eab..3122859d 100644 --- a/pkg/utils/csvutils/csv_rbac_utils.go +++ b/pkg/utils/csvutils/csv_rbac_utils.go @@ -1,13 +1,12 @@ package csvutils import ( - "encoding/json" "strings" "unicode" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" operatorv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/operator-framework/operator-registry/pkg/registry" rbac "k8s.io/api/rbac/v1" ) @@ -83,27 +82,20 @@ func WildCardResourcePresent(csvPermissions *types.CSVPermissions, ownedApis []s return len(matchedRules) > 0 } -func GetApisOwned(csv *registry.ClusterServiceVersion) ([]string, error) { - ownedApis, _, err := csv.GetCustomResourceDefintions() - if err != nil { - return nil, err - } - result := make([]string, 0) - for _, api := range ownedApis { - if api != nil { - result = append(result, trimWhiteSpace(api.Group)) - } +func GetApisOwned(csv operator.ClusterServiceVersion) ([]string, error) { + ownedAPIs := csv.OwnedCustomResourceDefinitions + + result := make([]string, 0, len(ownedAPIs)) + for _, api := range ownedAPIs { + result = append(result, trimWhiteSpace(api.Group)) } + return result, nil } -func GetPermissions(csv *registry.ClusterServiceVersion) (*types.CSVPermissions, error) { - var csvSpec operatorv1alpha1.ClusterServiceVersionSpec - if err := json.Unmarshal(csv.Spec, &csvSpec); err != nil { - return nil, err - } - clusterPermissions := csvSpec.InstallStrategy.StrategySpec.ClusterPermissions - permissions := csvSpec.InstallStrategy.StrategySpec.Permissions +func GetPermissions(csv operator.ClusterServiceVersion) (*types.CSVPermissions, error) { + clusterPermissions := csv.Spec.InstallStrategy.StrategySpec.ClusterPermissions + permissions := csv.Spec.InstallStrategy.StrategySpec.Permissions return &types.CSVPermissions{ ClusterPermissions: operatorPermissions2LocalPermissions(clusterPermissions), diff --git a/pkg/validator/am0001/default_channel.go b/pkg/validator/am0001/default_channel.go index 20acf7f0..73c4edf6 100644 --- a/pkg/validator/am0001/default_channel.go +++ b/pkg/validator/am0001/default_channel.go @@ -3,12 +3,11 @@ package am0001 import ( "context" "fmt" - "strings" - "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" + opsv1alpha1 "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/validator" - "github.com/operator-framework/operator-registry/pkg/registry" ) func init() { @@ -75,7 +74,7 @@ func (d *DefaultChannel) isPartOfEnum(defaultChannel string) validator.Result { } // TODO - deprecate this when we remove legacy builds -func (d *DefaultChannel) isListedInChannels(channels *[]v1alpha1.Channel, defaultChannel string) validator.Result { +func (d *DefaultChannel) isListedInChannels(channels *[]opsv1alpha1.Channel, defaultChannel string) validator.Result { // as the Channels field is deprecated, it can be omitted if channels == nil { return d.Success() @@ -91,11 +90,12 @@ func (d *DefaultChannel) isListedInChannels(channels *[]v1alpha1.Channel, defaul return d.Fail(msg) } -func (d *DefaultChannel) matchesBundleChannelAnnotations(defaultChannel string, bundles []*registry.Bundle) validator.Result { +func (d *DefaultChannel) matchesBundleChannelAnnotations(defaultChannel string, bundles []operator.Bundle) validator.Result { var message []string - bundle, err := validator.GetLatestBundle(bundles) - if err != nil { - return d.Fail("Error while checking bundles") + + bundle, ok := operator.HeadBundle(bundles...) + if !ok { + return d.Success() } if bundle.Annotations.DefaultChannelName == "" && defaultChannel != "alpha" { @@ -110,7 +110,7 @@ func (d *DefaultChannel) matchesBundleChannelAnnotations(defaultChannel string, message = append(message, msg) } - channels := strings.Split(bundle.Annotations.Channels, ",") + channels := bundle.Annotations.Channels if !isPresentInBundleChannels(defaultChannel, channels) { msg := fmt.Sprintf("The defaultChannel '%v' is not present in annotation operators.operatorframework.io.bundle.channels.v1 '%v'.", diff --git a/pkg/validator/am0001/default_channel_test.go b/pkg/validator/am0001/default_channel_test.go index 3225002c..da9baf67 100644 --- a/pkg/validator/am0001/default_channel_test.go +++ b/pkg/validator/am0001/default_channel_test.go @@ -4,9 +4,9 @@ import ( "testing" "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/validator/testutils" - "github.com/operator-framework/operator-registry/pkg/registry" "github.com/stretchr/testify/require" ) @@ -69,11 +69,11 @@ func TestDefaultChannelInvalid(t *testing.T) { }, }, }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ { - Annotations: ®istry.Annotations{ + Annotations: operator.Annotations{ DefaultChannelName: "alpha", - Channels: "beta,stable,rc", + Channels: []string{"beta", "stable", "rc"}, }, }, }, @@ -88,11 +88,11 @@ func TestDefaultChannelInvalid(t *testing.T) { }, }, }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ { - Annotations: ®istry.Annotations{ + Annotations: operator.Annotations{ DefaultChannelName: "beta", - Channels: "beta,stable,rc,alpha", + Channels: []string{"beta", "stable", "rc", "alpha"}, }, }, }, @@ -107,11 +107,11 @@ func TestDefaultChannelInvalid(t *testing.T) { }, }, }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ { - Annotations: ®istry.Annotations{ + Annotations: operator.Annotations{ DefaultChannelName: "", - Channels: "stable,beta", + Channels: []string{"stable", "beta"}, }, }, }, diff --git a/pkg/validator/am0003/operator_name.go b/pkg/validator/am0003/operator_name.go index a0ea7e5c..b2dfe484 100644 --- a/pkg/validator/am0003/operator_name.go +++ b/pkg/validator/am0003/operator_name.go @@ -6,10 +6,9 @@ import ( "strings" "github.com/blang/semver/v4" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" - "github.com/mt-sre/addon-metadata-operator/pkg/utils" "github.com/mt-sre/addon-metadata-operator/pkg/validator" - "github.com/operator-framework/operator-registry/pkg/registry" ) const ( @@ -61,34 +60,22 @@ func (o *OperatorName) Run(ctx context.Context, mb types.MetaBundle) validator.R return o.Success() } -func validateBundle(bundle *registry.Bundle, operatorName string) ([]string, error) { +func validateBundle(bundle operator.Bundle, operatorName string) ([]string, error) { var msgs []string - nameVer, err := utils.GetBundleNameVersion(bundle) - if err != nil { - return nil, fmt.Errorf("retrieving bundle name and version: %w", err) - } - + nameVer := bundle.GetNameVersion() if bundle.Annotations.PackageName != operatorName { msgs = append(msgs, fmt.Sprintf( "bundle %q package annotation does not match operatorName %q", nameVer, operatorName, )) } - csv, err := bundle.ClusterServiceVersion() - if err != nil { - return nil, fmt.Errorf("retrieving csv: %w", err) - } - + csv := bundle.ClusterServiceVersion if msg := validateBundleIdentifier(csv.Name, operatorName); msg != "" { msgs = append(msgs, fmt.Sprintf("bundle %q failed validation on csv.Name: %s.", nameVer, msg)) } - replaces, err := csv.GetReplaces() - if err != nil { - return nil, fmt.Errorf("retrieving 'replaces' field from csv: %w", err) - } - + replaces := csv.Spec.Replaces if replaces != "" { if msg := validateBundleIdentifier(replaces, operatorName); msg != "" { msgs = append(msgs, fmt.Sprintf("bundle %q failed validation on csv.Replaces: %s.", nameVer, msg)) diff --git a/pkg/validator/am0003/operator_name_test.go b/pkg/validator/am0003/operator_name_test.go index 27d35b36..33b054d2 100644 --- a/pkg/validator/am0003/operator_name_test.go +++ b/pkg/validator/am0003/operator_name_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/validator/testutils" - "github.com/operator-framework/operator-registry/pkg/registry" ) func TestOperatorNameValid(t *testing.T) { @@ -21,7 +21,7 @@ func TestOperatorNameValid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_valid.yaml"), testutils.WithPackageName("reference-addon"), @@ -42,7 +42,7 @@ func TestOperatornameInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_valid.yaml"), testutils.WithPackageName("invalid"), @@ -53,7 +53,7 @@ func TestOperatornameInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_name_invalid.yaml"), testutils.WithPackageName("reference-addon"), @@ -64,7 +64,7 @@ func TestOperatornameInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_replaces_invalid.yaml"), testutils.WithPackageName("reference-addon"), @@ -75,7 +75,7 @@ func TestOperatornameInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_semver_invalid.yaml"), testutils.WithPackageName("reference-addon"), diff --git a/pkg/validator/am0007/csv_install_modes.go b/pkg/validator/am0007/csv_install_modes.go index 5f301911..524cf17e 100644 --- a/pkg/validator/am0007/csv_install_modes.go +++ b/pkg/validator/am0007/csv_install_modes.go @@ -2,14 +2,11 @@ package am0007 import ( "context" - "encoding/json" "fmt" "github.com/mt-sre/addon-metadata-operator/pkg/types" - "github.com/mt-sre/addon-metadata-operator/pkg/utils" "github.com/mt-sre/addon-metadata-operator/pkg/validator" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/operator-framework/operator-registry/pkg/registry" ) func init() { @@ -50,15 +47,12 @@ func (c *CSVInstallModes) Run(ctx context.Context, mb types.MetaBundle) validato } for _, bundle := range mb.Bundles { - bundleName, err := utils.GetBundleNameVersion(bundle) - if err != nil { - return c.Error(err) - } - spec, err := extractCSVSpec(bundle) - if err != nil { - return c.Error(fmt.Errorf("unable to extract CSV for %v: %w", bundleName, err)) - } - if success, failureMsg := isInstallModeSupported(spec.InstallModes, installMode); !success { + var ( + bundleName = bundle.GetNameVersion() + modes = bundle.ClusterServiceVersion.Spec.InstallModes + ) + + if success, failureMsg := isInstallModeSupported(modes, installMode); !success { return c.Fail(fmt.Sprintf("Bundle %v failed CSV validation: %v.", bundleName, failureMsg)) } } @@ -86,19 +80,6 @@ type CSVSpec struct { InstallModes []operatorsv1alpha1.InstallMode `json:"installModes"` } -func extractCSVSpec(b *registry.Bundle) (*CSVSpec, error) { - csv, err := b.ClusterServiceVersion() - if err != nil { - return nil, err - } - var res CSVSpec - if err := json.Unmarshal(csv.Spec, &res); err != nil { - return nil, err - } - - return &res, nil -} - var validInstallModes = []string{"AllNamespaces", "OwnNamespace"} func indexOf(element string, data []string) int { diff --git a/pkg/validator/am0007/csv_install_modes_test.go b/pkg/validator/am0007/csv_install_modes_test.go index 6c3bff46..0c595994 100644 --- a/pkg/validator/am0007/csv_install_modes_test.go +++ b/pkg/validator/am0007/csv_install_modes_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/validator/testutils" - "github.com/operator-framework/operator-registry/pkg/registry" "github.com/stretchr/testify/require" ) @@ -24,7 +24,7 @@ func TestCSVInstallModeValid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ InstallMode: "OwnNamespace", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV(filepath.Join("test_csvs", "csv.yaml")), }, }, @@ -32,7 +32,7 @@ func TestCSVInstallModeValid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ InstallMode: "AllNamespaces", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV(filepath.Join("test_csvs", "csv.yaml")), }, }, @@ -55,7 +55,7 @@ func TestCSVInstallModeInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ InstallMode: "something", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV(filepath.Join("test_csvs", "csv.yaml")), }, }, @@ -63,7 +63,7 @@ func TestCSVInstallModeInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ InstallMode: "SingleNamespace", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV(filepath.Join("test_csvs", "csv.yaml")), }, }, @@ -71,7 +71,7 @@ func TestCSVInstallModeInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ InstallMode: "MultiNamespace", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV(filepath.Join("test_csvs", "csv.yaml")), }, }, diff --git a/pkg/validator/am0012/csv_rbac.go b/pkg/validator/am0012/csv_rbac.go index 561d47f4..ff726686 100644 --- a/pkg/validator/am0012/csv_rbac.go +++ b/pkg/validator/am0012/csv_rbac.go @@ -4,6 +4,7 @@ import ( "context" "strings" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/utils/csvutils" "github.com/mt-sre/addon-metadata-operator/pkg/validator" @@ -39,21 +40,13 @@ type CSVRBAC struct { } func (v *CSVRBAC) Run(ctx context.Context, mb types.MetaBundle) validator.Result { - // Guard against addons which do not have bundles yet - if len(mb.Bundles) == 0 { + bundle, ok := operator.HeadBundle(mb.Bundles...) + if !ok { return v.Success() } - // Only run validations on the latest bundle - latestBundle, err := validator.GetLatestBundle(mb.Bundles) - if err != nil { - return v.Error(err) - } + csv := bundle.ClusterServiceVersion - csv, err := latestBundle.ClusterServiceVersion() - if err != nil { - return v.Error(err) - } apisOwnedByOperator, err := csvutils.GetApisOwned(csv) if err != nil { return v.Error(err) diff --git a/pkg/validator/am0015/csv_deployments.go b/pkg/validator/am0015/csv_deployments.go index d79200b6..ae684894 100644 --- a/pkg/validator/am0015/csv_deployments.go +++ b/pkg/validator/am0015/csv_deployments.go @@ -2,12 +2,11 @@ package am0015 import ( "context" - "encoding/json" "github.com/mt-sre/addon-metadata-operator/internal/kube" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/validator" - operatorv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" appsv1 "k8s.io/api/apps/v1" ) @@ -42,28 +41,17 @@ type CSVDeployment struct { linter kube.DeploymentLinter } -type Spec struct { - InstallStrategy operatorv1alpha1.NamedInstallStrategy `json:"install"` -} - func (c *CSVDeployment) Run(ctx context.Context, mb types.MetaBundle) validator.Result { var msgs []string - var spec Spec - bundle, err := validator.GetLatestBundle(mb.Bundles) - if err != nil { - c.Fail("Error while checking bundles") - } - csv, err := bundle.ClusterServiceVersion() - if err != nil { - c.Error(err) + bundle, ok := operator.HeadBundle(mb.Bundles...) + if !ok { + return c.Success() } - if err := json.Unmarshal(csv.Spec, &spec); err != nil { - c.Error(err) - } + csv := bundle.ClusterServiceVersion - for _, deploymentSpec := range spec.InstallStrategy.StrategySpec.DeploymentSpecs { + for _, deploymentSpec := range csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs { deployment := appsv1.Deployment{Spec: deploymentSpec.Spec} res := c.linter.Lint(deployment) if !res.Success { diff --git a/pkg/validator/am0015/csv_deployments_test.go b/pkg/validator/am0015/csv_deployments_test.go index 2be89c5c..c8644390 100644 --- a/pkg/validator/am0015/csv_deployments_test.go +++ b/pkg/validator/am0015/csv_deployments_test.go @@ -5,9 +5,9 @@ import ( "testing" "github.com/mt-sre/addon-metadata-operator/api/v1alpha1" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/mt-sre/addon-metadata-operator/pkg/types" "github.com/mt-sre/addon-metadata-operator/pkg/validator/testutils" - "github.com/operator-framework/operator-registry/pkg/registry" ) func TestCSVDeploymentValid(t *testing.T) { @@ -21,7 +21,7 @@ func TestCSVDeploymentValid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_valid.yaml"), ), @@ -41,7 +41,7 @@ func TestCSVDeploymentInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_invalid_livenessprobe.yaml"), ), @@ -51,7 +51,7 @@ func TestCSVDeploymentInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_invalid_readinessprobe.yaml"), ), @@ -61,7 +61,7 @@ func TestCSVDeploymentInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_invalid_memory_requirement.yaml"), ), @@ -71,7 +71,7 @@ func TestCSVDeploymentInvalid(t *testing.T) { AddonMeta: &v1alpha1.AddonMetadataSpec{ OperatorName: "reference-addon", }, - Bundles: []*registry.Bundle{ + Bundles: []operator.Bundle{ loader.LoadFromCSV( filepath.Join("test_csvs", "csv_invalid_cpu_requirement.yaml"), ), diff --git a/pkg/validator/latest_bundle.go b/pkg/validator/latest_bundle.go deleted file mode 100644 index f07c84cc..00000000 --- a/pkg/validator/latest_bundle.go +++ /dev/null @@ -1,49 +0,0 @@ -package validator - -import ( - "fmt" - - "github.com/operator-framework/operator-registry/pkg/registry" - "golang.org/x/mod/semver" -) - -func GetLatestBundle(bundles []*registry.Bundle) (*registry.Bundle, error) { - if len(bundles) == 1 { - return bundles[0], nil - } - - latest := bundles[0] - for _, bundle := range bundles[1:] { - currVersion, err := getVersion(bundle) - if err != nil { - return nil, err - } - currLatestVersion, err := getVersion(latest) - if err != nil { - return nil, err - } - - res := semver.Compare(currVersion, currLatestVersion) - // If currVersion is greater than currLatestVersion - if res == 1 { - latest = bundle - } - } - return latest, nil -} - -func getVersion(bundle *registry.Bundle) (string, error) { - csv, err := bundle.ClusterServiceVersion() - if err != nil { - return "", err - } - - version, err := csv.GetVersion() - if err != nil { - return "", err - } - - // Prefix a `v` infront of the version - // so that semver package can parse it. - return fmt.Sprintf("v%s", version), nil -} diff --git a/pkg/validator/testutils/bundle_loader.go b/pkg/validator/testutils/bundle_loader.go index bb7ae59c..e101dcc0 100644 --- a/pkg/validator/testutils/bundle_loader.go +++ b/pkg/validator/testutils/bundle_loader.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/mt-sre/addon-metadata-operator/internal/testutils" - "github.com/operator-framework/operator-registry/pkg/registry" + "github.com/mt-sre/addon-metadata-operator/pkg/operator" "github.com/stretchr/testify/require" ) @@ -18,7 +18,7 @@ type BundleLoader struct { t *testing.T } -func (l *BundleLoader) LoadFromCSV(path string, opts ...LoadOption) *registry.Bundle { +func (l *BundleLoader) LoadFromCSV(path string, opts ...LoadOption) operator.Bundle { l.t.Helper() var cfg loadConfig @@ -26,13 +26,16 @@ func (l *BundleLoader) LoadFromCSV(path string, opts ...LoadOption) *registry.Bu cfg.Option(opts...) cfg.Default() - bundle, err := testutils.NewBundle(cfg.BundleName, path) + regBundle, err := testutils.NewBundle(cfg.BundleName, path) require.NoError(l.t, err) if cfg.PackageName != "" { - bundle.Annotations.PackageName = cfg.PackageName + regBundle.Annotations.PackageName = cfg.PackageName } + bundle, err := operator.NewBundleFromRegistryBundle(*regBundle) + require.NoError(l.t, err) + return bundle }