mirror of
https://github.com/weaveworks/scope.git
synced 2026-03-04 18:51:17 +00:00
181 lines
4.8 KiB
Go
181 lines
4.8 KiB
Go
package overlay
|
|
|
|
import (
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/weaveworks/scope/common/backoff"
|
|
"github.com/weaveworks/scope/common/weave"
|
|
"github.com/weaveworks/scope/probe/docker"
|
|
"github.com/weaveworks/scope/probe/host"
|
|
"github.com/weaveworks/scope/report"
|
|
)
|
|
|
|
const (
|
|
// WeavePeerName is the key for the peer name, typically a MAC address.
|
|
WeavePeerName = "weave_peer_name"
|
|
|
|
// WeavePeerNickName is the key for the peer nickname, typically a
|
|
// hostname.
|
|
WeavePeerNickName = "weave_peer_nick_name"
|
|
|
|
// WeaveDNSHostname is the ket for the WeaveDNS hostname
|
|
WeaveDNSHostname = "weave_dns_hostname"
|
|
|
|
// WeaveMACAddress is the key for the mac address of the container on the
|
|
// weave network, to be found in container node metadata
|
|
WeaveMACAddress = "weave_mac_address"
|
|
)
|
|
|
|
// 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
|
|
hostID string
|
|
|
|
mtx sync.RWMutex
|
|
statusCache weave.Status
|
|
psCache map[string]weave.PSEntry
|
|
|
|
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 {
|
|
w := &Weave{
|
|
client: client,
|
|
hostID: hostID,
|
|
psCache: map[string]weave.PSEntry{},
|
|
}
|
|
|
|
w.backoff = backoff.New(w.status, "collecting weave status")
|
|
w.backoff.SetInitialBackoff(5 * time.Second)
|
|
go w.backoff.Start()
|
|
|
|
w.psBackoff = backoff.New(w.ps, "collecting weave ps")
|
|
w.psBackoff.SetInitialBackoff(10 * time.Second)
|
|
go w.psBackoff.Start()
|
|
|
|
return w
|
|
}
|
|
|
|
// Name of this reporter/tagger/ticker, for metrics gathering
|
|
func (*Weave) Name() string { return "Weave" }
|
|
|
|
// Stop gathering weave ps output.
|
|
func (w *Weave) Stop() {
|
|
w.backoff.Stop()
|
|
w.psBackoff.Stop()
|
|
}
|
|
|
|
func (w *Weave) ps() (bool, error) {
|
|
psEntriesByPrefix, err := w.client.PS()
|
|
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
|
|
if err != nil {
|
|
w.psCache = map[string]weave.PSEntry{}
|
|
} else {
|
|
w.psCache = psEntriesByPrefix
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
func (w *Weave) status() (bool, error) {
|
|
status, err := w.client.Status()
|
|
|
|
w.mtx.Lock()
|
|
defer w.mtx.Unlock()
|
|
|
|
if err != nil {
|
|
w.statusCache = weave.Status{}
|
|
} else {
|
|
w.statusCache = status
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
// Tag implements Tagger.
|
|
func (w *Weave) Tag(r report.Report) (report.Report, error) {
|
|
w.mtx.RLock()
|
|
defer w.mtx.RUnlock()
|
|
|
|
// Put information from weaveDNS on the container nodes
|
|
for _, entry := range w.statusCache.DNS.Entries {
|
|
if entry.Tombstone > 0 {
|
|
continue
|
|
}
|
|
nodeID := report.MakeContainerNodeID(entry.ContainerID)
|
|
node, ok := r.Container.Nodes[nodeID]
|
|
if !ok {
|
|
continue
|
|
}
|
|
w, _ := node.Latest.Lookup(WeaveDNSHostname)
|
|
hostnames := report.IDList(strings.Fields(w))
|
|
hostnames = hostnames.Add(strings.TrimSuffix(entry.Hostname, "."))
|
|
r.Container.Nodes[nodeID] = node.WithLatests(map[string]string{WeaveDNSHostname: strings.Join(hostnames, " ")})
|
|
}
|
|
|
|
// Put information from weave ps on the container nodes
|
|
const maxPrefixSize = 12
|
|
for id, node := range r.Container.Nodes {
|
|
prefix, ok := node.Latest.Lookup(docker.ContainerID)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if len(prefix) > maxPrefixSize {
|
|
prefix = prefix[:maxPrefixSize]
|
|
}
|
|
entry, ok := w.psCache[prefix]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
ipsWithScope := report.MakeStringSet()
|
|
for _, ip := range entry.IPs {
|
|
ipsWithScope = ipsWithScope.Add(report.MakeAddressNodeID("", ip))
|
|
}
|
|
node = node.WithSet(docker.ContainerIPs, report.MakeStringSet(entry.IPs...))
|
|
node = node.WithSet(docker.ContainerIPsWithScopes, ipsWithScope)
|
|
node = node.WithLatests(map[string]string{
|
|
WeaveMACAddress: entry.MACAddress,
|
|
})
|
|
r.Container.Nodes[id] = node
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// Report implements Reporter.
|
|
func (w *Weave) Report() (report.Report, error) {
|
|
w.mtx.RLock()
|
|
defer w.mtx.RUnlock()
|
|
|
|
r := report.MakeReport()
|
|
r.Container = r.Container.WithMetadataTemplates(report.MetadataTemplates{
|
|
WeaveMACAddress: {ID: WeaveMACAddress, Label: "Weave MAC", From: report.FromLatest, Priority: 17},
|
|
WeaveDNSHostname: {ID: WeaveDNSHostname, Label: "Weave DNS Name", From: report.FromLatest, Priority: 18},
|
|
})
|
|
for _, peer := range w.statusCache.Router.Peers {
|
|
r.Overlay.AddNode(report.MakeNodeWith(report.MakeOverlayNodeID(peer.Name), map[string]string{
|
|
WeavePeerName: peer.Name,
|
|
WeavePeerNickName: peer.NickName,
|
|
}))
|
|
|
|
}
|
|
if w.statusCache.IPAM.DefaultSubnet != "" {
|
|
r.Overlay.AddNode(
|
|
report.MakeNode(report.MakeOverlayNodeID(w.statusCache.Router.Name)).WithSets(
|
|
report.MakeSets().Add(host.LocalNetworks, report.MakeStringSet(w.statusCache.IPAM.DefaultSubnet)),
|
|
),
|
|
)
|
|
}
|
|
return r, nil
|
|
}
|