Add driver api enhancements for gossip

With the introduction of a driver generic gossip in libnetwork it is not
necessary for drivers to run their own gossip protocol (like what
overlay driver is doing currently) but instead rely on the gossip
instance run centrally in libnetwork. In order to achieve this, certain
enhancements to driver api are needed. This api aims to provide these
enhancements.

The new api provides a way for drivers to register interest on table
names of their choice by returning a list of table names of interest as
a response to CreateNetwork. By doing that they will get notified if a
CRUD operation happened on the tables of their interest, via the newly
added EventNotify call.

Drivers themselves can add entries to any table during a Join call by
invoking AddTableEntry method any number of times during the Join
call. These entries lifetime is the same as the endpoint itself. As soon
as the container leaves the endpoint, those entries added by driver
during that endpoint's Join call will be automatically removed by
libnetwork. This action may trigger notification of such deletion to all
driver instances in the cluster who have registered interest in that
table's notification.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2016-04-18 19:55:39 -07:00
parent 6f51f5b76e
commit ed939ef5c3
23 changed files with 124 additions and 40 deletions

View File

@ -92,6 +92,10 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int,
return nil
}
func (ep *endpoint) AddTableEntry(tableName string, key string, value []byte) error {
return nil
}
func (ep *endpoint) DisableGatewayService() {}
func main() {
@ -120,7 +124,7 @@ func main() {
}
if err := r.d.CreateNetwork("testnetwork",
map[string]interface{}{}, nil, nil); err != nil {
map[string]interface{}{}, nil, nil, nil); err != nil {
fmt.Printf("Failed to create network in the driver: %v\n", err)
os.Exit(1)
}

View File

@ -506,7 +506,7 @@ func (c *controller) addNetwork(n *network) error {
}
// Create the network
if err := d.CreateNetwork(n.id, n.generic, n.getIPData(4), n.getIPData(6)); err != nil {
if err := d.CreateNetwork(n.id, n.generic, nil, n.getIPData(4), n.getIPData(6)); err != nil {
return err
}

View File

@ -23,10 +23,15 @@ type Driver interface {
// associated with a given network id.
NetworkFree(nid string) error
// CreateNetwork invokes the driver method to create a network passing
// the network id and network specific config. The config mechanism will
// eventually be replaced with labels which are yet to be introduced.
CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []IPAMData) error
// CreateNetwork invokes the driver method to create a network
// passing the network id and network specific config. The
// config mechanism will eventually be replaced with labels
// which are yet to be introduced. The driver can return a
// list of table names for which it is interested in receiving
// notification when a CRUD operation is performed on any
// entry in that table. This will be ignored for local scope
// drivers.
CreateNetwork(nid string, options map[string]interface{}, nInfo NetworkInfo, ipV4Data, ipV6Data []IPAMData) error
// DeleteNetwork invokes the driver method to delete network passing
// the network id.
@ -60,10 +65,24 @@ type Driver interface {
// programming that was done so far
RevokeExternalConnectivity(nid, eid string) error
// EventNotify notifies the driver when a CRUD operation has
// happened on a table of its interest as soon as this node
// receives such an event in the gossip layer. This method is
// only invoked for the global scope driver.
EventNotify(event EventType, nid string, tableName string, key string, value []byte)
// Type returns the the type of this driver, the network type this driver manages
Type() string
}
// NetworkInfo provides a go interface for drivers to provide network
// specific information to libnetwork.
type NetworkInfo interface {
// TableEventRegister registers driver interest in a given
// table name.
TableEventRegister(tableName string) error
}
// InterfaceInfo provides a go interface for drivers to retrive
// network information to interface resources.
type InterfaceInfo interface {
@ -112,6 +131,10 @@ type JoinInfo interface {
// DisableGatewayService tells libnetwork not to provide Default GW for the container
DisableGatewayService()
// AddTableEntry adds a table entry to the gossip layer
// passing the table name, key and an opaque value.
AddTableEntry(tableName string, key string, value []byte) error
}
// DriverCallback provides a Callback interface for Drivers into LibNetwork
@ -134,3 +157,15 @@ type IPAMData struct {
Gateway *net.IPNet
AuxAddresses map[string]*net.IPNet
}
// EventType defines a type for the CRUD event
type EventType uint8
const (
// Create event is generated when a table entry is created,
Create EventType = 1 + iota
// Update event is generated when a table entry is updated.
Update
// Delete event is generated when a table entry is deleted.
Delete
)

View File

@ -543,8 +543,11 @@ func (d *driver) NetworkFree(id string) error {
return types.NotImplementedErrorf("not implemented")
}
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
// Create a new network using bridge plugin
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
return types.BadRequestErrorf("ipv4 pool is empty")
}

View File

@ -69,7 +69,7 @@ func TestCreateFullOptions(t *testing.T) {
AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
},
}
err := d.CreateNetwork("dummy", netOption, ipdList, nil)
err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -95,7 +95,7 @@ func TestCreateNoConfig(t *testing.T) {
genericOption := make(map[string]interface{})
genericOption[netlabel.GenericData] = netconfig
if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
}
@ -142,7 +142,7 @@ func TestCreateFullOptionsLabels(t *testing.T) {
},
}
err := d.CreateNetwork("dummy", netOption, ipdList, ipd6List)
err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -211,11 +211,11 @@ func TestCreate(t *testing.T) {
genericOption := make(map[string]interface{})
genericOption[netlabel.GenericData] = netconfig
if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err != nil {
if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil)
err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil)
if err == nil {
t.Fatalf("Expected bridge driver to refuse creation of second network with default name")
}
@ -236,7 +236,7 @@ func TestCreateFail(t *testing.T) {
genericOption := make(map[string]interface{})
genericOption[netlabel.GenericData] = netconfig
if err := d.CreateNetwork("dummy", genericOption, getIPv4Data(t), nil); err == nil {
if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t), nil); err == nil {
t.Fatal("Bridge creation was expected to fail")
}
}
@ -258,13 +258,13 @@ func TestCreateMultipleNetworks(t *testing.T) {
config1 := &networkConfiguration{BridgeName: "net_test_1"}
genericOption = make(map[string]interface{})
genericOption[netlabel.GenericData] = config1
if err := d.CreateNetwork("1", genericOption, getIPv4Data(t), nil); err != nil {
if err := d.CreateNetwork("1", genericOption, nil, getIPv4Data(t), nil); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
config2 := &networkConfiguration{BridgeName: "net_test_2"}
genericOption[netlabel.GenericData] = config2
if err := d.CreateNetwork("2", genericOption, getIPv4Data(t), nil); err != nil {
if err := d.CreateNetwork("2", genericOption, nil, getIPv4Data(t), nil); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -273,7 +273,7 @@ func TestCreateMultipleNetworks(t *testing.T) {
config3 := &networkConfiguration{BridgeName: "net_test_3"}
genericOption[netlabel.GenericData] = config3
if err := d.CreateNetwork("3", genericOption, getIPv4Data(t), nil); err != nil {
if err := d.CreateNetwork("3", genericOption, nil, getIPv4Data(t), nil); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -282,7 +282,7 @@ func TestCreateMultipleNetworks(t *testing.T) {
config4 := &networkConfiguration{BridgeName: "net_test_4"}
genericOption[netlabel.GenericData] = config4
if err := d.CreateNetwork("4", genericOption, getIPv4Data(t), nil); err != nil {
if err := d.CreateNetwork("4", genericOption, nil, getIPv4Data(t), nil); err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -429,6 +429,10 @@ func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, ne
return nil
}
func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
return nil
}
func (te *testEndpoint) DisableGatewayService() {}
func TestQueryEndpointInfo(t *testing.T) {
@ -462,7 +466,7 @@ func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
genericOption[netlabel.GenericData] = netconfig
ipdList := getIPv4Data(t)
err := d.CreateNetwork("net1", genericOption, ipdList, nil)
err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -563,7 +567,7 @@ func TestLinkContainers(t *testing.T) {
genericOption[netlabel.GenericData] = netconfig
ipdList := getIPv4Data(t)
err := d.CreateNetwork("net1", genericOption, ipdList, nil)
err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -789,7 +793,7 @@ func TestSetDefaultGw(t *testing.T) {
genericOption[netlabel.EnableIPv6] = true
genericOption[netlabel.GenericData] = config
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}

View File

@ -27,7 +27,7 @@ func TestLinkCreate(t *testing.T) {
genericOption[netlabel.GenericData] = config
ipdList := getIPv4Data(t)
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -119,7 +119,7 @@ func TestLinkCreateTwo(t *testing.T) {
genericOption[netlabel.GenericData] = config
ipdList := getIPv4Data(t)
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -155,7 +155,7 @@ func TestLinkCreateNoEnableIPv6(t *testing.T) {
genericOption[netlabel.GenericData] = config
ipdList := getIPv4Data(t)
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}
@ -190,7 +190,7 @@ func TestLinkDelete(t *testing.T) {
genericOption[netlabel.GenericData] = config
ipdList := getIPv4Data(t)
err := d.CreateNetwork("dummy", genericOption, ipdList, nil)
err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}

View File

@ -45,7 +45,7 @@ func TestPortMappingConfig(t *testing.T) {
netOptions[netlabel.GenericData] = netConfig
ipdList := getIPv4Data(t)
err := d.CreateNetwork("dummy", netOptions, ipdList, nil)
err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil)
if err != nil {
t.Fatalf("Failed to create bridge: %v", err)
}

View File

@ -32,7 +32,10 @@ func (d *driver) NetworkFree(id string) error {
return types.NotImplementedErrorf("not implemented")
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
d.Lock()
defer d.Unlock()

View File

@ -14,7 +14,7 @@ func TestDriver(t *testing.T) {
t.Fatalf("Unexpected network type returned by driver")
}
err := d.CreateNetwork("first", nil, nil, nil)
err := d.CreateNetwork("first", nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
@ -23,7 +23,7 @@ func TestDriver(t *testing.T) {
t.Fatalf("Unexpected network id stored")
}
err = d.CreateNetwork("second", nil, nil, nil)
err = d.CreateNetwork("second", nil, nil, nil, nil)
if err == nil {
t.Fatalf("Second network creation should fail on this driver")
}

View File

@ -98,3 +98,6 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{})
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}

View File

@ -14,7 +14,7 @@ import (
)
// CreateNetwork the network for the specified driver type
func (d *driver) CreateNetwork(nid string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
defer osl.InitOSContext()()
kv, err := kernel.GetKernelVersion()
if err != nil {

View File

@ -100,3 +100,6 @@ func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{})
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
return nil
}
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}

View File

@ -14,7 +14,7 @@ import (
)
// CreateNetwork the network for the specified driver type
func (d *driver) CreateNetwork(nid string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
defer osl.InitOSContext()()
kv, err := kernel.GetKernelVersion()
if err != nil {

View File

@ -32,7 +32,10 @@ func (d *driver) NetworkFree(id string) error {
return types.NotImplementedErrorf("not implemented")
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
d.Lock()
defer d.Unlock()

View File

@ -14,7 +14,7 @@ func TestDriver(t *testing.T) {
t.Fatalf("Unexpected network type returned by driver")
}
err := d.CreateNetwork("first", nil, nil, nil)
err := d.CreateNetwork("first", nil, nil, nil, nil)
if err != nil {
t.Fatal(err)
}
@ -23,7 +23,7 @@ func TestDriver(t *testing.T) {
t.Fatalf("Unexpected network id stored")
}
err = d.CreateNetwork("second", nil, nil, nil)
err = d.CreateNetwork("second", nil, nil, nil, nil)
if err == nil {
t.Fatalf("Second network creation should fail on this driver")
}

View File

@ -67,7 +67,10 @@ func (d *driver) NetworkFree(id string) error {
return types.NotImplementedErrorf("not implemented")
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
if id == "" {
return fmt.Errorf("invalid network id")
}

View File

@ -187,10 +187,13 @@ func (n *network) releaseVxlanID() {
}
}
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
return types.NotImplementedErrorf("not implemented")
}
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
func (d *driver) DeleteNetwork(nid string) error {
return types.NotImplementedErrorf("not implemented")
}

View File

@ -91,7 +91,10 @@ func (d *driver) NetworkFree(id string) error {
return types.NotImplementedErrorf("not implemented")
}
func (d *driver) CreateNetwork(id string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
create := &api.CreateNetworkRequest{
NetworkID: id,
Options: options,

View File

@ -199,6 +199,10 @@ func (test *testEndpoint) DisableGatewayService() {
test.disableGatewayService = true
}
func (test *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
return nil
}
func TestGetEmptyCapabilities(t *testing.T) {
var plugin = "test-net-driver-empty-cap"
@ -400,7 +404,7 @@ func TestRemoteDriver(t *testing.T) {
}
netID := "dummy-network"
err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil)
err = d.CreateNetwork(netID, map[string]interface{}{}, nil, nil, nil)
if err != nil {
t.Fatal(err)
}

View File

@ -149,8 +149,11 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
return nil
}
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
// Create a new network
func (d *driver) CreateNetwork(id string, option map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
if _, err := d.getNetwork(id); err == nil {
return types.ForbiddenErrorf("network %s exists", id)
}

View File

@ -25,7 +25,7 @@ func mockDriverInit(reg driverapi.DriverCallback, opt map[string]interface{}) er
return reg.RegisterDriver(mockDriverName, &md, driverapi.Capability{DataScope: datastore.LocalScope})
}
func (m *mockDriver) CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (m *mockDriver) CreateNetwork(nid string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
return nil
}
@ -81,6 +81,9 @@ func (m *mockDriver) NetworkFree(id string) error {
return nil
}
func (m *mockDriver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}
func getNew(t *testing.T) *DrvRegistry {
reg, err := New(nil, nil, nil, nil)
if err != nil {

View File

@ -292,6 +292,10 @@ func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHo
return nil
}
func (ep *endpoint) AddTableEntry(tableName, key string, value []byte) error {
return nil
}
func (ep *endpoint) Sandbox() Sandbox {
cnt, ok := ep.getSandbox()
if !ok {

View File

@ -393,7 +393,7 @@ func badDriverInit(reg driverapi.DriverCallback, opt map[string]interface{}) err
return reg.RegisterDriver(badDriverName, &bd, driverapi.Capability{DataScope: datastore.LocalScope})
}
func (b *badDriver) CreateNetwork(nid string, options map[string]interface{}, ipV4Data, ipV6Data []driverapi.IPAMData) error {
func (b *badDriver) CreateNetwork(nid string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
if b.failNetworkCreation {
return fmt.Errorf("I will not create any network")
}
@ -440,3 +440,6 @@ func (b *badDriver) NetworkAllocate(id string, option map[string]string, ipV4Dat
func (b *badDriver) NetworkFree(id string) error {
return types.NotImplementedErrorf("not implemented")
}
func (b *badDriver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
}