Skip to content

Commit 5dabe8f

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

File tree

3 files changed

+112
-95
lines changed

3 files changed

+112
-95
lines changed

internal/resolution/variablesources/bundle_deployment.go

+13-17
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package variablesources
33
import (
44
"context"
55

6-
"k8s.io/apimachinery/pkg/util/sets"
7-
86
"github.com/operator-framework/deppy/pkg/deppy"
97
"github.com/operator-framework/deppy/pkg/deppy/input"
108
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
@@ -34,21 +32,19 @@ func (o *BundleDeploymentVariableSource) GetVariables(ctx context.Context) ([]de
3432
variableSources = append(variableSources, o.inputVariableSource)
3533
}
3634

37-
processed := sets.Set[string]{}
38-
for _, bundleDeployment := range o.bundleDeployments {
39-
sourceImage := bundleDeployment.Spec.Template.Spec.Source.Image
40-
if sourceImage != nil && sourceImage.Ref != "" {
41-
if processed.Has(sourceImage.Ref) {
42-
continue
43-
}
44-
processed.Insert(sourceImage.Ref)
45-
ips, err := NewInstalledPackageVariableSource(o.allBundles, bundleDeployment.Spec.Template.Spec.Source.Image.Ref)
46-
if err != nil {
47-
return nil, err
48-
}
49-
variableSources = append(variableSources, ips)
50-
}
35+
variables, err := variableSources.GetVariables(ctx)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
// This must go after
41+
installedPackages, err := MakeInstalledPackageVariables(o.allBundles, o.bundleDeployments)
42+
if err != nil {
43+
return nil, err
5144
}
5245

53-
return variableSources.GetVariables(ctx)
46+
for _, v := range installedPackages {
47+
variables = append(variables, v)
48+
}
49+
return variables, nil
5450
}

internal/resolution/variablesources/installed_package.go

+50-50
Original file line numberDiff line numberDiff line change
@@ -1,71 +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-
allBundles []*catalogmetadata.Bundle
23-
successors successorsFunc
24-
bundleImage string
25-
}
26-
27-
func (r *InstalledPackageVariableSource) GetVariables(_ context.Context) ([]deppy.Variable, error) {
28-
// find corresponding bundle for the installed content
29-
resultSet := catalogfilter.Filter(r.allBundles, catalogfilter.WithBundleImage(r.bundleImage))
30-
if len(resultSet) == 0 {
31-
return nil, r.notFoundError()
32-
}
33-
34-
// TODO: fast follow - we should check whether we are already supporting the channel attribute in the operator spec.
35-
// if so, we should take the value from spec of the operator CR in the owner ref of the bundle deployment.
36-
// If that channel is set, we need to update the filter above to filter by channel as well.
37-
sort.SliceStable(resultSet, func(i, j int) bool {
38-
return catalogsort.ByVersion(resultSet[i], resultSet[j])
39-
})
40-
installedBundle := resultSet[0]
41-
42-
upgradeEdges, err := r.successors(r.allBundles, installedBundle)
43-
if err != nil {
44-
return nil, err
45-
}
46-
47-
// you can always upgrade to yourself, i.e. not upgrade
48-
upgradeEdges = append(upgradeEdges, installedBundle)
49-
return []deppy.Variable{
50-
variables.NewInstalledPackageVariable(installedBundle.Package, upgradeEdges),
51-
}, nil
52-
}
53-
54-
func (r *InstalledPackageVariableSource) notFoundError() error {
55-
return fmt.Errorf("bundleImage %q not found", r.bundleImage)
56-
}
57-
58-
func NewInstalledPackageVariableSource(allBundles []*catalogmetadata.Bundle, bundleImage string) (*InstalledPackageVariableSource, error) {
59-
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
6028
if features.OperatorControllerFeatureGate.Enabled(features.ForceSemverUpgradeConstraints) {
6129
successors = semverSuccessors
6230
}
6331

64-
return &InstalledPackageVariableSource{
65-
allBundles: allBundles,
66-
bundleImage: bundleImage,
67-
successors: successors,
68-
}, 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
6969
}
7070

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

internal/resolution/variablesources/installed_package_test.go

+49-28
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
package variablesources_test
22

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

88
"github.com/operator-framework/deppy/pkg/deppy"
99
"github.com/operator-framework/operator-registry/alpha/declcfg"
1010
"github.com/operator-framework/operator-registry/alpha/property"
11+
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
1112
"github.com/stretchr/testify/assert"
1213
"github.com/stretchr/testify/require"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1315
featuregatetesting "k8s.io/component-base/featuregate/testing"
1416

1517
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
16-
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
1718
"github.com/operator-framework/operator-controller/internal/resolution/variablesources"
1819
"github.com/operator-framework/operator-controller/pkg/features"
1920
)
2021

