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