@@ -24,9 +24,7 @@ import (
24
24
"strings"
25
25
"time"
26
26
27
- sdk "github.com/openshift-online/ocm-sdk-go"
28
27
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"
29
- ocmerrors "github.com/openshift-online/ocm-sdk-go/errors"
30
28
apierrors "k8s.io/apimachinery/pkg/api/errors"
31
29
"k8s.io/apimachinery/pkg/types"
32
30
ctrl "sigs.k8s.io/controller-runtime"
@@ -40,6 +38,7 @@ import (
40
38
expinfrav1 "sigs.k8s.io/cluster-api-provider-aws/v2/exp/api/v1beta2"
41
39
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/scope"
42
40
"sigs.k8s.io/cluster-api-provider-aws/v2/pkg/logger"
41
+ "sigs.k8s.io/cluster-api-provider-aws/v2/pkg/rosa"
43
42
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
44
43
"sigs.k8s.io/cluster-api/util"
45
44
capiannotations "sigs.k8s.io/cluster-api/util/annotations"
@@ -171,9 +170,47 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
171
170
}
172
171
}
173
172
173
+ // TODO: token should be read from a secret: https://github.com/kubernetes-sigs/cluster-api-provider-aws/issues/4460
174
+ token := os .Getenv ("OCM_TOKEN" )
175
+ rosaClient , err := rosa .NewRosaClient (token )
176
+ if err != nil {
177
+ return ctrl.Result {}, fmt .Errorf ("failed to create a rosa client: %w" , err )
178
+ }
179
+
180
+ defer func () {
181
+ rosaClient .Close ()
182
+ }()
183
+
184
+ cluster , err := rosaClient .GetCluster (rosaScope .RosaClusterName (), rosaScope .ControlPlane .Spec .CreatorARN )
185
+ if err != nil {
186
+ return ctrl.Result {}, err
187
+ }
188
+
189
+ if clusterID := cluster .ID (); clusterID != "" {
190
+ rosaScope .ControlPlane .Status .ID = & clusterID
191
+ if cluster .Status ().State () == "ready" {
192
+ conditions .MarkTrue (rosaScope .ControlPlane , rosacontrolplanev1 .ROSAControlPlaneReadyCondition )
193
+ rosaScope .ControlPlane .Status .Ready = true
194
+ // TODO: distinguish when controlPlane is ready vs initialized
195
+ rosaScope .ControlPlane .Status .Initialized = true
196
+
197
+ return ctrl.Result {}, nil
198
+ }
199
+
200
+ conditions .MarkFalse (rosaScope .ControlPlane ,
201
+ rosacontrolplanev1 .ROSAControlPlaneReadyCondition ,
202
+ string (cluster .Status ().State ()),
203
+ clusterv1 .ConditionSeverityInfo ,
204
+ "" )
205
+
206
+ rosaScope .Info ("waiting for cluster to become ready" , "state" , cluster .Status ().State ())
207
+ // Requeue so that status.ready is set to true when the cluster is fully created.
208
+ return ctrl.Result {RequeueAfter : time .Second * 60 }, nil
209
+ }
210
+
174
211
// Create the cluster:
175
212
clusterBuilder := cmv1 .NewCluster ().
176
- Name (rosaScope .ControlPlane . Name [: 15 ] ).
213
+ Name (rosaScope .RosaClusterName () ).
177
214
MultiAZ (true ).
178
215
Product (
179
216
cmv1 .NewProduct ().
@@ -283,86 +320,46 @@ func (r *ROSAControlPlaneReconciler) reconcileNormal(ctx context.Context, rosaSc
283
320
return ctrl.Result {}, fmt .Errorf ("failed to create description of cluster: %v" , err )
284
321
}
285
322
286
- // create OCM NodePool
287
- ocmClient , err := newOCMClient ()
323
+ newCluster , err := rosaClient .CreateCluster (clusterSpec )
288
324
if err != nil {
289
- return ctrl.Result {}, err
290
- }
291
- defer func () {
292
- ocmClient .ocm .Close ()
293
- }()
294
-
295
- cluster , err := ocmClient .GetCluster (rosaScope )
296
- if err != nil {
297
- return ctrl.Result {}, err
298
- }
299
-
300
- log := logger .FromContext (ctx )
301
- if cluster .ID () != "" {
302
- clusterID := cluster .ID ()
303
- rosaScope .ControlPlane .Status .ID = & clusterID
304
- conditions .MarkFalse (rosaScope .ControlPlane ,
305
- rosacontrolplanev1 .ROSAControlPlaneReadyCondition ,
306
- string (cluster .Status ().State ()),
307
- clusterv1 .ConditionSeverityInfo ,
308
- "" )
309
-
310
- if cluster .Status ().State () == "ready" {
311
- conditions .MarkTrue (rosaScope .ControlPlane , rosacontrolplanev1 .ROSAControlPlaneReadyCondition )
312
- rosaScope .ControlPlane .Status .Ready = true
313
- }
314
-
315
- if err := rosaScope .PatchObject (); err != nil {
316
- return ctrl.Result {}, err
317
- }
318
-
319
- log .Info ("cluster exists" , "state" , cluster .Status ().State ())
320
- return ctrl.Result {}, nil
321
- }
322
-
323
- newCluster , err := ocmClient .CreateCluster (clusterSpec )
324
- if err != nil {
325
- log .Info ("error" , "error" , err )
325
+ rosaScope .Info ("error" , "error" , err )
326
326
return ctrl.Result {RequeueAfter : 10 * time .Second }, nil
327
327
}
328
328
329
- log .Info ("cluster created" , "state" , newCluster .Status ().State ())
329
+ rosaScope .Info ("cluster created" , "state" , newCluster .Status ().State ())
330
330
clusterID := newCluster .ID ()
331
331
rosaScope .ControlPlane .Status .ID = & clusterID
332
- if err := rosaScope .PatchObject (); err != nil {
333
- return ctrl.Result {}, err
334
- }
335
332
336
333
return ctrl.Result {}, nil
337
334
}
338
335
339
336
func (r * ROSAControlPlaneReconciler ) reconcileDelete (_ context.Context , rosaScope * scope.ROSAControlPlaneScope ) (res ctrl.Result , reterr error ) {
340
337
rosaScope .Info ("Reconciling ROSAControlPlane delete" )
341
338
342
- // create OCM NodePool
343
- ocmClient , err := newOCMClient ()
339
+ // Create the connection, and remember to close it:
340
+ // TODO: token should be read from a secret: https://github.com/kubernetes-sigs/cluster-api-provider-aws/issues/4460
341
+ token := os .Getenv ("OCM_TOKEN" )
342
+ rosaClient , err := rosa .NewRosaClient (token )
344
343
if err != nil {
345
- return ctrl.Result {}, err
344
+ return ctrl.Result {}, fmt . Errorf ( "failed to create a rosa client: %w" , err )
346
345
}
346
+
347
347
defer func () {
348
- ocmClient . ocm .Close ()
348
+ rosaClient .Close ()
349
349
}()
350
350
351
- cluster , err := ocmClient .GetCluster (rosaScope )
351
+ cluster , err := rosaClient .GetCluster (rosaScope . RosaClusterName (), rosaScope . ControlPlane . Spec . CreatorARN )
352
352
if err != nil {
353
353
return ctrl.Result {}, err
354
354
}
355
355
356
356
if cluster != nil {
357
- if _ , err := ocmClient .DeleteCluster (cluster .ID ()); err != nil {
357
+ if err := rosaClient .DeleteCluster (cluster .ID ()); err != nil {
358
358
return ctrl.Result {}, err
359
359
}
360
360
}
361
361
362
362
controllerutil .RemoveFinalizer (rosaScope .ControlPlane , ROSAControlPlaneFinalizer )
363
- if err := rosaScope .PatchObject (); err != nil {
364
- return ctrl.Result {}, err
365
- }
366
363
367
364
return ctrl.Result {}, nil
368
365
}
@@ -406,119 +403,3 @@ func (r *ROSAControlPlaneReconciler) rosaClusterToROSAControlPlane(log *logger.L
406
403
}
407
404
}
408
405
}
409
-
410
- // OCMClient is a temporary helper to talk to OCM API.
411
- // TODO(alberto): vendor this from https://github.com/openshift/rosa/tree/master/pkg/ocm or build its own package here.
412
- type OCMClient struct {
413
- ocm * sdk.Connection
414
- }
415
-
416
- func newOCMClient () (* OCMClient , error ) {
417
- // Create the connection, and remember to close it:
418
- token := os .Getenv ("OCM_TOKEN" )
419
- ocmAPIUrl := os .Getenv ("OCM_API_URL" )
420
- if ocmAPIUrl == "" {
421
- ocmAPIUrl = "https://api.openshift.com"
422
- }
423
-
424
- // Create a logger that has the debug level enabled:
425
- ocmLogger , err := sdk .NewGoLoggerBuilder ().
426
- Debug (false ).
427
- Build ()
428
- if err != nil {
429
- return nil , fmt .Errorf ("failed to build logger: %w" , err )
430
- }
431
-
432
- connection , err := sdk .NewConnectionBuilder ().
433
- Logger (ocmLogger ).
434
- Tokens (token ).
435
- URL (ocmAPIUrl ).
436
- Build ()
437
- if err != nil {
438
- return nil , fmt .Errorf ("failed to ocm client: %w" , err )
439
- }
440
- ocmClient := OCMClient {ocm : connection }
441
-
442
- return & ocmClient , nil
443
- }
444
-
445
- func (client * OCMClient ) Close () error {
446
- return client .ocm .Close ()
447
- }
448
-
449
- func (client * OCMClient ) CreateCluster (clusterSpec * cmv1.Cluster ) (* cmv1.Cluster , error ) {
450
- cluster , err := client .ocm .ClustersMgmt ().V1 ().Clusters ().
451
- Add ().
452
- Body (clusterSpec ).
453
- Send ()
454
- if err != nil {
455
- return nil , handleErr (cluster .Error (), err )
456
- }
457
-
458
- clusterObject := cluster .Body ()
459
-
460
- return clusterObject , nil
461
- }
462
-
463
- func (client * OCMClient ) GetCluster (rosaScope * scope.ROSAControlPlaneScope ) (* cmv1.Cluster , error ) {
464
- clusterKey := rosaScope .ControlPlane .Name [:15 ]
465
- query := fmt .Sprintf ("%s AND (id = '%s' OR name = '%s' OR external_id = '%s')" ,
466
- getClusterFilter (rosaScope ),
467
- clusterKey , clusterKey , clusterKey ,
468
- )
469
- response , err := client .ocm .ClustersMgmt ().V1 ().Clusters ().List ().
470
- Search (query ).
471
- Page (1 ).
472
- Size (1 ).
473
- Send ()
474
- if err != nil {
475
- return nil , err
476
- }
477
-
478
- switch response .Total () {
479
- case 0 :
480
- return nil , nil
481
- case 1 :
482
- return response .Items ().Slice ()[0 ], nil
483
- default :
484
- return nil , fmt .Errorf ("there are %d clusters with identifier or name '%s'" , response .Total (), clusterKey )
485
- }
486
- }
487
-
488
- func (client * OCMClient ) DeleteCluster (clusterID string ) (* cmv1.Cluster , error ) {
489
- response , err := client .ocm .ClustersMgmt ().V1 ().Clusters ().
490
- Cluster (clusterID ).
491
- Delete ().
492
- Send ()
493
- if err != nil {
494
- return nil , handleErr (response .Error (), err )
495
- }
496
-
497
- return nil , nil
498
- }
499
-
500
- // Generate a query that filters clusters running on the current AWS session account.
501
- func getClusterFilter (rosaScope * scope.ROSAControlPlaneScope ) string {
502
- filter := "product.id = 'rosa'"
503
- if rosaScope .ControlPlane .Spec .CreatorARN != nil {
504
- filter = fmt .Sprintf ("%s AND (properties.%s = '%s')" ,
505
- filter ,
506
- rosaCreatorArnProperty ,
507
- * rosaScope .ControlPlane .Spec .CreatorARN )
508
- }
509
- return filter
510
- }
511
-
512
- func handleErr (res * ocmerrors.Error , err error ) error {
513
- msg := res .Reason ()
514
- if msg == "" {
515
- msg = err .Error ()
516
- }
517
- // Hack to always display the correct terms and conditions message
518
- if res .Code () == "CLUSTERS-MGMT-451" {
519
- msg = "You must accept the Terms and Conditions in order to continue.\n " +
520
- "Go to https://www.redhat.com/wapps/tnc/ackrequired?site=ocm&event=register\n " +
521
- "Once you accept the terms, you will need to retry the action that was blocked."
522
- }
523
- return fmt .Errorf (msg )
524
- }
0 commit comments