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.
This commit is contained in:
Alfonso Acosta
2017-07-17 13:23:26 +00:00
parent a6d3542c89
commit b7d292e161
5 changed files with 60 additions and 179 deletions

View File

@@ -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]+)`)

View File

@@ -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))

View File

@@ -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)))

View File

@@ -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)

View File

@@ -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
}