~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/lxc/lxd/lxc/main.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package main
 
2
 
 
3
import (
 
4
        "fmt"
 
5
        "net"
 
6
        "net/url"
 
7
        "os"
 
8
        "os/exec"
 
9
        "path"
 
10
        "strings"
 
11
        "syscall"
 
12
 
 
13
        "github.com/lxc/lxd"
 
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"
 
18
)
 
19
 
 
20
var configPath string
 
21
 
 
22
func main() {
 
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) {
 
27
                case *url.Error:
 
28
                        switch u := t.Err.(type) {
 
29
                        case *net.OpError:
 
30
                                if u.Op == "dial" && u.Net == "unix" {
 
31
                                        switch errno := u.Err.(type) {
 
32
                                        case syscall.Errno:
 
33
                                                switch errno {
 
34
                                                case syscall.ENOENT:
 
35
                                                        msg = i18n.G("LXD socket not found; is LXD running?")
 
36
                                                case syscall.ECONNREFUSED:
 
37
                                                        msg = i18n.G("Connection refused; is LXD running?")
 
38
                                                case syscall.EACCES:
 
39
                                                        msg = i18n.G("Permisson denied, are you in the lxd group?")
 
40
                                                default:
 
41
                                                        msg = fmt.Sprintf("%d %s", uintptr(errno), errno.Error())
 
42
                                                }
 
43
                                        }
 
44
                                }
 
45
                        }
 
46
                }
 
47
 
 
48
                fmt.Fprintln(os.Stderr, fmt.Sprintf("%s", msg))
 
49
                os.Exit(1)
 
50
        }
 
51
}
 
52
 
 
53
func run() error {
 
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."))
 
58
 
 
59
        configDir := "$HOME/.config/lxc"
 
60
        if os.Getenv("LXD_CONF") != "" {
 
61
                configDir = os.Getenv("LXD_CONF")
 
62
        }
 
63
        configPath = os.ExpandEnv(path.Join(configDir, "config.yml"))
 
64
 
 
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:]...)
 
68
        }
 
69
 
 
70
        if len(os.Args) >= 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
 
71
                os.Args[1] = "help"
 
72
        }
 
73
 
 
74
        if len(os.Args) >= 2 && (os.Args[1] == "--all") {
 
75
                os.Args[1] = "help"
 
76
                os.Args = append(os.Args, "--all")
 
77
        }
 
78
 
 
79
        if len(os.Args) == 2 && os.Args[1] == "--version" {
 
80
                os.Args[1] = "version"
 
81
        }
 
82
 
 
83
        if len(os.Args) < 2 {
 
84
                commands["help"].run(nil, nil)
 
85
                os.Exit(1)
 
86
        }
 
87
 
 
88
        var config *lxd.Config
 
89
        var err error
 
90
 
 
91
        if *forceLocal {
 
92
                config = &lxd.DefaultConfig
 
93
        } else {
 
94
                config, err = lxd.LoadConfig(configPath)
 
95
                if err != nil {
 
96
                        return err
 
97
                }
 
98
        }
 
99
 
 
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.
 
105
        origArgs := os.Args
 
106
        name := os.Args[1]
 
107
 
 
108
        /* at this point we haven't parsed the args, so we have to look for
 
109
         * --no-alias by hand.
 
110
         */
 
111
        if !shared.StringInSlice("--no-alias", origArgs) {
 
112
                execIfAliases(config, origArgs)
 
113
        }
 
114
        cmd, ok := commands[name]
 
115
        if !ok {
 
116
                commands["help"].run(nil, nil)
 
117
                fmt.Fprintf(os.Stderr, "\n"+i18n.G("error: unknown command: %s")+"\n", name)
 
118
                os.Exit(1)
 
119
        }
 
120
        cmd.flags()
 
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()
 
124
        }
 
125
 
 
126
        os.Args = os.Args[1:]
 
127
        gnuflag.Parse(true)
 
128
 
 
129
        shared.Log, err = logging.GetLogger("", "", *verbose, *debug, nil)
 
130
        if err != nil {
 
131
                return err
 
132
        }
 
133
 
 
134
        certf := config.ConfigPath("client.crt")
 
135
        keyf := config.ConfigPath("client.key")
 
136
 
 
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")
 
139
 
 
140
                err = shared.FindOrGenCert(certf, keyf)
 
141
                if err != nil {
 
142
                        return err
 
143
                }
 
