Skip to content

Commit 1118b93

Browse files
authored
Merge pull request #21 from weaveworks/prevent-rebootstrapping
Prevent rebootstrapping
2 parents 4101e9d + 000065a commit 1118b93

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

controllers/clusterbootstrapconfig_controller.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ func (r *ClusterBootstrapConfigReconciler) Reconcile(ctx context.Context, req ct
112112
mergePatch, err := json.Marshal(map[string]interface{}{
113113
"metadata": map[string]interface{}{
114114
"annotations": map[string]interface{}{
115-
capiv1alpha1.BootstrappedAnnotation: "yes",
116115
capiv1alpha1.BootstrapConfigsAnnotation: appendClusterConfigToBootstrappedList(clusterBootstrapConfig, cluster),
117116
},
118117
},
@@ -178,10 +177,14 @@ func (r *ClusterBootstrapConfigReconciler) getClustersBySelector(ctx context.Con
178177
}
179178
}
180179

180+
// Check for the legacy bootstrapped annotation and skip bootstrapping if present.
181+
// We don't add this anymore but might be present on existing clusters bootstrapped from older versions.
181182
if metav1.HasAnnotation(cluster.ObjectMeta, capiv1alpha1.BootstrappedAnnotation) {
182-
if alreadyBootstrappedWithConfig(cluster, config) {
183-
continue
184-
}
183+
continue
184+
}
185+
186+
if alreadyBootstrappedWithConfig(cluster, config) {
187+
continue
185188
}
186189
if cluster.DeletionTimestamp.IsZero() {
187190
clusters = append(clusters, cluster)

controllers/clusterbootstrapconfig_controller_test.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,11 @@ func TestReconcile_when_cluster_ready(t *testing.T) {
101101
readyNode := makeNode(map[string]string{
102102
"node-role.kubernetes.io/control-plane": "",
103103
}, corev1.NodeCondition{
104-
Type: "Ready", Status: "True", LastHeartbeatTime: metav1.Now(), LastTransitionTime: metav1.Now(), Reason: "KubeletReady", Message: "kubelet is posting ready status"})
104+
Type: "Ready", Status: "True",
105+
LastHeartbeatTime: metav1.Now(),
106+
LastTransitionTime: metav1.Now(),
107+
Reason: "KubeletReady",
108+
Message: "kubelet is posting ready status"})
105109

106110
cl := makeTestCluster(func(c *gitopsv1alpha1.GitopsCluster) {
107111
c.ObjectMeta.Labels = bc.Spec.ClusterSelector.MatchLabels
@@ -196,7 +200,6 @@ func TestReconcile_when_cluster_ready_bootstrapped_with_different_config(t *test
196200
cl := makeTestCluster(func(c *gitopsv1alpha1.GitopsCluster) {
197201
c.ObjectMeta.Labels = bc.Spec.ClusterSelector.MatchLabels
198202
c.ObjectMeta.Annotations = map[string]string{
199-
capiv1alpha1.BootstrappedAnnotation: "true",
200203
capiv1alpha1.BootstrapConfigsAnnotation: "unknown/unknown",
201204
}
202205
c.Status.Conditions = append(c.Status.Conditions, makeReadyCondition())
@@ -387,6 +390,54 @@ func TestReconcile_when_cluster_ready_bootstrapped_with_multiple_config(t *testi
387390
}
388391
}
389392

393+
func TestReconcile_when_cluster_ready_bootstrapped_with_bootstrapped_annotation(t *testing.T) {
394+
// If the old annotation exists, don't rebootstrap even with newer configs.
395+
bc := makeTestClusterBootstrapConfig()
396+
cl := makeTestCluster(func(c *gitopsv1alpha1.GitopsCluster) {
397+
c.ObjectMeta.Labels = bc.Spec.ClusterSelector.MatchLabels
398+
c.ObjectMeta.Annotations = map[string]string{
399+
capiv1alpha1.BootstrappedAnnotation: "true",
400+
}
401+
c.Status.Conditions = append(c.Status.Conditions, makeReadyCondition())
402+
})
403+
readyNode := makeNode(map[string]string{
404+
"node-role.kubernetes.io/control-plane": "",
405+
}, corev1.NodeCondition{
406+
Type: "Ready", Status: "True",
407+
LastHeartbeatTime: metav1.Now(),
408+
LastTransitionTime: metav1.Now(),
409+
Reason: "KubeletReady",
410+
Message: "kubelet is posting ready status"})
411+
secret := makeTestSecret(types.NamespacedName{
412+
Name: cl.GetName() + "-kubeconfig",
413+
Namespace: cl.GetNamespace(),
414+
}, map[string][]byte{"value": []byte("testing")})
415+
// This cheats by using the local client as the remote client to simplify
416+
// getting the value from the remote client.
417+
reconciler := makeTestReconciler(t, bc, cl, secret, readyNode)
418+
reconciler.configParser = func(b []byte) (client.Client, error) {
419+
return reconciler.Client, nil
420+
}
421+
422+
result, err := reconciler.Reconcile(context.TODO(), ctrl.Request{NamespacedName: types.NamespacedName{
423+
Name: bc.GetName(),
424+
Namespace: bc.GetNamespace(),
425+
}})
426+
if err != nil {
427+
t.Fatal(err)
428+
}
429+
if !result.IsZero() {
430+
t.Fatalf("want empty result, got %v", result)
431+
}
432+
var jobs batchv1.JobList
433+
if err := reconciler.List(context.TODO(), &jobs, client.InNamespace(testNamespace)); err != nil {
434+
t.Fatal(err)
435+
}
436+
if l := len(jobs.Items); l != 0 {
437+
t.Fatalf("found %d jobs, want %d", l, 0)
438+
}
439+
}
440+
390441
func TestReconcile_when_empty_label_selector(t *testing.T) {
391442
// When the label selector is empty, we don't want any jobs created, rather
392443
// than a job for all clusters.

0 commit comments

Comments
 (0)