Skip to content

Commit 48523f5

Browse files
author
Mikalai Radchuk
committed
Turn installed package variable source into a func
Signed-off-by: Mikalai Radchuk <[email protected]>
1 parent 0c38e67 commit 48523f5

File tree

3 files changed

+119
-104
lines changed

3 files changed

+119
-104
lines changed

internal/resolution/variablesources/bundle_deployment.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"github.com/operator-framework/deppy/pkg/deppy"
77
"github.com/operator-framework/deppy/pkg/deppy/input"
88
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
9-
"k8s.io/apimachinery/pkg/util/sets"
109
"sigs.k8s.io/controller-runtime/pkg/client"
1110
)
1211

@@ -37,21 +36,23 @@ func (o *BundleDeploymentVariableSource) GetVariables(ctx context.Context) ([]de
3736
return nil, err
3837
}
3938

40-
processed := sets.Set[string]{}
41-
for _, bundleDeployment := range bundleDeployments.Items {
42-
sourceImage := bundleDeployment.Spec.Template.Spec.Source.Image
43-
if sourceImage != nil && sourceImage.Ref != "" {
44-
if processed.Has(sourceImage.Ref) {
45-
continue
46-
}
47-
processed.Insert(sourceImage.Ref)
48-
ips, err := NewInstalledPackageVariableSource(o.catalogClient, bundleDeployment.Spec.Template.Spec.Source.Image.Ref)
49-
if err != nil {
50-
return nil, err
51-
}
52-
variableSources = append(variableSources, ips)
53-
}
39+
allBundles, err := o.catalogClient.Bundles(ctx)
40+
if err != nil {
41+
return nil, err
42+
}
43+
44+
installedPackages, err := MakeInstalledPackageVariables(allBundles, bundleDeployments.Items)
45+
if err != nil {
46+
return nil, err
5447
}
5548

56-
return variableSources.GetVariables(ctx)
49+
variables, err := variableSources.GetVariables(ctx)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
for _, v := range installedPackages {
55+
variables = append(variables, v)
56+
}
57+
return variables, nil
5758
}

internal/resolution/variablesources/installed_package.go

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,71 @@
11
package variablesources
22

33
import (
4-
"context"
54
"fmt"
65
"sort"
76

87
mmsemver "github.com/Masterminds/semver/v3"
9-
"github.com/operator-framework/deppy/pkg/deppy"
10-
"github.com/operator-framework/deppy/pkg/deppy/input"
8+
"k8s.io/apimachinery/pkg/util/sets"
9+
10+
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
1111

1212
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
1313
catalogfilter "github.com/operator-framework/operator-controller/internal/catalogmetadata/filter"
1414
catalogsort "github.com/operator-framework/operator-controller/internal/catalogmetadata/sort"
15-
"github.com/operator-framework/operator-controller/internal/resolution/variables"
15+
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
1616
"github.com/operator-framework/operator-controller/pkg/features"
1717
)
1818

