Skip to content

Commit

Permalink
Merge pull request #12305 from colinbendell/add-expose-port-range
Browse files Browse the repository at this point in the history
Support EXPOSE with port ranges
  • Loading branch information
openshift-merge-robot authored Nov 21, 2021
2 parents a6976c9 + d173ebc commit 2f6cdd3
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 30 deletions.
36 changes: 9 additions & 27 deletions pkg/specgen/generate/ports.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import (
"fmt"
"net"
"sort"
"strconv"
"strings"

"github.com/containers/common/libimage"
"github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/utils"

"github.com/containers/podman/v3/pkg/specgen"
"github.com/containers/podman/v3/pkg/specgenutil"
"github.com/containers/podman/v3/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -410,31 +410,13 @@ func checkProtocol(protocol string, allowSCTP bool) ([]string, error) {
}

func GenExposedPorts(exposedPorts map[string]struct{}) (map[uint16]string, error) {
expose := make(map[uint16]string, len(exposedPorts))
for imgExpose := range exposedPorts {
// Expose format is portNumber[/protocol]
splitExpose := strings.SplitN(imgExpose, "/", 2)
num, err := strconv.Atoi(splitExpose[0])
if err != nil {
return nil, errors.Wrapf(err, "unable to convert image EXPOSE statement %q to port number", imgExpose)
}
if num > 65535 || num < 1 {
return nil, errors.Errorf("%d from image EXPOSE statement %q is not a valid port number", num, imgExpose)
}

// No need to validate protocol, we'll do it later.
newProto := "tcp"
if len(splitExpose) == 2 {
newProto = splitExpose[1]
}

proto := expose[uint16(num)]
if len(proto) > 1 {
proto = proto + "," + newProto
} else {
proto = newProto
}
expose[uint16(num)] = proto
expose := make([]string, 0, len(exposedPorts))
for e := range exposedPorts {
expose = append(expose, e)
}
toReturn, err := specgenutil.CreateExpose(expose)
if err != nil {
return nil, errors.Wrapf(err, "unable to convert image EXPOSE")
}
return expose, nil
return toReturn, nil
}
2 changes: 1 addition & 1 deletion pkg/specgenutil/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions
s.Pod = podID
}

expose, err := createExpose(c.Expose)
expose, err := CreateExpose(c.Expose)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/specgenutil/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ func ParseFilters(filter []string) (map[string][]string, error) {
return filters, nil
}

// createExpose parses user-provided exposed port definitions and converts them
// CreateExpose parses user-provided exposed port definitions and converts them
// into SpecGen format.
// TODO: The SpecGen format should really handle ranges more sanely - we could
// be massively inflating what is sent over the wire with a large range.
func createExpose(expose []string) (map[uint16]string, error) {
func CreateExpose(expose []string) (map[uint16]string, error) {
toReturn := make(map[uint16]string)

for _, e := range expose {
Expand Down
36 changes: 36 additions & 0 deletions test/e2e/run_networking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,42 @@ var _ = Describe("Podman run networking", func() {
Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal(""))
})

It("podman run --publish-all with EXPOSE port ranges in Dockerfile", func() {
// Test port ranges, range with protocol and with an overlapping port
podmanTest.AddImageToRWStore(ALPINE)
dockerfile := fmt.Sprintf(`FROM %s
EXPOSE 2002
EXPOSE 2001-2003
EXPOSE 2004-2005/tcp`, ALPINE)
imageName := "testimg"
podmanTest.BuildImage(dockerfile, imageName, "false")

// Verify that the buildah is just passing through the EXPOSE keys
inspect := podmanTest.Podman([]string{"inspect", imageName})
inspect.WaitWithDefaultTimeout()
image := inspect.InspectImageJSON()
Expect(len(image)).To(Equal(1))
Expect(len(image[0].Config.ExposedPorts)).To(Equal(3))
Expect(image[0].Config.ExposedPorts).To(HaveKey("2002/tcp"))
Expect(image[0].Config.ExposedPorts).To(HaveKey("2001-2003/tcp"))
Expect(image[0].Config.ExposedPorts).To(HaveKey("2004-2005/tcp"))

containerName := "testcontainer"
session := podmanTest.Podman([]string{"create", "--name", containerName, imageName, "true"})
session.WaitWithDefaultTimeout()
inspectOut := podmanTest.InspectContainer(containerName)
Expect(len(inspectOut)).To(Equal(1))

// Inspect the network settings with available ports to be mapped to the host
// Don't need to verity HostConfig.PortBindings since we used --publish-all
Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(5))
Expect(inspectOut[0].NetworkSettings.Ports).To(HaveKey("2001/tcp"))
Expect(inspectOut[0].NetworkSettings.Ports).To(HaveKey("2002/tcp"))
Expect(inspectOut[0].NetworkSettings.Ports).To(HaveKey("2003/tcp"))
Expect(inspectOut[0].NetworkSettings.Ports).To(HaveKey("2004/tcp"))
Expect(inspectOut[0].NetworkSettings.Ports).To(HaveKey("2005/tcp"))
})

It("podman run -p 127.0.0.1::8980/udp", func() {
name := "testctr"
session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1::8980/udp", "--name", name, ALPINE, "/bin/sh"})
Expand Down

0 comments on commit 2f6cdd3

Please sign in to comment.