mirror of
https://github.com/weaveworks/scope.git
synced 2026-02-14 18:09:59 +00:00
This shrinks some data-structures slightly. Citation: https://github.com/torvalds/linux/blob/6f0d349d922b/include/linux/ns_common.h#L10
329 lines
12 KiB
Go
329 lines
12 KiB
Go
package report
|
|
|
|
import (
|
|
"net"
|
|
"strconv"
|
|
"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 {
|
|
addressIP := net.ParseIP(address)
|
|
return makeAddressID(hostID, namespaceID, address, addressIP) + ScopeDelim + port
|
|
}
|
|
|
|
// MakeEndpointNodeIDB produces an endpoint node ID from its composite parts in binary, not strings.
|
|
func MakeEndpointNodeIDB(hostID string, namespaceID uint32, addressIP net.IP, port uint16) string {
|
|
namespace := ""
|
|
if namespaceID > 0 {
|
|
namespace = strconv.FormatUint(uint64(namespaceID), 10)
|
|
}
|
|
return makeAddressID(hostID, namespace, addressIP.String(), addressIP) + ScopeDelim + strconv.Itoa(int(port))
|
|
}
|
|
|
|
// MakeAddressNodeID produces an address node ID from its composite parts.
|
|
func MakeAddressNodeID(hostID, address string) string {
|
|
addressIP := net.ParseIP(address)
|
|
return makeAddressID(hostID, "", address, addressIP)
|
|
}
|
|
|
|
// MakeAddressNodeIDB produces an address node ID from its composite parts, in binary not string.
|
|
func MakeAddressNodeIDB(hostID string, addressIP net.IP) string {
|
|
return makeAddressID(hostID, "", addressIP.String(), addressIP)
|
|
}
|
|
|
|
func makeAddressID(hostID, namespaceID, address string, addressIP net.IP) 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.
|
|
if addressIP != nil && LocalNetworks.Contains(addressIP) {
|
|
scope = hostID
|
|
} else if addressIP != nil && addressIP.IsLoopback() {
|
|
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")
|
|
}
|