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 e10c244 commit b41e9c2
Show file tree
Hide file tree
Showing 2 changed files with 167 additions and 142 deletions.
16 changes: 12 additions & 4 deletions controllers/kubeadmconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,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 @@ -250,13 +250,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")
}

// Release any locks that might have been set during init process
initLocker.Release(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{}
}
}

// ensure that joinConfiguration.Discovery is properly set for joining node on the current cluster
Expand Down
293 changes: 155 additions & 138 deletions controllers/kubeadmconfig_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,77 +335,93 @@ func TestReconcileKubeadmConfigForInitNodesIfControlPlaneIsNotReady(t *testing.T
cluster.Status.InfrastructureReady = true

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

objects := []runtime.Object{
cluster,
controlPlaneMachine,
controlPlaneInitConfig,
var useCases = []struct {
name string
controlPlaneInitConfig *cabpkV1alpha2.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"),
},
}
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)

k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
}
for _, rt := range useCases {
t.Run(rt.name, func(t *testing.T) {
objects := []runtime.Object{
cluster,
controlPlaneMachine,
rt.controlPlaneInitConfig,
}
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)

request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "control-plane-init-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")
}
k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
}

cfg, err := getKubeadmConfig(myclient, "control-plane-init-cfg")
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "control-plane-init-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")
}

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

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

certsSecret, err := getCertsSecret(myclient, cluster.GetName())
if err != nil {
t.Fatal(fmt.Sprintf("Failed to locate certs secret:\n %+v", err))
}
if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}

certsMap := certs.NewCertificatesFromMap(certsSecret.Data)
err = certsMap.Validate()
if err != nil {
t.Fatal(fmt.Sprintf("Certificates not valid:\n %+v", err))
certsSecret, err := getCertsSecret(myclient, cluster.GetName())
if err != nil {
t.Fatal(fmt.Sprintf("Failed to locate certs secret:\n %+v", err))
}

certsMap := certs.NewCertificatesFromMap(certsSecret.Data)
err = certsMap.Validate()
if err != nil {
t.Fatal(fmt.Sprintf("Certificates not valid:\n %+v", err))
}
})
}
}

// Tests for cluster with infrastructure ready, control pane ready

func TestFailIfNotJoinConfigurationAndControlPlaneIsReady(t *testing.T) {
func TestFailIfClusterOrInitConfigurationAndControlPlaneIsReady(t *testing.T) {
cluster := newCluster("cluster")
cluster.Status.InfrastructureReady = true
cluster.Annotations = map[string]string{ControlPlaneReadyAnnotationKey: "true"}

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

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

Expand All @@ -417,7 +433,7 @@ func TestFailIfNotJoinConfigurationAndControlPlaneIsReady(t *testing.T) {
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 @@ -505,106 +521,107 @@ func TestReconcileIfJoinNodesAndControlPlaneIsReady(t *testing.T) {
cluster.Annotations = map[string]string{ControlPlaneReadyAnnotationKey: "true"}
cluster.Status.APIEndpoints = []capiv1alpha2.APIEndpoint{{Host: "100.105.150.1", Port: 6443}}

workerMachine := newWorkerMachine(cluster, "worker-machine")
workerJoinConfig := newWorkerJoinKubeadmConfig(workerMachine, "worker-join-cfg")

controlPaneMachine := newControlPlaneMachine(cluster, "control-plane-machine")
controlPaneJoinConfig := newControlPlaneJoinKubeadmConfig(controlPaneMachine, "control-plane-join-cfg")

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

// stage a secret for certs
certificates, _ := certs.NewCertificates()
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: ClusterCertificatesSecretName(cluster.GetName()),
Namespace: controlPaneJoinConfig.GetNamespace(),
var useCases = []struct {
name string
machine *capiv1alpha2.Machine
configName string
configBuilder func(machine *capiv1alpha2.Machine, name string) *cabpkV1alpha2.KubeadmConfig
}{
{
name: "Join a worker node with a fully compiled kubeadm config object",
machine: newWorkerMachine(cluster, "worker-machine"),
configName: "worker-join-cfg",
configBuilder: newWorkerJoinKubeadmConfig,
},
{
name: "Join a worker node with an empty kubeadm config object",
machine: newWorkerMachine(cluster, "worker-machine"),
configName: "worker-join-cfg",
configBuilder: newKubeadmConfig,
},
{
name: "Join a control plane node with a fully compiled kubeadm config object",
machine: newControlPlaneMachine(cluster, "control-plane-machine"),
configName: "control-plane-join-cfg",
configBuilder: newControlPlaneJoinKubeadmConfig,
},
{
name: "Join a control plane node with an empty kubeadm config object",
machine: newControlPlaneMachine(cluster, "control-plane-machine"),
configName: "control-plane-join-cfg",
configBuilder: newKubeadmConfig,
},
Data: certificates.ToMap(),
}
_ = myclient.Create(context.Background(), secret)

k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
SecretsClientFactory: newFakeSecretFactory(),
}
for _, rt := range useCases {
t.Run(rt.name, func(t *testing.T) {

request := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "default",
Name: "worker-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")
}
config := rt.configBuilder(rt.machine, rt.configName)

cfg, err := getKubeadmConfig(myclient, "worker-join-cfg")
if err != nil {
t.Fatal(fmt.Sprintf("Failed to reconcile:\n %+v", err))
}
objects := []runtime.Object{
cluster,
rt.machine,
config,
}
myclient := fake.NewFakeClientWithScheme(setupScheme(), objects...)

if cfg.Status.Ready != true {
t.Fatal("Expected status ready")
}
// stage a secret for certs
certificates, _ := certs.NewCertificates()
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: ClusterCertificatesSecretName(cluster.GetName()),
Namespace: config.GetNamespace(),
},
Data: certificates.ToMap(),
}
_ = myclient.Create(context.Background(), secret)

if cfg.Status.BootstrapData == nil {
t.Fatal("Expected status ready")
}
k := &KubeadmConfigReconciler{
Log: log.Log,
Client: myclient,
SecretsClientFactory: newFakeSecretFactory(),
}

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 b41e9c2

Please sign in to comment.