From b7d292e1610ceab66e134bcee747ffdcede98aee Mon Sep 17 00:00:00 2001 From: Alfonso Acosta Date: Mon, 17 Jul 2017 13:23:26 +0000 Subject: [PATCH] Gather Weave Net plugin and proxy info from report Instead of using Docker, because after Weave Net 2.0 there are no proxy nor plugin containers. This has the drawback of not detecting the plugin/proxy in systems running Weave Net < 2.0 , but I think we can live with it. --- common/weave/client.go | 12 +++ common/weave/client_test.go | 20 ++++- probe/overlay/weave.go | 141 +++++------------------------------- probe/overlay/weave_test.go | 58 ++------------- test/weave/mock.go | 8 ++ 5 files changed, 60 insertions(+), 179 deletions(-) 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 }