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  }