Skip to content

Commit d1f6f72

Browse files
committed
Only enqueue installed packages eligible for upgrade on package updates (carvel-dev#136)
1 parent b352b02 commit d1f6f72

File tree

3 files changed

+129
-10
lines changed

3 files changed

+129
-10
lines changed

cmd/controller/handlers/installed_pkg_version_handler.go

+34-9
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@ package handlers
55

66
import (
77
"github.com/go-logr/logr"
8+
ipkgv1alpha1 "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/installpackage/v1alpha1"
9+
pkgv1alpha1 "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/package/v1alpha1"
810
kcclient "github.com/vmware-tanzu/carvel-kapp-controller/pkg/client/clientset/versioned"
11+
versions "github.com/vmware-tanzu/carvel-vendir/pkg/vendir/versions/v1alpha1"
912
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
1014
"k8s.io/apimachinery/pkg/types"
1115
"k8s.io/client-go/util/workqueue"
1216
"sigs.k8s.io/controller-runtime/pkg/event"
@@ -31,48 +35,69 @@ func NewInstalledPkgVersionHandler(c kcclient.Interface, log logr.Logger) *Insta
3135

3236
func (ipvh *InstalledPkgVersionHandler) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
3337
ipvh.log.Info("enqueueing installedPkgList")
34-
err := ipvh.enqueueAllPackages(q)
38+
err := ipvh.enqueueEligibleInstalledPackages(q, evt.Object)
3539
if err != nil {
3640
ipvh.log.Error(err, "enqueueing all installed pakcages")
3741
}
3842
}
3943

4044
func (ipvh *InstalledPkgVersionHandler) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
4145
ipvh.log.Info("enqueueing installedPkgList")
42-
err := ipvh.enqueueAllPackages(q)
46+
err := ipvh.enqueueEligibleInstalledPackages(q, evt.ObjectNew)
4347
if err != nil {
4448
ipvh.log.Error(err, "enqueueing all installed pakcages")
4549
}
4650
}
4751

4852
func (ipvh *InstalledPkgVersionHandler) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
4953
ipvh.log.Info("enqueueing installedPkgList")
50-
err := ipvh.enqueueAllPackages(q)
54+
err := ipvh.enqueueEligibleInstalledPackages(q, evt.Object)
5155
if err != nil {
5256
ipvh.log.Error(err, "enqueueing all installed pakcages")
5357
}
5458
}
5559

5660
func (ipvh *InstalledPkgVersionHandler) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
5761
ipvh.log.Info("enqueueing installedPkgList")
58-
err := ipvh.enqueueAllPackages(q)
62+
err := ipvh.enqueueEligibleInstalledPackages(q, evt.Object)
5963
if err != nil {
6064
ipvh.log.Error(err, "enqueueing all installed pakcages")
6165
}
6266
}
6367

64-
func (ipvh *InstalledPkgVersionHandler) enqueueAllPackages(q workqueue.RateLimitingInterface) error {
68+
func (ipvh *InstalledPkgVersionHandler) enqueueEligibleInstalledPackages(q workqueue.RateLimitingInterface, obj runtime.Object) error {
69+
pkg := obj.(*pkgv1alpha1.Package)
6570
installedPkgList, err := ipvh.client.InstallV1alpha1().InstalledPackages("").List(metav1.ListOptions{})
6671
if err != nil {
6772
return err
6873
}
6974

7075
for _, ip := range installedPkgList.Items {
71-
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
72-
Name: ip.Name,
73-
Namespace: ip.Namespace,
74-
}})
76+
if ip.Spec.PkgRef.PublicName == pkg.Spec.PublicName && ipvh.isEligibleForVersionUpgrade(pkg.Spec.Version, ip) {
77+
q.Add(reconcile.Request{NamespacedName: types.NamespacedName{
78+
Name: ip.Name,
79+
Namespace: ip.Namespace,
80+
}})
81+
}
7582
}
7683

