1
0
Эх сурвалжийг харах

Merge pull request #97 from docker/feat-port-parsing

Port parsing on the comand line
Djordje Lukic 5 жил өмнө
parent
commit
23d2eacf84

+ 1 - 0
Dockerfile

@@ -9,6 +9,7 @@ ENV GO111MODULE=on
 
 WORKDIR ${PWD}
 ADD go.* ${PWD}
+RUN go mod download
 ADD . ${PWD}
 
 FROM golang:${GO_VERSION} AS protos-base

+ 2 - 2
azure/backend.go

@@ -148,8 +148,8 @@ func (cs *aciContainerService) Run(ctx context.Context, r containers.ContainerCo
 	var ports []types.ServicePortConfig
 	for _, p := range r.Ports {
 		ports = append(ports, types.ServicePortConfig{
-			Target:    p.Destination,
-			Published: p.Source,
+			Target:    p.ContainerPort,
+			Published: p.HostPort,
 		})
 	}
 	project := compose.Project{

+ 26 - 19
cli/cmd/run/opts.go

@@ -1,9 +1,9 @@
 package run
 
 import (
-	"fmt"
 	"strconv"
-	"strings"
+
+	"github.com/docker/go-connections/nat"
 
 	"github.com/docker/api/containers"
 )
@@ -14,27 +14,34 @@ type runOpts struct {
 }
 
 func toPorts(ports []string) ([]containers.Port, error) {
+	_, bindings, err := nat.ParsePortSpecs(ports)
+	if err != nil {
+		return nil, err
+	}
 	var result []containers.Port
 
-	for _, port := range ports {
-		parts := strings.Split(port, ":")
-		if len(parts) != 2 {
-			return nil, fmt.Errorf("unable to parse ports %q", port)
-		}
-		source, err := strconv.Atoi(parts[0])
-		if err != nil {
-			return nil, err
+	for port, bind := range bindings {
+		for _, portbind := range bind {
+			var hostPort uint32
+			if portbind.HostPort != "" {
+				hp, err := strconv.Atoi(portbind.HostPort)
+				if err != nil {
+					return nil, err
+				}
+				hostPort = uint32(hp)
+			} else {
+				hostPort = uint32(port.Int())
+			}
+
+			result = append(result, containers.Port{
+				HostPort:      hostPort,
+				ContainerPort: uint32(port.Int()),
+				Protocol:      port.Proto(),
+				HostIP:        portbind.HostIP,
+			})
 		}
-		destination, err := strconv.Atoi(parts[1])
-		if err != nil {
-			return nil, err
-		}
-
-		result = append(result, containers.Port{
-			Source:      uint32(source),
-			Destination: uint32(destination),
-		})
 	}
+
 	return result, nil
 }
 

+ 99 - 0
cli/cmd/run/opts_test.go

@@ -0,0 +1,99 @@
+package run
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"github.com/stretchr/testify/suite"
+
+	"github.com/docker/api/containers"
+)
+
+type RunOptsSuite struct {
+	suite.Suite
+}
+
+func (s *RunOptsSuite) TestPortParse() {
+	testCases := []struct {
+		in       string
+		expected []containers.Port
+	}{
+		{
+			in: "80",
+			expected: []containers.Port{
+				{
+					HostPort:      80,
+					ContainerPort: 80,
+					Protocol:      "tcp",
+				},
+			},
+		},
+		{
+			in: "80:80",
+			expected: []containers.Port{
+				{
+					HostPort:      80,
+					ContainerPort: 80,
+					Protocol:      "tcp",
+				},
+			},
+		},
+		{
+			in: "80:80/udp",
+			expected: []containers.Port{
+				{
+					ContainerPort: 80,
+					HostPort:      80,
+					Protocol:      "udp",
+				},
+			},
+		},
+		{
+			in: "8080:80",
+			expected: []containers.Port{
+				{
+					HostPort:      8080,
+					ContainerPort: 80,
+					Protocol:      "tcp",
+				},
+			},
+		},
+		{
+			in: "192.168.0.2:8080:80",
+			expected: []containers.Port{
+				{
+					HostPort:      8080,
+					ContainerPort: 80,
+					Protocol:      "tcp",
+					HostIP:        "192.168.0.2",
+				},
+			},
+		},
+		{
+			in: "80-81:80-81",
+			expected: []containers.Port{
+				{
+					HostPort:      80,
+					ContainerPort: 80,
+					Protocol:      "tcp",
+				},
+				{
+					HostPort:      81,
+					ContainerPort: 81,
+					Protocol:      "tcp",
+				},
+			},
+		},
+	}
+
+	for _, testCase := range testCases {
+		result, err := toPorts([]string{testCase.in})
+		require.Nil(s.T(), err)
+		assert.ElementsMatch(s.T(), testCase.expected, result)
+	}
+}
+
+func TestExampleTestSuite(t *testing.T) {
+	suite.Run(t, new(RunOptsSuite))
+}

+ 1 - 1
cli/cmd/run/run.go

@@ -50,7 +50,7 @@ func Command() *cobra.Command {
 		},
 	}
 
-	cmd.Flags().StringArrayVarP(&opts.publish, "publish", "p", []string{}, "Publish a container's port(s)")
+	cmd.Flags().StringArrayVarP(&opts.publish, "publish", "p", []string{}, "Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT")
 	cmd.Flags().StringVar(&opts.name, "name", getRandomName(), "Assign a name to the container")
 
 	return cmd

+ 9 - 4
containers/api.go

@@ -17,14 +17,19 @@ type Container struct {
 	PidsCurrent uint64
 	PidsLimit   uint64
 	Labels      []string
+	Ports       []Port
 }
 
 // Port represents a published port of a container
 type Port struct {
-	// Source is the source port
-	Source uint32
-	// Destination is the destination port
-	Destination uint32
+	// HostPort is the port number on the host
+	HostPort uint32
+	// ContainerPort is the port number inside the container
+	ContainerPort uint32
+	/// Protocol is the protocol of the port mapping
+	Protocol string
+	// HostIP is the host ip to use
+	HostIP string
 }
 
 // ContainerConfig contains the configuration data about a container

+ 1 - 0
go.mod

@@ -19,6 +19,7 @@ require (
 	github.com/containerd/containerd v1.3.4 // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
 	github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
+	github.com/docker/go-connections v0.4.0
 	github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect
 	github.com/gobwas/pool v0.2.0 // indirect
 	github.com/gobwas/ws v1.0.3

+ 15 - 0
moby/backend.go

@@ -66,6 +66,7 @@ func (ms *mobyService) List(ctx context.Context) ([]containers.Container, error)
 			Image:   container.Image,
 			Status:  container.Status,
 			Command: container.Command,
+			Ports:   getPorts(container.Ports),
 		})
 	}
 
@@ -143,3 +144,17 @@ func (ms *mobyService) Delete(ctx context.Context, containerID string, force boo
 	}
 	return err
 }
+
+func getPorts(ports []types.Port) []containers.Port {
+	result := []containers.Port{}
+	for _, port := range ports {
+		result = append(result, containers.Port{
+			ContainerPort: uint32(port.PrivatePort),
+			HostPort:      uint32(port.PublicPort),
+			HostIP:        port.IP,
+			Protocol:      port.Type,
+		})
+	}
+
+	return result
+}