diff --git a/cli/cmd/cluster_gate.go b/cli/cmd/cluster_gate.go index 021259c9..1aa257e8 100644 --- a/cli/cmd/cluster_gate.go +++ b/cli/cmd/cluster_gate.go @@ -222,7 +222,10 @@ func offerKind(d cluster.Decision) (string, error) { how := "Re-run kates deploy in a terminal to be asked." if configExistsFn(cluster.DefaultKindConfig) { how = fmt.Sprintf("Re-run in a terminal to be prompted, or create it directly:\n"+ - " kind create cluster --config %s --name %s", cluster.DefaultKindConfig, cluster.DefaultKindClusterName) + " kind create cluster --config %s --name %s\n"+ + // The first zone is the control-plane node, and Kafka pods pin to each zone. + " kubectl taint nodes %s node-role.kubernetes.io/control-plane:NoSchedule-", + cluster.DefaultKindConfig, cluster.DefaultKindClusterName, cluster.KindZones[0]) } return "", fmt.Errorf("no reachable Kubernetes cluster.\n"+ " Docker and kind are available — a local %d-zone cluster can be created.\n %s", diff --git a/cli/cmd/cluster_gate_test.go b/cli/cmd/cluster_gate_test.go index f2d272df..b694e981 100644 --- a/cli/cmd/cluster_gate_test.go +++ b/cli/cmd/cluster_gate_test.go @@ -514,6 +514,9 @@ func TestResolveCluster_OfferKindNonTTYFailsWithoutPrompting(t *testing.T) { if !strings.Contains(err.Error(), "kind create cluster") { t.Errorf("error should give the manual command, got: %v", err) } + if !strings.Contains(err.Error(), "kubectl taint nodes alpha node-role.kubernetes.io/control-plane:NoSchedule-") { + t.Errorf("error should free the control-plane zone, or Kafka stays Pending, got: %v", err) + } } // IsInteractive is the single guard everything else relies on.