Browse code

Integrate local datascope network with swarm

Signed-off-by: Alessandro Boch <aboch@docker.com>

Alessandro Boch authored on 2017/05/02 08:44:04
Showing 6 changed files
... ...
@@ -1,5 +1,9 @@
1 1
 package swarm
2 2
 
3
+import (
4
+	"github.com/docker/docker/api/types/network"
5
+)
6
+
3 7
 // Endpoint represents an endpoint.
4 8
 type Endpoint struct {
5 9
 	Spec       EndpointSpec        `json:",omitempty"`
... ...
@@ -78,12 +82,14 @@ type Network struct {
78 78
 // NetworkSpec represents the spec of a network.
79 79
 type NetworkSpec struct {
80 80
 	Annotations
81
-	DriverConfiguration *Driver      `json:",omitempty"`
82
-	IPv6Enabled         bool         `json:",omitempty"`
83
-	Internal            bool         `json:",omitempty"`
84
-	Attachable          bool         `json:",omitempty"`
85
-	Ingress             bool         `json:",omitempty"`
86
-	IPAMOptions         *IPAMOptions `json:",omitempty"`
81
+	DriverConfiguration *Driver                  `json:",omitempty"`
82
+	IPv6Enabled         bool                     `json:",omitempty"`
83
+	Internal            bool                     `json:",omitempty"`
84
+	Attachable          bool                     `json:",omitempty"`
85
+	Ingress             bool                     `json:",omitempty"`
86
+	IPAMOptions         *IPAMOptions             `json:",omitempty"`
87
+	ConfigFrom          *network.ConfigReference `json:",omitempty"`
88
+	Scope               string                   `json:",omitempty"`
87 89
 }
88 90
 
89 91
 // NetworkAttachmentConfig represents the configuration of a network attachment.
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	basictypes "github.com/docker/docker/api/types"
7 7
 	networktypes "github.com/docker/docker/api/types/network"
8 8
 	types "github.com/docker/docker/api/types/swarm"
9
+	netconst "github.com/docker/libnetwork/datastore"
9 10
 	swarmapi "github.com/docker/swarmkit/api"
10 11
 	gogotypes "github.com/gogo/protobuf/types"
11 12
 )
... ...
@@ -30,10 +31,17 @@ func networkFromGRPC(n *swarmapi.Network) types.Network {
30 30
 				Attachable:  n.Spec.Attachable,
31 31
 				Ingress:     n.Spec.Ingress,
32 32
 				IPAMOptions: ipamFromGRPC(n.Spec.IPAM),
33
+				Scope:       netconst.SwarmScope,
33 34
 			},
34 35
 			IPAMOptions: ipamFromGRPC(n.IPAM),
35 36
 		}
36 37
 
38
+		if n.Spec.ConfigFrom != "" {
39
+			network.Spec.ConfigFrom = &networktypes.ConfigReference{
40
+				Network: n.Spec.ConfigFrom,
41
+			}
42
+		}
43
+
37 44
 		// Meta
38 45
 		network.Version.Index = n.Meta.Version.Index
39 46
 		network.CreatedAt, _ = gogotypes.TimestampFromProto(n.Meta.CreatedAt)
... ...
@@ -152,7 +160,7 @@ func BasicNetworkFromGRPC(n swarmapi.Network) basictypes.NetworkResource {
152 152
 	nr := basictypes.NetworkResource{
153 153
 		ID:         n.ID,
154 154
 		Name:       n.Spec.Annotations.Name,
155
-		Scope:      "swarm",
155
+		Scope:      netconst.SwarmScope,
156 156
 		EnableIPv6: spec.Ipv6Enabled,
157 157
 		IPAM:       ipam,
158 158
 		Internal:   spec.Internal,
... ...
@@ -161,6 +169,12 @@ func BasicNetworkFromGRPC(n swarmapi.Network) basictypes.NetworkResource {
161 161
 		Labels:     n.Spec.Annotations.Labels,
162 162
 	}
163 163
 
164
+	if n.Spec.ConfigFrom != "" {
165
+		nr.ConfigFrom = networktypes.ConfigReference{
166
+			Network: n.Spec.ConfigFrom,
167
+		}
168
+	}
169
+
164 170
 	if n.DriverState != nil {
165 171
 		nr.Driver = n.DriverState.Name
166 172
 		nr.Options = n.DriverState.Options
... ...
@@ -206,5 +220,8 @@ func BasicNetworkCreateToGRPC(create basictypes.NetworkCreateRequest) swarmapi.N
206 206
 		}
207 207
 		ns.IPAM.Configs = ipamSpec
208 208
 	}
209
+	if create.ConfigFrom != nil {
210
+		ns.ConfigFrom = create.ConfigFrom.Network
211
+	}
209 212
 	return ns
210 213
 }
