github.com/leoh0/docker@v1.6.0-rc4/daemon/networkdriver/bridge/driver_test.go (about)

     1  package bridge
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strconv"
     7  	"testing"
     8  
     9  	"github.com/docker/docker/daemon/networkdriver/portmapper"
    10  	"github.com/docker/docker/engine"
    11  	"github.com/docker/docker/pkg/iptables"
    12  )
    13  
    14  func init() {
    15  	// reset the new proxy command for mocking out the userland proxy in tests
    16  	portmapper.NewProxy = portmapper.NewMockProxyCommand
    17  }
    18  
    19  func findFreePort(t *testing.T) int {
    20  	l, err := net.Listen("tcp", ":0")
    21  	if err != nil {
    22  		t.Fatal("Failed to find a free port")
    23  	}
    24  	defer l.Close()
    25  
    26  	result, err := net.ResolveTCPAddr("tcp", l.Addr().String())
    27  	if err != nil {
    28  		t.Fatal("Failed to resolve address to identify free port")
    29  	}
    30  	return result.Port
    31  }
    32  
    33  func newPortAllocationJob(eng *engine.Engine, port int) (job *engine.Job) {
    34  	strPort := strconv.Itoa(port)
    35  
    36  	job = eng.Job("allocate_port", "container_id")
    37  	job.Setenv("HostIP", "127.0.0.1")
    38  	job.Setenv("HostPort", strPort)
    39  	job.Setenv("Proto", "tcp")
    40  	job.Setenv("ContainerPort", strPort)
    41  	return
    42  }
    43  
    44  func newPortAllocationJobWithInvalidHostIP(eng *engine.Engine, port int) (job *engine.Job) {
    45  	strPort := strconv.Itoa(port)
    46  
    47  	job = eng.Job("allocate_port", "container_id")
    48  	job.Setenv("HostIP", "localhost")
    49  	job.Setenv("HostPort", strPort)
    50  	job.Setenv("Proto", "tcp")
    51  	job.Setenv("ContainerPort", strPort)
    52  	return
    53  }
    54  
    55  func TestAllocatePortDetection(t *testing.T) {
    56  	eng := engine.New()
    57  	eng.Logging = false
    58  
    59  	freePort := findFreePort(t)
    60  
    61  	// Init driver
    62  	job := eng.Job("initdriver")
    63  	if res := InitDriver(job); res != engine.StatusOK {
    64  		t.Fatal("Failed to initialize network driver")
    65  	}
    66  
    67  	// Allocate interface
    68  	job = eng.Job("allocate_interface", "container_id")
    69  	if res := Allocate(job); res != engine.StatusOK {
    70  		t.Fatal("Failed to allocate network interface")
    71  	}
    72  
    73  	// Allocate same port twice, expect failure on second call
    74  	job = newPortAllocationJob(eng, freePort)
    75  	if res := AllocatePort(job); res != engine.StatusOK {
    76  		t.Fatal("Failed to find a free port to allocate")
    77  	}
    78  	if res := AllocatePort(job); res == engine.StatusOK {
    79  		t.Fatal("Duplicate port allocation granted by AllocatePort")
    80  	}
    81  }
    82  
    83  func TestHostnameFormatChecking(t *testing.T) {
    84  	eng := engine.New()
    85  	eng.Logging = false
    86  
    87  	freePort := findFreePort(t)
    88  
    89  	// Init driver
    90  	job := eng.Job("initdriver")
    91  	if res := InitDriver(job); res != engine.StatusOK {
    92  		t.Fatal("Failed to initialize network driver")
    93  	}
    94  
    95  	// Allocate interface
    96  	job = eng.Job("allocate_interface", "container_id")
    97  	if res := Allocate(job); res != engine.StatusOK {
    98  		t.Fatal("Failed to allocate network interface")
    99  	}
   100  
   101  	// Allocate port with invalid HostIP, expect failure with Bad Request http status
   102  	job = newPortAllocationJobWithInvalidHostIP(eng, freePort)
   103  	if res := AllocatePort(job); res == engine.StatusOK {
   104  		t.Fatal("Failed to check invalid HostIP")
   105  	}
   106  }
   107  
   108  func newInterfaceAllocation(t *testing.T, input engine.Env) (output engine.Env) {
   109  	eng := engine.New()
   110  	eng.Logging = false
   111  
   112  	done := make(chan bool)
   113  
   114  	// set IPv6 global if given
   115  	if input.Exists("globalIPv6Network") {
   116  		_, globalIPv6Network, _ = net.ParseCIDR(input.Get("globalIPv6Network"))
   117  	}
   118  
   119  	job := eng.Job("allocate_interface", "container_id")
   120  	job.Env().Init(&input)
   121  	reader, _ := job.Stdout.AddPipe()
   122  	go func() {
   123  		output.Decode(reader)
   124  		done <- true
   125  	}()
   126  
   127  	res := Allocate(job)
   128  	job.Stdout.Close()
   129  	<-done
   130  
   131  	if input.Exists("expectFail") && input.GetBool("expectFail") {
   132  		if res == engine.StatusOK {
   133  			t.Fatal("Doesn't fail to allocate network interface")
   134  		}
   135  	} else {
   136  		if res != engine.StatusOK {
   137  			t.Fatal("Failed to allocate network interface")
   138  		}
   139  	}
   140  
   141  	if input.Exists("globalIPv6Network") {
   142  		// check for bug #11427
   143  		_, subnet, _ := net.ParseCIDR(input.Get("globalIPv6Network"))
   144  		if globalIPv6Network.IP.String() != subnet.IP.String() {
   145  			t.Fatal("globalIPv6Network was modified during allocation")
   146  		}
   147  		// clean up IPv6 global
   148  		globalIPv6Network = nil
   149  	}
   150  
   151  	return
   152  }
   153  
   154  func TestIPv6InterfaceAllocationAutoNetmaskGt80(t *testing.T) {
   155  
   156  	input := engine.Env{}
   157  
   158  	_, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/81")
   159  
   160  	// set global ipv6
   161  	input.Set("globalIPv6Network", subnet.String())
   162  
   163  	output := newInterfaceAllocation(t, input)
   164  
   165  	// ensure low manually assigend global ip
   166  	ip := net.ParseIP(output.Get("GlobalIPv6"))
   167  	_, subnet, _ = net.ParseCIDR(fmt.Sprintf("%s/%d", subnet.IP.String(), 120))
   168  	if !subnet.Contains(ip) {
   169  		t.Fatalf("Error ip %s not in subnet %s", ip.String(), subnet.String())
   170  	}
   171  }
   172  
   173  func TestIPv6InterfaceAllocationAutoNetmaskLe80(t *testing.T) {
   174  
   175  	input := engine.Env{}
   176  
   177  	_, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80")
   178  
   179  	// set global ipv6
   180  	input.Set("globalIPv6Network", subnet.String())
   181  	input.Set("RequestedMac", "ab:cd:ab:cd:ab:cd")
   182  
   183  	output := newInterfaceAllocation(t, input)
   184  
   185  	// ensure global ip with mac
   186  	ip := net.ParseIP(output.Get("GlobalIPv6"))
   187  	expected_ip := net.ParseIP("2001:db8:1234:1234:1234:abcd:abcd:abcd")
   188  	if ip.String() != expected_ip.String() {
   189  		t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String())
   190  	}
   191  
   192  	// ensure link local format
   193  	ip = net.ParseIP(output.Get("LinkLocalIPv6"))
   194  	expected_ip = net.ParseIP("fe80::a9cd:abff:fecd:abcd")
   195  	if ip.String() != expected_ip.String() {
   196  		t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String())
   197  	}
   198  
   199  }
   200  
   201  func TestIPv6InterfaceAllocationRequest(t *testing.T) {
   202  
   203  	input := engine.Env{}
   204  
   205  	_, subnet, _ := net.ParseCIDR("2001:db8:1234:1234:1234::/80")
   206  	expected_ip := net.ParseIP("2001:db8:1234:1234:1234::1328")
   207  
   208  	// set global ipv6
   209  	input.Set("globalIPv6Network", subnet.String())
   210  	input.Set("RequestedIPv6", expected_ip.String())
   211  
   212  	output := newInterfaceAllocation(t, input)
   213  
   214  	// ensure global ip with mac
   215  	ip := net.ParseIP(output.Get("GlobalIPv6"))
   216  	if ip.String() != expected_ip.String() {
   217  		t.Fatalf("Error ip %s should be %s", ip.String(), expected_ip.String())
   218  	}
   219  
   220  	// retry -> fails for duplicated address
   221  	input.SetBool("expectFail", true)
   222  	output = newInterfaceAllocation(t, input)
   223  }
   224  
   225  func TestMacAddrGeneration(t *testing.T) {
   226  	ip := net.ParseIP("192.168.0.1")
   227  	mac := generateMacAddr(ip).String()
   228  
   229  	// Should be consistent.
   230  	if generateMacAddr(ip).String() != mac {
   231  		t.Fatal("Inconsistent MAC address")
   232  	}
   233  
   234  	// Should be unique.
   235  	ip2 := net.ParseIP("192.168.0.2")
   236  	if generateMacAddr(ip2).String() == mac {
   237  		t.Fatal("Non-unique MAC address")
   238  	}
   239  }
   240  
   241  func TestLinkContainers(t *testing.T) {
   242  	eng := engine.New()
   243  	eng.Logging = false
   244  
   245  	// Init driver
   246  	job := eng.Job("initdriver")
   247  	if res := InitDriver(job); res != engine.StatusOK {
   248  		t.Fatal("Failed to initialize network driver")
   249  	}
   250  
   251  	// Allocate interface
   252  	job = eng.Job("allocate_interface", "container_id")
   253  	if res := Allocate(job); res != engine.StatusOK {
   254  		t.Fatal("Failed to allocate network interface")
   255  	}
   256  
   257  	job.Args[0] = "-I"
   258  
   259  	job.Setenv("ChildIP", "172.17.0.2")
   260  	job.Setenv("ParentIP", "172.17.0.1")
   261  	job.SetenvBool("IgnoreErrors", false)
   262  	job.SetenvList("Ports", []string{"1234"})
   263  
   264  	bridgeIface = "lo"
   265  	_, err := iptables.NewChain("DOCKER", bridgeIface, iptables.Filter)
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	if res := LinkContainers(job); res != engine.StatusOK {
   271  		t.Fatalf("LinkContainers failed")
   272  	}
   273  
   274  	// flush rules
   275  	if _, err = iptables.Raw([]string{"-F", "DOCKER"}...); err != nil {
   276  		t.Fatal(err)
   277  	}
   278  
   279  }