From 970eaf003328cab69aa4ccaa78cf908f5a87fff0 Mon Sep 17 00:00:00 2001 From: baude Date: Mon, 30 Apr 2018 15:22:50 -0500 Subject: podman should assign a host port to -p when omitted If the user does not provide a host port when adding -p to create/run, podman should inject an available random port. podman run -p 80 .... podman should assign a random port to the host and expose the container port 80 to it Signed-off-by: baude Closes: #703 Approved by: rhatdan --- cmd/podman/create.go | 43 ++++++++++++++++++++++++++++++----------- test/e2e/run_networking_test.go | 14 ++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/cmd/podman/create.go b/cmd/podman/create.go index 856fbfa83..54a542ee5 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -371,26 +371,47 @@ func exposedPorts(c *cli.Context, imageExposedPorts map[string]struct{}) (map[na if err != nil { return nil, err } - l, err := net.Listen("tcp", ":0") + rp, err := getRandomPort() if err != nil { - return nil, errors.Wrapf(err, "unable to get free port") - } - defer l.Close() - _, randomPort, err := net.SplitHostPort(l.Addr().String()) - if err != nil { - return nil, errors.Wrapf(err, "unable to determine free port") + return nil, err } - rp, err := strconv.Atoi(randomPort) + logrus.Debug(fmt.Sprintf("Using random host port %d with container port %d", rp, p.Int())) + portBindings[p] = CreatePortBinding(rp, "") + } + } + + // We need to see if any host ports are not populated and if so, we need to assign a + // random port to them. + for k, pb := range portBindings { + if pb[0].HostPort == "" { + hostPort, err := getRandomPort() if err != nil { - return nil, errors.Wrapf(err, "unable to convert random port to int") + return nil, err } - logrus.Debug(fmt.Sprintf("Using random host port %s with container port %d", randomPort, p.Int())) - portBindings[p] = CreatePortBinding(rp, "") + logrus.Debug(fmt.Sprintf("Using random host port %d with container port %s", hostPort, k.Port())) + pb[0].HostPort = strconv.Itoa(hostPort) } } return portBindings, nil } +func getRandomPort() (int, error) { + l, err := net.Listen("tcp", ":0") + if err != nil { + return 0, errors.Wrapf(err, "unable to get free port") + } + defer l.Close() + _, randomPort, err := net.SplitHostPort(l.Addr().String()) + if err != nil { + return 0, errors.Wrapf(err, "unable to determine free port") + } + rp, err := strconv.Atoi(randomPort) + if err != nil { + return 0, errors.Wrapf(err, "unable to convert random port to int") + } + return rp, nil +} + // Parses CLI options related to container creation into a config which can be // parsed into an OCI runtime spec func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime, imageName string, data *inspect.ImageData) (*createConfig, error) { diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index b56b11634..9a2858ca1 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -77,4 +77,18 @@ var _ = Describe("Podman rmi", func() { Expect(results.ExitCode()).To(Equal(0)) Expect(results.OutputToString()).To(ContainSubstring(": 80,")) }) + + It("podman run network expose duplicate host port results in error", func() { + session := podmanTest.Podman([]string{"run", "-dt", "-p", "80", ALPINE, "/bin/sh"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"inspect", "-l"}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + + containerConfig := inspect.InspectContainerToJSON() + Expect(containerConfig[0].NetworkSettings.Ports[0].HostPort).ToNot(Equal("80")) + }) + }) -- cgit v1.2.3-54-g00ecf