From 24a13af61e659df7d461bfe6ff88a691fe4daded Mon Sep 17 00:00:00 2001 From: David Gageot Date: Wed, 23 Dec 2015 18:09:24 +0100 Subject: [PATCH] FIX #2653 docker-machine ls need to identify machine or cluster Signed-off-by: David Gageot --- commands/ls.go | 80 +++++++++++++++--------- commands/ls_test.go | 29 ++++++++- test/integration/core/swarm-options.bats | 14 +++++ 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/commands/ls.go b/commands/ls.go index 86303993f8..b753fe791b 100644 --- a/commands/ls.go +++ b/commands/ls.go @@ -40,6 +40,7 @@ type FilterOptions struct { type HostListItem struct { Name string Active bool + SwarmActive bool DriverName string State state.State URL string @@ -78,6 +79,8 @@ func cmdLs(c CommandLine, api libmachine.API) error { swarmInfo := make(map[string]string) w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0) + defer w.Flush() + fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tDOCKER\tERRORS") for _, host := range hostList { @@ -96,28 +99,34 @@ func cmdLs(c CommandLine, api libmachine.API) error { items := getHostListItems(hostList, hostInError) for _, item := range items { - activeString := "-" - if item.Active { - activeString = "*" - } - - swarmInfo := "" - - if item.SwarmOptions != nil && 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\t%s\t%s\n", - item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo, item.DockerVersion, item.Error) + printItemToTabWriter(item, swarmInfo, swarmMasters, w) } - w.Flush() - return nil } +func printItemToTabWriter(item HostListItem, swarmInfo map[string]string, swarmMasters map[string]string, w *tabwriter.Writer) { + activeColumn := "-" + if item.Active { + activeColumn = "*" + } + if item.SwarmActive { + activeColumn = "* (swarm)" + } + + swarmColumn := "" + + if item.SwarmOptions != nil && item.SwarmOptions.Discovery != "" { + swarmColumn = swarmMasters[item.SwarmOptions.Discovery] + if item.SwarmOptions.Master { + swarmColumn = fmt.Sprintf("%s (master)", swarmColumn) + } + } + + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + item.Name, activeColumn, item.DriverName, item.State, item.URL, swarmColumn, item.DockerVersion, item.Error) +} + func parseFilters(filters []string) (FilterOptions, error) { options := FilterOptions{} for _, f := range filters { @@ -320,9 +329,17 @@ func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { engineOptions = h.HostOptions.EngineOptions } + isMaster := false + swarmHost := "" + if swarmOptions != nil { + isMaster = swarmOptions.Master + swarmHost = swarmOptions.Host + } + stateQueryChan <- HostListItem{ Name: h.Name, Active: isActive(currentState, url), + SwarmActive: isSwarmActive(currentState, url, isMaster, swarmHost), DriverName: h.Driver.DriverName(), State: currentState, URL: url, @@ -397,16 +414,21 @@ func sortHostListItemsByName(items []HostListItem) { } } -// IsActive provides a single function for determining if a host is active -// based on both the url and if the host is stopped. -func isActive(currentState state.State, url string) bool { - dockerHost := os.Getenv("DOCKER_HOST") - - // TODO: hard-coding the swarm port is a travesty... - deSwarmedHost := strings.Replace(dockerHost, ":3376", ":2376", 1) - if dockerHost == url || deSwarmedHost == url { - return currentState == state.Running - } - - return false +func isActive(currentState state.State, hostURL string) bool { + return currentState == state.Running && hostURL == os.Getenv("DOCKER_HOST") +} + +func isSwarmActive(currentState state.State, hostURL string, isMaster bool, swarmHost string) bool { + return isMaster && currentState == state.Running && toSwarmURL(hostURL, swarmHost) == os.Getenv("DOCKER_HOST") +} + +func urlPort(urlWithPort string) string { + parts := strings.Split(urlWithPort, ":") + return parts[len(parts)-1] +} + +func toSwarmURL(hostURL string, swarmHost string) string { + hostPort := urlPort(hostURL) + swarmPort := urlPort(swarmHost) + return strings.Replace(hostURL, ":"+hostPort, ":"+swarmPort, 1) } diff --git a/commands/ls_test.go b/commands/ls_test.go index e3938cbcac..037bfeea7b 100644 --- a/commands/ls_test.go +++ b/commands/ls_test.go @@ -415,7 +415,7 @@ func TestIsActive(t *testing.T) { {"tcp://5.6.7.8:2376", state.Running, false}, {"tcp://1.2.3.4:2376", state.Stopped, false}, {"tcp://1.2.3.4:2376", state.Running, true}, - {"tcp://1.2.3.4:3376", state.Running, true}, + {"tcp://1.2.3.4:3376", state.Running, false}, } for _, c := range cases { @@ -430,6 +430,33 @@ func TestIsActive(t *testing.T) { } } +func TestIsSwarmActive(t *testing.T) { + cases := []struct { + dockerHost string + state state.State + isMaster bool + expected bool + }{ + {"", state.Running, false, false}, + {"tcp://5.6.7.8:3376", state.Running, true, false}, + {"tcp://1.2.3.4:3376", state.Stopped, true, false}, + {"tcp://1.2.3.4:3376", state.Running, true, true}, + {"tcp://1.2.3.4:3376", state.Running, false, false}, + {"tcp://1.2.3.4:2376", state.Running, true, false}, + } + + for _, c := range cases { + os.Unsetenv("DOCKER_HOST") + if c.dockerHost != "" { + os.Setenv("DOCKER_HOST", c.dockerHost) + } + + actual := isSwarmActive(c.state, "tcp://1.2.3.4:2376", c.isMaster, "tcp://0.0.0.0:3376") + + assert.Equal(t, c.expected, actual) + } +} + func TestGetHostStateTimeout(t *testing.T) { defer func(timeout time.Duration) { stateTimeoutDuration = timeout }(stateTimeoutDuration) stateTimeoutDuration = 1 * time.Millisecond diff --git a/test/integration/core/swarm-options.bats b/test/integration/core/swarm-options.bats index 03cb0185b7..a36cdbb0a7 100644 --- a/test/integration/core/swarm-options.bats +++ b/test/integration/core/swarm-options.bats @@ -26,3 +26,17 @@ export TOKEN=$(curl -sS -X POST "https://discovery.hub.docker.com/v1/clusters") echo ${heartbeat_arg} [[ "$heartbeat_arg" =~ "--heartbeat=5s" ]] } + +@test "should not show as swarm active if normal active" { + eval $(machine env queenbee) + run machine ls + echo ${output} + [[ ${lines[1]} != *"* (swarm)"* ]] +} + +@test "should show as swarm active" { + eval $(machine env --swarm queenbee) + run machine ls + echo ${output} + [[ ${lines[1]} == *"* (swarm)"* ]] +}