github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/container/port.go (about) 1 package container 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "sort" 8 "strconv" 9 "strings" 10 11 "github.com/docker/cli/cli" 12 "github.com/docker/cli/cli/command" 13 "github.com/docker/cli/cli/command/completion" 14 "github.com/docker/go-connections/nat" 15 "github.com/fvbommel/sortorder" 16 "github.com/pkg/errors" 17 "github.com/spf13/cobra" 18 ) 19 20 type portOptions struct { 21 container string 22 23 port string 24 } 25 26 // NewPortCommand creates a new cobra.Command for `docker port` 27 func NewPortCommand(dockerCli command.Cli) *cobra.Command { 28 var opts portOptions 29 30 cmd := &cobra.Command{ 31 Use: "port CONTAINER [PRIVATE_PORT[/PROTO]]", 32 Short: "List port mappings or a specific mapping for the container", 33 Args: cli.RequiresRangeArgs(1, 2), 34 RunE: func(cmd *cobra.Command, args []string) error { 35 opts.container = args[0] 36 if len(args) > 1 { 37 opts.port = args[1] 38 } 39 return runPort(cmd.Context(), dockerCli, &opts) 40 }, 41 Annotations: map[string]string{ 42 "aliases": "docker container port, docker port", 43 }, 44 ValidArgsFunction: completion.ContainerNames(dockerCli, false), 45 } 46 return cmd 47 } 48 49 // runPort shows the port mapping for a given container. Optionally, it 50 // allows showing the mapping for a specific (container)port and proto. 51 // 52 // TODO(thaJeztah): currently this defaults to show the TCP port if no 53 // proto is specified. We should consider changing this to "any" protocol 54 // for the given private port. 55 func runPort(ctx context.Context, dockerCli command.Cli, opts *portOptions) error { 56 c, err := dockerCli.Client().ContainerInspect(ctx, opts.container) 57 if err != nil { 58 return err 59 } 60 61 var out []string 62 if opts.port != "" { 63 port, proto, _ := strings.Cut(opts.port, "/") 64 if proto == "" { 65 proto = "tcp" 66 } 67 if _, err = strconv.ParseUint(port, 10, 16); err != nil { 68 return errors.Wrapf(err, "Error: invalid port (%s)", port) 69 } 70 frontends, exists := c.NetworkSettings.Ports[nat.Port(port+"/"+proto)] 71 if !exists || frontends == nil { 72 return errors.Errorf("Error: No public port '%s' published for %s", opts.port, opts.container) 73 } 74 for _, frontend := range frontends { 75 out = append(out, net.JoinHostPort(frontend.HostIP, frontend.HostPort)) 76 } 77 } else { 78 for from, frontends := range c.NetworkSettings.Ports { 79 for _, frontend := range frontends { 80 out = append(out, fmt.Sprintf("%s -> %s", from, net.JoinHostPort(frontend.HostIP, frontend.HostPort))) 81 } 82 } 83 } 84 85 if len(out) > 0 { 86 sort.Slice(out, func(i, j int) bool { 87 return sortorder.NaturalLess(out[i], out[j]) 88 }) 89 _, _ = fmt.Fprintln(dockerCli.Out(), strings.Join(out, "\n")) 90 } 91 92 return nil 93 }