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  }