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