@@ -27,6 +27,7 @@ import (
27
27
"time"
28
28
29
29
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
30
+ corev1 "k8s.io/api/core/v1"
30
31
apierrors "k8s.io/apimachinery/pkg/api/errors"
31
32
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
33
"k8s.io/apimachinery/pkg/types"
@@ -188,6 +189,15 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
188
189
}
189
190
defer rosaClient .Close ()
190
191
192
+ isValid , err := validateControlPlaneSpec (rosaClient , rosaScope )
193
+ if err != nil {
194
+ return ctrl.Result {}, fmt .Errorf ("failed to validate ROSAControlPlane.spec: %w" , err )
195
+ }
196
+ if ! isValid {
197
+ // dont' requeue because input is invalid and manual intervention is needed.
198
+ return ctrl.Result {}, nil
199
+ }
200
+
191
201
cluster , err := rosaClient .GetCluster ()
192
202
if err != nil {
193
203
return ctrl.Result {}, err
@@ -213,6 +223,9 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
213
223
if err := r .reconcileKubeconfig (ctx , rosaScope , rosaClient , cluster ); err != nil {
214
224
return ctrl.Result {}, fmt .Errorf ("failed to reconcile kubeconfig: %w" , err )
215
225
}
226
+ if err := r .reconcileClusterVersion (rosaScope , rosaClient , cluster ); err != nil {
227
+ return ctrl.Result {}, err
228
+ }
216
229
return ctrl.Result {}, nil
217
230
case cmv1 .ClusterStateError :
218
231
errorMessage := cluster .Status ().ProvisionErrorMessage ()
@@ -255,7 +268,7 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
255
268
DisableUserWorkloadMonitoring (true ).
256
269
Version (
257
270
cmv1 .NewVersion ().
258
- ID (* rosaScope .ControlPlane .Spec .Version ).
271
+ ID (fmt . Sprintf ( "openshift-v%s" , rosaScope .ControlPlane .Spec .Version ) ).
259
272
ChannelGroup ("stable" ),
260
273
).
261
274
ExpirationTimestamp (time .Now ().Add (1 * time .Hour )).
@@ -394,6 +407,41 @@ func (r *ROSAControlPlaneReconciler) reconcileDelete(ctx context.Context, rosaSc
394
407
return ctrl.Result {RequeueAfter : time .Second * 60 }, nil
395
408
}
396
409
410
+ func (r * ROSAControlPlaneReconciler ) reconcileClusterVersion (rosaScope * scope.ROSAControlPlaneScope , rosaClient * rosa.RosaClient , cluster * cmv1.Cluster ) error {
411
+ version := rosaScope .ControlPlane .Spec .Version
412
+ if version == cluster .Version ().RawID () {
413
+ conditions .MarkFalse (rosaScope .ControlPlane , rosacontrolplanev1 .ROSAControlPlaneUpgradingCondition , "upgraded" , clusterv1 .ConditionSeverityInfo , "" )
414
+ return nil
415
+ }
416
+
417
+ scheduledUpgrade , err := rosaClient .CheckExistingScheduledUpgrade (cluster )
418
+ if err != nil {
419
+ return fmt .Errorf ("failed to get existing scheduled upgrades: %w" , err )
420
+ }
421
+
422
+ if scheduledUpgrade == nil {
423
+ scheduledUpgrade , err = rosaClient .ScheduleControlPlaneUpgrade (cluster , version , time .Now ())
424
+ if err != nil {
425
+ return fmt .Errorf ("failed to schedule control plane upgrade to version %s: %w" , version , err )
426
+ }
427
+ }
428
+
429
+ condition := & clusterv1.Condition {
430
+ Type : rosacontrolplanev1 .ROSAControlPlaneUpgradingCondition ,
431
+ Status : corev1 .ConditionTrue ,
432
+ Reason : string (scheduledUpgrade .State ().Value ()),
433
+ Message : fmt .Sprintf ("Upgrading to version %s" , scheduledUpgrade .Version ()),
434
+ }
435
+ conditions .Set (rosaScope .ControlPlane , condition )
436
+
437
+ // if cluster is already upgrading to another version we need to wait until the current upgrade is finished, return an error to requeue and try later.
438
+ if scheduledUpgrade .Version () != version {
439
+ return fmt .Errorf ("there is already a %s upgrade to version %s" , scheduledUpgrade .State ().Value (), scheduledUpgrade .Version ())
440
+ }
441
+
442
+ return nil
443
+ }
444
+
397
445
func (r * ROSAControlPlaneReconciler ) reconcileKubeconfig (ctx context.Context , rosaScope * scope.ROSAControlPlaneScope , rosaClient * rosa.RosaClient , cluster * cmv1.Cluster ) error {
398
446
rosaScope .Debug ("Reconciling ROSA kubeconfig for cluster" , "cluster-name" , rosaScope .RosaClusterName ())
399
447
@@ -510,6 +558,26 @@ func (r *ROSAControlPlaneReconciler) reconcileClusterAdminPassword(ctx context.C
510
558
return password , nil
511
559
}
512
560
561
+ func validateControlPlaneSpec (rosaClient * rosa.RosaClient , rosaScope * scope.ROSAControlPlaneScope ) (bool , error ) {
562
+ // reset previous message.
563
+ rosaScope .ControlPlane .Status .FailureMessage = nil
564
+
565
+ version := rosaScope .ControlPlane .Spec .Version
566
+ isSupported , err := rosaClient .IsVersionSupported (version )
567
+ if err != nil {
568
+ return false , err
569
+ }
570
+
571
+ if ! isSupported {
572
+ message := fmt .Sprintf ("version %s is not supported" , version )
573
+ rosaScope .ControlPlane .Status .FailureMessage = & message
574
+ return false , nil
575
+ }
576
+
577
+ // TODO: add more input validations
578
+ return true , nil
579
+ }
580
+
513
581
func (r * ROSAControlPlaneReconciler ) rosaClusterToROSAControlPlane (log * logger.Logger ) handler.MapFunc {
514
582
return func (ctx context.Context , o client.Object ) []ctrl.Request {
515
583
rosaCluster , ok := o .(* expinfrav1.ROSACluster )
0 commit comments