diff options
-rw-r--r-- | cmd/podman/containers/port.go | 123 | ||||
-rw-r--r-- | pkg/domain/entities/containers.go | 15 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 28 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 4 |
5 files changed, 171 insertions, 0 deletions
diff --git a/cmd/podman/containers/port.go b/cmd/podman/containers/port.go new file mode 100644 index 000000000..0e50140ca --- /dev/null +++ b/cmd/podman/containers/port.go @@ -0,0 +1,123 @@ +package containers + +import ( + "fmt" + "strconv" + "strings" + + "github.com/containers/libpod/cmd/podman/parse" + "github.com/containers/libpod/cmd/podman/registry" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/cri-o/ocicni/pkg/ocicni" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + portDescription = `List port mappings for the CONTAINER, or lookup the public-facing port that is NAT-ed to the PRIVATE_PORT +` + portCommand = &cobra.Command{ + Use: "port [flags] CONTAINER [PORT]", + Short: "List port mappings or a specific mapping for the container", + Long: portDescription, + RunE: port, + Args: func(cmd *cobra.Command, args []string) error { + return parse.CheckAllLatestAndCIDFile(cmd, args, true, false) + }, + Example: `podman port --all + podman port ctrID 80/tcp + podman port --latest 80`, + } +) + +var ( + portOpts entities.ContainerPortOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode}, + Command: portCommand, + }) + flags := portCommand.Flags() + flags.BoolVarP(&portOpts.All, "all", "a", false, "Display port information for all containers") + flags.BoolVarP(&portOpts.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + if registry.IsRemote() { + _ = flags.MarkHidden("latest") + } +} + +func port(cmd *cobra.Command, args []string) error { + var ( + container string + err error + userPort ocicni.PortMapping + ) + + if len(args) == 0 && !portOpts.Latest && !portOpts.All { + return errors.Errorf("you must supply a running container name or id") + } + if !portOpts.Latest && len(args) >= 1 { + container = args[0] + } + port := "" + if len(args) > 1 && !portOpts.Latest { + port = args[1] + } + if len(args) == 1 && portOpts.Latest { + port = args[0] + } + if len(port) > 0 { + fields := strings.Split(port, "/") + if len(fields) > 2 || len(fields) < 1 { + return errors.Errorf("port formats are port/protocol. '%s' is invalid", port) + } + if len(fields) == 1 { + fields = append(fields, "tcp") + } + + portNum, err := strconv.Atoi(fields[0]) + if err != nil { + return err + } + userPort = ocicni.PortMapping{ + HostPort: 0, + ContainerPort: int32(portNum), + Protocol: fields[1], + HostIP: "", + } + } + + reports, err := registry.ContainerEngine().ContainerPort(registry.GetContext(), container, portOpts) + if err != nil { + return err + } + var found bool + // Iterate mappings + for _, report := range reports { + for _, v := range report.Ports { + hostIP := v.HostIP + // Set host IP to 0.0.0.0 if blank + if hostIP == "" { + hostIP = "0.0.0.0" + } + if portOpts.All { + fmt.Printf("%s\t", report.Id[:12]) + } + // 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 + } + if v == userPort { + fmt.Printf("%s:%d\n", hostIP, v.HostPort) + found = true + break + } + } + if !found && port != "" { + return errors.Errorf("failed to find published port %q", port) + } + } + return nil +} diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 52327a905..3f9d2392c 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -8,6 +8,7 @@ import ( "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/specgen" + "github.com/cri-o/ocicni/pkg/ocicni" ) type WaitOptions struct { @@ -341,3 +342,17 @@ type ContainerPruneReport struct { ID map[string]int64 Err map[string]error } + +// ContainerPortOptions describes the options to obtain +// port information on containers +type ContainerPortOptions struct { + All bool + Latest bool +} + +// ContainerPortReport describes the output needed for +// the CLI to output ports +type ContainerPortReport struct { + Id string + Ports []ocicni.PortMapping +} diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 506d1c317..58f7af41a 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -28,6 +28,7 @@ type ContainerEngine interface { ContainerLogs(ctx context.Context, containers []string, options ContainerLogsOptions) error ContainerMount(ctx context.Context, nameOrIds []string, options ContainerMountOptions) ([]*ContainerMountReport, error) ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) + ContainerPort(ctx context.Context, nameOrId string, options ContainerPortOptions) ([]*ContainerPortReport, error) ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error) ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error) ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error) diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index e71ceb536..73a0d8ec3 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -929,3 +929,31 @@ func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []str func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) { return ic.Libpod.GetConfig() } + +func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrId string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) { + var reports []*entities.ContainerPortReport + ctrs, err := getContainersByContext(options.All, false, []string{nameOrId}, ic.Libpod) + if err != nil { + return nil, err + } + for _, con := range ctrs { + state, err := con.State() + if err != nil { + return nil, err + } + if state != define.ContainerStateRunning { + continue + } + portmappings, err := con.PortMappings() + if err != nil { + return nil, err + } + if len(portmappings) > 0 { + reports = append(reports, &entities.ContainerPortReport{ + Id: con.ID(), + Ports: portmappings, + }) + } + } + return reports, nil +} diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 679bb371b..0bcc70128 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -371,3 +371,7 @@ func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []str func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) { return config.Default() } + +func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrId string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) { + return nil, errors.New("not implemented") +} |