diff --git a/common/weave/client.go b/common/weave/client.go index 939e54671..b3874611d 100644 --- a/common/weave/client.go +++ b/common/weave/client.go @@ -34,6 +34,8 @@ type Status struct { Router Router DNS *DNS IPAM *IPAM + Proxy *Proxy + Plugin *Plugin } // Router describes the status of the Weave Router @@ -95,6 +97,16 @@ type IPAM struct { PendingAllocates []string } +// Proxy describes the status of Weave Proxy +type Proxy struct { + Addresses []string +} + +// Plugin describes the status of the Weave Plugin +type Plugin struct { + DriverName string +} + var weavePsMatch = regexp.MustCompile(`^([0-9a-f]{12}) ((?:[0-9a-f][0-9a-f]\:){5}(?:[0-9a-f][0-9a-f]))(.*)$`) var ipMatch = regexp.MustCompile(`([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})(/[0-9]+)`) diff --git a/common/weave/client_test.go b/common/weave/client_test.go index 57c26fa6a..769fbac96 100644 --- a/common/weave/client_test.go +++ b/common/weave/client_test.go @@ -25,6 +25,8 @@ const ( mockContainerIP = "10.0.0.123" mockContainerIPWithScope = ";10.0.0.123" mockHostname = "hostname.weave.local" + mockProxyAddress = "unix:///foo/bar/weave.sock" + mockDriverName = "weave_mock" ) var ( @@ -41,8 +43,16 @@ var ( "Hostname": "%s.", "Tombstone": 0 }] - } - }`, mockWeavePeerName, mockWeavePeerNickName, mockContainerID, mockHostname) + }, + "Proxy": { + "Addresses": [ + "%s" + ] + }, + "Plugin": { + "DriverName": "%s" + } + }`, mockWeavePeerName, mockWeavePeerNickName, mockContainerID, mockHostname, mockProxyAddress, mockDriverName) mockIP = net.ParseIP("1.2.3.4") ) @@ -84,6 +94,12 @@ func TestStatus(t *testing.T) { }, }, }, + Proxy: &weave.Proxy{ + Addresses: []string{mockProxyAddress}, + }, + Plugin: &weave.Plugin{ + DriverName: mockDriverName, + }, } if !reflect.DeepEqual(status, want) { t.Fatal(test.Diff(status, want)) diff --git a/probe/overlay/weave.go b/probe/overlay/weave.go index 4c18e1508..83a8bbf18 100644 --- a/probe/overlay/weave.go +++ b/probe/overlay/weave.go @@ -1,7 +1,6 @@ package overlay import ( - "bytes" "fmt" "regexp" "strings" @@ -13,8 +12,6 @@ import ( "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/probe/host" "github.com/weaveworks/scope/report" - - docker_client "github.com/fsouza/go-dockerclient" ) // Keys for use in Node @@ -54,9 +51,6 @@ const ( ) var ( - // NewDockerClientStub is used for testing - NewDockerClientStub = newDockerClient - containerNotRunningRE = regexp.MustCompile(`Container .* is not running\n`) containerMetadata = report.MetadataTemplates{ @@ -145,52 +139,30 @@ var ( } ) -// DockerClient is used for testing -type DockerClient interface { - CreateExec(docker_client.CreateExecOptions) (*docker_client.Exec, error) - StartExec(string, docker_client.StartExecOptions) error - InspectContainer(id string) (*docker_client.Container, error) -} - -func newDockerClient() (DockerClient, error) { - return docker_client.NewClientFromEnv() -} - // Weave represents a single Weave router, presumably on the same host // as the probe. It is both a Reporter and a Tagger: it produces an Overlay // topology, and (in theory) can tag existing topologies with foreign keys to // overlay -- though I'm not sure what that would look like in practice right // now. type Weave struct { - client weave.Client - dockerClient DockerClient - hostID string + client weave.Client + hostID string - mtx sync.RWMutex - statusCache weave.Status - psCache map[string]weave.PSEntry - proxyRunningCache bool - proxyAddressCache string - pluginRunningCache bool + mtx sync.RWMutex + statusCache weave.Status + psCache map[string]weave.PSEntry - backoff backoff.Interface - psBackoff backoff.Interface - proxyBackoff backoff.Interface - pluginBackoff backoff.Interface + backoff backoff.Interface + psBackoff backoff.Interface } // NewWeave returns a new Weave tagger based on the Weave router at // address. The address should be an IP or FQDN, no port. func NewWeave(hostID string, client weave.Client) (*Weave, error) { - dockerClient, err := NewDockerClientStub() - if err != nil { - return nil, err - } w := &Weave{ - client: client, - dockerClient: dockerClient, - hostID: hostID, - psCache: map[string]weave.PSEntry{}, + client: client, + hostID: hostID, + psCache: map[string]weave.PSEntry{}, } w.backoff = backoff.New(w.status, "collecting weave status") @@ -201,14 +173,6 @@ func NewWeave(hostID string, client weave.Client) (*Weave, error) { w.psBackoff.SetInitialBackoff(10 * time.Second) go w.psBackoff.Start() - w.proxyBackoff = backoff.New(w.proxyStatus, "collecting weave proxy status") - w.proxyBackoff.SetInitialBackoff(10 * time.Second) - go w.proxyBackoff.Start() - - w.pluginBackoff = backoff.New(w.pluginStatus, "collecting weave plugin status") - w.pluginBackoff.SetInitialBackoff(10 * time.Second) - go w.pluginBackoff.Start() - return w, nil } @@ -219,8 +183,6 @@ func (*Weave) Name() string { return "Weave" } func (w *Weave) Stop() { w.backoff.Stop() w.psBackoff.Stop() - w.proxyBackoff.Stop() - w.pluginBackoff.Stop() } func (w *Weave) ps() (bool, error) { @@ -251,78 +213,6 @@ func (w *Weave) status() (bool, error) { return false, err } -func filterContainerNotFound(err error) error { - if err == nil { - return nil - } - - switch err.(type) { - case *docker_client.Error: - // This is really ugly, but this error comes from the client in some cases - // and there is no other way to distinguish it :( - dockerError := err.(*docker_client.Error) - if containerNotRunningRE.MatchString(dockerError.Message) { - return nil - } - case *docker_client.ContainerNotRunning: - return nil - case *docker_client.NoSuchContainer: - return nil - } - - return err -} - -func (w *Weave) proxyStatus() (bool, error) { - update := func(running bool, address string) { - w.mtx.Lock() - defer w.mtx.Unlock() - w.proxyRunningCache = running - w.proxyAddressCache = address - } - - exec, err := w.dockerClient.CreateExec(docker_client.CreateExecOptions{ - AttachStdout: true, - Cmd: []string{"curl", "-s", "--unix-socket", "status.sock", "http:/status"}, - Container: "weaveproxy", - }) - if err != nil { - update(false, "") - return false, filterContainerNotFound(err) - } - out := bytes.NewBuffer(nil) - err = w.dockerClient.StartExec(exec.ID, docker_client.StartExecOptions{ - OutputStream: out, - }) - if err != nil { - update(true, "") - return false, filterContainerNotFound(err) - } - - update(true, out.String()) - - return false, nil -} - -func (w *Weave) pluginStatus() (bool, error) { - update := func(running bool) { - w.mtx.Lock() - defer w.mtx.Unlock() - - w.pluginRunningCache = running - } - - c, err := w.dockerClient.InspectContainer("weaveplugin") - if err != nil { - update(false) - return false, filterContainerNotFound(err) - } - - update(c.State.Running) - - return false, nil -} - // Tag implements Tagger. func (w *Weave) Tag(r report.Report) (report.Report, error) { w.mtx.RLock() @@ -462,14 +352,17 @@ func (w *Weave) addCurrentPeerInfo(latests map[string]string, node report.Node) latests[WeaveDNSEntryCount] = fmt.Sprintf("%d", dnsEntryCount) } latests[WeaveProxyStatus] = "not running" - if w.proxyRunningCache { + if w.statusCache.Proxy != nil { latests[WeaveProxyStatus] = "running" - latests[WeaveProxyAddress] = w.proxyAddressCache + latests[WeaveProxyAddress] = "" + if len(w.statusCache.Proxy.Addresses) > 0 { + latests[WeaveProxyAddress] = w.statusCache.Proxy.Addresses[0] + } } latests[WeavePluginStatus] = "not running" - if w.pluginRunningCache { + if w.statusCache.Plugin != nil { latests[WeavePluginStatus] = "running" - latests[WeavePluginDriver] = "weave" + latests[WeavePluginDriver] = w.statusCache.Plugin.DriverName } node = node.AddPrefixMulticolumnTable(WeaveConnectionsMulticolumnTablePrefix, getConnectionsTable(w.statusCache.Router)) node = node.WithParents(report.MakeSets().Add(report.Host, report.MakeStringSet(w.hostID))) diff --git a/probe/overlay/weave_test.go b/probe/overlay/weave_test.go index c3f819a1d..a857749be 100644 --- a/probe/overlay/weave_test.go +++ b/probe/overlay/weave_test.go @@ -1,7 +1,6 @@ package overlay_test import ( - "sync" "testing" "time" @@ -12,8 +11,6 @@ import ( "github.com/weaveworks/scope/test" "github.com/weaveworks/scope/test/reflect" "github.com/weaveworks/scope/test/weave" - - docker_client "github.com/fsouza/go-dockerclient" ) const ( @@ -21,54 +18,7 @@ const ( mockContainerIPWithScope = ";" + weave.MockContainerIP ) -type mockDockerClient struct { - sync.RWMutex - containers map[string]*docker_client.Container -} - -func (m *mockDockerClient) InspectContainer(id string) (*docker_client.Container, error) { - m.RLock() - defer m.RUnlock() - c, ok := m.containers[id] - if !ok { - return nil, &docker_client.NoSuchContainer{} - } - return c, nil -} - -func (m *mockDockerClient) CreateExec(docker_client.CreateExecOptions) (*docker_client.Exec, error) { - return &docker_client.Exec{ID: "id"}, nil -} - -func (m *mockDockerClient) StartExec(_ string, options docker_client.StartExecOptions) error { - options.OutputStream.Write([]byte("exec_output")) - return nil -} - -var mockWeaveContainers = map[string]*docker_client.Container{ - "weaveproxy": { - ID: "foo", - State: docker_client.State{ - Running: true, - }, - }, - - "weaveplugin": { - ID: "bar", - State: docker_client.State{ - Running: true, - }, - }, -} - func runTest(t *testing.T, f func(*overlay.Weave)) { - // Place and restore docker client - origNewDockerClientStub := overlay.NewDockerClientStub - overlay.NewDockerClientStub = func() (overlay.DockerClient, error) { - return &mockDockerClient{containers: mockWeaveContainers}, nil - } - defer func() { overlay.NewDockerClientStub = origNewDockerClientStub }() - w, err := overlay.NewWeave(mockHostID, weave.MockClient{}) if err != nil { t.Fatal(err) @@ -152,14 +102,16 @@ func TestOverlayTopology(t *testing.T) { if have, ok := node.Latest.Lookup(overlay.WeaveProxyStatus); !ok || have != "running" { t.Errorf("Expected weave proxy status %q, got %q", "running", have) } - // The weave proxy address should equal what Exec writes to stdout - if have, ok := node.Latest.Lookup(overlay.WeaveProxyAddress); !ok || have != "exec_output" { - t.Errorf("Expected weave proxy address %q, got %q", "exec_output", have) + if have, ok := node.Latest.Lookup(overlay.WeaveProxyAddress); !ok || have != weave.MockProxyAddress { + t.Errorf("Expected weave proxy address %q, got %q", weave.MockProxyAddress, have) } // The weave plugin container is running if have, ok := node.Latest.Lookup(overlay.WeavePluginStatus); !ok || have != "running" { t.Errorf("Expected weave plugin status %q, got %q", "running", have) } + if have, ok := node.Latest.Lookup(overlay.WeavePluginDriver); !ok || have != weave.MockDriverName { + t.Errorf("Expected weave proxy address %q, got %q", weave.MockDriverName, have) + } // The mock data indicates ranges are owned by unreachable peers if have, ok := node.Latest.Lookup(overlay.WeaveIPAMStatus); !ok || have != "all ranges owned by unreachable peers" { t.Errorf("Expected weave IPAM status %q, got %q", "all ranges owned by unreachable peers", have) diff --git a/test/weave/mock.go b/test/weave/mock.go index c5de9e4ab..8f8a418b6 100644 --- a/test/weave/mock.go +++ b/test/weave/mock.go @@ -15,6 +15,8 @@ const ( MockContainerMAC = "d6:f2:5a:12:36:a8" MockContainerIP = "10.0.0.123" MockHostname = "hostname.weave.local" + MockProxyAddress = "unix:///foo/bar/weave.sock" + MockDriverName = "weave_mock" ) // MockClient is a mock version of weave.Client @@ -54,6 +56,12 @@ func (MockClient) Status() (weave.Status, error) { {Size: 0, IsKnownPeer: false}, }, }, + Proxy: &weave.Proxy{ + Addresses: []string{MockProxyAddress}, + }, + Plugin: &weave.Plugin{ + DriverName: MockDriverName, + }, }, nil }