github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/daemon/cluster/networks.go (about) 1 package cluster 2 3 import ( 4 "fmt" 5 6 apitypes "github.com/docker/docker/api/types" 7 "github.com/docker/docker/api/types/network" 8 types "github.com/docker/docker/api/types/swarm" 9 "github.com/docker/docker/daemon/cluster/convert" 10 "github.com/docker/docker/errdefs" 11 "github.com/docker/docker/runconfig" 12 swarmapi "github.com/docker/swarmkit/api" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 "golang.org/x/net/context" 16 ) 17 18 // GetNetworks returns all current cluster managed networks. 19 func (c *Cluster) GetNetworks() ([]apitypes.NetworkResource, error) { 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 } 42 } 43 44 func (c *Cluster) getNetworks(filters *swarmapi.ListNetworksRequest_Filters) ([]apitypes.NetworkResource, error) { 45 c.mu.RLock() 46 defer c.mu.RUnlock() 47 48 state := c.currentNodeState() 49 if !state.IsActiveManager() { 50 return nil, c.errNoManager(state) 51 } 52 53 ctx, cancel := c.getRequestContext() 54 defer cancel() 55 56 r, err := state.controlClient.ListNetworks(ctx, &swarmapi.ListNetworksRequest{Filters: filters}) 57 if err != nil { 58 return nil, err 59 } 60 61 networks := make([]apitypes.NetworkResource, 0, len(r.Networks)) 62 63 for _, network := range r.Networks { 64 networks = append(networks, convert.BasicNetworkFromGRPC(*network)) 65 } 66 67 return networks, nil 68 } 69 70 // GetNetwork returns a cluster network by an ID. 71 func (c *Cluster) GetNetwork(input string) (apitypes.NetworkResource, error) { 72 var network *swarmapi.Network 73 74 if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error { 75 n, err := getNetwork(ctx, state.controlClient, input) 76 if err != nil { 77 return err 78 } 79 network = n 80 return nil 81 }); err != nil { 82 return apitypes.NetworkResource{}, err 83 } 84 return convert.BasicNetworkFromGRPC(*network), nil 85 } 86 87 // GetNetworksByName returns cluster managed networks by name. 88 // It is ok to have multiple networks here. #18864 89 func (c *Cluster) GetNetworksByName(name string) ([]apitypes.NetworkResource, error) { 90 // Note that swarmapi.GetNetworkRequest.Name is not functional. 91 // So we cannot just use that with c.GetNetwork. 92 return c.getNetworks(&swarmapi.ListNetworksRequest_Filters{ 93 Names: []string{name}, 94 }) 95 } 96 97 func attacherKey(target, containerID string) string { 98 return containerID + ":" + target 99 } 100 101 // UpdateAttachment signals the attachment config to the attachment 102 // waiter who is trying to start or attach the container to the 103 // network. 104 func (c *Cluster) UpdateAttachment(target, containerID string, config *network.NetworkingConfig) error { 105 c.mu.Lock() 106 attacher, ok := c.attachers[attacherKey(target, containerID)] 107 if !ok || attacher == nil { 108 c.mu.Unlock() 109 return fmt.Errorf("could not find attacher for container %s to network %s", containerID, target) 110 } 111 if attacher.inProgress { 112 logrus.Debugf("Discarding redundant notice of resource allocation on network %s for task id %s", target, attacher.taskID) 113 c.mu.Unlock() 114 return nil 115 } 116 attacher.inProgress = true 117 c.mu.Unlock() 118 119 attacher.attachWaitCh <- config 120 121 return nil 122 } 123 124 // WaitForDetachment waits for the container to stop or detach from 125 // the network. 126 func (c *Cluster) WaitForDetachment(ctx context.Context, networkName, networkID, taskID, containerID string) error { 127 c.mu.RLock() 128 attacher, ok := c.attachers[attacherKey(networkName, containerID)] 129 if !ok { 130 attacher, ok = c.attachers[attacherKey(networkID, containerID)] 131 } 132 state := c.currentNodeState() 133 if state.swarmNode == nil || state.swarmNode.Agent() == nil { 134 c.mu.RUnlock() 135 return errors.New("invalid cluster node while waiting for detachment") 136 } 137 138 c.mu.RUnlock() 139 agent := state.swarmNode.Agent() 140 if ok && attacher != nil && 141 attacher.detachWaitCh != nil && 142 attacher.attachCompleteCh != nil { 143 // Attachment may be in progress still so wait for 144 // attachment to complete. 145 select { 146 case <-attacher.attachCompleteCh: 147 case <-ctx.Done(): 148 return ctx.Err() 149 } 150 151 if attacher.taskID == taskID { 152 select { 153 case <-attacher.detachWaitCh: 154 case <-ctx.Done(): 155 return ctx.Err() 156 } 157 } 158 } 159 160 return agent.ResourceAllocator().DetachNetwork(ctx, taskID) 161 } 162 163 // AttachNetwork generates an attachment request towards the manager. 164 func (c *Cluster) AttachNetwork(target string, containerID string, addresses []string) (*network.NetworkingConfig, error) { 165 aKey := attacherKey(target, containerID) 166 c.mu.Lock() 167 state := c.currentNodeState() 168 if state.swarmNode == nil || state.swarmNode.Agent() == nil { 169 c.mu.Unlock() 170 return nil, errors.New("invalid cluster node while attaching to network") 171 } 172 if attacher, ok := c.attachers[aKey]; ok { 173 c.mu.Unlock() 174 return attacher.config, nil 175 } 176 177 agent := state.swarmNode.Agent() 178 attachWaitCh := make(chan *network.NetworkingConfig) 179 detachWaitCh := make(chan struct{}) 180 attachCompleteCh := make(chan struct{}) 181 c.attachers[aKey] = &attacher{ 182 attachWaitCh: attachWaitCh, 183 attachCompleteCh: attachCompleteCh, 184 detachWaitCh: detachWaitCh, 185 } 186 c.mu.Unlock() 187 188 ctx, cancel := c.getRequestContext() 189 defer cancel() 190 191 taskID, err := agent.ResourceAllocator().AttachNetwork(ctx, containerID, target, addresses) 192 if err != nil { 193 c.mu.Lock() 194 delete(c.attachers, aKey) 195 c.mu.Unlock() 196 return nil, fmt.Errorf("Could not attach to network %s: %v", target, err) 197 } 198 199 c.mu.Lock() 200 c.attachers[aKey].taskID = taskID 201 close(attachCompleteCh) 202 c.mu.Unlock() 203 204 logrus.Debugf("Successfully attached to network %s with task id %s", target, taskID) 205 206 release := func() { 207 ctx, cancel := c.getRequestContext() 208 defer cancel() 209 if err := agent.ResourceAllocator().DetachNetwork(ctx, taskID); err != nil { 210 logrus.Errorf("Failed remove network attachment %s to network %s on allocation failure: %v", 211 taskID, target, err) 212 } 213 } 214 215 var config *network.NetworkingConfig 216 select { 217 case config = <-attachWaitCh: 218 case <-ctx.Done(): 219 release() 220 return nil, fmt.Errorf("attaching to network failed, make sure your network options are correct and check manager logs: %v", ctx.Err()) 221 } 222 223 c.mu.Lock() 224 c.attachers[aKey].config = config 225 c.mu.Unlock() 226 227 logrus.Debugf("Successfully allocated resources on network %s for task id %s", target, taskID) 228 229 return config, nil 230 } 231 232 // DetachNetwork unblocks the waiters waiting on WaitForDetachment so 233 // that a request to detach can be generated towards the manager. 234 func (c *Cluster) DetachNetwork(target string, containerID string) error { 235 aKey := attacherKey(target, containerID) 236 237 c.mu.Lock() 238 attacher, ok := c.attachers[aKey] 239 delete(c.attachers, aKey) 240 c.mu.Unlock() 241 242 if !ok { 243 return fmt.Errorf("could not find network attachment for container %s to network %s", containerID, target) 244 } 245 246 close(attacher.detachWaitCh) 247 return nil 248 } 249 250 // CreateNetwork creates a new cluster managed network. 251 func (c *Cluster) CreateNetwork(s apitypes.NetworkCreateRequest) (string, error) { 252 if runconfig.IsPreDefinedNetwork(s.Name) { 253 err := notAllowedError(fmt.Sprintf("%s is a pre-defined network and cannot be created", s.Name)) 254 return "", errors.WithStack(err) 255 } 256 257 var resp *swarmapi.CreateNetworkResponse 258 if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error { 259 networkSpec := convert.BasicNetworkCreateToGRPC(s) 260 r, err := state.controlClient.CreateNetwork(ctx, &swarmapi.CreateNetworkRequest{Spec: &networkSpec}) 261 if err != nil { 262 return err 263 } 264 resp = r 265 return nil 266 }); err != nil { 267 return "", err 268 } 269 270 return resp.Network.ID, nil 271 } 272 273 // RemoveNetwork removes a cluster network. 274 func (c *Cluster) RemoveNetwork(input string) error { 275 return c.lockedManagerAction(func(ctx context.Context, state nodeState) error { 276 network, err := getNetwork(ctx, state.controlClient, input) 277 if err != nil { 278 return err 279 } 280 281 _, err = state.controlClient.RemoveNetwork(ctx, &swarmapi.RemoveNetworkRequest{NetworkID: network.ID}) 282 return err 283 }) 284 } 285 286 func (c *Cluster) populateNetworkID(ctx context.Context, client swarmapi.ControlClient, s *types.ServiceSpec) error { 287 // Always prefer NetworkAttachmentConfigs from TaskTemplate 288 // but fallback to service spec for backward compatibility 289 networks := s.TaskTemplate.Networks 290 if len(networks) == 0 { 291 networks = s.Networks 292 } 293 for i, n := range networks { 294 apiNetwork, err := getNetwork(ctx, client, n.Target) 295 if err != nil { 296 ln, _ := c.config.Backend.FindNetwork(n.Target) 297 if ln != nil && runconfig.IsPreDefinedNetwork(ln.Name()) { 298 // Need to retrieve the corresponding predefined swarm network 299 // and use its id for the request. 300 apiNetwork, err = getNetwork(ctx, client, ln.Name()) 301 if err != nil { 302 return errors.Wrap(errdefs.NotFound(err), "could not find the corresponding predefined swarm network") 303 } 304 goto setid 305 } 306 if ln != nil && !ln.Info().Dynamic() { 307 errMsg := fmt.Sprintf("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()) 308 return errors.WithStack(notAllowedError(errMsg)) 309 } 310 return err 311 } 312 setid: 313 networks[i].Target = apiNetwork.ID 314 } 315 return nil 316 }