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>
This commit is contained in:
baude 2018-01-22 13:56:08 -06:00
parent a03e040f0b
commit b74e38b042
6 changed files with 263 additions and 0 deletions

View file

@ -57,6 +57,7 @@ func main() {
mountCommand,
pauseCommand,
psCommand,
portCommand,
pullCommand,
pushCommand,
rmCommand,

145
cmd/podman/port.go Normal file
View file

@ -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
}

View file

@ -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)|

View file

@ -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

60
docs/podman-port.1.md Normal file
View file

@ -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>

43
test/podman_port.bats Normal file
View file

@ -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 ]
}