Skip to content

Commit cd784a0

Browse files
author
Mikalai Radchuk
committed
Turn installed package variable source into a func
Signed-off-by: Mikalai Radchuk <mradchuk@redhat.com>
1 parent 55d54ab commit cd784a0

File tree

3 files changed

+132
-95
lines changed

3 files changed

+132
-95
lines changed

internal/resolution/variablesources/bundle_deployment.go

Lines changed: 12 additions & 17 deletions
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,18 @@ 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+
installedPackages, err := MakeInstalledPackageVariables(o.allBundles, o.bundleDeployments)
41+
if err != nil {
42+
return nil, err
5143
}
5244

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

internal/resolution/variablesources/installed_package.go

Lines changed: 53 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,74 @@
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+
if bundleDeployment.Spec.Template == nil {
36+
continue
37+
}
38+
sourceImage := bundleDeployment.Spec.Template.Spec.Source.Image
39+
if sourceImage == nil || sourceImage.Ref == "" {
40+
continue
41+
}
42+
43+
if processed.Has(sourceImage.Ref) {
44+
continue
45+
}
46+
processed.Insert(sourceImage.Ref)
47+
48+
bundleImage := sourceImage.Ref
49+
50+
// find corresponding bundle for the installed content
51+
resultSet := catalogfilter.Filter(allBundles, catalogfilter.WithBundleImage(bundleImage))
52+
if len(resultSet) == 0 {
53+
return nil, fmt.Errorf("bundleImage %q not found", bundleImage)
54+
}
55+
56+
sort.SliceStable(resultSet, func(i, j int) bool {
57+
return catalogsort.ByVersion(resultSet[i], resultSet[j])
58+
})
59+
installedBundle := resultSet[0]
60+
61+
upgradeEdges, err := successors(allBundles, installedBundle)
62+
if err != nil {
63+
return nil, err
64+
}
65+
66+
// you can always upgrade to yourself, i.e. not upgrade
67+
upgradeEdges = append(upgradeEdges, installedBundle)
68+
result = append(result, olmvariables.NewInstalledPackageVariable(installedBundle.Package, upgradeEdges))
69+
}
70+
71+
return result, nil
6972
}
7073

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

internal/resolution/variablesources/installed_package_test.go

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
package variablesources_test
22

33
import (
4-
"context"
54
"encoding/json"
65
"testing"
76

87
"github.com/operator-framework/deppy/pkg/deppy"
98
"github.com/operator-framework/operator-registry/alpha/declcfg"
109
"github.com/operator-framework/operator-registry/alpha/property"
10+
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
1111
"github.com/stretchr/testify/assert"
1212
"github.com/stretchr/testify/require"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
featuregatetesting "k8s.io/component-base/featuregate/testing"
1415

1516
"github.com/operator-framework/operator-controller/internal/catalogmetadata"
16-
olmvariables "github.com/operator-framework/operator-controller/internal/resolution/variables"
1717
"github.com/operator-framework/operator-controller/internal/resolution/variablesources"
1818
"github.com/operator-framework/operator-controller/pkg/features"
1919
)
2020

