mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
New package nat
: utilities for manipulating the text description of network ports.
This facilitates the refactoring of commands.go Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)
This commit is contained in:
parent
0bcabdbdc7
commit
3ecd8ff0c8
12 changed files with 212 additions and 187 deletions
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/auth"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
flag "github.com/dotcloud/docker/pkg/mflag"
|
||||
"github.com/dotcloud/docker/pkg/sysinfo"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
|
@ -799,7 +800,7 @@ func (cli *DockerCli) CmdPort(args ...string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
if frontends, exists := out.NetworkSettings.Ports[Port(port+"/"+proto)]; exists && frontends != nil {
|
||||
if frontends, exists := out.NetworkSettings.Ports[nat.Port(port+"/"+proto)]; exists && frontends != nil {
|
||||
for _, frontend := range frontends {
|
||||
fmt.Fprintf(cli.out, "%s:%s\n", frontend.HostIp, frontend.HostPort)
|
||||
}
|
||||
|
@ -1792,7 +1793,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
cmd.Var(&flLinks, []string{"#link", "-link"}, "Add link to another container (name:alias)")
|
||||
cmd.Var(&flEnv, []string{"e", "-env"}, "Set environment variables")
|
||||
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", PortSpecTemplateFormat))
|
||||
cmd.Var(&flPublish, []string{"p", "-publish"}, fmt.Sprintf("Publish a container's port to the host (format: %s) (use 'docker port' to see the actual mapping)", nat.PortSpecTemplateFormat))
|
||||
cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port from the container without publishing it to your host")
|
||||
cmd.Var(&flDns, []string{"#dns", "-dns"}, "Set custom dns servers")
|
||||
cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
|
||||
|
@ -1885,7 +1886,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
domainname = parts[1]
|
||||
}
|
||||
|
||||
ports, portBindings, err := parsePortSpecs(flPublish.GetAll())
|
||||
ports, portBindings, err := nat.ParsePortSpecs(flPublish.GetAll())
|
||||
if err != nil {
|
||||
return nil, nil, cmd, err
|
||||
}
|
||||
|
@ -1895,7 +1896,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
if strings.Contains(e, ":") {
|
||||
return nil, nil, cmd, fmt.Errorf("Invalid port format for --expose: %s", e)
|
||||
}
|
||||
p := NewPort(splitProtoPort(e))
|
||||
p := nat.NewPort(nat.SplitProtoPort(e))
|
||||
if _, exists := ports[p]; !exists {
|
||||
ports[p] = struct{}{}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -125,7 +126,7 @@ func TestMergeConfig(t *testing.T) {
|
|||
t.Fatalf("Expected VolumesFrom to be 1111, found %s", configUser.VolumesFrom)
|
||||
}
|
||||
|
||||
ports, _, err := parsePortSpecs([]string{"0000"})
|
||||
ports, _, err := nat.ParsePortSpecs([]string{"0000"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
|
52
container.go
52
container.go
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/execdriver"
|
||||
"github.com/dotcloud/docker/graphdriver"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/pkg/mount"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
|
@ -86,7 +87,7 @@ type Config struct {
|
|||
AttachStdout bool
|
||||
AttachStderr bool
|
||||
PortSpecs []string // Deprecated - Can be in the format of 8080/tcp
|
||||
ExposedPorts map[Port]struct{}
|
||||
ExposedPorts map[nat.Port]struct{}
|
||||
Tty bool // Attach standard streams to a tty, including stdin if it is not closed.
|
||||
OpenStdin bool // Open stdin
|
||||
StdinOnce bool // If true, close stdin after the 1 attached client disconnects.
|
||||
|
@ -147,7 +148,7 @@ type HostConfig struct {
|
|||
ContainerIDFile string
|
||||
LxcConf []KeyValuePair
|
||||
Privileged bool
|
||||
PortBindings map[Port][]PortBinding
|
||||
PortBindings nat.PortMap
|
||||
Links []string
|
||||
PublishAllPorts bool
|
||||
}
|
||||
|
@ -189,38 +190,7 @@ type KeyValuePair struct {
|
|||
Value string
|
||||
}
|
||||
|
||||
type PortBinding struct {
|
||||
HostIp string
|
||||
HostPort string
|
||||
}
|
||||
|
||||
// 80/tcp
|
||||
type Port string
|
||||
|
||||
func (p Port) Proto() string {
|
||||
parts := strings.Split(string(p), "/")
|
||||
if len(parts) == 1 {
|
||||
return "tcp"
|
||||
}
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
func (p Port) Port() string {
|
||||
return strings.Split(string(p), "/")[0]
|
||||
}
|
||||
|
||||
func (p Port) Int() int {
|
||||
i, err := parsePort(p.Port())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
func NewPort(proto, port string) Port {
|
||||
return Port(fmt.Sprintf("%s/%s", port, proto))
|
||||
}
|
||||
|
||||
// FIXME: move deprecated port stuff to nat to clean up the core.
|
||||
type PortMapping map[string]string // Deprecated
|
||||
|
||||
type NetworkSettings struct {
|
||||
|
@ -229,13 +199,13 @@ type NetworkSettings struct {
|
|||
Gateway string
|
||||
Bridge string
|
||||
PortMapping map[string]PortMapping // Deprecated
|
||||
Ports map[Port][]PortBinding
|
||||
Ports nat.PortMap
|
||||
}
|
||||
|
||||
func (settings *NetworkSettings) PortMappingAPI() *engine.Table {
|
||||
var outs = engine.NewTable("", 0)
|
||||
for port, bindings := range settings.Ports {
|
||||
p, _ := parsePort(port.Port())
|
||||
p, _ := nat.ParsePort(port.Port())
|
||||
if len(bindings) == 0 {
|
||||
out := &engine.Env{}
|
||||
out.SetInt("PublicPort", p)
|
||||
|
@ -245,7 +215,7 @@ func (settings *NetworkSettings) PortMappingAPI() *engine.Table {
|
|||
}
|
||||
for _, binding := range bindings {
|
||||
out := &engine.Env{}
|
||||
h, _ := parsePort(binding.HostPort)
|
||||
h, _ := nat.ParsePort(binding.HostPort)
|
||||
out.SetInt("PrivatePort", p)
|
||||
out.SetInt("PublicPort", h)
|
||||
out.Set("Type", port.Proto())
|
||||
|
@ -1152,8 +1122,8 @@ func (container *Container) allocateNetwork() error {
|
|||
}
|
||||
|
||||
var (
|
||||
portSpecs = make(map[Port]struct{})
|
||||
bindings = make(map[Port][]PortBinding)
|
||||
portSpecs = make(nat.PortSet)
|
||||
bindings = make(nat.PortMap)
|
||||
)
|
||||
|
||||
if !container.State.IsGhost() {
|
||||
|
@ -1177,7 +1147,7 @@ func (container *Container) allocateNetwork() error {
|
|||
for port := range portSpecs {
|
||||
binding := bindings[port]
|
||||
if container.hostConfig.PublishAllPorts && len(binding) == 0 {
|
||||
binding = append(binding, PortBinding{})
|
||||
binding = append(binding, nat.PortBinding{})
|
||||
}
|
||||
|
||||
for i := 0; i < len(binding); i++ {
|
||||
|
@ -1593,7 +1563,7 @@ func (container *Container) Copy(resource string) (archive.Archive, error) {
|
|||
}
|
||||
|
||||
// Returns true if the container exposes a certain port
|
||||
func (container *Container) Exposes(p Port) bool {
|
||||
func (container *Container) Exposes(p nat.Port) bool {
|
||||
_, exists := container.Config.ExposedPorts[p]
|
||||
return exists
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -22,7 +23,7 @@ func TestParseLxcConfOpt(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
|
||||
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::80"})
|
||||
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::80"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -64,7 +65,7 @@ func TestParseNetworkOptsPrivateOnly(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseNetworkOptsPublic(t *testing.T) {
|
||||
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100:8080:80"})
|
||||
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100:8080:80"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -106,7 +107,7 @@ func TestParseNetworkOptsPublic(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseNetworkOptsUdp(t *testing.T) {
|
||||
ports, bindings, err := parsePortSpecs([]string{"192.168.1.100::6000/udp"})
|
||||
ports, bindings, err := nat.ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/dotcloud/docker"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/sysinit"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
|
@ -368,7 +369,7 @@ func startEchoServerContainer(t *testing.T, proto string) (*docker.Runtime, *doc
|
|||
eng = NewTestEngine(t)
|
||||
runtime = mkRuntimeFromEngine(eng, t)
|
||||
port = 5554
|
||||
p docker.Port
|
||||
p nat.Port
|
||||
)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
|
@ -387,8 +388,8 @@ func startEchoServerContainer(t *testing.T, proto string) (*docker.Runtime, *doc
|
|||
} else {
|
||||
t.Fatal(fmt.Errorf("Unknown protocol %v", proto))
|
||||
}
|
||||
ep := make(map[docker.Port]struct{}, 1)
|
||||
p = docker.Port(fmt.Sprintf("%s/%s", strPort, proto))
|
||||
ep := make(map[nat.Port]struct{}, 1)
|
||||
p = nat.Port(fmt.Sprintf("%s/%s", strPort, proto))
|
||||
ep[p] = struct{}{}
|
||||
|
||||
jobCreate := eng.Job("create")
|
||||
|
@ -411,8 +412,8 @@ func startEchoServerContainer(t *testing.T, proto string) (*docker.Runtime, *doc
|
|||
}
|
||||
|
||||
jobStart := eng.Job("start", id)
|
||||
portBindings := make(map[docker.Port][]docker.PortBinding)
|
||||
portBindings[p] = []docker.PortBinding{
|
||||
portBindings := make(map[nat.Port][]nat.PortBinding)
|
||||
portBindings[p] = []nat.PortBinding{
|
||||
{},
|
||||
}
|
||||
if err := jobStart.SetenvJson("PortsBindings", portBindings); err != nil {
|
||||
|
|
11
links.go
11
links.go
|
@ -3,6 +3,7 @@ package docker
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/engine"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
@ -12,7 +13,7 @@ type Link struct {
|
|||
ChildIP string
|
||||
Name string
|
||||
ChildEnvironment []string
|
||||
Ports []Port
|
||||
Ports []nat.Port
|
||||
IsEnabled bool
|
||||
eng *engine.Engine
|
||||
}
|
||||
|
@ -25,7 +26,7 @@ func NewLink(parent, child *Container, name string, eng *engine.Engine) (*Link,
|
|||
return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, name)
|
||||
}
|
||||
|
||||
ports := make([]Port, len(child.Config.ExposedPorts))
|
||||
ports := make([]nat.Port, len(child.Config.ExposedPorts))
|
||||
var i int
|
||||
for p := range child.Config.ExposedPorts {
|
||||
ports[i] = p
|
||||
|
@ -85,14 +86,14 @@ func (l *Link) ToEnv() []string {
|
|||
}
|
||||
|
||||
// Default port rules
|
||||
func (l *Link) getDefaultPort() *Port {
|
||||
var p Port
|
||||
func (l *Link) getDefaultPort() *nat.Port {
|
||||
var p nat.Port
|
||||
i := len(l.Ports)
|
||||
|
||||
if i == 0 {
|
||||
return nil
|
||||
} else if i > 1 {
|
||||
sortPorts(l.Ports, func(ip, jp Port) bool {
|
||||
nat.Sort(l.Ports, func(ip, jp nat.Port) bool {
|
||||
// If the two ports have the same number, tcp takes priority
|
||||
// Sort in desc order
|
||||
return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && strings.ToLower(ip.Proto()) == "tcp")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
@ -22,9 +23,9 @@ func TestLinkNew(t *testing.T) {
|
|||
from := newMockLinkContainer(fromID, "172.0.17.2")
|
||||
from.Config.Env = []string{}
|
||||
from.State = State{Running: true}
|
||||
ports := make(map[Port]struct{})
|
||||
ports := make(nat.PortSet)
|
||||
|
||||
ports[Port("6379/tcp")] = struct{}{}
|
||||
ports[nat.Port("6379/tcp")] = struct{}{}
|
||||
|
||||
from.Config.ExposedPorts = ports
|
||||
|
||||
|
@ -51,7 +52,7 @@ func TestLinkNew(t *testing.T) {
|
|||
t.Fail()
|
||||
}
|
||||
for _, p := range link.Ports {
|
||||
if p != Port("6379/tcp") {
|
||||
if p != nat.Port("6379/tcp") {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
@ -64,9 +65,9 @@ func TestLinkEnv(t *testing.T) {
|
|||
from := newMockLinkContainer(fromID, "172.0.17.2")
|
||||
from.Config.Env = []string{"PASSWORD=gordon"}
|
||||
from.State = State{Running: true}
|
||||
ports := make(map[Port]struct{})
|
||||
ports := make(nat.PortSet)
|
||||
|
||||
ports[Port("6379/tcp")] = struct{}{}
|
||||
ports[nat.Port("6379/tcp")] = struct{}{}
|
||||
|
||||
from.Config.ExposedPorts = ports
|
||||
|
||||
|
|
133
nat/nat.go
Normal file
133
nat/nat.go
Normal file
|
@ -0,0 +1,133 @@
|
|||
package nat
|
||||
|
||||
// nat is a convenience package for docker's manipulation of strings describing
|
||||
// network ports.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
PortSpecTemplate = "ip:hostPort:containerPort"
|
||||
PortSpecTemplateFormat = "ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort"
|
||||
)
|
||||
|
||||
type PortBinding struct {
|
||||
HostIp string
|
||||
HostPort string
|
||||
}
|
||||
|
||||
type PortMap map[Port][]PortBinding
|
||||
|
||||
type PortSet map[Port]struct{}
|
||||
|
||||
// 80/tcp
|
||||
type Port string
|
||||
|
||||
func NewPort(proto, port string) Port {
|
||||
return Port(fmt.Sprintf("%s/%s", port, proto))
|
||||
}
|
||||
|
||||
func ParsePort(rawPort string) (int, error) {
|
||||
port, err := strconv.ParseUint(rawPort, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(port), nil
|
||||
}
|
||||
|
||||
func (p Port) Proto() string {
|
||||
parts := strings.Split(string(p), "/")
|
||||
if len(parts) == 1 {
|
||||
return "tcp"
|
||||
}
|
||||
return parts[1]
|
||||
}
|
||||
|
||||
func (p Port) Port() string {
|
||||
return strings.Split(string(p), "/")[0]
|
||||
}
|
||||
|
||||
func (p Port) Int() int {
|
||||
i, err := ParsePort(p.Port())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Splits a port in the format of port/proto
|
||||
func SplitProtoPort(rawPort string) (string, string) {
|
||||
parts := strings.Split(rawPort, "/")
|
||||
l := len(parts)
|
||||
if l == 0 {
|
||||
return "", ""
|
||||
}
|
||||
if l == 1 {
|
||||
return "tcp", rawPort
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
// We will receive port specs in the format of ip:public:private/proto and these need to be
|
||||
// parsed in the internal types
|
||||
func ParsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) {
|
||||
var (
|
||||
exposedPorts = make(map[Port]struct{}, len(ports))
|
||||
bindings = make(map[Port][]PortBinding)
|
||||
)
|
||||
|
||||
for _, rawPort := range ports {
|
||||
proto := "tcp"
|
||||
|
||||
if i := strings.LastIndex(rawPort, "/"); i != -1 {
|
||||
proto = rawPort[i+1:]
|
||||
rawPort = rawPort[:i]
|
||||
}
|
||||
if !strings.Contains(rawPort, ":") {
|
||||
rawPort = fmt.Sprintf("::%s", rawPort)
|
||||
} else if len(strings.Split(rawPort, ":")) == 2 {
|
||||
rawPort = fmt.Sprintf(":%s", rawPort)
|
||||
}
|
||||
|
||||
parts, err := utils.PartParser(PortSpecTemplate, rawPort)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
containerPort = parts["containerPort"]
|
||||
rawIp = parts["ip"]
|
||||
hostPort = parts["hostPort"]
|
||||
)
|
||||
|
||||
if containerPort == "" {
|
||||
return nil, nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
|
||||
}
|
||||
if _, err := strconv.ParseUint(containerPort, 10, 16); err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
|
||||
}
|
||||
if _, err := strconv.ParseUint(hostPort, 10, 16); hostPort != "" && err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
|
||||
}
|
||||
|
||||
port := NewPort(proto, containerPort)
|
||||
if _, exists := exposedPorts[port]; !exists {
|
||||
exposedPorts[port] = struct{}{}
|
||||
}
|
||||
|
||||
binding := PortBinding{
|
||||
HostIp: rawIp,
|
||||
HostPort: hostPort,
|
||||
}
|
||||
bslice, exists := bindings[port]
|
||||
if !exists {
|
||||
bslice = []PortBinding{}
|
||||
}
|
||||
bindings[port] = append(bslice, binding)
|
||||
}
|
||||
return exposedPorts, bindings, nil
|
||||
}
|
28
nat/sort.go
Normal file
28
nat/sort.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package nat
|
||||
|
||||
import "sort"
|
||||
|
||||
type portSorter struct {
|
||||
ports []Port
|
||||
by func(i, j Port) bool
|
||||
}
|
||||
|
||||
func (s *portSorter) Len() int {
|
||||
return len(s.ports)
|
||||
}
|
||||
|
||||
func (s *portSorter) Swap(i, j int) {
|
||||
s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
|
||||
}
|
||||
|
||||
func (s *portSorter) Less(i, j int) bool {
|
||||
ip := s.ports[i]
|
||||
jp := s.ports[j]
|
||||
|
||||
return s.by(ip, jp)
|
||||
}
|
||||
|
||||
func Sort(ports []Port, predicate func(i, j Port) bool) {
|
||||
s := &portSorter{ports, predicate}
|
||||
sort.Sort(s)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package docker
|
||||
package nat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -11,7 +11,7 @@ func TestSortUniquePorts(t *testing.T) {
|
|||
Port("22/tcp"),
|
||||
}
|
||||
|
||||
sortPorts(ports, func(ip, jp Port) bool {
|
||||
Sort(ports, func(ip, jp Port) bool {
|
||||
return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
|
||||
})
|
||||
|
||||
|
@ -30,7 +30,7 @@ func TestSortSamePortWithDifferentProto(t *testing.T) {
|
|||
Port("6379/udp"),
|
||||
}
|
||||
|
||||
sortPorts(ports, func(ip, jp Port) bool {
|
||||
Sort(ports, func(ip, jp Port) bool {
|
||||
return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
|
||||
})
|
||||
|
25
sorter.go
25
sorter.go
|
@ -2,31 +2,6 @@ package docker
|
|||
|
||||
import "sort"
|
||||
|
||||
type portSorter struct {
|
||||
ports []Port
|
||||
by func(i, j Port) bool
|
||||
}
|
||||
|
||||
func (s *portSorter) Len() int {
|
||||
return len(s.ports)
|
||||
}
|
||||
|
||||
func (s *portSorter) Swap(i, j int) {
|
||||
s.ports[i], s.ports[j] = s.ports[j], s.ports[i]
|
||||
}
|
||||
|
||||
func (s *portSorter) Less(i, j int) bool {
|
||||
ip := s.ports[i]
|
||||
jp := s.ports[j]
|
||||
|
||||
return s.by(ip, jp)
|
||||
}
|
||||
|
||||
func sortPorts(ports []Port, predicate func(i, j Port) bool) {
|
||||
s := &portSorter{ports, predicate}
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
type containerSorter struct {
|
||||
containers []*Container
|
||||
by func(i, j *Container) bool
|
||||
|
|
103
utils.go
103
utils.go
|
@ -3,10 +3,10 @@ package docker
|
|||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/archive"
|
||||
"github.com/dotcloud/docker/nat"
|
||||
"github.com/dotcloud/docker/pkg/namesgenerator"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
@ -98,7 +98,7 @@ func MergeConfig(userConf, imageConf *Config) error {
|
|||
userConf.ExposedPorts = imageConf.ExposedPorts
|
||||
} else if imageConf.ExposedPorts != nil {
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(map[Port]struct{})
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
for port := range imageConf.ExposedPorts {
|
||||
if _, exists := userConf.ExposedPorts[port]; !exists {
|
||||
|
@ -109,9 +109,9 @@ func MergeConfig(userConf, imageConf *Config) error {
|
|||
|
||||
if userConf.PortSpecs != nil && len(userConf.PortSpecs) > 0 {
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(map[Port]struct{})
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
ports, _, err := parsePortSpecs(userConf.PortSpecs)
|
||||
ports, _, err := nat.ParsePortSpecs(userConf.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -125,10 +125,10 @@ func MergeConfig(userConf, imageConf *Config) error {
|
|||
if imageConf.PortSpecs != nil && len(imageConf.PortSpecs) > 0 {
|
||||
utils.Debugf("Migrating image port specs to containter: %s", strings.Join(imageConf.PortSpecs, ", "))
|
||||
if userConf.ExposedPorts == nil {
|
||||
userConf.ExposedPorts = make(map[Port]struct{})
|
||||
userConf.ExposedPorts = make(nat.PortSet)
|
||||
}
|
||||
|
||||
ports, _, err := parsePortSpecs(imageConf.PortSpecs)
|
||||
ports, _, err := nat.ParsePortSpecs(imageConf.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -212,96 +212,9 @@ func parseLxcOpt(opt string) (string, string, error) {
|
|||
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
||||
}
|
||||
|
||||
// FIXME: network related stuff (including parsing) should be grouped in network file
|
||||
const (
|
||||
PortSpecTemplate = "ip:hostPort:containerPort"
|
||||
PortSpecTemplateFormat = "ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort"
|
||||
)
|
||||
|
||||
// We will receive port specs in the format of ip:public:private/proto and these need to be
|
||||
// parsed in the internal types
|
||||
func parsePortSpecs(ports []string) (map[Port]struct{}, map[Port][]PortBinding, error) {
|
||||
var (
|
||||
exposedPorts = make(map[Port]struct{}, len(ports))
|
||||
bindings = make(map[Port][]PortBinding)
|
||||
)
|
||||
|
||||
for _, rawPort := range ports {
|
||||
proto := "tcp"
|
||||
|
||||
if i := strings.LastIndex(rawPort, "/"); i != -1 {
|
||||
proto = rawPort[i+1:]
|
||||
rawPort = rawPort[:i]
|
||||
}
|
||||
if !strings.Contains(rawPort, ":") {
|
||||
rawPort = fmt.Sprintf("::%s", rawPort)
|
||||
} else if len(strings.Split(rawPort, ":")) == 2 {
|
||||
rawPort = fmt.Sprintf(":%s", rawPort)
|
||||
}
|
||||
|
||||
parts, err := utils.PartParser(PortSpecTemplate, rawPort)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
containerPort = parts["containerPort"]
|
||||
rawIp = parts["ip"]
|
||||
hostPort = parts["hostPort"]
|
||||
)
|
||||
|
||||
if containerPort == "" {
|
||||
return nil, nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
|
||||
}
|
||||
if _, err := strconv.ParseUint(containerPort, 10, 16); err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
|
||||
}
|
||||
if _, err := strconv.ParseUint(hostPort, 10, 16); hostPort != "" && err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
|
||||
}
|
||||
|
||||
port := NewPort(proto, containerPort)
|
||||
if _, exists := exposedPorts[port]; !exists {
|
||||
exposedPorts[port] = struct{}{}
|
||||
}
|
||||
|
||||
binding := PortBinding{
|
||||
HostIp: rawIp,
|
||||
HostPort: hostPort,
|
||||
}
|
||||
bslice, exists := bindings[port]
|
||||
if !exists {
|
||||
bslice = []PortBinding{}
|
||||
}
|
||||
bindings[port] = append(bslice, binding)
|
||||
}
|
||||
return exposedPorts, bindings, nil
|
||||
}
|
||||
|
||||
// Splits a port in the format of port/proto
|
||||
func splitProtoPort(rawPort string) (string, string) {
|
||||
parts := strings.Split(rawPort, "/")
|
||||
l := len(parts)
|
||||
if l == 0 {
|
||||
return "", ""
|
||||
}
|
||||
if l == 1 {
|
||||
return "tcp", rawPort
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
func parsePort(rawPort string) (int, error) {
|
||||
port, err := strconv.ParseUint(rawPort, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(port), nil
|
||||
}
|
||||
|
||||
func migratePortMappings(config *Config, hostConfig *HostConfig) error {
|
||||
if config.PortSpecs != nil {
|
||||
ports, bindings, err := parsePortSpecs(config.PortSpecs)
|
||||
ports, bindings, err := nat.ParsePortSpecs(config.PortSpecs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -314,7 +227,7 @@ func migratePortMappings(config *Config, hostConfig *HostConfig) error {
|
|||
}
|
||||
|
||||
if config.ExposedPorts == nil {
|
||||
config.ExposedPorts = make(map[Port]struct{}, len(ports))
|
||||
config.ExposedPorts = make(nat.PortSet, len(ports))
|
||||
}
|
||||
for k, v := range ports {
|
||||
config.ExposedPorts[k] = v
|
||||
|
|
Loading…
Add table
Reference in a new issue