container.go 2.3 KB

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