run install.sh script when initialising a cluster on the init machine

This commit is contained in:
Pavel Sviderski
2024-09-21 00:43:33 +10:00
parent 18d5680863
commit d735d568b3
4 changed files with 88 additions and 9 deletions
+14 -9
View File
@@ -132,13 +132,17 @@ func (cli *CLI) InitCluster(
func (cli *CLI) initRemoteMachine(
ctx context.Context, remoteMachine RemoteMachine, clusterName, machineName string, netPrefix netip.Prefix,
) error {
sshConfig := &connector.SSHConnectorConfig{
User: remoteMachine.User,
Host: remoteMachine.Host,
Port: remoteMachine.Port,
KeyPath: remoteMachine.KeyPath,
// Create a command executor and a machine API client over the SSH connection to the remote machine.
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,
)
}
c, err := client.New(ctx, connector.NewSSHConnector(sshConfig))
exec := sshexec.NewRemote(sshClient)
c, err := client.New(ctx, connector.NewSSHConnectorFromClient(sshClient))
if err != nil {
return fmt.Errorf("connect to remote machine: %w", err)
}
@@ -157,9 +161,10 @@ func (cli *CLI) initRemoteMachine(
return fmt.Errorf("generate cluster user: %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.
// TODO: Check if the machine is already provisioned and ask the user to reset it first.
// Install and run the Uncloud daemon and dependencies on the remote machine.
if err = provisionMachine(ctx, exec); err != nil {
return fmt.Errorf("provision machine: %w", err)
}
req := &pb.InitClusterRequest{
MachineName: machineName,
+40
View File
@@ -1,8 +1,48 @@
package cli
import (
"context"
"fmt"
"os"
"uncloud/internal/sshexec"
)
// TODO: support pinning the script version to the CLI version.
const installScriptURL = "https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/install.sh"
type RemoteMachine struct {
User string
Host string
Port int
KeyPath string
}
// provisionMachine provisions the remote machine by downloading the Uncloud install script from GitHub and running it.
func provisionMachine(ctx context.Context, exec sshexec.Executor) error {
// TODO: Check if the machine is already provisioned and ask the user to reset it first.
user, err := exec.Run(ctx, "whoami")
if err != nil {
return fmt.Errorf("run whoami: %w", err)
}
sudoPrefix, env := "", ""
if user != "root" {
sudoPrefix = "sudo"
// Add the SSH user (non-root) to the uncloud group to allow access to the Uncloud daemon unix socket.
env = "UNCLOUD_GROUP_ADD_USER=" + user
}
fmt.Println("Downloading Uncloud install script:", installScriptURL)
curlBashCmd := fmt.Sprintf(
"curl -fsSL %s | %s %s bash", sshexec.Quote(installScriptURL), sudoPrefix, sshexec.Quote(env),
)
cmd := sshexec.QuoteCommand("bash", "-c", "set -o pipefail; "+curlBashCmd)
// TODO: figure out why sometimes the output of `docker version` within the script is intermixed with other
// script output. Note, that the same behavior is observed when using exec.Run but not when running the script
// using ssh CLI. Requesting a pseudo-terminal may help fix this issue:
// session.RequestPty("xterm", 40, 80, ssh.TerminalModes{})
if err = exec.Stream(ctx, cmd, os.Stdout, os.Stderr); err != nil {
return fmt.Errorf("download and run install script: %w", err)
}
return nil
}