19-
var _ input.VariableSource = &InstalledPackageVariableSource{}
20-
21-
type InstalledPackageVariableSource struct {
22-
catalogClient BundleProvider
23-
successors successorsFunc
24-
bundleImage string
25-
}
26-
27-
func (r *InstalledPackageVariableSource) GetVariables(ctx context.Context) ([]deppy.Variable, error) {
28-
allBundles, err := r.catalogClient.Bundles(ctx)
29-
if err != nil {
30-
return nil, err
31-
}
32-
33-
// find corresponding bundle for the installed content
34-
resultSet := catalogfilter.Filter(allBundles, catalogfilter.WithBundleImage(r.bundleImage))
35-
if len(resultSet) == 0 {
36-
return nil, r.notFoundError()
37-
}
38-
39-
// TODO: fast follow - we should check whether we are already supporting the channel attribute in the operator spec.
40-
// if so, we should take the value from spec of the operator CR in the owner ref of the bundle deployment.
41-
// If that channel is set, we need to update the filter above to filter by channel as well.
42-
sort.SliceStable(resultSet, func(i, j int) bool {
43-
return catalogsort.ByVersion(resultSet[i], resultSet[j])
44-
})
45-
installedBundle := resultSet[0]
46-
47-
upgradeEdges, err := r.successors(allBundles, installedBundle)
48-
if err != nil {
49-
return nil, err
50-
}
51-
52-
// you can always upgrade to yourself, i.e. not upgrade
53-
upgradeEdges = append(upgradeEdges, installedBundle)
54-
return []deppy.Variable{
55-
variables.NewInstalledPackageVariable(installedBundle.Package, upgradeEdges),
56-
}, nil
57-
}
58-
59-
func (r *InstalledPackageVariableSource) notFoundError() error {
60-
return fmt.Errorf("bundleImage %q not found", r.bundleImage)
61-
}
62-
63-
func NewInstalledPackageVariableSource(catalogClient BundleProvider, bundleImage string) (*InstalledPackageVariableSource, error) {
64-
successors := legacySemanticsSuccessors
19+
// MakeInstalledPackageVariables returns variables representing packages
20+
// already installed in the system.
21+
// Meaning that each BundleDeployment managed by operator-controller
22+
// has own variable.
23+
func MakeInstalledPackageVariables(
24+
allBundles []*catalogmetadata.Bundle,
25+
bundleDeployments []rukpakv1alpha1.BundleDeployment,
26+
) ([]*olmvariables.InstalledPackageVariable, error) {
27+
var successors successorsFunc = legacySemanticsSuccessors
6528
if features.OperatorControllerFeatureGate.Enabled(features.ForceSemverUpgradeConstraints) {
6629
successors = semverSuccessors
6730
}
6831

69-
return &InstalledPackageVariableSource{
70-
catalogClient: catalogClient,
71-
bundleImage: bundleImage,
72-
successors: successors,
73-
}, nil
32+
result := make([]*olmvariables.InstalledPackageVariable, 0, len(bundleDeployments))
33+
processed := sets.Set[string]{}
34+
for _, bundleDeployment := range bundleDeployments {
35+
sourceImage := bundleDeployment.Spec.Template.Spec.Source.Image
36+
if sourceImage == nil || sourceImage.Ref == "" {
37+
continue
38+
}
39+
40+
if processed.Has(sourceImage.Ref) {
41+
continue
42+
}
43+
processed.Insert(sourceImage.Ref)
44+
45+
bundleImage := sourceImage.Ref
46+
47+
// find corresponding bundle for the installed content
48+
resultSet := catalogfilter.Filter(allBundles, catalogfilter.WithBundleImage(bundleImage))
49+
if len(resultSet) == 0 {
50+
return nil, fmt.Errorf("bundleImage %q not found", bundleImage)
51+
}
52+
53+
sort.SliceStable(resultSet, func(i, j int) bool {
54+
return catalogsort.ByVersion(resultSet[i], resultSet[j])
55+
})
56+
installedBundle := resultSet[0]
57+
58+
upgradeEdges, err := successors(allBundles, installedBundle)
59+
if err != nil {
60+
return nil, err
61+
}
62+
63+
// you can always upgrade to yourself, i.e. not upgrade
64+
upgradeEdges = append(upgradeEdges, installedBundle)
65+
result = append(result, olmvariables.NewInstalledPackageVariable(installedBundle.Package, upgradeEdges))
66+
}
67+
68+
return result, nil
7469
}
7570

7671
// successorsFunc must return successors of a currently installed bundle

internal/resolution/variablesources/installed_package_test.go

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
package variablesources_test
22

33
import (
4-
"context"
54
"encoding/json"
5+
"fmt"
66
"testing"
77

8-
"github.com/operator-framework/deppy/pkg/deppy"
9-
"github.com/operator-framework/operator-registry/alpha/declcfg"
10-
"github.com/operator-framework/operator-registry/alpha/property"
118
"github.com/stretchr/testify/assert"
129
"github.com/stretchr/testify/require"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1311
featuregatetesting "k8s.io/component-base/featuregate/testing"
1412

13+
"github.com/operator-framework/deppy/pkg/deppy"
14+
"github.com/operator-framework/operator-registry/alpha/declcfg"
15+
"github.com/operator-framework/operator-registry/alpha/property"
16+
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
17+
1518
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
16-
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
1719
"github.com/operator-framework/operator-controller/internal/resolution/variablesources"
1820
"github.com/operator-framework/operator-controller/pkg/features"
19-
testutil "github.com/operator-framework/operator-controller/test/util"
2021
)
2122

22-
func TestInstalledPackageVariableSource(t *testing.T) {
23+
func TestMakeInstalledPackageVariables(t *testing.T) {
2324
someOtherPackageChannel := catalogmetadata.Channel{Channel: declcfg.Channel{
2425
Name: "stable",
2526
Package: "some-other-package",
@@ -82,7 +83,7 @@ func TestInstalledPackageVariableSource(t *testing.T) {
8283
},
8384
},
8485
}}
85-
bundleList := []*catalogmetadata.Bundle{
86+
allBundles := []*catalogmetadata.Bundle{
8687
{Bundle: declcfg.Bundle{
8788
Name: "test-package.v0.0.1",
8889
Package: "test-package",
@@ -202,21 +203,41 @@ func TestInstalledPackageVariableSource(t *testing.T) {
202203
},
203204
}
204205

205-
fakeCatalogClient := testutil.NewFakeCatalogClient(bundleList)
206+
fakeBundleDeployments := func(bundleImages ...string) []rukpakv1alpha1.BundleDeployment {
207+
bundleDeployments := []rukpakv1alpha1.BundleDeployment{}
208+
for idx, bundleImage := range bundleImages {
209+
bd := rukpakv1alpha1.BundleDeployment{
210+
ObjectMeta: metav1.ObjectMeta{
211+
Name: fmt.Sprintf("bd-%d", idx),
212+
},
213+
Spec: rukpakv1alpha1.BundleDeploymentSpec{
214+
Template: &rukpakv1alpha1.BundleTemplate{
215+
Spec: rukpakv1alpha1.BundleSpec{
216+
Source: rukpakv1alpha1.BundleSource{
217+
Image: &rukpakv1alpha1.ImageSource{
218+
Ref: bundleImage,
219+
},
220+
},
221+
},
222+
},
223+
},
224+
}
225+
bundleDeployments = append(bundleDeployments, bd)
226+
}
227+
228+
return bundleDeployments
229+
}
206230

207231
t.Run("with ForceSemverUpgradeConstraints feature gate enabled", func(t *testing.T) {
208232
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, true)()
209233

210234
t.Run("with non-zero major version", func(t *testing.T) {
211235
const bundleImage = "registry.io/repo/[email protected]"
212-
ipvs, err := variablesources.NewInstalledPackageVariableSource(&fakeCatalogClient, bundleImage)
236+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
213237
require.NoError(t, err)
214238

215-
variables, err := ipvs.GetVariables(context.TODO())
216-
require.NoError(t, err)
217-
require.Len(t, variables, 1)
218-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
219-
assert.True(t, ok)
239+
require.Len(t, installedPackages, 1)
240+
packageVariable := installedPackages[0]
220241
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
221242

222243
// ensure bundles are in version order (high to low)
@@ -230,14 +251,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
230251
t.Run("with zero major version", func(t *testing.T) {
231252
t.Run("with zero minor version", func(t *testing.T) {
232253
const bundleImage = "registry.io/repo/[email protected]"
233-
ipvs, err := variablesources.NewInstalledPackageVariableSource(&fakeCatalogClient, bundleImage)
254+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
234255
require.NoError(t, err)
235256

236-
variables, err := ipvs.GetVariables(context.TODO())
237-
require.NoError(t, err)
238-
require.Len(t, variables, 1)
239-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
240-
assert.True(t, ok)
257+
require.Len(t, installedPackages, 1)
258+
packageVariable := installedPackages[0]
241259
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
242260

243261
// No upgrades are allowed in major version zero when minor version is also zero
@@ -248,14 +266,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
248266

249267
t.Run("with non-zero minor version", func(t *testing.T) {
250268
const bundleImage = "registry.io/repo/[email protected]"
251-
ipvs, err := variablesources.NewInstalledPackageVariableSource(&fakeCatalogClient, bundleImage)
269+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
252270
require.NoError(t, err)
253271

254-
variables, err := ipvs.GetVariables(context.TODO())
255-
require.NoError(t, err)
256-
require.Len(t, variables, 1)
257-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
258-
assert.True(t, ok)
272+
require.Len(t, installedPackages, 1)
273+
packageVariable := installedPackages[0]
259274
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
260275

261276
// Patch version upgrades are allowed, but not minor upgrades
@@ -271,14 +286,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
271286
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, false)()
272287

273288
const bundleImage = "registry.io/repo/[email protected]"
274-
ipvs, err := variablesources.NewInstalledPackageVariableSource(&fakeCatalogClient, bundleImage)
289+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
275290
require.NoError(t, err)
276291

277-
variables, err := ipvs.GetVariables(context.TODO())
278-
require.NoError(t, err)
279-
require.Len(t, variables, 1)
280-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
281-
assert.True(t, ok)
292+
require.Len(t, installedPackages, 1)
293+
packageVariable := installedPackages[0]
282294
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
283295

284296
// ensure bundles are in version order (high to low)
@@ -287,4 +299,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
287299
assert.Equal(t, "test-package.v2.1.0", packageVariable.Bundles()[0].Name)
288300
assert.Equal(t, "test-package.v2.0.0", packageVariable.Bundles()[1].Name)
289301
})
302+
303+
t.Run("installed bundle not found", func(t *testing.T) {
304+
const bundleImage = "registry.io/repo/[email protected]"
305+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
306+
assert.Nil(t, installedPackages)
307+
assert.ErrorContains(t, err, `bundleImage "registry.io/repo/[email protected]" not found`)
308+
})
290309
}

0 commit comments

Comments
 (0)