Files
weave-scope/report/id.go
Bryan Boreham 871751873b Stop render package depending on probe
This dependency makes it harder to see the structure of the program,
and sometimes complicates compilation.

Mostly just changing the source of strings that are already exported
from the report package.  A few new strings have to be moved there,
plus the function `IsPauseImageName()`.
2019-09-15 17:03:04 +00:00

313 lines
11 KiB
Go

package report
import (
"net"
"strings"
)
// 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"
// WeaveOverlayPeerPrefix is the prefix for weave peers in the overlay network
WeaveOverlayPeerPrefix = ""
// DockerOverlayPeerPrefix is the prefix for docker peers in the overlay network
DockerOverlayPeerPrefix = "docker_peer_"
)
// MakeEndpointNodeID produces an endpoint node ID from its composite parts.
func MakeEndpointNodeID(hostID, namespaceID, address, port string) string {
return makeAddressID(hostID, namespaceID, address) + ScopeDelim + port
}
// MakeAddressNodeID produces an address node ID from its composite parts.
func MakeAddressNodeID(hostID, address string) string {
return makeAddressID(hostID, "", address)
}
func makeAddressID(hostID, namespaceID, address string) string {
var scope string
// Loopback addresses and addresses explicitly marked as local get
// scoped by hostID
// Loopback addresses are also scoped by the networking
// namespace if available, since they can clash.
addressIP := net.ParseIP(address)
if addressIP != nil && LocalNetworks.Contains(addressIP) {
scope = hostID
} else if IsLoopback(address) {
scope = hostID
if namespaceID != "" {
scope += "-" + namespaceID
}
}
return scope + ScopeDelim + address
}
// MakeScopedEndpointNodeID is like MakeEndpointNodeID, but it always
// prefixes the ID with a scope.
func MakeScopedEndpointNodeID(scope, address, port string) string {
return scope + ScopeDelim + address + ScopeDelim + port
}
// MakeScopedAddressNodeID is like MakeAddressNodeID, but it always
// prefixes the ID witha scope.
func MakeScopedAddressNodeID(scope, address string) string {
return scope + ScopeDelim + address
}
// MakeProcessNodeID produces a process node ID from its composite parts.
func MakeProcessNodeID(hostID, pid string) string {
return hostID + ScopeDelim + pid
}
// MakeECSServiceNodeID produces an ECS Service node ID from its composite parts.
func MakeECSServiceNodeID(cluster, serviceName string) string {
return cluster + ScopeDelim + serviceName
}
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")
// MakeDaemonSetNodeID produces a replica set node ID from its composite parts.
MakeDaemonSetNodeID = makeSingleComponentID("daemonset")
// ParseDaemonSetNodeID parses a daemon set node ID
ParseDaemonSetNodeID = parseSingleComponentID("daemonset")
// MakeStatefulSetNodeID produces a statefulset node ID from its composite parts.
MakeStatefulSetNodeID = makeSingleComponentID("statefulset")
// ParseStatefulSetNodeID parses a statefulset node ID
ParseStatefulSetNodeID = parseSingleComponentID("statefulset")
// MakeCronJobNodeID produces a cronjob node ID from its composite parts.
MakeCronJobNodeID = makeSingleComponentID("cronjob")
// ParseCronJobNodeID parses a cronjob node ID
ParseCronJobNodeID = parseSingleComponentID("cronjob")
// MakeJobNodeID produces a job node ID from its composite parts.
MakeJobNodeID = makeSingleComponentID("job")
// ParseJobNodeID parses a job node ID
ParseJobNodeID = parseSingleComponentID("job")
// MakeNamespaceNodeID produces a namespace node ID from its composite parts.
MakeNamespaceNodeID = makeSingleComponentID("namespace")
// ParseNamespaceNodeID parses a namespace set node ID
ParseNamespaceNodeID = parseSingleComponentID("namespace")
// MakeECSTaskNodeID produces a ECSTask node ID from its composite parts.
MakeECSTaskNodeID = makeSingleComponentID("ecs_task")
// ParseECSTaskNodeID parses a ECSTask node ID
ParseECSTaskNodeID = parseSingleComponentID("ecs_task")
// MakeSwarmServiceNodeID produces a Swarm service node ID from its composite parts.
MakeSwarmServiceNodeID = makeSingleComponentID("swarm_service")
// ParseSwarmServiceNodeID parses a Swarm service node ID
ParseSwarmServiceNodeID = parseSingleComponentID("swarm_service")
// MakePersistentVolumeNodeID produces a Persistent Volume node ID from its composite parts.
MakePersistentVolumeNodeID = makeSingleComponentID("persistent_volume")
// ParsePersistentVolumeNodeID parses a Persistent Volume node ID
ParsePersistentVolumeNodeID = parseSingleComponentID("persistent_volume")
// MakePersistentVolumeClaimNodeID produces a Persistent Volume Claim node ID from its composite parts.
MakePersistentVolumeClaimNodeID = makeSingleComponentID("persistent_volume_claim")
// ParsePersistentVolumeClaimNodeID parses a Persistent Volume Claim node ID
ParsePersistentVolumeClaimNodeID = parseSingleComponentID("persistent_volume_claim")
// MakeStorageClassNodeID produces a storage class node ID from its composite parts.
MakeStorageClassNodeID = makeSingleComponentID("storage_class")
// ParseStorageClassNodeID parses a storage class node ID
ParseStorageClassNodeID = parseSingleComponentID("storage_class")
// MakeVolumeSnapshotNodeID produces a volume snapshot node ID from its composite parts.
MakeVolumeSnapshotNodeID = makeSingleComponentID("volume_snapshot")
// ParseVolumeSnapshotNodeID parses a volume snapshot node ID
ParseVolumeSnapshotNodeID = parseSingleComponentID("volume_snapshot")
// MakeVolumeSnapshotDataNodeID produces a volume snapshot data node ID from its composite parts.
MakeVolumeSnapshotDataNodeID = makeSingleComponentID("volume_snapshot_data")
// ParseVolumeSnapshotDataNodeID parses a volume snapshot data node ID
ParseVolumeSnapshotDataNodeID = parseSingleComponentID("volume_snapshot_data")
)
// 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) {
field0, field1, ok := split2(id, ScopeDelim)
if !ok || field1 != "<"+tag+">" {
return "", false
}
return field0, true
}
}
// MakeOverlayNodeID produces an overlay topology node ID from a router peer's
// prefix and name, which is assumed to be globally unique.
func MakeOverlayNodeID(peerPrefix, peerName string) string {
return "#" + peerPrefix + peerName
}
// ParseOverlayNodeID produces the overlay type and peer name.
func ParseOverlayNodeID(id string) (overlayPrefix string, peerName string) {
if !strings.HasPrefix(id, "#") {
// Best we can do
return "", ""
}
id = id[1:]
if strings.HasPrefix(id, DockerOverlayPeerPrefix) {
return DockerOverlayPeerPrefix, id[len(DockerOverlayPeerPrefix):]
}
return WeaveOverlayPeerPrefix, id
}
// Split a string s into two parts separated by sep.
func split2(s, sep string) (s1, s2 string, ok bool) {
// Not using strings.SplitN() to avoid a heap allocation
pos := strings.Index(s, sep)
if pos == -1 {
return "", "", false
}
return s[:pos], s[pos+1:], true
}
// ParseNodeID produces the id and tag of a single-component node ID.
func ParseNodeID(nodeID string) (id string, tag string, ok bool) {
return split2(nodeID, ScopeDelim)
}
// ParseEndpointNodeID produces the scope, address, and port and remainder.
// Note that scope may be blank.
func ParseEndpointNodeID(endpointNodeID string) (scope, address, port string, ok bool) {
// Not using strings.SplitN() to avoid a heap allocation
first := strings.Index(endpointNodeID, ScopeDelim)
if first == -1 {
return "", "", "", false
}
second := strings.Index(endpointNodeID[first+1:], ScopeDelim)
if second == -1 {
return "", "", "", false
}
return endpointNodeID[:first], endpointNodeID[first+1 : first+1+second], endpointNodeID[first+1+second+1:], true
}
// ParseAddressNodeID produces the host ID, address from an address node ID.
func ParseAddressNodeID(addressNodeID string) (hostID, address string, ok bool) {
return split2(addressNodeID, ScopeDelim)
}
// ParseProcessNodeID produces the host ID and PID from a process node ID.
func ParseProcessNodeID(processNodeID string) (hostID, pid string, ok bool) {
return split2(processNodeID, ScopeDelim)
}
// ParseECSServiceNodeID produces the cluster, service name from an ECS Service node ID
func ParseECSServiceNodeID(ecsServiceNodeID string) (cluster, serviceName string, ok bool) {
cluster, serviceName, ok = split2(ecsServiceNodeID, ScopeDelim)
if !ok {
return "", "", false
}
// In previous versions, ECS Service node IDs were of form serviceName + "<ecs_service>".
// For backwards compatibility, we should still return a sensical serviceName for these cases.
if serviceName == "<ecs_service>" {
return "unknown", cluster, true
}
return cluster, serviceName, true
}
// ExtractHostID extracts the host id from Node
func ExtractHostID(m Node) string {
hostNodeID, _ := m.Latest.Lookup(HostNodeID)
hostID, _ := ParseHostNodeID(hostNodeID)
return hostID
}
// IsLoopback ascertains if an address comes from a loopback interface.
func IsLoopback(address string) bool {
ip := net.ParseIP(address)
return ip != nil && ip.IsLoopback()
}
// IsPauseImageName indicates whether an image name corresponds to a
// kubernetes pause container image.
func IsPauseImageName(imageName string) bool {
return strings.Contains(imageName, "google_containers/pause") ||
strings.Contains(imageName, "k8s.gcr.io/pause") ||
strings.Contains(imageName, "eks/pause")
}