mirror of https://github.com/docker/docs.git
Merge pull request #1103 from nathanleclaire/active_based_on_env
Read active host from DOCKER_HOST instead of from file
This commit is contained in:
commit
e4b6ff1ae9
|
@ -8,7 +8,9 @@ import (
|
|||
)
|
||||
|
||||
func cmdActive(c *cli.Context) {
|
||||
name := c.Args().First()
|
||||
if len(c.Args()) > 0 {
|
||||
log.Fatal("Error: Too many arguments given.")
|
||||
}
|
||||
|
||||
certInfo := getCertPathInfo(c)
|
||||
defaultStore, err := getDefaultStore(
|
||||
|
@ -25,24 +27,12 @@ func cmdActive(c *cli.Context) {
|
|||
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)
|
||||
}
|
||||
host, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting active host: %s", err)
|
||||
}
|
||||
|
||||
if err := mcn.SetActive(host); err != nil {
|
||||
log.Fatalf("error setting active host: %v", err)
|
||||
}
|
||||
} else {
|
||||
cli.ShowCommandHelp(c, "active")
|
||||
if host != nil {
|
||||
fmt.Println(host.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,12 +32,13 @@ import (
|
|||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
"github.com/docker/machine/log"
|
||||
"github.com/docker/machine/state"
|
||||
"github.com/docker/machine/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnknownShell = errors.New("unknown shell")
|
||||
ErrUnknownShell = errors.New("Error: Unknown shell")
|
||||
ErrNoMachineSpecified = errors.New("Error: Expected to get one or more machine names as arguments.")
|
||||
ErrExpectedOneMachine = errors.New("Error: Expected one machine name as an argument.")
|
||||
)
|
||||
|
||||
type machineConfig struct {
|
||||
|
@ -54,17 +55,8 @@ type machineConfig struct {
|
|||
SwarmOptions swarm.SwarmOptions
|
||||
}
|
||||
|
||||
type hostListItem struct {
|
||||
Name string
|
||||
Active bool
|
||||
DriverName string
|
||||
State state.State
|
||||
URL string
|
||||
SwarmOptions swarm.SwarmOptions
|
||||
}
|
||||
|
||||
func sortHostListItemsByName(items []hostListItem) {
|
||||
m := make(map[string]hostListItem, len(items))
|
||||
func sortHostListItemsByName(items []libmachine.HostListItem) {
|
||||
m := make(map[string]libmachine.HostListItem, len(items))
|
||||
s := make([]string, len(items))
|
||||
for i, v := range items {
|
||||
name := strings.ToLower(v.Name)
|
||||
|
@ -226,13 +218,13 @@ var sharedCreateFlags = []cli.Flag{
|
|||
var Commands = []cli.Command{
|
||||
{
|
||||
Name: "active",
|
||||
Usage: "Get or set the active machine",
|
||||
Usage: "Print which machine is active",
|
||||
Action: cmdActive,
|
||||
},
|
||||
{
|
||||
Name: "config",
|
||||
Usage: "Print the connection config for machine",
|
||||
Description: "Argument is a machine name. Will use the active machine if none is provided.",
|
||||
Description: "Argument is a machine name.",
|
||||
Action: cmdConfig,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
|
@ -253,7 +245,7 @@ var Commands = []cli.Command{
|
|||
{
|
||||
Name: "env",
|
||||
Usage: "Display the commands to set up the environment for the Docker client",
|
||||
Description: "Argument is a machine name. Will use the active machine if none is provided.",
|
||||
Description: "Argument is a machine name.",
|
||||
Action: cmdEnv,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
|
@ -273,7 +265,7 @@ var Commands = []cli.Command{
|
|||
{
|
||||
Name: "inspect",
|
||||
Usage: "Inspect information about a machine",
|
||||
Description: "Argument is a machine name. Will use the active machine if none is provided.",
|
||||
Description: "Argument is a machine name.",
|
||||
Action: cmdInspect,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
|
@ -286,13 +278,13 @@ var Commands = []cli.Command{
|
|||
{
|
||||
Name: "ip",
|
||||
Usage: "Get the IP address of a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdIp,
|
||||
},
|
||||
{
|
||||
Name: "kill",
|
||||
Usage: "Kill a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdKill,
|
||||
},
|
||||
{
|
||||
|
@ -309,7 +301,7 @@ var Commands = []cli.Command{
|
|||
{
|
||||
Name: "regenerate-certs",
|
||||
Usage: "Regenerate TLS Certificates for a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdRegenerateCerts,
|
||||
Flags: []cli.Flag{
|
||||
cli.BoolFlag{
|
||||
|
@ -321,7 +313,7 @@ var Commands = []cli.Command{
|
|||
{
|
||||
Name: "restart",
|
||||
Usage: "Restart a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdRestart,
|
||||
},
|
||||
{
|
||||
|
@ -338,32 +330,32 @@ var Commands = []cli.Command{
|
|||
},
|
||||
{
|
||||
Name: "ssh",
|
||||
Usage: "Log into or run a command on a machine with SSH",
|
||||
Description: "Arguments are [machine-name] command - Will use the active machine if none is provided.",
|
||||
Usage: "Log into or run a command on a machine with SSH.",
|
||||
Description: "Arguments are [machine-name] [command]",
|
||||
Action: cmdSsh,
|
||||
},
|
||||
{
|
||||
Name: "start",
|
||||
Usage: "Start a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdStart,
|
||||
},
|
||||
{
|
||||
Name: "stop",
|
||||
Usage: "Stop a machine",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdStop,
|
||||
},
|
||||
{
|
||||
Name: "upgrade",
|
||||
Usage: "Upgrade a machine to the latest version of Docker",
|
||||
Description: "Argument(s) are one or more machine names. Will use the active machine if none is provided.",
|
||||
Description: "Argument(s) are one or more machine names.",
|
||||
Action: cmdUpgrade,
|
||||
},
|
||||
{
|
||||
Name: "url",
|
||||
Usage: "Get the URL of a machine",
|
||||
Description: "Argument is a machine name. Will use the active machine if none is provided.",
|
||||
Description: "Argument is a machine name.",
|
||||
Action: cmdUrl,
|
||||
},
|
||||
}
|
||||
|
@ -443,31 +435,8 @@ func runActionWithContext(actionName string, c *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// No args specified, so use active.
|
||||
if len(machines) == 0 {
|
||||
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)
|
||||
}
|
||||
|
||||
activeHost, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to get active host: %v", err)
|
||||
}
|
||||
if activeHost == nil {
|
||||
log.Fatalf("There is no active host. Please set it with %s active <machine name>.", c.App.Name)
|
||||
}
|
||||
machines = []*libmachine.Host{activeHost}
|
||||
log.Fatal(ErrNoMachineSpecified)
|
||||
}
|
||||
|
||||
runActionForeachMachine(actionName, machines)
|
||||
|
@ -530,18 +499,6 @@ func getHost(c *cli.Context) *libmachine.Host {
|
|||
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.Fatal("unable to get active host, active file not found")
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
host, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to load host: %v", err)
|
||||
|
@ -549,35 +506,23 @@ func getHost(c *cli.Context) *libmachine.Host {
|
|||
return host
|
||||
}
|
||||
|
||||
func getHostState(host libmachine.Host, store libmachine.Store, hostListItems chan<- hostListItem) {
|
||||
currentState, err := host.Driver.GetState()
|
||||
func getDefaultMcn(c *cli.Context) *libmachine.Machine {
|
||||
certInfo := getCertPathInfo(c)
|
||||
defaultStore, err := getDefaultStore(
|
||||
c.GlobalString("storage-path"),
|
||||
certInfo.CaCertPath,
|
||||
certInfo.CaKeyPath,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("error getting state for host %s: %s", host.Name, err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
url, err := host.GetURL()
|
||||
mcn, err := newMcn(defaultStore)
|
||||
if err != nil {
|
||||
if err == drivers.ErrHostIsNotRunning {
|
||||
url = ""
|
||||
} else {
|
||||
log.Errorf("error getting URL for host %s: %s", host.Name, err)
|
||||
}
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
isActive, err := store.IsActive(&host)
|
||||
if err != nil {
|
||||
log.Debugf("error determining whether host %q is active: %s",
|
||||
host.Name, err)
|
||||
}
|
||||
|
||||
hostListItems <- hostListItem{
|
||||
Name: host.Name,
|
||||
Active: isActive,
|
||||
DriverName: host.Driver.DriverName(),
|
||||
State: currentState,
|
||||
URL: url,
|
||||
SwarmOptions: *host.HostOptions.SwarmOptions,
|
||||
}
|
||||
return mcn
|
||||
}
|
||||
|
||||
func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
||||
|
@ -597,33 +542,16 @@ func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var machine *libmachine.Host
|
||||
m, err := mcn.Get(name)
|
||||
|
||||
if name == "" {
|
||||
m, err := mcn.GetActive()
|
||||
if err != nil {
|
||||
log.Fatalf("error getting active host: %v", err)
|
||||
}
|
||||
if m == nil {
|
||||
return nil, fmt.Errorf("There is no active host")
|
||||
}
|
||||
machine = m
|
||||
} else {
|
||||
m, err := mcn.Get(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error loading machine config: %s", err)
|
||||
}
|
||||
machine = m
|
||||
}
|
||||
|
||||
machineDir := filepath.Join(utils.GetMachineDir(), machine.Name)
|
||||
machineDir := filepath.Join(utils.GetMachineDir(), m.Name)
|
||||
caCert := filepath.Join(machineDir, "ca.pem")
|
||||
caKey := filepath.Join(utils.GetMachineCertDir(), "ca-key.pem")
|
||||
clientCert := filepath.Join(machineDir, "cert.pem")
|
||||
clientKey := filepath.Join(machineDir, "key.pem")
|
||||
serverCert := filepath.Join(machineDir, "server.pem")
|
||||
serverKey := filepath.Join(machineDir, "server-key.pem")
|
||||
machineUrl, err := machine.GetURL()
|
||||
machineUrl, err := m.GetURL()
|
||||
if err != nil {
|
||||
if err == drivers.ErrHostIsNotRunning {
|
||||
machineUrl = ""
|
||||
|
@ -641,8 +569,8 @@ func getMachineConfig(c *cli.Context) (*machineConfig, error) {
|
|||
caKeyPath: caKey,
|
||||
caCertPath: caCert,
|
||||
serverKeyPath: serverKey,
|
||||
AuthOptions: *machine.HostOptions.AuthOptions,
|
||||
SwarmOptions: *machine.HostOptions.SwarmOptions,
|
||||
AuthOptions: *m.HostOptions.AuthOptions,
|
||||
SwarmOptions: *m.HostOptions.SwarmOptions,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -119,91 +119,6 @@ func (d DriverOptionsMock) Int(key string) int {
|
|||
func (d DriverOptionsMock) Bool(key string) bool {
|
||||
return d.Data[key].(bool)
|
||||
}
|
||||
func TestGetHostState(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
hostListItems := make(chan hostListItem)
|
||||
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts := []libmachine.Host{
|
||||
{
|
||||
Name: "foo",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &fakedriver.FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
StorePath: store.GetPath(),
|
||||
HostOptions: &libmachine.HostOptions{
|
||||
SwarmOptions: &swarm.SwarmOptions{
|
||||
Master: false,
|
||||
Address: "",
|
||||
Discovery: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &fakedriver.FakeDriver{
|
||||
MockState: state.Stopped,
|
||||
},
|
||||
StorePath: store.GetPath(),
|
||||
HostOptions: &libmachine.HostOptions{
|
||||
SwarmOptions: &swarm.SwarmOptions{
|
||||
Master: false,
|
||||
Address: "",
|
||||
Discovery: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &fakedriver.FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
StorePath: store.GetPath(),
|
||||
HostOptions: &libmachine.HostOptions{
|
||||
SwarmOptions: &swarm.SwarmOptions{
|
||||
Master: false,
|
||||
Address: "",
|
||||
Discovery: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, h := range hosts {
|
||||
if err := store.Save(&h); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
expected := map[string]state.State{
|
||||
"foo": state.Running,
|
||||
"bar": state.Stopped,
|
||||
"baz": state.Running,
|
||||
}
|
||||
|
||||
items := []hostListItem{}
|
||||
for _, host := range hosts {
|
||||
go getHostState(host, store, hostListItems)
|
||||
}
|
||||
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
items = append(items, <-hostListItems)
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if expected[item.Name] != item.State {
|
||||
t.Fatal("Expected state did not match for item", item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunActionForeachMachine(t *testing.T) {
|
||||
storePath, err := ioutil.TempDir("", ".docker")
|
||||
|
|
|
@ -11,6 +11,9 @@ import (
|
|||
)
|
||||
|
||||
func cmdConfig(c *cli.Context) {
|
||||
if len(c.Args()) != 1 {
|
||||
log.Fatal(ErrExpectedOneMachine)
|
||||
}
|
||||
cfg, err := getMachineConfig(c)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
@ -56,10 +56,6 @@ func TestCmdConfig(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := store.SetActive(host); err != nil {
|
||||
t.Fatalf("error setting active host: %v", err)
|
||||
}
|
||||
|
||||
outStr := make(chan string)
|
||||
|
||||
go func() {
|
||||
|
@ -69,6 +65,7 @@ func TestCmdConfig(t *testing.T) {
|
|||
}()
|
||||
|
||||
set := flag.NewFlagSet("config", 0)
|
||||
set.Parse([]string{"test-a"})
|
||||
globalSet := flag.NewFlagSet("test", 0)
|
||||
globalSet.String("storage-path", store.GetPath(), "")
|
||||
|
||||
|
|
|
@ -85,14 +85,10 @@ func cmdCreate(c *cli.Context) {
|
|||
},
|
||||
}
|
||||
|
||||
host, err := mcn.Create(name, driver, hostOptions, c)
|
||||
_, 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)
|
||||
log.Fatal("You will want to check the provider to make sure the machine and associated resources were properly removed.")
|
||||
}
|
||||
|
||||
info := fmt.Sprintf("%s env %s", c.App.Name, name)
|
||||
|
|
|
@ -28,6 +28,9 @@ type ShellConfig struct {
|
|||
}
|
||||
|
||||
func cmdEnv(c *cli.Context) {
|
||||
if len(c.Args()) > 1 {
|
||||
log.Fatal("Error: Expected either a machine name, or -u flag to unset the variables in the arguments.")
|
||||
}
|
||||
userShell := c.String("shell")
|
||||
if userShell == "" {
|
||||
shell, err := detectShell()
|
||||
|
|
|
@ -69,10 +69,6 @@ func TestCmdEnvBash(t *testing.T) {
|
|||
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() {
|
||||
|
@ -82,6 +78,7 @@ func TestCmdEnvBash(t *testing.T) {
|
|||
}()
|
||||
|
||||
set := flag.NewFlagSet("config", 0)
|
||||
set.Parse([]string{"test-a"})
|
||||
c := cli.NewContext(nil, set, set)
|
||||
c.App = &cli.App{
|
||||
Name: "docker-machine-test",
|
||||
|
@ -170,10 +167,6 @@ func TestCmdEnvFish(t *testing.T) {
|
|||
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() {
|
||||
|
@ -183,6 +176,7 @@ func TestCmdEnvFish(t *testing.T) {
|
|||
}()
|
||||
|
||||
set := flag.NewFlagSet("config", 0)
|
||||
set.Parse([]string{"test-a"})
|
||||
c := cli.NewContext(nil, set, set)
|
||||
c.App = &cli.App{
|
||||
Name: "docker-machine-test",
|
||||
|
@ -271,10 +265,6 @@ func TestCmdEnvPowerShell(t *testing.T) {
|
|||
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() {
|
||||
|
@ -284,6 +274,7 @@ func TestCmdEnvPowerShell(t *testing.T) {
|
|||
}()
|
||||
|
||||
set := flag.NewFlagSet("config", 0)
|
||||
set.Parse([]string{"test-a"})
|
||||
set.String("shell", "powershell", "")
|
||||
c := cli.NewContext(nil, set, set)
|
||||
c.App = &cli.App{
|
||||
|
|
|
@ -18,17 +18,17 @@ import (
|
|||
)
|
||||
|
||||
func TestCmdInspectFormat(t *testing.T) {
|
||||
actual, host := runInspectCommand(t, []string{})
|
||||
actual, host := runInspectCommand(t, []string{"test-a"})
|
||||
expected, _ := json.MarshalIndent(host, "", " ")
|
||||
assert.Equal(t, string(expected), actual)
|
||||
|
||||
actual, _ = runInspectCommand(t, []string{"--format", "{{.DriverName}}"})
|
||||
actual, _ = runInspectCommand(t, []string{"--format", "{{.DriverName}}", "test-a"})
|
||||
assert.Equal(t, "none", actual)
|
||||
|
||||
actual, _ = runInspectCommand(t, []string{"--format", "{{json .DriverName}}"})
|
||||
actual, _ = runInspectCommand(t, []string{"--format", "{{json .DriverName}}", "test-a"})
|
||||
assert.Equal(t, "\"none\"", actual)
|
||||
|
||||
actual, _ = runInspectCommand(t, []string{"--format", "{{prettyjson .Driver}}"})
|
||||
actual, _ = runInspectCommand(t, []string{"--format", "{{prettyjson .Driver}}", "test-a"})
|
||||
assert.Equal(t, "{\n \"IPAddress\": \"\",\n \"URL\": \"unix:///var/run/docker.sock\"\n}", actual)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,45 +2,28 @@ package commands
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/docker/machine/log"
|
||||
|
||||
"github.com/codegangsta/cli"
|
||||
"github.com/docker/machine/libmachine"
|
||||
)
|
||||
|
||||
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)
|
||||
mcn := getDefaultMcn(c)
|
||||
hostList, err := mcn.List()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
swarmMasters := make(map[string]string)
|
||||
swarmInfo := make(map[string]string)
|
||||
|
@ -55,20 +38,12 @@ func cmdLs(c *cli.Context) {
|
|||
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)
|
||||
items := libmachine.GetHostListItems(hostList)
|
||||
|
||||
sortHostListItemsByName(items)
|
||||
|
||||
|
|
|
@ -14,8 +14,14 @@ import (
|
|||
|
||||
func cmdSsh(c *cli.Context) {
|
||||
var (
|
||||
err error
|
||||
output ssh.Output
|
||||
err error
|
||||
)
|
||||
|
||||
if len(c.Args()) == 0 {
|
||||
log.Fatal("Error: Please specify a machine name.")
|
||||
}
|
||||
|
||||
name := c.Args().First()
|
||||
|
||||
certInfo := getCertPathInfo(c)
|
||||
|
@ -33,19 +39,6 @@ func cmdSsh(c *cli.Context) {
|
|||
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)
|
||||
|
@ -60,13 +53,13 @@ func cmdSsh(c *cli.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
var output ssh.Output
|
||||
|
||||
if len(c.Args()) <= 1 {
|
||||
if len(c.Args()) == 1 {
|
||||
err = host.CreateSSHShell()
|
||||
} else {
|
||||
var cmd string
|
||||
var args []string = c.Args()
|
||||
var (
|
||||
cmd string
|
||||
args []string = c.Args()
|
||||
)
|
||||
|
||||
for i, arg := range args {
|
||||
if arg == "--" {
|
||||
|
|
|
@ -141,7 +141,6 @@ INFO[0011] Creating SSH key...
|
|||
INFO[0012] Creating VirtualBox VM...
|
||||
INFO[0019] Starting VirtualBox VM...
|
||||
INFO[0020] Waiting for VM to start...
|
||||
INFO[0053] "dev" has been created and is now the active machine.
|
||||
INFO[0053] To see how to connect Docker to this machine, run: docker-machine env dev"
|
||||
```
|
||||
|
||||
|
@ -151,12 +150,9 @@ again:
|
|||
```
|
||||
$ docker-machine ls
|
||||
NAME ACTIVE DRIVER STATE URL SWARM
|
||||
dev * virtualbox Running tcp://192.168.99.100:2376
|
||||
dev virtualbox Running tcp://192.168.99.100:2376
|
||||
```
|
||||
|
||||
The `*` next to `dev` indicates that it is the active host.
|
||||
|
||||
|
||||
Next, as noted in the output of the `docker-machine create` command, we have to tell
|
||||
Docker to talk to that machine. You can do this with the `docker-machine env`
|
||||
command. For example,
|
||||
|
@ -249,17 +245,8 @@ run `docker-machine create` again. All created machines will appear in the
|
|||
output of `docker-machine ls`.
|
||||
|
||||
If you are finished using a host for the time being, you can stop it with
|
||||
`docker-machine stop` and later start it again with `docker-machine start`:
|
||||
|
||||
```
|
||||
$ docker-machine stop
|
||||
$ docker-machine start
|
||||
```
|
||||
|
||||
If they aren't passed any arguments, commands such as `docker-machine stop` will run
|
||||
against the active host (in this case, the VirtualBox VM). You can also specify
|
||||
a host to run a command against as an argument. For instance, you could also
|
||||
have written:
|
||||
`docker-machine stop` and later start it again with `docker-machine start`.
|
||||
Make sure to specify the machine name as an argument:
|
||||
|
||||
```
|
||||
$ docker-machine stop dev
|
||||
|
@ -306,7 +293,7 @@ $ docker-machine create \
|
|||
INFO[0000] Creating SSH key...
|
||||
INFO[0000] Creating Digital Ocean droplet...
|
||||
INFO[0002] Waiting for SSH...
|
||||
INFO[0085] "staging" has been created and is now the active machine
|
||||
INFO[0085] "staging" has been created.
|
||||
INFO[0085] To see how to connect Docker to this machine, run: docker-machine env staging"
|
||||
```
|
||||
|
||||
|
@ -326,28 +313,24 @@ Docker will be installed on the remote machine and the daemon will be configured
|
|||
to accept remote connections over TCP using TLS for authentication. Once this
|
||||
is finished, the host is ready for connection.
|
||||
|
||||
And then from this point, the remote host behaves much like the local host we
|
||||
created in the last section. If we look at `docker-machine`, we’ll see it is now
|
||||
the active host:
|
||||
To prepare the Docker client to send commands to the remote server we have
|
||||
created, we can use the subshell method again:
|
||||
|
||||
```
|
||||
$ eval "$(docker-machine env staging)"
|
||||
```
|
||||
|
||||
From this point, the remote host behaves much like the local host we created in
|
||||
the last section. If we look at `docker-machine ls`, we'll see it is now the
|
||||
"active" host, indicated by an asterisk (`*`) in that column:
|
||||
|
||||
```
|
||||
$ docker-machine active dev
|
||||
$ docker-machine ls
|
||||
NAME ACTIVE DRIVER STATE URL
|
||||
dev virtualbox Running tcp://192.168.99.103:2376
|
||||
staging * digitalocean Running tcp://104.236.50.118:2376
|
||||
```
|
||||
|
||||
To select an active host, you can use the `docker-machine active` command.
|
||||
|
||||
```
|
||||
$ docker-machine active dev
|
||||
$ docker-machine ls
|
||||
NAME ACTIVE DRIVER STATE URL
|
||||
dev * virtualbox Running tcp://192.168.99.103:2376
|
||||
staging digitalocean Running tcp://104.236.50.118:2376
|
||||
```
|
||||
|
||||
To remove a host and all of its containers and images, use `docker-machine rm`:
|
||||
|
||||
```
|
||||
|
@ -458,18 +441,18 @@ Nodes: 1
|
|||
|
||||
#### active
|
||||
|
||||
Get or set the active machine.
|
||||
See which machine is "active" (a machine is considered active if the
|
||||
`DOCKER_HOST` environment variable points to it).
|
||||
|
||||
```
|
||||
$ docker-machine ls
|
||||
NAME ACTIVE DRIVER STATE URL
|
||||
dev virtualbox Running tcp://192.168.99.103:2376
|
||||
staging * digitalocean Running tcp://104.236.50.118:2376
|
||||
$ docker-machine active dev
|
||||
$ docker-machine ls
|
||||
NAME ACTIVE DRIVER STATE URL
|
||||
dev * virtualbox Running tcp://192.168.99.103:2376
|
||||
staging digitalocean Running tcp://104.236.50.118:2376
|
||||
$ echo $DOCKER_HOST
|
||||
tcp://104.236.50.118:2376
|
||||
$ docker-machine active
|
||||
staging
|
||||
```
|
||||
|
||||
#### create
|
||||
|
@ -483,8 +466,7 @@ INFO[0000] Creating SSH key...
|
|||
INFO[0000] Creating VirtualBox VM...
|
||||
INFO[0007] Starting VirtualBox VM...
|
||||
INFO[0007] Waiting for VM to start...
|
||||
INFO[0038] "dev" has been created and is now the active machine.
|
||||
INFO[0038] To see how to connect Docker to this machine, run: docker-machine env dev"
|
||||
INFO[0038] To see how to connect Docker to this machine, run: docker-machine env dev
|
||||
```
|
||||
|
||||
##### Filtering create flags by driver in the help text
|
||||
|
@ -687,7 +669,7 @@ Usage: docker-machine inspect [OPTIONS] [arg...]
|
|||
Inspect information about a machine
|
||||
|
||||
Description:
|
||||
Argument is a machine name. Will use the active machine if none is provided.
|
||||
Argument is a machine name.
|
||||
|
||||
Options:
|
||||
--format, -f Format the output using the given go template.
|
||||
|
|
|
@ -2,6 +2,7 @@ package libmachine
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -111,39 +112,23 @@ func (s Filestore) Get(name string) (*Host, error) {
|
|||
}
|
||||
|
||||
func (s Filestore) GetActive() (*Host, error) {
|
||||
hostName, err := ioutil.ReadFile(s.activePath())
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
hosts, err := s.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.Get(string(hostName))
|
||||
}
|
||||
|
||||
func (s Filestore) IsActive(host *Host) (bool, error) {
|
||||
active, err := s.GetActive()
|
||||
if err != nil {
|
||||
return false, err
|
||||
dockerHost := os.Getenv("DOCKER_HOST")
|
||||
hostListItems := GetHostListItems(hosts)
|
||||
|
||||
for _, item := range hostListItems {
|
||||
if dockerHost == item.URL {
|
||||
host, err := s.Get(item.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return host, nil
|
||||
}
|
||||
}
|
||||
if active == nil {
|
||||
return false, nil
|
||||
}
|
||||
return active.Name == host.Name, nil
|
||||
}
|
||||
|
||||
func (s Filestore) SetActive(host *Host) error {
|
||||
if err := os.MkdirAll(filepath.Dir(s.activePath()), 0700); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(s.activePath(), []byte(host.Name), 0600)
|
||||
}
|
||||
|
||||
func (s Filestore) RemoveActive() error {
|
||||
return os.Remove(s.activePath())
|
||||
}
|
||||
|
||||
// activePath returns the path to the file that stores the name of the
|
||||
// active host
|
||||
func (s Filestore) activePath() string {
|
||||
return filepath.Join(utils.GetMachineDir(), ".active")
|
||||
return nil, errors.New("Active host not found")
|
||||
}
|
||||
|
|
|
@ -193,10 +193,10 @@ func TestStoreGetSetActive(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// No hosts set
|
||||
// No host set
|
||||
host, err := store.GetActive()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if err == nil {
|
||||
t.Fatal("Expected an error because there is no active host set")
|
||||
}
|
||||
|
||||
if host != nil {
|
||||
|
@ -213,12 +213,13 @@ func TestStoreGetSetActive(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
originalHost := host
|
||||
|
||||
if err := store.SetActive(originalHost); err != nil {
|
||||
url, err := host.GetURL()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
os.Setenv("DOCKER_HOST", url)
|
||||
|
||||
host, err = store.GetActive()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -226,25 +227,4 @@ func TestStoreGetSetActive(t *testing.T) {
|
|||
if host.Name != host.Name {
|
||||
t.Fatalf("Active host is not 'test', got %s", host.Name)
|
||||
}
|
||||
isActive, err := store.IsActive(host)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if isActive != true {
|
||||
t.Fatal("IsActive: Active host is not test")
|
||||
}
|
||||
|
||||
// remove active host altogether
|
||||
if err := store.RemoveActive(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
host, err = store.GetActive()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if host != nil {
|
||||
t.Fatalf("Active host %s is not nil", host.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,15 @@ type HostMetadata struct {
|
|||
ClientCertPath string
|
||||
}
|
||||
|
||||
type HostListItem struct {
|
||||
Name string
|
||||
Active bool
|
||||
DriverName string
|
||||
State state.State
|
||||
URL string
|
||||
SwarmOptions swarm.SwarmOptions
|
||||
}
|
||||
|
||||
func NewHost(name, driverName string, hostOptions *HostOptions) (*Host, error) {
|
||||
authOptions := hostOptions.AuthOptions
|
||||
storePath := filepath.Join(utils.GetMachineDir(), name)
|
||||
|
@ -375,3 +384,46 @@ func WaitForSSH(h *Host) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHostState(host Host, hostListItemsChan chan<- HostListItem) {
|
||||
currentState, err := host.Driver.GetState()
|
||||
if err != nil {
|
||||
log.Errorf("error getting state for host %s: %s", host.Name, err)
|
||||
}
|
||||
|
||||
url, err := host.GetURL()
|
||||
if err != nil {
|
||||
if err == drivers.ErrHostIsNotRunning {
|
||||
url = ""
|
||||
} else {
|
||||
log.Errorf("error getting URL for host %s: %s", host.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
dockerHost := os.Getenv("DOCKER_HOST")
|
||||
|
||||
hostListItemsChan <- HostListItem{
|
||||
Name: host.Name,
|
||||
Active: dockerHost == url && currentState != state.Stopped,
|
||||
DriverName: host.Driver.DriverName(),
|
||||
State: currentState,
|
||||
URL: url,
|
||||
SwarmOptions: *host.HostOptions.SwarmOptions,
|
||||
}
|
||||
}
|
||||
|
||||
func GetHostListItems(hostList []*Host) []HostListItem {
|
||||
hostListItems := []HostListItem{}
|
||||
hostListItemsChan := make(chan HostListItem)
|
||||
|
||||
for _, host := range hostList {
|
||||
go getHostState(*host, hostListItemsChan)
|
||||
}
|
||||
|
||||
for _ = range hostList {
|
||||
hostListItems = append(hostListItems, <-hostListItemsChan)
|
||||
}
|
||||
|
||||
close(hostListItemsChan)
|
||||
return hostListItems
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/docker/machine/libmachine/auth"
|
||||
"github.com/docker/machine/libmachine/engine"
|
||||
"github.com/docker/machine/libmachine/swarm"
|
||||
"github.com/docker/machine/state"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -226,3 +227,89 @@ func captureStdout() (chan string, *os.File) {
|
|||
|
||||
return out, w
|
||||
}
|
||||
|
||||
func TestGetHostListItems(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
hostListItemsChan := make(chan HostListItem)
|
||||
|
||||
store, err := getTestStore()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts := []Host{
|
||||
{
|
||||
Name: "foo",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &fakedriver.FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
StorePath: store.GetPath(),
|
||||
HostOptions: &HostOptions{
|
||||
SwarmOptions: &swarm.SwarmOptions{
|
||||
Master: false,
|
||||
Address: "",
|
||||
Discovery: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "bar",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &fakedriver.FakeDriver{
|
||||
MockState: state.Stopped,
|
||||
},
|
||||
StorePath: store.GetPath(),
|
||||
HostOptions: &HostOptions{
|
||||
SwarmOptions: &swarm.SwarmOptions{
|
||||
Master: false,
|
||||
Address: "",
|
||||
Discovery: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "baz",
|
||||
DriverName: "fakedriver",
|
||||
Driver: &fakedriver.FakeDriver{
|
||||
MockState: state.Running,
|
||||
},
|
||||
StorePath: store.GetPath(),
|
||||
HostOptions: &HostOptions{
|
||||
SwarmOptions: &swarm.SwarmOptions{
|
||||
Master: false,
|
||||
Address: "",
|
||||
Discovery: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, h := range hosts {
|
||||
if err := store.Save(&h); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
expected := map[string]state.State{
|
||||
"foo": state.Running,
|
||||
"bar": state.Stopped,
|
||||
"baz": state.Running,
|
||||
}
|
||||
|
||||
items := []HostListItem{}
|
||||
for _, host := range hosts {
|
||||
go getHostState(host, hostListItemsChan)
|
||||
}
|
||||
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
items = append(items, <-hostListItemsChan)
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
if expected[item.Name] != item.State {
|
||||
t.Fatal("Expected state did not match for item", item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,10 +60,6 @@ func (m *Machine) Create(name string, driverName string, hostOptions *HostOption
|
|||
return host, err
|
||||
}
|
||||
|
||||
if err := m.store.SetActive(host); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return host, nil
|
||||
}
|
||||
|
||||
|
@ -75,10 +71,6 @@ func (m *Machine) GetActive() (*Host, error) {
|
|||
return m.store.GetActive()
|
||||
}
|
||||
|
||||
func (m *Machine) IsActive(host *Host) (bool, error) {
|
||||
return m.store.IsActive(host)
|
||||
}
|
||||
|
||||
func (m *Machine) List() ([]*Host, error) {
|
||||
return m.store.List()
|
||||
}
|
||||
|
@ -88,17 +80,6 @@ func (m *Machine) Get(name string) (*Host, error) {
|
|||
}
|
||||
|
||||
func (m *Machine) Remove(name string, force bool) error {
|
||||
active, err := m.store.GetActive()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if active != nil && active.Name == name {
|
||||
if err := m.RemoveActive(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
host, err := m.store.Get(name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -110,11 +91,3 @@ func (m *Machine) Remove(name string, force bool) error {
|
|||
}
|
||||
return m.store.Remove(name, force)
|
||||
}
|
||||
|
||||
func (m *Machine) RemoveActive() error {
|
||||
return m.store.RemoveActive()
|
||||
}
|
||||
|
||||
func (m *Machine) SetActive(host *Host) error {
|
||||
return m.store.SetActive(host)
|
||||
}
|
||||
|
|
|
@ -11,18 +11,12 @@ type Store interface {
|
|||
GetCACertificatePath() (string, error)
|
||||
// GetPrivateKeyPath returns the private key
|
||||
GetPrivateKeyPath() (string, error)
|
||||
// IsActive returns whether the host is active or not
|
||||
IsActive(host *Host) (bool, error)
|
||||
// List returns a list of hosts
|
||||
List() ([]*Host, error)
|
||||
// Load loads a host by name
|
||||
Get(name string) (*Host, error)
|
||||
// Remove removes a machine from the store
|
||||
Remove(name string, force bool) error
|
||||
// RemoveActive removes the active machine from the store
|
||||
RemoveActive() error
|
||||
// Save persists a machine in the store
|
||||
Save(host *Host) error
|
||||
// SetActive sets the specified host as the active host
|
||||
SetActive(host *Host) error
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ func WaitForDocker(ip string, daemonPort int) error {
|
|||
return WaitFor(func() bool {
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", ip, daemonPort))
|
||||
if err != nil {
|
||||
log.Debugf("Got an error it was %s", err)
|
||||
log.Debugf("Daemon not responding yet: ", err)
|
||||
return false
|
||||
}
|
||||
conn.Close()
|
||||
|
|
Loading…
Reference in New Issue