Add ExposedPorts to Inspect's ContainerConfig
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 <mheon@redhat.com>
This commit is contained in:
parent
e1496c992a
commit
edc3dc5e11
|
@ -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{}{}
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ package libpod
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/image/v5/docker"
|
||||
"github.com/containers/image/v5/pkg/shortnames"
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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{
|
||||
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue