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  }