diff options
author | baude <bbaude@redhat.com> | 2018-01-22 13:56:08 -0600 |
---|---|---|
committer | baude <bbaude@redhat.com> | 2018-01-23 08:54:57 -0600 |
commit | b74e38b042cb32cead9adacbe75256a89e5cb664 (patch) | |
tree | ef61dc8a9e6ae41f46dea5fc1a1d22f78b1d4b70 | |
parent | a03e040f0bb1d32645879b2c8bec7c5e1fe0561f (diff) | |
download | podman-b74e38b042cb32cead9adacbe75256a89e5cb664.tar.gz podman-b74e38b042cb32cead9adacbe75256a89e5cb664.tar.bz2 podman-b74e38b042cb32cead9adacbe75256a89e5cb664.zip |
podman port
podman port reports the port mappings per container. it can be used
to report the ports ofa single container or latest container or all
containers.
in the case of a single container, the user can add an option filter for
port and protocol.
Signed-off-by: baude <bbaude@redhat.com>
-rw-r--r-- | cmd/podman/main.go | 1 | ||||
-rw-r--r-- | cmd/podman/port.go | 145 | ||||
-rw-r--r-- | commands.md | 1 | ||||
-rw-r--r-- | completions/bash/podman | 13 | ||||
-rw-r--r-- | docs/podman-port.1.md | 60 | ||||
-rw-r--r-- | test/podman_port.bats | 43 |
6 files changed, 263 insertions, 0 deletions
diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 0fd30fa71..bda8ff517 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -57,6 +57,7 @@ func main() { mountCommand, pauseCommand, psCommand, + portCommand, pullCommand, pushCommand, rmCommand, diff --git a/cmd/podman/port.go b/cmd/podman/port.go new file mode 100644 index 000000000..f105a14ed --- /dev/null +++ b/cmd/podman/port.go @@ -0,0 +1,145 @@ +package main + +import ( + "fmt" + "strconv" + "strings" + + "github.com/pkg/errors" + "github.com/projectatomic/libpod/libpod" + "github.com/urfave/cli" +) + +var ( + portFlags = []cli.Flag{ + cli.BoolFlag{ + Name: "all, a", + Usage: "display port information for all containers", + }, + LatestFlag, + } + portDescription = ` + podman port + + List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT +` + + portCommand = cli.Command{ + Name: "port", + Usage: "List port mappings or a specific mapping for the container", + Description: portDescription, + Flags: portFlags, + Action: portCmd, + ArgsUsage: "CONTAINER-NAME [mapping]", + } +) + +func portCmd(c *cli.Context) error { + var ( + userProto, containerName string + userPort int + container *libpod.Container + containers []*libpod.Container + ) + + args := c.Args() + if err := validateFlags(c, portFlags); err != nil { + return err + } + + if c.Bool("latest") && c.Bool("all") { + return errors.Errorf("the 'all' and 'latest' options cannot be used together") + } + if c.Bool("all") && len(args) > 0 { + return errors.Errorf("no additional arguments can be used with 'all'") + } + if len(args) == 0 && !c.Bool("latest") && !c.Bool("all") { + return errors.Errorf("you must supply a running container name or id") + } + if !c.Bool("latest") && !c.Bool("all") { + containerName = args[0] + } + + port := "" + if len(args) > 1 && !c.Bool("latest") { + port = args[1] + } + if len(args) == 1 && c.Bool("latest") { + port = args[0] + } + if port != "" { + fields := strings.Split(port, "/") + // User supplied at least port + var err error + // User supplied port and protocol + if len(fields) == 2 { + userProto = fields[1] + } + if len(fields) >= 1 { + p := fields[0] + userPort, err = strconv.Atoi(p) + if err != nil { + return errors.Wrapf(err, "unable to format port") + } + } + // Format is incorrect + if len(fields) > 2 || len(fields) < 1 { + return errors.Errorf("port formats are port/protocol. '%s' is invalid", port) + } + } + + runtime, err := getRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + if !c.Bool("latest") && !c.Bool("all") { + container, err = runtime.LookupContainer(containerName) + if err != nil { + return errors.Wrapf(err, "unable to find container %s", containerName) + } + containers = append(containers, container) + } else if c.Bool("latest") { + container, err = runtime.GetLatestContainer() + containers = append(containers, container) + } else { + containers, err = runtime.GetRunningContainers() + if err != nil { + return errors.Wrapf(err, "unable to get all containers") + } + } + + for _, con := range containers { + if state, _ := con.State(); state != libpod.ContainerStateRunning { + continue + } + if c.Bool("all") { + fmt.Println(con.ID()) + } + // Iterate mappings + for _, v := range con.Config().PortMappings { + hostIP := v.HostIP + // Set host IP to 0.0.0.0 if blank + if hostIP == "" { + hostIP = "0.0.0.0" + } + // If not searching by port or port/proto, then dump what we see + if port == "" { + fmt.Printf("%d/%s -> %s:%d\n", v.ContainerPort, v.Protocol, hostIP, v.HostPort) + continue + } + // We have a match on ports + if v.ContainerPort == int32(userPort) { + if userProto == "" || userProto == v.Protocol { + fmt.Printf("%s:%d", hostIP, v.HostPort) + break + } + } else { + return errors.Errorf("No public port '%d' published for %s", userPort, containerName) + } + } + } + + return nil +} diff --git a/commands.md b/commands.md index 7ce60d309..7eff993cd 100644 --- a/commands.md +++ b/commands.md @@ -25,6 +25,7 @@ | [podman-logs(1)](/docs/podman-logs.1.md) | Display the logs of a container |[![...](/docs/play.png)](https://asciinema.org/a/MZPTWD5CVs3dMREkBxQBY9C5z)| | [podman-mount(1)](/docs/podman-mount.1.md) | Mount a working container's root filesystem |[![...](/docs/play.png)](https://asciinema.org/a/YSP6hNvZo0RGeMHDA97PhPAf3)| | [podman-pause(1)](/docs/podman-pause.1.md) | Pause one or more running containers |[![...](/docs/play.png)](https://asciinema.org/a/141292)| +| [podman-port(1)](/docs/podman-port.1.md) | List port mappings for running containers |[![...](/docs/play.png)]()| | [podman-ps(1)](/docs/podman-ps.1.md) | Prints out information about containers |[![...](/docs/play.png)](https://asciinema.org/a/bbT41kac6CwZ5giESmZLIaTLR)| | [podman-pull(1)](/docs/podman-pull.1.md) | Pull an image from a registry |[![...](/docs/play.png)](https://asciinema.org/a/lr4zfoynHJOUNu1KaXa1dwG2X)| | [podman-push(1)](/docs/podman-push.1.md) | Push an image to a specified destination |[![...](/docs/play.png)](https://asciinema.org/a/133276)| diff --git a/completions/bash/podman b/completions/bash/podman index b1a19f255..f8086220e 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1413,6 +1413,18 @@ _podman_pause() { _complete_ "$options_with_args" "$boolean_options" } +_podman_port() { + local options_with_args=" + --help -h + " + local boolean_options=" + --all + -a + -l + --latest" + _complete_ "$options_with_args" "$boolean_options" +} + _podman_ps() { local options_with_args=" --filter -f @@ -1566,6 +1578,7 @@ _podman_podman() { logs mount pause + port ps pull push diff --git a/docs/podman-port.1.md b/docs/podman-port.1.md new file mode 100644 index 000000000..026c52cca --- /dev/null +++ b/docs/podman-port.1.md @@ -0,0 +1,60 @@ +% podman(1) podman-port - List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT +% Brent Baude +# podman-port "1" "January 2018" "podman" + +## NAME +podman port - List port mappings for a container + +## SYNOPSIS +**podman port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]** + +## DESCRIPTION +List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT + +## OPTIONS + +**--all, a** + +List all known port mappings for running containers. When using this option, you cannot pass any container names +or private ports/protocols as filters. + +**--latest, -l** +Instead of providing the container name or ID, use the last created container. If you use methods other than Podman +to run containers such as CRI-O, the last started container could be from either of those methods. + +## EXAMPLE + +List all port mappings +``` +#podman port -a +b4d2f05432e482e017b1a4b2eae15fa7b4f6fb7e9f65c1bde46294fdef285906 +80/udp -> 0.0.0.0:44327 +80/tcp -> 0.0.0.0:44327 +# +``` + +List port mappings for a specific container +``` +#podman port b4d2f054 +80/udp -> 0.0.0.0:44327 +80/tcp -> 0.0.0.0:44327 +# +``` +List the port mappings for the latest container and port 80 +``` +#podman port b4d2f054 80 + 0.0.0.0:44327 +# +``` + +List the port mappings for a specific container for port 80 and the tcp protocol. +``` +#podman port b4d2f054 80/tcp +0.0.0.0:44327 +# +``` +## SEE ALSO +podman(1), podan-inspect(1) + +## HISTORY +January 2018, Originally compiled by Brent Baude <bbaude@redhat.com> diff --git a/test/podman_port.bats b/test/podman_port.bats new file mode 100644 index 000000000..d13227b3c --- /dev/null +++ b/test/podman_port.bats @@ -0,0 +1,43 @@ +#!/usr/bin/env bats + +load helpers + +function teardown() { + cleanup_test +} + +function setup() { + copy_images +} + +@test "podman port all and latest" { + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} port -a -l + echo "$output" + echo "$status" + [ "$status" -ne 0 ] +} + +@test "podman port all and extra" { + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} port -a foobar + echo "$output" + echo "$status" + [ "$status" -ne 0 ] +} + +@test "podman port nginx" { + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -dt -P docker.io/library/nginx:latest + echo "$output" + [ "$status" -eq 0 ] + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} port -l + echo "$output" + [ "$status" -eq 0 ] + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} port -l 80 + echo "$output" + [ "$status" -eq 0 ] + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} port -l 80/tcp + echo "$output" + [ "$status" -eq 0 ] + run ${PODMAN_BINARY} ${PODMAN_OPTIONS} port -a + echo "$output" + [ "$status" -eq 0 ] +} |