Merge pull request #2719 from weaveworks/update-weave-client-to-2.0

Gather Weave Net plugin and proxy info from report
This commit is contained in:
Alfonso Acosta
2017-07-18 11:01:55 +02:00
committed by GitHub
5 changed files with 60 additions and 179 deletions
+12
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]+)`)
+18 -2
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))
+17 -124
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)))
+5 -53
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)
+8
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
}