mirror of https://github.com/docker/docs.git
Merge pull request #923 from hairyhenderson/refactor-split-subcommands
Refactoring commands.go into new commands package
This commit is contained in:
commit
3e0477e14c
|
|
@ -0,0 +1,49 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdActive(c *cli.Context) {
|
||||||
|
name := c.Args().First()
|
||||||
|
|
||||||
|
certInfo := getCertPathInfo(c)
|
||||||
|
defaultStore, err := getDefaultStore(
|
||||||
|
c.GlobalString("storage-path"),
|
||||||
|
certInfo.CaCertPath,
|
||||||
|
certInfo.CaKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := newMcn(defaultStore)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
host, err := mcn.GetActive()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error getting active host: %v", err)
|
||||||
|
}
|
||||||
|
if host != nil {
|
||||||
|
fmt.Println(host.Name)
|
||||||
|
}
|
||||||
|
} else if name != "" {
|
||||||
|
host, err := mcn.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error loading host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mcn.SetActive(host); err != nil {
|
||||||
|
log.Fatalf("error setting active host: %v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cli.ShowCommandHelp(c, "active")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
package main
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
|
@ -29,9 +25,9 @@ import (
|
||||||
_ "github.com/docker/machine/drivers/vmwarefusion"
|
_ "github.com/docker/machine/drivers/vmwarefusion"
|
||||||
_ "github.com/docker/machine/drivers/vmwarevcloudair"
|
_ "github.com/docker/machine/drivers/vmwarevcloudair"
|
||||||
_ "github.com/docker/machine/drivers/vmwarevsphere"
|
_ "github.com/docker/machine/drivers/vmwarevsphere"
|
||||||
|
|
||||||
"github.com/docker/machine/libmachine"
|
"github.com/docker/machine/libmachine"
|
||||||
"github.com/docker/machine/libmachine/auth"
|
"github.com/docker/machine/libmachine/auth"
|
||||||
"github.com/docker/machine/libmachine/engine"
|
|
||||||
"github.com/docker/machine/libmachine/swarm"
|
"github.com/docker/machine/libmachine/swarm"
|
||||||
"github.com/docker/machine/state"
|
"github.com/docker/machine/state"
|
||||||
"github.com/docker/machine/utils"
|
"github.com/docker/machine/utils"
|
||||||
|
|
@ -329,536 +325,6 @@ var Commands = []cli.Command{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdActive(c *cli.Context) {
|
|
||||||
name := c.Args().First()
|
|
||||||
|
|
||||||
certInfo := getCertPathInfo(c)
|
|
||||||
defaultStore, err := getDefaultStore(
|
|
||||||
c.GlobalString("storage-path"),
|
|
||||||
certInfo.CaCertPath,
|
|
||||||
certInfo.CaKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := newMcn(defaultStore)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "" {
|
|
||||||
host, err := mcn.GetActive()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error getting active host: %v", err)
|
|
||||||
}
|
|
||||||
if host != nil {
|
|
||||||
fmt.Println(host.Name)
|
|
||||||
}
|
|
||||||
} else if name != "" {
|
|
||||||
host, err := mcn.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error loading host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := mcn.SetActive(host); err != nil {
|
|
||||||
log.Fatalf("error setting active host: %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cli.ShowCommandHelp(c, "active")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user has specified a driver, they should not see the flags for all
|
|
||||||
// of the drivers in `docker-machine create`. This method replaces the 100+
|
|
||||||
// create flags with only the ones applicable to the driver specified
|
|
||||||
func trimDriverFlags(driver string, cmds []cli.Command) ([]cli.Command, error) {
|
|
||||||
filteredCmds := cmds
|
|
||||||
driverFlags, err := drivers.GetCreateFlagsForDriver(driver)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, cmd := range cmds {
|
|
||||||
if cmd.HasName("create") {
|
|
||||||
filteredCmds[i].Flags = append(driverFlags, sharedCreateFlags...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredCmds, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdCreate(c *cli.Context) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
driver := c.String("driver")
|
|
||||||
name := c.Args().First()
|
|
||||||
|
|
||||||
// TODO: Not really a fan of "none" as the default driver...
|
|
||||||
if driver != "none" {
|
|
||||||
c.App.Commands, err = trimDriverFlags(driver, c.App.Commands)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "" {
|
|
||||||
cli.ShowCommandHelp(c, "create")
|
|
||||||
log.Fatal("You must specify a machine name")
|
|
||||||
}
|
|
||||||
|
|
||||||
certInfo := getCertPathInfo(c)
|
|
||||||
|
|
||||||
if err := setupCertificates(
|
|
||||||
certInfo.CaCertPath,
|
|
||||||
certInfo.CaKeyPath,
|
|
||||||
certInfo.ClientCertPath,
|
|
||||||
certInfo.ClientKeyPath); err != nil {
|
|
||||||
log.Fatalf("Error generating certificates: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultStore, err := getDefaultStore(
|
|
||||||
c.GlobalString("storage-path"),
|
|
||||||
certInfo.CaCertPath,
|
|
||||||
certInfo.CaKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := newMcn(defaultStore)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostOptions := &libmachine.HostOptions{
|
|
||||||
AuthOptions: &auth.AuthOptions{
|
|
||||||
CaCertPath: certInfo.CaCertPath,
|
|
||||||
PrivateKeyPath: certInfo.CaKeyPath,
|
|
||||||
ClientCertPath: certInfo.ClientCertPath,
|
|
||||||
ClientKeyPath: certInfo.ClientKeyPath,
|
|
||||||
ServerCertPath: filepath.Join(utils.GetMachineDir(), name, "server.pem"),
|
|
||||||
ServerKeyPath: filepath.Join(utils.GetMachineDir(), name, "server-key.pem"),
|
|
||||||
},
|
|
||||||
EngineOptions: &engine.EngineOptions{},
|
|
||||||
SwarmOptions: &swarm.SwarmOptions{
|
|
||||||
IsSwarm: c.Bool("swarm"),
|
|
||||||
Master: c.Bool("swarm-master"),
|
|
||||||
Discovery: c.String("swarm-discovery"),
|
|
||||||
Address: c.String("swarm-addr"),
|
|
||||||
Host: c.String("swarm-host"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := mcn.Create(name, driver, hostOptions, c)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error creating machine: %s", err)
|
|
||||||
log.Warn("You will want to check the provider to make sure the machine and associated resources were properly removed.")
|
|
||||||
log.Fatal("Error creating machine")
|
|
||||||
}
|
|
||||||
if err := mcn.SetActive(host); err != nil {
|
|
||||||
log.Fatalf("error setting active host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
info := ""
|
|
||||||
userShell := filepath.Base(os.Getenv("SHELL"))
|
|
||||||
|
|
||||||
switch userShell {
|
|
||||||
case "fish":
|
|
||||||
info = fmt.Sprintf("%s env %s | source", c.App.Name, name)
|
|
||||||
default:
|
|
||||||
info = fmt.Sprintf(`eval "$(%s env %s)"`, c.App.Name, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Infof("%q has been created and is now the active machine.", name)
|
|
||||||
|
|
||||||
if info != "" {
|
|
||||||
log.Infof("To point your Docker client at it, run this in your shell: %s", info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdConfig(c *cli.Context) {
|
|
||||||
cfg, err := getMachineConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerHost, err := getHost(c).Driver.GetURL()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Bool("swarm") {
|
|
||||||
if !cfg.SwarmOptions.Master {
|
|
||||||
log.Fatalf("%s is not a swarm master", cfg.machineName)
|
|
||||||
}
|
|
||||||
u, err := url.Parse(cfg.SwarmOptions.Host)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
parts := strings.Split(u.Host, ":")
|
|
||||||
swarmPort := parts[1]
|
|
||||||
|
|
||||||
// get IP of machine to replace in case swarm host is 0.0.0.0
|
|
||||||
mUrl, err := url.Parse(dockerHost)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
mParts := strings.Split(mUrl.Host, ":")
|
|
||||||
machineIp := mParts[0]
|
|
||||||
|
|
||||||
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug(dockerHost)
|
|
||||||
|
|
||||||
u, err := url.Parse(cfg.machineUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.Scheme != "unix" {
|
|
||||||
// validate cert and regenerate if needed
|
|
||||||
valid, err := utils.ValidateCertificate(
|
|
||||||
u.Host,
|
|
||||||
cfg.caCertPath,
|
|
||||||
cfg.serverCertPath,
|
|
||||||
cfg.serverKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !valid {
|
|
||||||
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
|
|
||||||
|
|
||||||
if err := runActionWithContext("configureAuth", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s",
|
|
||||||
cfg.caCertPath, cfg.clientCertPath, cfg.clientKeyPath, dockerHost)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdInspect(c *cli.Context) {
|
|
||||||
prettyJSON, err := json.MarshalIndent(getHost(c), "", " ")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(string(prettyJSON))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdIp(c *cli.Context) {
|
|
||||||
ip, err := getHost(c).Driver.GetIP()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdLs(c *cli.Context) {
|
|
||||||
quiet := c.Bool("quiet")
|
|
||||||
|
|
||||||
certInfo := getCertPathInfo(c)
|
|
||||||
defaultStore, err := getDefaultStore(
|
|
||||||
c.GlobalString("storage-path"),
|
|
||||||
certInfo.CaCertPath,
|
|
||||||
certInfo.CaKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := newMcn(defaultStore)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostList, err := mcn.List()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM")
|
|
||||||
}
|
|
||||||
|
|
||||||
items := []hostListItem{}
|
|
||||||
hostListItems := make(chan hostListItem)
|
|
||||||
|
|
||||||
swarmMasters := make(map[string]string)
|
|
||||||
swarmInfo := make(map[string]string)
|
|
||||||
|
|
||||||
for _, host := range hostList {
|
|
||||||
swarmOptions := host.HostOptions.SwarmOptions
|
|
||||||
if !quiet {
|
|
||||||
if swarmOptions.Master {
|
|
||||||
swarmMasters[swarmOptions.Discovery] = host.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
if swarmOptions.Discovery != "" {
|
|
||||||
swarmInfo[host.Name] = swarmOptions.Discovery
|
|
||||||
}
|
|
||||||
|
|
||||||
go getHostState(*host, defaultStore, hostListItems)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(w, "%s\n", host.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
for i := 0; i < len(hostList); i++ {
|
|
||||||
items = append(items, <-hostListItems)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close(hostListItems)
|
|
||||||
|
|
||||||
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 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 {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdRm(c *cli.Context) {
|
|
||||||
if len(c.Args()) == 0 {
|
|
||||||
cli.ShowCommandHelp(c, "rm")
|
|
||||||
log.Fatal("You must specify a machine name")
|
|
||||||
}
|
|
||||||
|
|
||||||
force := c.Bool("force")
|
|
||||||
|
|
||||||
isError := false
|
|
||||||
|
|
||||||
certInfo := getCertPathInfo(c)
|
|
||||||
defaultStore, err := getDefaultStore(
|
|
||||||
c.GlobalString("storage-path"),
|
|
||||||
certInfo.CaCertPath,
|
|
||||||
certInfo.CaKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := newMcn(defaultStore)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, host := range c.Args() {
|
|
||||||
if err := mcn.Remove(host, force); err != nil {
|
|
||||||
log.Errorf("Error removing machine %s: %s", host, err)
|
|
||||||
isError = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isError {
|
|
||||||
log.Fatal("There was an error removing a machine. To force remove it, pass the -f option. Warning: this might leave it running on the provider.")
|
|
||||||
}
|
|
||||||
log.Print("The machine was successfully removed.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdEnv(c *cli.Context) {
|
|
||||||
userShell := filepath.Base(os.Getenv("SHELL"))
|
|
||||||
if c.Bool("unset") {
|
|
||||||
switch userShell {
|
|
||||||
case "fish":
|
|
||||||
fmt.Printf("set -e DOCKER_TLS_VERIFY;\nset -e DOCKER_CERT_PATH;\nset -e DOCKER_HOST;\n")
|
|
||||||
default:
|
|
||||||
fmt.Println("unset DOCKER_TLS_VERIFY DOCKER_CERT_PATH DOCKER_HOST")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg, err := getMachineConfig(c)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.machineUrl == "" {
|
|
||||||
log.Fatalf("%s is not running. Please start this with docker-machine start %s", cfg.machineName, cfg.machineName)
|
|
||||||
}
|
|
||||||
|
|
||||||
dockerHost := cfg.machineUrl
|
|
||||||
if c.Bool("swarm") {
|
|
||||||
if !cfg.SwarmOptions.Master {
|
|
||||||
log.Fatalf("%s is not a swarm master", cfg.machineName)
|
|
||||||
}
|
|
||||||
u, err := url.Parse(cfg.SwarmOptions.Host)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
parts := strings.Split(u.Host, ":")
|
|
||||||
swarmPort := parts[1]
|
|
||||||
|
|
||||||
// get IP of machine to replace in case swarm host is 0.0.0.0
|
|
||||||
mUrl, err := url.Parse(cfg.machineUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
mParts := strings.Split(mUrl.Host, ":")
|
|
||||||
machineIp := mParts[0]
|
|
||||||
|
|
||||||
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(cfg.machineUrl)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.Scheme != "unix" {
|
|
||||||
// validate cert and regenerate if needed
|
|
||||||
valid, err := utils.ValidateCertificate(
|
|
||||||
u.Host,
|
|
||||||
cfg.caCertPath,
|
|
||||||
cfg.serverCertPath,
|
|
||||||
cfg.serverKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !valid {
|
|
||||||
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
|
|
||||||
|
|
||||||
if err := runActionWithContext("configureAuth", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
usageHint := generateUsageHint(c.Args().First(), userShell)
|
|
||||||
|
|
||||||
switch userShell {
|
|
||||||
case "fish":
|
|
||||||
fmt.Printf("set -x DOCKER_TLS_VERIFY 1;\nset -x DOCKER_CERT_PATH %q;\nset -x DOCKER_HOST %s;\n\n%s\n",
|
|
||||||
cfg.machineDir, dockerHost, usageHint)
|
|
||||||
default:
|
|
||||||
fmt.Printf("export DOCKER_TLS_VERIFY=1\nexport DOCKER_CERT_PATH=%q\nexport DOCKER_HOST=%s\n\n%s\n",
|
|
||||||
cfg.machineDir, dockerHost, usageHint)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateUsageHint(machineName string, userShell string) string {
|
|
||||||
cmd := ""
|
|
||||||
switch userShell {
|
|
||||||
case "fish":
|
|
||||||
if machineName != "" {
|
|
||||||
cmd = fmt.Sprintf("eval (docker-machine env %s)", machineName)
|
|
||||||
} else {
|
|
||||||
cmd = "eval (docker-machine env)"
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if machineName != "" {
|
|
||||||
cmd = fmt.Sprintf("eval \"$(docker-machine env %s)\"", machineName)
|
|
||||||
} else {
|
|
||||||
cmd = "eval \"$(docker-machine env)\""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("# Run this command to configure your shell: %s\n", cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdSsh(c *cli.Context) {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
sshCmd *exec.Cmd
|
|
||||||
)
|
|
||||||
name := c.Args().First()
|
|
||||||
|
|
||||||
certInfo := getCertPathInfo(c)
|
|
||||||
defaultStore, err := getDefaultStore(
|
|
||||||
c.GlobalString("storage-path"),
|
|
||||||
certInfo.CaCertPath,
|
|
||||||
certInfo.CaKeyPath,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := newMcn(defaultStore)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "" {
|
|
||||||
host, err := mcn.GetActive()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("unable to get active host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if host == nil {
|
|
||||||
log.Fatalf("There is no active host. Please set it with %s active <machine name>.", c.App.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
name = host.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := mcn.Get(name)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = host.GetURL()
|
|
||||||
if err != nil {
|
|
||||||
if err == drivers.ErrHostIsNotRunning {
|
|
||||||
log.Fatalf("%s is not running. Please start this with docker-machine start %s", host.Name, host.Name)
|
|
||||||
} else {
|
|
||||||
log.Fatalf("Unexpected error getting machine url: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.Args()) <= 1 {
|
|
||||||
sshCmd, err = host.GetSSHCommand()
|
|
||||||
} else {
|
|
||||||
sshCmd, err = host.GetSSHCommand(c.Args()[1:]...)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sshCmd.Stdin = os.Stdin
|
|
||||||
sshCmd.Stdout = os.Stdout
|
|
||||||
sshCmd.Stderr = os.Stderr
|
|
||||||
if err := sshCmd.Run(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// machineCommand maps the command name to the corresponding machine command.
|
// machineCommand maps the command name to the corresponding machine command.
|
||||||
// We run commands concurrently and communicate back an error if there was one.
|
// We run commands concurrently and communicate back an error if there was one.
|
||||||
func machineCommand(actionName string, host *libmachine.Host, errorChan chan<- error) {
|
func machineCommand(actionName string, host *libmachine.Host, errorChan chan<- error) {
|
||||||
|
|
@ -965,55 +431,6 @@ func runActionWithContext(actionName string, c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdStart(c *cli.Context) {
|
|
||||||
if err := runActionWithContext("start", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdStop(c *cli.Context) {
|
|
||||||
if err := runActionWithContext("stop", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdRestart(c *cli.Context) {
|
|
||||||
if err := runActionWithContext("restart", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdKill(c *cli.Context) {
|
|
||||||
if err := runActionWithContext("kill", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdUpgrade(c *cli.Context) {
|
|
||||||
if err := runActionWithContext("upgrade", c); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdUrl(c *cli.Context) {
|
|
||||||
url, err := getHost(c).GetURL()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
func cmdNotFound(c *cli.Context, command string) {
|
|
||||||
log.Fatalf(
|
|
||||||
"%s: '%s' is not a %s command. See '%s --help'.",
|
|
||||||
c.App.Name,
|
|
||||||
command,
|
|
||||||
c.App.Name,
|
|
||||||
c.App.Name,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getHosts(c *cli.Context) ([]*libmachine.Host, error) {
|
func getHosts(c *cli.Context) ([]*libmachine.Host, error) {
|
||||||
machines := []*libmachine.Host{}
|
machines := []*libmachine.Host{}
|
||||||
for _, n := range c.Args() {
|
for _, n := range c.Args() {
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
package main
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
|
||||||
"github.com/docker/machine/drivers/fakedriver"
|
"github.com/docker/machine/drivers/fakedriver"
|
||||||
|
_ "github.com/docker/machine/drivers/none"
|
||||||
"github.com/docker/machine/libmachine"
|
"github.com/docker/machine/libmachine"
|
||||||
"github.com/docker/machine/libmachine/auth"
|
"github.com/docker/machine/libmachine/auth"
|
||||||
"github.com/docker/machine/libmachine/engine"
|
"github.com/docker/machine/libmachine/engine"
|
||||||
|
|
@ -310,288 +305,3 @@ func TestRunActionForeachMachine(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCmdConfig(t *testing.T) {
|
|
||||||
defer cleanup()
|
|
||||||
|
|
||||||
stdout := os.Stdout
|
|
||||||
r, w, _ := os.Pipe()
|
|
||||||
|
|
||||||
os.Stdout = w
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
os.Stdout = stdout
|
|
||||||
}()
|
|
||||||
|
|
||||||
store, err := getTestStore()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := libmachine.New(store)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := getTestDriverFlags()
|
|
||||||
hostOptions := &libmachine.HostOptions{
|
|
||||||
EngineOptions: &engine.EngineOptions{},
|
|
||||||
SwarmOptions: &swarm.SwarmOptions{
|
|
||||||
Master: false,
|
|
||||||
Discovery: "",
|
|
||||||
Address: "",
|
|
||||||
Host: "",
|
|
||||||
},
|
|
||||||
AuthOptions: &auth.AuthOptions{},
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := mcn.Create("test-a", "none", hostOptions, flags)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := store.SetActive(host); err != nil {
|
|
||||||
t.Fatalf("error setting active host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outStr := make(chan string)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
var testOutput bytes.Buffer
|
|
||||||
io.Copy(&testOutput, r)
|
|
||||||
outStr <- testOutput.String()
|
|
||||||
}()
|
|
||||||
|
|
||||||
set := flag.NewFlagSet("config", 0)
|
|
||||||
globalSet := flag.NewFlagSet("test", 0)
|
|
||||||
globalSet.String("storage-path", store.GetPath(), "")
|
|
||||||
|
|
||||||
c := cli.NewContext(nil, set, globalSet)
|
|
||||||
|
|
||||||
cmdConfig(c)
|
|
||||||
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
out := <-outStr
|
|
||||||
|
|
||||||
if !strings.Contains(out, "--tlsverify") {
|
|
||||||
t.Fatalf("Expect --tlsverify")
|
|
||||||
}
|
|
||||||
|
|
||||||
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
|
|
||||||
|
|
||||||
tlscacert := fmt.Sprintf("--tlscacert=\"%s/ca.pem\"", testMachineDir)
|
|
||||||
if !strings.Contains(out, tlscacert) {
|
|
||||||
t.Fatalf("Expected to find %s in %s", tlscacert, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
tlscert := fmt.Sprintf("--tlscert=\"%s/cert.pem\"", testMachineDir)
|
|
||||||
if !strings.Contains(out, tlscert) {
|
|
||||||
t.Fatalf("Expected to find %s in %s", tlscert, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
tlskey := fmt.Sprintf("--tlskey=\"%s/key.pem\"", testMachineDir)
|
|
||||||
if !strings.Contains(out, tlskey) {
|
|
||||||
t.Fatalf("Expected to find %s in %s", tlskey, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.Contains(out, "-H=unix:///var/run/docker.sock") {
|
|
||||||
t.Fatalf("Expect docker host URL")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmdEnvBash(t *testing.T) {
|
|
||||||
stdout := os.Stdout
|
|
||||||
shell := os.Getenv("SHELL")
|
|
||||||
r, w, _ := os.Pipe()
|
|
||||||
|
|
||||||
os.Stdout = w
|
|
||||||
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
|
|
||||||
os.Setenv("SHELL", "/bin/bash")
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
os.Setenv("MACHINE_STORAGE_PATH", "")
|
|
||||||
os.Setenv("SHELL", shell)
|
|
||||||
os.Stdout = stdout
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := clearHosts(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := getTestDriverFlags()
|
|
||||||
|
|
||||||
store, sErr := getTestStore()
|
|
||||||
if sErr != nil {
|
|
||||||
t.Fatal(sErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := libmachine.New(store)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostOptions := &libmachine.HostOptions{
|
|
||||||
EngineOptions: &engine.EngineOptions{},
|
|
||||||
SwarmOptions: &swarm.SwarmOptions{
|
|
||||||
Master: false,
|
|
||||||
Discovery: "",
|
|
||||||
Address: "",
|
|
||||||
Host: "",
|
|
||||||
},
|
|
||||||
AuthOptions: &auth.AuthOptions{},
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := mcn.Create("test-a", "none", hostOptions, flags)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err = mcn.Get("test-a")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error loading host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := mcn.SetActive(host); err != nil {
|
|
||||||
t.Fatalf("error setting active host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outStr := make(chan string)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
var testOutput bytes.Buffer
|
|
||||||
io.Copy(&testOutput, r)
|
|
||||||
outStr <- testOutput.String()
|
|
||||||
}()
|
|
||||||
|
|
||||||
set := flag.NewFlagSet("config", 0)
|
|
||||||
c := cli.NewContext(nil, set, set)
|
|
||||||
cmdEnv(c)
|
|
||||||
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
out := <-outStr
|
|
||||||
|
|
||||||
// parse the output into a map of envvar:value for easier testing below
|
|
||||||
envvars := make(map[string]string)
|
|
||||||
for _, e := range strings.Split(strings.TrimSpace(out), "\n") {
|
|
||||||
if !strings.HasPrefix(e, "export ") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
kv := strings.SplitN(e, "=", 2)
|
|
||||||
key, value := kv[0], kv[1]
|
|
||||||
envvars[strings.Replace(key, "export ", "", 1)] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
|
|
||||||
|
|
||||||
expected := map[string]string{
|
|
||||||
"DOCKER_TLS_VERIFY": "1",
|
|
||||||
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
|
|
||||||
"DOCKER_HOST": "unix:///var/run/docker.sock",
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range envvars {
|
|
||||||
if v != expected[k] {
|
|
||||||
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCmdEnvFish(t *testing.T) {
|
|
||||||
stdout := os.Stdout
|
|
||||||
shell := os.Getenv("SHELL")
|
|
||||||
r, w, _ := os.Pipe()
|
|
||||||
|
|
||||||
os.Stdout = w
|
|
||||||
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
|
|
||||||
os.Setenv("SHELL", "/bin/fish")
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
os.Setenv("MACHINE_STORAGE_PATH", "")
|
|
||||||
os.Setenv("SHELL", shell)
|
|
||||||
os.Stdout = stdout
|
|
||||||
}()
|
|
||||||
|
|
||||||
if err := clearHosts(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
flags := getTestDriverFlags()
|
|
||||||
|
|
||||||
store, err := getTestStore()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mcn, err := libmachine.New(store)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
hostOptions := &libmachine.HostOptions{
|
|
||||||
EngineOptions: &engine.EngineOptions{},
|
|
||||||
SwarmOptions: &swarm.SwarmOptions{
|
|
||||||
Master: false,
|
|
||||||
Discovery: "",
|
|
||||||
Address: "",
|
|
||||||
Host: "",
|
|
||||||
},
|
|
||||||
AuthOptions: &auth.AuthOptions{},
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := mcn.Create("test-a", "none", hostOptions, flags)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err = mcn.Get("test-a")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("error loading host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := mcn.SetActive(host); err != nil {
|
|
||||||
t.Fatalf("error setting active host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outStr := make(chan string)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
var testOutput bytes.Buffer
|
|
||||||
io.Copy(&testOutput, r)
|
|
||||||
outStr <- testOutput.String()
|
|
||||||
}()
|
|
||||||
|
|
||||||
set := flag.NewFlagSet("config", 0)
|
|
||||||
c := cli.NewContext(nil, set, set)
|
|
||||||
cmdEnv(c)
|
|
||||||
|
|
||||||
w.Close()
|
|
||||||
|
|
||||||
out := <-outStr
|
|
||||||
|
|
||||||
// parse the output into a map of envvar:value for easier testing below
|
|
||||||
envvars := make(map[string]string)
|
|
||||||
for _, e := range strings.Split(strings.TrimSuffix(out, ";\n"), ";\n") {
|
|
||||||
if !strings.HasPrefix(e, "set -x ") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
kv := strings.SplitN(strings.Replace(e, "set -x ", "", 1), " ", 2)
|
|
||||||
key, value := kv[0], kv[1]
|
|
||||||
envvars[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
|
|
||||||
|
|
||||||
expected := map[string]string{
|
|
||||||
"DOCKER_TLS_VERIFY": "1",
|
|
||||||
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
|
|
||||||
"DOCKER_HOST": "unix:///var/run/docker.sock",
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range envvars {
|
|
||||||
if v != expected[k] {
|
|
||||||
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdConfig(c *cli.Context) {
|
||||||
|
cfg, err := getMachineConfig(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerHost, err := getHost(c).Driver.GetURL()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Bool("swarm") {
|
||||||
|
if !cfg.SwarmOptions.Master {
|
||||||
|
log.Fatalf("%s is not a swarm master", cfg.machineName)
|
||||||
|
}
|
||||||
|
u, err := url.Parse(cfg.SwarmOptions.Host)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
parts := strings.Split(u.Host, ":")
|
||||||
|
swarmPort := parts[1]
|
||||||
|
|
||||||
|
// get IP of machine to replace in case swarm host is 0.0.0.0
|
||||||
|
mUrl, err := url.Parse(dockerHost)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
mParts := strings.Split(mUrl.Host, ":")
|
||||||
|
machineIp := mParts[0]
|
||||||
|
|
||||||
|
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug(dockerHost)
|
||||||
|
|
||||||
|
u, err := url.Parse(cfg.machineUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Scheme != "unix" {
|
||||||
|
// validate cert and regenerate if needed
|
||||||
|
valid, err := utils.ValidateCertificate(
|
||||||
|
u.Host,
|
||||||
|
cfg.caCertPath,
|
||||||
|
cfg.serverCertPath,
|
||||||
|
cfg.serverKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
|
||||||
|
|
||||||
|
if err := runActionWithContext("configureAuth", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("--tlsverify --tlscacert=%q --tlscert=%q --tlskey=%q -H=%s",
|
||||||
|
cfg.caCertPath, cfg.clientCertPath, cfg.clientKeyPath, dockerHost)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/libmachine"
|
||||||
|
"github.com/docker/machine/libmachine/auth"
|
||||||
|
"github.com/docker/machine/libmachine/engine"
|
||||||
|
"github.com/docker/machine/libmachine/swarm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCmdConfig(t *testing.T) {
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
stdout := os.Stdout
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
|
||||||
|
os.Stdout = w
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
os.Stdout = stdout
|
||||||
|
}()
|
||||||
|
|
||||||
|
store, err := getTestStore()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := libmachine.New(store)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := getTestDriverFlags()
|
||||||
|
hostOptions := &libmachine.HostOptions{
|
||||||
|
EngineOptions: &engine.EngineOptions{},
|
||||||
|
SwarmOptions: &swarm.SwarmOptions{
|
||||||
|
Master: false,
|
||||||
|
Discovery: "",
|
||||||
|
Address: "",
|
||||||
|
Host: "",
|
||||||
|
},
|
||||||
|
AuthOptions: &auth.AuthOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := mcn.Create("test-a", "none", hostOptions, flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := store.SetActive(host); err != nil {
|
||||||
|
t.Fatalf("error setting active host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outStr := make(chan string)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var testOutput bytes.Buffer
|
||||||
|
io.Copy(&testOutput, r)
|
||||||
|
outStr <- testOutput.String()
|
||||||
|
}()
|
||||||
|
|
||||||
|
set := flag.NewFlagSet("config", 0)
|
||||||
|
globalSet := flag.NewFlagSet("test", 0)
|
||||||
|
globalSet.String("storage-path", store.GetPath(), "")
|
||||||
|
|
||||||
|
c := cli.NewContext(nil, set, globalSet)
|
||||||
|
|
||||||
|
cmdConfig(c)
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
out := <-outStr
|
||||||
|
|
||||||
|
if !strings.Contains(out, "--tlsverify") {
|
||||||
|
t.Fatalf("Expect --tlsverify")
|
||||||
|
}
|
||||||
|
|
||||||
|
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
|
||||||
|
|
||||||
|
tlscacert := fmt.Sprintf("--tlscacert=\"%s/ca.pem\"", testMachineDir)
|
||||||
|
if !strings.Contains(out, tlscacert) {
|
||||||
|
t.Fatalf("Expected to find %s in %s", tlscacert, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlscert := fmt.Sprintf("--tlscert=\"%s/cert.pem\"", testMachineDir)
|
||||||
|
if !strings.Contains(out, tlscert) {
|
||||||
|
t.Fatalf("Expected to find %s in %s", tlscert, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
tlskey := fmt.Sprintf("--tlskey=\"%s/key.pem\"", testMachineDir)
|
||||||
|
if !strings.Contains(out, tlskey) {
|
||||||
|
t.Fatalf("Expected to find %s in %s", tlskey, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(out, "-H=unix:///var/run/docker.sock") {
|
||||||
|
t.Fatalf("Expect docker host URL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/drivers"
|
||||||
|
"github.com/docker/machine/libmachine"
|
||||||
|
"github.com/docker/machine/libmachine/auth"
|
||||||
|
"github.com/docker/machine/libmachine/engine"
|
||||||
|
"github.com/docker/machine/libmachine/swarm"
|
||||||
|
"github.com/docker/machine/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdCreate(c *cli.Context) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
driver := c.String("driver")
|
||||||
|
name := c.Args().First()
|
||||||
|
|
||||||
|
// TODO: Not really a fan of "none" as the default driver...
|
||||||
|
if driver != "none" {
|
||||||
|
c.App.Commands, err = trimDriverFlags(driver, c.App.Commands)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
cli.ShowCommandHelp(c, "create")
|
||||||
|
log.Fatal("You must specify a machine name")
|
||||||
|
}
|
||||||
|
|
||||||
|
certInfo := getCertPathInfo(c)
|
||||||
|
|
||||||
|
if err := setupCertificates(
|
||||||
|
certInfo.CaCertPath,
|
||||||
|
certInfo.CaKeyPath,
|
||||||
|
certInfo.ClientCertPath,
|
||||||
|
certInfo.ClientKeyPath); err != nil {
|
||||||
|
log.Fatalf("Error generating certificates: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultStore, err := getDefaultStore(
|
||||||
|
c.GlobalString("storage-path"),
|
||||||
|
certInfo.CaCertPath,
|
||||||
|
certInfo.CaKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := newMcn(defaultStore)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostOptions := &libmachine.HostOptions{
|
||||||
|
AuthOptions: &auth.AuthOptions{
|
||||||
|
CaCertPath: certInfo.CaCertPath,
|
||||||
|
PrivateKeyPath: certInfo.CaKeyPath,
|
||||||
|
ClientCertPath: certInfo.ClientCertPath,
|
||||||
|
ClientKeyPath: certInfo.ClientKeyPath,
|
||||||
|
ServerCertPath: filepath.Join(utils.GetMachineDir(), name, "server.pem"),
|
||||||
|
ServerKeyPath: filepath.Join(utils.GetMachineDir(), name, "server-key.pem"),
|
||||||
|
},
|
||||||
|
EngineOptions: &engine.EngineOptions{},
|
||||||
|
SwarmOptions: &swarm.SwarmOptions{
|
||||||
|
IsSwarm: c.Bool("swarm"),
|
||||||
|
Master: c.Bool("swarm-master"),
|
||||||
|
Discovery: c.String("swarm-discovery"),
|
||||||
|
Address: c.String("swarm-addr"),
|
||||||
|
Host: c.String("swarm-host"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := mcn.Create(name, driver, hostOptions, c)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Error creating machine: %s", err)
|
||||||
|
log.Warn("You will want to check the provider to make sure the machine and associated resources were properly removed.")
|
||||||
|
log.Fatal("Error creating machine")
|
||||||
|
}
|
||||||
|
if err := mcn.SetActive(host); err != nil {
|
||||||
|
log.Fatalf("error setting active host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
info := ""
|
||||||
|
userShell := filepath.Base(os.Getenv("SHELL"))
|
||||||
|
|
||||||
|
switch userShell {
|
||||||
|
case "fish":
|
||||||
|
info = fmt.Sprintf("%s env %s | source", c.App.Name, name)
|
||||||
|
default:
|
||||||
|
info = fmt.Sprintf(`eval "$(%s env %s)"`, c.App.Name, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("%q has been created and is now the active machine.", name)
|
||||||
|
|
||||||
|
if info != "" {
|
||||||
|
log.Infof("To point your Docker client at it, run this in your shell: %s", info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user has specified a driver, they should not see the flags for all
|
||||||
|
// of the drivers in `docker-machine create`. This method replaces the 100+
|
||||||
|
// create flags with only the ones applicable to the driver specified
|
||||||
|
func trimDriverFlags(driver string, cmds []cli.Command) ([]cli.Command, error) {
|
||||||
|
filteredCmds := cmds
|
||||||
|
driverFlags, err := drivers.GetCreateFlagsForDriver(driver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, cmd := range cmds {
|
||||||
|
if cmd.HasName("create") {
|
||||||
|
filteredCmds[i].Flags = append(driverFlags, sharedCreateFlags...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredCmds, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdEnv(c *cli.Context) {
|
||||||
|
userShell := filepath.Base(os.Getenv("SHELL"))
|
||||||
|
if c.Bool("unset") {
|
||||||
|
switch userShell {
|
||||||
|
case "fish":
|
||||||
|
fmt.Printf("set -e DOCKER_TLS_VERIFY;\nset -e DOCKER_CERT_PATH;\nset -e DOCKER_HOST;\n")
|
||||||
|
default:
|
||||||
|
fmt.Println("unset DOCKER_TLS_VERIFY DOCKER_CERT_PATH DOCKER_HOST")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := getMachineConfig(c)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.machineUrl == "" {
|
||||||
|
log.Fatalf("%s is not running. Please start this with docker-machine start %s", cfg.machineName, cfg.machineName)
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerHost := cfg.machineUrl
|
||||||
|
if c.Bool("swarm") {
|
||||||
|
if !cfg.SwarmOptions.Master {
|
||||||
|
log.Fatalf("%s is not a swarm master", cfg.machineName)
|
||||||
|
}
|
||||||
|
u, err := url.Parse(cfg.SwarmOptions.Host)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
parts := strings.Split(u.Host, ":")
|
||||||
|
swarmPort := parts[1]
|
||||||
|
|
||||||
|
// get IP of machine to replace in case swarm host is 0.0.0.0
|
||||||
|
mUrl, err := url.Parse(cfg.machineUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
mParts := strings.Split(mUrl.Host, ":")
|
||||||
|
machineIp := mParts[0]
|
||||||
|
|
||||||
|
dockerHost = fmt.Sprintf("tcp://%s:%s", machineIp, swarmPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(cfg.machineUrl)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Scheme != "unix" {
|
||||||
|
// validate cert and regenerate if needed
|
||||||
|
valid, err := utils.ValidateCertificate(
|
||||||
|
u.Host,
|
||||||
|
cfg.caCertPath,
|
||||||
|
cfg.serverCertPath,
|
||||||
|
cfg.serverKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
log.Debugf("invalid certs detected; regenerating for %s", u.Host)
|
||||||
|
|
||||||
|
if err := runActionWithContext("configureAuth", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usageHint := generateUsageHint(c.Args().First(), userShell)
|
||||||
|
|
||||||
|
switch userShell {
|
||||||
|
case "fish":
|
||||||
|
fmt.Printf("set -x DOCKER_TLS_VERIFY 1;\nset -x DOCKER_CERT_PATH %q;\nset -x DOCKER_HOST %s;\n\n%s\n",
|
||||||
|
cfg.machineDir, dockerHost, usageHint)
|
||||||
|
default:
|
||||||
|
fmt.Printf("export DOCKER_TLS_VERIFY=1\nexport DOCKER_CERT_PATH=%q\nexport DOCKER_HOST=%s\n\n%s\n",
|
||||||
|
cfg.machineDir, dockerHost, usageHint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateUsageHint(machineName string, userShell string) string {
|
||||||
|
cmd := ""
|
||||||
|
switch userShell {
|
||||||
|
case "fish":
|
||||||
|
if machineName != "" {
|
||||||
|
cmd = fmt.Sprintf("eval (docker-machine env %s)", machineName)
|
||||||
|
} else {
|
||||||
|
cmd = "eval (docker-machine env)"
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if machineName != "" {
|
||||||
|
cmd = fmt.Sprintf("eval \"$(docker-machine env %s)\"", machineName)
|
||||||
|
} else {
|
||||||
|
cmd = "eval \"$(docker-machine env)\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("# Run this command to configure your shell: %s\n", cmd)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/libmachine"
|
||||||
|
"github.com/docker/machine/libmachine/auth"
|
||||||
|
"github.com/docker/machine/libmachine/engine"
|
||||||
|
"github.com/docker/machine/libmachine/swarm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCmdEnvBash(t *testing.T) {
|
||||||
|
stdout := os.Stdout
|
||||||
|
shell := os.Getenv("SHELL")
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
|
||||||
|
os.Stdout = w
|
||||||
|
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
|
||||||
|
os.Setenv("SHELL", "/bin/bash")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
os.Setenv("MACHINE_STORAGE_PATH", "")
|
||||||
|
os.Setenv("SHELL", shell)
|
||||||
|
os.Stdout = stdout
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := clearHosts(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := getTestDriverFlags()
|
||||||
|
|
||||||
|
store, sErr := getTestStore()
|
||||||
|
if sErr != nil {
|
||||||
|
t.Fatal(sErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := libmachine.New(store)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostOptions := &libmachine.HostOptions{
|
||||||
|
EngineOptions: &engine.EngineOptions{},
|
||||||
|
SwarmOptions: &swarm.SwarmOptions{
|
||||||
|
Master: false,
|
||||||
|
Discovery: "",
|
||||||
|
Address: "",
|
||||||
|
Host: "",
|
||||||
|
},
|
||||||
|
AuthOptions: &auth.AuthOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := mcn.Create("test-a", "none", hostOptions, flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err = mcn.Get("test-a")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mcn.SetActive(host); err != nil {
|
||||||
|
t.Fatalf("error setting active host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outStr := make(chan string)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var testOutput bytes.Buffer
|
||||||
|
io.Copy(&testOutput, r)
|
||||||
|
outStr <- testOutput.String()
|
||||||
|
}()
|
||||||
|
|
||||||
|
set := flag.NewFlagSet("config", 0)
|
||||||
|
c := cli.NewContext(nil, set, set)
|
||||||
|
cmdEnv(c)
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
out := <-outStr
|
||||||
|
|
||||||
|
// parse the output into a map of envvar:value for easier testing below
|
||||||
|
envvars := make(map[string]string)
|
||||||
|
for _, e := range strings.Split(strings.TrimSpace(out), "\n") {
|
||||||
|
if !strings.HasPrefix(e, "export ") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kv := strings.SplitN(e, "=", 2)
|
||||||
|
key, value := kv[0], kv[1]
|
||||||
|
envvars[strings.Replace(key, "export ", "", 1)] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
|
||||||
|
|
||||||
|
expected := map[string]string{
|
||||||
|
"DOCKER_TLS_VERIFY": "1",
|
||||||
|
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
|
||||||
|
"DOCKER_HOST": "unix:///var/run/docker.sock",
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range envvars {
|
||||||
|
if v != expected[k] {
|
||||||
|
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCmdEnvFish(t *testing.T) {
|
||||||
|
stdout := os.Stdout
|
||||||
|
shell := os.Getenv("SHELL")
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
|
||||||
|
os.Stdout = w
|
||||||
|
os.Setenv("MACHINE_STORAGE_PATH", TestStoreDir)
|
||||||
|
os.Setenv("SHELL", "/bin/fish")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
os.Setenv("MACHINE_STORAGE_PATH", "")
|
||||||
|
os.Setenv("SHELL", shell)
|
||||||
|
os.Stdout = stdout
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := clearHosts(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
flags := getTestDriverFlags()
|
||||||
|
|
||||||
|
store, err := getTestStore()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := libmachine.New(store)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostOptions := &libmachine.HostOptions{
|
||||||
|
EngineOptions: &engine.EngineOptions{},
|
||||||
|
SwarmOptions: &swarm.SwarmOptions{
|
||||||
|
Master: false,
|
||||||
|
Discovery: "",
|
||||||
|
Address: "",
|
||||||
|
Host: "",
|
||||||
|
},
|
||||||
|
AuthOptions: &auth.AuthOptions{},
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := mcn.Create("test-a", "none", hostOptions, flags)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err = mcn.Get("test-a")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("error loading host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mcn.SetActive(host); err != nil {
|
||||||
|
t.Fatalf("error setting active host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outStr := make(chan string)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
var testOutput bytes.Buffer
|
||||||
|
io.Copy(&testOutput, r)
|
||||||
|
outStr <- testOutput.String()
|
||||||
|
}()
|
||||||
|
|
||||||
|
set := flag.NewFlagSet("config", 0)
|
||||||
|
c := cli.NewContext(nil, set, set)
|
||||||
|
cmdEnv(c)
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
out := <-outStr
|
||||||
|
|
||||||
|
// parse the output into a map of envvar:value for easier testing below
|
||||||
|
envvars := make(map[string]string)
|
||||||
|
for _, e := range strings.Split(strings.TrimSuffix(out, ";\n"), ";\n") {
|
||||||
|
if !strings.HasPrefix(e, "set -x ") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
kv := strings.SplitN(strings.Replace(e, "set -x ", "", 1), " ", 2)
|
||||||
|
key, value := kv[0], kv[1]
|
||||||
|
envvars[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
testMachineDir := filepath.Join(store.GetPath(), "machines", host.Name)
|
||||||
|
|
||||||
|
expected := map[string]string{
|
||||||
|
"DOCKER_TLS_VERIFY": "1",
|
||||||
|
"DOCKER_CERT_PATH": fmt.Sprintf("\"%s\"", testMachineDir),
|
||||||
|
"DOCKER_HOST": "unix:///var/run/docker.sock",
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range envvars {
|
||||||
|
if v != expected[k] {
|
||||||
|
t.Fatalf("Expected %s == <%s>, but was <%s>", k, expected[k], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdInspect(c *cli.Context) {
|
||||||
|
prettyJSON, err := json.MarshalIndent(getHost(c), "", " ")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(prettyJSON))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdIp(c *cli.Context) {
|
||||||
|
ip, err := getHost(c).Driver.GetIP()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(ip)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdKill(c *cli.Context) {
|
||||||
|
if err := runActionWithContext("kill", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"text/tabwriter"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdLs(c *cli.Context) {
|
||||||
|
quiet := c.Bool("quiet")
|
||||||
|
|
||||||
|
certInfo := getCertPathInfo(c)
|
||||||
|
defaultStore, err := getDefaultStore(
|
||||||
|
c.GlobalString("storage-path"),
|
||||||
|
certInfo.CaCertPath,
|
||||||
|
certInfo.CaKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := newMcn(defaultStore)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostList, err := mcn.List()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM")
|
||||||
|
}
|
||||||
|
|
||||||
|
items := []hostListItem{}
|
||||||
|
hostListItems := make(chan hostListItem)
|
||||||
|
|
||||||
|
swarmMasters := make(map[string]string)
|
||||||
|
swarmInfo := make(map[string]string)
|
||||||
|
|
||||||
|
for _, host := range hostList {
|
||||||
|
swarmOptions := host.HostOptions.SwarmOptions
|
||||||
|
if !quiet {
|
||||||
|
if swarmOptions.Master {
|
||||||
|
swarmMasters[swarmOptions.Discovery] = host.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
if swarmOptions.Discovery != "" {
|
||||||
|
swarmInfo[host.Name] = swarmOptions.Discovery
|
||||||
|
}
|
||||||
|
|
||||||
|
go getHostState(*host, defaultStore, hostListItems)
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(w, "%s\n", host.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !quiet {
|
||||||
|
for i := 0; i < len(hostList); i++ {
|
||||||
|
items = append(items, <-hostListItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(hostListItems)
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdRestart(c *cli.Context) {
|
||||||
|
if err := runActionWithContext("restart", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdRm(c *cli.Context) {
|
||||||
|
if len(c.Args()) == 0 {
|
||||||
|
cli.ShowCommandHelp(c, "rm")
|
||||||
|
log.Fatal("You must specify a machine name")
|
||||||
|
}
|
||||||
|
|
||||||
|
force := c.Bool("force")
|
||||||
|
|
||||||
|
isError := false
|
||||||
|
|
||||||
|
certInfo := getCertPathInfo(c)
|
||||||
|
defaultStore, err := getDefaultStore(
|
||||||
|
c.GlobalString("storage-path"),
|
||||||
|
certInfo.CaCertPath,
|
||||||
|
certInfo.CaKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := newMcn(defaultStore)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, host := range c.Args() {
|
||||||
|
if err := mcn.Remove(host, force); err != nil {
|
||||||
|
log.Errorf("Error removing machine %s: %s", host, err)
|
||||||
|
isError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isError {
|
||||||
|
log.Fatal("There was an error removing a machine. To force remove it, pass the -f option. Warning: this might leave it running on the provider.")
|
||||||
|
}
|
||||||
|
log.Print("The machine was successfully removed.")
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/docker/machine/drivers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdSsh(c *cli.Context) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
sshCmd *exec.Cmd
|
||||||
|
)
|
||||||
|
name := c.Args().First()
|
||||||
|
|
||||||
|
certInfo := getCertPathInfo(c)
|
||||||
|
defaultStore, err := getDefaultStore(
|
||||||
|
c.GlobalString("storage-path"),
|
||||||
|
certInfo.CaCertPath,
|
||||||
|
certInfo.CaKeyPath,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mcn, err := newMcn(defaultStore)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
host, err := mcn.GetActive()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("unable to get active host: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if host == nil {
|
||||||
|
log.Fatalf("There is no active host. Please set it with %s active <machine name>.", c.App.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
name = host.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
host, err := mcn.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = host.GetURL()
|
||||||
|
if err != nil {
|
||||||
|
if err == drivers.ErrHostIsNotRunning {
|
||||||
|
log.Fatalf("%s is not running. Please start this with docker-machine start %s", host.Name, host.Name)
|
||||||
|
} else {
|
||||||
|
log.Fatalf("Unexpected error getting machine url: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.Args()) <= 1 {
|
||||||
|
sshCmd, err = host.GetSSHCommand()
|
||||||
|
} else {
|
||||||
|
sshCmd, err = host.GetSSHCommand(c.Args()[1:]...)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sshCmd.Stdin = os.Stdin
|
||||||
|
sshCmd.Stdout = os.Stdout
|
||||||
|
sshCmd.Stderr = os.Stderr
|
||||||
|
if err := sshCmd.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdStart(c *cli.Context) {
|
||||||
|
if err := runActionWithContext("start", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdStop(c *cli.Context) {
|
||||||
|
if err := runActionWithContext("stop", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdUpgrade(c *cli.Context) {
|
||||||
|
if err := runActionWithContext("upgrade", c); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func cmdUrl(c *cli.Context) {
|
||||||
|
url, err := getHost(c).GetURL()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(url)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package commands
|
||||||
14
main.go
14
main.go
|
|
@ -6,6 +6,8 @@ import (
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
|
||||||
|
"github.com/docker/machine/commands"
|
||||||
"github.com/docker/machine/utils"
|
"github.com/docker/machine/utils"
|
||||||
"github.com/docker/machine/version"
|
"github.com/docker/machine/version"
|
||||||
)
|
)
|
||||||
|
|
@ -26,7 +28,7 @@ func main() {
|
||||||
os.Setenv("MACHINE_STORAGE_PATH", c.GlobalString("storage-path"))
|
os.Setenv("MACHINE_STORAGE_PATH", c.GlobalString("storage-path"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
app.Commands = Commands
|
app.Commands = commands.Commands
|
||||||
app.CommandNotFound = cmdNotFound
|
app.CommandNotFound = cmdNotFound
|
||||||
app.Usage = "Create and manage machines running Docker."
|
app.Usage = "Create and manage machines running Docker."
|
||||||
app.Version = version.VERSION + " (" + version.GITCOMMIT + ")"
|
app.Version = version.VERSION + " (" + version.GITCOMMIT + ")"
|
||||||
|
|
@ -70,3 +72,13 @@ func main() {
|
||||||
|
|
||||||
app.Run(os.Args)
|
app.Run(os.Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cmdNotFound(c *cli.Context, command string) {
|
||||||
|
log.Fatalf(
|
||||||
|
"%s: '%s' is not a %s command. See '%s --help'.",
|
||||||
|
c.App.Name,
|
||||||
|
command,
|
||||||
|
c.App.Name,
|
||||||
|
c.App.Name,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package main
|
||||||
Loading…
Reference in New Issue