github.com/sams1990/dockerrepo@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  }