Treat addresses on the docker bridge as local.

This commit is contained in:
Tom Wilkie
2015-06-22 11:18:16 +00:00
parent 608abf0e4f
commit 82a7f93e17
7 changed files with 154 additions and 38 deletions

View File

@@ -34,6 +34,7 @@ func main() {
spyProcs = flag.Bool("processes", true, "report processes (needs root)")
dockerEnabled = flag.Bool("docker", true, "collect Docker-related attributes for processes")
dockerInterval = flag.Duration("docker.interval", 10*time.Second, "how often to update Docker attributes")
dockerBridge = flag.String("docker.bridge", "docker0", "the docker bridge name")
weaveRouterAddr = flag.String("weave.router.addr", "", "IP address or FQDN of the Weave router")
procRoot = flag.String("proc.root", "/proc", "location of the proc filesystem")
)
@@ -81,6 +82,10 @@ func main() {
reporters := []tag.Reporter{}
if *dockerEnabled && runtime.GOOS == linux {
if err = report.AddLocalBridge(*dockerBridge); err != nil {
log.Fatalf("failed to get docker bridge address: %v", err)
}
dockerRegistry, err := docker.NewRegistry(*dockerInterval)
if err != nil {
log.Fatalf("failed to start docker registry: %v", err)

View File

@@ -34,7 +34,7 @@ type LeafMapFunc func(report.NodeMetadata) (RenderableNode, bool)
// The srcNode renderable node is essentially from MapFunc, representing one of
// the rendered nodes this pseudo node refers to. srcNodeID and dstNodeID are
// node IDs prior to mapping.
type PseudoFunc func(srcNodeID string, srcNode RenderableNode, dstNodeID string, local Networks) (RenderableNode, bool)
type PseudoFunc func(srcNodeID string, srcNode RenderableNode, dstNodeID string, local report.Networks) (RenderableNode, bool)
// MapFunc is anything which can take an arbitrary RenderableNode and
// return another RenderableNode.
@@ -257,7 +257,7 @@ func MapAddress2Host(n RenderableNode) (RenderableNode, bool) {
// the report's local networks. Otherwise, the returned function will
// produce a single pseudo node per (dst address, src address, src port).
func GenericPseudoNode(addresser func(id string) net.IP) PseudoFunc {
return func(src string, srcMapped RenderableNode, dst string, local Networks) (RenderableNode, bool) {
return func(src string, srcMapped RenderableNode, dst string, local report.Networks) (RenderableNode, bool) {
// Use the addresser to extract the destination IP
dstNodeAddr := addresser(dst)
@@ -278,7 +278,7 @@ func GenericPseudoNode(addresser func(id string) net.IP) PseudoFunc {
}
// PanicPseudoNode just panics; it is for Topologies without edges
func PanicPseudoNode(src string, srcMapped RenderableNode, dst string, local Networks) (RenderableNode, bool) {
func PanicPseudoNode(src string, srcMapped RenderableNode, dst string, local report.Networks) (RenderableNode, bool) {
panic(dst)
}

View File

@@ -7,16 +7,13 @@ import (
"github.com/weaveworks/scope/report"
)
// Networks represent a set of subnets local to a report.
type Networks []*net.IPNet
// LocalNetworks returns a superset of the networks (think: CIDRs) that are
// "local" from the perspective of each host represented in the report. It's
// used to determine which nodes in the report are "remote", i.e. outside of
// our infrastructure.
func LocalNetworks(r report.Report) Networks {
func LocalNetworks(r report.Report) report.Networks {
var (
result = Networks{}
result = report.Networks{}
networks = map[string]struct{}{}
)
@@ -39,13 +36,3 @@ func LocalNetworks(r report.Report) Networks {
}
return result
}
// Contains returns true if IP is in Networks.
func (n Networks) Contains(ip net.IP) bool {
for _, net := range n {
if net.Contains(ip) {
return true
}
}
return false
}

View File

@@ -16,7 +16,7 @@ func TestReportLocalNetworks(t *testing.T) {
"nonets": {},
"foo": {"local_networks": "10.0.0.1/8 192.168.1.1/24 10.0.0.1/8 badnet/33"},
}}})
want := render.Networks([]*net.IPNet{
want := report.Networks([]*net.IPNet{
mustParseCIDR("10.0.0.1/8"),
mustParseCIDR("192.168.1.1/24"),
})
@@ -26,21 +26,6 @@ func TestReportLocalNetworks(t *testing.T) {
}
}
func TestContains(t *testing.T) {
networks := render.Networks([]*net.IPNet{
mustParseCIDR("10.0.0.1/8"),
mustParseCIDR("192.168.1.1/24"),
})
if networks.Contains(net.ParseIP("52.52.52.52")) {
t.Errorf("52.52.52.52 not in %v", networks)
}
if !networks.Contains(net.ParseIP("10.0.0.1")) {
t.Errorf("10.0.0.1 in %v", networks)
}
}
func mustParseCIDR(s string) *net.IPNet {
_, ipNet, err := net.ParseCIDR(s)
if err != nil {

View File

@@ -55,11 +55,18 @@ func MakeEndpointNodeID(hostID, address, port string) string {
// MakeAddressNodeID produces an address node ID from its composite parts.
func MakeAddressNodeID(hostID, address string) string {
if !isLoopback(address) {
// Only loopback addresses get scoped by hostID.
hostID = ""
var scope string
// Loopback addresses and addresses explicity marked as
// local get scoped by hostID
addressIP := net.ParseIP(address)
if addressIP != nil && LocalNetworks.Contains(addressIP) {
scope = hostID
} else if isLoopback(address) {
scope = hostID
}
return hostID + ScopeDelim + address
return scope + ScopeDelim + address
}
// MakeProcessNodeID produces a process node ID from its composite parts.

60
report/networks.go Normal file
View File

@@ -0,0 +1,60 @@
package report
import (
"net"
)
// Networks represent a set of subnets
type Networks []*net.IPNet
// Interface is exported for testing.
type Interface interface {
Addrs() ([]net.Addr, error)
}
// Variables exposed for testing
var (
LocalNetworks = Networks{}
InterfaceByNameStub = func(name string) (Interface, error) {
return net.InterfaceByName(name)
}
)
// Contains returns true if IP is in Networks.
func (n Networks) Contains(ip net.IP) bool {
for _, net := range n {
if net.Contains(ip) {
return true
}
}
return false
}
// AddLocalBridge records the subnet address associated with the bridge name
// supplied, such that MakeAddressNodeID will scope addresses in this subnet
// as local.
func AddLocalBridge(name string) error {
inf, err := InterfaceByNameStub(name)
if err != nil {
return err
}
addrs, err := inf.Addrs()
if err != nil {
return err
}
for _, addr := range addrs {
_, network, err := net.ParseCIDR(addr.String())
if err != nil {
return err
}
if network == nil {
continue
}
LocalNetworks = append(LocalNetworks, network)
}
return nil
}

72
report/networks_test.go Normal file
View File

@@ -0,0 +1,72 @@
package report_test
import (
"net"
"reflect"
"testing"
"github.com/weaveworks/scope/report"
"github.com/weaveworks/scope/test"
)
func TestContains(t *testing.T) {
networks := report.Networks([]*net.IPNet{
mustParseCIDR("10.0.0.1/8"),
mustParseCIDR("192.168.1.1/24"),
})
if networks.Contains(net.ParseIP("52.52.52.52")) {
t.Errorf("52.52.52.52 not in %v", networks)
}
if !networks.Contains(net.ParseIP("10.0.0.1")) {
t.Errorf("10.0.0.1 in %v", networks)
}
}
func mustParseCIDR(s string) *net.IPNet {
_, ipNet, err := net.ParseCIDR(s)
if err != nil {
panic(err)
}
return ipNet
}
type mockInterface struct {
addrs []net.Addr
}
type mockAddr string
func (m mockInterface) Addrs() ([]net.Addr, error) {
return m.addrs, nil
}
func (m mockAddr) Network() string {
return "ip+net"
}
func (m mockAddr) String() string {
return string(m)
}
func TestAddLocal(t *testing.T) {
oldInterfaceByNameStub := report.InterfaceByNameStub
defer func() { report.InterfaceByNameStub = oldInterfaceByNameStub }()
report.InterfaceByNameStub = func(name string) (report.Interface, error) {
return mockInterface{[]net.Addr{mockAddr("52.53.54.55/16")}}, nil
}
err := report.AddLocalBridge("foo")
if err != nil {
t.Errorf("%v", err)
}
want := report.Networks([]*net.IPNet{mustParseCIDR("52.53.54.55/16")})
have := report.LocalNetworks
if !reflect.DeepEqual(want, have) {
t.Errorf("%s", test.Diff(want, have))
}
}