123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- package report
- // "github.com/weaveworks/scope/common/xfer"
- // Names of the various topologies.
- const (
- Endpoint = "endpoint"
- Process = "process"
- Container = "container"
- Pod = "pod"
- Service = "service"
- Deployment = "deployment"
- ReplicaSet = "replica_set"
- DaemonSet = "daemon_set"
- StatefulSet = "stateful_set"
- CronJob = "cron_job"
- Namespace = "namespace"
- ContainerImage = "container_image"
- Host = "host"
- Overlay = "overlay"
- ECSService = "ecs_service"
- ECSTask = "ecs_task"
- SwarmService = "swarm_service"
- PersistentVolume = "persistent_volume"
- PersistentVolumeClaim = "persistent_volume_claim"
- StorageClass = "storage_class"
- VolumeSnapshot = "volume_snapshot"
- VolumeSnapshotData = "volume_snapshot_data"
- Job = "job"
- // Shapes used for different nodes
- Circle = "circle"
- Triangle = "triangle"
- Square = "square"
- Pentagon = "pentagon"
- Hexagon = "hexagon"
- Heptagon = "heptagon"
- Octagon = "octagon"
- Cloud = "cloud"
- Cylinder = "cylinder"
- DottedCylinder = "dottedcylinder"
- StorageSheet = "sheet"
- Camera = "camera"
- DottedTriangle = "dottedtriangle"
- // Used when counting the number of containers
- ContainersKey = "containers"
- )
- // topologyNames are the names of all report topologies.
- var topologyNames = []string{
- Endpoint,
- Process,
- Container,
- ContainerImage,
- Pod,
- Service,
- Deployment,
- ReplicaSet,
- DaemonSet,
- StatefulSet,
- CronJob,
- Namespace,
- Host,
- Overlay,
- ECSTask,
- ECSService,
- SwarmService,
- PersistentVolume,
- PersistentVolumeClaim,
- StorageClass,
- VolumeSnapshot,
- VolumeSnapshotData,
- Job,
- }
- // Report is the core data type. It's produced by probes, and consumed and
- // stored by apps. It's composed of multiple topologies, each representing
- // a different (related, but not equivalent) view of the network.
- // type Report struct {
- // // TS is the time this report was generated
- // TS time.Time
- // // Endpoint nodes are individual (address, port) tuples on each host.
- // // They come from inspecting active connections and can (theoretically)
- // // be traced back to a process. Edges are present.
- // Endpoint Topology
- // // Process nodes are processes on each host. Edges are not present.
- // Process Topology
- // // Container nodes represent all Docker containers on hosts running probes.
- // // Metadata includes things like containter id, name, image id etc.
- // // Edges are not present.
- // Container Topology
- // // Pod nodes represent all Kubernetes pods running on hosts running probes.
- // // Metadata includes things like pod id, name etc. Edges are not
- // // present.
- // Pod Topology
- // // Service nodes represent all Kubernetes services running on hosts running probes.
- // // Metadata includes things like service id, name etc. Edges are not
- // // present.
- // Service Topology
- // // Deployment nodes represent all Kubernetes deployments running on hosts running probes.
- // // Metadata includes things like deployment id, name etc. Edges are not
- // // present.
- // Deployment Topology
- // // ReplicaSet nodes represent all Kubernetes ReplicaSets running on hosts running probes.
- // // Metadata includes things like ReplicaSet id, name etc. Edges are not
- // // present.
- // ReplicaSet Topology
- // // DaemonSet nodes represent all Kubernetes DaemonSets running on hosts running probes.
- // // Metadata includes things like DaemonSet id, name etc. Edges are not
- // // present.
- // DaemonSet Topology
- // // StatefulSet nodes represent all Kubernetes Stateful Sets running on hosts running probes.
- // // Metadata includes things like Stateful Set id, name, etc. Edges are not
- // // present.
- // StatefulSet Topology
- // // CronJob nodes represent all Kubernetes Cron Jobs running on hosts running probes.
- // // Metadata includes things like Cron Job id, name, etc. Edges are not
- // // present.
- // CronJob Topology
- // // Namespace nodes represent all Kubernetes Namespaces running on hosts running probes.
- // // Metadata includes things like Namespace id, name, etc. Edges are not
- // // present.
- // Namespace Topology
- // // ContainerImages nodes represent all Docker containers images on
- // // hosts running probes. Metadata includes things like image id, name etc.
- // // Edges are not present.
- // ContainerImage Topology
- // // Host nodes are physical hosts that run probes. Metadata includes things
- // // like operating system, load, etc. The information is scraped by the
- // // probes with each published report. Edges are not present.
- // Host Topology
- // // ECS Task nodes are AWS ECS tasks, which represent a group of containers.
- // // Metadata is limited for now, more to come later. Edges are not present.
- // ECSTask Topology
- // // ECS Service nodes are AWS ECS services, which represent a specification for a
- // // desired count of tasks with a task definition template.
- // // Metadata is limited for now, more to come later. Edges are not present.
- // ECSService Topology
- // // Swarm Service nodes are Docker Swarm services, which represent a specification for a
- // // group of tasks (either one per host, or a desired count).
- // // Edges are not present.
- // SwarmService Topology
- // // Overlay nodes are active peers in any software-defined network that's
- // // overlaid on the infrastructure. The information is scraped by polling
- // // their status endpoints. Edges are present.
- // Overlay Topology
- // // Persistent Volume nodes represent all Kubernetes Persistent Volumes running on hosts running probes.
- // // Metadata is limited for now, more to come later.
- // PersistentVolume Topology
- // // Persistent Volume Claim nodes represent all Kubernetes Persistent Volume Claims running on hosts running probes.
- // // Metadata is limited for now, more to come later.
- // PersistentVolumeClaim Topology
- // // Storage Class represent all kubernetes Storage Classes on hosts running probes.
- // // Metadata is limited for now, more to come later.
- // StorageClass Topology
- // // VolumeSnapshot represent all Kubernetes Volume Snapshots on hosts running probes.
- // VolumeSnapshot Topology
- // // VolumeSnapshotData represent all Kubernetes Volume Snapshot Data on hosts running probes.
- // VolumeSnapshotData Topology
- // // Job represent all Kubernetes Job on hosts running probes.
- // Job Topology
- // DNS DNSRecords `json:"DNS,omitempty" deepequal:"nil==empty"`
- // // Backwards-compatibility for an accident in commit 951629a / release 1.11.6.
- // BugDNS DNSRecords `json:"nodes,omitempty"`
- // // Sampling data for this report.
- // Sampling Sampling
- // // Window is the amount of time that this report purports to represent.
- // // Windows must be carefully merged. They should only be added when
- // // reports cover non-overlapping periods of time. By default, we assume
- // // that's true, and add windows in merge operations. When that's not true,
- // // such as in the app, we expect the component to overwrite the window
- // // before serving it to consumers.
- // Window time.Duration
- // // Shortcut reports should be propagated to the UI as quickly as possible,
- // // bypassing the usual spy interval, publish interval and app ws interval.
- // Shortcut bool
- // Plugins xfer.PluginSpecs
- // // ID a random identifier for this report, used when caching
- // // rendered views of the report. Reports with the same id
- // // must be equal, but we don't require that equal reports have
- // // the same id.
- // ID string `deepequal:"skip"`
- // }
- // // MakeReport makes a clean report, ready to Merge() other reports into.
- // func MakeReport() Report {
- // return Report{
- // Endpoint: MakeTopology(),
- // Process: MakeTopology().
- // WithShape(Square).
- // WithLabel("process", "processes"),
- // Container: MakeTopology().
- // WithShape(Hexagon).
- // WithLabel("container", "containers"),
- // ContainerImage: MakeTopology().
- // WithShape(Hexagon).
- // WithLabel("image", "images"),
- // Host: MakeTopology().
- // WithShape(Circle).
- // WithLabel("host", "hosts"),
- // Pod: MakeTopology().
- // WithShape(Heptagon).
- // WithLabel("pod", "pods"),
- // Service: MakeTopology().
- // WithShape(Heptagon).
- // WithLabel("service", "services"),
- // Deployment: MakeTopology().
- // WithShape(Heptagon).
- // WithLabel("deployment", "deployments"),
- // ReplicaSet: MakeTopology().
- // WithShape(Triangle).
- // WithLabel("replica set", "replica sets"),
- // DaemonSet: MakeTopology().
- // WithShape(Pentagon).
- // WithLabel("daemonset", "daemonsets"),
- // StatefulSet: MakeTopology().
- // WithShape(Octagon).
- // WithLabel("stateful set", "stateful sets"),
- // CronJob: MakeTopology().
- // WithShape(Triangle).
- // WithLabel("cron job", "cron jobs"),
- // Namespace: MakeTopology(),
- // Overlay: MakeTopology().
- // WithShape(Circle).
- // WithLabel("peer", "peers"),
- // ECSTask: MakeTopology().
- // WithShape(Heptagon).
- // WithLabel("task", "tasks"),
- // ECSService: MakeTopology().
- // WithShape(Heptagon).
- // WithLabel("service", "services"),
- // SwarmService: MakeTopology().
- // WithShape(Heptagon).
- // WithLabel("service", "services"),
- // PersistentVolume: MakeTopology().
- // WithShape(Cylinder).
- // WithLabel("persistent volume", "persistent volumes"),
- // PersistentVolumeClaim: MakeTopology().
- // WithShape(DottedCylinder).
- // WithLabel("persistent volume claim", "persistent volume claims"),
- // StorageClass: MakeTopology().
- // WithShape(StorageSheet).
- // WithLabel("storage class", "storage classes"),
- // VolumeSnapshot: MakeTopology().
- // WithShape(DottedCylinder).
- // WithTag(Camera).
- // WithLabel("volume snapshot", "volume snapshots"),
- // VolumeSnapshotData: MakeTopology().
- // WithShape(Cylinder).
- // WithTag(Camera).
- // WithLabel("volume snapshot data", "volume snapshot data"),
- // Job: MakeTopology().
- // WithShape(DottedTriangle).
- // WithLabel("job", "jobs"),
- // DNS: DNSRecords{},
- // Sampling: Sampling{},
- // Window: 0,
- // Plugins: xfer.MakePluginSpecs(),
- // ID: fmt.Sprintf("%d", rand.Int63()),
- // }
- // }
- // // Copy returns a value copy of the report.
- // func (r Report) Copy() Report {
- // newReport := Report{
- // TS: r.TS,
- // DNS: r.DNS.Copy(),
- // Sampling: r.Sampling,
- // Window: r.Window,
- // Shortcut: r.Shortcut,
- // Plugins: r.Plugins.Copy(),
- // ID: fmt.Sprintf("%d", rand.Int63()),
- // }
- // newReport.WalkPairedTopologies(&r, func(newTopology, oldTopology *Topology) {
- // *newTopology = oldTopology.Copy()
- // })
- // return newReport
- // }
- // // UnsafeMerge merges another Report into the receiver. The original is modified.
- // func (r *Report) UnsafeMerge(other Report) {
- // // Merged report has the earliest non-zero timestamp
- // if !other.TS.IsZero() && (r.TS.IsZero() || other.TS.Before(r.TS)) {
- // r.TS = other.TS
- // }
- // r.DNS = r.DNS.Merge(other.DNS)
- // r.Sampling = r.Sampling.Merge(other.Sampling)
- // r.Window = r.Window + other.Window
- // r.Plugins = r.Plugins.Merge(other.Plugins)
- // r.WalkPairedTopologies(&other, func(ourTopology, theirTopology *Topology) {
- // ourTopology.UnsafeMerge(*theirTopology)
- // })
- // }
- // // UnsafeUnMerge removes any information from r that would be added by merging other.
- // // The original is modified.
- // func (r *Report) UnsafeUnMerge(other Report) {
- // // TODO: DNS, Sampling, Plugins
- // r.Window = r.Window - other.Window
- // r.WalkPairedTopologies(&other, func(ourTopology, theirTopology *Topology) {
- // ourTopology.UnsafeUnMerge(*theirTopology)
- // })
- // }
- // // UnsafeRemovePartMergedNodes removes nodes that have not fully re-merged.
- // // E.g. if a node is removed from source between two full reports, then we
- // // might only have a delta of its last state. Remove that from the set.
- // // The original is modified.
- // func (r *Report) UnsafeRemovePartMergedNodes(ctx context.Context) {
- // dropped := map[string]int{}
- // r.WalkNamedTopologies(func(name string, t *Topology) {
- // for k, v := range t.Nodes {
- // if v.isPartMerged() {
- // delete(t.Nodes, k)
- // dropped[name]++
- // }
- // }
- // })
- // if span := opentracing.SpanFromContext(ctx); span != nil && len(dropped) > 0 {
- // msg := ""
- // for name, count := range dropped {
- // msg += fmt.Sprintf("%s: %d, ", name, count)
- // }
- // span.LogKV("dropped-part-merged", msg)
- // }
- // }
- // // WalkTopologies iterates through the Topologies of the report,
- // // potentially modifying them
- // func (r *Report) WalkTopologies(f func(*Topology)) {
- // for _, name := range topologyNames {
- // f(r.topology(name))
- // }
- // }
- // // WalkNamedTopologies iterates through the Topologies of the report,
- // // potentially modifying them.
- // func (r *Report) WalkNamedTopologies(f func(string, *Topology)) {
- // for _, name := range topologyNames {
- // f(name, r.topology(name))
- // }
- // }
- // // WalkPairedTopologies iterates through the Topologies of this and another report,
- // // potentially modifying one or both.
- // func (r *Report) WalkPairedTopologies(o *Report, f func(*Topology, *Topology)) {
- // for _, name := range topologyNames {
- // f(r.topology(name), o.topology(name))
- // }
- // }
- // // topology returns a reference to one of the report's topologies,
- // // selected by name.
- // func (r *Report) topology(name string) *Topology {
- // switch name {
- // case Endpoint:
- // return &r.Endpoint
- // case Process:
- // return &r.Process
- // case Container:
- // return &r.Container
- // case ContainerImage:
- // return &r.ContainerImage
- // case Pod:
- // return &r.Pod
- // case Service:
- // return &r.Service
- // case Deployment:
- // return &r.Deployment
- // case ReplicaSet:
- // return &r.ReplicaSet
- // case DaemonSet:
- // return &r.DaemonSet
- // case StatefulSet:
- // return &r.StatefulSet
- // case CronJob:
- // return &r.CronJob
- // case Namespace:
- // return &r.Namespace
- // case Host:
- // return &r.Host
- // case Overlay:
- // return &r.Overlay
- // case ECSTask:
- // return &r.ECSTask
- // case ECSService:
- // return &r.ECSService
- // case SwarmService:
- // return &r.SwarmService
- // case PersistentVolume:
- // return &r.PersistentVolume
- // case PersistentVolumeClaim:
- // return &r.PersistentVolumeClaim
- // case StorageClass:
- // return &r.StorageClass
- // case VolumeSnapshot:
- // return &r.VolumeSnapshot
- // case VolumeSnapshotData:
- // return &r.VolumeSnapshotData
- // case Job:
- // return &r.Job
- // }
- // return nil
- // }
- // // Topology returns one of the report's topologies, selected by name.
- // func (r Report) Topology(name string) (Topology, bool) {
- // if t := r.topology(name); t != nil {
- // return *t, true
- // }
- // return Topology{}, false
- // }
- // // Validate checks the report for various inconsistencies.
- // func (r Report) Validate() error {
- // var errs []string
- // for _, name := range topologyNames {
- // if err := r.topology(name).Validate(); err != nil {
- // errs = append(errs, err.Error())
- // }
- // }
- // if r.Sampling.Count > r.Sampling.Total {
- // errs = append(errs, fmt.Sprintf("sampling count (%d) bigger than total (%d)", r.Sampling.Count, r.Sampling.Total))
- // }
- // if len(errs) > 0 {
- // return fmt.Errorf("%d error(s): %s", len(errs), strings.Join(errs, "; "))
- // }
- // return nil
- // }
- // // DropTopologiesOver - as a protection against overloading the app
- // // server, drop topologies that have really large node counts. In
- // // practice we only see this with runaway numbers of zombie processes.
- // func (r Report) DropTopologiesOver(limit int) (Report, []string) {
- // dropped := []string{}
- // r.WalkNamedTopologies(func(name string, topology *Topology) {
- // if topology != nil && len(topology.Nodes) > limit {
- // topology.Nodes = Nodes{}
- // dropped = append(dropped, name)
- // }
- // })
- // return r, dropped
- // }
- // // Summary returns a human-readable string summarising the contents, for diagnostic purposes
- // func (r Report) Summary() string {
- // ret := ""
- // if len(r.Host.Nodes) == 1 {
- // for k := range r.Host.Nodes {
- // ret = k + ": "
- // }
- // }
- // count := 0
- // r.WalkNamedTopologies(func(n string, t *Topology) {
- // if len(t.Nodes) > 0 {
- // count++
- // if count > 1 {
- // ret = ret + ", "
- // }
- // ret = ret + fmt.Sprintf("%s:%d", n, len(t.Nodes))
- // }
- // })
- // return ret
- // }
- // // Sampling describes how the packet data sources for this report were
- // // sampled. It can be used to calculate effective sample rates. We can't
- // // just put the rate here, because that can't be accurately merged. Counts
- // // in e.g. edge metadata structures have already been adjusted to
- // // compensate for the sample rate.
- // type Sampling struct {
- // Count uint64 // observed and processed
- // Total uint64 // observed overall
- // }
- // // Rate returns the effective sampling rate.
- // func (s Sampling) Rate() float64 {
- // if s.Total <= 0 {
- // return 1.0
- // }
- // return float64(s.Count) / float64(s.Total)
- // }
- // // Merge combines two sampling structures via simple addition and returns the
- // // result. The original is not modified.
- // func (s Sampling) Merge(other Sampling) Sampling {
- // return Sampling{
- // Count: s.Count + other.Count,
- // Total: s.Total + other.Total,
- // }
- // }
- // const (
- // // HostNodeID is a metadata foreign key, linking a node in any topology to
- // // a node in the host topology. That host node is the origin host, where
- // // the node was originally detected.
- // HostNodeID = "host_node_id"
- // // ControlProbeID is the random ID of the probe which controls the specific node.
- // ControlProbeID = "control_probe_id"
- // )
|