21-
func TestInstalledPackageVariableSource(t *testing.T) {
22+
func TestMakeInstalledPackageVariables(t *testing.T) {
2223
someOtherPackageChannel := catalogmetadata.Channel{Channel: declcfg.Channel{
2324
Name: "stable",
2425
Package: "some-other-package",
@@ -81,7 +82,7 @@ func TestInstalledPackageVariableSource(t *testing.T) {
8182
},
8283
},
8384
}}
84-
bundleList := []*catalogmetadata.Bundle{
85+
allBundles := []*catalogmetadata.Bundle{
8586
{Bundle: declcfg.Bundle{
8687
Name: "test-package.v0.0.1",
8788
Package: "test-package",
@@ -201,19 +202,41 @@ func TestInstalledPackageVariableSource(t *testing.T) {
201202
},
202203
}
203204

205+
fakeBundleDeployments := func(bundleImages ...string) []rukpakv1alpha1.BundleDeployment {
206+
bundleDeployments := []rukpakv1alpha1.BundleDeployment{}
207+
for idx, bundleImage := range bundleImages {
208+
bd := rukpakv1alpha1.BundleDeployment{
209+
ObjectMeta: metav1.ObjectMeta{
210+
Name: fmt.Sprintf("bd-%d", idx),
211+
},
212+
Spec: rukpakv1alpha1.BundleDeploymentSpec{
213+
Template: &rukpakv1alpha1.BundleTemplate{
214+
Spec: rukpakv1alpha1.BundleSpec{
215+
Source: rukpakv1alpha1.BundleSource{
216+
Image: &rukpakv1alpha1.ImageSource{
217+
Ref: bundleImage,
218+
},
219+
},
220+
},
221+
},
222+
},
223+
}
224+
bundleDeployments = append(bundleDeployments, bd)
225+
}
226+
227+
return bundleDeployments
228+
}
229+
204230
t.Run("with ForceSemverUpgradeConstraints feature gate enabled", func(t *testing.T) {
205231
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, true)()
206232

207233
t.Run("with non-zero major version", func(t *testing.T) {
208234
const bundleImage = "registry.io/repo/[email protected]"
209-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
235+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
210236
require.NoError(t, err)
211237

212-
variables, err := ipvs.GetVariables(context.TODO())
213-
require.NoError(t, err)
214-
require.Len(t, variables, 1)
215-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
216-
assert.True(t, ok)
238+
require.Len(t, installedPackages, 1)
239+
packageVariable := installedPackages[0]
217240
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
218241

219242
// ensure bundles are in version order (high to low)
@@ -227,14 +250,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
227250
t.Run("with zero major version", func(t *testing.T) {
228251
t.Run("with zero minor version", func(t *testing.T) {
229252
const bundleImage = "registry.io/repo/[email protected]"
230-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
253+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
231254
require.NoError(t, err)
232255

233-
variables, err := ipvs.GetVariables(context.TODO())
234-
require.NoError(t, err)
235-
require.Len(t, variables, 1)
236-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
237-
assert.True(t, ok)
256+
require.Len(t, installedPackages, 1)
257+
packageVariable := installedPackages[0]
238258
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
239259

240260
// No upgrades are allowed in major version zero when minor version is also zero
@@ -245,14 +265,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
245265

246266
t.Run("with non-zero minor version", func(t *testing.T) {
247267
const bundleImage = "registry.io/repo/[email protected]"
248-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
268+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
249269
require.NoError(t, err)
250270

251-
variables, err := ipvs.GetVariables(context.TODO())
252-
require.NoError(t, err)
253-
require.Len(t, variables, 1)
254-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
255-
assert.True(t, ok)
271+
require.Len(t, installedPackages, 1)
272+
packageVariable := installedPackages[0]
256273
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
257274

258275
// Patch version upgrades are allowed, but not minor upgrades
@@ -268,14 +285,11 @@ func TestInstalledPackageVariableSource(t *testing.T) {
268285
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, false)()
269286

270287
const bundleImage = "registry.io/repo/[email protected]"
271-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
288+
installedPackages, err := variablesources.MakeInstalledPackageVariables(allBundles, fakeBundleDeployments(bundleImage))
272289
require.NoError(t, err)
273290

274-
variables, err := ipvs.GetVariables(context.TODO())
275-
require.NoError(t, err)
276-
require.Len(t, variables, 1)
277-
packageVariable, ok := variables[0].(*olmvariables.InstalledPackageVariable)
278-
assert.True(t, ok)
291+
require.Len(t, installedPackages, 1)
292+
packageVariable := installedPackages[0]
279293
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
280294

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

0 commit comments

Comments
 (0)