Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ExposedPorts to Inspect's ContainerConfig #24110

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions libpod/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,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{}{}
}
}
mheon marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -4,6 +4,7 @@ package libpod

import (
"fmt"
"strings"

"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/pkg/shortnames"
Expand Down Expand Up @@ -175,6 +176,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 @@ -97,6 +97,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"`

// V4PodmanCompatMarshal indicates that the json marshaller should
// use the old v4 inspect format to keep API compatibility.
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 @@ -535,19 +535,6 @@ func LibpodToContainerJSON(l *libpod.Container, sz bool) (*types.ContainerJSON,
}
stopTimeout := int(l.StopTimeout())

exposedPorts := make(nat.PortSet)
for ep := range inspect.NetworkSettings.Ports {
port, proto, ok := strings.Cut(ep, "/")
if !ok {
return nil, fmt.Errorf("PORT/PROTOCOL Format required for %q", ep)
}
exposedPort, err := nat.NewPort(proto, port)
if err != nil {
return nil, err
}
exposedPorts[exposedPort] = struct{}{}
}

var healthcheck *container.HealthConfig
if inspect.Config.Healthcheck != nil {
healthcheck = &container.HealthConfig{
Expand All @@ -559,6 +546,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
23 changes: 23 additions & 0 deletions test/e2e/container_inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ 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, "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()
Expand All @@ -61,6 +63,27 @@ var _ = Describe("Podman container inspect", func() {
Expect(session.OutputToString()).To(Equal("80/tcp, 8989/tcp"))
})

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())
})

It("podman inspect shows volumes-from with mount options", func() {
ctr1 := "volfctr"
ctr2 := "voltctr"
Expand Down