Skip to content

Commit 59643a0

Browse files
authored
Check k3s-serving secret to determine controlPlane.Status.Initialized (#113)
Signed-off-by: Andrea Mazzotti <[email protected]>
1 parent 7e7531a commit 59643a0

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed

controlplane/controllers/kthreescontrolplane_controller.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,12 @@ func (r *KThreesControlPlaneReconciler) updateStatus(ctx context.Context, kcp *c
395395
kcp.Status.ReadyReplicas = status.ReadyNodes
396396
kcp.Status.UnavailableReplicas = replicas - status.ReadyNodes
397397

398+
if status.HasK3sServingSecret {
399+
kcp.Status.Initialized = true
400+
}
401+
398402
if kcp.Status.ReadyReplicas > 0 {
399403
kcp.Status.Ready = true
400-
kcp.Status.Initialized = true
401404
conditions.MarkTrue(kcp, controlplanev1.AvailableCondition)
402405
}
403406

pkg/k3s/workload_cluster.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"sigs.k8s.io/cluster-api/util/collections"
2626
"sigs.k8s.io/cluster-api/util/conditions"
2727
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
28+
"sigs.k8s.io/controller-runtime/pkg/log"
2829

2930
controlplanev1 "github.com/k3s-io/cluster-api-k3s/controlplane/api/v1beta2"
3031
"github.com/k3s-io/cluster-api-k3s/pkg/etcd"
@@ -34,6 +35,7 @@ import (
3435
const (
3536
kubeProxyKey = "kube-proxy"
3637
labelNodeRoleControlPlane = "node-role.kubernetes.io/master"
38+
k3sServingSecretKey = "k3s-serving"
3739
)
3840

3941
var (
@@ -74,6 +76,8 @@ type ClusterStatus struct {
7476
Nodes int32
7577
// ReadyNodes are the count of nodes that are reporting ready
7678
ReadyNodes int32
79+
// HasK3sServingSecret will be true if the k3s-serving secret has been uploaded, false otherwise.
80+
HasK3sServingSecret bool
7781
}
7882

7983
func (w *Workload) getControlPlaneNodes(ctx context.Context) (*corev1.NodeList, error) {
@@ -105,6 +109,28 @@ func (w *Workload) ClusterStatus(ctx context.Context) (ClusterStatus, error) {
105109
}
106110
}
107111

112+
// Get the 'k3s-serving' secret in the 'kube-system' namespace.
113+
//
114+
// The resource we fetch has no particular importance,
115+
// this is just to verify that the Control Plane has been initialized,
116+
// by fetching any resource that has been uploaded.
117+
// Since the `k3s-serving` secret contains the cluster certificate,
118+
// this secret is guaranteed to exist in any k3s deployment,
119+
// therefore it can be reliably used for this test.
120+
key := ctrlclient.ObjectKey{
121+
Name: k3sServingSecretKey,
122+
Namespace: metav1.NamespaceSystem,
123+
}
124+
125+
err = w.Client.Get(ctx, key, &corev1.Secret{})
126+
// In case of error we do assume the control plane is not initialized yet.
127+
if err != nil {
128+
logger := log.FromContext(ctx)
129+
logger.Info("Control Plane does not seem to be initialized yet.", "reason", err.Error())
130+
}
131+
132+
status.HasK3sServingSecret = err == nil
133+
108134
return status, nil
109135
}
110136

pkg/k3s/workload_cluster_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package k3s
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
. "github.com/onsi/gomega"
8+
corev1 "k8s.io/api/core/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"sigs.k8s.io/controller-runtime/pkg/client"
11+
"sigs.k8s.io/controller-runtime/pkg/client/fake"
12+
)
13+
14+
func TestClusterStatus(t *testing.T) {
15+
node1 := &corev1.Node{
16+
ObjectMeta: metav1.ObjectMeta{
17+
Name: "node1",
18+
Labels: map[string]string{
19+
labelNodeRoleControlPlane: "true",
20+
},
21+
},
22+
Status: corev1.NodeStatus{
23+
Conditions: []corev1.NodeCondition{{
24+
Type: corev1.NodeReady,
25+
Status: corev1.ConditionTrue,
26+
}},
27+
},
28+
}
29+
node2 := &corev1.Node{
30+
ObjectMeta: metav1.ObjectMeta{
31+
Name: "node2",
32+
Labels: map[string]string{
33+
labelNodeRoleControlPlane: "true",
34+
},
35+
},
36+
Status: corev1.NodeStatus{
37+
Conditions: []corev1.NodeCondition{{
38+
Type: corev1.NodeReady,
39+
Status: corev1.ConditionFalse,
40+
}},
41+
},
42+
}
43+
servingSecret := &corev1.Secret{
44+
ObjectMeta: metav1.ObjectMeta{
45+
Name: k3sServingSecretKey,
46+
Namespace: metav1.NamespaceSystem,
47+
},
48+
}
49+
tests := []struct {
50+
name string
51+
objs []client.Object
52+
expectErr bool
53+
expectHasSecret bool
54+
}{
55+
{
56+
name: "returns cluster status",
57+
objs: []client.Object{node1, node2},
58+
expectHasSecret: false,
59+
},
60+
{
61+
name: "returns cluster status with k3s-serving secret",
62+
objs: []client.Object{node1, node2, servingSecret},
63+
expectHasSecret: true,
64+
},
65+
}
66+
67+
for _, tt := range tests {
68+
t.Run(tt.name, func(t *testing.T) {
69+
g := NewWithT(t)
70+
fakeClient := fake.NewClientBuilder().WithObjects(tt.objs...).Build()
71+
w := &Workload{
72+
Client: fakeClient,
73+
}
74+
status, err := w.ClusterStatus(context.TODO())
75+
g.Expect(err).ToNot(HaveOccurred())
76+
g.Expect(status.Nodes).To(BeEquivalentTo(2))
77+
g.Expect(status.ReadyNodes).To(BeEquivalentTo(1))
78+
g.Expect(status.HasK3sServingSecret).To(Equal(tt.expectHasSecret))
79+
})
80+
}
81+
}

0 commit comments

Comments
 (0)