14
"github.com/lxc/lxd/shared"
15
"github.com/lxc/lxd/shared/gnuflag"
16
"github.com/lxc/lxd/shared/i18n"
17
"github.com/lxc/lxd/shared/logging"
23
if err := run(); err != nil {
24
// The action we take depends on the error we get.
25
msg := fmt.Sprintf(i18n.G("error: %v"), err)
26
switch t := err.(type) {
28
switch u := t.Err.(type) {
30
if u.Op == "dial" && u.Net == "unix" {
31
switch errno := u.Err.(type) {
35
msg = i18n.G("LXD socket not found; is LXD running?")
36
case syscall.ECONNREFUSED:
37
msg = i18n.G("Connection refused; is LXD running?")
39
msg = i18n.G("Permisson denied, are you in the lxd group?")
41
msg = fmt.Sprintf("%d %s", uintptr(errno), errno.Error())
48
fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", msg))
54
verbose := gnuflag.Bool("verbose", false, i18n.G("Enables verbose mode."))
55
debug := gnuflag.Bool("debug", false, i18n.G("Enables debug mode."))
56
forceLocal := gnuflag.Bool("force-local", false, i18n.G("Force using the local unix socket."))
57
noAlias := gnuflag.Bool("no-alias", false, i18n.G("Ignore aliases when determining what command to run."))
59
configDir := "$HOME/.config/lxc"
60
if os.Getenv("LXD_CONF") != "" {
61
configDir = os.Getenv("LXD_CONF")
63
configPath = os.ExpandEnv(path.Join(configDir, "config.yml"))
65
if len(os.Args) >= 3 && os.Args[1] == "config" && os.Args[2] == "profile" {
66
fmt.Fprintf(os.Stderr, i18n.G("`lxc config profile` is deprecated, please use `lxc profile`")+"\n")
67
os.Args = append(os.Args[:1], os.Args[2:]...)
70
if len(os.Args) >= 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
74
if len(os.Args) >= 2 && (os.Args[1] == "--all") {
76
os.Args = append(os.Args, "--all")
79
if len(os.Args) == 2 && os.Args[1] == "--version" {
80
os.Args[1] = "version"
84
commands["help"].run(nil, nil)
88
var config *lxd.Config
92
config = &lxd.DefaultConfig
94
config, err = lxd.LoadConfig(configPath)
100
// This is quite impolite, but it seems gnuflag needs us to shift our
101
// own exename out of the arguments before parsing them. However, this
102
// is useful for execIfAlias, which wants to know exactly the command
103
// line we received, and in some cases is called before this shift, and
104
// in others after. So, let's save the original args.
108
/* at this point we haven't parsed the args, so we have to look for
109
* --no-alias by hand.
111
if !shared.StringInSlice("--no-alias", origArgs) {
112
execIfAliases(config, origArgs)
114
cmd, ok := commands[name]
116
commands["help"].run(nil, nil)
117
fmt.Fprintf(os.Stderr, "\n"+i18n.G("error: unknown command: %s")+"\n", name)
121
gnuflag.Usage = func() {
122
fmt.Fprintf(os.Stderr, i18n.G("Usage: %s")+"\n\n"+i18n.G("Options:")+"\n\n", strings.TrimSpace(cmd.usage()))
123
gnuflag.PrintDefaults()
126
os.Args = os.Args[1:]
129
shared.Log, err = logging.GetLogger("", "", *verbose, *debug, nil)
134
certf := config.ConfigPath("client.crt")
135
keyf := config.ConfigPath("client.key")
137
if !*forceLocal && os.Args[0] != "help" && os.Args[0] != "version" && (!shared.PathExists(certf) || !shared.PathExists(keyf)) {
138
fmt.Fprintf(os.Stderr, i18n.G("Generating a client certificate. This may take a minute...")+"\n")
140
err = shared.FindOrGenCert(certf, keyf)
146
err = cmd.run(config, gnuflag.Args())
148
/* If we got an error about invalid arguments, let's try to
149
* expand this as an alias
152
execIfAliases(config, origArgs)
154
fmt.Fprintf(os.Stderr, "%s\n\n"+i18n.G("error: %v")+"\n", cmd.usage(), err)
160
type command interface {
164
run(config *lxd.Config, args []string) error
167
var commands = map[string]command{
168
"config": &configCmd{},
170
"delete": &deleteCmd{},
173
"finger": &fingerCmd{},
175
"image": &imageCmd{},
178
"launch": &launchCmd{},
180
"monitor": &monitorCmd{},
182
"pause": &actionCmd{shared.Freeze, false, false, "pause", -1, false, false, false},
183
"profile": &profileCmd{},
184
"publish": &publishCmd{},
185
"remote": &remoteCmd{},
186
"restart": &actionCmd{shared.Restart, true, true, "restart", -1, false, false, false},
187
"restore": &restoreCmd{},
188
"snapshot": &snapshotCmd{},
189
"start": &actionCmd{shared.Start, false, true, "start", -1, false, false, false},
190
"stop": &actionCmd{shared.Stop, true, true, "stop", -1, false, false, false},
191
"version": &versionCmd{},
194
var errArgs = fmt.Errorf(i18n.G("wrong number of subcommand arguments"))
196
func expandAlias(config *lxd.Config, origArgs []string) ([]string, bool) {
198
aliasKey := []string{}
199
aliasValue := []string{}
201
for k, v := range config.Aliases {
203
for i, key := range strings.Split(k, " ") {
204
if len(origArgs) <= i+1 {
208
if origArgs[i+1] == key {
210
aliasKey = strings.Split(k, " ")
211
aliasValue = strings.Split(v, " ")
225
return []string{}, false
228
newArgs := []string{origArgs[0]}
229
hasReplacedArgsVar := false
231
for i, aliasArg := range aliasValue {
232
if aliasArg == "@ARGS@" && len(origArgs) > i {
233
newArgs = append(newArgs, origArgs[i+1:]...)
234
hasReplacedArgsVar = true
236
newArgs = append(newArgs, aliasArg)
240
if !hasReplacedArgsVar {
241
/* add the rest of the arguments */
242
newArgs = append(newArgs, origArgs[len(aliasKey)+1:]...)
245
/* don't re-do aliases the next time; this allows us to have recursive
246
* aliases, e.g. `lxc list` to `lxc list -c n`
248
newArgs = append(newArgs[:2], append([]string{"--no-alias"}, newArgs[2:]...)...)
253
func execIfAliases(config *lxd.Config, origArgs []string) {
254
newArgs, expanded := expandAlias(config, origArgs)
259
path, err := exec.LookPath(origArgs[0])
261
fmt.Fprintf(os.Stderr, i18n.G("processing aliases failed %s\n"), err)
264
ret := syscall.Exec(path, newArgs, syscall.Environ())
265
fmt.Fprintf(os.Stderr, i18n.G("processing aliases failed %s\n"), ret)