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

Commit 54a04d8

Browse files
authored
Merge pull request #234 from fabriziopandini/initialize-configobjects-if-missing
✨ Initialize JoinConfiguration if missing
2 parents 57f7ce6 + 4de256f commit 54a04d8

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
@@ -189,6 +189,8 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
189189

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

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

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

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

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

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

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

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

controllers/kubeadmconfig_controller_test.go

Lines changed: 83 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -400,42 +400,6 @@ func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T)
400400
}
401401
}
402402

403-
// Return an error if a worker has no JoinConfiguration defined
404-
// TODO: This logic should not error in this case. A JoinConfiguration should be autogenerated
405-
func TestKubeadmConfigReconciler_Reconcile_ErrorIfAWorkerHasNoJoinConfigurationAndTheControlPlaneIsInitialized(t *testing.T) {
406-
cluster := newCluster("cluster")
407-
cluster.Status.InfrastructureReady = true
408-
cluster.Status.ControlPlaneInitialized = true
409-
410-
workerMachine := newWorkerMachine(cluster)
411-
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine)
412-
workerJoinConfig.Spec.JoinConfiguration = nil // Makes workerJoinConfig invalid
413-
414-
objects := []runtime.Object{
415-
cluster,
416-
workerMachine,
417-
workerJoinConfig,
418-
}
419-
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
420-
421-
k := &KubeadmConfigReconciler{
422-
Log: log.Log,
423-
Client: myclient,
424-
KubeadmInitLock: &myInitLocker{},
425-
}
426-
427-
request := ctrl.Request{
428-
NamespacedName: types.NamespacedName{
429-
Namespace: "default",
430-
Name: "worker-join-cfg",
431-
},
432-
}
433-
_, err := k.Reconcile(request)
434-
if err == nil {
435-
t.Fatal("Expected error, got nil")
436-
}
437-
}
438-
439403
// If a controlplane has an invalid JoinConfiguration then user intervention is required.
440404
func TestKubeadmConfigReconciler_Reconcile_ErrorIfJoiningControlPlaneHasInvalidConfiguration(t *testing.T) {
441405
// TODO: extract this kind of code into a setup function that puts the state of objects into an initialized controlplane (implies secrets exist)
@@ -526,99 +490,101 @@ func TestReconcileIfJoinNodesAndControlPlaneIsReady(t *testing.T) {
526490
cluster.Status.InfrastructureReady = true
527491
cluster.Status.ControlPlaneInitialized = true
528492
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}
529-
controlPlaneInitMachine := newControlPlaneMachine(cluster, "control-plane-init-machine")
530-
initConfig := newControlPlaneInitKubeadmConfig(controlPlaneInitMachine, "control-plane-init-config")
531-
532-
workerMachine := newWorkerMachine(cluster)
533-
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine)
534493

