process.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. package render
  2. import (
  3. "context"
  4. "github.com/weaveworks/scope/report"
  5. )
  6. // Constants are used in the tests.
  7. const (
  8. InboundMajor = "The Internet"
  9. OutboundMajor = "The Internet"
  10. InboundMinor = "Inbound connections"
  11. OutboundMinor = "Outbound connections"
  12. )
  13. func renderProcesses(rpt report.Report) bool {
  14. return len(rpt.Process.Nodes) >= 1
  15. }
  16. // ProcessRenderer is a Renderer which produces a renderable process
  17. // graph by merging the endpoint graph and the process topology.
  18. var ProcessRenderer = Memoise(endpoints2Processes{})
  19. // ConnectedProcessRenderer is a Renderer which colors
  20. // connected nodes, so we can apply a filter to show/hide unconnected
  21. // nodes depending on user choice.
  22. //
  23. // not memoised
  24. var ConnectedProcessRenderer = ColorConnected(ProcessRenderer)
  25. // ProcessNameRenderer is a Renderer which produces a renderable
  26. // process name graph by munging the progess graph.
  27. //
  28. // It also colors connected nodes, so we can apply a filter to
  29. // show/hide unconnected nodes depending on user choice.
  30. //
  31. // not memoised
  32. var ProcessNameRenderer = ColorConnected(CustomRenderer{RenderFunc: processes2Names, Renderer: ProcessRenderer})
  33. // endpoints2Processes joins the endpoint topology to the process
  34. // topology, matching on hostID and pid.
  35. type endpoints2Processes struct {
  36. }
  37. func (e endpoints2Processes) Render(ctx context.Context, rpt report.Report) Nodes {
  38. if len(rpt.Process.Nodes) == 0 {
  39. return Nodes{}
  40. }
  41. endpoints := SelectEndpoint.Render(ctx, rpt).Nodes
  42. return MapEndpoints(
  43. func(n report.Node) string {
  44. pid, ok := n.Latest.Lookup(report.PID)
  45. if !ok {
  46. return ""
  47. }
  48. if hasMoreThanOneConnection(n, endpoints) {
  49. return ""
  50. }
  51. hostID := report.ExtractHostID(n)
  52. if hostID == "" {
  53. return ""
  54. }
  55. return report.MakeProcessNodeID(hostID, pid)
  56. }, report.Process).Render(ctx, rpt)
  57. }
  58. // When there is more than one connection originating from a source
  59. // endpoint, we cannot be sure that its pid is associated with all of
  60. // them, since the source endpoint may have been re-used by a
  61. // different process. See #2665. It is better to drop such an endpoint
  62. // than risk rendering bogus connections. Aliased connections - when
  63. // all the remote endpoints represent the same logical endpoint, due
  64. // to NATing - are fine though.
  65. func hasMoreThanOneConnection(n report.Node, endpoints report.Nodes) bool {
  66. if len(n.Adjacency) < 2 {
  67. return false
  68. }
  69. firstRealEndpointID := ""
  70. for _, endpointID := range n.Adjacency {
  71. if ep, ok := endpoints[endpointID]; ok {
  72. if copyID, _, ok := ep.Latest.LookupEntry(report.CopyOf); ok {
  73. endpointID = copyID
  74. }
  75. }
  76. if firstRealEndpointID == "" {
  77. firstRealEndpointID = endpointID
  78. } else if firstRealEndpointID != endpointID {
  79. return true
  80. }
  81. }
  82. return false
  83. }
  84. var processNameTopology = MakeGroupNodeTopology(report.Process, report.Name)
  85. // processes2Names maps process Nodes to Nodes for each process name.
  86. func processes2Names(ctx context.Context, processes Nodes) Nodes {
  87. ret := newJoinResults(nil)
  88. for _, n := range processes.Nodes {
  89. if n.Topology == Pseudo {
  90. ret.passThrough(n)
  91. } else if name, ok := n.Latest.Lookup(report.Name); ok {
  92. ret.addChildAndChildren(n, name, processNameTopology)
  93. }
  94. }
  95. return ret.result(ctx, processes)
  96. }