Skip to content

Commit 6322ced

Browse files
committed
NE-2097: Add logic to pick up next InstallPlan if desired version jumps upgrade graph
1 parent 0820427 commit 6322ced

File tree

4 files changed

+447
-2
lines changed

4 files changed

+447
-2
lines changed

manifests/00-cluster-role.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ rules:
180180
resources:
181181
- subscriptions
182182
- installplans
183+
- clusterserviceversions
183184
verbs:
184185
- '*'
185186

manifests/02-deployment.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ spec:
8787
value: redhat-operators
8888
- name: GATEWAY_API_OPERATOR_CHANNEL
8989
value: stable
90+
# NOTE:
91+
# Use an operator version that exists in the catalog.
92+
# If the specified version is not found, the latest available
93+
# OSSM operator version will be installed as of the upgrade date.
94+
# Downgrades are not supported; the new version must be
95+
# semantically greater than the previous one.
9096
- name: GATEWAY_API_OPERATOR_VERSION
9197
value: servicemeshoperator3.v3.0.1
9298
- name: ISTIO_VERSION

pkg/operator/controller/gatewayclass/subscription.go

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ func (r *reconciler) ensureServiceMeshOperatorInstallPlan(ctx context.Context, v
176176
}
177177

178178
// currentInstallPlan returns the InstallPlan that describes installing the expected version of the GatewayAPI
179-
// implementation, if one exists.
179+
// implementation. If no InstallPlan exists for the expected version, return the InstallPlan which replaces the currently installed one.
180+
// This InstallPlan is expected to advance the OSSM operator toward the next CSV in the upgrade graph,
181+
// assuming that the configured version is available further up the graph.
180182
func (r *reconciler) currentInstallPlan(ctx context.Context, version string) (bool, *operatorsv1alpha1.InstallPlan, error) {
181183
_, subscription, err := r.currentSubscription(ctx, operatorcontroller.ServiceMeshOperatorSubscriptionName())
182184
if err != nil {
@@ -189,7 +191,7 @@ func (r *reconciler) currentInstallPlan(ctx context.Context, version string) (bo
189191
if installPlans == nil || len(installPlans.Items) == 0 {
190192
return false, nil, nil
191193
}
192-
var currentInstallPlan *operatorsv1alpha1.InstallPlan
194+
var currentInstallPlan, nextInstallPlan *operatorsv1alpha1.InstallPlan
193195
multipleInstallPlans := false
194196
for _, installPlan := range installPlans.Items {
195197
if len(installPlan.OwnerReferences) == 0 || len(installPlan.Spec.ClusterServiceVersionNames) == 0 {
@@ -209,6 +211,7 @@ func (r *reconciler) currentInstallPlan(ctx context.Context, version string) (bo
209211
if installPlan.Status.Phase != operatorsv1alpha1.InstallPlanPhaseRequiresApproval {
210212
continue
211213
}
214+
// Check whether InstallPlan implements the expected operator version.
212215
for _, csvName := range installPlan.Spec.ClusterServiceVersionNames {
213216
if csvName == version {
214217
// Keep the newest InstallPlan to return at the end of the loop.
@@ -223,10 +226,62 @@ func (r *reconciler) currentInstallPlan(ctx context.Context, version string) (bo
223226
}
224227
}
225228
}
229+
// Check whether InstallPlan implements the next operator version in the upgrade graph.
230+
for _, csvName := range installPlan.Spec.ClusterServiceVersionNames {
231+
// The definitions of InstalledCSV and CurrentCSV are non-trivial:
232+
//
233+
// - InstalledCSV represents the currently running CSV.
234+
// - CurrentCSV represents the version that "subscription is progressing to"
235+
// which practically means "the next CSV in the upgrade graph."
236+
//
237+
// - If InstalledCSV < CurrentCSV:
238+
// No CSV replacement is ongoing. InstalledCSV is the current version,
239+
// and CurrentCSV is the next one in the upgrade graph.
240+
// - If InstalledCSV == CurrentCSV:
241+
// One of the following scenarios is possible:
242+
// 1. CSV replacement is in progress "InstalledCSV-1" is being replaced with CurrentCSV.
243+
// 2. Installation of the first CSV is in progress.
244+
// 3. There is no "next CSV" in the upgrade graph, so CurrentCSV
245+
// cannot point to a future version.
246+
// CurrentCSV only becomes the next version once the replacement finishes,
247+
// and the next InstallPlan appears around the same time.
248+
//
249+
// The first condition (below) prevents setting the next InstallPlan while a replacement
250+
// or installation is ongoing, or when the end of the upgrade graph is reached.
251+
if subscription.Status.InstalledCSV != subscription.Status.CurrentCSV && csvName == subscription.Status.CurrentCSV {
252+
// CurrentCSV should not be greater (semver-wise) than desiredCSV to avoid upgrading past the desired version,
253+
// in case the desired one was skipped.
254+
// Note: since we use the "stable" channel, the upgrade graph allows transitions between minor releases.
255+
// For example, after installing 3.0.3, we may see 3.1.0 in currentCSV.
256+
if currentCSVSemVer != nil && desiredCSVSemVer != nil && currentCSVSemVer.Compare(*desiredCSVSemVer) != 1 {
257+
if nextInstallPlan == nil {
258+
nextInstallPlan = &installPlan
259+
break
260+
}
261+
}
262+
}
263+
}
226264
}
227265
if multipleInstallPlans {
228266
log.Info(fmt.Sprintf("found multiple valid InstallPlans. using %s because it's the newest", currentInstallPlan.Name))
229267
}
268+
// No InstallPlan with the expected operator version was found,
269+
// but the next one in the upgrade graph exists.
270+
// Return the next InstallPlan to continue the upgrade.
271+
if currentInstallPlan == nil && nextInstallPlan != nil {
272+
log.Info("next install plan time")
273+
// The condition below prevents approving an InstallPlan
274+
// that targets a version beyond the expected operator version.
275+
// This can happen when:
276+
// - InstallPlan with the expected version is complete (no approval needed).
277+
// - Newer versions exist in the upgrade graph.
278+
// The check ensures that the currently running CSV is different
279+
// from the expected version. Once they match, no further action is needed.
280+
if subscription.Status.InstalledCSV != version {
281+
log.Info("installplan with expected operator version was not found; proceedng with an intermedite installplan", "name", nextInstallPlan.Name, "csv", subscription.Status.CurrentCSV)
282+
currentInstallPlan = nextInstallPlan
283+
}
284+
}
230285
return (currentInstallPlan != nil), currentInstallPlan, nil
231286
}
232287

0 commit comments

Comments
 (0)