diff --git a/internal/cli/node/add.go b/internal/cli/node/add.go index b45d008..d449f88 100644 --- a/internal/cli/node/add.go +++ b/internal/cli/node/add.go @@ -108,21 +108,6 @@ func runAdd(ctx context.Context, nodeName, controlPlane, nodeImage, role string, return fmt.Errorf("ensuring cluster image: %w", err) } - // Ensure images volume exists for this node image version - logger.Infof("Step 0: Ensuring cluster images volume...") - clusterMgr := cluster.New(cluster.Config{ - Name: clusterName, - ControlPlane: controlPlane, - HostNetworkPopulator: hostNetworkPopulator, - Logger: logger, - }) - - clusterImagesVolume, err := clusterMgr.EnsureImagesVolume(ctx, nodeImage) - if err != nil { - return fmt.Errorf("ensuring images volume: %w", err) - } - logger.Info("") - // Step 1: Create the new node logger.Infof("Step 1: Creating %s node...", role) logger.Infof("Node image: %s", nodeImage) @@ -140,6 +125,27 @@ func runAdd(ctx context.Context, nodeName, controlPlane, nodeImage, role string, } } + // Auto-detect the control-plane node name from container labels + discovered, err := findControlPlaneNode(ctx, podmanClient, clusterName, "") + if err == nil { + controlPlane = discovered + } + + // Ensure images volume exists for this node image version + logger.Infof("Step 0: Ensuring cluster images volume...") + clusterMgr := cluster.New(cluster.Config{ + Name: clusterName, + ControlPlane: controlPlane, + HostNetworkPopulator: hostNetworkPopulator, + Logger: logger, + }) + + clusterImagesVolume, err := clusterMgr.EnsureImagesVolume(ctx, nodeImage) + if err != nil { + return fmt.Errorf("ensuring images volume: %w", err) + } + logger.Info("") + // Discover DNS container IP for cloud-init config dnsMgr, err := dns.NewManager(clusterName) if err != nil { diff --git a/test/integration/helpers/cluster.go b/test/integration/helpers/cluster.go index a998337..291d94e 100644 --- a/test/integration/helpers/cluster.go +++ b/test/integration/helpers/cluster.go @@ -50,6 +50,14 @@ func CreateCluster(name string) { Expect(session.ExitCode()).To(Equal(0), "Failed to create cluster: %s", string(session.Err.Contents())) } +// CreateClusterWithNodeName creates a cluster with a custom control-plane node name +func CreateClusterWithNodeName(name, nodeName string) { + GinkgoWriter.Printf("Creating cluster: %s with node name: %s (with auto-assigned API port)\n", name, nodeName) + cmd := BinkCmd("cluster", "start", "--cluster-name", name, "--node-name", nodeName, "--api-port", "0", "--memory", "1900", "--max-memory", "4096") + session := RunCommand(cmd, 10*time.Minute) + Expect(session.ExitCode()).To(Equal(0), "Failed to create cluster: %s", string(session.Err.Contents())) +} + // AddNode adds a node to the cluster func AddNode(clusterName, nodeName string, extraArgs ...string) { GinkgoWriter.Printf("Adding node %s to cluster %s\n", nodeName, clusterName) diff --git a/test/integration/multinode_test.go b/test/integration/multinode_test.go index ab99e61..9b54474 100644 --- a/test/integration/multinode_test.go +++ b/test/integration/multinode_test.go @@ -134,6 +134,31 @@ var _ = Describe("Multi-Node Clusters", func() { } }) + It("should add worker node when cluster uses custom node name", func() { + const customNodeName = "cp-custom" + + By("Creating a cluster with a custom control-plane node name") + helpers.CreateClusterWithNodeName(clusterName, customNodeName) + + By("Verifying control-plane container has the custom name") + containerName := helpers.NodeContainerName(clusterName, customNodeName) + container := helpers.GetContainer(containerName) + Expect(container).ToNot(BeNil(), "Container %s should exist", containerName) + Expect(container.State).To(Equal("running")) + + By("Adding a worker node without specifying --control-plane") + helpers.AddNode(clusterName, node2, "--role", "worker") + + By("Exposing API and creating Kubernetes client") + kubeClient, kubeconfigPath := helpers.SetupKubeClient(clusterName) + defer helpers.CleanupKubeconfig(kubeconfigPath) + + By("Verifying both nodes are Ready in Kubernetes") + helpers.WaitForNodeReady(kubeClient, customNodeName, 5*time.Minute) + helpers.WaitForNodeReady(kubeClient, node2, 5*time.Minute) + Expect(helpers.GetNodeCount(kubeClient)).To(Equal(2)) + }) + It("should add control-plane nodes for HA configuration", Serial, func() { By("Creating a single-node cluster") helpers.CreateCluster(clusterName)