Skip to content

Commit

Permalink
[v4.9-rhel] Add ExposedPorts to Inspect's ContainerConfig
Browse files Browse the repository at this point in the history
A field we missed versus Docker. Matches the format of our
existing Ports list in the NetworkConfig, but only includes
exposed ports (and maps these to struct{}, as they never go to
real ports on the host).

Fixes https://issues.redhat.com/browse/RHEL-60382

Signed-off-by: Matt Heon <[email protected]>
(cherry picked from commit edc3dc5)
Signed-off-by: tomsweeneyredhat <[email protected]>
  • Loading branch information
mheon authored and TomSweeneyRedHat committed Oct 22, 2024
1 parent 2e16c89 commit cc9b697
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 14 deletions.
19 changes: 19 additions & 0 deletions libpod/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,25 @@ func (c *Container) generateInspectContainerConfig(spec *spec.Spec) *define.Insp

ctrConfig.SdNotifyMode = c.config.SdNotifyMode
ctrConfig.SdNotifySocket = c.config.SdNotifySocket

// Exosed ports consists of all exposed ports and all port mappings for
// this container. It does *NOT* follow to another container if we share
// the network namespace.
exposedPorts := make(map[string]struct{})
for port, protocols := range c.config.ExposedPorts {
for _, proto := range protocols {
exposedPorts[fmt.Sprintf("%d/%s", port, proto)] = struct{}{}
}
}
for _, mapping := range c.config.PortMappings {
for i := range mapping.Range {
exposedPorts[fmt.Sprintf("%d/%s", mapping.ContainerPort+i, mapping.Protocol)] = struct{}{}
}
}
if len(exposedPorts) > 0 {
ctrConfig.ExposedPorts = exposedPorts
}

return ctrConfig
}

Expand Down
8 changes: 8 additions & 0 deletions libpod/container_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package libpod

import (
"fmt"
"strings"

"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/pkg/shortnames"
Expand Down Expand Up @@ -164,6 +165,13 @@ func (c *Container) validate() error {
return fmt.Errorf("cannot set a startup healthcheck when there is no regular healthcheck: %w", define.ErrInvalidArg)
}

// Ensure all ports list a single protocol
for _, p := range c.config.PortMappings {
if strings.Contains(p.Protocol, ",") {
return fmt.Errorf("each port mapping must define a single protocol, got a comma-separated list for container port %d (protocols requested %q): %w", p.ContainerPort, p.Protocol, define.ErrInvalidArg)
}
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions libpod/define/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ type InspectContainerConfig struct {
SdNotifyMode string `json:"sdNotifyMode,omitempty"`
// SdNotifySocket is the NOTIFY_SOCKET in use by/configured for the container.
SdNotifySocket string `json:"sdNotifySocket,omitempty"`
// ExposedPorts includes ports the container has exposed.
ExposedPorts map[string]struct{} `json:"ExposedPorts,omitempty"`
}

// InspectRestartPolicy holds information about the container's restart policy.
Expand Down
23 changes: 10 additions & 13 deletions pkg/api/handlers/compat/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,19 +522,6 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
}
stopTimeout := int(l.StopTimeout())

exposedPorts := make(nat.PortSet)
for ep := range inspect.NetworkSettings.Ports {
splitp := strings.SplitN(ep, "/", 2)
if len(splitp) != 2 {
return nil, fmt.Errorf("PORT/PROTOCOL Format required for %q", ep)
}
exposedPort, err := nat.NewPort(splitp[1], splitp[0])
if err != nil {
return nil, err
}
exposedPorts[exposedPort] = struct{}{}
}

var healthcheck *container.HealthConfig
if inspect.Config.Healthcheck != nil {
healthcheck = &container.HealthConfig{
Expand All @@ -546,6 +533,16 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
}
}

// Apparently the compiler can't convert a map[string]struct{} into a nat.PortSet
// (Despite a nat.PortSet being that exact struct with some types added)
var exposedPorts nat.PortSet
if len(inspect.Config.ExposedPorts) > 0 {
exposedPorts = make(nat.PortSet)
for p := range inspect.Config.ExposedPorts {
exposedPorts[nat.Port(p)] = struct{}{}
}
}

config := container.Config{
Hostname: l.Hostname(),
Domainname: inspect.Config.DomainName,
Expand Down
30 changes: 29 additions & 1 deletion test/e2e/container_inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ var _ = Describe("Podman container inspect", func() {

Expect(data).To(HaveLen(1))
Expect(data[0].NetworkSettings.Ports).
To(Equal(map[string][]define.InspectHostPort{"8787/udp": nil}))
To(Equal(map[string][]define.InspectHostPort{"8787/udp": nil, "99/sctp": nil}))
Expect(data[0].Config.ExposedPorts).
To(Equal(map[string]struct{}{"8787/udp": {}, "99/sctp": {}}))

session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(ExitCleanly())
Expect(session.OutputToString()).To(Equal("99/sctp, 8787/udp"))
})

It("podman inspect shows exposed ports on image", func() {
Expand All @@ -44,4 +51,25 @@ var _ = Describe("Podman container inspect", func() {
Expect(data[0].NetworkSettings.Ports).
To(Equal(map[string][]define.InspectHostPort{"80/tcp": nil, "8989/tcp": nil}))
})

It("podman inspect exposed ports includes published ports", func() {
c1 := "ctr1"
c1s := podmanTest.Podman([]string{"run", "-d", "--expose", "22/tcp", "-p", "8080:80/tcp", "--name", c1, ALPINE, "top"})
c1s.WaitWithDefaultTimeout()
Expect(c1s).Should(ExitCleanly())

c2 := "ctr2"
c2s := podmanTest.Podman([]string{"run", "-d", "--net", fmt.Sprintf("container:%s", c1), "--name", c2, ALPINE, "top"})
c2s.WaitWithDefaultTimeout()
Expect(c2s).Should(ExitCleanly())

data1 := podmanTest.InspectContainer(c1)
Expect(data1).To(HaveLen(1))
Expect(data1[0].Config.ExposedPorts).
To(Equal(map[string]struct{}{"22/tcp": {}, "80/tcp": {}}))

data2 := podmanTest.InspectContainer(c2)
Expect(data2).To(HaveLen(1))
Expect(data2[0].Config.ExposedPorts).To(BeNil())
})
})

0 comments on commit cc9b697

Please sign in to comment.