Skip to content
This repository was archived by the owner on Jul 30, 2021. It is now read-only.

Commit 4de256f

Browse files
initialize join configuration if missing
1 parent 92d49ae commit 4de256f

File tree

2 files changed

+96
-119
lines changed

2 files changed

+96
-119
lines changed

controllers/kubeadmconfig_controller.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
190190

191191
log.Info("Creating BootstrapData for the init control plane")
192192

193+
// Nb. in this case JoinConfiguration should not be defined by users, but in case of misconfigurations, CABPK simply ignore it
194+
193195
// get both of ClusterConfiguration and InitConfiguration strings to pass to the cloud init control plane generator
194196
// kubeadm allows one of these values to be empty; CABPK replace missing values with an empty config, so the cloud init generation
195197
// should not handle special cases.
@@ -256,13 +258,18 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
256258
}
257259

258260
// Every other case it's a join scenario
259-
// Nb. in this case ClusterConfiguration and JoinConfiguration should not be defined by users, but in case of misconfigurations, CABPK simply ignore them
261+
// Nb. in this case ClusterConfiguration and InitConfiguration should not be defined by users, but in case of misconfigurations, CABPK simply ignore them
260262

261263
// Unlock any locks that might have been set during init process
262264
r.KubeadmInitLock.Unlock(ctx, cluster)
263265

266+
// if the JoinConfiguration is missing, create a default one
264267
if config.Spec.JoinConfiguration == nil {
265-
return ctrl.Result{}, errors.New("Control plane already exists for the cluster, only KubeadmConfig objects with JoinConfiguration are allowed")
268+
log.Info("Creating default JoinConfiguration")
269+
config.Spec.JoinConfiguration = &kubeadmv1beta1.JoinConfiguration{}
270+
if util.IsControlPlaneMachine(machine) {
271+
config.Spec.JoinConfiguration.ControlPlane = &kubeadmv1beta1.JoinControlPlane{}
272+
}
266273
}
267274

268275
certificates := internalcluster.NewCertificates()
@@ -306,6 +313,8 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
306313
return ctrl.Result{}, errors.New("Machine is a ControlPlane, but JoinConfiguration.ControlPlane is not set in the KubeadmConfig object")
307314
}
308315

316+
log.Info("Creating BootstrapData for the join control plane")
317+
309318
cloudJoinData, err := cloudinit.NewJoinControlPlane(&cloudinit.ControlPlaneJoinInput{
310319
JoinConfiguration: joindata,
311320
Certificates: certificates,
@@ -332,6 +341,8 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
332341
return ctrl.Result{}, errors.New("Machine is a Worker, but JoinConfiguration.ControlPlane is set in the KubeadmConfig object")
333342
}
334343

344+
log.Info("Creating BootstrapData for the worker node")
345+
335346
cloudJoinData, err := cloudinit.NewNode(&cloudinit.NodeInput{
336347
BaseUserData: cloudinit.BaseUserData{
337348
AdditionalFiles: config.Spec.Files,

controllers/kubeadmconfig_controller_test.go

Lines changed: 83 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -371,42 +371,6 @@ func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T)
371371
}
372372
}
373373

374-
// Return an error if a worker has no JoinConfiguration defined
375-
// TODO: This logic should not error in this case. A JoinConfiguration should be autogenerated
376-
func TestKubeadmConfigReconciler_Reconcile_ErrorIfAWorkerHasNoJoinConfigurationAndTheControlPlaneIsInitialized(t *testing.T) {
377-
cluster := newCluster("cluster")
378-
cluster.Status.InfrastructureReady = true
379-
cluster.Status.ControlPlaneInitialized = true
380-
381-
workerMachine := newWorkerMachine(cluster)
382-
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine)
383-
workerJoinConfig.Spec.JoinConfiguration = nil // Makes workerJoinConfig invalid
384-
385-
objects := []runtime.Object{
386-
cluster,
387-
workerMachine,
388-
workerJoinConfig,
389-
}
390-
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
391-
392-
k := &KubeadmConfigReconciler{
393-
Log: log.Log,
394-
Client: myclient,
395-
KubeadmInitLock: &myInitLocker{},
396-
}
397-
398-
request := ctrl.Request{
399-
NamespacedName: types.NamespacedName{
400-
Namespace: "default",
401-
Name: "worker-join-cfg",
402-
},
403-
}
404-
_, err := k.Reconcile(request)
405-
if err == nil {
406-
t.Fatal("Expected error, got nil")
407-
}
408-
}
409-
410374
// If a controlplane has an invalid JoinConfiguration then user intervention is required.
411375
func TestKubeadmConfigReconciler_Reconcile_ErrorIfJoiningControlPlaneHasInvalidConfiguration(t *testing.T) {
412376
// TODO: extract this kind of code into a setup function that puts the state of objects into an initialized controlplane (implies secrets exist)
@@ -497,99 +461,101 @@ func TestReconcileIfJoinNodesAndControlPlaneIsReady(t *testing.T) {
497461
cluster.Status.InfrastructureReady = true
498462
cluster.Status.ControlPlaneInitialized = true
499463
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}
500-
controlPlaneInitMachine := newControlPlaneMachine(cluster, "control-plane-init-machine")
501-
initConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine, "control-plane-init-config")
502-
503-
workerMachine := newWorkerMachine(cluster)
504-
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine)
505464

