mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-15 03:20:03 +00:00
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:
@@ -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]+)`)
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user