21-
func TestInstalledPackageVariableSource(t *testing.T) {
21+
func TestMakeInstalledPackageVariables(t *testing.T) {
2222
someOtherPackageChannel := catalogmetadata.Channel{Channel: declcfg.Channel{
2323
Name: "stable",
2424
Package: "some-other-package",
@@ -81,7 +81,7 @@ func TestInstalledPackageVariableSource(t *testing.T) {
8181
},
8282
},
8383
}}
84-
bundleList := []*catalogmetadata.Bundle{
84+
allBundles := []*catalogmetadata.Bundle{
8585
{Bundle: declcfg.Bundle{
8686
Name: "test-package.v0.0.1",
8787
Package: "test-package",
@@ -201,19 +201,40 @@ func TestInstalledPackageVariableSource(t *testing.T) {
201201
},
202202
}
203203

204+
fakeBundleDeployment := func(name, bundleImage string) rukpakv1alpha1.BundleDeployment {
205+
return rukpakv1alpha1.BundleDeployment{
206+
ObjectMeta: metav1.ObjectMeta{
207+
Name: name,
208+
},
209+
Spec: rukpakv1alpha1.BundleDeploymentSpec{
210+
Template: &rukpakv1alpha1.BundleTemplate{
211+
Spec: rukpakv1alpha1.BundleSpec{
212+
Source: rukpakv1alpha1.BundleSource{
213+
Image: &rukpakv1alpha1.ImageSource{
214+
Ref: bundleImage,
215+
},
216+
},
217+
},
218+
},
219+
},
220+
}
221+
}
222+
204223
t.Run("with ForceSemverUpgradeConstraints feature gate enabled", func(t *testing.T) {
205224
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, true)()
206225

207226
t.Run("with non-zero major version", func(t *testing.T) {
208227
const bundleImage = "registry.io/repo/test-package@v2.0.0"
209-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
228+
installedPackages, err := variablesources.MakeInstalledPackageVariables(
229+
allBundles,
230+
[]rukpakv1alpha1.BundleDeployment{
231+
fakeBundleDeployment("test-bd", bundleImage),
232+
},
233+
)
210234
require.NoError(t, err)
211235

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)
236+
require.Len(t, installedPackages, 1)
237+
packageVariable := installedPackages[0]
217238
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
218239

219240
// ensure bundles are in version order (high to low)
@@ -227,14 +248,16 @@ func TestInstalledPackageVariableSource(t *testing.T) {
227248
t.Run("with zero major version", func(t *testing.T) {
228249
t.Run("with zero minor version", func(t *testing.T) {
229250
const bundleImage = "registry.io/repo/test-package@v0.0.1"
230-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
251+
installedPackages, err := variablesources.MakeInstalledPackageVariables(
252+
allBundles,
253+
[]rukpakv1alpha1.BundleDeployment{
254+
fakeBundleDeployment("test-bd", bundleImage),
255+
},
256+
)
231257
require.NoError(t, err)
232258

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)
259+
require.Len(t, installedPackages, 1)
260+
packageVariable := installedPackages[0]
238261
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
239262

240263
// No upgrades are allowed in major version zero when minor version is also zero
@@ -245,14 +268,16 @@ func TestInstalledPackageVariableSource(t *testing.T) {
245268

246269
t.Run("with non-zero minor version", func(t *testing.T) {
247270
const bundleImage = "registry.io/repo/test-package@v0.1.0"
248-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
271+
installedPackages, err := variablesources.MakeInstalledPackageVariables(
272+
allBundles,
273+
[]rukpakv1alpha1.BundleDeployment{
274+
fakeBundleDeployment("test-bd", bundleImage),
275+
},
276+
)
249277
require.NoError(t, err)
250278

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)
279+
require.Len(t, installedPackages, 1)
280+
packageVariable := installedPackages[0]
256281
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
257282

258283
// Patch version upgrades are allowed, but not minor upgrades
@@ -268,14 +293,16 @@ func TestInstalledPackageVariableSource(t *testing.T) {
268293
defer featuregatetesting.SetFeatureGateDuringTest(t, features.OperatorControllerFeatureGate, features.ForceSemverUpgradeConstraints, false)()
269294

270295
const bundleImage = "registry.io/repo/test-package@v2.0.0"
271-
ipvs, err := variablesources.NewInstalledPackageVariableSource(bundleList, bundleImage)
296+
installedPackages, err := variablesources.MakeInstalledPackageVariables(
297+
allBundles,
298+
[]rukpakv1alpha1.BundleDeployment{
299+
fakeBundleDeployment("test-bd", bundleImage),
300+
},
301+
)
272302
require.NoError(t, err)
273303

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)
304+
require.Len(t, installedPackages, 1)
305+
packageVariable := installedPackages[0]
279306
assert.Equal(t, deppy.IdentifierFromString("installed package test-package"), packageVariable.Identifier())
280307

281308
// ensure bundles are in version order (high to low)
@@ -284,4 +311,16 @@ func TestInstalledPackageVariableSource(t *testing.T) {
284311
assert.Equal(t, "test-package.v2.1.0", packageVariable.Bundles()[0].Name)
285312
assert.Equal(t, "test-package.v2.0.0", packageVariable.Bundles()[1].Name)
286313
})
314+
315+
t.Run("installed bundle not found", func(t *testing.T) {
316+
const bundleImage = "registry.io/repo/test-package@v9.0.0"
317+
installedPackages, err := variablesources.MakeInstalledPackageVariables(
318+
allBundles,
319+
[]rukpakv1alpha1.BundleDeployment{
320+
fakeBundleDeployment("test-bd", bundleImage),
321+
},
322+
)
323+
assert.Nil(t, installedPackages)
324+
assert.ErrorContains(t, err, `bundleImage "registry.io/repo/test-package@v9.0.0" not found`)
325+
})
287326
}

0 commit comments

Comments
 (0)