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

Commit

Permalink
initialize config objects if missing
Browse files Browse the repository at this point in the history
  • Loading branch information
fabriziopandini committed Sep 17, 2019
1 parent 46acfbd commit 6d6589b
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 137 deletions.
16 changes: 12 additions & 4 deletions controllers/kubeadmconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}

// if the machine has not ClusterConfiguration and InitConfiguration, requeue
if config.Spec.InitConfiguration == nil && config.Spec.ClusterConfiguration == nil {
// if the machine is configured has a secondary control-plane, requeue
if config.Spec.JoinConfiguration != nil {
log.Info("Control plane is not ready, requeing joining control planes until ready.")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
}
Expand Down Expand Up @@ -260,13 +260,21 @@ func (r *KubeadmConfigReconciler) Reconcile(req ctrl.Request) (_ ctrl.Result, re
}

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

//In case of join, ClusterConfiguration and InitConfiguration should not be defined by users
if config.Spec.ClusterConfiguration != nil || config.Spec.InitConfiguration != nil {
return ctrl.Result{}, errors.New("Control plane already exists for the cluster, KubeadmConfig objects with ClusterConfiguration or InitConfiguration can not be processed at this stage")
}

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

// if the JoinConfiguration is missing, create a default one
if config.Spec.JoinConfiguration == nil {
return ctrl.Result{}, errors.New("Control plane already exists for the cluster, only KubeadmConfig objects with JoinConfiguration are allowed")
config.Spec.JoinConfiguration = &kubeadmv1beta1.JoinConfiguration{}
if util.IsControlPlaneMachine(machine) {
config.Spec.JoinConfiguration.ControlPlane = &kubeadmv1beta1.JoinControlPlane{}
}
}

// Get certificates to improve security of discovery
Expand Down
287 changes: 154 additions & 133 deletions controllers/kubeadmconfig_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,75 +285,93 @@ func TestKubeadmConfigReconciler_Reconcile_GenerateCloudConfigData(t *testing.T)
cluster.Status.InfrastructureReady = true

controlPlaneMachine := newControlPlaneMachine(cluster)
controlPlaneInitConfig := newControlPlaneInitKubeadmConfig(controlPlaneMachine, "control-plane-init-cfg")

objects := []runtime.Object{
cluster,
controlPlaneMachine,
controlPlaneInitConfig,
var useCases = []struct {
name string
controlPlaneInitConfig *bootstrapv1.KubeadmConfig
}{
{
name: "machine with a fully compiled kubeadm config object",
controlPlaneInitConfig: newControlPlaneInitKubeadmConfig(controlPlaneMachine, "control-plane-init-cfg"),
},
{
name: "machine with an empty kubeadm config object",
controlPlaneInitConfig: newKubeadmConfig(controlPlaneMachine, "control-plane-init-cfg"),
},
}
objects = append(objects, createSecrets(t, cluster)...)

myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
for _, rt := range useCases {
rt := rt // pin!
t.Run(rt.name, func(t *testing.T) {

k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
KubeadmInitLock: &myInitLocker{},
}
objects := []runtime.Object{
cluster,
controlPlaneMachine,
rt.controlPlaneInitConfig,
}
objects = append(objects, createSecrets(t, cluster)...)

request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "control-plane-init-cfg",
},
}
result, err := k.Reconcile(request)
if err != nil {
t.Fatalf("Failed to reconcile:\n %+v", err)
}
if result.Requeue != false {
t.Fatal("did not expected to requeue")
}
if result.RequeueAfter != time.Duration(0) {
t.Fatal("did not expected to requeue after")
}
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)

cfg, err := getKubeadmConfig(myclient, "control-plane-init-cfg")
if err != nil {
t.Fatalf("Failed to reconcile:\n %+v", err)
}
if cfg.Status.Ready != true {
t.Fatal("Expected status ready")
}
if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}
k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
KubeadmInitLock: &myInitLocker{},
}

c, err := k.getClusterCertificates(cluster)
if err != nil {
t.Fatalf("Failed to locate certs secret:\n %+v", err)
}
if err := c.Validate(); err != nil {
t.Fatalf("Failed to validate certs: %+v", err)
request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "control-plane-init-cfg",
},
}
result, err := k.Reconcile(request)
if err != nil {
t.Fatalf("Failed to reconcile:\n %+v", err)
}
if result.Requeue != false {
t.Fatal("did not expected to requeue")
}
if result.RequeueAfter != time.Duration(0) {
t.Fatal("did not expected to requeue after")
}

cfg, err := getKubeadmConfig(myclient, "control-plane-init-cfg")
if err != nil {
t.Fatalf("Failed to reconcile:\n %+v", err)
}
if cfg.Status.Ready != true {
t.Fatal("Expected status ready")
}
if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}

c, err := k.getClusterCertificates(cluster)
if err != nil {
t.Fatalf("Failed to locate certs secret:\n %+v", err)
}
if err := c.Validate(); err != nil {
t.Fatalf("Failed to validate certs: %+v", err)
}
})
}
}