144
        }
 
145
 
 
146
        err = cmd.run(config, gnuflag.Args())
 
147
        if err == errArgs {
 
148
                /* If we got an error about invalid arguments, let's try to
 
149
                 * expand this as an alias
 
150
                 */
 
151
                if !*noAlias {
 
152
                        execIfAliases(config, origArgs)
 
153
                }
 
154
                fmt.Fprintf(os.Stderr, "%s\n\n"+i18n.G("error: %v")+"\n", cmd.usage(), err)
 
155
                os.Exit(1)
 
156
        }
 
157
        return err
 
158
}
 
159
 
 
160
type command interface {
 
161
        usage() string
 
162
        flags()
 
163
        showByDefault() bool
 
164
        run(config *lxd.Config, args []string) error
 
165
}
 
166
 
 
167
var commands = map[string]command{
 
168
        "config":   &configCmd{},
 
169
        "copy":     &copyCmd{},
 
170
        "delete":   &deleteCmd{},
 
171
        "exec":     &execCmd{},
 
172
        "file":     &fileCmd{},
 
173
        "finger":   &fingerCmd{},
 
174
        "help":     &helpCmd{},
 
175
        "image":    &imageCmd{},
 
176
        "info":     &infoCmd{},
 
177
        "init":     &initCmd{},
 
178
        "launch":   &launchCmd{},
 
179
        "list":     &listCmd{},
 
180
        "monitor":  &monitorCmd{},
 
181
        "move":     &moveCmd{},
 
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{},
 
192
}
 
193
 
 
194
var errArgs = fmt.Errorf(i18n.G("wrong number of subcommand arguments"))
 
195
 
 
196
func expandAlias(config *lxd.Config, origArgs []string) ([]string, bool) {
 
197
        foundAlias := false
 
198
        aliasKey := []string{}
 
199
        aliasValue := []string{}
 
200
 
 
201
        for k, v := range config.Aliases {
 
202
                matches := false
 
203
                for i, key := range strings.Split(k, " ") {
 
204
                        if len(origArgs) <= i+1 {
 
205
                                break
 
206
                        }
 
207
 
 
208
                        if origArgs[i+1] == key {
 
209
                                matches = true
 
210
                                aliasKey = strings.Split(k, " ")
 
211
                                aliasValue = strings.Split(v, " ")
 
212
                                break
 
213
                        }
 
214
                }
 
215
 
 
216
                if !matches {
 
217
                        continue
 
218
                }
 
219
 
 
220
                foundAlias = true
 
221
                break
 
222
        }
 
223
 
 
224
        if !foundAlias {
 
225
                return []string{}, false
 
226
        }
 
227
 
 
228
        newArgs := []string{origArgs[0]}
 
229
        hasReplacedArgsVar := false
 
230
 
 
231
        for i, aliasArg := range aliasValue {
 
232
                if aliasArg == "@ARGS@" && len(origArgs) > i {
 
233
                        newArgs = append(newArgs, origArgs[i+1:]...)
 
234
                        hasReplacedArgsVar = true
 
235
                } else {
 
236
                        newArgs = append(newArgs, aliasArg)
 
237
                }
 
238
        }
 
239
 
 
240
        if !hasReplacedArgsVar {
 
241
                /* add the rest of the arguments */
 
242
                newArgs = append(newArgs, origArgs[len(aliasKey)+1:]...)
 
243
        }
 
244
 
 
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`
 
247
         */
 
248
        newArgs = append(newArgs[:2], append([]string{"--no-alias"}, newArgs[2:]...)...)
 
249
 
 
250
        return newArgs, true
 
251
}
 
252
 
 
253
func execIfAliases(config *lxd.Config, origArgs []string) {
 
254
        newArgs, expanded := expandAlias(config, origArgs)
 
255
        if !expanded {
 
256
                return
 
257
        }
 
258
 
 
259
        path, err := exec.LookPath(origArgs[0])
 
260
        if err != nil {
 
261
                fmt.Fprintf(os.Stderr, i18n.G("processing aliases failed %s\n"), err)
 
262
                os.Exit(5)
 
263
        }
 
264
        ret := syscall.Exec(path, newArgs, syscall.Environ())
 
265
        fmt.Fprintf(os.Stderr, i18n.G("processing aliases failed %s\n"), ret)
 
266
        os.Exit(5)
 
267
}