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

Support EXPOSE with port ranges #12305

Merged
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
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