cluster: derive default machine name from its hostname when adding to cluster

This commit is contained in:
Pasha Sviderski
2026-06-19 16:54:59 +10:00
parent e3823c29bf
commit 0c42a7df65
8 changed files with 352 additions and 203 deletions
+26 -6
View File
@@ -11,6 +11,7 @@ import (
"github.com/psviderski/uncloud/internal/cli/config"
"github.com/psviderski/uncloud/internal/machine"
"github.com/psviderski/uncloud/internal/machine/api/pb"
"github.com/psviderski/uncloud/internal/machine/cluster"
"github.com/psviderski/uncloud/internal/machine/network"
"github.com/psviderski/uncloud/internal/sshexec"
"github.com/psviderski/uncloud/pkg/api"
@@ -330,7 +331,7 @@ type AddMachineOptions struct {
// The cluster client is connected to the existing machine in the cluster. It was used to add the new machine to the
// cluster. The machine client is connected to the new machine and can be used to interact with it.
// Both client should be closed after use by the caller.
func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client.Client, *client.Client, error) {
func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (_ *client.Client, _ *client.Client, err error) {
contextName := cli.ContextOverrideOrCurrent()
c, err := cli.ConnectCluster(ctx)
if err != nil {
@@ -351,16 +352,19 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client
machineClient.Close()
}
}()
// IMPORTANT: 'err' is a named return value so the deferred cleanups above observe it on every error return.
// Do not shadow it with ':=' in a nested scope, or the deferred client cleanup would be skipped on error.
// Check if the machine is already initialised as a cluster member and prompt the user to reset it first.
// TODO: refactor to use client.InspectMachine.
minfo, err := machineClient.Inspect(ctx, &emptypb.Empty{})
inspectResp, err := machineClient.MachineClient.InspectMachine(ctx, nil)
if err != nil {
return nil, nil, fmt.Errorf("inspect machine: %w", err)
}
minfo := inspectResp.Machines[0].Machine
if minfo.Id != "" {
// Check if the machine is already a member of this cluster.
machines, err := c.ListMachines(ctx, nil)
var machines api.MachineMembersList
machines, err = c.ListMachines(ctx, nil)
if err != nil {
return nil, nil, fmt.Errorf("list cluster machines: %w", err)
}
@@ -416,8 +420,24 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client
endpoints[i] = pb.NewIPPort(addrPort)
}
}
// Default the machine name to the machine's hostname when not explicitly provided, ensuring it is
// unique within the cluster.
machineName := opts.MachineName
if machineName == "" {
var machines api.MachineMembersList
if machines, err = c.ListMachines(ctx, nil); err != nil {
return nil, nil, fmt.Errorf("list cluster machines: %w", err)
}
existing := make([]string, len(machines))
for i, m := range machines {
existing[i] = m.Machine.Name
}
if machineName, err = cluster.DefaultMachineName(minfo.Hostname, existing); err != nil {
return nil, nil, fmt.Errorf("generate machine name: %w", err)
}
}
addReq := &pb.AddMachineRequest{
Name: opts.MachineName,
Name: machineName,
Network: &pb.NetworkConfig{
Endpoints: endpoints,
PublicKey: token.PublicKey,
@@ -439,7 +459,7 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client
// Snapshot the cluster store version so the new machine can catch up before participating.
var storeVersion map[string]int64
inspectResp, err := c.MachineClient.InspectMachine(ctx, &emptypb.Empty{})
inspectResp, err = c.MachineClient.InspectMachine(ctx, &emptypb.Empty{})
if err != nil {
// TODO(lhf): remove Unimplemented check when v0.17.0 is released.
if status.Convert(err).Code() != codes.Unimplemented {