Merge pull request #1742 from aboch/nlo2
ConnectivityScope capability and configuration networks
This commit is contained in:
commit
f32eec401b
27 changed files with 706 additions and 46 deletions
|
@ -222,7 +222,7 @@ func (c *controller) agentSetup(clusterProvider cluster.Provider) error {
|
|||
return err
|
||||
}
|
||||
c.drvRegistry.WalkDrivers(func(name string, driver driverapi.Driver, capability driverapi.Capability) bool {
|
||||
if capability.DataScope == datastore.GlobalScope {
|
||||
if capability.ConnectivityScope == datastore.GlobalScope {
|
||||
c.agentDriverNotify(driver)
|
||||
}
|
||||
return false
|
||||
|
@ -507,7 +507,7 @@ func (n *network) Services() map[string]ServiceInfo {
|
|||
}
|
||||
|
||||
func (n *network) isClusterEligible() bool {
|
||||
if n.driverScope() != datastore.GlobalScope {
|
||||
if n.scope != datastore.SwarmScope || !n.driverIsMultihost() {
|
||||
return false
|
||||
}
|
||||
return n.getController().getAgent() != nil
|
||||
|
|
|
@ -621,7 +621,7 @@ func (c *controller) pushNodeDiscovery(d driverapi.Driver, cap driverapi.Capabil
|
|||
}
|
||||
}
|
||||
|
||||
if d == nil || cap.DataScope != datastore.GlobalScope || nodes == nil {
|
||||
if d == nil || cap.ConnectivityScope != datastore.GlobalScope || nodes == nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -722,22 +722,46 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
|
|||
}
|
||||
|
||||
network.processOptions(options...)
|
||||
if err := network.validateConfiguration(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, cap, err := network.resolveDriver(networkType, true)
|
||||
var (
|
||||
cap *driverapi.Capability
|
||||
err error
|
||||
)
|
||||
|
||||
// Reset network types, force local scope and skip allocation and
|
||||
// plumbing for configuration networks. Reset of the config-only
|
||||
// network drivers is needed so that this special network is not
|
||||
// usable by old engine versions.
|
||||
if network.configOnly {
|
||||
network.scope = datastore.LocalScope
|
||||
network.networkType = "null"
|
||||
network.ipamType = ""
|
||||
goto addToStore
|
||||
}
|
||||
|
||||
_, cap, err = network.resolveDriver(network.networkType, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if network.scope == datastore.LocalScope && cap.DataScope == datastore.GlobalScope {
|
||||
return nil, types.ForbiddenErrorf("cannot downgrade network scope for %s networks", networkType)
|
||||
|
||||
}
|
||||
if network.ingress && cap.DataScope != datastore.GlobalScope {
|
||||
return nil, types.ForbiddenErrorf("Ingress network can only be global scope network")
|
||||
}
|
||||
|
||||
if cap.DataScope == datastore.GlobalScope && !c.isDistributedControl() && !network.dynamic {
|
||||
// At this point the network scope is still unknown if not set by user
|
||||
if (cap.DataScope == datastore.GlobalScope || network.scope == datastore.SwarmScope) &&
|
||||
!c.isDistributedControl() && !network.dynamic {
|
||||
if c.isManager() {
|
||||
// For non-distributed controlled environment, globalscoped non-dynamic networks are redirected to Manager
|
||||
return nil, ManagerRedirectError(name)
|
||||
}
|
||||
|
||||
return nil, types.ForbiddenErrorf("Cannot create a multi-host network from a worker node. Please create the network from a manager node.")
|
||||
}
|
||||
|
||||
|
@ -747,6 +771,26 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// From this point on, we need the network specific configuration,
|
||||
// which may come from a configuration-only network
|
||||
if network.configFrom != "" {
|
||||
t, err := c.getConfigNetwork(network.configFrom)
|
||||
if err != nil {
|
||||
return nil, types.NotFoundErrorf("configuration network %q does not exist", network.configFrom)
|
||||
}
|
||||
if err := t.applyConfigurationTo(network); err != nil {
|
||||
return nil, types.InternalErrorf("Failed to apply configuration: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err == nil {
|
||||
if err := t.getEpCnt().IncEndpointCnt(); err != nil {
|
||||
logrus.Warnf("Failed to update reference count for configuration network %q on creation of network %q: %v",
|
||||
t.Name(), network.Name(), err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
err = network.ipamAllocate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -769,6 +813,7 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
|
|||
}
|
||||
}()
|
||||
|
||||
addToStore:
|
||||
// First store the endpoint count, then the network. To avoid to
|
||||
// end up with a datastore containing a network and not an epCnt,
|
||||
// in case of an ungraceful shutdown during this function call.
|
||||
|
@ -788,6 +833,9 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
|
|||
if err = c.updateToStore(network); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if network.configOnly {
|
||||
return network, nil
|
||||
}
|
||||
|
||||
joinCluster(network)
|
||||
if !c.isDistributedControl() {
|
||||
|
@ -801,6 +849,9 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
|
|||
|
||||
var joinCluster NetworkWalker = func(nw Network) bool {
|
||||
n := nw.(*network)
|
||||
if n.configOnly {
|
||||
return false
|
||||
}
|
||||
if err := n.joinCluster(); err != nil {
|
||||
logrus.Errorf("Failed to join network %s (%s) into agent cluster: %v", n.Name(), n.ID(), err)
|
||||
}
|
||||
|
@ -816,6 +867,9 @@ func (c *controller) reservePools() {
|
|||
}
|
||||
|
||||
for _, n := range networks {
|
||||
if n.configOnly {
|
||||
continue
|
||||
}
|
||||
if !doReplayPoolReserve(n) {
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -115,7 +115,10 @@ const (
|
|||
// LocalScope indicates to store the KV object in local datastore such as boltdb
|
||||
LocalScope = "local"
|
||||
// GlobalScope indicates to store the KV object in global datastore such as consul/etcd/zookeeper
|
||||
GlobalScope = "global"
|
||||
GlobalScope = "global"
|
||||
// SwarmScope is not indicating a datastore location. It is defined here
|
||||
// along with the other two scopes just for consistency.
|
||||
SwarmScope = "swarm"
|
||||
defaultPrefix = "/var/lib/docker/network/files"
|
||||
)
|
||||
|
||||
|
|
|
@ -56,10 +56,12 @@ Other entries in the list value are allowed; `"NetworkDriver"` indicates that th
|
|||
After Handshake, the remote driver will receive another POST message to the URL `/NetworkDriver.GetCapabilities` with no payload. The driver's response should have the form:
|
||||
|
||||
{
|
||||
"Scope": "local"
|
||||
"Scope": "local"
|
||||
"ConnectivityScope": "global"
|
||||
}
|
||||
|
||||
Value of "Scope" should be either "local" or "global" which indicates the capability of remote driver, values beyond these will fail driver's registration and return an error to the caller.
|
||||
Value of "Scope" should be either "local" or "global" which indicates whether the resource allocations for this driver's network can be done only locally to the node or globally across the cluster of nodes. Any other value will fail driver's registration and return an error to the caller.
|
||||
Similarly, value of "ConnectivityScope" should be either "local" or "global" which indicates whether the driver's network can provide connectivity only locally to this node or globally across the cluster of nodes. If the value is missing, libnetwork will set it to the value of "Scope". should be either "local" or "global" which indicates
|
||||
|
||||
### Create network
|
||||
|
||||
|
|
|
@ -161,7 +161,8 @@ type DriverCallback interface {
|
|||
|
||||
// Capability represents the high level capabilities of the drivers which libnetwork can make use of
|
||||
type Capability struct {
|
||||
DataScope string
|
||||
DataScope string
|
||||
ConnectivityScope string
|
||||
}
|
||||
|
||||
// IPAMData represents the per-network ip related
|
||||
|
|
|
@ -153,7 +153,8 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
|||
}
|
||||
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, d, c)
|
||||
}
|
||||
|
|
88
libnetwork/drivers/bridge/brmanager/brmanager.go
Normal file
88
libnetwork/drivers/bridge/brmanager/brmanager.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package brmanager
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const networkType = "bridge"
|
||||
|
||||
type driver struct{}
|
||||
|
||||
// Init registers a new instance of bridge manager driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
||||
func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
|
||||
return nil, types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) NetworkFree(id string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
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) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return nil, types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
func (d *driver) IsBuiltIn() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
|
@ -19,7 +19,8 @@ type driver struct {
|
|||
// Init registers a new instance of host driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
|
|
@ -58,7 +58,8 @@ type network struct {
|
|||
// Init initializes and registers the libnetwork ipvlan driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
d := &driver{
|
||||
networks: networkTable{},
|
||||
|
|
88
libnetwork/drivers/ipvlan/ivmanager/ivmanager.go
Normal file
88
libnetwork/drivers/ipvlan/ivmanager/ivmanager.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package ivmanager
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const networkType = "ipvlan"
|
||||
|
||||
type driver struct{}
|
||||
|
||||
// Init registers a new instance of ipvlan manager driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
||||
func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
|
||||
return nil, types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) NetworkFree(id string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
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) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return nil, types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
func (d *driver) IsBuiltIn() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
|
@ -60,7 +60,8 @@ type network struct {
|
|||
// Init initializes and registers the libnetwork macvlan driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
d := &driver{
|
||||
networks: networkTable{},
|
||||
|
|
88
libnetwork/drivers/macvlan/mvmanager/mvmanager.go
Normal file
88
libnetwork/drivers/macvlan/mvmanager/mvmanager.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package mvmanager
|
||||
|
||||
import (
|
||||
"github.com/docker/libnetwork/datastore"
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/driverapi"
|
||||
"github.com/docker/libnetwork/types"
|
||||
)
|
||||
|
||||
const networkType = "macvlan"
|
||||
|
||||
type driver struct{}
|
||||
|
||||
// Init registers a new instance of macvlan manager driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, &driver{}, c)
|
||||
}
|
||||
|
||||
func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
|
||||
return nil, types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) NetworkFree(id string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
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) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (d *driver) DeleteNetwork(nid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) DeleteEndpoint(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
|
||||
return nil, types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Leave(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) Type() string {
|
||||
return networkType
|
||||
}
|
||||
|
||||
func (d *driver) IsBuiltIn() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
||||
|
||||
func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
|
||||
return types.NotImplementedErrorf("not implemented")
|
||||
}
|
|
@ -56,7 +56,8 @@ type driver struct {
|
|||
// Init registers a new instance of overlay driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.GlobalScope,
|
||||
DataScope: datastore.GlobalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
d := &driver{
|
||||
networks: networkTable{},
|
||||
|
|
|
@ -49,7 +49,8 @@ type network struct {
|
|||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
var err error
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.GlobalScope,
|
||||
DataScope: datastore.GlobalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
|
||||
d := &driver{
|
||||
|
|
|
@ -24,7 +24,8 @@ func (r *Response) GetError() string {
|
|||
// GetCapabilityResponse is the response of GetCapability request
|
||||
type GetCapabilityResponse struct {
|
||||
Response
|
||||
Scope string
|
||||
Scope string
|
||||
ConnectivityScope string
|
||||
}
|
||||
|
||||
// AllocateNetworkRequest requests allocation of new network by manager
|
||||
|
|
|
@ -74,6 +74,17 @@ func (d *driver) getCapabilities() (*driverapi.Capability, error) {
|
|||
return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope)
|
||||
}
|
||||
|
||||
switch capResp.ConnectivityScope {
|
||||
case "global":
|
||||
c.ConnectivityScope = datastore.GlobalScope
|
||||
case "local":
|
||||
c.ConnectivityScope = datastore.LocalScope
|
||||
case "":
|
||||
c.ConnectivityScope = c.DataScope
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope)
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -238,8 +238,9 @@ func TestGetExtraCapabilities(t *testing.T) {
|
|||
|
||||
handle(t, mux, "GetCapabilities", func(msg map[string]interface{}) interface{} {
|
||||
return map[string]interface{}{
|
||||
"Scope": "local",
|
||||
"foo": "bar",
|
||||
"Scope": "local",
|
||||
"foo": "bar",
|
||||
"ConnectivityScope": "global",
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -258,6 +259,8 @@ func TestGetExtraCapabilities(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
} else if c.DataScope != datastore.LocalScope {
|
||||
t.Fatalf("get capability '%s', expecting 'local'", c.DataScope)
|
||||
} else if c.ConnectivityScope != datastore.GlobalScope {
|
||||
t.Fatalf("get capability '%s', expecting %q", c.ConnectivityScope, datastore.GlobalScope)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,8 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
|||
}
|
||||
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.LocalScope,
|
||||
}
|
||||
return dc.RegisterDriver(networkType, d, c)
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ type driver struct {
|
|||
// Init registers a new instance of overlay driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.GlobalScope,
|
||||
DataScope: datastore.GlobalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
d := &driver{
|
||||
networks: networkTable{},
|
||||
|
|
|
@ -49,7 +49,8 @@ type network struct {
|
|||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
var err error
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.GlobalScope,
|
||||
DataScope: datastore.GlobalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
|
||||
d := &driver{
|
||||
|
|
|
@ -36,7 +36,8 @@ type driver struct {
|
|||
// Init registers a new instance of overlay driver
|
||||
func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
|
||||
c := driverapi.Capability{
|
||||
DataScope: datastore.GlobalScope,
|
||||
DataScope: datastore.GlobalScope,
|
||||
ConnectivityScope: datastore.GlobalScope,
|
||||
}
|
||||
|
||||
d := &driver{
|
||||
|
|
|
@ -104,7 +104,8 @@ func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[st
|
|||
}
|
||||
|
||||
return dc.RegisterDriver(networkType, newDriver(networkType), driverapi.Capability{
|
||||
DataScope: datastore.LocalScope,
|
||||
DataScope: datastore.LocalScope,
|
||||
ConnectivityScope: datastore.LocalScope,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1152,6 +1152,9 @@ func (c *controller) cleanupLocalEndpoints() {
|
|||
}
|
||||
|
||||
for _, n := range nl {
|
||||
if n.ConfigOnly() {
|
||||
continue
|
||||
}
|
||||
epl, err := n.getEndpointsFromStore()
|
||||
if err != nil {
|
||||
logrus.Warnf("Could not get list of endpoints in network %s during endpoint cleanup: %v", n.name, err)
|
||||
|
|
|
@ -25,6 +25,8 @@ func TestNetworkMarshalling(t *testing.T) {
|
|||
networkType: "bridge",
|
||||
enableIPv6: true,
|
||||
persist: true,
|
||||
configOnly: true,
|
||||
configFrom: "configOnlyX",
|
||||
ipamOptions: map[string]string{
|
||||
netlabel.MacAddress: "a:b:c:d:e:f",
|
||||
"primary": "",
|
||||
|
@ -136,7 +138,8 @@ func TestNetworkMarshalling(t *testing.T) {
|
|||
!compareIpamInfoList(n.ipamV6Info, nn.ipamV6Info) ||
|
||||
!compareStringMaps(n.ipamOptions, nn.ipamOptions) ||
|
||||
!compareStringMaps(n.labels, nn.labels) ||
|
||||
!n.created.Equal(nn.created) {
|
||||
!n.created.Equal(nn.created) ||
|
||||
n.configOnly != nn.configOnly || n.configFrom != nn.configFrom {
|
||||
t.Fatalf("JSON marsh/unmarsh failed."+
|
||||
"\nOriginal:\n%#v\nDecoded:\n%#v"+
|
||||
"\nOriginal ipamV4Conf: %#v\n\nDecoded ipamV4Conf: %#v"+
|
||||
|
|
|
@ -359,6 +359,109 @@ func TestDeleteNetworkWithActiveEndpoints(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNetworkConfig(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
}
|
||||
|
||||
// Verify config network cannot inherit another config network
|
||||
configNetwork, err := controller.NewNetwork("bridge", "config_network0", "",
|
||||
libnetwork.NetworkOptionConfigOnly(),
|
||||
libnetwork.NetworkOptionConfigFrom("anotherConfigNw"))
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail. But instead succeeded")
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||
}
|
||||
|
||||
// Create supported config network
|
||||
netOption := options.Generic{
|
||||
"EnableICC": false,
|
||||
}
|
||||
option := options.Generic{
|
||||
netlabel.GenericData: netOption,
|
||||
}
|
||||
ipamV4ConfList := []*libnetwork.IpamConf{{PreferredPool: "192.168.100.0/24", SubPool: "192.168.100.128/25", Gateway: "192.168.100.1"}}
|
||||
ipamV6ConfList := []*libnetwork.IpamConf{{PreferredPool: "2001:db8:abcd::/64", SubPool: "2001:db8:abcd::ef99/80", Gateway: "2001:db8:abcd::22"}}
|
||||
|
||||
netOptions := []libnetwork.NetworkOption{
|
||||
libnetwork.NetworkOptionConfigOnly(),
|
||||
libnetwork.NetworkOptionEnableIPv6(true),
|
||||
libnetwork.NetworkOptionGeneric(option),
|
||||
libnetwork.NetworkOptionIpam("default", "", ipamV4ConfList, ipamV6ConfList, nil),
|
||||
}
|
||||
|
||||
configNetwork, err = controller.NewNetwork(bridgeNetType, "config_network0", "", netOptions...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify a config-only network cannot be created with network operator configurations
|
||||
for i, opt := range []libnetwork.NetworkOption{
|
||||
libnetwork.NetworkOptionInternalNetwork(),
|
||||
libnetwork.NetworkOptionAttachable(true),
|
||||
libnetwork.NetworkOptionIngress(true),
|
||||
} {
|
||||
_, err = controller.NewNetwork(bridgeNetType, "testBR", "",
|
||||
libnetwork.NetworkOptionConfigOnly(), opt)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected to fail. But instead succeeded for option: %d", i)
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify a network cannot be created with both config-from and network specific configurations
|
||||
for i, opt := range []libnetwork.NetworkOption{
|
||||
libnetwork.NetworkOptionEnableIPv6(true),
|
||||
libnetwork.NetworkOptionIpam("my-ipam", "", nil, nil, nil),
|
||||
libnetwork.NetworkOptionIpam("", "", ipamV4ConfList, nil, nil),
|
||||
libnetwork.NetworkOptionIpam("", "", nil, ipamV6ConfList, nil),
|
||||
libnetwork.NetworkOptionLabels(map[string]string{"number": "two"}),
|
||||
libnetwork.NetworkOptionDriverOpts(map[string]string{"com.docker.network.mtu": "1600"}),
|
||||
} {
|
||||
_, err = controller.NewNetwork(bridgeNetType, "testBR", "",
|
||||
libnetwork.NetworkOptionConfigFrom("config_network0"), opt)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected to fail. But instead succeeded for option: %d", i)
|
||||
}
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create a valid network
|
||||
network, err := controller.NewNetwork(bridgeNetType, "testBR", "",
|
||||
libnetwork.NetworkOptionConfigFrom("config_network0"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify the config network cannot be removed
|
||||
err = configNetwork.Delete()
|
||||
if err == nil {
|
||||
t.Fatal("Expected to fail. But instead succeeded")
|
||||
}
|
||||
|
||||
if _, ok := err.(types.ForbiddenError); !ok {
|
||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||
}
|
||||
|
||||
// Delete network
|
||||
if err := network.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Verify the config network can now be removed
|
||||
if err := configNetwork.Delete(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestUnknownNetwork(t *testing.T) {
|
||||
if !testutils.IsRunningInContainer() {
|
||||
defer testutils.SetupTestOSContext(t)()
|
||||
|
|
|
@ -67,6 +67,8 @@ type NetworkInfo interface {
|
|||
Internal() bool
|
||||
Attachable() bool
|
||||
Ingress() bool
|
||||
ConfigFrom() string
|
||||
ConfigOnly() bool
|
||||
Labels() map[string]string
|
||||
Dynamic() bool
|
||||
Created() time.Time
|
||||
|
@ -193,7 +195,7 @@ type network struct {
|
|||
networkType string
|
||||
id string
|
||||
created time.Time
|
||||
scope string
|
||||
scope string // network data scope
|
||||
labels map[string]string
|
||||
ipamType string
|
||||
ipamOptions map[string]string
|
||||
|
@ -219,6 +221,8 @@ type network struct {
|
|||
ingress bool
|
||||
driverTables []networkDBTable
|
||||
dynamic bool
|
||||
configOnly bool
|
||||
configFrom string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -348,6 +352,95 @@ func (i *IpamInfo) CopyTo(dstI *IpamInfo) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (n *network) validateConfiguration() error {
|
||||
if n.configOnly {
|
||||
// Only supports network specific configurations.
|
||||
// Network operator configurations are not supported.
|
||||
if n.ingress || n.internal || n.attachable {
|
||||
return types.ForbiddenErrorf("configuration network can only contain network " +
|
||||
"specific fields. Network operator fields like " +
|
||||
"[ ingress | internal | attachable ] are not supported.")
|
||||
}
|
||||
}
|
||||
if n.configFrom != "" {
|
||||
if n.configOnly {
|
||||
return types.ForbiddenErrorf("a configuration network cannot depend on another configuration network")
|
||||
}
|
||||
if n.ipamType != "" &&
|
||||
n.ipamType != defaultIpamForNetworkType(n.networkType) ||
|
||||
n.enableIPv6 ||
|
||||
len(n.labels) > 0 || len(n.ipamOptions) > 0 ||
|
||||
len(n.ipamV4Config) > 0 || len(n.ipamV6Config) > 0 {
|
||||
return types.ForbiddenErrorf("user specified configurations are not supported if the network depends on a configuration network")
|
||||
}
|
||||
if len(n.generic) > 0 {
|
||||
if data, ok := n.generic[netlabel.GenericData]; ok {
|
||||
var (
|
||||
driverOptions map[string]string
|
||||
opts interface{}
|
||||
)
|
||||
switch data.(type) {
|
||||
case map[string]interface{}:
|
||||
opts = data.(map[string]interface{})
|
||||
case map[string]string:
|
||||
opts = data.(map[string]string)
|
||||
}
|
||||
ba, err := json.Marshal(opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to validate network configuration: %v", err)
|
||||
}
|
||||
if err := json.Unmarshal(ba, &driverOptions); err != nil {
|
||||
return fmt.Errorf("failed to validate network configuration: %v", err)
|
||||
}
|
||||
if len(driverOptions) > 0 {
|
||||
return types.ForbiddenErrorf("network driver options are not supported if the network depends on a configuration network")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Applies network specific configurations
|
||||
func (n *network) applyConfigurationTo(to *network) error {
|
||||
to.enableIPv6 = n.enableIPv6
|
||||
if len(n.labels) > 0 {
|
||||
to.labels = make(map[string]string, len(n.labels))
|
||||
for k, v := range n.labels {
|
||||
if _, ok := to.labels[k]; !ok {
|
||||
to.labels[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(n.ipamOptions) > 0 {
|
||||
to.ipamOptions = make(map[string]string, len(n.ipamOptions))
|
||||
for k, v := range n.ipamOptions {
|
||||
if _, ok := to.ipamOptions[k]; !ok {
|
||||
to.ipamOptions[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(n.ipamV4Config) > 0 {
|
||||
to.ipamV4Config = make([]*IpamConf, 0, len(n.ipamV4Config))
|
||||
for _, v4conf := range n.ipamV4Config {
|
||||
to.ipamV4Config = append(to.ipamV4Config, v4conf)
|
||||
}
|
||||
}
|
||||
if len(n.ipamV6Config) > 0 {
|
||||
to.ipamV6Config = make([]*IpamConf, 0, len(n.ipamV6Config))
|
||||
for _, v6conf := range n.ipamV6Config {
|
||||
to.ipamV6Config = append(to.ipamV6Config, v6conf)
|
||||
}
|
||||
}
|
||||
if len(n.generic) > 0 {
|
||||
to.generic = options.Generic{}
|
||||
for k, v := range n.generic {
|
||||
to.generic[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *network) CopyTo(o datastore.KVObject) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
@ -370,6 +463,8 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
|||
dstN.attachable = n.attachable
|
||||
dstN.inDelete = n.inDelete
|
||||
dstN.ingress = n.ingress
|
||||
dstN.configOnly = n.configOnly
|
||||
dstN.configFrom = n.configFrom
|
||||
|
||||
// copy labels
|
||||
if dstN.labels == nil {
|
||||
|
@ -419,7 +514,12 @@ func (n *network) CopyTo(o datastore.KVObject) error {
|
|||
}
|
||||
|
||||
func (n *network) DataScope() string {
|
||||
return n.Scope()
|
||||
s := n.Scope()
|
||||
// All swarm scope networks have local datascope
|
||||
if s == datastore.SwarmScope {
|
||||
s = datastore.LocalScope
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (n *network) getEpCnt() *endpointCnt {
|
||||
|
@ -479,6 +579,8 @@ func (n *network) MarshalJSON() ([]byte, error) {
|
|||
netMap["attachable"] = n.attachable
|
||||
netMap["inDelete"] = n.inDelete
|
||||
netMap["ingress"] = n.ingress
|
||||
netMap["configOnly"] = n.configOnly
|
||||
netMap["configFrom"] = n.configFrom
|
||||
return json.Marshal(netMap)
|
||||
}
|
||||
|
||||
|
@ -583,6 +685,12 @@ func (n *network) UnmarshalJSON(b []byte) (err error) {
|
|||
if v, ok := netMap["ingress"]; ok {
|
||||
n.ingress = v.(bool)
|
||||
}
|
||||
if v, ok := netMap["configOnly"]; ok {
|
||||
n.configOnly = v.(bool)
|
||||
}
|
||||
if v, ok := netMap["configFrom"]; ok {
|
||||
n.configFrom = v.(string)
|
||||
}
|
||||
// Reconcile old networks with the recently added `--ipv6` flag
|
||||
if !n.enableIPv6 {
|
||||
n.enableIPv6 = len(n.ipamV6Info) > 0
|
||||
|
@ -659,6 +767,14 @@ func NetworkOptionAttachable(attachable bool) NetworkOption {
|
|||
}
|
||||
}
|
||||
|
||||
// NetworkOptionScope returns an option setter to overwrite the network's scope.
|
||||
// By default the network's scope is set to the network driver's datascope.
|
||||
func NetworkOptionScope(scope string) NetworkOption {
|
||||
return func(n *network) {
|
||||
n.scope = scope
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkOptionIpam function returns an option setter for the ipam configuration for this network
|
||||
func NetworkOptionIpam(ipamDriver string, addrSpace string, ipV4 []*IpamConf, ipV6 []*IpamConf, opts map[string]string) NetworkOption {
|
||||
return func(n *network) {
|
||||
|
@ -713,6 +829,23 @@ func NetworkOptionDeferIPv6Alloc(enable bool) NetworkOption {
|
|||
}
|
||||
}
|
||||
|
||||
// NetworkOptionConfigOnly tells controller this network is
|
||||
// a configuration only network. It serves as a configuration
|
||||
// for other networks.
|
||||
func NetworkOptionConfigOnly() NetworkOption {
|
||||
return func(n *network) {
|
||||
n.configOnly = true
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkOptionConfigFrom tells controller to pick the
|
||||
// network configuration from a configuration only network
|
||||
func NetworkOptionConfigFrom(name string) NetworkOption {
|
||||
return func(n *network) {
|
||||
n.configFrom = name
|
||||
}
|
||||
}
|
||||
|
||||
func (n *network) processOptions(options ...NetworkOption) {
|
||||
for _, opt := range options {
|
||||
if opt != nil {
|
||||
|
@ -757,6 +890,14 @@ func (n *network) driverScope() string {
|
|||
return cap.DataScope
|
||||
}
|
||||
|
||||
func (n *network) driverIsMultihost() bool {
|
||||
_, cap, err := n.resolveDriver(n.networkType, true)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return cap.ConnectivityScope == datastore.GlobalScope
|
||||
}
|
||||
|
||||
func (n *network) driver(load bool) (driverapi.Driver, error) {
|
||||
d, cap, err := n.resolveDriver(n.networkType, load)
|
||||
if err != nil {
|
||||
|
@ -767,14 +908,14 @@ func (n *network) driver(load bool) (driverapi.Driver, error) {
|
|||
isAgent := c.isAgent()
|
||||
n.Lock()
|
||||
// If load is not required, driver, cap and err may all be nil
|
||||
if cap != nil {
|
||||
if n.scope == "" && cap != nil {
|
||||
n.scope = cap.DataScope
|
||||
}
|
||||
if isAgent || n.dynamic {
|
||||
// If we are running in agent mode then all networks
|
||||
// in libnetwork are local scope regardless of the
|
||||
// backing driver.
|
||||
n.scope = datastore.LocalScope
|
||||
if isAgent && n.dynamic {
|
||||
// If we are running in agent mode and the network
|
||||
// is dynamic, then the networks are swarm scoped
|
||||
// regardless of the backing driver.
|
||||
n.scope = datastore.SwarmScope
|
||||
}
|
||||
n.Unlock()
|
||||
return d, nil
|
||||
|
@ -797,6 +938,9 @@ func (n *network) delete(force bool) error {
|
|||
}
|
||||
|
||||
if !force && n.getEpCnt().EndpointCnt() != 0 {
|
||||
if n.configOnly {
|
||||
return types.ForbiddenErrorf("configuration network %q is in use", n.Name())
|
||||
}
|
||||
return &ActiveEndpointsError{name: n.name, id: n.id}
|
||||
}
|
||||
|
||||
|
@ -806,6 +950,21 @@ func (n *network) delete(force bool) error {
|
|||
return fmt.Errorf("error marking network %s (%s) for deletion: %v", n.Name(), n.ID(), err)
|
||||
}
|
||||
|
||||
if n.ConfigFrom() != "" {
|
||||
if t, err := c.getConfigNetwork(n.ConfigFrom()); err == nil {
|
||||
if err := t.getEpCnt().DecEndpointCnt(); err != nil {
|
||||
logrus.Warnf("Failed to update reference count for configuration network %q on removal of network %q: %v",
|
||||
t.Name(), n.Name(), err)
|
||||
}
|
||||
} else {
|
||||
logrus.Warnf("Could not find configuration network %q during removal of network %q", n.configOnly, n.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if n.configOnly {
|
||||
goto removeFromStore
|
||||
}
|
||||
|
||||
if err = n.deleteNetwork(); err != nil {
|
||||
if !force {
|
||||
return err
|
||||
|
@ -831,6 +990,7 @@ func (n *network) delete(force bool) error {
|
|||
|
||||
c.cleanupServiceBindings(n.ID())
|
||||
|
||||
removeFromStore:
|
||||
// deleteFromStore performs an atomic delete operation and the
|
||||
// network.epCnt will help prevent any possible
|
||||
// race between endpoint join and network delete
|
||||
|
@ -892,6 +1052,10 @@ func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoi
|
|||
return nil, ErrInvalidName(name)
|
||||
}
|
||||
|
||||
if n.ConfigOnly() {
|
||||
return nil, types.ForbiddenErrorf("cannot create endpoint on configuration-only network")
|
||||
}
|
||||
|
||||
if _, err = n.EndpointByName(name); err == nil {
|
||||
return nil, types.ForbiddenErrorf("endpoint with name %s already exists in network %s", name, n.Name())
|
||||
}
|
||||
|
@ -1611,6 +1775,20 @@ func (n *network) IPv6Enabled() bool {
|
|||
return n.enableIPv6
|
||||
}
|
||||
|
||||
func (n *network) ConfigFrom() string {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.configFrom
|
||||
}
|
||||
|
||||
func (n *network) ConfigOnly() bool {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
return n.configOnly
|
||||
}
|
||||
|
||||
func (n *network) Labels() map[string]string {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
@ -1778,3 +1956,24 @@ func (n *network) ExecFunc(f func()) error {
|
|||
func (n *network) NdotsSet() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// config-only network is looked up by name
|
||||
func (c *controller) getConfigNetwork(name string) (*network, error) {
|
||||
var n Network
|
||||
|
||||
s := func(current Network) bool {
|
||||
if current.Info().ConfigOnly() && current.Name() == name {
|
||||
n = current
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
c.WalkNetworks(s)
|
||||
|
||||
if n == nil {
|
||||
return nil, types.NotFoundErrorf("configuration network %q not found", name)
|
||||
}
|
||||
|
||||
return n.(*network), nil
|
||||
}
|
||||
|
|
|
@ -350,17 +350,18 @@ func (c *controller) networkWatchLoop(nw *netWatch, ep *endpoint, ecCh <-chan da
|
|||
}
|
||||
|
||||
func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoint) {
|
||||
if !c.isDistributedControl() && ep.getNetwork().driverScope() == datastore.GlobalScope {
|
||||
n := ep.getNetwork()
|
||||
if !c.isDistributedControl() && n.Scope() == datastore.SwarmScope && n.driverIsMultihost() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
nw, ok := nmap[ep.getNetwork().ID()]
|
||||
nw, ok := nmap[n.ID()]
|
||||
c.Unlock()
|
||||
|
||||
if ok {
|
||||
// Update the svc db for the local endpoint join right away
|
||||
ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)
|
||||
n.updateSvcRecord(ep, c.getLocalEps(nw), true)
|
||||
|
||||
c.Lock()
|
||||
nw.localEps[ep.ID()] = ep
|
||||
|
@ -381,15 +382,15 @@ func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoi
|
|||
// Update the svc db for the local endpoint join right away
|
||||
// Do this before adding this ep to localEps so that we don't
|
||||
// try to update this ep's container's svc records
|
||||
ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), true)
|
||||
n.updateSvcRecord(ep, c.getLocalEps(nw), true)
|
||||
|
||||
c.Lock()
|
||||
nw.localEps[ep.ID()] = ep
|
||||
nmap[ep.getNetwork().ID()] = nw
|
||||
nmap[n.ID()] = nw
|
||||
nw.stopCh = make(chan struct{})
|
||||
c.Unlock()
|
||||
|
||||
store := c.getStore(ep.getNetwork().DataScope())
|
||||
store := c.getStore(n.DataScope())
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
|
@ -398,7 +399,7 @@ func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoi
|
|||
return
|
||||
}
|
||||
|
||||
ch, err := store.Watch(ep.getNetwork().getEpCnt(), nw.stopCh)
|
||||
ch, err := store.Watch(n.getEpCnt(), nw.stopCh)
|
||||
if err != nil {
|
||||
logrus.Warnf("Error creating watch for network: %v", err)
|
||||
return
|
||||
|
@ -408,12 +409,13 @@ func (c *controller) processEndpointCreate(nmap map[string]*netWatch, ep *endpoi
|
|||
}
|
||||
|
||||
func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoint) {
|
||||
if !c.isDistributedControl() && ep.getNetwork().driverScope() == datastore.GlobalScope {
|
||||
n := ep.getNetwork()
|
||||
if !c.isDistributedControl() && n.Scope() == datastore.SwarmScope && n.driverIsMultihost() {
|
||||
return
|
||||
}
|
||||
|
||||
c.Lock()
|
||||
nw, ok := nmap[ep.getNetwork().ID()]
|
||||
nw, ok := nmap[n.ID()]
|
||||
|
||||
if ok {
|
||||
delete(nw.localEps, ep.ID())
|
||||
|
@ -422,7 +424,7 @@ func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoi
|
|||
// Update the svc db about local endpoint leave right away
|
||||
// Do this after we remove this ep from localEps so that we
|
||||
// don't try to remove this svc record from this ep's container.
|
||||
ep.getNetwork().updateSvcRecord(ep, c.getLocalEps(nw), false)
|
||||
n.updateSvcRecord(ep, c.getLocalEps(nw), false)
|
||||
|
||||
c.Lock()
|
||||
if len(nw.localEps) == 0 {
|
||||
|
@ -430,9 +432,9 @@ func (c *controller) processEndpointDelete(nmap map[string]*netWatch, ep *endpoi
|
|||
|
||||
// This is the last container going away for the network. Destroy
|
||||
// this network's svc db entry
|
||||
delete(c.svcRecords, ep.getNetwork().ID())
|
||||
delete(c.svcRecords, n.ID())
|
||||
|
||||
delete(nmap, ep.getNetwork().ID())
|
||||
delete(nmap, n.ID())
|
||||
}
|
||||
}
|
||||
c.Unlock()
|
||||
|
@ -478,7 +480,7 @@ func (c *controller) networkCleanup() {
|
|||
}
|
||||
|
||||
var populateSpecial NetworkWalker = func(nw Network) bool {
|
||||
if n := nw.(*network); n.hasSpecialDriver() {
|
||||
if n := nw.(*network); n.hasSpecialDriver() && !n.ConfigOnly() {
|
||||
if err := n.getController().addNetwork(n); err != nil {
|
||||
logrus.Warnf("Failed to populate network %q with driver %q", nw.Name(), nw.Type())
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue