Skip to content

Commit c774f08

Browse files
committed
NE-2097: Avoid installing past desired version
This commit introduces a sematic version check for the CSV of next installplan. If the next installplan has a version which is sematically past the desired it's not considered for the upgrade.
1 parent ead2398 commit c774f08

File tree

9 files changed

+639
-0
lines changed

9 files changed

+639
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/IBM/go-sdk-core/v5 v5.17.4
1414
github.com/IBM/networking-go-sdk v0.26.0
1515
github.com/aws/aws-sdk-go v1.38.49
16+
github.com/coreos/go-semver v0.3.1
1617
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
1718
github.com/florianl/go-nfqueue v1.3.2
1819
github.com/go-logr/logr v1.4.2

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH
8080
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
8181
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
8282
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
83+
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
84+
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
8385
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
8486
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
8587
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

pkg/operator/controller/gatewayclass/subscription.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package gatewayclass
33
import (
44
"context"
55
"fmt"
6+
"regexp"
67

8+
"github.com/coreos/go-semver/semver"
79
"github.com/google/go-cmp/cmp"
810
"github.com/google/go-cmp/cmp/cmpopts"
911
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -31,6 +33,11 @@ const (
3133
WorkloadPartitioningManagementPreferredScheduling = `{"effect": "PreferredDuringScheduling"}`
3234
)
3335

36+
var (
37+
// csvSemVerRegexp is a RegExp to extract semantic version from OLM CSV name.
38+
csvSemVerRegexp = regexp.MustCompile(`v(\d+\.\d+\.\d+)`)
39+
)
40+
3441
// ensureServiceMeshOperatorSubscription attempts to ensure that a subscription
3542
// for servicemeshoperator is present and returns a Boolean indicating whether
3643
// it exists, the subscription if it exists, and an error value.
@@ -193,6 +200,8 @@ func (r *reconciler) currentInstallPlan(ctx context.Context, version string) (bo
193200
}
194201
var currentInstallPlan, nextInstallPlan *operatorsv1alpha1.InstallPlan
195202
multipleInstallPlans := false
203+
desiredCSVSemVer, currentCSVSemVer := extractSemVerFromCSV(version), extractSemVerFromCSV(subscription.Status.CurrentCSV)
204+
196205
for _, installPlan := range installPlans.Items {
197206
if len(installPlan.OwnerReferences) == 0 || len(installPlan.Spec.ClusterServiceVersionNames) == 0 {
198207
continue
@@ -317,3 +326,15 @@ func installPlanChanged(current, expected *operatorsv1alpha1.InstallPlan) (bool,
317326

318327
return true, updated
319328
}
329+
330+
// extractSemVerFromCSV exctracts the semantic version from an OLM CSV name.
331+
// Returns a nil pointer if it fails to parse the CSV name.
332+
func extractSemVerFromCSV(csv string) *semver.Version {
333+
match := csvSemVerRegexp.FindStringSubmatch(csv)
334+
if len(match) > 1 {
335+
if v, err := semver.NewVersion(match[1]); err == nil {
336+
return v
337+
}
338+
}
339+
return nil
340+
}

pkg/operator/controller/gatewayclass/subscription_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,77 @@ func Test_ensureServiceMeshOperatorInstallPlan(t *testing.T) {
986986
},
987987
expectUpdate: []client.Object{},
988988
},
989+
{
990+
name: "Upgrade to non-existing desired version",
991+
channel: "stable",
992+
version: "servicemeshoperator.v1.0.2",
993+
existingObjects: []runtime.Object{
994+
&operatorsv1alpha1.Subscription{
995+
ObjectMeta: metav1.ObjectMeta{
996+
Namespace: operatorcontroller.ServiceMeshOperatorSubscriptionName().Namespace,
997+
Name: operatorcontroller.ServiceMeshOperatorSubscriptionName().Name,
998+
UID: "foobar",
999+
},
1000+
Spec: &operatorsv1alpha1.SubscriptionSpec{
1001+
Channel: "stable",
1002+
InstallPlanApproval: operatorsv1alpha1.ApprovalManual,
1003+
Package: "servicemeshoperator",
1004+
CatalogSource: "redhat-operators",
1005+
CatalogSourceNamespace: "openshift-marketplace",
1006+
StartingCSV: "servicemeshoperator.v1.0.2",
1007+
},
1008+
Status: operatorsv1alpha1.SubscriptionStatus{
1009+
InstalledCSV: "servicemeshoperator.v1.0.1",
1010+
CurrentCSV: "servicemeshoperator.v1.0.3", // 1.0.2 was skipped from upgrade graph
1011+
},
1012+
},
1013+
// Current
1014+
&operatorsv1alpha1.InstallPlan{
1015+
ObjectMeta: metav1.ObjectMeta{
1016+
Name: "Install-bar",
1017+
Namespace: operatorcontroller.OpenshiftOperatorNamespace,
1018+
OwnerReferences: []metav1.OwnerReference{
1019+
{
1020+
UID: "foobar",
1021+
},
1022+
},
1023+
},
1024+
Spec: operatorsv1alpha1.InstallPlanSpec{
1025+
ClusterServiceVersionNames: []string{
1026+
"servicemeshoperator.v1.0.1",
1027+
},
1028+
Approval: operatorsv1alpha1.ApprovalManual,
1029+
Approved: true,
1030+
},
1031+
Status: operatorsv1alpha1.InstallPlanStatus{
1032+
Phase: operatorsv1alpha1.InstallPlanPhaseComplete,
1033+
},
1034+
},
1035+
// N+2 (and expected is in between but skipped).
1036+
&operatorsv1alpha1.InstallPlan{
1037+
ObjectMeta: metav1.ObjectMeta{
1038+
Name: "Install-baz",
1039+
Namespace: operatorcontroller.OpenshiftOperatorNamespace,
1040+
OwnerReferences: []metav1.OwnerReference{
1041+
{
1042+
UID: "foobar",
1043+
},
1044+
},
1045+
},
1046+
Spec: operatorsv1alpha1.InstallPlanSpec{
1047+
ClusterServiceVersionNames: []string{
1048+
"servicemeshoperator.v1.0.3",
1049+
},
1050+
Approval: operatorsv1alpha1.ApprovalManual,
1051+
Approved: false,
1052+
},
1053+
Status: operatorsv1alpha1.InstallPlanStatus{
1054+
Phase: operatorsv1alpha1.InstallPlanPhaseRequiresApproval,
1055+
},
1056+
},
1057+
},
1058+
expectUpdate: []client.Object{},
1059+
},
9891060
}
9901061

9911062
scheme := runtime.NewScheme()

vendor/github.com/coreos/go-semver/LICENSE

Lines changed: 202 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/coreos/go-semver/NOTICE

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)