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