Signed-off-by: Alessandro Boch <aboch@docker.com>
| ... | ... |
@@ -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 |
} |