From 2c02139369831d39221bcce0277ef301e55e0dde Mon Sep 17 00:00:00 2001 From: Pasha Sviderski Date: Wed, 6 Aug 2025 16:49:57 +1000 Subject: [PATCH] fix: add ssh_key_path for connections in uncloud config only when using SSH key explicitly (not SSH agent) --- cmd/uncloud/machine/add.go | 9 +++++---- cmd/uncloud/machine/init.go | 5 +++-- internal/cli/cli.go | 26 ++++++++++++++++++++------ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/cmd/uncloud/machine/add.go b/cmd/uncloud/machine/add.go index a23ab2a0..7b9fec3d 100644 --- a/cmd/uncloud/machine/add.go +++ b/cmd/uncloud/machine/add.go @@ -41,7 +41,7 @@ func NewAddCommand() *cobra.Command { if err != nil { return fmt.Errorf("parse remote machine: %w", err) } - remoteMachine := cli.RemoteMachine{ + remoteMachine := &cli.RemoteMachine{ User: user, Host: host, Port: port, @@ -62,8 +62,9 @@ func NewAddCommand() *cobra.Command { fmt.Sprintf("blank '' or '%s' to disable ingress on this machine, or specify an IP address.", PublicIPNone), ) cmd.Flags().StringVarP( - &opts.sshKey, "ssh-key", "i", "~/.ssh/id_ed25519", - "Path to SSH private key for remote login (if not already added to SSH agent).", + &opts.sshKey, "ssh-key", "i", "", + fmt.Sprintf("Path to SSH private key for remote login (if not already added to SSH agent). (default %q)", + cli.DefaultSSHKeyPath), ) cmd.Flags().StringVar( &opts.version, "version", "latest", @@ -77,7 +78,7 @@ func NewAddCommand() *cobra.Command { return cmd } -func add(ctx context.Context, uncli *cli.CLI, remoteMachine cli.RemoteMachine, opts addOptions) error { +func add(ctx context.Context, uncli *cli.CLI, remoteMachine *cli.RemoteMachine, opts addOptions) error { var publicIP *netip.Addr switch opts.publicIP { case "auto": diff --git a/cmd/uncloud/machine/init.go b/cmd/uncloud/machine/init.go index 3ab0dd3e..85ddd2bd 100644 --- a/cmd/uncloud/machine/init.go +++ b/cmd/uncloud/machine/init.go @@ -80,8 +80,9 @@ func NewInitCommand() *cobra.Command { fmt.Sprintf("blank '' or '%s' to disable ingress on this machine, or specify an IP address.", PublicIPNone), ) cmd.Flags().StringVarP( - &opts.sshKey, "ssh-key", "i", "~/.ssh/id_ed25519", - "Path to SSH private key for remote login (if not already added to SSH agent).", + &opts.sshKey, "ssh-key", "i", "", + fmt.Sprintf("Path to SSH private key for remote login (if not already added to SSH agent). (default %q)", + cli.DefaultSSHKeyPath), ) cmd.Flags().StringVar( &opts.version, "version", "latest", diff --git a/internal/cli/cli.go b/internal/cli/cli.go index f9f06873..675281cd 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -22,7 +22,12 @@ import ( "google.golang.org/protobuf/types/known/emptypb" ) -const defaultContextName = "default" +const ( + // DefaultSSHKeyPath is the fallback location for the SSH private key when provisioning remote machines. + // Used when no key is explicitly provided and SSH agent authentication fails. + DefaultSSHKeyPath = "~/.ssh/id_ed25519" + defaultContextName = "default" +) type CLI struct { Config *config.Config @@ -173,7 +178,7 @@ func (cli *CLI) initRemoteMachine(ctx context.Context, opts InitClusterOptions) return nil, fmt.Errorf("cluster context '%s' already exists", contextName) } - machineClient, err := cli.provisionRemoteMachine(ctx, *opts.RemoteMachine, opts.Version) + machineClient, err := provisionRemoteMachine(ctx, opts.RemoteMachine, opts.Version) if err != nil { return nil, err } @@ -249,7 +254,7 @@ type AddMachineOptions struct { Context string MachineName string PublicIP *netip.Addr - RemoteMachine RemoteMachine + RemoteMachine *RemoteMachine Version string } @@ -272,7 +277,7 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client } }() - machineClient, err := cli.provisionRemoteMachine(ctx, opts.RemoteMachine, opts.Version) + machineClient, err := provisionRemoteMachine(ctx, opts.RemoteMachine, opts.Version) if err != nil { return nil, nil, err } @@ -382,11 +387,20 @@ func (cli *CLI) AddMachine(ctx context.Context, opts AddMachineOptions) (*client // provisionRemoteMachine installs the Uncloud daemon and dependencies on the remote machine over SSH and returns // a machine API client to interact with the machine. The client should be closed after use by the caller. // The version parameter specifies the version of the Uncloud daemon to install. If empty, the latest version is used. -func (cli *CLI) provisionRemoteMachine( - ctx context.Context, remoteMachine RemoteMachine, version string, +// The remoteMachine.SSHKeyPath could be updated to the default SSH key path if it is not set and the SSH agent +// authentication fails. +func provisionRemoteMachine( + ctx context.Context, remoteMachine *RemoteMachine, version string, ) (*client.Client, error) { // Provision the remote machine by installing the Uncloud daemon and dependencies over SSH. sshClient, err := sshexec.Connect(remoteMachine.User, remoteMachine.Host, remoteMachine.Port, remoteMachine.KeyPath) + // If the SSH connection using SSH agent fails and no key path is provided, try to use the default SSH key. + if err != nil && remoteMachine.KeyPath == "" { + remoteMachine.KeyPath = DefaultSSHKeyPath + sshClient, err = sshexec.Connect( + remoteMachine.User, remoteMachine.Host, remoteMachine.Port, remoteMachine.KeyPath, + ) + } if err != nil { return nil, fmt.Errorf( "SSH login to remote machine %s: %w",