@@ -148,7 +148,7 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
148
148
149
149
// Look up the owner of this KubeConfig if there is one
150
150
configOwner , err := bsutil .GetConfigOwner (ctx , r .Client , config )
151
- if apierrors .IsNotFound (err ) {
151
+ if apierrors .IsNotFound (errors . Cause ( err ) ) {
152
152
// Could not find the owner yet, this is not an error and will rereconcile when the owner gets set.
153
153
return ctrl.Result {}, nil
154
154
}
@@ -169,7 +169,7 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
169
169
return ctrl.Result {}, nil
170
170
}
171
171
172
- if apierrors .IsNotFound (err ) {
172
+ if apierrors .IsNotFound (errors . Cause ( err ) ) {
173
173
log .Info ("Cluster does not exist yet, waiting until it is created" )
174
174
return ctrl.Result {}, nil
175
175
}
@@ -225,10 +225,7 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
225
225
return ctrl.Result {}, nil
226
226
// Migrate plaintext data to secret.
227
227
case config .Status .BootstrapData != nil && config .Status .DataSecretName == nil :
228
- if err := r .storeBootstrapData (ctx , scope , config .Status .BootstrapData ); err != nil {
229
- return ctrl.Result {}, err
230
- }
231
- return ctrl.Result {}, nil
228
+ return ctrl.Result {}, r .storeBootstrapData (ctx , scope , config .Status .BootstrapData )
232
229
// Reconcile status for machines that already have a secret reference, but our status isn't up to date.
233
230
// This case solves the pivoting scenario (or a backup restore) which doesn't preserve the status subresource on objects.
234
231
case configOwner .DataSecretName () != nil && (! config .Status .Ready || config .Status .DataSecretName == nil ):
@@ -240,26 +237,14 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
240
237
case config .Status .Ready :
241
238
// If the BootstrapToken has been generated for a join and the infrastructure is not ready.
242
239
// This indicates the token in the join config has not been consumed and it may need a refresh.
243
- if (config .Spec .JoinConfiguration != nil && config .Spec .JoinConfiguration .Discovery .BootstrapToken != nil ) && ! configOwner .IsInfrastructureReady () {
244
-
245
- token := config .Spec .JoinConfiguration .Discovery .BootstrapToken .Token
246
-
247
- remoteClient , err := r .remoteClientGetter (ctx , r .Client , util .ObjectKey (cluster ), r .scheme )
248
- if err != nil {
249
- log .Error (err , "Error creating remote cluster client" )
250
- return ctrl.Result {}, err
251
- }
252
-
253
- log .Info ("Refreshing token until the infrastructure has a chance to consume it" )
254
- err = refreshToken (remoteClient , token )
255
- if err != nil {
256
- // It would be nice to re-create the bootstrap token if the error was "not found", but we have no way to update the Machine's bootstrap data
257
- return ctrl.Result {}, errors .Wrapf (err , "failed to refresh bootstrap token" )
240
+ if config .Spec .JoinConfiguration != nil && config .Spec .JoinConfiguration .Discovery .BootstrapToken != nil {
241
+ if ! configOwner .IsInfrastructureReady () {
242
+ return r .refreshBootstrapToken (ctx , log , cluster , config )
243
+ } else if (config .Spec .JoinConfiguration != nil && config .Spec .JoinConfiguration .Discovery .BootstrapToken != nil ) && configOwner .IsMachinePool () {
244
+ // If the BootstrapToken has been generated and infrastructure is ready but the configOwner is a MachinePool,
245
+ // we rotate the token to keep it fresh for future scale ups.
246
+ return r .rotateMachinePoolBootstrapToken (ctx , log , cluster , config , scope )
258
247
}
259
- // NB: this may not be sufficient to keep the token live if we don't see it before it expires, but when we generate a config we will set the status to "ready" which should generate an update event
260
- return ctrl.Result {
261
- RequeueAfter : DefaultTokenTTL / 2 ,
262
- }, nil
263
248
}
264
249
// In any other case just return as the config is already generated and need not be generated again.
265
250
return ctrl.Result {}, nil
@@ -290,6 +275,54 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
290
275
return r .joinWorker (ctx , scope )
291
276
}
292
277
278
+ func (r * KubeadmConfigReconciler ) refreshBootstrapToken (ctx context.Context , log logr.Logger , cluster * clusterv1.Cluster , config * bootstrapv1.KubeadmConfig ) (ctrl.Result , error ) {
279
+ token := config .Spec .JoinConfiguration .Discovery .BootstrapToken .Token
280
+
281
+ remoteClient , err := r .remoteClientGetter (ctx , r .Client , util .ObjectKey (cluster ), r .scheme )
282
+ if err != nil {
283
+ log .Error (err , "Error creating remote cluster client" )
284
+ return ctrl.Result {}, err
285
+ }
286
+
287
+ log .Info ("Refreshing token until the infrastructure has a chance to consume it" )
288
+ if err := refreshToken (remoteClient , token ); err != nil {
289
+ return ctrl.Result {}, errors .Wrapf (err , "failed to refresh bootstrap token" )
290
+ }
291
+ return ctrl.Result {
292
+ RequeueAfter : DefaultTokenTTL / 2 ,
293
+ }, nil
294
+ }
295
+
296
+ func (r * KubeadmConfigReconciler ) rotateMachinePoolBootstrapToken (ctx context.Context , log logr.Logger , cluster * clusterv1.Cluster , config * bootstrapv1.KubeadmConfig , scope * Scope ) (ctrl.Result , error ) {
297
+ log .V (2 ).Info ("Config is owned by a MachinePool, checking if token should be rotated" )
298
+ remoteClient , err := r .remoteClientGetter (ctx , r .Client , util .ObjectKey (cluster ), r .scheme )
299
+ if err != nil {
300
+ return ctrl.Result {}, err
301
+ }
302
+
303
+ token := config .Spec .JoinConfiguration .Discovery .BootstrapToken .Token
304
+ shouldRotate , err := shouldRotate (remoteClient , token )
305
+ if err != nil {
306
+ return ctrl.Result {}, err
307
+ }
308
+ if shouldRotate {
309
+ log .V (2 ).Info ("Creating new bootstrap token" )
310
+ token , err := createToken (remoteClient )
311
+ if err != nil {
312
+ return ctrl.Result {}, errors .Wrapf (err , "failed to create new bootstrap token" )
313
+ }
314
+
315
+ config .Spec .JoinConfiguration .Discovery .BootstrapToken .Token = token
316
+ log .Info ("Altering JoinConfiguration.Discovery.BootstrapToken" , "Token" , token )
317
+
318
+ // update the bootstrap data
319
+ return r .joinWorker (ctx , scope )
320
+ }
321
+ return ctrl.Result {
322
+ RequeueAfter : DefaultTokenTTL / 3 ,
323
+ }, nil
324
+ }
325
+
293
326
func (r * KubeadmConfigReconciler ) handleClusterNotInitialized (ctx context.Context , scope * Scope ) (_ ctrl.Result , reterr error ) {
294
327
// initialize the DataSecretAvailableCondition if missing.
295
328
// this is required in order to avoid the condition's LastTransitionTime to flicker in case of errors surfacing
@@ -839,7 +872,10 @@ func (r *KubeadmConfigReconciler) storeBootstrapData(ctx context.Context, scope
839
872
if ! apierrors .IsAlreadyExists (err ) {
840
873
return errors .Wrapf (err , "failed to create bootstrap data secret for KubeadmConfig %s/%s" , scope .Config .Namespace , scope .Config .Name )
841
874
}
842
- r .Log .Info ("bootstrap data secret for KubeadmConfig already exists" , "secret" , secret .Name , "KubeadmConfig" , scope .Config .Name )
875
+ r .Log .Info ("bootstrap data secret for KubeadmConfig already exists, updating" , "secret" , secret .Name , "KubeadmConfig" , scope .Config .Name )
876
+ if err := r .Client .Update (ctx , secret ); err != nil {
877
+ return errors .Wrapf (err , "failed to update bootstrap data secret for KubeadmConfig %s/%s" , scope .Config .Namespace , scope .Config .Name )
878
+ }
843
879
}
844
880
scope .Config .Status .DataSecretName = pointer .StringPtr (secret .Name )
845
881
scope .Config .Status .Ready = true
0 commit comments