hostmap.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. //go:build e2e_testing
  2. // +build e2e_testing
  3. package router
  4. import (
  5. "fmt"
  6. "sort"
  7. "strings"
  8. "github.com/slackhq/nebula"
  9. "github.com/slackhq/nebula/iputil"
  10. )
  11. type edge struct {
  12. from string
  13. to string
  14. dual bool
  15. }
  16. func renderHostmaps(controls ...*nebula.Control) string {
  17. var lines []*edge
  18. r := "graph TB\n"
  19. for _, c := range controls {
  20. sr, se := renderHostmap(c)
  21. r += sr
  22. for _, e := range se {
  23. add := true
  24. // Collapse duplicate edges into a bi-directionally connected edge
  25. for _, ge := range lines {
  26. if e.to == ge.from && e.from == ge.to {
  27. add = false
  28. ge.dual = true
  29. break
  30. }
  31. }
  32. if add {
  33. lines = append(lines, e)
  34. }
  35. }
  36. }
  37. for _, line := range lines {
  38. if line.dual {
  39. r += fmt.Sprintf("\t%v <--> %v\n", line.from, line.to)
  40. } else {
  41. r += fmt.Sprintf("\t%v --> %v\n", line.from, line.to)
  42. }
  43. }
  44. return r
  45. }
  46. func renderHostmap(c *nebula.Control) (string, []*edge) {
  47. var lines []string
  48. var globalLines []*edge
  49. clusterName := strings.Trim(c.GetCert().Details.Name, " ")
  50. clusterVpnIp := c.GetCert().Details.Ips[0].IP
  51. r := fmt.Sprintf("\tsubgraph %s[\"%s (%s)\"]\n", clusterName, clusterName, clusterVpnIp)
  52. hm := c.GetHostmap()
  53. hm.RLock()
  54. defer hm.RUnlock()
  55. // Draw the vpn to index nodes
  56. r += fmt.Sprintf("\t\tsubgraph %s.hosts[\"Hosts (vpn ip to index)\"]\n", clusterName)
  57. hosts := sortedHosts(hm.Hosts)
  58. for _, vpnIp := range hosts {
  59. hi := hm.Hosts[vpnIp]
  60. r += fmt.Sprintf("\t\t\t%v.%v[\"%v\"]\n", clusterName, vpnIp, vpnIp)
  61. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, hi.GetLocalIndex()))
  62. rs := hi.GetRelayState()
  63. for _, relayIp := range rs.CopyRelayIps() {
  64. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, relayIp))
  65. }
  66. for _, relayIp := range rs.CopyRelayForIdxs() {
  67. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, vpnIp, clusterName, relayIp))
  68. }
  69. }
  70. r += "\t\tend\n"
  71. // Draw the relay hostinfos
  72. if len(hm.Relays) > 0 {
  73. r += fmt.Sprintf("\t\tsubgraph %s.relays[\"Relays (relay index to hostinfo)\"]\n", clusterName)
  74. for relayIndex, hi := range hm.Relays {
  75. r += fmt.Sprintf("\t\t\t%v.%v[\"%v\"]\n", clusterName, relayIndex, relayIndex)
  76. lines = append(lines, fmt.Sprintf("%v.%v --> %v.%v", clusterName, relayIndex, clusterName, hi.GetLocalIndex()))
  77. }
  78. r += "\t\tend\n"
  79. }
  80. // Draw the local index to relay or remote index nodes
  81. r += fmt.Sprintf("\t\tsubgraph indexes.%s[\"Indexes (index to hostinfo)\"]\n", clusterName)
  82. indexes := sortedIndexes(hm.Indexes)
  83. for _, idx := range indexes {
  84. hi, ok := hm.Indexes[idx]
  85. if ok {
  86. r += fmt.Sprintf("\t\t\t%v.%v[\"%v (%v)\"]\n", clusterName, idx, idx, hi.GetVpnIp())
  87. remoteClusterName := strings.Trim(hi.GetCert().Details.Name, " ")
  88. globalLines = append(globalLines, &edge{from: fmt.Sprintf("%v.%v", clusterName, idx), to: fmt.Sprintf("%v.%v", remoteClusterName, hi.GetRemoteIndex())})
  89. _ = hi
  90. }
  91. }
  92. r += "\t\tend\n"
  93. // Add the edges inside this host
  94. for _, line := range lines {
  95. r += fmt.Sprintf("\t\t%v\n", line)
  96. }
  97. r += "\tend\n"
  98. return r, globalLines
  99. }
  100. func sortedHosts(hosts map[iputil.VpnIp]*nebula.HostInfo) []iputil.VpnIp {
  101. keys := make([]iputil.VpnIp, 0, len(hosts))
  102. for key := range hosts {
  103. keys = append(keys, key)
  104. }
  105. sort.SliceStable(keys, func(i, j int) bool {
  106. return keys[i] > keys[j]
  107. })
  108. return keys
  109. }
  110. func sortedIndexes(indexes map[uint32]*nebula.HostInfo) []uint32 {
  111. keys := make([]uint32, 0, len(indexes))
  112. for key := range indexes {
  113. keys = append(keys, key)
  114. }
  115. sort.SliceStable(keys, func(i, j int) bool {
  116. return keys[i] > keys[j]
  117. })
  118. return keys
  119. }