func cmdConfig(c *cli.Context) error { // Ensure that log messages always go to stderr when this command is // being run (it is intended to be run in a subshell) log.SetOutWriter(os.Stderr) if len(c.Args()) != 1 { return ErrExpectedOneMachine } host, err := getFirstArgHost(c) if err != nil { return err } dockerHost, authOptions, err := runConnectionBoilerplate(host, c) if err != nil { return fmt.Errorf("Error running connection boilerplate: %s", err) } log.Debug(dockerHost) fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s", authOptions.CaCertPath, authOptions.ClientCertPath, authOptions.ClientKeyPath, dockerHost) return nil }
func cmdSsh(c *cli.Context) error { name := c.Args().First() if name == "" { return ErrExpectedOneMachine } store := getStore(c) host, err := loadHost(store, name) if err != nil { return err } currentState, err := host.Driver.GetState() if err != nil { return err } if currentState != state.Running { return fmt.Errorf("Error: Cannot run SSH command: Host %q is not running", host.Name) } client, err := host.CreateSSHClient() if err != nil { return err } return client.Shell(c.Args().Tail()...) }
func cmdSsh(c *cli.Context) { args := c.Args() name := args.First() if name == "" { fatal("Error: Please specify a machine name.") } store := getStore(c) host, err := loadHost(store, name) if err != nil { fatal(err) } currentState, err := host.Driver.GetState() if err != nil { fatal(err) } if currentState != state.Running { fatalf("Error: Cannot run SSH command: Host %q is not running", host.Name) } client, err := host.CreateSSHClient() if err != nil { fatal(err) } if err := client.Shell(c.Args().Tail()...); err != nil { fatal(err) } }
func cmdScp(c *cli.Context) error { hostLoader = &ScpHostLoader{} args := c.Args() if len(args) != 2 { cli.ShowCommandHelp(c, "scp") return errWrongNumberArguments } // TODO: Check that "-3" flag is available in user's version of scp. // It is on every system I've checked, but the manual mentioned it's "newer" sshArgs := append(baseSSHArgs, "-3") if c.Bool("recursive") { sshArgs = append(sshArgs, "-r") } src := args[0] dest := args[1] store := getStore(c) cmd, err := getScpCmd(src, dest, sshArgs, store) if err != nil { return err } return runCmdWithStdIo(*cmd) }
func getStore(c *cli.Context) persist.Store { certInfo := getCertPathInfoFromContext(c) return &persist.Filestore{ Path: c.GlobalString("storage-path"), CaCertPath: certInfo.CaCertPath, CaPrivateKeyPath: certInfo.CaPrivateKeyPath, } }
func cmdRegenerateCerts(c *cli.Context) { force := c.Bool("force") if force || confirmInput("Regenerate TLS machine certs? Warning: this is irreversible.") { log.Infof("Regenerating TLS certificates") if err := runActionWithContext("configureAuth", c); err != nil { fatal(err) } } }
func cmdCreateOuter(c *cli.Context) { driverName := flagHackLookup("--driver") // We didn't recognize the driver name. if driverName == "" { cli.ShowCommandHelp(c, "create") return } name := c.Args().First() // TODO: Fix hacky JSON solution bareDriverData, err := json.Marshal(&drivers.BaseDriver{ MachineName: name, }) if err != nil { fatalf("Error attempting to marshal bare driver data: %s", err) } driver, err := newPluginDriver(driverName, bareDriverData) if err != nil { fatalf("Error loading driver %q: %s", driverName, err) } // TODO: So much flag manipulation and voodoo here, it seems to be // asking for trouble. // // mcnFlags is the data we get back over the wire (type mcnflag.Flag) // to indicate which parameters are available. mcnFlags := driver.GetCreateFlags() // This bit will actually make "create" display the correct flags based // on the requested driver. cliFlags, err := convertMcnFlagsToCliFlags(mcnFlags) if err != nil { fatalf("Error trying to convert provided driver flags to cli flags: %s", err) } for i := range c.App.Commands { cmd := &c.App.Commands[i] if cmd.HasName("create") { cmd = addDriverFlagsToCommand(cliFlags, cmd) } } if err := driver.Close(); err != nil { fatal(err) } if err := c.App.Run(os.Args); err != nil { fatal(err) } }
func cmdStatus(c *cli.Context) { if len(c.Args()) != 1 { fatal(ErrExpectedOneMachine) } host := getFirstArgHost(c) currentState, err := host.Driver.GetState() if err != nil { log.Errorf("error getting state for host %s: %s", host.Name, err) } log.Info(currentState) }
func getHostsFromContext(c *cli.Context) ([]*host.Host, error) { store := getStore(c) hosts := []*host.Host{} for _, hostName := range c.Args() { h, err := loadHost(store, hostName) if err != nil { return nil, fmt.Errorf("Could not load host %q: %s", hostName, err) } hosts = append(hosts, h) } return hosts, nil }
// Returns the cert paths. // codegangsta/cli will not set the cert paths if the storage-path is set to // something different so we cannot use the paths in the global options. le // sigh. func getCertPathInfoFromContext(c *cli.Context) cert.CertPathInfo { caCertPath := c.GlobalString("tls-ca-cert") caKeyPath := c.GlobalString("tls-ca-key") clientCertPath := c.GlobalString("tls-client-cert") clientKeyPath := c.GlobalString("tls-client-key") if caCertPath == "" { caCertPath = filepath.Join(mcndirs.GetMachineCertDir(), "ca.pem") } if caKeyPath == "" { caKeyPath = filepath.Join(mcndirs.GetMachineCertDir(), "ca-key.pem") } if clientCertPath == "" { clientCertPath = filepath.Join(mcndirs.GetMachineCertDir(), "cert.pem") } if clientKeyPath == "" { clientKeyPath = filepath.Join(mcndirs.GetMachineCertDir(), "key.pem") } return cert.CertPathInfo{ CaCertPath: caCertPath, CaPrivateKeyPath: caKeyPath, ClientCertPath: clientCertPath, ClientKeyPath: clientKeyPath, } }
func cmdActive(c *cli.Context) { if len(c.Args()) > 0 { fatal("Error: Too many arguments given.") } store := getStore(c) host, err := getActiveHost(store) if err != nil { fatalf("Error getting active host: %s", err) } if host != nil { fmt.Println(host.Name) } }
func cmdRegenerateCerts(c *cli.Context) error { if !c.Bool("force") { ok, err := confirmInput("Regenerate TLS machine certs? Warning: this is irreversible.") if err != nil { return err } if !ok { return nil } } log.Infof("Regenerating TLS certificates") return runActionWithContext("configureAuth", c) }
func cmdConfig(c *cli.Context) { if len(c.Args()) != 1 { fatal(ErrExpectedOneMachine) } h := getFirstArgHost(c) dockerHost, authOptions, err := runConnectionBoilerplate(h, c) if err != nil { fatalf("Error running connection boilerplate: %s", err) } log.Debug(dockerHost) fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s", authOptions.CaCertPath, authOptions.ClientCertPath, authOptions.ClientKeyPath, dockerHost) }
func cmdInspect(c *cli.Context) error { if len(c.Args()) == 0 { cli.ShowCommandHelp(c, "inspect") return ErrExpectedOneMachine } host, err := getFirstArgHost(c) if err != nil { return err } tmplString := c.String("format") if tmplString != "" { var tmpl *template.Template var err error if tmpl, err = template.New("").Funcs(funcMap).Parse(tmplString); err != nil { return fmt.Errorf("Template parsing error: %v\n", err) } jsonHost, err := json.Marshal(host) if err != nil { return err } obj := make(map[string]interface{}) if err := json.Unmarshal(jsonHost, &obj); err != nil { return err } if err := tmpl.Execute(os.Stdout, obj); err != nil { return err } os.Stdout.Write([]byte{'\n'}) } else { prettyJSON, err := json.MarshalIndent(host, "", " ") if err != nil { return err } fmt.Println(string(prettyJSON)) } return nil }
func cmdActive(c *cli.Context) error { if len(c.Args()) > 0 { return errTooManyArguments } store := getStore(c) host, err := getActiveHost(store) if err != nil { return fmt.Errorf("Error getting active host: %s", err) } if host != nil { fmt.Println(host.Name) } return nil }
func cmdUrl(c *cli.Context) error { if len(c.Args()) != 1 { return ErrExpectedOneMachine } host, err := getFirstArgHost(c) if err != nil { return err } url, err := host.GetURL() if err != nil { return err } fmt.Println(url) return nil }
func cmdStatus(c *cli.Context) error { if len(c.Args()) != 1 { return ErrExpectedOneMachine } host, err := getFirstArgHost(c) if err != nil { return err } currentState, err := host.Driver.GetState() if err != nil { log.Errorf("error getting state for host %s: %s", host.Name, err) } log.Info(currentState) return nil }
func cmdRm(c *cli.Context) { if len(c.Args()) == 0 { cli.ShowCommandHelp(c, "rm") fatal("You must specify a machine name") } force := c.Bool("force") store := getStore(c) for _, hostName := range c.Args() { h, err := loadHost(store, hostName) if err != nil { fatalf("Error removing host %q: %s", hostName, err) } if err := h.Driver.Remove(); err != nil { if !force { log.Errorf("Provider error removing machine %q: %s", hostName, err) continue } } if err := store.Remove(hostName); err != nil { log.Errorf("Error removing machine %q from store: %s", hostName, err) } else { log.Infof("Successfully removed %s", hostName) } } }
func getDriverOpts(c *cli.Context, mcnflags []mcnflag.Flag) drivers.DriverOptions { // TODO: This function is pretty damn YOLO and would benefit from some // sanity checking around types and assertions. // // But, we need it so that we can actually send the flags for creating // a machine over the wire (cli.Context is a no go since there is so // much stuff in it). driverOpts := rpcdriver.RpcFlags{ Values: make(map[string]interface{}), } for _, f := range mcnflags { driverOpts.Values[f.String()] = f.Default() // Hardcoded logic for boolean... :( if f.Default() == nil { driverOpts.Values[f.String()] = false } } for _, name := range c.FlagNames() { getter, ok := c.Generic(name).(flag.Getter) if !ok { // TODO: This is pretty hacky. StringSlice is the only // type so far we have to worry about which is not a // Getter, though. driverOpts.Values[name] = c.StringSlice(name) continue } driverOpts.Values[name] = getter.Get() } return driverOpts }
func getFirstArgHost(c *cli.Context) *host.Host { store := getStore(c) hostName := c.Args().First() exists, err := store.Exists(hostName) if err != nil { fatalf("Error checking if host %q exists: %s", hostName, err) } if !exists { fatalf("Host %q does not exist", hostName) } h, err := loadHost(store, hostName) if err != nil { // I guess I feel OK with bailing here since if we can't get // the host reliably we're definitely not going to be able to // do anything else interesting, but also this premature exit // feels wrong to me. Let's revisit it later. fatalf("Error trying to get host %q: %s", hostName, err) } return h }
func runConnectionBoilerplate(h *host.Host, c *cli.Context) (string, *auth.AuthOptions, error) { hostState, err := h.Driver.GetState() if err != nil { // TODO: This is a common operation and should have a commonly // defined error. return "", &auth.AuthOptions{}, fmt.Errorf("Error trying to get host state: %s", err) } if hostState != state.Running { return "", &auth.AuthOptions{}, fmt.Errorf("%s is not running. Please start it in order to use the connection settings.", h.Name) } dockerHost, err := h.Driver.GetURL() if err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error getting driver URL: %s", err) } if c.Bool("swarm") { var err error dockerHost, err = parseSwarm(dockerHost, h) if err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error parsing swarm: %s", err) } } u, err := url.Parse(dockerHost) if err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error parsing URL: %s", err) } authOptions := h.HostOptions.AuthOptions if err := checkCert(u.Host, authOptions, c); err != nil { return "", &auth.AuthOptions{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err) } return dockerHost, authOptions, nil }
func cmdScp(c *cli.Context) error { args := c.Args() if len(args) != 2 { cli.ShowCommandHelp(c, "scp") return errWrongNumberArguments } src := args[0] dest := args[1] store := getStore(c) hostInfoLoader := &storeHostInfoLoader{store} cmd, err := getScpCmd(src, dest, c.Bool("recursive"), hostInfoLoader) if err != nil { return err } if err := runCmdWithStdIo(*cmd); err != nil { return err } return runCmdWithStdIo(*cmd) }
func cmdInspect(c *cli.Context) { if len(c.Args()) == 0 { cli.ShowCommandHelp(c, "inspect") fatal("You must specify a machine name") } tmplString := c.String("format") if tmplString != "" { var tmpl *template.Template var err error if tmpl, err = template.New("").Funcs(funcMap).Parse(tmplString); err != nil { fatalf("Template parsing error: %v\n", err) } jsonHost, err := json.Marshal(getFirstArgHost(c)) if err != nil { fatal(err) } obj := make(map[string]interface{}) if err := json.Unmarshal(jsonHost, &obj); err != nil { fatal(err) } if err := tmpl.Execute(os.Stdout, obj); err != nil { fatal(err) } os.Stdout.Write([]byte{'\n'}) } else { prettyJSON, err := json.MarshalIndent(getFirstArgHost(c), "", " ") if err != nil { fatal(err) } fmt.Println(string(prettyJSON)) } }
func cmdSsh(c *cli.Context) error { // Check for help flag -- Needed due to SkipFlagParsing for _, arg := range c.Args() { if arg == "-help" || arg == "--help" || arg == "-h" { cli.ShowCommandHelp(c, "ssh") return nil } } name := c.Args().First() if name == "" { return ErrExpectedOneMachine } store := getStore(c) host, err := loadHost(store, name) if err != nil { return err } currentState, err := host.Driver.GetState() if err != nil { return err } if currentState != state.Running { return fmt.Errorf("Error: Cannot run SSH command: Host %q is not running", host.Name) } client, err := host.CreateSSHClient() if err != nil { return err } return client.Shell(c.Args().Tail()...) }
func cmdEnv(c *cli.Context) { // Ensure that log messages always go to stderr when this command is // being run (it is intended to be run in a subshell) log.SetOutWriter(os.Stderr) if len(c.Args()) != 1 && !c.Bool("unset") { fatal(improperEnvArgsError) } h := getFirstArgHost(c) dockerHost, authOptions, err := runConnectionBoilerplate(h, c) if err != nil { fatalf("Error running connection boilerplate: %s", err) } userShell := c.String("shell") if userShell == "" { shell, err := detectShell() if err != nil { fatal(err) } userShell = shell } t := template.New("envConfig") usageHint := generateUsageHint(c.App.Name, c.Args().First(), userShell, c.Bool("no-proxy"), c.Bool("swarm")) shellCfg := &ShellConfig{ DockerCertPath: authOptions.CertDir, DockerHost: dockerHost, DockerTLSVerify: "1", UsageHint: usageHint, MachineName: h.Name, } if c.Bool("no-proxy") { ip, err := h.Driver.GetIP() if err != nil { fatalf("Error getting host IP: %s", err) } // first check for an existing lower case no_proxy var noProxyVar := "no_proxy" noProxyValue := os.Getenv("no_proxy") // otherwise default to allcaps HTTP_PROXY if noProxyValue == "" { noProxyVar = "NO_PROXY" noProxyValue = os.Getenv("NO_PROXY") } // add the docker host to the no_proxy list idempotently switch { case noProxyValue == "": noProxyValue = ip case strings.Contains(noProxyValue, ip): //ip already in no_proxy list, nothing to do default: noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ip) } shellCfg.NoProxyVar = noProxyVar shellCfg.NoProxyValue = noProxyValue } // unset vars if c.Bool("unset") { switch userShell { case "fish": shellCfg.Prefix = "set -e " shellCfg.Delimiter = "" shellCfg.Suffix = ";\n" case "powershell": shellCfg.Prefix = "Remove-Item Env:\\\\" shellCfg.Delimiter = "" shellCfg.Suffix = "\n" case "cmd": // since there is no way to unset vars in cmd just reset to empty shellCfg.DockerCertPath = "" shellCfg.DockerHost = "" shellCfg.DockerTLSVerify = "" shellCfg.Prefix = "set " shellCfg.Delimiter = "=" shellCfg.Suffix = "\n" default: shellCfg.Prefix = "unset " shellCfg.Delimiter = " " shellCfg.Suffix = "\n" } tmpl, err := t.Parse(envTmpl) if err != nil { fatal(err) } if err := tmpl.Execute(os.Stdout, shellCfg); err != nil { fatal(err) } return } switch userShell { case "fish": shellCfg.Prefix = "set -x " shellCfg.Suffix = "\";\n" shellCfg.Delimiter = " \"" case "powershell": shellCfg.Prefix = "$Env:" shellCfg.Suffix = "\"\n" shellCfg.Delimiter = " = \"" case "cmd": shellCfg.Prefix = "set " shellCfg.Suffix = "\n" shellCfg.Delimiter = "=" default: shellCfg.Prefix = "export " shellCfg.Suffix = "\"\n" shellCfg.Delimiter = "=\"" } tmpl, err := t.Parse(envTmpl) if err != nil { fatal(err) } if err := tmpl.Execute(os.Stdout, shellCfg); err != nil { fatal(err) } }
func cmdLs(c *cli.Context) { quiet := c.Bool("quiet") filters, err := parseFilters(c.StringSlice("filter")) if err != nil { fatal(err) } store := getStore(c) hostList, err := listHosts(store) if err != nil { fatal(err) } hostList = filterHosts(hostList, filters) // Just print out the names if we're being quiet if quiet { for _, host := range hostList { fmt.Println(host.Name) } return } swarmMasters := make(map[string]string) swarmInfo := make(map[string]string) w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0) fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM") for _, host := range hostList { swarmOptions := host.HostOptions.SwarmOptions if swarmOptions.Master { swarmMasters[swarmOptions.Discovery] = host.Name } if swarmOptions.Discovery != "" { swarmInfo[host.Name] = swarmOptions.Discovery } } items := getHostListItems(hostList) sortHostListItemsByName(items) for _, item := range items { activeString := "-" if item.Active { activeString = "*" } swarmInfo := "" if item.SwarmOptions.Discovery != "" { swarmInfo = swarmMasters[item.SwarmOptions.Discovery] if item.SwarmOptions.Master { swarmInfo = fmt.Sprintf("%s (master)", swarmInfo) } } fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n", item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo) } w.Flush() }
func cmdCreateInner(c *cli.Context) { if len(c.Args()) > 1 { fatalf("Invalid command line. Found extra arguments %v", c.Args()[1:]) } name := c.Args().First() driverName := c.String("driver") certInfo := getCertPathInfoFromContext(c) storePath := c.GlobalString("storage-path") store := &persist.Filestore{ Path: storePath, CaCertPath: certInfo.CaCertPath, CaPrivateKeyPath: certInfo.CaPrivateKeyPath, } if name == "" { cli.ShowCommandHelp(c, "create") fatal("Error: No machine name specified.") } validName := host.ValidateHostName(name) if !validName { fatal("Error creating machine: ", mcnerror.ErrInvalidHostname) } if err := validateSwarmDiscovery(c.String("swarm-discovery")); err != nil { fatalf("Error parsing swarm discovery: %s", err) } // TODO: Fix hacky JSON solution bareDriverData, err := json.Marshal(&drivers.BaseDriver{ MachineName: name, StorePath: c.GlobalString("storage-path"), }) if err != nil { fatalf("Error attempting to marshal bare driver data: %s", err) } driver, err := newPluginDriver(driverName, bareDriverData) if err != nil { fatalf("Error loading driver %q: %s", driverName, err) } h, err := store.NewHost(driver) if err != nil { fatalf("Error getting new host: %s", err) } h.HostOptions = &host.HostOptions{ AuthOptions: &auth.AuthOptions{ CertDir: mcndirs.GetMachineCertDir(), CaCertPath: certInfo.CaCertPath, CaPrivateKeyPath: certInfo.CaPrivateKeyPath, ClientCertPath: certInfo.ClientCertPath, ClientKeyPath: certInfo.ClientKeyPath, ServerCertPath: filepath.Join(mcndirs.GetMachineDir(), name, "server.pem"), ServerKeyPath: filepath.Join(mcndirs.GetMachineDir(), name, "server-key.pem"), StorePath: filepath.Join(mcndirs.GetMachineDir(), name), }, EngineOptions: &engine.EngineOptions{ ArbitraryFlags: c.StringSlice("engine-opt"), Env: c.StringSlice("engine-env"), InsecureRegistry: c.StringSlice("engine-insecure-registry"), Labels: c.StringSlice("engine-label"), RegistryMirror: c.StringSlice("engine-registry-mirror"), StorageDriver: c.String("engine-storage-driver"), TlsVerify: true, InstallURL: c.String("engine-install-url"), }, SwarmOptions: &swarm.SwarmOptions{ IsSwarm: c.Bool("swarm"), Image: c.String("swarm-image"), Master: c.Bool("swarm-master"), Discovery: c.String("swarm-discovery"), Address: c.String("swarm-addr"), Host: c.String("swarm-host"), Strategy: c.String("swarm-strategy"), ArbitraryFlags: c.StringSlice("swarm-opt"), }, } exists, err := store.Exists(h.Name) if err != nil { fatalf("Error checking if host exists: %s", err) } if exists { fatal(mcnerror.ErrHostAlreadyExists{ Name: h.Name, }) } // driverOpts is the actual data we send over the wire to set the // driver parameters (an interface fulfilling drivers.DriverOptions, // concrete type rpcdriver.RpcFlags). mcnFlags := driver.GetCreateFlags() driverOpts := getDriverOpts(c, mcnFlags) if err := h.Driver.SetConfigFromFlags(driverOpts); err != nil { fatalf("Error setting machine configuration from flags provided: %s", err) } if err := libmachine.Create(store, h); err != nil { fatalf("Error creating machine: %s", err) } if err := saveHost(store, h); err != nil { fatalf("Error attempting to save store: %s", err) } log.Infof("To see how to connect Docker to this machine, run: %s", fmt.Sprintf("%s env %s", os.Args[0], name)) }