Tizen_4.0 base
[platform/upstream/docker-engine.git] / daemon / cluster / networks.go
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         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 := fmt.Errorf("%s is a pre-defined network and cannot be created", s.Name)
254                 return "", apierrors.NewRequestForbiddenError(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                                         err = fmt.Errorf("could not find the corresponding predefined swarm network: %v", err)
303                                         return apierrors.NewRequestNotFoundError(err)
304                                 }
305                                 goto setid
306                         }
307                         if ln != nil && !ln.Info().Dynamic() {
308                                 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())
309                                 return apierrors.NewRequestForbiddenError(err)
310                         }
311                         return err
312                 }
313         setid:
314                 networks[i].Target = apiNetwork.ID
315         }
316         return nil
317 }