container.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package formatter
  2. import (
  3. "fmt"
  4. "sort"
  5. "strconv"
  6. "strings"
  7. "github.com/docker/api/containers"
  8. )
  9. type portGroup struct {
  10. first uint32
  11. last uint32
  12. }
  13. // PortsString returns a human readable published ports
  14. func PortsString(ports []containers.Port) string {
  15. groupMap := make(map[string]*portGroup)
  16. var (
  17. result []string
  18. hostMappings []string
  19. groupMapKeys []string
  20. )
  21. sort.Slice(ports, func(i int, j int) bool {
  22. return comparePorts(ports[i], ports[j])
  23. })
  24. for _, port := range ports {
  25. // Simple case: HOST_IP:PORT1:PORT2
  26. hostIP := "0.0.0.0"
  27. if port.HostIP != "" {
  28. hostIP = port.HostIP
  29. }
  30. if port.HostPort != port.ContainerPort {
  31. hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", hostIP, port.HostPort, port.ContainerPort, port.Protocol))
  32. continue
  33. }
  34. current := port.ContainerPort
  35. portKey := fmt.Sprintf("%s/%s", hostIP, port.Protocol)
  36. group := groupMap[portKey]
  37. if group == nil {
  38. groupMap[portKey] = &portGroup{first: current, last: current}
  39. // record order that groupMap keys are created
  40. groupMapKeys = append(groupMapKeys, portKey)
  41. continue
  42. }
  43. if current == (group.last + 1) {
  44. group.last = current
  45. continue
  46. }
  47. result = append(result, formGroup(portKey, group.first, group.last))
  48. groupMap[portKey] = &portGroup{first: current, last: current}
  49. }
  50. for _, portKey := range groupMapKeys {
  51. g := groupMap[portKey]
  52. result = append(result, formGroup(portKey, g.first, g.last))
  53. }
  54. result = append(result, hostMappings...)
  55. return strings.Join(result, ", ")
  56. }
  57. func formGroup(key string, start uint32, last uint32) string {
  58. parts := strings.Split(key, "/")
  59. protocol := parts[0]
  60. var ip string
  61. if len(parts) > 1 {
  62. ip = parts[0]
  63. protocol = parts[1]
  64. }
  65. group := strconv.Itoa(int(start))
  66. // add range
  67. if start != last {
  68. group = fmt.Sprintf("%s-%d", group, last)
  69. }
  70. // add host ip
  71. if ip != "" {
  72. group = fmt.Sprintf("%s:%s->%s", ip, group, group)
  73. }
  74. // add protocol
  75. return fmt.Sprintf("%s/%s", group, protocol)
  76. }
  77. func comparePorts(i containers.Port, j containers.Port) bool {
  78. if i.ContainerPort != j.ContainerPort {
  79. return i.ContainerPort < j.ContainerPort
  80. }
  81. if i.HostIP != j.HostIP {
  82. return i.HostIP < j.HostIP
  83. }
  84. if i.HostPort != j.HostPort {
  85. return i.HostPort < j.HostPort
  86. }
  87. return i.Protocol < j.Protocol
  88. }