Files
docker-cli/cli/command/container/port.go
Rob Murray 4a608069a7 vendor: github.com/moby/moby/api, moby/moby/client master
Signed-off-by: Rob Murray <rob.murray@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-10-27 20:26:27 +01:00

91 lines
2.5 KiB
Go

package container
import (
"context"
"fmt"
"net"
"sort"
"strings"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/fvbommel/sortorder"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/client"
"github.com/spf13/cobra"
)
type portOptions struct {
container string
port string
}
// newPortCommand creates a new cobra.Command for "docker container port".
func newPortCommand(dockerCLI command.Cli) *cobra.Command {
var opts portOptions
cmd := &cobra.Command{
Use: "port CONTAINER [PRIVATE_PORT[/PROTO]]",
Short: "List port mappings or a specific mapping for the container",
Args: cli.RequiresRangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
opts.container = args[0]
if len(args) > 1 {
opts.port = args[1]
}
return runPort(cmd.Context(), dockerCLI, &opts)
},
Annotations: map[string]string{
"aliases": "docker container port, docker port",
},
ValidArgsFunction: completion.ContainerNames(dockerCLI, false),
DisableFlagsInUseLine: true,
}
return cmd
}
// runPort shows the port mapping for a given container. Optionally, it
// allows showing the mapping for a specific (container)port and proto.
//
// TODO(thaJeztah): currently this defaults to show the TCP port if no
// proto is specified. We should consider changing this to "any" protocol
// for the given private port.
func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) error {
c, err := dockerCli.Client().ContainerInspect(ctx, opts.container, client.ContainerInspectOptions{})
if err != nil {
return err
}
var out []string
if opts.port != "" {
port, err := network.ParsePort(opts.port)
if err != nil {
return err
}
frontends, exists := c.Container.NetworkSettings.Ports[port]
if !exists || len(frontends) == 0 {
return fmt.Errorf("no public port '%s' published for %s", opts.port, opts.container)
}
for _, frontend := range frontends {
out = append(out, net.JoinHostPort(frontend.HostIP.String(), frontend.HostPort))
}
} else {
for from, frontends := range c.Container.NetworkSettings.Ports {
for _, frontend := range frontends {
out = append(out, fmt.Sprintf("%s -> %s", from, net.JoinHostPort(frontend.HostIP.String(), frontend.HostPort)))
}
}
}
if len(out) > 0 {
sort.Slice(out, func(i, j int) bool {
return sortorder.NaturalLess(out[i], out[j])
})
_, _ = fmt.Fprintln(dockerCli.Out(), strings.Join(out, "\n"))
}
return nil
}