Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 896ac10

Browse files
Print all the published ports using port ranges.
Signed-off-by: Silvin Lubecki <silvin.lubecki@docker.com>
1 parent bb9310f commit 896ac10

5 files changed

Lines changed: 152 additions & 15 deletions

File tree

internal/inspect/inspect.go

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func Inspect(out io.Writer, app *types.App, argSettings map[string]string) error
3636
// Add Service section
3737
addSection(&sections, len(config.Services), func(w io.Writer) {
3838
for _, service := range config.Services {
39-
fmt.Fprintf(w, "%s\t%d\t%s\t%s\n", service.Name, getReplicas(service), getPorts(service), service.Image)
39+
fmt.Fprintf(w, "%s\t%d\t%s\t%s\n", service.Name, getReplicas(service), getPorts(service.Ports), service.Image)
4040
}
4141
}, "Service", "Replicas", "Ports", "Image")
4242

@@ -126,16 +126,6 @@ func getReplicas(service composetypes.ServiceConfig) int {
126126
return 1
127127
}
128128

129-
func getPorts(service composetypes.ServiceConfig) string {
130-
var ports []string
131-
for _, port := range service.Ports {
132-
if port.Published > 0 {
133-
ports = append(ports, fmt.Sprintf("%d", port.Published))
134-
}
135-
}
136-
return strings.Join(ports, ",")
137-
}
138-
139129
func extractSettings(app *types.App, argSettings map[string]string) ([]string, map[string]string, error) {
140130
allSettings, err := mergeAndFlattenSettings(app, argSettings)
141131
if err != nil {

internal/inspect/inspect_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ services:
7070
web:
7171
image: nginx:latest
7272
ports:
73-
- 8080:80
73+
- 8080-8100:12300-12320
7474
deploy:
7575
replicas: 2
7676
networks:

internal/inspect/ports.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package inspect
2+
3+
import (
4+
"fmt"
5+
"sort"
6+
"strings"
7+
8+
composetypes "github.com/docker/cli/cli/compose/types"
9+
)
10+
11+
type portRange struct {
12+
start uint32
13+
end *uint32
14+
}
15+
16+
func newPort(start uint32) *portRange {
17+
return &portRange{start: start}
18+
}
19+
20+
func (p *portRange) add(end uint32) bool {
21+
if p.end == nil {
22+
if p.start+1 == end {
23+
p.end = &end
24+
return true
25+
}
26+
return false
27+
}
28+
if *p.end+1 == end {
29+
p.end = &end
30+
return true
31+
32+
}
33+
return false
34+
}
35+
36+
func (p portRange) String() string {
37+
res := fmt.Sprintf("%d", p.start)
38+
if p.end != nil {
39+
res += fmt.Sprintf("-%d", *p.end)
40+
}
41+
return res
42+
}
43+
44+
// getPorts identifies all the published port ranges, merges them
45+
// if they are consecutive, and return a string with all the published
46+
// ports.
47+
func getPorts(ports []composetypes.ServicePortConfig) string {
48+
var (
49+
portRanges []*portRange
50+
lastPortRange *portRange
51+
)
52+
sort.Slice(ports, func(i int, j int) bool { return ports[i].Published < ports[j].Published })
53+
for _, port := range ports {
54+
if port.Published > 0 {
55+
if lastPortRange == nil {
56+
lastPortRange = newPort(port.Published)
57+
} else if !lastPortRange.add(port.Published) {
58+
portRanges = append(portRanges, lastPortRange)
59+
lastPortRange = newPort(port.Published)
60+
}
61+
}
62+
}
63+
if lastPortRange != nil {
64+
portRanges = append(portRanges, lastPortRange)
65+
}
66+
output := make([]string, len(portRanges))
67+
for i, p := range portRanges {
68+
output[i] = p.String()
69+
}
70+
return strings.Join(output, ",")
71+
}

internal/inspect/ports_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package inspect
2+
3+
import (
4+
"testing"
5+
6+
composetypes "github.com/docker/cli/cli/compose/types"
7+
"gotest.tools/assert"
8+
)
9+
10+
func TestGetPorts(t *testing.T) {
11+
for _, testcase := range []struct {
12+
name string
13+
ports []composetypes.ServicePortConfig
14+
expected string
15+
}{
16+
{
17+
name: "no-published-ports",
18+
ports: []composetypes.ServicePortConfig{target(80)},
19+
expected: "",
20+
},
21+
{
22+
name: "published-port",
23+
ports: []composetypes.ServicePortConfig{published(8080)},
24+
expected: "8080",
25+
},
26+
{
27+
name: "mix-published-target-ports",
28+
ports: []composetypes.ServicePortConfig{published(8080), target(80), published(9090)},
29+
expected: "8080,9090",
30+
},
31+
{
32+
name: "simple-range",
33+
ports: publishedRange(8080, 8085),
34+
expected: "8080-8085",
35+
},
36+
{
37+
name: "complex-range",
38+
ports: append(append(publishedRange(8080, 8081), target(80), published(8082)), publishedRange(8083, 8090)...),
39+
expected: "8080-8090",
40+
},
41+
{
42+
name: "multi-range",
43+
ports: append(append(publishedRange(8080, 8081), published(8083)), publishedRange(8085, 8086)...),
44+
expected: "8080-8081,8083,8085-8086",
45+
},
46+
{
47+
name: "ports-are-sorted",
48+
ports: []composetypes.ServicePortConfig{published(8080), published(8082), published(7979), published(8081)},
49+
expected: "7979,8080-8082",
50+
},
51+
} {
52+
t.Run(testcase.name, func(t *testing.T) {
53+
assert.Equal(t, getPorts(testcase.ports), testcase.expected)
54+
})
55+
}
56+
}
57+
58+
func published(port uint32) composetypes.ServicePortConfig {
59+
return composetypes.ServicePortConfig{
60+
Published: port,
61+
}
62+
}
63+
64+
func target(port uint32) composetypes.ServicePortConfig {
65+
return composetypes.ServicePortConfig{
66+
Target: port,
67+
}
68+
}
69+
70+
func publishedRange(start, end uint32) []composetypes.ServicePortConfig {
71+
var ports []composetypes.ServicePortConfig
72+
for i := start; i <= end; i++ {
73+
ports = append(ports, published(i))
74+
}
75+
return ports
76+
}

internal/inspect/testdata/inspect-full.golden

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ Maintained by: foo <foo@bar.com>
44

55
this is sparta !
66

7-
Service Replicas Ports Image
8-
------- -------- ----- -----
9-
web 2 8080 nginx:latest
7+
Service Replicas Ports Image
8+
------- -------- ----- -----
9+
web 2 8080-8100 nginx:latest
1010

1111
Network
1212
-------

0 commit comments

Comments
 (0)