// Return an error if a worker has no JoinConfiguration defined
// TODO: This logic should not error in this case. A JoinConfiguration should be autogenerated
func TestKubeadmConfigReconciler_Reconcile_ErrorIfAWorkerHasNoJoinConfigurationAndTheControlPlaneIsInitialized(t *testing.T) {
// Tests for cluster with infrastructure ready, control pane ready

func TestFailIfClusterOrInitConfigurationAndControlPlaneIsReady(t *testing.T) {
cluster := newCluster("cluster")
cluster.Status.InfrastructureReady = true
cluster.Status.ControlPlaneInitialized = true

workerMachine := newWorkerMachine(cluster)
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine)
workerJoinConfig.Spec.JoinConfiguration = nil // Makes workerJoinConfig invalid
controlPaneMachine := newControlPlaneMachine(cluster)
controlPaneJoinConfig := newControlPlaneInitKubeadmConfig(controlPaneMachine, "control-plane-init-cfg")

objects := []runtime.Object{
cluster,
workerMachine,
workerJoinConfig,
controlPaneMachine,
controlPaneJoinConfig,
}
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)

Expand All @@ -366,7 +384,7 @@ func TestKubeadmConfigReconciler_Reconcile_ErrorIfAWorkerHasNoJoinConfigurationA
request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "worker-join-cfg",
Name: "control-plane-init-cfg",
},
}
_, err := k.Reconcile(request)
Expand Down Expand Up @@ -458,96 +476,99 @@ func TestReconcileIfJoinNodesAndControlPlaneIsReady(t *testing.T) {
cluster.Status.ControlPlaneInitialized = true
cluster.Status.APIEndpoints = []clusterv1.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}

workerMachine := newWorkerMachine(cluster)
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine)

controlPlaneMachine := newControlPlaneMachine(cluster)
controlPlaneJoinConfig := newControlPlaneJoinKubeadmConfig(controlPlaneMachine, "control-plane-join-cfg")

objects := []runtime.Object{
cluster,
workerMachine,
workerJoinConfig,
controlPlaneMachine,
controlPlaneJoinConfig,
}
objects = append(objects, createSecrets(t, cluster)...)
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
SecretsClientFactory: newFakeSecretFactory(),
KubeadmInitLock: &myInitLocker{},
}

request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "worker-join-cfg",
var useCases = []struct {
name string
machine *clusterv1.Machine
configName string
configBuilder func(*clusterv1.Machine, string) *bootstrapv1.KubeadmConfig
}{
{
name: "Join a worker node with a fully compiled kubeadm config object",
machine: newWorkerMachine(cluster),
configName: "worker-join-cfg",
configBuilder: func(machine *clusterv1.Machine, name string) *bootstrapv1.KubeadmConfig {
return newWorkerJoinKubeadmConfig(machine)
},
},
{
name: "Join a worker node with an empty kubeadm config object",
machine: newWorkerMachine(cluster),
configName: "worker-join-cfg",
configBuilder: newKubeadmConfig,
},
{
name: "Join a control plane node with a fully compiled kubeadm config object",
machine: newControlPlaneMachine(cluster),
configName: "control-plane-join-cfg",
configBuilder: newControlPlaneJoinKubeadmConfig,
},
{
name: "Join a control plane node with an empty kubeadm config object",
machine: newControlPlaneMachine(cluster),
configName: "control-plane-join-cfg",
configBuilder: newKubeadmConfig,
},
}
result, err := k.Reconcile(request)
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
if result.Requeue == true {
t.Fatal("did not expected to requeue")
}
if result.RequeueAfter != time.Duration(0) {
t.Fatal("did not expected to requeue after")
}

cfg, err := getKubeadmConfig(myclient, "worker-join-cfg")
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}

if cfg.Status.Ready != true {
t.Fatal("Expected status ready")
}
for _, rt := range useCases {
rt := rt // pin!
t.Run(rt.name, func(t *testing.T) {
config := rt.configBuilder(rt.machine, rt.configName)

if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}
objects := []runtime.Object{
cluster,
rt.machine,
config,
}
objects = append(objects, createSecrets(t, cluster)...)
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)
k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
SecretsClientFactory: newFakeSecretFactory(),
KubeadmInitLock: &myInitLocker{},
}

request = ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "control-plane-join-cfg",
},
}
result, err = k.Reconcile(request)
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
if result.Requeue == true {
t.Fatal("did not expected to requeue")
}
if result.RequeueAfter != time.Duration(0) {
t.Fatal("did not expected to requeue after")
}
request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: config.GetNamespace(),
Name: rt.configName,
},
}
result, err := k.Reconcile(request)
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
if result.Requeue == true {
t.Fatal("did not expected to requeue")
}
if result.RequeueAfter != time.Duration(0) {
t.Fatal("did not expected to requeue after")
}

cfg, err = getKubeadmConfig(myclient, "control-plane-join-cfg")
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
cfg, err := getKubeadmConfig(myclient, rt.configName)
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}

if cfg.Status.Ready != true {
t.Fatal("Expected status ready")
}
if cfg.Status.Ready != true {
t.Fatal("Expected status ready")
}

if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}
if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}

myremoteclient, _ := k.SecretsClientFactory.NewSecretsClient(nil, nil)
l, err := myremoteclient.List(metav1.ListOptions{})
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
myremoteclient, _ := k.SecretsClientFactory.NewSecretsClient(nil, nil)
l, err := myremoteclient.List(metav1.ListOptions{})
if err != nil {
t.Fatal(fmt.Sprintf("Failed to get secrets after reconcyle:\n %+v", err))
}

if len(l.Items) != 2 {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
if len(l.Items) != 1 {
t.Fatal(fmt.Sprintf("Failed to bootstrap token secrets:\n %+v", err))
}
})
}
}

Expand Down

0 comments on commit 6d6589b

Please sign in to comment.