Skip to content

Commit 813fff2

Browse files
feat(cli): add multi lifecycle operations
Signed-off-by: Yaroslav Borbat <yaroslav.borbat@flant.com>
1 parent 5b6108a commit 813fff2

6 files changed

Lines changed: 93 additions & 29 deletions

File tree

src/cli/internal/cmd/lifecycle/evict.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ func NewEvictCommand() *cobra.Command {
2828
Use: "evict (VirtualMachine)",
2929
Short: "Evict a virtual machine.",
3030
Example: lifecycle.Usage(),
31-
Args: templates.ExactArgs("evict", 1),
3231
RunE: lifecycle.Run,
3332
}
3433
AddCommandLineArgs(cmd.Flags(), &lifecycle.opts)

src/cli/internal/cmd/lifecycle/lifecycle.go

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type Options struct {
9090
Force bool
9191
WaitComplete bool
9292
CreateOnly bool
93+
All bool
9394
Timeout time.Duration
9495
}
9596

@@ -102,40 +103,79 @@ func (l *Lifecycle) Run(cmd *cobra.Command, args []string) error {
102103
if err != nil {
103104
return err
104105
}
105-
name, namespace, err := l.getNameNamespace(defaultNamespace, args)
106-
key := types.NamespacedName{Namespace: namespace, Name: name}
107-
if err != nil {
108-
return err
106+
107+
if len(args) > 0 && l.opts.All {
108+
return fmt.Errorf("cannot use --all flag with specific keys")
109+
}
110+
111+
var keys []types.NamespacedName
112+
if l.opts.All {
113+
keys, err = l.getVirtualMachines(cmd.Context(), defaultNamespace, client)
114+
if err != nil {
115+
return fmt.Errorf("failed to get virtual machines in namespace %q: %w", defaultNamespace, err)
116+
}
117+
} else {
118+
keys, err = l.getNamespacedNames(defaultNamespace, args)
119+
if err != nil {
120+
return fmt.Errorf("failed to parse keys: %w", err)
121+
}
122+
}
123+
124+
if len(keys) == 0 {
125+
return fmt.Errorf("no one virtual machine found for execute command")
109126
}
127+
110128
forceSet := cmd.Flags().Changed(forceFlag)
111-
mgr := l.getManager(client, forceSet)
129+
mgr := l.getManager(client, forceSet, len(keys) > 1)
112130

113131
ctx, cancel := context.WithTimeout(context.Background(), l.opts.Timeout)
114132
defer cancel()
115-
var msg string
133+
116134
switch l.cmd {
117135
case Stop:
118-
cmd.Printf("Stopping virtual machine %q\n", key.String())
119-
msg, err = mgr.Stop(ctx, name, namespace)
136+
for _, key := range keys {
137+
cmd.Printf("Stopping virtual machine %q\n", key.String())
138+
msg, err := mgr.Stop(ctx, key.Name, key.Namespace)
139+
l.handleMsgError(cmd, msg, err)
140+
}
120141
case Start:
121-
cmd.Printf("Starting virtual machine %q\n", key.String())
122-
msg, err = mgr.Start(ctx, name, namespace)
142+
for _, key := range keys {
143+
cmd.Printf("Starting virtual machine %q\n", key.String())
144+
msg, err := mgr.Start(ctx, key.Name, key.Namespace)
145+
l.handleMsgError(cmd, msg, err)
146+
}
123147
case Restart:
124-
cmd.Printf("Restarting virtual machine %q\n", key.String())
125-
msg, err = mgr.Restart(ctx, name, namespace)
148+
for _, key := range keys {
149+
cmd.Printf("Restarting virtual machine %q\n", key.String())
150+
msg, err := mgr.Restart(ctx, key.Name, key.Namespace)
151+
l.handleMsgError(cmd, msg, err)
152+
}
126153
case Evict:
127-
cmd.Printf("Evicting virtual machine %q\n", key.String())
128-
msg, err = mgr.Evict(ctx, name, namespace)
154+
for _, key := range keys {
155+
cmd.Printf("Evicting virtual machine %q\n", key.String())
156+
msg, err := mgr.Evict(ctx, key.Name, key.Namespace)
157+
l.handleMsgError(cmd, msg, err)
158+
}
129159
case Migrate:
130-
cmd.Printf("Migrating virtual machine %q\n", key.String())
131-
msg, err = mgr.Migrate(ctx, name, namespace, l.migrationOpts.TargetNodeName)
160+
for _, key := range keys {
161+
cmd.Printf("Migrating virtual machine %q\n", key.String())
162+
msg, err := mgr.Migrate(ctx, key.Name, key.Namespace, l.migrationOpts.TargetNodeName)
163+
l.handleMsgError(cmd, msg, err)
164+
}
132165
default:
133166
return fmt.Errorf("invalid command %q", l.cmd)
134167
}
168+
169+
return nil
170+
}
171+
172+
func (l *Lifecycle) handleMsgError(cmd *cobra.Command, msg string, err error) {
135173
if msg != "" {
136-
cmd.Printf("%s", msg)
174+
cmd.Printf("%s\n", msg)
175+
}
176+
if err != nil {
177+
cmd.Printf("Error: %s\n", err.Error())
137178
}
138-
return err
139179
}
140180

141181
func (l *Lifecycle) Usage() string {
@@ -157,26 +197,52 @@ func (l *Lifecycle) Usage() string {
157197
return usage
158198
}
159199

160-
func (l *Lifecycle) getNameNamespace(defaultNamespace string, args []string) (string, string, error) {
161-
namespace, name, err := templates.ParseTarget(args[0])
200+
func (l *Lifecycle) getNamespacedName(defaultNamespace, arg string) (types.NamespacedName, error) {
201+
namespace, name, err := templates.ParseTarget(arg)
162202
if err != nil {
163-
return "", "", err
203+
return types.NamespacedName{}, err
164204
}
165205
if namespace == "" {
166206
namespace = defaultNamespace
167207
}
168-
return name, namespace, nil
208+
return types.NamespacedName{Namespace: namespace, Name: name}, nil
209+
}
210+
211+
func (l *Lifecycle) getNamespacedNames(defaultNamespace string, args []string) ([]types.NamespacedName, error) {
212+
var keys []types.NamespacedName
213+
for _, arg := range args {
214+
key, err := l.getNamespacedName(defaultNamespace, arg)
215+
if err != nil {
216+
return nil, err
217+
}
218+
keys = append(keys, key)
219+
}
220+
return keys, nil
221+
}
222+
223+
func (l *Lifecycle) getVirtualMachines(ctx context.Context, namespace string, client kubeclient.Client) ([]types.NamespacedName, error) {
224+
vmList, err := client.VirtualMachines(namespace).List(ctx, metav1.ListOptions{})
225+
if err != nil {
226+
return nil, err
227+
}
228+
229+
var keys []types.NamespacedName
230+
for _, vm := range vmList.Items {
231+
keys = append(keys, types.NamespacedName{Namespace: vm.Namespace, Name: vm.Name})
232+
}
233+
234+
return keys, nil
169235
}
170236

171-
func (l *Lifecycle) getManager(client kubeclient.Client, forceSet bool) Manager {
237+
func (l *Lifecycle) getManager(client kubeclient.Client, forceSet bool, severalVms bool) Manager {
172238
var forcePtr *bool
173239
if forceSet {
174240
forcePtr = ptr.To(l.opts.Force)
175241
}
176242

177243
return vmop.New(
178244
client,
179-
vmop.WithCreateOnly(l.opts.CreateOnly),
245+
vmop.WithCreateOnly(l.opts.CreateOnly || severalVms),
180246
vmop.WithWaitComplete(l.opts.WaitComplete),
181247
vmop.WithForce(forcePtr),
182248
)
@@ -219,6 +285,7 @@ const (
219285
forceFlag, forceFlagShort = "force", "f"
220286
waitFlag, waitFlagShort = "wait", "w"
221287
createOnlyFlag, createOnlyFlagShort = "create-only", "c"
288+
allFlag, allFlagShort = "all", "a"
222289
timeoutFlag, timeoutFlagShort = "timeout", "t"
223290
)
224291

@@ -229,6 +296,8 @@ func AddCommandLineArgs(flagset *pflag.FlagSet, opts *Options) {
229296
"Set this flag to wait for the operation to complete.")
230297
flagset.BoolVarP(&opts.CreateOnly, createOnlyFlag, createOnlyFlagShort, opts.CreateOnly,
231298
"Set this flag to only create the action without status warnings or notifications.")
299+
flagset.BoolVarP(&opts.All, allFlag, allFlagShort, opts.All,
300+
"Set this flag to apply the action to all VMs.")
232301
flagset.DurationVarP(&opts.Timeout, timeoutFlag, timeoutFlagShort, opts.Timeout,
233302
"Set this flag to change the timeout.")
234303
}

src/cli/internal/cmd/lifecycle/migrate.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ func NewMigrateCommand() *cobra.Command {
2929
Use: "migrate (VirtualMachine)",
3030
Short: "Migrate a virtual machine.",
3131
Example: lifecycle.Usage(),
32-
Args: templates.ExactArgs("migrate", 1),
3332
PreRunE: func(cmd *cobra.Command, args []string) error {
3433
vmName := args[0]
3534
err := lifecycle.ValidateNodeName(cmd, vmName, lifecycle.migrationOpts.TargetNodeName)

src/cli/internal/cmd/lifecycle/restart.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ func NewRestartCommand() *cobra.Command {
2828
Use: "restart (VirtualMachine)",
2929
Short: "Restart a virtual machine.",
3030
Example: lifecycle.Usage(),
31-
Args: templates.ExactArgs("restart", 1),
3231
RunE: lifecycle.Run,
3332
}
3433
AddCommandLineArgs(cmd.Flags(), &lifecycle.opts)

src/cli/internal/cmd/lifecycle/start.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ func NewStartCommand() *cobra.Command {
2828
Use: "start (VirtualMachine)",
2929
Short: "Start a virtual machine.",
3030
Example: lifecycle.Usage(),
31-
Args: templates.ExactArgs("start", 1),
3231
RunE: lifecycle.Run,
3332
}
3433
AddCommandLineArgs(cmd.Flags(), &lifecycle.opts)

src/cli/internal/cmd/lifecycle/stop.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ func NewStopCommand() *cobra.Command {
2828
Use: "stop (VirtualMachine)",
2929
Short: "Stop a virtual machine.",
3030
Example: lifecycle.Usage(),
31-
Args: templates.ExactArgs("stop", 1),
3231
RunE: lifecycle.Run,
3332
}
3433
AddCommandLineArgs(cmd.Flags(), &lifecycle.opts)

0 commit comments

Comments
 (0)