aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/port.go145
-rw-r--r--commands.md1
-rw-r--r--completions/bash/podman13
-rw-r--r--docs/podman-port.1.md60
-rw-r--r--test/podman_port.bats43
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 ]
+}