فهرست منبع

Merge pull request #55 from mrjana/cnm

Add more test cases to test libnetwork API
Madhu Venugopal 10 سال پیش
والد
کامیت
381592d1c1

+ 53 - 0
libnetwork/cmd/readme_test/readme.go

@@ -0,0 +1,53 @@
+package main
+
+import (
+	"github.com/docker/libnetwork"
+	"github.com/docker/libnetwork/pkg/options"
+	"github.com/docker/libnetwork/sandbox"
+)
+
+func main() {
+	// Create a new controller instance
+	controller := libnetwork.New()
+
+	option := options.Generic{}
+	driver, err := controller.NewNetworkDriver("simplebridge", option)
+	if err != nil {
+		return
+	}
+
+	netOptions := options.Generic{}
+	// Create a network for containers to join.
+	network, err := controller.NewNetwork(driver, "network1", netOptions)
+	if err != nil {
+		return
+	}
+
+	// For a new container: create a sandbox instance (providing a unique key).
+	// For linux it is a filesystem path
+	networkPath := "/var/lib/docker/.../4d23e"
+	networkNamespace, err := sandbox.NewSandbox(networkPath)
+	if err != nil {
+		return
+	}
+
+	// For each new container: allocate IP and interfaces. The returned network
+	// settings will be used for container infos (inspect and such), as well as
+	// iptables rules for port publishing.
+	_, sinfo, err := network.CreateEndpoint("Endpoint1", networkNamespace.Key(), "")
+	if err != nil {
+		return
+	}
+
+	// Add interfaces to the namespace.
+	for _, iface := range sinfo.Interfaces {
+		if err := networkNamespace.AddInterface(iface); err != nil {
+			return
+		}
+	}
+
+	// Set the gateway IP
+	if err := networkNamespace.SetGateway(sinfo.Gateway); err != nil {
+		return
+	}
+}

+ 1 - 1
libnetwork/drivers/bridge/bridge.go