506-
controlPlaneJoinMachine := newControlPlaneMachine(cluster, "control-plane-join-machine")
507-
controlPlaneJoinConfig := newControlPlaneJoinKubeadmConfig(controlPlaneJoinMachine, "control-plane-join-cfg")
508-
509-
objects := []runtime.Object{
510-
cluster,
511-
workerMachine,
512-
workerJoinConfig,
513-
controlPlaneJoinMachine,
514-
controlPlaneJoinConfig,
515-
}
516-
objects = append(objects, createSecrets(t, cluster, initConfig)...)
517-
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
518-
k := &KubeadmConfigReconciler{
519-
Log: log.Log,
520-
Client: myclient,
521-
SecretsClientFactory: newFakeSecretFactory(),
522-
KubeadmInitLock: &myInitLocker{},
523-
}
524-
525-
request := ctrl.Request{
526-
NamespacedName: types.NamespacedName{
527-
Namespace: "default",
528-
Name: "worker-join-cfg",
465+
var useCases = []struct {
466+
name string
467+
machine *clusterv1.Machine
468+
configName string
469+
configBuilder func(*clusterv1.Machine, string) *bootstrapv1.KubeadmConfig
470+
}{
471+
{
472+
name: "Join a worker node with a fully compiled kubeadm config object",
473+
machine: newWorkerMachine(cluster),
474+
configName: "worker-join-cfg",
475+
configBuilder: func(machine *clusterv1.Machine, name string) *bootstrapv1.KubeadmConfig {
476+
return newWorkerJoinKubeadmConfig(machine)
477+
},
478+
},
479+
{
480+
name: "Join a worker node with an empty kubeadm config object (defaults apply)",
481+
machine: newWorkerMachine(cluster),
482+
configName: "worker-join-cfg",
483+
configBuilder: newKubeadmConfig,
484+
},
485+
{
486+
name: "Join a control plane node with a fully compiled kubeadm config object",
487+
machine: newControlPlaneMachine(cluster, "control-plane-join-machine"),
488+
configName: "control-plane-join-cfg",
489+
configBuilder: newControlPlaneJoinKubeadmConfig,
490+
},
491+
{
492+
name: "Join a control plane node with an empty kubeadm config object (defaults apply)",
493+
machine: newControlPlaneMachine(cluster, "control-plane-join-machine"),
494+
configName: "control-plane-join-cfg",
495+
configBuilder: newKubeadmConfig,
529496
},
530-
}
531-
result, err := k.Reconcile(request)
532-
if err != nil {
533-
t.Fatalf("Failed to reconcile:\n %+v", err)
534-
}
535-
if result.Requeue == true {
536-
t.Fatal("did not expect to requeue")
537-
}
538-
if result.RequeueAfter != time.Duration(0) {
539-
t.Fatal("did not expect to requeue after")
540497
}
541498

542-
cfg, err := getKubeadmConfig(myclient, "worker-join-cfg")
543-
if err != nil {
544-
t.Fatalf("Failed to reconcile:\n %+v", err)
545-
}
499+
for _, rt := range useCases {
500+
rt := rt // pin!
501+
t.Run(rt.name, func(t *testing.T) {
502+
config := rt.configBuilder(rt.machine, rt.configName)
546503

547-
if cfg.Status.Ready != true {
548-
t.Fatal("Expected status ready")
549-
}
504+
objects := []runtime.Object{
505+
cluster,
506+
rt.machine,
507+
config,
508+
}
509+
objects = append(objects, createSecrets(t, cluster, config)...)
510+
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
511+
k := &KubeadmConfigReconciler{
512+
Log: log.Log,
513+
Client: myclient,
514+
SecretsClientFactory: newFakeSecretFactory(),
515+
KubeadmInitLock: &myInitLocker{},
516+
}
550517

551-
if cfg.Status.BootstrapData == nil {
552-
t.Fatal("Expected status ready")
553-
}
518+
request := ctrl.Request{
519+
NamespacedName: types.NamespacedName{
520+
Namespace: config.GetNamespace(),
521+
Name: rt.configName,
522+
},
523+
}
524+
result, err := k.Reconcile(request)
525+
if err != nil {
526+
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
527+
}
528+
if result.Requeue == true {
529+
t.Fatal("did not expected to requeue")
530+
}
531+
if result.RequeueAfter != time.Duration(0) {
532+
t.Fatal("did not expected to requeue after")
533+
}
554534

555-
request = ctrl.Request{
556-
NamespacedName: types.NamespacedName{
557-
Namespace: "default",
558-
Name: "control-plane-join-cfg",
559-
},
560-
}
561-
result, err = k.Reconcile(request)
562-
if err != nil {
563-
t.Fatalf("Failed to reconcile:\n %+v", err)
564-
}
565-
if result.Requeue == true {
566-
t.Fatal("did not expect to requeue")
567-
}
568-
if result.RequeueAfter != time.Duration(0) {
569-
t.Fatal("did not expect to requeue after")
570-
}
535+
cfg, err := getKubeadmConfig(myclient, rt.configName)
536+
if err != nil {
537+
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
538+
}
571539

572-
cfg, err = getKubeadmConfig(myclient, "control-plane-join-cfg")
573-
if err != nil {
574-
t.Fatalf("Failed to reconcile:\n %+v", err)
575-
}
540+
if cfg.Status.Ready != true {
541+
t.Fatal("Expected status ready")
542+
}
576543

577-
if cfg.Status.Ready != true {
578-
t.Fatal("Expected status ready")
579-
}
544+
if cfg.Status.BootstrapData == nil {
545+
t.Fatal("Expected status ready")
546+
}
580547

581-
if cfg.Status.BootstrapData == nil {
582-
t.Fatal("Expected status ready")
583-
}
548+
myremoteclient, _ := k.SecretsClientFactory.NewSecretsClient(nil, nil)
549+
l, err := myremoteclient.List(metav1.ListOptions{})
550+
if err != nil {
551+
t.Fatal(fmt.Sprintf("Failed to get secrets after reconcyle:\n %+v", err))
552+
}
584553

585-
myremoteclient, _ := k.SecretsClientFactory.NewSecretsClient(nil, nil)
586-
l, err := myremoteclient.List(metav1.ListOptions{})
587-
if err != nil {
588-
t.Fatalf("Failed to reconcile:\n %+v", err)
589-
}
554+
if len(l.Items) != 1 {
555+
t.Fatal("Failed to get bootstrap token secret")
556+
}
557+
})
590558

591-
if len(l.Items) != 2 {
592-
t.Fatalf("Failed to reconcile:\n %+v", err)
593559
}
594560
}
595561

0 commit comments

Comments
 (0)