535-
controlPlaneJoinMachine := newControlPlaneMachine(cluster, "control-plane-join-machine")
536-
controlPlaneJoinConfig := newControlPlaneJoinKubeadmConfig(controlPlaneJoinMachine, "control-plane-join-cfg")
537-
538-
objects := []runtime.Object{
539-
cluster,
540-
workerMachine,
541-
workerJoinConfig,
542-
controlPlaneJoinMachine,
543-
controlPlaneJoinConfig,
544-
}
545-
objects = append(objects, createSecrets(t, cluster, initConfig)...)
546-
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
547-
k := &KubeadmConfigReconciler{
548-
Log: log.Log,
549-
Client: myclient,
550-
SecretsClientFactory: newFakeSecretFactory(),
551-
KubeadmInitLock: &myInitLocker{},
552-
}
553-
554-
request := ctrl.Request{
555-
NamespacedName: types.NamespacedName{
556-
Namespace: "default",
557-
Name: "worker-join-cfg",
494+
var useCases = []struct {
495+
name string
496+
machine *clusterv1.Machine
497+
configName string
498+
configBuilder func(*clusterv1.Machine, string) *bootstrapv1.KubeadmConfig
499+
}{
500+
{
501+
name: "Join a worker node with a fully compiled kubeadm config object",
502+
machine: newWorkerMachine(cluster),
503+
configName: "worker-join-cfg",
504+
configBuilder: func(machine *clusterv1.Machine, name string) *bootstrapv1.KubeadmConfig {
505+
return newWorkerJoinKubeadmConfig(machine)
506+
},
507+
},
508+
{
509+
name: "Join a worker node with an empty kubeadm config object (defaults apply)",
510+
machine: newWorkerMachine(cluster),
511+
configName: "worker-join-cfg",
512+
configBuilder: newKubeadmConfig,
513+
},
514+
{
515+
name: "Join a control plane node with a fully compiled kubeadm config object",
516+
machine: newControlPlaneMachine(cluster, "control-plane-join-machine"),
517+
configName: "control-plane-join-cfg",
518+
configBuilder: newControlPlaneJoinKubeadmConfig,
519+
},
520+
{
521+
name: "Join a control plane node with an empty kubeadm config object (defaults apply)",
522+
machine: newControlPlaneMachine(cluster, "control-plane-join-machine"),
523+
configName: "control-plane-join-cfg",
524+
configBuilder: newKubeadmConfig,
558525
},
559-
}
560-
result, err := k.Reconcile(request)
561-
if err != nil {
562-
t.Fatalf("Failed to reconcile:\n %+v", err)
563-
}
564-
if result.Requeue == true {
565-
t.Fatal("did not expect to requeue")
566-
}
567-
if result.RequeueAfter != time.Duration(0) {
568-
t.Fatal("did not expect to requeue after")
569526
}
570527

571-
cfg, err := getKubeadmConfig(myclient, "worker-join-cfg")
572-
if err != nil {
573-
t.Fatalf("Failed to reconcile:\n %+v", err)
574-
}
528+
for _, rt := range useCases {
529+
rt := rt // pin!
530+
t.Run(rt.name, func(t *testing.T) {
531+
config := rt.configBuilder(rt.machine, rt.configName)
575532

576-
if cfg.Status.Ready != true {
577-
t.Fatal("Expected status ready")
578-
}
533+
objects := []runtime.Object{
534+
cluster,
535+
rt.machine,
536+
config,
537+
}
538+
objects = append(objects, createSecrets(t, cluster, config)...)
539+
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
540+
k := &KubeadmConfigReconciler{
541+
Log: log.Log,
542+
Client: myclient,
543+
SecretsClientFactory: newFakeSecretFactory(),
544+
KubeadmInitLock: &myInitLocker{},
545+
}
579546

580-
if cfg.Status.BootstrapData == nil {
581-
t.Fatal("Expected status ready")
582-
}
547+
request := ctrl.Request{
548+
NamespacedName: types.NamespacedName{
549+
Namespace: config.GetNamespace(),
550+
Name: rt.configName,
551+
},
552+
}
553+
result, err := k.Reconcile(request)
554+
if err != nil {
555+
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
556+
}
557+
if result.Requeue == true {
558+
t.Fatal("did not expected to requeue")
559+
}
560+
if result.RequeueAfter != time.Duration(0) {
561+
t.Fatal("did not expected to requeue after")
562+
}
583563

584-
request = ctrl.Request{
585-
NamespacedName: types.NamespacedName{
586-
Namespace: "default",
587-
Name: "control-plane-join-cfg",
588-
},
589-
}
590-
result, err = k.Reconcile(request)
591-
if err != nil {
592-
t.Fatalf("Failed to reconcile:\n %+v", err)
593-
}
594-
if result.Requeue == true {
595-
t.Fatal("did not expect to requeue")
596-
}
597-
if result.RequeueAfter != time.Duration(0) {
598-
t.Fatal("did not expect to requeue after")
599-
}
564+
cfg, err := getKubeadmConfig(myclient, rt.configName)
565+
if err != nil {
566+
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
567+
}
600568

601-
cfg, err = getKubeadmConfig(myclient, "control-plane-join-cfg")
602-
if err != nil {
603-
t.Fatalf("Failed to reconcile:\n %+v", err)
604-
}
569+
if cfg.Status.Ready != true {
570+
t.Fatal("Expected status ready")
571+
}
605572

606-
if cfg.Status.Ready != true {
607-
t.Fatal("Expected status ready")
608-
}
573+
if cfg.Status.BootstrapData == nil {
574+
t.Fatal("Expected status ready")
575+
}
609576

610-
if cfg.Status.BootstrapData == nil {
611-
t.Fatal("Expected status ready")
612-
}
577+
myremoteclient, _ := k.SecretsClientFactory.NewSecretsClient(nil, nil)
578+
l, err := myremoteclient.List(metav1.ListOptions{})
579+
if err != nil {
580+
t.Fatal(fmt.Sprintf("Failed to get secrets after reconcyle:\n %+v", err))
581+
}
613582

614-
myremoteclient, _ := k.SecretsClientFactory.NewSecretsClient(nil, nil)
615-
l, err := myremoteclient.List(metav1.ListOptions{})
616-
if err != nil {
617-
t.Fatalf("Failed to reconcile:\n %+v", err)
618-
}
583+
if len(l.Items) != 1 {
584+
t.Fatal("Failed to get bootstrap token secret")
585+
}
586+
})
619587

620-
if len(l.Items) != 2 {
621-
t.Fatalf("Failed to reconcile:\n %+v", err)
622588
}
623589
}
624590

0 commit comments

Comments
 (0)