-
Notifications
You must be signed in to change notification settings - Fork 40
Expand file tree
/
Copy pathrescue.go
More file actions
139 lines (116 loc) · 4.07 KB
/
Copy pathrescue.go
File metadata and controls
139 lines (116 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package rescue
import (
"context"
"fmt"
"github.com/stackitcloud/stackit-cli/internal/pkg/types"
iaas "github.com/stackitcloud/stackit-sdk-go/services/iaas/v2api"
"github.com/stackitcloud/stackit-sdk-go/services/iaas/v2api/wait"
"github.com/stackitcloud/stackit-cli/internal/pkg/args"
"github.com/stackitcloud/stackit-cli/internal/pkg/errors"
"github.com/stackitcloud/stackit-cli/internal/pkg/examples"
"github.com/stackitcloud/stackit-cli/internal/pkg/flags"
"github.com/stackitcloud/stackit-cli/internal/pkg/globalflags"
"github.com/stackitcloud/stackit-cli/internal/pkg/print"
"github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/client"
iaasUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/iaas/utils"
"github.com/stackitcloud/stackit-cli/internal/pkg/spinner"
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
"github.com/spf13/cobra"
)
const (
serverIdArg = "SERVER_ID"
imageIdFlag = "image-id"
)
type inputModel struct {
*globalflags.GlobalFlagModel
ServerId string
ImageId string
}
func NewCmd(params *types.CmdParams) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("rescue %s", serverIdArg),
Short: "Rescues an existing server",
Long: "Rescues an existing server.",
Args: args.SingleArg(serverIdArg, utils.ValidateUUID),
Example: examples.Build(
examples.NewExample(
`Rescue an existing server with ID "xxx" using image with ID "yyy" as boot volume`,
"$ stackit server rescue xxx --image-id yyy",
),
),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.Background()
model, err := parseInput(params.Printer, cmd, args)
if err != nil {
return err
}
// Configure API client
apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion)
if err != nil {
return err
}
serverLabel, err := iaasUtils.GetServerName(ctx, apiClient.DefaultAPI, model.ProjectId, model.Region, model.ServerId)
if err != nil {
params.Printer.Debug(print.ErrorLevel, "get server name: %v", err)
serverLabel = model.ServerId
} else if serverLabel == "" {
serverLabel = model.ServerId
}
prompt := fmt.Sprintf("Are you sure you want to rescue server %q?", serverLabel)
err = params.Printer.PromptForConfirmation(prompt)
if err != nil {
return err
}
// Call API
req := buildRequest(ctx, model, apiClient)
err = req.Execute()
if err != nil {
return fmt.Errorf("server rescue: %w", err)
}
// Wait for async operation, if async mode not enabled
if !model.Async {
err := spinner.Run(params.Printer, "Rescuing server", func() error {
_, err = wait.RescueServerWaitHandler(ctx, apiClient.DefaultAPI, model.ProjectId, model.Region, model.ServerId).WaitWithContext(ctx)
return err
})
if err != nil {
return fmt.Errorf("wait for server rescuing: %w", err)
}
}
operationState := "Rescued"
if model.Async {
operationState = "Triggered rescue of"
}
params.Printer.Info("%s server %q. Image %q is used as temporary boot image\n", operationState, serverLabel, model.ImageId)
return nil
},
}
configureFlags(cmd)
return cmd
}
func configureFlags(cmd *cobra.Command) {
cmd.Flags().Var(flags.UUIDFlag(), imageIdFlag, "The image ID to be used for a temporary boot volume.")
err := flags.MarkFlagsRequired(cmd, imageIdFlag)
cobra.CheckErr(err)
}
func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) {
serverId := inputArgs[0]
globalFlags := globalflags.Parse(p, cmd)
if globalFlags.ProjectId == "" {
return nil, &errors.ProjectIdError{}
}
model := inputModel{
GlobalFlagModel: globalFlags,
ServerId: serverId,
ImageId: flags.FlagToStringValue(p, cmd, imageIdFlag),
}
p.DebugInputModel(model)
return &model, nil
}
func buildRequest(ctx context.Context, model *inputModel, apiClient *iaas.APIClient) iaas.ApiRescueServerRequest {
req := apiClient.DefaultAPI.RescueServer(ctx, model.ProjectId, model.Region, model.ServerId)
payload := iaas.RescueServerPayload{
Image: model.ImageId,
}
return req.RescueServerPayload(payload)
}