Merge pull request #18762 from calavera/runconfig_to_types
Move container configuration types to api/types/container.
This commit is contained in:
commit
b635d70be4
7 changed files with 0 additions and 1166 deletions
|
@ -1,25 +0,0 @@
|
|||
package blkiodev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// WeightDevice is a structure that hold device:weight pair
|
||||
type WeightDevice struct {
|
||||
Path string
|
||||
Weight uint16
|
||||
}
|
||||
|
||||
func (w *WeightDevice) String() string {
|
||||
return fmt.Sprintf("%s:%d", w.Path, w.Weight)
|
||||
}
|
||||
|
||||
// ThrottleDevice is a structure that hold device:rate_per_second pair
|
||||
type ThrottleDevice struct {
|
||||
Path string
|
||||
Rate uint64
|
||||
}
|
||||
|
||||
func (t *ThrottleDevice) String() string {
|
||||
return fmt.Sprintf("%s:%d", t.Path, t.Rate)
|
||||
}
|
227
nat/nat.go
227
nat/nat.go
|
@ -1,227 +0,0 @@
|
|||
package nat
|
||||
|
||||
// nat is a convenience package for docker's manipulation of strings describing
|
||||
// network ports.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
)
|
||||
|
||||
const (
|
||||
// portSpecTemplate is the expected format for port specifications
|
||||
portSpecTemplate = "ip:hostPort:containerPort"
|
||||
)
|
||||
|
||||
// PortBinding represents a binding between a Host IP address and a Host Port
|
||||
type PortBinding struct {
|
||||
// HostIP is the host IP Address
|
||||
HostIP string `json:"HostIp"`
|
||||
// HostPort is the host port number
|
||||
HostPort string
|
||||
}
|
||||
|
||||
// PortMap is a collection of PortBinding indexed by Port
|
||||
type PortMap map[Port][]PortBinding
|
||||
|
||||
// PortSet is a collection of structs indexed by Port
|
||||
type PortSet map[Port]struct{}
|
||||
|
||||
// Port is a string containing port number and protocol in the format "80/tcp"
|
||||
type Port string
|
||||
|
||||
// NewPort creates a new instance of a Port given a protocol and port number or port range
|
||||
func NewPort(proto, port string) (Port, error) {
|
||||
// Check for parsing issues on "port" now so we can avoid having
|
||||
// to check it later on.
|
||||
|
||||
portStartInt, portEndInt, err := ParsePortRange(port)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if portStartInt == portEndInt {
|
||||
return Port(fmt.Sprintf("%d/%s", portStartInt, proto)), nil
|
||||
}
|
||||
return Port(fmt.Sprintf("%d-%d/%s", portStartInt, portEndInt, proto)), nil
|
||||
}
|
||||
|
||||
// ParsePort parses the port number string and returns an int
|
||||
func ParsePort(rawPort string) (int, error) {
|
||||
if len(rawPort) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
port, err := strconv.ParseUint(rawPort, 10, 16)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(port), nil
|
||||
}
|
||||
|
||||
// ParsePortRange parses the port range string and returns start/end ints
|
||||
func ParsePortRange(rawPort string) (int, int, error) {
|
||||
if len(rawPort) == 0 {
|
||||
return 0, 0, nil
|
||||
}
|
||||
start, end, err := parsers.ParsePortRange(rawPort)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return int(start), int(end), nil
|
||||
}
|
||||
|
||||
// Proto returns the protocol of a Port
|
||||
func (p Port) Proto() string {
|
||||
proto, _ := SplitProtoPort(string(p))
|
||||
return proto
|
||||
}
|
||||
|
||||
// Port returns the port number of a Port
|
||||
func (p Port) Port() string {
|
||||
_, port := SplitProtoPort(string(p))
|
||||
return port
|
||||
}
|
||||
|
||||
// Int returns the port number of a Port as an int
|
||||
func (p Port) Int() int {
|
||||
portStr := p.Port()
|
||||
if len(portStr) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// We don't need to check for an error because we're going to
|
||||
// assume that any error would have been found, and reported, in NewPort()
|
||||
port, _ := strconv.ParseUint(portStr, 10, 16)
|
||||
return int(port)
|
||||
}
|
||||
|
||||
// Range returns the start/end port numbers of a Port range as ints
|
||||
func (p Port) Range() (int, int, error) {
|
||||
return ParsePortRange(p.Port())
|
||||
}
|
||||
|
||||
// SplitProtoPort splits a port in the format of proto/port
|
||||
func SplitProtoPort(rawPort string) (string, string) {
|
||||
parts := strings.Split(rawPort, "/")
|
||||
l := len(parts)
|
||||
if len(rawPort) == 0 || l == 0 || len(parts[0]) == 0 {
|
||||
return "", ""
|
||||
}
|
||||
if l == 1 {
|
||||
return "tcp", rawPort
|
||||
}
|
||||
if len(parts[1]) == 0 {
|
||||
return "tcp", parts[0]
|
||||
}
|
||||
return parts[1], parts[0]
|
||||
}
|
||||
|
||||
func validateProto(proto string) bool {
|
||||
for _, availableProto := range []string{"tcp", "udp"} {
|
||||
if availableProto == proto {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ParsePortSpecs receives port specs in the format of ip:public:private/proto and parses
|
||||
// these in to 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 := parsers.PartParser(portSpecTemplate, rawPort)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
containerPort = parts["containerPort"]
|
||||
rawIP = parts["ip"]
|
||||
hostPort = parts["hostPort"]
|
||||
)
|
||||
|
||||
if rawIP != "" && net.ParseIP(rawIP) == nil {
|
||||
return nil, nil, fmt.Errorf("Invalid ip address: %s", rawIP)
|
||||
}
|
||||
if containerPort == "" {
|
||||
return nil, nil, fmt.Errorf("No port specified: %s<empty>", rawPort)
|
||||
}
|
||||
|
||||
startPort, endPort, err := parsers.ParsePortRange(containerPort)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid containerPort: %s", containerPort)
|
||||
}
|
||||
|
||||
var startHostPort, endHostPort uint64 = 0, 0
|
||||
if len(hostPort) > 0 {
|
||||
startHostPort, endHostPort, err = parsers.ParsePortRange(hostPort)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Invalid hostPort: %s", hostPort)
|
||||
}
|
||||
}
|
||||
|
||||
if hostPort != "" && (endPort-startPort) != (endHostPort-startHostPort) {
|
||||
// Allow host port range iff containerPort is not a range.
|
||||
// In this case, use the host port range as the dynamic
|
||||
// host port range to allocate into.
|
||||
if endPort != startPort {
|
||||
return nil, nil, fmt.Errorf("Invalid ranges specified for container and host Ports: %s and %s", containerPort, hostPort)
|
||||
}
|
||||
}
|
||||
|
||||
if !validateProto(strings.ToLower(proto)) {
|
||||
return nil, nil, fmt.Errorf("Invalid proto: %s", proto)
|
||||
}
|
||||
|
||||
for i := uint64(0); i <= (endPort - startPort); i++ {
|
||||
containerPort = strconv.FormatUint(startPort+i, 10)
|
||||
if len(hostPort) > 0 {
|
||||
hostPort = strconv.FormatUint(startHostPort+i, 10)
|
||||
}
|
||||
// Set hostPort to a range only if there is a single container port
|
||||
// and a dynamic host port.
|
||||
if startPort == endPort && startHostPort != endHostPort {
|
||||
hostPort = fmt.Sprintf("%s-%s", hostPort, strconv.FormatUint(endHostPort, 10))
|
||||
}
|
||||
port, err := NewPort(strings.ToLower(proto), containerPort)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
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
|
||||
}
|
525
nat/nat_test.go
525
nat/nat_test.go
|
@ -1,525 +0,0 @@
|
|||
package nat
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParsePort(t *testing.T) {
|
||||
var (
|
||||
p int
|
||||
err error
|
||||
)
|
||||
|
||||
p, err = ParsePort("1234")
|
||||
|
||||
if err != nil || p != 1234 {
|
||||
t.Fatal("Parsing '1234' did not succeed")
|
||||
}
|
||||
|
||||
// FIXME currently this is a valid port. I don't think it should be.
|
||||
// I'm leaving this test commented out until we make a decision.
|
||||
// - erikh
|
||||
|
||||
/*
|
||||
p, err = ParsePort("0123")
|
||||
|
||||
if err != nil {
|
||||
t.Fatal("Successfully parsed port '0123' to '123'")
|
||||
}
|
||||
*/
|
||||
|
||||
p, err = ParsePort("asdf")
|
||||
|
||||
if err == nil || p != 0 {
|
||||
t.Fatal("Parsing port 'asdf' succeeded")
|
||||
}
|
||||
|
||||
p, err = ParsePort("1asdf")
|
||||
|
||||
if err == nil || p != 0 {
|
||||
t.Fatal("Parsing port '1asdf' succeeded")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePortRange(t *testing.T) {
|
||||
var (
|
||||
begin int
|
||||
end int
|
||||
err error
|
||||
)
|
||||
|
||||
type TestRange struct {
|
||||
Range string
|
||||
Begin int
|
||||
End int
|
||||
}
|
||||
validRanges := []TestRange{
|
||||
{"1234", 1234, 1234},
|
||||
{"1234-1234", 1234, 1234},
|
||||
{"1234-1235", 1234, 1235},
|
||||
{"8000-9000", 8000, 9000},
|
||||
{"0", 0, 0},
|
||||
{"0-0", 0, 0},
|
||||
}
|
||||
|
||||
for _, r := range validRanges {
|
||||
begin, end, err = ParsePortRange(r.Range)
|
||||
|
||||
if err != nil || begin != r.Begin {
|
||||
t.Fatalf("Parsing port range '%s' did not succeed. Expected begin %d, got %d", r.Range, r.Begin, begin)
|
||||
}
|
||||
if err != nil || end != r.End {
|
||||
t.Fatalf("Parsing port range '%s' did not succeed. Expected end %d, got %d", r.Range, r.End, end)
|
||||
}
|
||||
}
|
||||
|
||||
invalidRanges := []string{
|
||||
"asdf",
|
||||
"1asdf",
|
||||
"9000-8000",
|
||||
"9000-",
|
||||
"-8000",
|
||||
"-8000-",
|
||||
}
|
||||
|
||||
for _, r := range invalidRanges {
|
||||
begin, end, err = ParsePortRange(r)
|
||||
|
||||
if err == nil || begin != 0 || end != 0 {
|
||||
t.Fatalf("Parsing port range '%s' succeeded", r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPort(t *testing.T) {
|
||||
p, err := NewPort("tcp", "1234")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("tcp, 1234 had a parsing issue: %v", err)
|
||||
}
|
||||
|
||||
if string(p) != "1234/tcp" {
|
||||
t.Fatal("tcp, 1234 did not result in the string 1234/tcp")
|
||||
}
|
||||
|
||||
if p.Proto() != "tcp" {
|
||||
t.Fatal("protocol was not tcp")
|
||||
}
|
||||
|
||||
if p.Port() != "1234" {
|
||||
t.Fatal("port string value was not 1234")
|
||||
}
|
||||
|
||||
if p.Int() != 1234 {
|
||||
t.Fatal("port int value was not 1234")
|
||||
}
|
||||
|
||||
p, err = NewPort("tcp", "asd1234")
|
||||
if err == nil {
|
||||
t.Fatal("tcp, asd1234 was supposed to fail")
|
||||
}
|
||||
|
||||
p, err = NewPort("tcp", "1234-1230")
|
||||
if err == nil {
|
||||
t.Fatal("tcp, 1234-1230 was supposed to fail")
|
||||
}
|
||||
|
||||
p, err = NewPort("tcp", "1234-1242")
|
||||
if err != nil {
|
||||
t.Fatalf("tcp, 1234-1242 had a parsing issue: %v", err)
|
||||
}
|
||||
|
||||
if string(p) != "1234-1242/tcp" {
|
||||
t.Fatal("tcp, 1234-1242 did not result in the string 1234-1242/tcp")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitProtoPort(t *testing.T) {
|
||||
var (
|
||||
proto string
|
||||
port string
|
||||
)
|
||||
|
||||
proto, port = SplitProtoPort("1234/tcp")
|
||||
|
||||
if proto != "tcp" || port != "1234" {
|
||||
t.Fatal("Could not split 1234/tcp properly")
|
||||
}
|
||||
|
||||
proto, port = SplitProtoPort("")
|
||||
|
||||
if proto != "" || port != "" {
|
||||
t.Fatal("parsing an empty string yielded surprising results", proto, port)
|
||||
}
|
||||
|
||||
proto, port = SplitProtoPort("1234")
|
||||
|
||||
if proto != "tcp" || port != "1234" {
|
||||
t.Fatal("tcp is not the default protocol for portspec '1234'", proto, port)
|
||||
}
|
||||
|
||||
proto, port = SplitProtoPort("1234/")
|
||||
|
||||
if proto != "tcp" || port != "1234" {
|
||||
t.Fatal("parsing '1234/' yielded:" + port + "/" + proto)
|
||||
}
|
||||
|
||||
proto, port = SplitProtoPort("/tcp")
|
||||
|
||||
if proto != "" || port != "" {
|
||||
t.Fatal("parsing '/tcp' yielded:" + port + "/" + proto)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePortSpecs(t *testing.T) {
|
||||
var (
|
||||
portMap map[Port]struct{}
|
||||
bindingMap map[Port][]PortBinding
|
||||
err error
|
||||
)
|
||||
|
||||
portMap, bindingMap, err = ParsePortSpecs([]string{"1234/tcp", "2345/udp"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while processing ParsePortSpecs: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("1234/tcp")]; !ok {
|
||||
t.Fatal("1234/tcp was not parsed properly")
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("2345/udp")]; !ok {
|
||||
t.Fatal("2345/udp was not parsed properly")
|
||||
}
|
||||
|
||||
for portspec, bindings := range bindingMap {
|
||||
if len(bindings) != 1 {
|
||||
t.Fatalf("%s should have exactly one binding", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostIP != "" {
|
||||
t.Fatalf("HostIP should not be set for %s", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostPort != "" {
|
||||
t.Fatalf("HostPort should not be set for %s", portspec)
|
||||
}
|
||||
}
|
||||
|
||||
portMap, bindingMap, err = ParsePortSpecs([]string{"1234:1234/tcp", "2345:2345/udp"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while processing ParsePortSpecs: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("1234/tcp")]; !ok {
|
||||
t.Fatal("1234/tcp was not parsed properly")
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("2345/udp")]; !ok {
|
||||
t.Fatal("2345/udp was not parsed properly")
|
||||
}
|
||||
|
||||
for portspec, bindings := range bindingMap {
|
||||
_, port := SplitProtoPort(string(portspec))
|
||||
|
||||
if len(bindings) != 1 {
|
||||
t.Fatalf("%s should have exactly one binding", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostIP != "" {
|
||||
t.Fatalf("HostIP should not be set for %s", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostPort != port {
|
||||
t.Fatalf("HostPort should be %s for %s", port, portspec)
|
||||
}
|
||||
}
|
||||
|
||||
portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234:1234/tcp", "0.0.0.0:2345:2345/udp"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while processing ParsePortSpecs: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("1234/tcp")]; !ok {
|
||||
t.Fatal("1234/tcp was not parsed properly")
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("2345/udp")]; !ok {
|
||||
t.Fatal("2345/udp was not parsed properly")
|
||||
}
|
||||
|
||||
for portspec, bindings := range bindingMap {
|
||||
_, port := SplitProtoPort(string(portspec))
|
||||
|
||||
if len(bindings) != 1 {
|
||||
t.Fatalf("%s should have exactly one binding", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostIP != "0.0.0.0" {
|
||||
t.Fatalf("HostIP is not 0.0.0.0 for %s", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostPort != port {
|
||||
t.Fatalf("HostPort should be %s for %s", port, portspec)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err = ParsePortSpecs([]string{"localhost:1234:1234/tcp"})
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Received no error while trying to parse a hostname instead of ip")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePortSpecsWithRange(t *testing.T) {
|
||||
var (
|
||||
portMap map[Port]struct{}
|
||||
bindingMap map[Port][]PortBinding
|
||||
err error
|
||||
)
|
||||
|
||||
portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236/tcp", "2345-2347/udp"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while processing ParsePortSpecs: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("1235/tcp")]; !ok {
|
||||
t.Fatal("1234/tcp was not parsed properly")
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("2346/udp")]; !ok {
|
||||
t.Fatal("2345/udp was not parsed properly")
|
||||
}
|
||||
|
||||
for portspec, bindings := range bindingMap {
|
||||
if len(bindings) != 1 {
|
||||
t.Fatalf("%s should have exactly one binding", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostIP != "" {
|
||||
t.Fatalf("HostIP should not be set for %s", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostPort != "" {
|
||||
t.Fatalf("HostPort should not be set for %s", portspec)
|
||||
}
|
||||
}
|
||||
|
||||
portMap, bindingMap, err = ParsePortSpecs([]string{"1234-1236:1234-1236/tcp", "2345-2347:2345-2347/udp"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while processing ParsePortSpecs: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("1235/tcp")]; !ok {
|
||||
t.Fatal("1234/tcp was not parsed properly")
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("2346/udp")]; !ok {
|
||||
t.Fatal("2345/udp was not parsed properly")
|
||||
}
|
||||
|
||||
for portspec, bindings := range bindingMap {
|
||||
_, port := SplitProtoPort(string(portspec))
|
||||
if len(bindings) != 1 {
|
||||
t.Fatalf("%s should have exactly one binding", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostIP != "" {
|
||||
t.Fatalf("HostIP should not be set for %s", portspec)
|
||||
}
|
||||
|
||||
if bindings[0].HostPort != port {
|
||||
t.Fatalf("HostPort should be %s for %s", port, portspec)
|
||||
}
|
||||
}
|
||||
|
||||
portMap, bindingMap, err = ParsePortSpecs([]string{"0.0.0.0:1234-1236:1234-1236/tcp", "0.0.0.0:2345-2347:2345-2347/udp"})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error while processing ParsePortSpecs: %s", err)
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("1235/tcp")]; !ok {
|
||||
t.Fatal("1234/tcp was not parsed properly")
|
||||
}
|
||||
|
||||
if _, ok := portMap[Port("2346/udp")]; !ok {
|
||||
t.Fatal("2345/udp was not parsed properly")
|
||||
}
|
||||
|
||||
for portspec, bindings := range bindingMap {
|
||||
_, port := SplitProtoPort(string(portspec))
|
||||
if len(bindings) != 1 || bindings[0].HostIP != "0.0.0.0" || bindings[0].HostPort != port {
|
||||
t.Fatalf("Expect single binding to port %s but found %s", port, bindings)
|
||||
}
|
||||
}
|
||||
|
||||
_, _, err = ParsePortSpecs([]string{"localhost:1234-1236:1234-1236/tcp"})
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Received no error while trying to parse a hostname instead of ip")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsPrivateOnly(t *testing.T) {
|
||||
ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::80"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(ports))
|
||||
t.FailNow()
|
||||
}
|
||||
if len(bindings) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(bindings))
|
||||
t.FailNow()
|
||||
}
|
||||
for k := range ports {
|
||||
if k.Proto() != "tcp" {
|
||||
t.Logf("Expected tcp got %s", k.Proto())
|
||||
t.Fail()
|
||||
}
|
||||
if k.Port() != "80" {
|
||||
t.Logf("Expected 80 got %s", k.Port())
|
||||
t.Fail()
|
||||
}
|
||||
b, exists := bindings[k]
|
||||
if !exists {
|
||||
t.Log("Binding does not exist")
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(b))
|
||||
t.FailNow()
|
||||
}
|
||||
s := b[0]
|
||||
if s.HostPort != "" {
|
||||
t.Logf("Expected \"\" got %s", s.HostPort)
|
||||
t.Fail()
|
||||
}
|
||||
if s.HostIP != "192.168.1.100" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsPublic(t *testing.T) {
|
||||
ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:8080:80"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(ports))
|
||||
t.FailNow()
|
||||
}
|
||||
if len(bindings) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(bindings))
|
||||
t.FailNow()
|
||||
}
|
||||
for k := range ports {
|
||||
if k.Proto() != "tcp" {
|
||||
t.Logf("Expected tcp got %s", k.Proto())
|
||||
t.Fail()
|
||||
}
|
||||
if k.Port() != "80" {
|
||||
t.Logf("Expected 80 got %s", k.Port())
|
||||
t.Fail()
|
||||
}
|
||||
b, exists := bindings[k]
|
||||
if !exists {
|
||||
t.Log("Binding does not exist")
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(b))
|
||||
t.FailNow()
|
||||
}
|
||||
s := b[0]
|
||||
if s.HostPort != "8080" {
|
||||
t.Logf("Expected 8080 got %s", s.HostPort)
|
||||
t.Fail()
|
||||
}
|
||||
if s.HostIP != "192.168.1.100" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsPublicNoPort(t *testing.T) {
|
||||
ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100"})
|
||||
|
||||
if err == nil {
|
||||
t.Logf("Expected error Invalid containerPort")
|
||||
t.Fail()
|
||||
}
|
||||
if ports != nil {
|
||||
t.Logf("Expected nil got %s", ports)
|
||||
t.Fail()
|
||||
}
|
||||
if bindings != nil {
|
||||
t.Logf("Expected nil got %s", bindings)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsNegativePorts(t *testing.T) {
|
||||
ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100:-1:-1"})
|
||||
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
if len(ports) != 0 {
|
||||
t.Logf("Expected nil got %d", len(ports))
|
||||
t.Fail()
|
||||
}
|
||||
if len(bindings) != 0 {
|
||||
t.Logf("Expected 0 got %d", len(bindings))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNetworkOptsUdp(t *testing.T) {
|
||||
ports, bindings, err := ParsePortSpecs([]string{"192.168.1.100::6000/udp"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ports) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(ports))
|
||||
t.FailNow()
|
||||
}
|
||||
if len(bindings) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(bindings))
|
||||
t.FailNow()
|
||||
}
|
||||
for k := range ports {
|
||||
if k.Proto() != "udp" {
|
||||
t.Logf("Expected udp got %s", k.Proto())
|
||||
t.Fail()
|
||||
}
|
||||
if k.Port() != "6000" {
|
||||
t.Logf("Expected 6000 got %s", k.Port())
|
||||
t.Fail()
|
||||
}
|
||||
b, exists := bindings[k]
|
||||
if !exists {
|
||||
t.Log("Binding does not exist")
|
||||
t.FailNow()
|
||||
}
|
||||
if len(b) != 1 {
|
||||
t.Logf("Expected 1 got %d", len(b))
|
||||
t.FailNow()
|
||||
}
|
||||
s := b[0]
|
||||
if s.HostPort != "" {
|
||||
t.Logf("Expected \"\" got %s", s.HostPort)
|
||||
t.Fail()
|
||||
}
|
||||
if s.HostIP != "192.168.1.100" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
98
nat/sort.go
98
nat/sort.go
|
@ -1,98 +0,0 @@
|
|||
package nat
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/parsers"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// Sort sorts a list of ports using the provided predicate
|
||||
// This function should compare `i` and `j`, returning true if `i` is
|
||||
// considered to be less than `j`
|
||||
func Sort(ports []Port, predicate func(i, j Port) bool) {
|
||||
s := &portSorter{ports, predicate}
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
type portMapEntry struct {
|
||||
port Port
|
||||
binding PortBinding
|
||||
}
|
||||
|
||||
type portMapSorter []portMapEntry
|
||||
|
||||
func (s portMapSorter) Len() int { return len(s) }
|
||||
func (s portMapSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// sort the port so that the order is:
|
||||
// 1. port with larger specified bindings
|
||||
// 2. larger port
|
||||
// 3. port with tcp protocol
|
||||
func (s portMapSorter) Less(i, j int) bool {
|
||||
pi, pj := s[i].port, s[j].port
|
||||
hpi, hpj := toInt(s[i].binding.HostPort), toInt(s[j].binding.HostPort)
|
||||
return hpi > hpj || pi.Int() > pj.Int() || (pi.Int() == pj.Int() && strings.ToLower(pi.Proto()) == "tcp")
|
||||
}
|
||||
|
||||
// SortPortMap sorts the list of ports and their respected mapping. The ports
|
||||
// will explicit HostPort will be placed first.
|
||||
func SortPortMap(ports []Port, bindings PortMap) {
|
||||
s := portMapSorter{}
|
||||
for _, p := range ports {
|
||||
if binding, ok := bindings[p]; ok {
|
||||
for _, b := range binding {
|
||||
s = append(s, portMapEntry{port: p, binding: b})
|
||||
}
|
||||
bindings[p] = []PortBinding{}
|
||||
} else {
|
||||
s = append(s, portMapEntry{port: p})
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(s)
|
||||
var (
|
||||
i int
|
||||
pm = make(map[Port]struct{})
|
||||
)
|
||||
// reorder ports
|
||||
for _, entry := range s {
|
||||
if _, ok := pm[entry.port]; !ok {
|
||||
ports[i] = entry.port
|
||||
pm[entry.port] = struct{}{}
|
||||
i++
|
||||
}
|
||||
// reorder bindings for this port
|
||||
if _, ok := bindings[entry.port]; ok {
|
||||
bindings[entry.port] = append(bindings[entry.port], entry.binding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toInt(s string) uint64 {
|
||||
i, _, err := parsers.ParsePortRange(s)
|
||||
if err != nil {
|
||||
i = 0
|
||||
}
|
||||
return i
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package nat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSortUniquePorts(t *testing.T) {
|
||||
ports := []Port{
|
||||
Port("6379/tcp"),
|
||||
Port("22/tcp"),
|
||||
}
|
||||
|
||||
Sort(ports, func(ip, jp Port) bool {
|
||||
return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
|
||||
})
|
||||
|
||||
first := ports[0]
|
||||
if fmt.Sprint(first) != "22/tcp" {
|
||||
t.Log(fmt.Sprint(first))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortSamePortWithDifferentProto(t *testing.T) {
|
||||
ports := []Port{
|
||||
Port("8888/tcp"),
|
||||
Port("8888/udp"),
|
||||
Port("6379/tcp"),
|
||||
Port("6379/udp"),
|
||||
}
|
||||
|
||||
Sort(ports, func(ip, jp Port) bool {
|
||||
return ip.Int() < jp.Int() || (ip.Int() == jp.Int() && ip.Proto() == "tcp")
|
||||
})
|
||||
|
||||
first := ports[0]
|
||||
if fmt.Sprint(first) != "6379/tcp" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortPortMap(t *testing.T) {
|
||||
ports := []Port{
|
||||
Port("22/tcp"),
|
||||
Port("22/udp"),
|
||||
Port("8000/tcp"),
|
||||
Port("6379/tcp"),
|
||||
Port("9999/tcp"),
|
||||
}
|
||||
|
||||
portMap := PortMap{
|
||||
Port("22/tcp"): []PortBinding{
|
||||
{},
|
||||
},
|
||||
Port("8000/tcp"): []PortBinding{
|
||||
{},
|
||||
},
|
||||
Port("6379/tcp"): []PortBinding{
|
||||
{},
|
||||
{HostIP: "0.0.0.0", HostPort: "32749"},
|
||||
},
|
||||
Port("9999/tcp"): []PortBinding{
|
||||
{HostIP: "0.0.0.0", HostPort: "40000"},
|
||||
},
|
||||
}
|
||||
|
||||
SortPortMap(ports, portMap)
|
||||
if !reflect.DeepEqual(ports, []Port{
|
||||
Port("9999/tcp"),
|
||||
Port("6379/tcp"),
|
||||
Port("8000/tcp"),
|
||||
Port("22/tcp"),
|
||||
Port("22/udp"),
|
||||
}) {
|
||||
t.Errorf("failed to prioritize port with explicit mappings, got %v", ports)
|
||||
}
|
||||
if pm := portMap[Port("6379/tcp")]; !reflect.DeepEqual(pm, []PortBinding{
|
||||
{HostIP: "0.0.0.0", HostPort: "32749"},
|
||||
{},
|
||||
}) {
|
||||
t.Errorf("failed to prioritize bindings with explicit mappings, got %v", pm)
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package stringutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StrSlice represents a string or an array of strings.
|
||||
// We need to override the json decoder to accept both options.
|
||||
type StrSlice struct {
|
||||
parts []string
|
||||
}
|
||||
|
||||
// MarshalJSON Marshals (or serializes) the StrSlice into the json format.
|
||||
// This method is needed to implement json.Marshaller.
|
||||
func (e *StrSlice) MarshalJSON() ([]byte, error) {
|
||||
if e == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
return json.Marshal(e.Slice())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes the byte slice whether it's a string or an array of strings.
|
||||
// This method is needed to implement json.Unmarshaler.
|
||||
func (e *StrSlice) UnmarshalJSON(b []byte) error {
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
p := make([]string, 0, 1)
|
||||
if err := json.Unmarshal(b, &p); err != nil {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
p = append(p, s)
|
||||
}
|
||||
|
||||
e.parts = p
|
||||
return nil
|
||||
}
|
||||
|
||||
// Len returns the number of parts of the StrSlice.
|
||||
func (e *StrSlice) Len() int {
|
||||
if e == nil {
|
||||
return 0
|
||||
}
|
||||
return len(e.parts)
|
||||
}
|
||||
|
||||
// Slice gets the parts of the StrSlice as a Slice of string.
|
||||
func (e *StrSlice) Slice() []string {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return e.parts
|
||||
}
|
||||
|
||||
// ToString gets space separated string of all the parts.
|
||||
func (e *StrSlice) ToString() string {
|
||||
s := e.Slice()
|
||||
if s == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.Join(s, " ")
|
||||
}
|
||||
|
||||
// NewStrSlice creates an StrSlice based on the specified parts (as strings).
|
||||
func NewStrSlice(parts ...string) *StrSlice {
|
||||
return &StrSlice{parts}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
package stringutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStrSliceMarshalJSON(t *testing.T) {
|
||||
strss := map[*StrSlice]string{
|
||||
nil: "",
|
||||
&StrSlice{}: "null",
|
||||
&StrSlice{[]string{"/bin/sh", "-c", "echo"}}: `["/bin/sh","-c","echo"]`,
|
||||
}
|
||||
|
||||
for strs, expected := range strss {
|
||||
data, err := strs.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(data) != expected {
|
||||
t.Fatalf("Expected %v, got %v", expected, string(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrSliceUnmarshalJSON(t *testing.T) {
|
||||
parts := map[string][]string{
|
||||
"": {"default", "values"},
|
||||
"[]": {},
|
||||
`["/bin/sh","-c","echo"]`: {"/bin/sh", "-c", "echo"},
|
||||
}
|
||||
for json, expectedParts := range parts {
|
||||
strs := &StrSlice{
|
||||
[]string{"default", "values"},
|
||||
}
|
||||
if err := strs.UnmarshalJSON([]byte(json)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
actualParts := strs.Slice()
|
||||
if len(actualParts) != len(expectedParts) {
|
||||
t.Fatalf("Expected %v parts, got %v (%v)", len(expectedParts), len(actualParts), expectedParts)
|
||||
}
|
||||
for index, part := range actualParts {
|
||||
if part != expectedParts[index] {
|
||||
t.Fatalf("Expected %v, got %v", expectedParts, actualParts)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrSliceUnmarshalString(t *testing.T) {
|
||||
var e *StrSlice
|
||||
echo, err := json.Marshal("echo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := json.Unmarshal(echo, &e); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slice := e.Slice()
|
||||
if len(slice) != 1 {
|
||||
t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
||||
}
|
||||
|
||||
if slice[0] != "echo" {
|
||||
t.Fatalf("expected `echo`, got: %q", slice[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrSliceUnmarshalSlice(t *testing.T) {
|
||||
var e *StrSlice
|
||||
echo, err := json.Marshal([]string{"echo"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := json.Unmarshal(echo, &e); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
slice := e.Slice()
|
||||
if len(slice) != 1 {
|
||||
t.Fatalf("expected 1 element after unmarshal: %q", slice)
|
||||
}
|
||||
|
||||
if slice[0] != "echo" {
|
||||
t.Fatalf("expected `echo`, got: %q", slice[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrSliceToString(t *testing.T) {
|
||||
slices := map[*StrSlice]string{
|
||||
NewStrSlice(""): "",
|
||||
NewStrSlice("one"): "one",
|
||||
NewStrSlice("one", "two"): "one two",
|
||||
}
|
||||
for s, expected := range slices {
|
||||
toString := s.ToString()
|
||||
if toString != expected {
|
||||
t.Fatalf("Expected %v, got %v", expected, toString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrSliceLen(t *testing.T) {
|
||||
var emptyStrSlice *StrSlice
|
||||
slices := map[*StrSlice]int{
|
||||
NewStrSlice(""): 1,
|
||||
NewStrSlice("one"): 1,
|
||||
NewStrSlice("one", "two"): 2,
|
||||
emptyStrSlice: 0,
|
||||
}
|
||||
for s, expected := range slices {
|
||||
if s.Len() != expected {
|
||||
t.Fatalf("Expected %d, got %d", s.Len(), expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStrSliceSlice(t *testing.T) {
|
||||
var emptyStrSlice *StrSlice
|
||||
slices := map[*StrSlice][]string{
|
||||
NewStrSlice("one"): {"one"},
|
||||
NewStrSlice("one", "two"): {"one", "two"},
|
||||
emptyStrSlice: nil,
|
||||
}
|
||||
for s, expected := range slices {
|
||||
if !reflect.DeepEqual(s.Slice(), expected) {
|
||||
t.Fatalf("Expected %v, got %v", s.Slice(), expected)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue