Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,8 @@ $ scw inspect myserver | jq '.[0].public_ip.address'

### master (unreleased)

* Update gotty-client to 1.3.0
* Support of `scw run --show-boot` option ([#156](https://github.com/scaleway/scaleway-cli/issues/156))
* Remove go1.[34] support
* Update gotty-client to 1.2.0
* Improve _cs format ([#223](https://github.com/scaleway/scaleway-cli/issues/223))
Expand Down
12 changes: 12 additions & 0 deletions pkg/cli/cmd_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func init() {
cmdRun.Flag.StringVar(&runGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway")
cmdRun.Flag.BoolVar(&runAutoRemove, []string{"-rm"}, false, "Automatically remove the server when it exits")
cmdRun.Flag.BoolVar(&runTmpSSHKey, []string{"-tmp-ssh-key"}, false, "Access your server without uploading your SSH key to your account")
cmdRun.Flag.BoolVar(&runShowBoot, []string{"-show-boot"}, false, "Allows to show the boot")
// FIXME: handle start --timeout
}

Expand All @@ -55,6 +56,7 @@ var runAttachFlag bool // -a, --attach flag
var runDetachFlag bool // -d, --detach flag
var runGateway string // -g, --gateway flag
var runTmpSSHKey bool // --tmp-ssh-key flag
var runShowBoot bool // --show-boot flag

func runRun(cmd *Command, rawArgs []string) error {
if runHelpFlag {
Expand All @@ -69,6 +71,15 @@ func runRun(cmd *Command, rawArgs []string) error {
if runAttachFlag && runDetachFlag {
return fmt.Errorf("conflicting options: -a and -d")
}
if runAttachFlag && runShowBoot {
return fmt.Errorf("conflicting options: -a and --show-boot")
}
if runShowBoot && len(rawArgs) > 1 {
return fmt.Errorf("conflicting options: --show-boot and COMMAND")
}
if runShowBoot && runDetachFlag {
return fmt.Errorf("conflicting options: --show-boot and -d")
}
if runDetachFlag && len(rawArgs) > 1 {
return fmt.Errorf("conflicting options: -d and COMMAND")
}
Expand All @@ -86,6 +97,7 @@ func runRun(cmd *Command, rawArgs []string) error {
Name: runCreateName,
AutoRemove: runAutoRemove,
TmpSSHKey: runTmpSSHKey,
ShowBoot: runShowBoot,
// FIXME: DynamicIPRequired
// FIXME: Timeout
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/commands/attach.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ type AttachArgs struct {
func RunAttach(ctx CommandContext, args AttachArgs) error {
serverID := ctx.API.GetServerID(args.Server)

return utils.AttachToSerial(serverID, ctx.API.Token, !args.NoStdin)
_, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
if err != nil {
return err
}
<-done
return nil
}
101 changes: 77 additions & 24 deletions pkg/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type RunArgs struct {
Volumes []string
AutoRemove bool
TmpSSHKey bool
ShowBoot bool
// DynamicIPRequired
// Timeout
}
Expand Down Expand Up @@ -103,47 +104,99 @@ func Run(ctx CommandContext, args RunArgs) error {
if args.Detach {
fmt.Fprintln(ctx.Stdout, serverID)
return nil
} else {
// Sync cache on disk
ctx.API.Sync()
}
// Sync cache on disk
ctx.API.Sync()

if args.Attach {
if args.ShowBoot {
// Attach to server serial
logrus.Info("Attaching to server console ...")
err = utils.AttachToSerial(serverID, ctx.API.Token, true)
gottycli, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
if err != nil {
return fmt.Errorf("cannot attach to server serial: %v", err)
}
} else {
// Resolve gateway
gateway, err := api.ResolveGateway(ctx.API, args.Gateway)
utils.Quiet(true)
notif, gateway, err := waitSSHConnection(ctx, args, serverID)
if err != nil {
return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
return err
}

// waiting for server to be ready
logrus.Debug("Waiting for server to be ready")
// We wait for 30 seconds, which is the minimal amount of time needed by a server to boot
server, err := api.WaitForServerReady(ctx.API, serverID, gateway)
sshConnection := <-notif
gottycli.ExitLoop()
<-done
utils.Quiet(false)
if sshConnection.err != nil {
return sshConnection.err
}
server := sshConnection.server
logrus.Info("Connecting to server ...")
if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil {
return fmt.Errorf("Connection to server failed: %v", err)
}
} else if args.Attach {
// Attach to server serial
logrus.Info("Attaching to server console ...")
gottycli, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
if err != nil {
return fmt.Errorf("cannot get access to server %s: %v", serverID, err)
return fmt.Errorf("cannot attach to server serial: %v", err)
}
logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP)
logrus.Info("Server is ready !")

<-done
gottycli.Close()
} else {
notif, gateway, err := waitSSHConnection(ctx, args, serverID)
if err != nil {
return err
}
sshConnection := <-notif
if sshConnection.err != nil {
return sshConnection.err
}
server := sshConnection.server
// exec -w SERVER COMMAND ARGS...
if len(args.Command) < 1 {
logrus.Info("Connecting to server ...")
err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway)
if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil {
return fmt.Errorf("Connection to server failed: %v", err)
}
} else {
logrus.Infof("Executing command: %s ...", args.Command)
err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway)
}
if err != nil {
return fmt.Errorf("command execution failed: %v", err)
if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway); err != nil {
return fmt.Errorf("command execution failed: %v", err)
}
logrus.Info("Command successfuly executed")
}
logrus.Info("Command successfuly executed")
}
return nil
}

type notifSSHConnection struct {
server *api.ScalewayServer
err error
}

func waitSSHConnection(ctx CommandContext, args RunArgs, serverID string) (chan notifSSHConnection, string, error) {
notif := make(chan notifSSHConnection)
// Resolve gateway
gateway, err := api.ResolveGateway(ctx.API, args.Gateway)
if err != nil {
return nil, "", fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
}

// waiting for server to be ready
logrus.Debug("Waiting for server to be ready")
// We wait for 30 seconds, which is the minimal amount of time needed by a server to boot
go func() {
server, err := api.WaitForServerReady(ctx.API, serverID, gateway)
if err != nil {
notif <- notifSSHConnection{
err: fmt.Errorf("cannot get access to server %s: %v", serverID, err),
}
return
}
logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP)
logrus.Info("Server is ready !")
notif <- notifSSHConnection{
server: server,
}
}()
return notif, gateway, nil
}
16 changes: 13 additions & 3 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,26 @@ func RemoveDuplicates(elements []string) []string {
}

// AttachToSerial tries to connect to server serial using 'gotty-client' and fallback with a help message
func AttachToSerial(serverID string, apiToken string, attachStdin bool) error {
func AttachToSerial(serverID string, apiToken string) (*gottyclient.Client, chan bool, error) {
URL := fmt.Sprintf("https://tty.scaleway.com/v2/?arg=%s&arg=%s", apiToken, serverID)

logrus.Debug("Connection to ", URL)
gottycli, err := gottyclient.NewClient(URL)
if err != nil {
return err
return nil, nil, err
}
if err = gottycli.Connect(); err != nil {
return nil, nil, err
}
done := make(chan bool)

fmt.Println("You are connected, type 'Ctrl+q' to quit.")
return gottycli.Loop()
go func() {
gottycli.Loop()
gottycli.Close()
done <- true
}()
return gottycli, done, nil
}

func SSHGetFingerprint(key string) (string, error) {
Expand Down
9 changes: 8 additions & 1 deletion vendor/github.com/moul/gotty-client/README.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file removed vendor/github.com/moul/gotty-client/gotty-client
Binary file not shown.
52 changes: 34 additions & 18 deletions vendor/github.com/moul/gotty-client/gotty-client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.