Skip to content

Commit be79ef2

Browse files
authored
Wait for worker node to be ready when joining (#2019)
* Wait for worker node to be ready when joining
1 parent 1cd37cf commit be79ef2

File tree

7 files changed

+70
-27
lines changed

7 files changed

+70
-27
lines changed

cmd/installer/cli/install.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ func waitForNode(ctx context.Context) error {
976976
if err != nil {
977977
return fmt.Errorf("get hostname: %w", err)
978978
}
979-
if err := kubeutils.WaitForControllerNode(ctx, kcli, hostname); err != nil {
979+
if err := kubeutils.WaitForNode(ctx, kcli, hostname, false); err != nil {
980980
return fmt.Errorf("wait for node: %w", err)
981981
}
982982
return nil

cmd/installer/cli/join.go

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,26 @@ func runJoin(ctx context.Context, name string, flags JoinCmdFlags, jcmd *kotsadm
182182
return err
183183
}
184184

185-
if isWorker {
186-
logrus.Debugf("worker node join finished")
187-
return nil
188-
}
189-
190185
kcli, err := kubeutils.KubeClient()
191186
if err != nil {
192187
return fmt.Errorf("unable to get kube client: %w", err)
193188
}
194189

190+
hostname, err := os.Hostname()
191+
if err != nil {
192+
return fmt.Errorf("unable to get hostname: %w", err)
193+
}
194+
195+
logrus.Debugf("waiting for node to join cluster")
196+
if err := waitForNodeToJoin(ctx, kcli, hostname, isWorker); err != nil {
197+
return fmt.Errorf("unable to wait for node: %w", err)
198+
}
199+
200+
if isWorker {
201+
logrus.Debugf("worker node join finished")
202+
return nil
203+
}
204+
195205
airgapChartsPath := ""
196206
if flags.isAirgap {
197207
airgapChartsPath = runtimeconfig.EmbeddedClusterChartsSubDir()
@@ -207,15 +217,6 @@ func runJoin(ctx context.Context, name string, flags JoinCmdFlags, jcmd *kotsadm
207217
}
208218
defer hcli.Close()
209219

210-
hostname, err := os.Hostname()
211-
if err != nil {
212-
return fmt.Errorf("unable to get hostname: %w", err)
213-
}
214-
215-
if err := waitForNodeToJoin(ctx, kcli, hostname); err != nil {
216-
return fmt.Errorf("unable to wait for node: %w", err)
217-
}
218-
219220
if flags.enableHighAvailability {
220221
if err := maybeEnableHA(ctx, kcli, hcli, flags.isAirgap, cidrCfg.ServiceCIDR, jcmd.InstallationSpec.Proxy, jcmd.InstallationSpec.Config); err != nil {
221222
return fmt.Errorf("unable to enable high availability: %w", err)
@@ -246,7 +247,12 @@ func runJoinVerifyAndPrompt(name string, flags JoinCmdFlags, jcmd *kotsadm.JoinC
246247
}
247248

248249
runtimeconfig.Set(jcmd.InstallationSpec.RuntimeConfig)
249-
os.Setenv("KUBECONFIG", runtimeconfig.PathToKubeConfig())
250+
isWorker := !strings.Contains(jcmd.K0sJoinCommand, "controller")
251+
if isWorker {
252+
os.Setenv("KUBECONFIG", runtimeconfig.PathToKubeletConfig())
253+
} else {
254+
os.Setenv("KUBECONFIG", runtimeconfig.PathToKubeConfig())
255+
}
250256
os.Setenv("TMPDIR", runtimeconfig.EmbeddedClusterTmpSubDir())
251257

252258
if err := runtimeconfig.WriteToDisk(); err != nil {
@@ -476,11 +482,11 @@ func runK0sInstallCommand(networkInterface string, fullcmd string) error {
476482
return nil
477483
}
478484

479-
func waitForNodeToJoin(ctx context.Context, kcli client.Client, hostname string) error {
485+
func waitForNodeToJoin(ctx context.Context, kcli client.Client, hostname string, isWorker bool) error {
480486
loading := spinner.Start()
481487
defer loading.Close()
482488
loading.Infof("Waiting for node to join the cluster")
483-
if err := kubeutils.WaitForControllerNode(ctx, kcli, hostname); err != nil {
489+
if err := kubeutils.WaitForNode(ctx, kcli, hostname, isWorker); err != nil {
484490
return fmt.Errorf("unable to wait for node: %w", err)
485491
}
486492
loading.Infof("Node has joined the cluster!")

pkg/dryrun/kubeutils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ func (k *KubeUtils) WaitForNodes(ctx context.Context, cli client.Client) error {
4444
return nil
4545
}
4646

47-
func (k *KubeUtils) WaitForControllerNode(ctx context.Context, kcli client.Client, name string) error {
47+
func (k *KubeUtils) WaitForNode(ctx context.Context, kcli client.Client, name string, isWorker bool) error {
4848
return nil
4949
}
5050

pkg/kubeutils/interface.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type KubeUtilsInterface interface {
2828
WaitForPodComplete(ctx context.Context, cli client.Client, ns, name string, opts *WaitOptions) error
2929
WaitForInstallation(ctx context.Context, cli client.Client, writer *spinner.MessageWriter) error
3030
WaitForNodes(ctx context.Context, cli client.Client) error
31-
WaitForControllerNode(ctx context.Context, kcli client.Client, name string) error
31+
WaitForNode(ctx context.Context, kcli client.Client, name string, isWorker bool) error
3232
IsNamespaceReady(ctx context.Context, cli client.Client, ns string) (bool, error)
3333
IsDeploymentReady(ctx context.Context, cli client.Client, ns, name string) (bool, error)
3434
IsStatefulSetReady(ctx context.Context, cli client.Client, ns, name string) (bool, error)
@@ -86,8 +86,8 @@ func WaitForNodes(ctx context.Context, cli client.Client) error {
8686
return kb.WaitForNodes(ctx, cli)
8787
}
8888

89-
func WaitForControllerNode(ctx context.Context, kcli client.Client, name string) error {
90-
return kb.WaitForControllerNode(ctx, kcli, name)
89+
func WaitForNode(ctx context.Context, kcli client.Client, name string, isWorker bool) error {
90+
return kb.WaitForNode(ctx, kcli, name, isWorker)
9191
}
9292

9393
func IsNamespaceReady(ctx context.Context, cli client.Client, ns string) (bool, error) {

pkg/kubeutils/kubeutils.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ func (k *KubeUtils) WaitForNodes(ctx context.Context, cli client.Client) error {
187187
return nil
188188
}
189189

190-
// WaitForControllerNode waits for a specific controller node to be registered with the cluster.
191-
func (k *KubeUtils) WaitForControllerNode(ctx context.Context, kcli client.Client, name string) error {
190+
// WaitForNode waits for a specific controller node to be registered with the cluster.
191+
func (k *KubeUtils) WaitForNode(ctx context.Context, kcli client.Client, name string, isWorker bool) error {
192192
backoff := wait.Backoff{Steps: 60, Duration: 5 * time.Second, Factor: 1.0, Jitter: 0.1}
193193
var lasterr error
194194
if err := wait.ExponentialBackoffWithContext(
@@ -198,9 +198,11 @@ func (k *KubeUtils) WaitForControllerNode(ctx context.Context, kcli client.Clien
198198
lasterr = fmt.Errorf("unable to get node: %v", err)
199199
return false, nil
200200
}
201-
if _, ok := node.Labels["node-role.kubernetes.io/control-plane"]; !ok {
202-
lasterr = fmt.Errorf("control plane label not found")
203-
return false, nil
201+
if !isWorker {
202+
if _, ok := node.Labels["node-role.kubernetes.io/control-plane"]; !ok {
203+
lasterr = fmt.Errorf("control plane label not found")
204+
return false, nil
205+
}
204206
}
205207
for _, condition := range node.Status.Conditions {
206208
if condition.Type == corev1.NodeReady && condition.Status == corev1.ConditionTrue {

pkg/runtimeconfig/runtimeconfig.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@ func PathToKubeConfig() string {
121121
return filepath.Join(EmbeddedClusterK0sSubDir(), "pki/admin.conf")
122122
}
123123

124+
// PathToKubeletConfig returns the path to the kubelet config file.
125+
func PathToKubeletConfig() string {
126+
return filepath.Join(EmbeddedClusterK0sSubDir(), "kubelet.conf")
127+
}
128+
124129
// EmbeddedClusterSupportSubDir returns the path to the directory where embedded-cluster
125130
// support files are stored. Things that are useful when providing end user support in
126131
// a running cluster should be stored into this directory.

tests/dryrun/join_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,33 @@ func TestJoinRunPreflights(t *testing.T) {
176176
dryrunJoin(t, "run-preflights", "10.0.0.1", "some-token")
177177
t.Logf("%s: test complete", time.Now().Format(time.RFC3339))
178178
}
179+
180+
func TestJoinWorkerNode(t *testing.T) {
181+
drFile := filepath.Join(t.TempDir(), "ec-dryrun.yaml")
182+
client := &dryrun.Client{
183+
Kotsadm: dryrun.NewKotsadm(),
184+
}
185+
clusterID := uuid.New()
186+
jcmd := &kotsadm.JoinCommandResponse{
187+
K0sJoinCommand: "/usr/local/bin/k0s install worker --no-taints --labels kots.io/embedded-cluster-role=total-1,kots.io/embedded-cluster-role-0=worker-test,worker-label=worker-label-value",
188+
K0sToken: "some-k0s-token",
189+
EmbeddedClusterVersion: "v0.0.0",
190+
ClusterID: clusterID,
191+
InstallationSpec: ecv1beta1.InstallationSpec{
192+
ClusterID: clusterID.String(),
193+
Config: &ecv1beta1.ConfigSpec{
194+
UnsupportedOverrides: ecv1beta1.UnsupportedOverrides{},
195+
},
196+
},
197+
}
198+
client.Kotsadm.SetGetJoinTokenResponse("10.0.0.1", "some-token", jcmd, nil)
199+
dryrun.Init(drFile, client)
200+
dr := dryrunJoin(t, "10.0.0.1", "some-token")
201+
202+
// --- validate os env --- //
203+
assertEnv(t, dr.OSEnv, map[string]string{
204+
"KUBECONFIG": "/var/lib/embedded-cluster/k0s/kubelet.conf", // uses kubelet config
205+
})
206+
207+
t.Logf("%s: test complete", time.Now().Format(time.RFC3339))
208+
}

0 commit comments

Comments
 (0)