mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 19:13:34 +00:00
establish SSH connection when adding a new machine
This commit is contained in:
+46
-2
@@ -10,6 +10,7 @@ import (
|
|||||||
"uncloud/internal/cli/config"
|
"uncloud/internal/cli/config"
|
||||||
"uncloud/internal/machine/api/pb"
|
"uncloud/internal/machine/api/pb"
|
||||||
"uncloud/internal/secret"
|
"uncloud/internal/secret"
|
||||||
|
"uncloud/internal/sshexec"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultClusterName = "default"
|
const defaultClusterName = "default"
|
||||||
@@ -196,9 +197,52 @@ func (cli *CLI) AddMachine(ctx context.Context, remoteMachine RemoteMachine, clu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("connect to cluster: %w", err)
|
return fmt.Errorf("connect to cluster: %w", err)
|
||||||
}
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = c.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
sshClient, err := sshexec.Connect(remoteMachine.User, remoteMachine.Host, remoteMachine.Port, remoteMachine.KeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"SSH login to remote machine %s: %w",
|
||||||
|
config.NewSSHDestination(remoteMachine.User, remoteMachine.Host, remoteMachine.Port), err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
machineExec := sshexec.NewRemote(sshClient)
|
||||||
|
|
||||||
|
// TODO: Check if the machine is already provisioned using machineClient and ask the user to reset it first.
|
||||||
|
//conn := connector.NewSSHConnectorFromClient(sshClient)
|
||||||
|
//machineClient, err := client.New(ctx, conn)
|
||||||
|
//if err != nil {
|
||||||
|
// return fmt.Errorf("connect to remote machine API: %w", err)
|
||||||
|
//}
|
||||||
|
|
||||||
|
// TODO: Download and install the latest uncloudd binary by running the install shell script from GitHub.
|
||||||
|
// For now upload the binary using scp manually.
|
||||||
|
if _, err = machineExec.Run(ctx, "which uncloudd"); err != nil {
|
||||||
|
return fmt.Errorf("uncloudd binary not found on the remote machine: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//req := &pb.AddMachineRequest{
|
||||||
|
// Name: machineName,
|
||||||
|
// Network: &pb.NetworkConfig{
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//resp, err := c.AddMachine(ctx, req)
|
||||||
|
//if err != nil {
|
||||||
|
// return fmt.Errorf("add machine to cluster: %w", err)
|
||||||
|
//}
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// --1. Establish a client connection to the remote machine.
|
||||||
|
// --2. Check if the machine is already provisioned and ask the user to reset it first.
|
||||||
|
// --3. Download and install the latest uncloudd binary by running the install shell script from GitHub.
|
||||||
|
// 4. Request token from the remote machine.
|
||||||
|
// 5. Add the machine to the cluster using its token and receive a configuration token.
|
||||||
|
// 6. Request the machine to join the cluster using the configuration token.
|
||||||
|
// 7. Save the machine's SSH connection details in the cluster config.
|
||||||
|
|
||||||
fmt.Println("Adding machine to cluster...", c)
|
|
||||||
// TODO
|
|
||||||
//name, connCfg, err := c.AddMachine(ctx, machineName, user, host, port, sshKeyPath)
|
//name, connCfg, err := c.AddMachine(ctx, machineName, user, host, port, sshKeyPath)
|
||||||
//if err != nil {
|
//if err != nil {
|
||||||
// return fmt.Errorf("add machine to cluster %q: %w", cluster.Name(), err)
|
// return fmt.Errorf("add machine to cluster %q: %w", cluster.Name(), err)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ed25519"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -297,11 +296,3 @@ func (c *ClusterClient) registerNewMachine(
|
|||||||
}
|
}
|
||||||
return c.client.AddMachine(ctx, req)
|
return c.client.AddMachine(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func privateKeyFromSecret(s secret.Secret) (ed25519.PrivateKey, error) {
|
|
||||||
// Cluster secret in the config is a hex-encoded private key seed.
|
|
||||||
if len(s) != ed25519.SeedSize {
|
|
||||||
return nil, fmt.Errorf("invalid cluster secret length")
|
|
||||||
}
|
|
||||||
return ed25519.NewKeyFromSeed(s), nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -41,13 +41,23 @@ func NewSSHConnector(cfg *SSHConnectorConfig) *SSHConnector {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSSHConnectorFromClient(client *ssh.Client) *SSHConnector {
|
||||||
|
return &SSHConnector{client: client}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: handle context cancelation.
|
// TODO: handle context cancelation.
|
||||||
func (c *SSHConnector) Connect(ctx context.Context) (*grpc.ClientConn, error) {
|
func (c *SSHConnector) Connect(ctx context.Context) (*grpc.ClientConn, error) {
|
||||||
|
if c.client == nil {
|
||||||
|
// Establish an SSH connection if the SSH client is not provided.
|
||||||
|
if c.config == (SSHConnectorConfig{}) {
|
||||||
|
return nil, fmt.Errorf("SSH connector not configured")
|
||||||
|
}
|
||||||
var err error
|
var err error
|
||||||
c.client, err = sshexec.Connect(c.config.User, c.config.Host, c.config.Port, c.config.KeyPath)
|
c.client, err = sshexec.Connect(c.config.User, c.config.Host, c.config.Port, c.config.KeyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("SSH login to %s@%s:%d: %w", c.config.User, c.config.Host, c.config.Port, err)
|
return nil, fmt.Errorf("SSH login to %s@%s:%d: %w", c.config.User, c.config.Host, c.config.Port, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conn, err := grpc.NewClient(
|
conn, err := grpc.NewClient(
|
||||||
"unix://"+c.config.APISockPath,
|
"unix://"+c.config.APISockPath,
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ type MachineConnection struct {
|
|||||||
PublicKey secret.Secret `toml:"public_key,omitempty"`
|
PublicKey secret.Secret `toml:"public_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SSHDestination represents an SSH destination string in the canonical form of "user@host:port".
|
||||||
|
// The default user "root" and port 22 can be omitted.
|
||||||
type SSHDestination string
|
type SSHDestination string
|
||||||
|
|
||||||
func NewSSHDestination(user, host string, port int) SSHDestination {
|
func NewSSHDestination(user, host string, port int) SSHDestination {
|
||||||
@@ -37,10 +39,16 @@ func (d SSHDestination) Parse() (user string, host string, port int, err error)
|
|||||||
if strings.Contains(host, "@") {
|
if strings.Contains(host, "@") {
|
||||||
user, host, _ = strings.Cut(host, "@")
|
user, host, _ = strings.Cut(host, "@")
|
||||||
}
|
}
|
||||||
|
if user == "" {
|
||||||
|
user = DefaultSSHUser
|
||||||
|
}
|
||||||
h, p, sErr := net.SplitHostPort(host)
|
h, p, sErr := net.SplitHostPort(host)
|
||||||
if sErr == nil {
|
if sErr == nil {
|
||||||
host = h
|
host = h
|
||||||
port, err = strconv.Atoi(p)
|
port, err = strconv.Atoi(p)
|
||||||
}
|
}
|
||||||
|
if port == 0 {
|
||||||
|
port = DefaultSSHPort
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user