forked from canonical/lxd
/
action.go
138 lines (111 loc) · 3.19 KB
/
action.go
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
package main
import (
"fmt"
"os"
"strings"
"github.com/lxc/lxd"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
"github.com/lxc/lxd/shared/gnuflag"
"github.com/lxc/lxd/shared/i18n"
)
type actionCmd struct {
action shared.ContainerAction
description string
hasTimeout bool
visible bool
name string
timeout int
force bool
stateful bool
stateless bool
}
func (c *actionCmd) showByDefault() bool {
return c.visible
}
func (c *actionCmd) usage() string {
extra := ""
if c.name == "pause" {
extra = "\n" + i18n.G("The opposite of \"lxc pause\" is \"lxc start\".")
}
return fmt.Sprintf(i18n.G(
`Usage: lxc %s [<remote>:]<container> [[<remote>:]<container>...]
%s%s`), c.name, c.description, extra)
}
func (c *actionCmd) flags() {
if c.hasTimeout {
gnuflag.IntVar(&c.timeout, "timeout", -1, i18n.G("Time to wait for the container before killing it"))
gnuflag.BoolVar(&c.force, "f", false, i18n.G("Force the container to shutdown"))
gnuflag.BoolVar(&c.force, "force", false, i18n.G("Force the container to shutdown"))
}
gnuflag.BoolVar(&c.stateful, "stateful", false, i18n.G("Store the container state (only for stop)"))
gnuflag.BoolVar(&c.stateless, "stateless", false, i18n.G("Ignore the container state (only for start)"))
}
func (c *actionCmd) doAction(config *lxd.Config, nameArg string) error {
state := false
// Only store state if asked to
if c.action == "stop" && c.stateful {
state = true
}
remote, name := config.ParseRemoteAndContainer(nameArg)
d, err := lxd.NewClient(config, remote)
if err != nil {
return err
}
if name == "" {
return fmt.Errorf(i18n.G("Must supply container name for: ")+"\"%s\"", nameArg)
}
if c.action == shared.Start {
current, err := d.ContainerInfo(name)
if err != nil {
return err
}
// "start" for a frozen container means "unfreeze"
if current.StatusCode == api.Frozen {
c.action = shared.Unfreeze
}
// Always restore state (if present) unless asked not to
if c.action == shared.Start && current.Stateful && !c.stateless {
state = true
}
}
resp, err := d.Action(name, c.action, c.timeout, c.force, state)
if err != nil {
return err
}
if resp.Type != api.AsyncResponse {
return fmt.Errorf(i18n.G("bad result type from action"))
}
if err := d.WaitForSuccess(resp.Operation); err != nil {
return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
}
return nil
}
func (c *actionCmd) run(config *lxd.Config, args []string) error {
if len(args) == 0 {
return errArgs
}
// Run the action for every listed container
results := runBatch(args, func(name string) error { return c.doAction(config, name) })
// Single container is easy
if len(results) == 1 {
return results[0].err
}
// Do fancier rendering for batches
success := true
for _, result := range results {
if result.err == nil {
continue
}
success = false
msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
for _, line := range strings.Split(msg, "\n") {
fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
}
}
if !success {
fmt.Fprintln(os.Stderr, "")
return fmt.Errorf(i18n.G("Some containers failed to %s"), c.name)
}
return nil
}