Skip to content

Commit 14994c6

Browse files
committed
MGMT-19979: Propagate ClusterVersion upgrade status message
Adds the upgrade message from the ClusterVersion in the workload cluster to the OACP's upgrade status so it's transparent to the user. Also adds a failure reason in case the upgrade fails.
1 parent 56b7af3 commit 14994c6

File tree

6 files changed

+98
-12
lines changed

6 files changed

+98
-12
lines changed

controlplane/api/v1alpha2/condition_consts.go

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ const (
3636
// UpgradeInProgressReason (Severity=Info) documents that an upgrade is in progress.
3737
UpgradeInProgressReason = "UpgradeInProgress"
3838

39+
// UpgradeFailedReason (Severity=Error) documents that an upgrade has failed.
40+
UpgradeFailedReason = "UpgradeFailed"
41+
3942
// UpgradeImageUnavailableReason (Severity=Error) documents whether an upgrade image is available
4043
UpgradeImageUnavailableReason = "UpgradeImageUnavailable"
4144

controlplane/internal/controller/openshiftassistedcontrolplane_controller.go

+27-8
Original file line numberDiff line numberDiff line change
@@ -286,16 +286,11 @@ func (r *OpenshiftAssistedControlPlaneReconciler) upgradeWorkloadCluster(ctx con
286286
log := ctrl.LoggerFrom(ctx)
287287

288288
var isUpdateInProgress bool
289+
var upgradeConditionMessage string
289290
defer func() {
290291
if isUpdateInProgress || !isWorkloadClusterRunningDesiredVersion(oacp) {
291-
conditions.MarkFalse(
292-
oacp,
293-
controlplanev1alpha2.UpgradeCompletedCondition,
294-
controlplanev1alpha2.UpgradeInProgressReason,
295-
clusterv1.ConditionSeverityInfo,
296-
"upgrade to version %s in progress",
297-
oacp.Spec.DistributionVersion,
298-
)
292+
// Either upgrade is in progress or it failed
293+
setUpgradeStatus(oacp, isUpdateInProgress, upgradeConditionMessage)
299294
return
300295
}
301296
if conditions.IsFalse(oacp, controlplanev1alpha2.UpgradeCompletedCondition) {
@@ -316,6 +311,10 @@ func (r *OpenshiftAssistedControlPlaneReconciler) upgradeWorkloadCluster(ctx con
316311
if err != nil {
317312
return ctrl.Result{}, err
318313
}
314+
upgradeConditionMessage, err = upgrader.GetUpgradeStatus(ctx)
315+
if err != nil {
316+
return ctrl.Result{}, err
317+
}
319318

320319
oacp.Status.DistributionVersion, err = upgrader.GetCurrentVersion(ctx)
321320
if err != nil {
@@ -354,6 +353,26 @@ func (r *OpenshiftAssistedControlPlaneReconciler) upgradeWorkloadCluster(ctx con
354353
)
355354
}
356355

356+
func setUpgradeStatus(oacp *controlplanev1alpha2.OpenshiftAssistedControlPlane, upgradeInProgress bool, conditionMessage string) {
357+
reason := controlplanev1alpha2.UpgradeInProgressReason
358+
severity := clusterv1.ConditionSeverityInfo
359+
msg := "upgrade to version %s in progress\n%s"
360+
if !upgradeInProgress {
361+
reason = controlplanev1alpha2.UpgradeFailedReason
362+
severity = clusterv1.ConditionSeverityError
363+
msg = "upgrade to version %s has failed\n%s"
364+
}
365+
conditions.MarkFalse(
366+
oacp,
367+
controlplanev1alpha2.UpgradeCompletedCondition,
368+
reason,
369+
severity,
370+
msg,
371+
oacp.Spec.DistributionVersion,
372+
conditionMessage,
373+
)
374+
}
375+
357376
func getUpgradeOptions(oacp *controlplanev1alpha2.OpenshiftAssistedControlPlane, pullSecret []byte) []upgrade.ClusterUpgradeOption {
358377
upgradeOptions := []upgrade.ClusterUpgradeOption{
359378
{

controlplane/internal/controller/openshiftassistedcontrolplane_controller_test.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ var _ = Describe("OpenshiftAssistedControlPlane Controller", func() {
8181
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(false, nil).AnyTimes()
8282
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return("4.18.0", nil).AnyTimes()
8383
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), gomock.Any()).Return(true, nil).AnyTimes()
84+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("", nil).AnyTimes()
8485

8586
mockUpgradeFactory = upgrade.NewMockClusterUpgradeFactory(ctrl)
8687
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil).AnyTimes()
@@ -384,6 +385,7 @@ var _ = Describe("Upgrade scenarios", func() {
384385
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil)
385386
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(false, nil)
386387
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return(currentVersion, nil)
388+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("", nil)
387389
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), desiredVersion).Return(false, nil)
388390
mockUpgrader.EXPECT().UpdateClusterVersionDesiredUpdate(gomock.Any(), desiredVersion, gomock.Any(), gomock.Any()).Return(nil)
389391

@@ -403,6 +405,7 @@ var _ = Describe("Upgrade scenarios", func() {
403405
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil)
404406
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(true, nil)
405407
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return(currentVersion, nil)
408+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("upgrading cluster", nil)
406409
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), desiredVersion).Return(true, nil)
407410
conditions.MarkFalse(openshiftAssistedControlPlane, controlplanev1alpha2.UpgradeCompletedCondition, controlplanev1alpha2.UpgradeInProgressReason, clusterv1.ConditionSeverityInfo, "upgrade in progress")
408411

@@ -417,12 +420,14 @@ var _ = Describe("Upgrade scenarios", func() {
417420
Expect(condition).NotTo(BeNil())
418421
Expect(condition.Status).To(Equal(corev1.ConditionFalse))
419422
Expect(condition.Reason).To(Equal(controlplanev1alpha2.UpgradeInProgressReason))
423+
Expect(condition.Message).To(Equal("upgrade to version 4.15.0 in progress\nupgrading cluster"))
420424
})
421425

422426
It("should handle completed upgrade", func() {
423427
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil)
424428
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(false, nil)
425429
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return(desiredVersion, nil)
430+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("", nil)
426431
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), desiredVersion).Return(true, nil)
427432

428433
// Make sure upgrade is in progress: once we reconcile it should be marked as complete
@@ -453,6 +458,7 @@ var _ = Describe("Upgrade scenarios", func() {
453458
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil)
454459
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(false, nil)
455460
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return(currentVersion, nil)
461+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("failed to upgrade", nil)
456462
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), desiredVersion).Return(false, nil)
457463
mockUpgrader.EXPECT().UpdateClusterVersionDesiredUpdate(gomock.Any(), desiredVersion, gomock.Any(), gomock.Any()).Return(expectedError)
458464

@@ -469,17 +475,22 @@ var _ = Describe("Upgrade scenarios", func() {
469475
Expect(err).To(HaveOccurred())
470476
Expect(err).To(Equal(expectedError))
471477

472-
// Upgrade is in progres: spec.distributionVersion is 4.15 and status.distributionVersion is 4.14
478+
err = k8sClient.Get(ctx, typeNamespacedName, openshiftAssistedControlPlane)
479+
Expect(err).NotTo(HaveOccurred())
480+
// Upgrade is in progress but failed: spec.distributionVersion is 4.15 and status.distributionVersion is 4.14
473481
condition := conditions.Get(openshiftAssistedControlPlane, controlplanev1alpha2.UpgradeCompletedCondition)
474482
Expect(condition).NotTo(BeNil())
475483
Expect(condition.Status).To(Equal(corev1.ConditionFalse))
484+
Expect(condition.Reason).To(Equal(controlplanev1alpha2.UpgradeFailedReason))
485+
Expect(condition.Message).To(Equal("upgrade to version 4.15.0 has failed\nfailed to upgrade"))
476486
})
477487

478488
It("should handle errors getting current version", func() {
479489
expectedError := fmt.Errorf("failed to get version")
480490
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil)
481491
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(false, nil)
482492
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return("", expectedError)
493+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("failed to upgrade", nil)
483494
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), desiredVersion).Return(true, nil)
484495
mockUpgrader.EXPECT().UpdateClusterVersionDesiredUpdate(ctx, desiredVersion, gomock.Any(), gomock.Any()).Return(nil)
485496

@@ -494,8 +505,8 @@ var _ = Describe("Upgrade scenarios", func() {
494505
condition := conditions.Get(openshiftAssistedControlPlane, controlplanev1alpha2.UpgradeCompletedCondition)
495506
Expect(condition).NotTo(BeNil())
496507
Expect(condition.Status).To(Equal(corev1.ConditionFalse))
497-
Expect(condition.Reason).To(Equal(controlplanev1alpha2.UpgradeInProgressReason))
498-
Expect(condition.Message).To(Equal("upgrade to version 4.15.0 in progress"))
508+
Expect(condition.Reason).To(Equal(controlplanev1alpha2.UpgradeFailedReason))
509+
Expect(condition.Message).To(Equal("upgrade to version 4.15.0 has failed\nfailed to upgrade"))
499510
})
500511

501512
It("should handle upgrade with repository override", func() {
@@ -506,8 +517,9 @@ var _ = Describe("Upgrade scenarios", func() {
506517
Expect(k8sClient.Update(ctx, openshiftAssistedControlPlane)).To(Succeed())
507518

508519
mockUpgradeFactory.EXPECT().NewUpgrader(gomock.Any()).Return(mockUpgrader, nil)
509-
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(false, nil)
520+
mockUpgrader.EXPECT().IsUpgradeInProgress(gomock.Any()).Return(true, nil) // should this be successfully starting upgrade?
510521
mockUpgrader.EXPECT().GetCurrentVersion(gomock.Any()).Return(currentVersion, nil)
522+
mockUpgrader.EXPECT().GetUpgradeStatus(gomock.Any()).Return("", nil)
511523
mockUpgrader.EXPECT().IsDesiredVersionUpdated(gomock.Any(), desiredVersion).Return(false, nil)
512524
expectedParams := []upgrade.ClusterUpgradeOption{
513525
{Name: upgrade.ReleaseImagePullSecretOption, Value: "{\"auths\":{\"fake-pull-secret\":{\"auth\":\"cGxhY2Vob2xkZXI6c2VjcmV0Cg==\"}}}"},
@@ -528,6 +540,7 @@ var _ = Describe("Upgrade scenarios", func() {
528540
condition := conditions.Get(openshiftAssistedControlPlane, controlplanev1alpha2.UpgradeCompletedCondition)
529541
Expect(condition).NotTo(BeNil())
530542
Expect(condition.Status).To(Equal(corev1.ConditionFalse))
543+
Expect(condition.Message).To(Equal("upgrade to version 4.15.0 in progress\n"))
531544
})
532545
})
533546

controlplane/internal/upgrade/mock_upgrade.go

+15
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controlplane/internal/upgrade/upgrade.go

+19
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type ClusterUpgrade interface {
3535
IsUpgradeInProgress(ctx context.Context) (bool, error)
3636
GetCurrentVersion(ctx context.Context) (string, error)
3737
IsDesiredVersionUpdated(ctx context.Context, desiredVersion string) (bool, error)
38+
GetUpgradeStatus(ctx context.Context) (string, error)
3839
UpdateClusterVersionDesiredUpdate(ctx context.Context, desiredVersion string, architecture string, options ...ClusterUpgradeOption) error
3940
}
4041

@@ -113,6 +114,24 @@ func (u *OpenshiftUpgrader) GetCurrentVersion(ctx context.Context) (string, erro
113114
return "", fmt.Errorf("no completed update found in ClusterVersion history")
114115
}
115116

117+
// Returns the cluster version's current upgrade condition message for the client's cluster.
118+
// If any error occurs while performing this operation, it will be returned.
119+
func (u *OpenshiftUpgrader) GetUpgradeStatus(ctx context.Context) (string, error) {
120+
clusterVersion, err := u.getClusterVersion(ctx)
121+
if err != nil {
122+
return "", err
123+
}
124+
for _, condition := range clusterVersion.Status.Conditions {
125+
// Condition is only set to one of Available, Progressing, and Degraded
126+
// and they are mutually exclusive, so only one of these is true
127+
// at any given point.
128+
if condition.Status == configv1.ConditionTrue {
129+
return condition.Message, nil
130+
}
131+
}
132+
return "", nil
133+
}
134+
116135
// Returns true if the desired version matches the cluster's desired version, false otherwise. If any error occurs while
117136
// performing this operation, it will be returned
118137
func (u *OpenshiftUpgrader) IsDesiredVersionUpdated(ctx context.Context, desiredVersion string) (bool, error) {

controlplane/internal/upgrade/upgrade_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,13 @@ var _ = Describe("OpenShift Upgrader", func() {
176176
Expect(updatedCV.Spec.DesiredUpdate.Force).To(BeTrue())
177177
})
178178
})
179+
Context("GetUpgradeStatus", func() {
180+
It("should return an upgrade is in progress message", func() {
181+
msg, err := upgrader.GetUpgradeStatus(ctx)
182+
Expect(err).To(BeNil())
183+
Expect(msg).To(Equal("upgrade is in progress"))
184+
})
185+
})
179186
})
180187
})
181188

@@ -189,6 +196,16 @@ func getClusterVersion(history []configv1.UpdateHistory) configv1.ClusterVersion
189196
Desired: configv1.Release{
190197
Version: "4.10.0",
191198
},
199+
Conditions: []configv1.ClusterOperatorStatusCondition{
200+
{
201+
Message: "upgrade is in progress",
202+
Status: configv1.ConditionTrue,
203+
},
204+
{
205+
Message: "upgrade is not in progress",
206+
Status: configv1.ConditionFalse,
207+
},
208+
},
192209
},
193210
}
194211
}

0 commit comments

Comments
 (0)