Merge pull request #22319 from Luap99/exposed-ports-ps

podman ps: show exposed ports under PORTS as well
This commit is contained in:
openshift-merge-bot[bot]
2024-04-12 10:11:43 +00:00
committed by GitHub
6 changed files with 67 additions and 34 deletions

View File

@ -20,6 +20,7 @@ import (
"github.com/docker/go-units" "github.com/docker/go-units"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/exp/slices"
) )
var ( var (
@ -434,10 +435,7 @@ func (l psReporter) Networks() string {
// Ports converts from Portmappings to the string form // Ports converts from Portmappings to the string form
// required by ps // required by ps
func (l psReporter) Ports() string { func (l psReporter) Ports() string {
if len(l.ListContainer.Ports) < 1 { return portsToString(l.ListContainer.Ports, l.ListContainer.ExposedPorts)
return ""
}
return portsToString(l.ListContainer.Ports)
} }
// CreatedAt returns the container creation time in string format. podman // CreatedAt returns the container creation time in string format. podman
@ -489,8 +487,8 @@ func (l psReporter) UTS() string {
// portsToString converts the ports used to a string of the from "port1, port2" // portsToString converts the ports used to a string of the from "port1, port2"
// and also groups a continuous list of ports into a readable format. // and also groups a continuous list of ports into a readable format.
// The format is IP:HostPort(-Range)->ContainerPort(-Range)/Proto // The format is IP:HostPort(-Range)->ContainerPort(-Range)/Proto
func portsToString(ports []types.PortMapping) string { func portsToString(ports []types.PortMapping, exposedPorts map[uint16][]string) string {
if len(ports) == 0 { if len(ports) == 0 && len(exposedPorts) == 0 {
return "" return ""
} }
sb := &strings.Builder{} sb := &strings.Builder{}
@ -512,6 +510,20 @@ func portsToString(ports []types.PortMapping) string {
} }
} }
} }
// iterating a map is not deterministic so let's convert slice first and sort by port to make it deterministic
sortedPorts := make([]uint16, 0, len(exposedPorts))
for port := range exposedPorts {
sortedPorts = append(sortedPorts, port)
}
slices.Sort(sortedPorts)
for _, port := range sortedPorts {
for _, protocol := range exposedPorts[port] {
// exposed ports do not have a host part and are just written as "NUM/PROTO"
fmt.Fprintf(sb, "%d/%s, ", port, protocol)
}
}
display := sb.String() display := sb.String()
// make sure to trim the last ", " of the string // make sure to trim the last ", " of the string
return display[:len(display)-2] return display[:len(display)-2]

View File

@ -2,7 +2,11 @@
####> podman create, run ####> podman create, run
####> If file is edited, make sure the changes ####> If file is edited, make sure the changes
####> are applicable to all of those. ####> are applicable to all of those.
#### **--expose**=*port* #### **--expose**=*port[/protocol]*
Expose a port, or a range of ports (e.g. **--expose=3300-3310**) to set up port redirection Expose a port or a range of ports (e.g. **--expose=3300-3310**).
on the host system. The protocol can be `tcp`, `udp` or `sctp` and if not given `tcp` is assumed.
This option matches the EXPOSE instruction for image builds and has no effect on
the actual networking rules unless **-P/--publish-all** is used to forward to all
exposed ports from random host ports. To forward specific ports from the host
into the container use the **-p/--publish** option instead.

View File

@ -80,6 +80,7 @@ Valid placeholders for the Go template are listed below:
| .ExitCode | Container exit code | | .ExitCode | Container exit code |
| .Exited | "true" if container has exited | | .Exited | "true" if container has exited |
| .ExitedAt | Time (epoch seconds) that container exited | | .ExitedAt | Time (epoch seconds) that container exited |
| .ExposedPorts ... | Map of exposed ports on this container |
| .ID | Container ID | | .ID | Container ID |
| .Image | Image Name/ID | | .Image | Image Name/ID |
| .ImageID | Image ID | | .ImageID | Image ID |
@ -92,7 +93,7 @@ Valid placeholders for the Go template are listed below:
| .Pid | Process ID on host system | | .Pid | Process ID on host system |
| .Pod | Pod the container is associated with (SHA) | | .Pod | Pod the container is associated with (SHA) |
| .PodName | PodName of the container | | .PodName | PodName of the container |
| .Ports | Exposed ports | | .Ports | Forwarded and exposed ports |
| .Restarts | Display the container restart count | | .Restarts | Display the container restart count |
| .RunningFor | Time elapsed since container was started | | .RunningFor | Time elapsed since container was started |
| .Size | Size of container | | .Size | Size of container |

View File

@ -25,6 +25,11 @@ type ListContainer struct {
ExitedAt int64 ExitedAt int64
// If container has exited, the return code from the command // If container has exited, the return code from the command
ExitCode int32 ExitCode int32
// ExposedPorts contains the ports that are exposed but not forwarded,
// see Ports for forwarded ports.
// The key is the port number and the string slice contains the protocols,
// i.e. "tcp", "udp" and "sctp".
ExposedPorts map[uint16][]string
// The unique identifier for the container // The unique identifier for the container
ID string `json:"Id"` ID string `json:"Id"`
// Container image // Container image

View File

@ -245,6 +245,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
ExitCode: exitCode, ExitCode: exitCode,
Exited: exited, Exited: exited,
ExitedAt: exitedTime.Unix(), ExitedAt: exitedTime.Unix(),
ExposedPorts: conConfig.ExposedPorts,
ID: conConfig.ID, ID: conConfig.ID,
Image: conConfig.RootfsImageName, Image: conConfig.RootfsImageName,
ImageID: conConfig.RootfsImageID, ImageID: conConfig.RootfsImageID,

View File

@ -26,7 +26,7 @@ var _ = Describe("Podman container inspect", func() {
It("podman inspect shows exposed ports", func() { It("podman inspect shows exposed ports", func() {
name := "testcon" name := "testcon"
session := podmanTest.Podman([]string{"run", "-d", "--stop-timeout", "0", "--expose", "8787/udp", "--name", name, ALPINE, "sleep", "inf"}) session := podmanTest.Podman([]string{"run", "-d", "--stop-timeout", "0", "--expose", "8787/udp", "--name", name, ALPINE, "sleep", "100"})
session.WaitWithDefaultTimeout() session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly()) Expect(session).Should(ExitCleanly())
data := podmanTest.InspectContainer(name) data := podmanTest.InspectContainer(name)
@ -34,6 +34,11 @@ var _ = Describe("Podman container inspect", func() {
Expect(data).To(HaveLen(1)) Expect(data).To(HaveLen(1))
Expect(data[0].NetworkSettings.Ports). Expect(data[0].NetworkSettings.Ports).
To(Equal(map[string][]define.InspectHostPort{"8787/udp": nil})) To(Equal(map[string][]define.InspectHostPort{"8787/udp": nil}))
session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("8787/udp"))
}) })
It("podman inspect shows exposed ports on image", func() { It("podman inspect shows exposed ports on image", func() {
@ -46,6 +51,11 @@ var _ = Describe("Podman container inspect", func() {
Expect(data).To(HaveLen(1)) Expect(data).To(HaveLen(1))
Expect(data[0].NetworkSettings.Ports). Expect(data[0].NetworkSettings.Ports).
To(Equal(map[string][]define.InspectHostPort{"80/tcp": nil, "8989/tcp": nil})) To(Equal(map[string][]define.InspectHostPort{"80/tcp": nil, "8989/tcp": nil}))
session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("80/tcp, 8989/tcp"))
}) })
It("podman inspect shows volumes-from with mount options", func() { It("podman inspect shows volumes-from with mount options", func() {