Files
weave-scope/report/id.go

208 lines
6.3 KiB
Go

package report
import (
"hash"
"hash/fnv"
"net"
"strings"
"sync"
"github.com/bluele/gcache"
)
// TheInternet is used as a node ID to indicate a remote IP.
const TheInternet = "theinternet"
// Delimiters are used to separate parts of node IDs, to guarantee uniqueness
// in particular contexts.
const (
// ScopeDelim is a general-purpose delimiter used within node IDs to
// separate different contextual scopes. Different topologies have
// different key structures.
ScopeDelim = ";"
// EdgeDelim separates two node IDs when they need to exist in the same key.
// Concretely, it separates node IDs in keys that represent edges.
EdgeDelim = "|"
// Key added to nodes to prevent them being joined with conntracked connections
DoesNotMakeConnections = "does_not_make_connections"
)
var (
idCache = gcache.New(1024).LRU().Build()
hashers = sync.Pool{
New: func() interface{} {
return fnv.New64a()
},
}
)
func lookupID(part1, part2, part3 string, f func() string) string {
h := hashers.Get().(hash.Hash64)
h.Write([]byte(part1))
h.Write([]byte(part2))
h.Write([]byte(part3))
sum := h.Sum64()
var result string
if id, err := idCache.Get(sum); id != nil && err != nil {
result = id.(string)
} else {
result = f()
idCache.Set(sum, result)
}
h.Reset()
hashers.Put(h)
return result
}
// MakeEndpointNodeID produces an endpoint node ID from its composite parts.
func MakeEndpointNodeID(hostID, address, port string) string {
return lookupID(hostID, address, port, func() string {
return MakeAddressNodeID(hostID, address) + ScopeDelim + port
})
}
// MakeAddressNodeID produces an address node ID from its composite parts.
func MakeAddressNodeID(hostID, address string) string {
var scope string
// Loopback addresses and addresses explicitly 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 scope + ScopeDelim + address
}
// MakeScopedEndpointNodeID is like MakeEndpointNodeID, but it always
// prefixes the ID witha scope.
func MakeScopedEndpointNodeID(hostID, address, port string) string {
return hostID + ScopeDelim + address + ScopeDelim + port
}
// MakeScopedAddressNodeID is like MakeAddressNodeID, but it always
// prefixes the ID witha scope.
func MakeScopedAddressNodeID(hostID, address string) string {
return hostID + ScopeDelim + address
}
// MakeProcessNodeID produces a process node ID from its composite parts.
func MakeProcessNodeID(hostID, pid string) string {
return hostID + ScopeDelim + pid
}
var (
// MakeHostNodeID produces a host node ID from its composite parts.
MakeHostNodeID = makeSingleComponentID("host")
// ParseHostNodeID parses a host node ID
ParseHostNodeID = parseSingleComponentID("host")
// MakeContainerNodeID produces a container node ID from its composite parts.
MakeContainerNodeID = makeSingleComponentID("container")
// ParseContainerNodeID parses a container node ID
ParseContainerNodeID = parseSingleComponentID("container")
// MakeContainerImageNodeID produces a container image node ID from its composite parts.
MakeContainerImageNodeID = makeSingleComponentID("container_image")
// ParseContainerImageNodeID parses a container image node ID
ParseContainerImageNodeID = parseSingleComponentID("container_image")
// MakePodNodeID produces a pod node ID from its composite parts.
MakePodNodeID = makeSingleComponentID("pod")
// ParsePodNodeID parses a pod node ID
ParsePodNodeID = parseSingleComponentID("pod")
// MakeServiceNodeID produces a service node ID from its composite parts.
MakeServiceNodeID = makeSingleComponentID("service")
// ParseServiceNodeID parses a service node ID
ParseServiceNodeID = parseSingleComponentID("service")
// MakeDeploymentNodeID produces a deployment node ID from its composite parts.
MakeDeploymentNodeID = makeSingleComponentID("deployment")
// ParseDeploymentNodeID parses a deployment node ID
ParseDeploymentNodeID = parseSingleComponentID("deployment")
// MakeReplicaSetNodeID produces a replica set node ID from its composite parts.
MakeReplicaSetNodeID = makeSingleComponentID("replica_set")
// ParseReplicaSetNodeID parses a replica set node ID
ParseReplicaSetNodeID = parseSingleComponentID("replica_set")
)
// makeSingleComponentID makes a single-component node id encoder
func makeSingleComponentID(tag string) func(string) string {
return func(id string) string {
return id + ScopeDelim + "<" + tag + ">"
}
}
// parseSingleComponentID makes a single-component node id decoder
func parseSingleComponentID(tag string) func(string) (string, bool) {
return func(id string) (string, bool) {
fields := strings.SplitN(id, ScopeDelim, 2)
if len(fields) != 2 || fields[1] != "<"+tag+">" {
return "", false
}
return fields[0], true
}
}
// MakeOverlayNodeID produces an overlay topology node ID from a router peer's
// name, which is assumed to be globally unique.
func MakeOverlayNodeID(peerName string) string {
return "#" + peerName
}
// ParseNodeID produces the host ID and remainder (typically an address) from
// a node ID. Note that hostID may be blank.
func ParseNodeID(nodeID string) (hostID string, remainder string, ok bool) {
fields := strings.SplitN(nodeID, ScopeDelim, 2)
if len(fields) != 2 {
return "", "", false
}
return fields[0], fields[1], true
}
// ParseEndpointNodeID produces the host ID, address, and port and remainder
// (typically an address) from an endpoint node ID. Note that hostID may be
// blank.
func ParseEndpointNodeID(endpointNodeID string) (hostID, address, port string, ok bool) {
fields := strings.SplitN(endpointNodeID, ScopeDelim, 3)
if len(fields) != 3 {
return "", "", "", false
}
return fields[0], fields[1], fields[2], true
}
// ParseAddressNodeID produces the host ID, address from an address node ID.
func ParseAddressNodeID(addressNodeID string) (hostID, address string, ok bool) {
fields := strings.SplitN(addressNodeID, ScopeDelim, 2)
if len(fields) != 2 {
return "", "", false
}
return fields[0], fields[1], true
}
// ExtractHostID extracts the host id from Node
func ExtractHostID(m Node) string {
hostNodeID, _ := m.Latest.Lookup(HostNodeID)
hostID, _, _ := ParseNodeID(hostNodeID)
return hostID
}
func isLoopback(address string) bool {
ip := net.ParseIP(address)
return ip != nil && ip.IsLoopback()
}