From 8a23cd955765efc5a96759dba98b0d004aac5239 Mon Sep 17 00:00:00 2001 From: Mikalai Radchuk Date: Tue, 31 Oct 2023 16:17:52 +0000 Subject: [PATCH] Clean up the variable source code Signed-off-by: Mikalai Radchuk --- internal/resolution/variablesources/bundle.go | 52 --- .../variablesources/bundle_deployment.go | 58 --- .../variablesources/bundle_deployment_test.go | 146 ------- .../variablesources/bundle_provider.go | 14 - .../resolution/variablesources/bundle_test.go | 405 ------------------ .../variablesources/bundle_uniqueness.go | 48 --- .../variablesources/bundle_uniqueness_test.go | 311 -------------- .../resolution/variablesources/composite.go | 62 --- .../variablesources/composite_test.go | 172 -------- .../resolution/variablesources/operator.go | 59 --- .../variablesources/operator_test.go | 156 ------- .../variablesources/variablesources_test.go | 13 - 12 files changed, 1496 deletions(-) delete mode 100644 internal/resolution/variablesources/bundle_deployment.go delete mode 100644 internal/resolution/variablesources/bundle_deployment_test.go delete mode 100644 internal/resolution/variablesources/bundle_provider.go delete mode 100644 internal/resolution/variablesources/composite.go delete mode 100644 internal/resolution/variablesources/composite_test.go delete mode 100644 internal/resolution/variablesources/operator.go delete mode 100644 internal/resolution/variablesources/operator_test.go delete mode 100644 internal/resolution/variablesources/variablesources_test.go diff --git a/internal/resolution/variablesources/bundle.go b/internal/resolution/variablesources/bundle.go index b5f77fe01..234034caa 100644 --- a/internal/resolution/variablesources/bundle.go +++ b/internal/resolution/variablesources/bundle.go @@ -1,14 +1,12 @@ package variablesources import ( - "context" "fmt" "sort" "k8s.io/apimachinery/pkg/util/sets" "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/deppy/pkg/deppy/input" "github.com/operator-framework/operator-controller/internal/catalogmetadata" catalogfilter "github.com/operator-framework/operator-controller/internal/catalogmetadata/filter" @@ -92,53 +90,3 @@ func filterBundleDependencies(allBundles []*catalogmetadata.Bundle, bundle *cata return dependencies, nil } - -type BundlesAndDepsVariableSource struct { - catalogClient BundleProvider - variableSources []input.VariableSource -} - -func NewBundlesAndDepsVariableSource(catalogClient BundleProvider, inputVariableSources ...input.VariableSource) *BundlesAndDepsVariableSource { - return &BundlesAndDepsVariableSource{ - catalogClient: catalogClient, - variableSources: inputVariableSources, - } -} - -func (b *BundlesAndDepsVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - var variables []deppy.Variable - - for _, variableSource := range b.variableSources { - inputVariables, err := variableSource.GetVariables(ctx) - if err != nil { - return nil, err - } - variables = append(variables, inputVariables...) - } - - allBundles, err := b.catalogClient.Bundles(ctx) - if err != nil { - return nil, err - } - - requiredPackages := []*olmvariables.RequiredPackageVariable{} - installedPackages := []*olmvariables.InstalledPackageVariable{} - for _, variable := range variables { - switch v := variable.(type) { - case *olmvariables.RequiredPackageVariable: - requiredPackages = append(requiredPackages, v) - case *olmvariables.InstalledPackageVariable: - installedPackages = append(installedPackages, v) - } - } - - bundles, err := MakeBundleVariables(allBundles, requiredPackages, installedPackages) - if err != nil { - return nil, err - } - - for _, v := range bundles { - variables = append(variables, v) - } - return variables, nil -} diff --git a/internal/resolution/variablesources/bundle_deployment.go b/internal/resolution/variablesources/bundle_deployment.go deleted file mode 100644 index 671513bba..000000000 --- a/internal/resolution/variablesources/bundle_deployment.go +++ /dev/null @@ -1,58 +0,0 @@ -package variablesources - -import ( - "context" - - "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/deppy/pkg/deppy/input" - rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var _ input.VariableSource = &BundleDeploymentVariableSource{} - -type BundleDeploymentVariableSource struct { - client client.Client - catalogClient BundleProvider - inputVariableSource input.VariableSource -} - -func NewBundleDeploymentVariableSource(cl client.Client, catalogClient BundleProvider, inputVariableSource input.VariableSource) *BundleDeploymentVariableSource { - return &BundleDeploymentVariableSource{ - client: cl, - catalogClient: catalogClient, - inputVariableSource: inputVariableSource, - } -} - -func (o *BundleDeploymentVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - variableSources := SliceVariableSource{} - if o.inputVariableSource != nil { - variableSources = append(variableSources, o.inputVariableSource) - } - - bundleDeployments := rukpakv1alpha1.BundleDeploymentList{} - if err := o.client.List(ctx, &bundleDeployments); err != nil { - return nil, err - } - - allBundles, err := o.catalogClient.Bundles(ctx) - if err != nil { - return nil, err - } - - installedPackages, err := MakeInstalledPackageVariables(allBundles, bundleDeployments.Items) - if err != nil { - return nil, err - } - - variables, err := variableSources.GetVariables(ctx) - if err != nil { - return nil, err - } - - for _, v := range installedPackages { - variables = append(variables, v) - } - return variables, nil -} diff --git a/internal/resolution/variablesources/bundle_deployment_test.go b/internal/resolution/variablesources/bundle_deployment_test.go deleted file mode 100644 index 0e640210e..000000000 --- a/internal/resolution/variablesources/bundle_deployment_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package variablesources_test - -import ( - "context" - "encoding/json" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "github.com/operator-framework/operator-registry/alpha/declcfg" - "github.com/operator-framework/operator-registry/alpha/property" - - "github.com/operator-framework/operator-controller/internal/catalogmetadata" - olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables" - "github.com/operator-framework/operator-controller/internal/resolution/variablesources" - testutil "github.com/operator-framework/operator-controller/test/util" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - "github.com/operator-framework/deppy/pkg/deppy" - rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1" -) - -func BundleDeploymentFakeClient(objects ...client.Object) client.Client { - scheme := runtime.NewScheme() - utilruntime.Must(rukpakv1alpha1.AddToScheme(scheme)) - return fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build() -} - -func bundleDeployment(name, image string) *rukpakv1alpha1.BundleDeployment { - return &rukpakv1alpha1.BundleDeployment{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: rukpakv1alpha1.BundleDeploymentSpec{ - ProvisionerClassName: "core-rukpak-io-plain", - Template: &rukpakv1alpha1.BundleTemplate{ - Spec: rukpakv1alpha1.BundleSpec{ - ProvisionerClassName: "core-rukpak-io-plain", - Source: rukpakv1alpha1.BundleSource{ - Image: &rukpakv1alpha1.ImageSource{ - Ref: image, - }, - }, - }, - }, - }, - } -} - -var _ = Describe("BundleDeploymentVariableSource", func() { - var fakeCatalogClient testutil.FakeCatalogClient - var betaChannel catalogmetadata.Channel - var stableChannel catalogmetadata.Channel - var testBundleList []*catalogmetadata.Bundle - - BeforeEach(func() { - betaChannel = catalogmetadata.Channel{Channel: declcfg.Channel{ - Name: "beta", - Entries: []declcfg.ChannelEntry{ - { - Name: "operatorhub/prometheus/0.37.0", - Replaces: "operatorhub/prometheus/0.32.0", - }, - { - Name: "operatorhub/prometheus/0.47.0", - Replaces: "operatorhub/prometheus/0.37.0", - }, - }, - }} - - stableChannel = catalogmetadata.Channel{Channel: declcfg.Channel{ - Name: "beta", - Entries: []declcfg.ChannelEntry{ - { - Name: "operatorhub/packageA/2.0.0", - }, - }, - }} - - testBundleList = []*catalogmetadata.Bundle{ - {Bundle: declcfg.Bundle{ - Name: "operatorhub/prometheus/0.37.0", - Package: "prometheus", - Image: "quay.io/operatorhubio/prometheus@sha256:3e281e587de3d03011440685fc4fb782672beab044c1ebadc42788ce05a21c35", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"prometheus","version":"0.37.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"monitoring.coreos.com","kind":"Alertmanager","version":"v1"}, {"group":"monitoring.coreos.com","kind":"Prometheus","version":"v1"}]`)}, - }, - }, InChannels: []*catalogmetadata.Channel{&betaChannel}}, - {Bundle: declcfg.Bundle{ - Name: "operatorhub/prometheus/0.47.0", - Package: "prometheus", - Image: "quay.io/operatorhubio/prometheus@sha256:5b04c49d8d3eff6a338b56ec90bdf491d501fe301c9cdfb740e5bff6769a21ed", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"prometheus","version":"0.47.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"monitoring.coreos.com","kind":"Alertmanager","version":"v1"}, {"group":"monitoring.coreos.com","kind":"Prometheus","version":"v1alpha1"}]`)}, - }, - }, InChannels: []*catalogmetadata.Channel{&betaChannel}}, - {Bundle: declcfg.Bundle{ - Name: "operatorhub/packageA/2.0.0", - Package: "packageA", - Image: "foo.io/packageA/packageA:v2.0.0", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"packageA","version":"2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }, - }, InChannels: []*catalogmetadata.Channel{&stableChannel}}, - } - - fakeCatalogClient = testutil.NewFakeCatalogClient(testBundleList) - }) - - It("should produce RequiredPackage variables", func() { - cl := BundleDeploymentFakeClient(bundleDeployment("prometheus", "quay.io/operatorhubio/prometheus@sha256:3e281e587de3d03011440685fc4fb782672beab044c1ebadc42788ce05a21c35")) - - bdVariableSource := variablesources.NewBundleDeploymentVariableSource(cl, &fakeCatalogClient, &MockRequiredPackageSource{}) - variables, err := bdVariableSource.GetVariables(context.Background()) - Expect(err).ToNot(HaveOccurred()) - - installedPackageVariable := filterVariables[*olmvariables.InstalledPackageVariable](variables) - Expect(installedPackageVariable).To(HaveLen(1)) - Expect(installedPackageVariable).To(WithTransform(func(bvars []*olmvariables.InstalledPackageVariable) map[deppy.Identifier]int { - out := map[deppy.Identifier]int{} - for _, variable := range bvars { - out[variable.Identifier()] = len(variable.Bundles()) - } - return out - }, Equal(map[deppy.Identifier]int{ - // Underlying `InstalledPackageVariableSource` returns current installed package - // as a possible upgrade edge - deppy.IdentifierFromString("installed package prometheus"): 2, - }))) - }) - It("should return an error if the bundleDeployment image doesn't match any operator resource", func() { - cl := BundleDeploymentFakeClient(bundleDeployment("prometheus", "quay.io/operatorhubio/prometheus@sha256:nonexistent")) - - bdVariableSource := variablesources.NewBundleDeploymentVariableSource(cl, &fakeCatalogClient, &MockRequiredPackageSource{}) - _, err := bdVariableSource.GetVariables(context.Background()) - Expect(err.Error()).To(Equal("bundleImage \"quay.io/operatorhubio/prometheus@sha256:nonexistent\" not found")) - }) -}) diff --git a/internal/resolution/variablesources/bundle_provider.go b/internal/resolution/variablesources/bundle_provider.go deleted file mode 100644 index c6517069a..000000000 --- a/internal/resolution/variablesources/bundle_provider.go +++ /dev/null @@ -1,14 +0,0 @@ -package variablesources - -import ( - "context" - - "github.com/operator-framework/operator-controller/internal/catalogmetadata" -) - -// BundleProvider provides the Bundles method through which we can retrieve -// a list of Bundles from any source, generally from a catalog client of -// some kind. -type BundleProvider interface { - Bundles(ctx context.Context) ([]*catalogmetadata.Bundle, error) -} diff --git a/internal/resolution/variablesources/bundle_test.go b/internal/resolution/variablesources/bundle_test.go index 5cc62ddb4..2a1cd7d59 100644 --- a/internal/resolution/variablesources/bundle_test.go +++ b/internal/resolution/variablesources/bundle_test.go @@ -1,14 +1,9 @@ package variablesources_test import ( - "context" "encoding/json" - "errors" "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "github.com/operator-framework/deppy/pkg/deppy" "github.com/operator-framework/operator-registry/alpha/declcfg" "github.com/operator-framework/operator-registry/alpha/property" "github.com/stretchr/testify/assert" @@ -17,7 +12,6 @@ import ( "github.com/operator-framework/operator-controller/internal/catalogmetadata" olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables" "github.com/operator-framework/operator-controller/internal/resolution/variablesources" - testutil "github.com/operator-framework/operator-controller/test/util" ) func TestMakeBundleVariables(t *testing.T) { @@ -341,402 +335,3 @@ func TestMakeBundleVariables(t *testing.T) { assert.Nil(t, bundles) }) } - -var _ = Describe("BundlesAndDepsVariableSource", func() { - var ( - bdvs *variablesources.BundlesAndDepsVariableSource - testBundleList []*catalogmetadata.Bundle - fakeCatalogClient testutil.FakeCatalogClient - ) - - BeforeEach(func() { - channel := catalogmetadata.Channel{Channel: declcfg.Channel{Name: "stable"}} - testBundleList = []*catalogmetadata.Bundle{ - // required package bundles - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-1", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-2", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`{"group":"foo.io","kind":"Foo","version":"v1"}`)}, - {Type: property.TypePackageRequired, Value: json.RawMessage(`{"packageName": "some-package", "versionRange": ">=1.0.0 <2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // dependencies - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-4", - Package: "some-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-package", "version": "1.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-5", - Package: "some-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-package", "version": "1.5.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-6", - Package: "some-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-package", "version": "2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-7", - Package: "some-other-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-other-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-8", - Package: "some-other-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-other-package", "version": "1.5.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`{"group":"foo.io","kind":"Foo","version":"v1"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`{"group":"bar.io","kind":"Bar","version":"v1"}`)}, - {Type: property.TypePackageRequired, Value: json.RawMessage(`{"packageName": "another-package", "versionRange": "< 2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // dependencies of dependencies - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-9", Package: "another-package", Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "another-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-10", - Package: "bar-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "bar-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"bar.io","kind":"Bar","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-11", - Package: "bar-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "bar-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"bar.io","kind":"Bar","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // test-package-2 required package - no dependencies - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-15", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "1.5.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-16", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "2.0.1"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-17", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "3.16.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // completely unrelated - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-12", - Package: "unrelated-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "unrelated-package", "version": "2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-13", - Package: "unrelated-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "unrelated-package-2", "version": "2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-14", - Package: "unrelated-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "unrelated-package-2", "version": "3.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - } - fakeCatalogClient = testutil.NewFakeCatalogClient(testBundleList) - bdvs = variablesources.NewBundlesAndDepsVariableSource( - &fakeCatalogClient, - &MockRequiredPackageSource{ - ResultSet: []deppy.Variable{ - // must match data in fakeCatalogClient - olmvariables.NewRequiredPackageVariable("test-package", []*catalogmetadata.Bundle{ - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-2", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`{"group":"foo.io","kind":"Foo","version":"v1"}`)}, - {Type: property.TypePackageRequired, Value: json.RawMessage(`{"packageName": "some-package", "versionRange": ">=1.0.0 <2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-1", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - }), - }, - }, - &MockRequiredPackageSource{ - ResultSet: []deppy.Variable{ - // must match data in fakeCatalogClient - olmvariables.NewRequiredPackageVariable("test-package-2", []*catalogmetadata.Bundle{ - // test-package-2 required package - no dependencies - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-15", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "1.5.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-16", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "2.0.1"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-17", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "3.16.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - }), - }, - }, - ) - }) - - It("should return bundle variables with correct dependencies", func() { - variables, err := bdvs.GetVariables(context.TODO()) - Expect(err).NotTo(HaveOccurred()) - - var bundleVariables []*olmvariables.BundleVariable - for _, variable := range variables { - switch v := variable.(type) { - case *olmvariables.BundleVariable: - bundleVariables = append(bundleVariables, v) - } - } - // Note: When accounting for Required GVKs (currently not in use), we would expect additional - // dependencies (bundles 7, 8, 9, 10, 11) to appear here due to their GVKs being required by - // some of the packages. - Expect(bundleVariables).To(WithTransform(CollectBundleVariableIDs, Equal([]string{ - "fake-catalog-test-package-bundle-2", - "fake-catalog-test-package-bundle-1", - "fake-catalog-test-package-2-bundle-15", - "fake-catalog-test-package-2-bundle-16", - "fake-catalog-test-package-2-bundle-17", - "fake-catalog-some-package-bundle-5", - "fake-catalog-some-package-bundle-4", - }))) - - // check dependencies for one of the bundles - bundle2 := VariableWithName("bundle-2")(bundleVariables) - // Note: As above, bundle-2 has GVK requirements satisfied by bundles 7, 8, and 9, but they - // will not appear in this list as we are not currently taking Required GVKs into account - Expect(bundle2.Dependencies()).To(HaveLen(2)) - Expect(bundle2.Dependencies()[0].Name).To(Equal("bundle-5")) - Expect(bundle2.Dependencies()[1].Name).To(Equal("bundle-4")) - }) - - It("should return error if dependencies not found", func() { - emptyCatalogClient := testutil.NewFakeCatalogClient(make([]*catalogmetadata.Bundle, 0)) - - bdvs = variablesources.NewBundlesAndDepsVariableSource( - &emptyCatalogClient, - &MockRequiredPackageSource{ - ResultSet: []deppy.Variable{ - // must match data in fakeCatalogClient - olmvariables.NewRequiredPackageVariable("test-package", []*catalogmetadata.Bundle{ - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-2", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`{"group":"foo.io","kind":"Foo","version":"v1"}`)}, - {Type: property.TypePackageRequired, Value: json.RawMessage(`{"packageName": "some-package", "versionRange": ">=1.0.0 <2.0.0"}`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{{Channel: declcfg.Channel{Name: "stable"}}}, - }, - { - CatalogName: "fake-catalog", - Bundle: declcfg.Bundle{ - Name: "bundle-1", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }, - }, - InChannels: []*catalogmetadata.Channel{{Channel: declcfg.Channel{Name: "stable"}}}, - }, - }), - }, - }, - ) - _, err := bdvs.GetVariables(context.TODO()) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("could not determine dependencies for bundle with id 'fake-catalog-test-package-bundle-2': could not find package dependencies for bundle 'bundle-2'")) - }) - - It("should return error if an inner variable source returns an error", func() { - bdvs = variablesources.NewBundlesAndDepsVariableSource( - &fakeCatalogClient, - &MockRequiredPackageSource{Error: errors.New("fake error")}, - ) - _, err := bdvs.GetVariables(context.TODO()) - Expect(err).To(HaveOccurred()) - Expect(err).To(MatchError("fake error")) - }) -}) - -type MockRequiredPackageSource struct { - ResultSet []deppy.Variable - Error error -} - -func (m *MockRequiredPackageSource) GetVariables(_ context.Context) ([]deppy.Variable, error) { - return m.ResultSet, m.Error -} - -func VariableWithName(name string) func(vars []*olmvariables.BundleVariable) *olmvariables.BundleVariable { - return func(vars []*olmvariables.BundleVariable) *olmvariables.BundleVariable { - for i := 0; i < len(vars); i++ { - if vars[i].Bundle().Name == name { - return vars[i] - } - } - return nil - } -} - -func CollectBundleVariableIDs(vars []*olmvariables.BundleVariable) []string { - ids := make([]string, 0, len(vars)) - for _, v := range vars { - ids = append(ids, v.Identifier().String()) - } - return ids -} diff --git a/internal/resolution/variablesources/bundle_uniqueness.go b/internal/resolution/variablesources/bundle_uniqueness.go index 5f57fad9c..e67c4971a 100644 --- a/internal/resolution/variablesources/bundle_uniqueness.go +++ b/internal/resolution/variablesources/bundle_uniqueness.go @@ -1,13 +1,11 @@ package variablesources import ( - "context" "fmt" "k8s.io/apimachinery/pkg/util/sets" "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/deppy/pkg/deppy/input" "github.com/operator-framework/operator-controller/internal/catalogmetadata" olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables" @@ -50,49 +48,3 @@ func MakeBundleUniquenessVariables(bundleVariables []*olmvariables.BundleVariabl return result, nil } - -// CRDUniquenessConstraintsVariableSource produces variables that constraint the solution to -// 1. at most 1 bundle per package -// 2. at most 1 bundle per gvk (provided by the bundle) -// these variables guarantee that no two operators provide the same gvk and no two version of -// the same operator are running at the same time. -// This variable source does not itself reach out to catalog metadata. It produces its variables -// by searching for BundleVariables that are produced by its 'inputVariableSource' and working out -// which bundles correspond to which package and which gvks are provided by which bundle -type CRDUniquenessConstraintsVariableSource struct { - inputVariableSource input.VariableSource -} - -// NewCRDUniquenessConstraintsVariableSource creates a new instance of the CRDUniquenessConstraintsVariableSource. -// its purpose if to provide variables with constraints that restrict the solutions to bundle sets where -// no two bundles come from the same package and not two bundles provide the same gvk -func NewCRDUniquenessConstraintsVariableSource(inputVariableSource input.VariableSource) *CRDUniquenessConstraintsVariableSource { - return &CRDUniquenessConstraintsVariableSource{ - inputVariableSource: inputVariableSource, - } -} - -func (g *CRDUniquenessConstraintsVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - variables, err := g.inputVariableSource.GetVariables(ctx) - if err != nil { - return nil, err - } - - bundleVariables := []*olmvariables.BundleVariable{} - for _, variable := range variables { - switch v := variable.(type) { - case *olmvariables.BundleVariable: - bundleVariables = append(bundleVariables, v) - } - } - - bundleUniqueness, err := MakeBundleUniquenessVariables(bundleVariables) - if err != nil { - return nil, err - } - - for _, v := range bundleUniqueness { - variables = append(variables, v) - } - return variables, nil -} diff --git a/internal/resolution/variablesources/bundle_uniqueness_test.go b/internal/resolution/variablesources/bundle_uniqueness_test.go index 9c66b5e94..4e866343c 100644 --- a/internal/resolution/variablesources/bundle_uniqueness_test.go +++ b/internal/resolution/variablesources/bundle_uniqueness_test.go @@ -1,17 +1,12 @@ package variablesources_test import ( - "context" "encoding/json" - "fmt" "testing" - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/operator-framework/deppy/pkg/deppy" "github.com/operator-framework/operator-registry/alpha/declcfg" "github.com/operator-framework/operator-registry/alpha/property" @@ -268,309 +263,3 @@ func TestMakeBundleUniquenessVariables(t *testing.T) { assert.EqualValues(t, expectedIDs, actualIDs) }) } - -var channel = catalogmetadata.Channel{Channel: declcfg.Channel{Name: "stable"}} -var bundleSet = map[string]*catalogmetadata.Bundle{ - // required package bundles - "bundle-1": {Bundle: declcfg.Bundle{ - Name: "bundle-1", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"bit.io","kind":"Bit","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-2": {Bundle: declcfg.Bundle{ - Name: "bundle-2", - Package: "test-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`{"group":"foo.io","kind":"Foo","version":"v1"}`)}, - {Type: property.TypePackageRequired, Value: json.RawMessage(`{"packageName": "some-package", "versionRange": ">=1.0.0 <2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`{"group":"bit.io","kind":"Bit","version":"v1"}`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // dependencies - "bundle-3": {Bundle: declcfg.Bundle{ - Name: "bundle-3", - Package: "some-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"fiz.io","kind":"Fiz","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-4": {Bundle: declcfg.Bundle{ - Name: "bundle-4", - Package: "some-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-package", "version": "1.5.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"fiz.io","kind":"Fiz","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-5": {Bundle: declcfg.Bundle{ - Name: "bundle-5", - Package: "some-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"fiz.io","kind":"Fiz","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-6": {Bundle: declcfg.Bundle{ - Name: "bundle-6", - Package: "some-other-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-other-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-7": {Bundle: declcfg.Bundle{ - Name: "bundle-7", - Package: "some-other-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "some-other-package", "version": "1.5.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`{"group":"foo.io","kind":"Foo","version":"v1"}`)}, - {Type: property.TypeGVKRequired, Value: json.RawMessage(`{"group":"bar.io","kind":"Bar","version":"v1"}`)}, - {Type: property.TypePackageRequired, Value: json.RawMessage(`{"packageName": "another-package", "versionRange": "< 2.0.0"}`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // dependencies of dependencies - "bundle-8": {Bundle: declcfg.Bundle{ - Name: "bundle-8", - Package: "another-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "another-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-9": {Bundle: declcfg.Bundle{ - Name: "bundle-9", - Package: "bar-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "bar-package", "version": "1.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"bar.io","kind":"Bar","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-10": {Bundle: declcfg.Bundle{ - Name: "bundle-10", - Package: "bar-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "bar-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"bar.io","kind":"Bar","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // test-package-2 required package - no dependencies - "bundle-14": {Bundle: declcfg.Bundle{ - Name: "bundle-14", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "1.5.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"buz.io","kind":"Buz","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-15": {Bundle: declcfg.Bundle{ - Name: "bundle-15", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "2.0.1"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"buz.io","kind":"Buz","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-16": {Bundle: declcfg.Bundle{ - Name: "bundle-16", - Package: "test-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "test-package-2", "version": "3.16.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"buz.io","kind":"Buz","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - - // completely unrelated - "bundle-11": {Bundle: declcfg.Bundle{ - Name: "bundle-11", - Package: "unrelated-package", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "unrelated-package", "version": "2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"buz.io","kind":"Buz","version":"v1alpha1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-12": {Bundle: declcfg.Bundle{ - Name: "bundle-12", - Package: "unrelated-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "unrelated-package-2", "version": "2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"buz.io","kind":"Buz","version":"v1alpha1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, - "bundle-13": {Bundle: declcfg.Bundle{ - Name: "bundle-13", - Package: "unrelated-package-2", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName": "unrelated-package-2", "version": "3.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"buz.io","kind":"Buz","version":"v1alpha1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&channel}, - }, -} - -var _ = Describe("CRDUniquenessConstraintsVariableSource", func() { - var ( - inputVariableSource *MockInputVariableSource - crdConstraintVariableSource *variablesources.CRDUniquenessConstraintsVariableSource - ctx context.Context - ) - - BeforeEach(func() { - inputVariableSource = &MockInputVariableSource{} - crdConstraintVariableSource = variablesources.NewCRDUniquenessConstraintsVariableSource(inputVariableSource) - ctx = context.Background() - }) - - It("should get variables from the input variable source and create global constraint variables", func() { - inputVariableSource.ResultSet = []deppy.Variable{ - olmvariables.NewRequiredPackageVariable("test-package", []*catalogmetadata.Bundle{ - bundleSet["bundle-2"], - bundleSet["bundle-1"], - }), - olmvariables.NewRequiredPackageVariable("test-package-2", []*catalogmetadata.Bundle{ - bundleSet["bundle-14"], - bundleSet["bundle-15"], - bundleSet["bundle-16"], - }), - olmvariables.NewBundleVariable( - bundleSet["bundle-2"], - []*catalogmetadata.Bundle{ - bundleSet["bundle-3"], - bundleSet["bundle-4"], - bundleSet["bundle-5"], - bundleSet["bundle-6"], - bundleSet["bundle-7"], - }, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-1"], - []*catalogmetadata.Bundle{ - bundleSet["bundle-6"], - bundleSet["bundle-7"], - bundleSet["bundle-8"], - }, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-3"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-4"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-5"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-6"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-7"], - []*catalogmetadata.Bundle{ - bundleSet["bundle-8"], - bundleSet["bundle-9"], - bundleSet["bundle-10"], - }, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-8"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-9"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-10"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-14"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-15"], - []*catalogmetadata.Bundle{}, - ), - olmvariables.NewBundleVariable( - bundleSet["bundle-16"], - []*catalogmetadata.Bundle{}, - ), - } - variables, err := crdConstraintVariableSource.GetVariables(ctx) - Expect(err).ToNot(HaveOccurred()) - // Note: When accounting for GVK Uniqueness (which we are currently not doing), we - // would expect to have 26 variables from the 5 unique GVKs (Bar, Bit, Buz, Fiz, Foo). - Expect(variables).To(HaveLen(21)) - var crdConstraintVariables []*olmvariables.BundleUniquenessVariable - for _, variable := range variables { - switch v := variable.(type) { - case *olmvariables.BundleUniquenessVariable: - crdConstraintVariables = append(crdConstraintVariables, v) - } - } - // Note: As above, the 5 GVKs would appear here as GVK uniqueness constraints - // if GVK Uniqueness were being accounted for. - Expect(crdConstraintVariables).To(WithTransform(CollectGlobalConstraintVariableIDs, Equal([]string{ - "test-package package uniqueness", - "some-package package uniqueness", - "some-other-package package uniqueness", - "another-package package uniqueness", - "bar-package package uniqueness", - "test-package-2 package uniqueness", - }))) - }) - - It("should return an error if input variable source returns an error", func() { - inputVariableSource = &MockInputVariableSource{Err: fmt.Errorf("error getting variables")} - crdConstraintVariableSource = variablesources.NewCRDUniquenessConstraintsVariableSource(inputVariableSource) - _, err := crdConstraintVariableSource.GetVariables(ctx) - Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("error getting variables")) - }) -}) - -type MockInputVariableSource struct { - ResultSet []deppy.Variable - Err error -} - -func (m *MockInputVariableSource) GetVariables(_ context.Context) ([]deppy.Variable, error) { - if m.Err != nil { - return nil, m.Err - } - return m.ResultSet, nil -} - -func CollectGlobalConstraintVariableIDs(vars []*olmvariables.BundleUniquenessVariable) []string { - ids := make([]string, 0, len(vars)) - for _, v := range vars { - ids = append(ids, v.Identifier().String()) - } - return ids -} diff --git a/internal/resolution/variablesources/composite.go b/internal/resolution/variablesources/composite.go deleted file mode 100644 index d0e3a20b9..000000000 --- a/internal/resolution/variablesources/composite.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package variablesources - -import ( - "context" - "errors" - - "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/deppy/pkg/deppy/input" -) - -var _ input.VariableSource = &SliceVariableSource{} -var _ input.VariableSource = &NestedVariableSource{} - -type NestedVariableSource []func(inputVariableSource input.VariableSource) (input.VariableSource, error) - -func (s NestedVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - if len(s) == 0 { - return nil, errors.New("empty nested variable sources") - } - - var variableSource input.VariableSource - var err error - for _, constructor := range s { - variableSource, err = constructor(variableSource) - if err != nil { - return nil, err - } - } - - return variableSource.GetVariables(ctx) -} - -type SliceVariableSource []input.VariableSource - -func (s SliceVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - var variables []deppy.Variable - for _, variableSource := range s { - inputVariables, err := variableSource.GetVariables(ctx) - if err != nil { - return nil, err - } - variables = append(variables, inputVariables...) - } - - return variables, nil -} diff --git a/internal/resolution/variablesources/composite_test.go b/internal/resolution/variablesources/composite_test.go deleted file mode 100644 index bfbf859e8..000000000 --- a/internal/resolution/variablesources/composite_test.go +++ /dev/null @@ -1,172 +0,0 @@ -/* -Copyright 2023. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package variablesources_test - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/deppy/pkg/deppy/input" - - "github.com/operator-framework/operator-controller/internal/resolution/variablesources" -) - -func TestNestedVariableSource(t *testing.T) { - for _, tt := range []struct { - name string - varSources []*mockVariableSource - - wantVariables []deppy.Variable - wantErr string - }{ - { - name: "multiple nested sources", - varSources: []*mockVariableSource{ - {fakeVariables: []deppy.Variable{mockVariable("fake-var-1"), mockVariable("fake-var-2")}}, - {fakeVariables: []deppy.Variable{mockVariable("fake-var-3")}}, - }, - wantVariables: []deppy.Variable{mockVariable("fake-var-1"), mockVariable("fake-var-2"), mockVariable("fake-var-3")}, - }, - { - name: "error when no nested sources provided", - wantErr: "empty nested variable sources", - }, - } { - t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() - - nestedSource := variablesources.NestedVariableSource{} - for i := range tt.varSources { - i := i // Same reason as https://go.dev/doc/faq#closures_and_goroutines - nestedSource = append(nestedSource, func(inputVariableSource input.VariableSource) (input.VariableSource, error) { - if i == 0 { - assert.Nil(t, inputVariableSource) - } else { - assert.Equal(t, tt.varSources[i-1], inputVariableSource) - - tt.varSources[i].inputVariableSource = inputVariableSource - } - - return tt.varSources[i], nil - }) - } - - variables, err := nestedSource.GetVariables(ctx) - if tt.wantErr != "" { - assert.EqualError(t, err, tt.wantErr) - } else { - assert.NoError(t, err) - } - assert.Equal(t, tt.wantVariables, variables) - }) - } - - t.Run("error from a nested constructor", func(t *testing.T) { - ctx := context.Background() - - nestedSource := variablesources.NestedVariableSource{ - func(inputVariableSource input.VariableSource) (input.VariableSource, error) { - return nil, errors.New("fake error from a constructor") - }, - } - - variables, err := nestedSource.GetVariables(ctx) - assert.EqualError(t, err, "fake error from a constructor") - assert.Nil(t, variables) - }) -} - -func TestSliceVariableSource(t *testing.T) { - for _, tt := range []struct { - name string - varSources []input.VariableSource - - wantVariables []deppy.Variable - wantErr string - }{ - { - name: "multiple sources in the slice", - varSources: []input.VariableSource{ - &mockVariableSource{fakeVariables: []deppy.Variable{mockVariable("fake-var-1"), mockVariable("fake-var-2")}}, - &mockVariableSource{fakeVariables: []deppy.Variable{mockVariable("fake-var-3")}}, - }, - wantVariables: []deppy.Variable{mockVariable("fake-var-1"), mockVariable("fake-var-2"), mockVariable("fake-var-3")}, - }, - { - name: "error from GetVariables", - varSources: []input.VariableSource{ - &mockVariableSource{fakeVariables: []deppy.Variable{mockVariable("fake-var-1"), mockVariable("fake-var-2")}}, - &mockVariableSource{fakeError: errors.New("fake error from GetVariables")}, - }, - wantErr: "fake error from GetVariables", - }, - } { - t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() - - sliceSource := variablesources.SliceVariableSource(tt.varSources) - variables, err := sliceSource.GetVariables(ctx) - if tt.wantErr != "" { - assert.EqualError(t, err, tt.wantErr) - } else { - assert.NoError(t, err) - } - assert.Equal(t, tt.wantVariables, variables) - }) - } -} - -var _ input.VariableSource = &mockVariableSource{} - -type mockVariableSource struct { - inputVariableSource input.VariableSource - fakeVariables []deppy.Variable - fakeError error -} - -func (m *mockVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - if m.fakeError != nil { - return nil, m.fakeError - } - - if m.inputVariableSource == nil { - return m.fakeVariables, nil - } - - nestedVars, err := m.inputVariableSource.GetVariables(ctx) - if err != nil { - return nil, err - } - - return append(nestedVars, m.fakeVariables...), nil -} - -var _ deppy.Variable = mockVariable("") - -type mockVariable string - -func (m mockVariable) Identifier() deppy.Identifier { - return deppy.IdentifierFromString(string(m)) -} - -func (m mockVariable) Constraints() []deppy.Constraint { - return nil -} diff --git a/internal/resolution/variablesources/operator.go b/internal/resolution/variablesources/operator.go deleted file mode 100644 index 79dd37099..000000000 --- a/internal/resolution/variablesources/operator.go +++ /dev/null @@ -1,59 +0,0 @@ -package variablesources - -import ( - "context" - - operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" - - "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/deppy/pkg/deppy/input" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -var _ input.VariableSource = &OperatorVariableSource{} - -type OperatorVariableSource struct { - client client.Client - catalogClient BundleProvider - inputVariableSource input.VariableSource -} - -func NewOperatorVariableSource(cl client.Client, catalogClient BundleProvider, inputVariableSource input.VariableSource) *OperatorVariableSource { - return &OperatorVariableSource{ - client: cl, - catalogClient: catalogClient, - inputVariableSource: inputVariableSource, - } -} - -func (o *OperatorVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) { - variableSources := SliceVariableSource{} - if o.inputVariableSource != nil { - variableSources = append(variableSources, o.inputVariableSource) - } - - operatorList := operatorsv1alpha1.OperatorList{} - if err := o.client.List(ctx, &operatorList); err != nil { - return nil, err - } - - allBundles, err := o.catalogClient.Bundles(ctx) - if err != nil { - return nil, err - } - - requiredPackages, err := MakeRequiredPackageVariables(allBundles, operatorList.Items) - if err != nil { - return nil, err - } - - variables, err := variableSources.GetVariables(ctx) - if err != nil { - return nil, err - } - - for _, v := range requiredPackages { - variables = append(variables, v) - } - return variables, nil -} diff --git a/internal/resolution/variablesources/operator_test.go b/internal/resolution/variablesources/operator_test.go deleted file mode 100644 index 426cf82c2..000000000 --- a/internal/resolution/variablesources/operator_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package variablesources_test - -import ( - "context" - "encoding/json" - "errors" - - "github.com/operator-framework/deppy/pkg/deppy" - "github.com/operator-framework/operator-registry/alpha/declcfg" - "github.com/operator-framework/operator-registry/alpha/property" - - . "github.com/onsi/ginkgo/v2" - - . "github.com/onsi/gomega" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - - operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1" - testutil "github.com/operator-framework/operator-controller/test/util" - - "github.com/operator-framework/operator-controller/internal/catalogmetadata" - olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables" - "github.com/operator-framework/operator-controller/internal/resolution/variablesources" -) - -func FakeClient(objects ...client.Object) client.Client { - scheme := runtime.NewScheme() - utilruntime.Must(operatorsv1alpha1.AddToScheme(scheme)) - return fake.NewClientBuilder().WithScheme(scheme).WithObjects(objects...).Build() -} - -func operator(name string) *operatorsv1alpha1.Operator { - return &operatorsv1alpha1.Operator{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - Spec: operatorsv1alpha1.OperatorSpec{ - PackageName: name, - }, - } -} - -var _ = Describe("OperatorVariableSource", func() { - var betaChannel catalogmetadata.Channel - var stableChannel catalogmetadata.Channel - var testBundleList []*catalogmetadata.Bundle - - BeforeEach(func() { - betaChannel = catalogmetadata.Channel{ - Channel: declcfg.Channel{ - Name: "beta", - Entries: []declcfg.ChannelEntry{ - { - Name: "operatorhub/prometheus/0.37.0", - Replaces: "operatorhub/prometheus/0.32.0", - }, - { - Name: "operatorhub/prometheus/0.47.0", - Replaces: "operatorhub/prometheus/0.37.0", - }, - }, - }, - } - - stableChannel = catalogmetadata.Channel{ - Channel: declcfg.Channel{ - Name: "stable", - Entries: []declcfg.ChannelEntry{ - { - Name: "operatorhub/packageA/2.0.0", - }, - }, - }, - } - - testBundleList = []*catalogmetadata.Bundle{ - {Bundle: declcfg.Bundle{ - Name: "operatorhub/prometheus/0.37.0", - Package: "prometheus", - Image: "quay.io/operatorhubio/prometheus@sha256:3e281e587de3d03011440685fc4fb782672beab044c1ebadc42788ce05a21c35", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"prometheus","version":"0.37.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"monitoring.coreos.com","kind":"Alertmanager","version":"v1"}, {"group":"monitoring.coreos.com","kind":"Prometheus","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&betaChannel}, - }, - {Bundle: declcfg.Bundle{ - Name: "operatorhub/prometheus/0.47.0", - Package: "prometheus", - Image: "quay.io/operatorhubio/prometheus@sha256:5b04c49d8d3eff6a338b56ec90bdf491d501fe301c9cdfb740e5bff6769a21ed", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"prometheus","version":"0.47.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"monitoring.coreos.com","kind":"Alertmanager","version":"v1"}, {"group":"monitoring.coreos.com","kind":"Prometheus","version":"v1alpha1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&betaChannel}, - }, - {Bundle: declcfg.Bundle{ - Name: "operatorhub/packageA/2.0.0", - Package: "packageA", - Image: "foo.io/packageA/packageA:v2.0.0", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"packageA","version":"2.0.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[{"group":"foo.io","kind":"Foo","version":"v1"}]`)}, - }}, - InChannels: []*catalogmetadata.Channel{&stableChannel}, - }, - } - - }) - - It("should produce RequiredPackage variables", func() { - cl := FakeClient(operator("prometheus"), operator("packageA")) - fakeCatalogClient := testutil.NewFakeCatalogClient(testBundleList) - opVariableSource := variablesources.NewOperatorVariableSource(cl, &fakeCatalogClient, &MockRequiredPackageSource{}) - variables, err := opVariableSource.GetVariables(context.Background()) - Expect(err).ToNot(HaveOccurred()) - - packageRequiredVariables := filterVariables[*olmvariables.RequiredPackageVariable](variables) - Expect(packageRequiredVariables).To(HaveLen(2)) - Expect(packageRequiredVariables).To(WithTransform(func(bvars []*olmvariables.RequiredPackageVariable) map[deppy.Identifier]int { - out := map[deppy.Identifier]int{} - for _, variable := range bvars { - out[variable.Identifier()] = len(variable.Bundles()) - } - return out - }, Equal(map[deppy.Identifier]int{ - deppy.IdentifierFromString("required package prometheus"): 2, - deppy.IdentifierFromString("required package packageA"): 1, - }))) - }) - - It("should return an errors when they occur", func() { - cl := FakeClient(operator("prometheus"), operator("packageA")) - fakeCatalogClient := testutil.NewFakeCatalogClientWithError(errors.New("something bad happened")) - - opVariableSource := variablesources.NewOperatorVariableSource(cl, &fakeCatalogClient, nil) - _, err := opVariableSource.GetVariables(context.Background()) - Expect(err).To(HaveOccurred()) - }) -}) - -func filterVariables[D deppy.Variable](variables []deppy.Variable) []D { - var out []D - for _, variable := range variables { - switch v := variable.(type) { - case D: - out = append(out, v) - } - } - return out -} diff --git a/internal/resolution/variablesources/variablesources_test.go b/internal/resolution/variablesources/variablesources_test.go deleted file mode 100644 index 7bb8d97b8..000000000 --- a/internal/resolution/variablesources/variablesources_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package variablesources_test - -import ( - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -func TestVariableSources(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Variable Sources Suite") -}