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  }