... ...
@@ -176,7 +176,7 @@ func (c *containerAdapter) removeNetworks(ctx context.Context) error {
176 176
 }
177 177
 
178 178
 func (c *containerAdapter) networkAttach(ctx context.Context) error {
179
-	config := c.container.createNetworkingConfig()
179
+	config := c.container.createNetworkingConfig(c.backend)
180 180
 
181 181
 	var (
182 182
 		networkName string
... ...
@@ -195,7 +195,7 @@ func (c *containerAdapter) networkAttach(ctx context.Context) error {
195 195
 }
196 196
 
197 197
 func (c *containerAdapter) waitForDetach(ctx context.Context) error {
198
-	config := c.container.createNetworkingConfig()
198
+	config := c.container.createNetworkingConfig(c.backend)
199 199
 
200 200
 	var (
201 201
 		networkName string
... ...
@@ -216,20 +216,19 @@ func (c *containerAdapter) waitForDetach(ctx context.Context) error {
216 216
 func (c *containerAdapter) create(ctx context.Context) error {
217 217
 	var cr containertypes.ContainerCreateCreatedBody
218 218
 	var err error
219
-
220 219
 	if cr, err = c.backend.CreateManagedContainer(types.ContainerCreateConfig{
221 220
 		Name:       c.container.name(),
222 221
 		Config:     c.container.config(),
223 222
 		HostConfig: c.container.hostConfig(),
224 223
 		// Use the first network in container create
225
-		NetworkingConfig: c.container.createNetworkingConfig(),
224
+		NetworkingConfig: c.container.createNetworkingConfig(c.backend),
226 225
 	}); err != nil {
227 226
 		return err
228 227
 	}
229 228
 
230 229
 	// Docker daemon currently doesn't support multiple networks in container create
231 230
 	// Connect to all other networks
232
-	nc := c.container.connectNetworkingConfig()
231
+	nc := c.container.connectNetworkingConfig(c.backend)
233 232
 
234 233
 	if nc != nil {
235 234
 		for n, ep := range nc.EndpointsConfig {
... ...
@@ -18,8 +18,10 @@ import (
18 18
 	enginemount "github.com/docker/docker/api/types/mount"
19 19
 	"github.com/docker/docker/api/types/network"
20 20
 	volumetypes "github.com/docker/docker/api/types/volume"
21
+	executorpkg "github.com/docker/docker/daemon/cluster/executor"
21 22
 	clustertypes "github.com/docker/docker/daemon/cluster/provider"
22 23
 	"github.com/docker/go-connections/nat"
24
+	netconst "github.com/docker/libnetwork/datastore"
23 25
 	"github.com/docker/swarmkit/agent/exec"
24 26
 	"github.com/docker/swarmkit/api"
25 27
 	"github.com/docker/swarmkit/template"
... ...
@@ -374,6 +376,14 @@ func (c *containerConfig) hostConfig() *enginecontainer.HostConfig {
374 374
 		}
375 375
 	}
376 376
 
377
+	if len(c.task.Networks) > 0 {
378
+		labels := c.task.Networks[0].Network.Spec.Annotations.Labels
379
+		name := c.task.Networks[0].Network.Spec.Annotations.Name
380
+		if v, ok := labels["com.docker.swarm.predefined"]; ok && v == "true" {
381
+			hc.NetworkMode = enginecontainer.NetworkMode(name)
382
+		}
383
+	}
384
+
377 385
 	return hc
378 386
 }
379 387
 
... ...
@@ -428,7 +438,7 @@ func (c *containerConfig) resources() enginecontainer.Resources {
428 428
 }
429 429
 
430 430
 // Docker daemon supports just 1 network during container create.
431
-func (c *containerConfig) createNetworkingConfig() *network.NetworkingConfig {
431
+func (c *containerConfig) createNetworkingConfig(b executorpkg.Backend) *network.NetworkingConfig {
432 432
 	var networks []*api.NetworkAttachment
433 433
 	if c.task.Spec.GetContainer() != nil || c.task.Spec.GetAttachment() != nil {
434 434
 		networks = c.task.Networks
... ...
@@ -436,19 +446,18 @@ func (c *containerConfig) createNetworkingConfig() *network.NetworkingConfig {
436 436
 
437 437
 	epConfig := make(map[string]*network.EndpointSettings)
438 438
 	if len(networks) > 0 {
439
-		epConfig[networks[0].Network.Spec.Annotations.Name] = getEndpointConfig(networks[0])
439
+		epConfig[networks[0].Network.Spec.Annotations.Name] = getEndpointConfig(networks[0], b)
440 440
 	}
441 441
 
442 442
 	return &network.NetworkingConfig{EndpointsConfig: epConfig}
443 443
 }
444 444
 
445 445
 // TODO: Merge this function with createNetworkingConfig after daemon supports multiple networks in container create
446
-func (c *containerConfig) connectNetworkingConfig() *network.NetworkingConfig {
446
+func (c *containerConfig) connectNetworkingConfig(b executorpkg.Backend) *network.NetworkingConfig {
447 447
 	var networks []*api.NetworkAttachment
448 448
 	if c.task.Spec.GetContainer() != nil {
449 449
 		networks = c.task.Networks
450 450
 	}
451
-
452 451
 	// First network is used during container create. Other networks are used in "docker network connect"
453 452
 	if len(networks) < 2 {
454 453
 		return nil
... ...
@@ -456,12 +465,12 @@ func (c *containerConfig) connectNetworkingConfig() *network.NetworkingConfig {
456 456
 
457 457
 	epConfig := make(map[string]*network.EndpointSettings)
458 458
 	for _, na := range networks[1:] {
459
-		epConfig[na.Network.Spec.Annotations.Name] = getEndpointConfig(na)
459
+		epConfig[na.Network.Spec.Annotations.Name] = getEndpointConfig(na, b)
460 460
 	}
461 461
 	return &network.NetworkingConfig{EndpointsConfig: epConfig}
462 462
 }
463 463
 
464
-func getEndpointConfig(na *api.NetworkAttachment) *network.EndpointSettings {
464
+func getEndpointConfig(na *api.NetworkAttachment, b executorpkg.Backend) *network.EndpointSettings {
465 465
 	var ipv4, ipv6 string
466 466
 	for _, addr := range na.Addresses {
467 467
 		ip, _, err := net.ParseCIDR(addr)
... ...
@@ -479,13 +488,19 @@ func getEndpointConfig(na *api.NetworkAttachment) *network.EndpointSettings {
479 479
 		}
480 480
 	}
481 481
 
482
-	return &network.EndpointSettings{
482
+	n := &network.EndpointSettings{
483 483
 		NetworkID: na.Network.ID,
484 484
 		IPAMConfig: &network.EndpointIPAMConfig{
485 485
 			IPv4Address: ipv4,
486 486
 			IPv6Address: ipv6,
487 487
 		},
488 488
 	}
489
+	if v, ok := na.Network.Spec.Annotations.Labels["com.docker.swarm.predefined"]; ok && v == "true" {
490
+		if ln, err := b.FindNetwork(na.Network.Spec.Annotations.Name); err == nil {
491
+			n.NetworkID = ln.ID()
492
+		}
493
+	}
494
+	return n
489 495
 }
490 496
 
491 497
 func (c *containerConfig) virtualIP(networkID string) string {
... ...
@@ -570,27 +585,38 @@ func (c *containerConfig) networkCreateRequest(name string) (clustertypes.Networ
570 570
 
571 571
 	options := types.NetworkCreate{
572 572
 		// ID:     na.Network.ID,
573
-		Driver: na.Network.DriverState.Name,
574
-		IPAM: &network.IPAM{
575
-			Driver:  na.Network.IPAM.Driver.Name,
576
-			Options: na.Network.IPAM.Driver.Options,
577
-		},
578
-		Options:        na.Network.DriverState.Options,
579 573
 		Labels:         na.Network.Spec.Annotations.Labels,
580 574
 		Internal:       na.Network.Spec.Internal,
581 575
 		Attachable:     na.Network.Spec.Attachable,
582 576
 		Ingress:        na.Network.Spec.Ingress,
583 577
 		EnableIPv6:     na.Network.Spec.Ipv6Enabled,
584 578
 		CheckDuplicate: true,
579
+		Scope:          netconst.SwarmScope,
585 580
 	}
586 581
 
587
-	for _, ic := range na.Network.IPAM.Configs {
588
-		c := network.IPAMConfig{
589
-			Subnet:  ic.Subnet,
590
-			IPRange: ic.Range,
591
-			Gateway: ic.Gateway,
582
+	if na.Network.Spec.ConfigFrom != "" {
583
+		options.ConfigFrom = &network.ConfigReference{
584
+			Network: na.Network.Spec.ConfigFrom,
585
+		}
586
+	}
587
+
588
+	if na.Network.DriverState != nil {
589
+		options.Driver = na.Network.DriverState.Name
590
+		options.Options = na.Network.DriverState.Options
591
+	}
592
+	if na.Network.IPAM != nil {
593
+		options.IPAM = &network.IPAM{
594
+			Driver:  na.Network.IPAM.Driver.Name,
595
+			Options: na.Network.IPAM.Driver.Options,
596
+		}
597
+		for _, ic := range na.Network.IPAM.Configs {
598
+			c := network.IPAMConfig{
599
+				Subnet:  ic.Subnet,
600
+				IPRange: ic.Range,
601
+				Gateway: ic.Gateway,
602
+			}
603
+			options.IPAM.Config = append(options.IPAM.Config, c)
592 604
 		}
593
-		options.IPAM.Config = append(options.IPAM.Config, c)
594 605
 	}
595 606
 
596 607
 	return clustertypes.NetworkCreateRequest{
... ...
@@ -17,7 +17,28 @@ import (
17 17
 
18 18
 // GetNetworks returns all current cluster managed networks.
19 19
 func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) {
20
-	return c.getNetworks(nil)
20
+	list, err := c.getNetworks(nil)
21
+	if err != nil {
22
+		return nil, err
23
+	}
24
+	removePredefinedNetworks(&list)
25
+	return list, nil
26
+}
27
+
28
+func removePredefinedNetworks(networks *[]apitypes.NetworkResource) {
29
+	if networks == nil {
30
+		return
31
+	}
32
+	var idxs []int
33
+	for i, n := range *networks {
34
+		if v, ok := n.Labels["com.docker.swarm.predefined"]; ok && v == "true" {
35
+			idxs = append(idxs, i)
36
+		}
37
+	}
38
+	for i, idx := range idxs {
39
+		idx -= i
40
+		*networks = append((*networks)[:idx], (*networks)[idx+1:]...)
41
+	}
21 42
 }
22 43
 
23 44
 func (c *Cluster) getNetworks(filters *swarmapi.ListNetworksRequest_Filters) ([]apitypes.NetworkResource, error) {
... ...
@@ -269,16 +290,27 @@ func (c *Cluster) populateNetworkID(ctx context.Context, client swarmapi.Control
269 269
 	if len(networks) == 0 {
270 270
 		networks = s.Networks
271 271
 	}
272
-
273 272
 	for i, n := range networks {
274 273
 		apiNetwork, err := getNetwork(ctx, client, n.Target)
275 274
 		if err != nil {
276
-			if ln, _ := c.config.Backend.FindNetwork(n.Target); ln != nil && !ln.Info().Dynamic() {
275
+			ln, _ := c.config.Backend.FindNetwork(n.Target)
276
+			if ln != nil && runconfig.IsPreDefinedNetwork(ln.Name()) {
277
+				// Need to retrieve the corresponding predefined swarm network
278
+				// and use its id for the request.
279
+				apiNetwork, err = getNetwork(ctx, client, ln.Name())
280
+				if err != nil {
281
+					err = fmt.Errorf("could not find the corresponding predefined swarm network: %v", err)
282
+					return apierrors.NewRequestNotFoundError(err)
283
+				}
284
+				goto setid
285
+			}
286
+			if ln != nil && !ln.Info().Dynamic() {
277 287
 				err = fmt.Errorf("The network %s cannot be used with services. Only networks scoped to the swarm can be used, such as those created with the overlay driver.", ln.Name())
278 288
 				return apierrors.NewRequestForbiddenError(err)
279 289
 			}
280 290
 			return err
281 291
 		}
292
+	setid:
282 293
 		networks[i].Target = apiNetwork.ID
283 294
 	}
284 295
 	return nil
... ...
@@ -507,6 +507,16 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
507 507
 		return apierrors.NewRequestForbiddenError(err)
508 508
 	}
509 509
 
510
+	if dynamic && !nw.Info().Dynamic() {
511
+		if runconfig.IsPreDefinedNetwork(nw.Name()) {
512
+			// Predefined networks now support swarm services. Make this
513
+			// a no-op when cluster requests to remove the predefined network.
514
+			return nil
515
+		}
516
+		err := fmt.Errorf("%s is not a dynamic network", nw.Name())
517
+		return apierrors.NewRequestForbiddenError(err)
518
+	}
519
+
510 520
 	if err := nw.Delete(); err != nil {
511 521
 		return err
512 522
 	}