diff --git a/commands/ls.go b/commands/ls.go index 78c652bc44..c866268647 100644 --- a/commands/ls.go +++ b/commands/ls.go @@ -39,6 +39,7 @@ type HostListItem struct { State state.State URL string SwarmOptions *swarm.Options + Error string } func cmdLs(c CommandLine, api libmachine.API) error { @@ -67,7 +68,7 @@ func cmdLs(c CommandLine, api libmachine.API) error { swarmInfo := make(map[string]string) w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0) - fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM") + fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tERRORS") for _, host := range hostList { swarmOptions := host.HostOptions.SwarmOptions @@ -98,8 +99,8 @@ func cmdLs(c CommandLine, api libmachine.API) error { 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) + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo, item.Error) } w.Flush() @@ -231,36 +232,19 @@ func matchesName(host *host.Host, names []string) bool { } func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { - stateCh := make(chan state.State) - urlCh := make(chan string) + url := "" + hostError := "" - go func() { - currentState, err := h.Driver.GetState() - if err != nil { - log.Errorf("error getting state for host %s: %s", h.Name, err) - } - - stateCh <- currentState - }() - - go func() { - url, err := h.GetURL() - if err != nil { - if err.Error() == drivers.ErrHostIsNotRunning.Error() { - url = "" - } else { - log.Errorf("error getting URL for host %s: %s", h.Name, err) - } - } - - urlCh <- url - }() - - currentState := <-stateCh - url := <-urlCh - - close(stateCh) - close(urlCh) + currentState, err := h.Driver.GetState() + if err == nil { + url, err = h.GetURL() + } + if err != nil { + hostError = err.Error() + } + if hostError == drivers.ErrHostIsNotRunning.Error() { + hostError = "" + } stateQueryChan <- HostListItem{ Name: h.Name, @@ -269,6 +253,7 @@ func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { State: currentState, URL: url, SwarmOptions: h.HostOptions.SwarmOptions, + Error: hostError, } } diff --git a/commands/ls_test.go b/commands/ls_test.go index de88d514a7..8e8b40165b 100644 --- a/commands/ls_test.go +++ b/commands/ls_test.go @@ -276,6 +276,7 @@ func TestFilterHostsDifferentFlagsProduceAND(t *testing.T) { assert.EqualValues(t, filterHosts(hosts, opts), expected) } + func captureStdout() (chan string, *os.File) { r, w, _ := os.Pipe() os.Stdout = w @@ -296,68 +297,58 @@ func TestGetHostListItems(t *testing.T) { hosts := []*host.Host{ { - Name: "foo", - DriverName: "fakedriver", + Name: "foo", Driver: &fakedriver.Driver{ MockState: state.Running, }, HostOptions: &host.Options{ - SwarmOptions: &swarm.Options{ - Master: false, - Address: "", - Discovery: "", - }, + SwarmOptions: &swarm.Options{}, }, }, { - Name: "bar", - DriverName: "fakedriver", + Name: "bar", Driver: &fakedriver.Driver{ MockState: state.Stopped, }, HostOptions: &host.Options{ - SwarmOptions: &swarm.Options{ - Master: false, - Address: "", - Discovery: "", - }, + SwarmOptions: &swarm.Options{}, }, }, { - Name: "baz", - DriverName: "fakedriver", + Name: "baz", Driver: &fakedriver.Driver{ - MockState: state.Running, + MockState: state.Error, }, HostOptions: &host.Options{ - SwarmOptions: &swarm.Options{ - Master: false, - Address: "", - Discovery: "", - }, + SwarmOptions: &swarm.Options{}, }, }, } - expected := map[string]state.State{ - "foo": state.Running, - "bar": state.Stopped, - "baz": state.Running, + expected := map[string]struct { + state state.State + active bool + error string + }{ + "foo": {state.Running, true, ""}, + "bar": {state.Stopped, false, ""}, + "baz": {state.Error, false, "Unable to get url"}, } 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) - } + expected := expected[item.Name] + + assert.Equal(t, expected.state, item.State) + assert.Equal(t, expected.active, item.Active) + assert.Equal(t, expected.error, item.Error) } } @@ -376,8 +367,7 @@ func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) { hosts := []*host.Host{ { - Name: "foo", - DriverName: "fakedriver", + Name: "foo", Driver: &fakedriver.Driver{ MockState: state.Running, MockURL: "tcp://120.0.0.1:2376", @@ -391,8 +381,7 @@ func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) { }, }, { - Name: "bar", - DriverName: "fakedriver", + Name: "bar", Driver: &fakedriver.Driver{ MockState: state.Stopped, }, @@ -405,8 +394,7 @@ func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) { }, }, { - Name: "baz", - DriverName: "fakedriver", + Name: "baz", Driver: &fakedriver.Driver{ MockState: state.Saved, }, @@ -433,18 +421,15 @@ func TestGetHostListItemsEnvDockerHostUnset(t *testing.T) { 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].state != item.State { - t.Fatal("Expected state did not match for item", item) - } - if expected[item.Name].active != item.Active { - t.Fatal("Expected active flag did not match for item", item) - } + expected := expected[item.Name] + + assert.Equal(t, expected.state, item.State) + assert.Equal(t, expected.active, item.Active) } } diff --git a/drivers/fakedriver/fakedriver.go b/drivers/fakedriver/fakedriver.go index e3d1318005..5727b91b77 100644 --- a/drivers/fakedriver/fakedriver.go +++ b/drivers/fakedriver/fakedriver.go @@ -1,6 +1,8 @@ package fakedriver import ( + "fmt" + "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/mcnflag" "github.com/docker/machine/libmachine/state" @@ -27,6 +29,12 @@ func (d *Driver) SetConfigFromFlags(flags drivers.DriverOptions) error { } func (d *Driver) GetURL() (string, error) { + if d.MockState == state.Error { + return "", fmt.Errorf("Unable to get url") + } + if d.MockState != state.Running { + return "", drivers.ErrHostIsNotRunning + } return d.MockURL, nil }