7784
return nil
7885
}
86+
87+
func (ipvh *InstalledPkgVersionHandler) isEligibleForVersionUpgrade(version string, installedPkg ipkgv1alpha1.InstalledPackage) bool {
88+
semverConfig := installedPkg.Spec.PkgRef.VersionSelection
89+
if installedPkg.Spec.PkgRef.Version != "" {
90+
semverConfig = &versions.VersionSelectionSemver{
91+
Constraints: installedPkg.Spec.PkgRef.Version,
92+
// Prereleases must be non nil to be included
93+
Prereleases: &versions.VersionSelectionSemverPrereleases{},
94+
}
95+
}
96+
97+
selectedVersion, err := versions.HighestConstrainedVersion([]string{version}, versions.VersionSelection{Semver: semverConfig})
98+
if selectedVersion == "" || err != nil {
99+
return false
100+
}
101+
102+
return true
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2021 VMware, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package handlers_test
5+
6+
import (
7+
"reflect"
8+
"testing"
9+
10+
"github.com/go-logr/logr"
11+
12+
instpackagev1 "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/installpackage/v1alpha1"
13+
packagev1 "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/package/v1alpha1"
14+
"github.com/vmware-tanzu/carvel-vendir/pkg/vendir/versions/v1alpha1"
15+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
16+
"k8s.io/apimachinery/pkg/types"
17+
18+
"github.com/vmware-tanzu/carvel-kapp-controller/cmd/controller/handlers"
19+
"github.com/vmware-tanzu/carvel-kapp-controller/pkg/client/clientset/versioned/fake"
20+
"k8s.io/client-go/util/workqueue"
21+
"sigs.k8s.io/controller-runtime/pkg/event"
22+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
23+
)
24+
25+
func TestOnlyEligiblePackagesAreEnqueued(t *testing.T) {
26+
q := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
27+
28+
eligibleInstalledPkg := instpackagev1.InstalledPackage{
29+
ObjectMeta: metav1.ObjectMeta{
30+
Name: "expected-pkg",
31+
},
32+
Spec: instpackagev1.InstalledPackageSpec{
33+
PkgRef: &instpackagev1.PackageRef{
34+
PublicName: "expec-pkg",
35+
VersionSelection: &v1alpha1.VersionSelectionSemver{
36+
Constraints: ">=1.0.0",
37+
},
38+
},
39+
},
40+
}
41+
42+
ineligibleInstalledPkg := instpackagev1.InstalledPackage{
43+
ObjectMeta: metav1.ObjectMeta{
44+
Name: "expected-pkg-ineligible",
45+
},
46+
Spec: instpackagev1.InstalledPackageSpec{
47+
PkgRef: &instpackagev1.PackageRef{
48+
PublicName: "expec-pkg",
49+
VersionSelection: &v1alpha1.VersionSelectionSemver{
50+
Constraints: "<1.0.0",
51+
},
52+
},
53+
},
54+
}
55+
56+
// Load installed package into fake client
57+
kappcs := fake.NewSimpleClientset(&eligibleInstalledPkg, &ineligibleInstalledPkg)
58+
ipvh := handlers.NewInstalledPkgVersionHandler(kappcs, &EmptyLog{})
59+
60+
event := event.GenericEvent{
61+
Object: &packagev1.Package{
62+
Spec: packagev1.PackageSpec{
63+
PublicName: "expec-pkg",
64+
Version: "1.5.0",
65+
},
66+
},
67+
}
68+
69+
ipvh.Generic(event, q)
70+
71+
if q.Len() != 1 {
72+
t.Fatalf("Expected queue to have length of 1, got %d", q.Len())
73+
}
74+
75+
expectedRequest := reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "", Name: "expected-pkg"}}
76+
if obj, _ := q.Get(); !reflect.DeepEqual(obj, expectedRequest) {
77+
t.Fatalf("Expected queue to contain the installed package eligible for upgrade, but contained:\n\n%#v\n", obj)
78+
}
79+
80+
}
81+
82+
type EmptyLog struct{}
83+
84+
func (l *EmptyLog) Info(msg string, keysAndValues ...interface{}) {}
85+
86+
func (l *EmptyLog) Enabled() bool { return false }
87+
88+
func (l *EmptyLog) Error(err error, msg string, keysAndValues ...interface{}) {}
89+
90+
func (l *EmptyLog) V(level int) logr.InfoLogger { return l }
91+
92+
func (l *EmptyLog) WithValues(keysAndValues ...interface{}) logr.Logger { return l }
93+
94+
func (l *EmptyLog) WithName(name string) logr.Logger { return l }

hack/test.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ fi
88

99
set -u
1010

11-
go test ./pkg/... -test.v $@
11+
go test ./pkg/... ./cmd/... -test.v $@
1212

1313
echo UNIT SUCCESS

0 commit comments

Comments
 (0)