@@ -156,7 +156,7 @@ func (d *driver) CreateNetwork(id driverapi.UUID, option interface{}) error {
 
 		// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
 		// the case of a previously existing device.
-		{bridgeAlreadyExists, setupVerifyConfiguredAddresses},
+		{bridgeAlreadyExists, setupVerifyAndReconcile},
 
 		// Setup the bridge to allocate containers IPv4 addresses in the
 		// specified subnet.

+ 7 - 1
libnetwork/drivers/bridge/setup_verify.go

@@ -6,7 +6,7 @@ import (
 	"github.com/vishvananda/netlink"
 )
 
-func setupVerifyConfiguredAddresses(config *Configuration, i *bridgeInterface) error {
+func setupVerifyAndReconcile(config *Configuration, i *bridgeInterface) error {
 	// Fetch a single IPv4 and a slice of IPv6 addresses from the bridge.
 	addrv4, addrsv6, err := i.addresses()
 	if err != nil {
@@ -29,6 +29,12 @@ func setupVerifyConfiguredAddresses(config *Configuration, i *bridgeInterface) e
 		return fmt.Errorf("Bridge IPv6 addresses do not match the expected bridge configuration %s", bridgeIPv6)
 	}
 
+	// By this time we have either configured a new bridge with an IP address
+	// or made sure an existing bridge's IP matches the configuration
+	// Now is the time to cache these states in the bridgeInterface.
+	i.bridgeIPv4 = addrv4.IPNet
+	i.bridgeIPv6 = bridgeIPv6
+
 	return nil
 }
 

+ 63 - 0
libnetwork/error.go

@@ -0,0 +1,63 @@
+package libnetwork
+
+import (
+	"errors"
+	"fmt"
+)
+
+var (
+	// ErrNilNetworkDriver is returned if a nil network driver
+	// is passed to NewNetwork api.
+	ErrNilNetworkDriver = errors.New("nil NetworkDriver instance")
+	// ErrInvalidNetworkDriver is returned if an invalid driver
+	// instance is passed.
+	ErrInvalidNetworkDriver = errors.New("invalid driver bound to network")
+)
+
+// NetworkTypeError type is returned when the network type string is not
+// known to libnetwork.
+type NetworkTypeError string
+
+func (nt NetworkTypeError) Error() string {
+	return fmt.Sprintf("unknown driver %q", string(nt))
+}
+
+// NetworkNameError is returned when a network with the same name already exists.
+type NetworkNameError string
+
+func (name NetworkNameError) Error() string {
+	return fmt.Sprintf("network with name %s already exists", string(name))
+}
+
+// UnknownNetworkError is returned when libnetwork could not find in it's database
+// a network with the same name and id.
+type UnknownNetworkError struct {
+	name string
+	id   string
+}
+
+func (une *UnknownNetworkError) Error() string {
+	return fmt.Sprintf("unknown network %s id %s", une.name, une.id)
+}
+
+// ActiveEndpointsError is returned when a network is deleted which has active
+// endpoints in it.
+type ActiveEndpointsError struct {
+	name string
+	id   string
+}
+
+func (aee *ActiveEndpointsError) Error() string {
+	return fmt.Sprintf("network with name %s id %s has active endpoints", aee.name, aee.id)
+}
+
+// UnknownEndpointError is returned when libnetwork could not find in it's database
+// an endpoint with the same name and id.
+type UnknownEndpointError struct {
+	name string
+	id   string
+}
+
+func (uee *UnknownEndpointError) Error() string {
+	return fmt.Sprintf("unknown endpoint %s id %s", uee.name, uee.id)
+}

+ 215 - 7
libnetwork/libnetwork_test.go

@@ -8,15 +8,27 @@ import (
 	"github.com/docker/libnetwork"
 	_ "github.com/docker/libnetwork/drivers/bridge"
 	"github.com/docker/libnetwork/pkg/options"
-	"github.com/vishvananda/netlink"
 )
 
 var bridgeName = "dockertest0"
 
-func TestSimplebridge(t *testing.T) {
-	bridge := &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}
-	netlink.LinkDel(bridge)
+func createTestNetwork(networkType, networkName string, option options.Generic) (libnetwork.Network, error) {
+	controller := libnetwork.New()
+
+	driver, err := controller.NewNetworkDriver(networkType, option)
+	if err != nil {
+		return nil, err
+	}
 
+	network, err := controller.NewNetwork(driver, networkName, "")
+	if err != nil {
+		return nil, err
+	}
+
+	return network, nil
+}
+
+func TestSimplebridge(t *testing.T) {
 	ip, subnet, err := net.ParseCIDR("192.168.100.1/24")
 	if err != nil {
 		t.Fatal(err)
@@ -36,7 +48,7 @@ func TestSimplebridge(t *testing.T) {
 	cidrv6.IP = ip
 
 	log.Debug("Adding a simple bridge")
-	options := options.Generic{
+	option := options.Generic{
 		"BridgeName":            bridgeName,
 		"AddressIPv4":           subnet,
 		"FixedCIDR":             cidr,
@@ -48,14 +60,133 @@ func TestSimplebridge(t *testing.T) {
 		"EnableIPForwarding":    true,
 		"AllowNonDefaultBridge": true}
 
+	network, err := createTestNetwork("simplebridge", "testnetwork", option)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ep, _, err := network.CreateEndpoint("testep", "", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if err := ep.Delete(); err != nil {
+		t.Fatal(err)
+	}
+
+	if err := network.Delete(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestUnknownDriver(t *testing.T) {
+	_, err := createTestNetwork("unknowndriver", "testnetwork", options.Generic{})
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if _, ok := err.(libnetwork.NetworkTypeError); !ok {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+}
+
+func TestNilDriver(t *testing.T) {
 	controller := libnetwork.New()
 
-	driver, err := controller.NewNetworkDriver("simplebridge", options)
+	option := options.Generic{}
+	_, err := controller.NewNetwork(nil, "dummy", option)
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if err != libnetwork.ErrNilNetworkDriver {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+}
+
+func TestNoInitDriver(t *testing.T) {
+	controller := libnetwork.New()
+
+	option := options.Generic{}
+	_, err := controller.NewNetwork(&libnetwork.NetworkDriver{}, "dummy", option)
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if err != libnetwork.ErrInvalidNetworkDriver {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+}
+
+func TestDuplicateNetwork(t *testing.T) {
+	controller := libnetwork.New()
+
+	option := options.Generic{}
+	driver, err := controller.NewNetworkDriver("simplebridge", option)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = controller.NewNetwork(driver, "testnetwork", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	_, err = controller.NewNetwork(driver, "testnetwork", "")
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if _, ok := err.(libnetwork.NetworkNameError); !ok {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+}
+
+func TestNetworkName(t *testing.T) {
+	networkName := "testnetwork"
+
+	n, err := createTestNetwork("simplebridge", networkName, options.Generic{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if n.Name() != networkName {
+		t.Fatalf("Expected network name %s, got %s", networkName, n.Name())
+	}
+}
+
+func TestNetworkType(t *testing.T) {
+	networkType := "simplebridge"
+
+	n, err := createTestNetwork(networkType, "testnetwork", options.Generic{})
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	network, err := controller.NewNetwork(driver, "testnetwork", "")
+	if n.Type() != networkType {
+		t.Fatalf("Expected network type %s, got %s", networkType, n.Type())
+	}
+}
+
+func TestNetworkID(t *testing.T) {
+	networkType := "simplebridge"
+
+	n, err := createTestNetwork(networkType, "testnetwork", options.Generic{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	if n.ID() == "" {
+		t.Fatal("Expected non-empty network id")
+	}
+}
+
+func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
+	option := options.Generic{
+		"BridgeName":            bridgeName,
+		"AllowNonDefaultBridge": true}
+
+	network, err := createTestNetwork("simplebridge", "testnetwork", option)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -65,6 +196,16 @@ func TestSimplebridge(t *testing.T) {
 		t.Fatal(err)
 	}
 
+	err = network.Delete()
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if _, ok := err.(*libnetwork.ActiveEndpointsError); !ok {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+
+	// Done testing. Now cleanup.
 	if err := ep.Delete(); err != nil {
 		t.Fatal(err)
 	}
@@ -73,3 +214,70 @@ func TestSimplebridge(t *testing.T) {
 		t.Fatal(err)
 	}
 }
+
+func TestUnknownNetwork(t *testing.T) {
+	option := options.Generic{
+		"BridgeName":            bridgeName,
+		"AllowNonDefaultBridge": true}
+
+	network, err := createTestNetwork("simplebridge", "testnetwork", option)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = network.Delete()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = network.Delete()
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if _, ok := err.(*libnetwork.UnknownNetworkError); !ok {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+}
+
+func TestUnknownEndpoint(t *testing.T) {
+	ip, subnet, err := net.ParseCIDR("192.168.100.1/24")
+	if err != nil {
+		t.Fatal(err)
+	}
+	subnet.IP = ip
+
+	option := options.Generic{
+		"BridgeName":            bridgeName,
+		"AddressIPv4":           subnet,
+		"AllowNonDefaultBridge": true}
+
+	network, err := createTestNetwork("simplebridge", "testnetwork", option)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ep, _, err := network.CreateEndpoint("testep", "", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ep.Delete()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ep.Delete()
+	if err == nil {
+		t.Fatal("Expected to fail. But instead succeeded")
+	}
+
+	if _, ok := err.(*libnetwork.UnknownEndpointError); !ok {
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
+	}
+
+	// Done testing. Now cleanup
+	if err := network.Delete(); err != nil {
+		t.Fatal(err)
+	}
+}

+ 26 - 9
libnetwork/network.go

@@ -39,7 +39,6 @@ create network namespaces and allocate interfaces for containers to use.
 package libnetwork
 
 import (
-	"fmt"
 	"sync"
 
 	"github.com/docker/docker/pkg/common"
@@ -84,6 +83,7 @@ type Endpoint interface {
 
 // NetworkDriver provides a reference to driver and way to push driver specific config
 type NetworkDriver struct {
+	networkType    string
 	internalDriver driverapi.Driver
 }
 
@@ -121,19 +121,32 @@ func New() NetworkController {
 func (c *controller) NewNetworkDriver(networkType string, options interface{}) (*NetworkDriver, error) {
 	d, ok := c.drivers[networkType]
 	if !ok {
-		return nil, fmt.Errorf("unknown driver %q", networkType)
+		return nil, NetworkTypeError(networkType)
 	}
 
 	if err := d.Config(options); err != nil {
 		return nil, err
 	}
 
-	return &NetworkDriver{internalDriver: d}, nil
+	return &NetworkDriver{networkType: networkType, internalDriver: d}, nil
 }
 
-// NewNetwork creates a new network of the specified networkType. The options
+// NewNetwork creates a new network of the specified NetworkDriver. The options
 // are driver specific and modeled in a generic way.
 func (c *controller) NewNetwork(nd *NetworkDriver, name string, options interface{}) (Network, error) {
+	if nd == nil {
+		return nil, ErrNilNetworkDriver
+	}
+
+	c.Lock()
+	for _, n := range c.networks {
+		if n.name == name {
+			c.Unlock()
+			return nil, NetworkNameError(name)
+		}
+	}
+	c.Unlock()
+
 	network := &network{
 		name:   name,
 		id:     driverapi.UUID(common.GenerateRandomID()),
@@ -143,7 +156,7 @@ func (c *controller) NewNetwork(nd *NetworkDriver, name string, options interfac
 
 	d := network.driver.internalDriver
 	if d == nil {
-		return nil, fmt.Errorf("invalid driver bound to network")
+		return nil, ErrInvalidNetworkDriver
 	}
 
 	if err := d.CreateNetwork(network.id, options); err != nil {
@@ -166,7 +179,11 @@ func (n *network) ID() string {
 }
 
 func (n *network) Type() string {
-	return n.networkType
+	if n.driver == nil {
+		return ""
+	}
+
+	return n.driver.networkType
 }
 
 func (n *network) Delete() error {
@@ -176,7 +193,7 @@ func (n *network) Delete() error {
 	_, ok := n.ctrlr.networks[n.id]
 	if !ok {
 		n.ctrlr.Unlock()
-		return fmt.Errorf("unknown network %s id %s", n.name, n.id)
+		return &UnknownNetworkError{name: n.name, id: string(n.id)}
 	}
 
 	n.Lock()
@@ -184,7 +201,7 @@ func (n *network) Delete() error {
 	n.Unlock()
 	if numEps != 0 {
 		n.ctrlr.Unlock()
-		return fmt.Errorf("network %s has active endpoints", n.id)
+		return &ActiveEndpointsError{name: n.name, id: string(n.id)}
 	}
 
 	delete(n.ctrlr.networks, n.id)
@@ -228,7 +245,7 @@ func (ep *endpoint) Delete() error {
 	_, ok := n.endpoints[ep.id]
 	if !ok {
 		n.Unlock()
-		return fmt.Errorf("unknown endpoint %s id %s", ep.name, ep.id)
+		return &UnknownEndpointError{name: ep.name, id: string(ep.id)}
 	}
 
 	delete(n.endpoints, ep.id)