Skip to content

Commit 8934e97

Browse files
committed
feat(server): add wait flag to create and stop commands
1 parent fd87a41 commit 8934e97

5 files changed

Lines changed: 45 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99
### Added
1010
- Add `zone list` command that lists available zones.
11+
- Add `--wait` flag to `server create` and `server stop` commands to wait until server is in `started` and `stopped` state, respectively.
1112

1213
### Fixed
1314
- Do not display usage if execution fails because of missing credentials

internal/commands/server/create.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ func CreateCommand() commands.Command {
3030
"create",
3131
"Create a server",
3232
"upctl server create --title myapp --zone fi-hel1 --hostname myapp --password-delivery email",
33+
"upctl server create --wait --title myapp --zone fi-hel1 --hostname myapp --password-delivery email",
3334
"upctl server create --title \"My Server\" --zone fi-hel1 --hostname myapp --password-delivery email",
3435
"upctl server create --zone fi-hel1 --hostname myapp --password-delivery email --plan 2xCPU-4GB",
3536
"upctl server create --zone fi-hel1 --hostname myapp --password-delivery email --plan custom --cores 2 --memory 4096",
@@ -243,6 +244,7 @@ type createCommand struct {
243244
metadata config.OptionalBoolean
244245
remoteAccess config.OptionalBoolean
245246
createPassword config.OptionalBoolean
247+
wait config.OptionalBoolean
246248
}
247249

248250
// InitCommand implements Command.InitCommand
@@ -275,6 +277,7 @@ func (s *createCommand) InitCommand() {
275277
fs.StringVar(&s.params.UserData, "user-data", def.UserData, "Defines URL for a server setup script, or the script body itself.")
276278
fs.StringVar(&s.params.username, "username", def.username, "Admin account username.")
277279
fs.StringVar(&s.params.VideoModel, "video-model", def.VideoModel, "Video interface model of the server. Available: vga, cirrus")
280+
config.AddToggleFlag(fs, &s.wait, "wait", false, "Wait for server to be in started state before returning.")
278281
fs.StringVar(&s.params.Zone, "zone", def.Zone, "Zone where to create the server.")
279282
// fs.BoolVar(&s.params.firewall, "firewall", def.firewall, "Enables the firewall. You can manage firewall rules with the firewall command.")
280283
// fs.BoolVar(&s.params.metadata, "metadata", def.metadata, "Enable metadata service.")
@@ -369,6 +372,13 @@ func (s *createCommand) ExecuteWithoutArguments(exec commands.Executor) (output.
369372
logline.SetMessage(fmt.Sprintf("%s: request sent", msg))
370373
logline.MarkDone()
371374

375+
if s.wait.Value() {
376+
logline := exec.NewLogEntry(msg)
377+
if err := waitForServerState(res.UUID, upcloud.ServerStateStarted, serverSvc, logline); err != nil {
378+
return nil, err
379+
}
380+
}
381+
372382
return output.MarshaledWithHumanDetails{Value: res, Details: []output.DetailRow{
373383
{Title: "UUID", Value: res.UUID, Colour: ui.DefaultUUUIDColours},
374384
{Title: "IP Addresses", Value: res, Format: formatIPAddresses},

internal/commands/server/server.go

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package server
22

33
import (
4+
"fmt"
45
"time"
56

67
"github.com/UpCloudLtd/upcloud-cli/internal/commands"
8+
"github.com/UpCloudLtd/upcloud-cli/internal/ui"
79
"github.com/UpCloudLtd/upcloud-go-api/v4/upcloud/request"
10+
"github.com/UpCloudLtd/upcloud-go-api/v4/upcloud/service"
811
)
912

1013
const (
@@ -28,20 +31,23 @@ type serverCommand struct {
2831
*commands.BaseCommand
2932
}
3033

31-
// TODO: re-add when wait flag is refactored
32-
/*func serverStateWaiter(uuid, state, msg string, service service.Server, logline *ui.LogEntry) func() error {
33-
return func() error {
34-
for {
35-
time.Sleep(100 * time.Millisecond)
36-
details, err := service.GetServerDetails(&request.GetServerDetailsRequest{UUID: uuid})
37-
if err != nil {
38-
return err
39-
}
40-
if details.State == state {
41-
return nil
42-
}
43-
logline.SetMessage(fmt.Sprintf("%s: waiting to start (%v)", msg, details.State))
44-
}
34+
func waitForServerState(uuid, state string, service service.Server, logline *ui.LogEntry) error {
35+
msg := fmt.Sprintf("Waiting for server %s to be in %s state", uuid, state)
36+
logline.SetMessage(fmt.Sprintf("%s: polling", msg))
37+
logline.StartedNow()
38+
39+
if _, err := service.WaitForServerState(&request.WaitForServerStateRequest{
40+
UUID: uuid,
41+
DesiredState: state,
42+
Timeout: 5 * time.Minute,
43+
}); err != nil {
44+
logline.SetMessage(ui.LiveLogEntryErrorColours.Sprintf("%s: failed (%v)", msg, err.Error()))
45+
logline.SetDetails(err.Error(), "error: ")
46+
return err
4547
}
48+
49+
logline.SetMessage(fmt.Sprintf("%s: done", msg))
50+
logline.MarkDone()
51+
52+
return nil
4653
}
47-
*/

internal/commands/server/start.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func (s *startCommand) Execute(exec commands.Executor, uuid string) (output.Outp
5353
return nil, err
5454
}
5555

56-
logline.SetMessage(fmt.Sprintf("%s: request sent", msg))
56+
logline.SetMessage(fmt.Sprintf("%s: done", msg))
5757
logline.MarkDone()
5858

5959
return output.OnlyMarshaled{Value: res}, nil

internal/commands/server/stop.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55

66
"github.com/UpCloudLtd/upcloud-cli/internal/commands"
77
"github.com/UpCloudLtd/upcloud-cli/internal/completion"
8+
"github.com/UpCloudLtd/upcloud-cli/internal/config"
89
"github.com/UpCloudLtd/upcloud-cli/internal/output"
910
"github.com/UpCloudLtd/upcloud-cli/internal/resolver"
1011
"github.com/UpCloudLtd/upcloud-cli/internal/ui"
1112

13+
"github.com/UpCloudLtd/upcloud-go-api/v4/upcloud"
1214
"github.com/UpCloudLtd/upcloud-go-api/v4/upcloud/request"
1315
"github.com/spf13/pflag"
1416
)
@@ -22,13 +24,15 @@ func StopCommand() commands.Command {
2224
"upctl server stop 00cbe2f3-4cf9-408b-afee-bd340e13cdd8",
2325
"upctl server stop 00cbe2f3-4cf9-408b-afee-bd340e13cdd8 0053a6f5-e6d1-4b0b-b9dc-b90d0894e8d0",
2426
"upctl server stop my_server",
27+
"upctl server stop --wait my_server",
2528
),
2629
}
2730
}
2831

2932
type stopCommand struct {
3033
*commands.BaseCommand
3134
StopType string
35+
wait config.OptionalBoolean
3236
resolver.CachingServer
3337
completion.Server
3438
}
@@ -38,6 +42,7 @@ func (s *stopCommand) InitCommand() {
3842
//XXX: findout what to do with risky params (timeout actions)
3943
flags := &pflag.FlagSet{}
4044
flags.StringVar(&s.StopType, "type", defaultStopType, "The type of stop operation. Available: soft, hard")
45+
config.AddToggleFlag(flags, &s.wait, "wait", false, "Wait for server to be in stopped state before returning.")
4146
s.AddFlags(flags)
4247
}
4348

@@ -63,5 +68,12 @@ func (s *stopCommand) Execute(exec commands.Executor, uuid string) (output.Outpu
6368
logline.SetMessage(fmt.Sprintf("%s: request sent", msg))
6469
logline.MarkDone()
6570

71+
if s.wait.Value() {
72+
logline := exec.NewLogEntry(msg)
73+
if err := waitForServerState(uuid, upcloud.ServerStateStopped, svc, logline); err != nil {
74+
return nil, err
75+
}
76+
}
77+
6678
return output.OnlyMarshaled{Value: res}, nil
6779
}

0 commit comments

Comments
 (0)