Skip to content

Commit 141dcf7

Browse files
committed
Merge pull request #228 from QuentinPerez/show-boot
Support scw run --show-boot
2 parents 32a7e0f + 5c6a3f2 commit 141dcf7

File tree

8 files changed

+152
-47
lines changed

8 files changed

+152
-47
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,8 @@ $ scw inspect myserver | jq '.[0].public_ip.address'
11321132

11331133
### master (unreleased)
11341134

1135+
* Update gotty-client to 1.3.0
1136+
* Support of `scw run --show-boot` option ([#156](https://github.com/scaleway/scaleway-cli/issues/156))
11351137
* Remove go1.[34] support
11361138
* Update gotty-client to 1.2.0
11371139
* Improve _cs format ([#223](https://github.com/scaleway/scaleway-cli/issues/223))

pkg/cli/cmd_run.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ func init() {
4141
cmdRun.Flag.StringVar(&runGateway, []string{"g", "-gateway"}, "", "Use a SSH gateway")
4242
cmdRun.Flag.BoolVar(&runAutoRemove, []string{"-rm"}, false, "Automatically remove the server when it exits")
4343
cmdRun.Flag.BoolVar(&runTmpSSHKey, []string{"-tmp-ssh-key"}, false, "Access your server without uploading your SSH key to your account")
44+
cmdRun.Flag.BoolVar(&runShowBoot, []string{"-show-boot"}, false, "Allows to show the boot")
4445
// FIXME: handle start --timeout
4546
}
4647

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

5961
func runRun(cmd *Command, rawArgs []string) error {
6062
if runHelpFlag {
@@ -69,6 +71,15 @@ func runRun(cmd *Command, rawArgs []string) error {
6971
if runAttachFlag && runDetachFlag {
7072
return fmt.Errorf("conflicting options: -a and -d")
7173
}
74+
if runAttachFlag && runShowBoot {
75+
return fmt.Errorf("conflicting options: -a and --show-boot")
76+
}
77+
if runShowBoot && len(rawArgs) > 1 {
78+
return fmt.Errorf("conflicting options: --show-boot and COMMAND")
79+
}
80+
if runShowBoot && runDetachFlag {
81+
return fmt.Errorf("conflicting options: --show-boot and -d")
82+
}
7283
if runDetachFlag && len(rawArgs) > 1 {
7384
return fmt.Errorf("conflicting options: -d and COMMAND")
7485
}
@@ -86,6 +97,7 @@ func runRun(cmd *Command, rawArgs []string) error {
8697
Name: runCreateName,
8798
AutoRemove: runAutoRemove,
8899
TmpSSHKey: runTmpSSHKey,
100+
ShowBoot: runShowBoot,
89101
// FIXME: DynamicIPRequired
90102
// FIXME: Timeout
91103
}

pkg/commands/attach.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,10 @@ type AttachArgs struct {
1616
func RunAttach(ctx CommandContext, args AttachArgs) error {
1717
serverID := ctx.API.GetServerID(args.Server)
1818

19-
return utils.AttachToSerial(serverID, ctx.API.Token, !args.NoStdin)
19+
_, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
20+
if err != nil {
21+
return err
22+
}
23+
<-done
24+
return nil
2025
}

pkg/commands/run.go

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type RunArgs struct {
3030
Volumes []string
3131
AutoRemove bool
3232
TmpSSHKey bool
33+
ShowBoot bool
3334
// DynamicIPRequired
3435
// Timeout
3536
}
@@ -103,47 +104,99 @@ func Run(ctx CommandContext, args RunArgs) error {
103104
if args.Detach {
104105
fmt.Fprintln(ctx.Stdout, serverID)
105106
return nil
106-
} else {
107-
// Sync cache on disk
108-
ctx.API.Sync()
109107
}
108+
// Sync cache on disk
109+
ctx.API.Sync()
110110

111-
if args.Attach {
111+
if args.ShowBoot {
112112
// Attach to server serial
113113
logrus.Info("Attaching to server console ...")
114-
err = utils.AttachToSerial(serverID, ctx.API.Token, true)
114+
gottycli, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
115115
if err != nil {
116116
return fmt.Errorf("cannot attach to server serial: %v", err)
117117
}
118-
} else {
119-
// Resolve gateway
120-
gateway, err := api.ResolveGateway(ctx.API, args.Gateway)
118+
utils.Quiet(true)
119+
notif, gateway, err := waitSSHConnection(ctx, args, serverID)
121120
if err != nil {
122-
return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
121+
return err
123122
}
124-
125-
// waiting for server to be ready
126-
logrus.Debug("Waiting for server to be ready")
127-
// We wait for 30 seconds, which is the minimal amount of time needed by a server to boot
128-
server, err := api.WaitForServerReady(ctx.API, serverID, gateway)
123+
sshConnection := <-notif
124+
gottycli.ExitLoop()
125+
<-done
126+
utils.Quiet(false)
127+
if sshConnection.err != nil {
128+
return sshConnection.err
129+
}
130+
server := sshConnection.server
131+
logrus.Info("Connecting to server ...")
132+
if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil {
133+
return fmt.Errorf("Connection to server failed: %v", err)
134+
}
135+
} else if args.Attach {
136+
// Attach to server serial
137+
logrus.Info("Attaching to server console ...")
138+
gottycli, done, err := utils.AttachToSerial(serverID, ctx.API.Token)
129139
if err != nil {
130-
return fmt.Errorf("cannot get access to server %s: %v", serverID, err)
140+
return fmt.Errorf("cannot attach to server serial: %v", err)
131141
}
132-
logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP)
133-
logrus.Info("Server is ready !")
134-
142+
<-done
143+
gottycli.Close()
144+
} else {
145+
notif, gateway, err := waitSSHConnection(ctx, args, serverID)
146+
if err != nil {
147+
return err
148+
}
149+
sshConnection := <-notif
150+
if sshConnection.err != nil {
151+
return sshConnection.err
152+
}
153+
server := sshConnection.server
135154
// exec -w SERVER COMMAND ARGS...
136155
if len(args.Command) < 1 {
137156
logrus.Info("Connecting to server ...")
138-
err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway)
157+
if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway); err != nil {
158+
return fmt.Errorf("Connection to server failed: %v", err)
159+
}
139160
} else {
140161
logrus.Infof("Executing command: %s ...", args.Command)
141-
err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway)
142-
}
143-
if err != nil {
144-
return fmt.Errorf("command execution failed: %v", err)
162+
if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway); err != nil {
163+
return fmt.Errorf("command execution failed: %v", err)
164+
}
165+
logrus.Info("Command successfuly executed")
145166
}
146-
logrus.Info("Command successfuly executed")
147167
}
148168
return nil
149169
}
170+
171+
type notifSSHConnection struct {
172+
server *api.ScalewayServer
173+
err error
174+
}
175+
176+
func waitSSHConnection(ctx CommandContext, args RunArgs, serverID string) (chan notifSSHConnection, string, error) {
177+
notif := make(chan notifSSHConnection)
178+
// Resolve gateway
179+
gateway, err := api.ResolveGateway(ctx.API, args.Gateway)
180+
if err != nil {
181+
return nil, "", fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err)
182+
}
183+
184+
// waiting for server to be ready
185+
logrus.Debug("Waiting for server to be ready")
186+
// We wait for 30 seconds, which is the minimal amount of time needed by a server to boot
187+
go func() {
188+
server, err := api.WaitForServerReady(ctx.API, serverID, gateway)
189+
if err != nil {
190+
notif <- notifSSHConnection{
191+
err: fmt.Errorf("cannot get access to server %s: %v", serverID, err),
192+
}
193+
return
194+
}
195+
logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP)
196+
logrus.Info("Server is ready !")
197+
notif <- notifSSHConnection{
198+
server: server,
199+
}
200+
}()
201+
return notif, gateway, nil
202+
}

pkg/utils/utils.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,26 @@ func RemoveDuplicates(elements []string) []string {
182182
}
183183

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

188188
logrus.Debug("Connection to ", URL)
189189
gottycli, err := gottyclient.NewClient(URL)
190190
if err != nil {
191-
return err
191+
return nil, nil, err
192192
}
193+
if err = gottycli.Connect(); err != nil {
194+
return nil, nil, err
195+
}
196+
done := make(chan bool)
197+
193198
fmt.Println("You are connected, type 'Ctrl+q' to quit.")
194-
return gottycli.Loop()
199+
go func() {
200+
gottycli.Loop()
201+
gottycli.Close()
202+
done <- true
203+
}()
204+
return gottycli, done, nil
195205
}
196206

197207
func SSHGetFingerprint(key string) (string, error) {

vendor/github.com/moul/gotty-client/README.md

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
-8.22 MB
Binary file not shown.

vendor/github.com/moul/gotty-client/gotty-client.go

Lines changed: 34 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)