Skip to content

Commit 108cf9e

Browse files
committed
PRIVATE_PORT optional for docker compose port
Signed-off-by: Max Proske <max@mproske.com>
1 parent af0029a commit 108cf9e

8 files changed

Lines changed: 89 additions & 33 deletions

File tree

cmd/compose/port.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,20 @@ func portCommand(p *ProjectOptions, dockerCli command.Cli, backendOptions *Backe
4141
ProjectOptions: p,
4242
}
4343
cmd := &cobra.Command{
44-
Use: "port [OPTIONS] SERVICE PRIVATE_PORT",
45-
Short: "Print the public port for a port binding",
46-
Args: cobra.MinimumNArgs(2),
44+
Use: "port [OPTIONS] SERVICE [PRIVATE_PORT]",
45+
Short: "List port mappings or print the public port of a specific mapping for the service",
46+
Args: cobra.RangeArgs(1, 2),
4747
PreRunE: Adapt(func(ctx context.Context, args []string) error {
48-
port, err := strconv.ParseUint(args[1], 10, 16)
49-
if err != nil {
50-
return err
51-
}
52-
opts.port = uint16(port)
5348
opts.protocol = strings.ToLower(opts.protocol)
49+
if len(args) > 1 {
50+
port, err := strconv.ParseUint(args[1], 10, 16)
51+
if err != nil {
52+
return err
53+
}
54+
opts.port = uint16(port)
55+
} else {
56+
opts.protocol = ""
57+
}
5458
return nil
5559
}),
5660
RunE: Adapt(func(ctx context.Context, args []string) error {
@@ -73,14 +77,21 @@ func runPort(ctx context.Context, dockerCli command.Cli, backendOptions *Backend
7377
if err != nil {
7478
return err
7579
}
76-
ip, port, err := backend.Port(ctx, projectName, service, opts.port, api.PortOptions{
80+
publishers, err := backend.Ports(ctx, projectName, service, opts.port, api.PortOptions{
7781
Protocol: opts.protocol,
7882
Index: opts.index,
7983
})
8084
if err != nil {
8185
return err
8286
}
8387

84-
_, _ = fmt.Fprintf(dockerCli.Out(), "%s:%d\n", ip, port)
88+
if opts.port != 0 && len(publishers) > 0 {
89+
p := publishers[0]
90+
_, _ = fmt.Fprintf(dockerCli.Out(), "%s:%d\n", p.URL, p.PublishedPort)
91+
return nil
92+
}
93+
for _, p := range publishers {
94+
_, _ = fmt.Fprintln(dockerCli.Out(), p.String())
95+
}
8596
return nil
8697
}

docs/reference/compose.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Define and run multi-container applications with Docker
2828
| [`logs`](compose_logs.md) | View output from containers |
2929
| [`ls`](compose_ls.md) | List running compose projects |
3030
| [`pause`](compose_pause.md) | Pause services |
31-
| [`port`](compose_port.md) | Print the public port for a port binding |
31+
| [`port`](compose_port.md) | List port mappings or print the public port of a specific mapping for the service |
3232
| [`ps`](compose_ps.md) | List containers |
3333
| [`publish`](compose_publish.md) | Publish compose application |
3434
| [`pull`](compose_pull.md) | Pull service images |

docs/reference/compose_port.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# docker compose port
22

33
<!---MARKER_GEN_START-->
4-
Prints the public port for a port binding
4+
List port mappings or print the public port of a specific mapping for the service
55

66
### Options
77

@@ -16,4 +16,4 @@ Prints the public port for a port binding
1616

1717
## Description
1818

19-
Prints the public port for a port binding
19+
List port mappings or print the public port of a specific mapping for the service

docs/reference/docker_compose_port.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
command: docker compose port
2-
short: Print the public port for a port binding
3-
long: Prints the public port for a port binding
4-
usage: docker compose port [OPTIONS] SERVICE PRIVATE_PORT
2+
short: |
3+
List port mappings or print the public port of a specific mapping for the service
4+
long: |
5+
List port mappings or print the public port of a specific mapping for the service
6+
usage: docker compose port [OPTIONS] SERVICE [PRIVATE_PORT]
57
pname: docker compose
68
plink: docker_compose.yaml
79
options:

pkg/api/api.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import (
2020
"context"
2121
"fmt"
2222
"io"
23+
"net"
2324
"slices"
25+
"strconv"
2426
"strings"
2527
"time"
2628

@@ -124,8 +126,8 @@ type Compose interface {
124126
Top(ctx context.Context, projectName string, services []string) ([]ContainerProcSummary, error)
125127
// Events executes the equivalent to a `compose events`
126128
Events(ctx context.Context, projectName string, options EventsOptions) error
127-
// Port executes the equivalent to a `compose port`
128-
Port(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (string, int, error)
129+
// Ports executes the equivalent to a `compose port`
130+
Ports(ctx context.Context, projectName string, service string, port uint16, options PortOptions) (PortPublishers, error)
129131
// Publish executes the equivalent to a `compose publish`
130132
Publish(ctx context.Context, project *types.Project, repository string, options PublishOptions) error
131133
// Images executes the equivalent of a `compose images`
@@ -534,6 +536,10 @@ type PortPublisher struct {
534536
Protocol string
535537
}
536538

539+
func (p PortPublisher) String() string {
540+
return fmt.Sprintf("%d/%s -> %s", p.TargetPort, p.Protocol, net.JoinHostPort(p.URL, strconv.Itoa(p.PublishedPort)))
541+
}
542+
537543
// ContainerSummary hold high-level description of a container
538544
type ContainerSummary struct {
539545
ID string

pkg/api/api_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ import (
2323
"gotest.tools/v3/assert"
2424
)
2525

26+
func TestPortPublisherString(t *testing.T) {
27+
tests := []struct {
28+
name string
29+
pub PortPublisher
30+
want string
31+
}{
32+
{"ipv4", PortPublisher{URL: "0.0.0.0", TargetPort: 80, PublishedPort: 8080, Protocol: "tcp"}, "80/tcp -> 0.0.0.0:8080"},
33+
{"ipv6", PortPublisher{URL: "::", TargetPort: 5060, PublishedPort: 32769, Protocol: "udp"}, "5060/udp -> [::]:32769"},
34+
}
35+
for _, tt := range tests {
36+
t.Run(tt.name, func(t *testing.T) {
37+
assert.Equal(t, tt.pub.String(), tt.want)
38+
})
39+
}
40+
}
41+
2642
func TestRunOptionsEnvironmentMap(t *testing.T) {
2743
opts := RunOptions{
2844
Environment: []string{

pkg/compose/port.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,40 @@ import (
2626
"github.com/docker/compose/v5/pkg/api"
2727
)
2828

29-
func (s *composeService) Port(ctx context.Context, projectName string, service string, port uint16, options api.PortOptions) (string, int, error) {
29+
func (s *composeService) Ports(ctx context.Context, projectName string, service string, port uint16, options api.PortOptions) (api.PortPublishers, error) {
3030
projectName = strings.ToLower(projectName)
3131
ctr, err := s.getSpecifiedContainer(ctx, projectName, oneOffInclude, false, service, options.Index)
3232
if err != nil {
33-
return "", 0, err
33+
return nil, err
3434
}
35+
36+
if port != 0 {
37+
for _, p := range ctr.Ports {
38+
if p.PrivatePort == port && p.Type == options.Protocol {
39+
return api.PortPublishers{{
40+
URL: p.IP,
41+
TargetPort: int(p.PrivatePort),
42+
PublishedPort: int(p.PublicPort),
43+
Protocol: p.Type,
44+
}}, nil
45+
}
46+
}
47+
return nil, portNotFoundError(options.Protocol, port, ctr)
48+
}
49+
50+
var publishers api.PortPublishers
3551
for _, p := range ctr.Ports {
36-
if p.PrivatePort == port && p.Type == options.Protocol {
37-
return p.IP, int(p.PublicPort), nil
52+
if options.Protocol != "" && p.Type != options.Protocol {
53+
continue
3854
}
55+
publishers = append(publishers, api.PortPublisher{
56+
URL: p.IP,
57+
TargetPort: int(p.PrivatePort),
58+
PublishedPort: int(p.PublicPort),
59+
Protocol: p.Type,
60+
})
3961
}
40-
return "", 0, portNotFoundError(options.Protocol, port, ctr)
62+
return publishers, nil
4163
}
4264

4365
func portNotFoundError(protocol string, port uint16, ctr container.Summary) error {

pkg/mocks/mock_docker_compose_api.go

Lines changed: 9 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)