github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/client/allocrunner/network_manager_linux.go (about)

     1  package allocrunner
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path"
     7  	"strings"
     8  	"syscall"
     9  
    10  	hclog "github.com/hashicorp/go-hclog"
    11  	clientconfig "github.com/hashicorp/nomad/client/config"
    12  	"github.com/hashicorp/nomad/client/lib/nsutil"
    13  	"github.com/hashicorp/nomad/client/pluginmanager/drivermanager"
    14  	"github.com/hashicorp/nomad/nomad/structs"
    15  	"github.com/hashicorp/nomad/plugins/drivers"
    16  )
    17  
    18  func newNetworkManager(alloc *structs.Allocation, driverManager drivermanager.Manager) (nm drivers.DriverNetworkManager, err error) {
    19  	// The defaultNetworkManager is used if a driver doesn't need to create the network
    20  	nm = &defaultNetworkManager{}
    21  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
    22  
    23  	// default netmode to host, this can be overridden by the task or task group
    24  	tgNetMode := "host"
    25  	if len(tg.Networks) > 0 && tg.Networks[0].Mode != "" {
    26  		tgNetMode = tg.Networks[0].Mode
    27  	}
    28  
    29  	// networkInitiator tracks the task driver which needs to create the network
    30  	// to check for multiple drivers needing the create the network
    31  	var networkInitiator string
    32  
    33  	// driverCaps tracks which drivers we've checked capabilities for so as not
    34  	// to do extra work
    35  	driverCaps := make(map[string]struct{})
    36  	for _, task := range tg.Tasks {
    37  		// the task's netmode defaults to the the task group but can be overridden
    38  		taskNetMode := tgNetMode
    39  		if len(task.Resources.Networks) > 0 && task.Resources.Networks[0].Mode != "" {
    40  			taskNetMode = task.Resources.Networks[0].Mode
    41  		}
    42  
    43  		// netmode host should always work to support backwards compat
    44  		if taskNetMode == "host" {
    45  			continue
    46  		}
    47  
    48  		// check to see if capabilities of this task's driver have already been checked
    49  		if _, ok := driverCaps[task.Driver]; ok {
    50  			continue
    51  		}
    52  
    53  		driver, err := driverManager.Dispense(task.Driver)
    54  		if err != nil {
    55  			return nil, fmt.Errorf("failed to dispense driver %s: %v", task.Driver, err)
    56  		}
    57  
    58  		caps, err := driver.Capabilities()
    59  		if err != nil {
    60  			return nil, fmt.Errorf("failed to retrieve capabilities for driver %s: %v",
    61  				task.Driver, err)
    62  		}
    63  
    64  		// check that the driver supports the requested network isolation mode
    65  		netIsolationMode := netModeToIsolationMode(taskNetMode)
    66  		if !caps.HasNetIsolationMode(netIsolationMode) {
    67  			return nil, fmt.Errorf("task %s does not support %q networking mode", task.Name, taskNetMode)
    68  		}
    69  
    70  		// check if the driver needs to create the network and if a different
    71  		// driver has already claimed it needs to initiate the network
    72  		if caps.MustInitiateNetwork {
    73  			if networkInitiator != "" {
    74  				return nil, fmt.Errorf("tasks %s and %s want to initiate networking but only one driver can do so", networkInitiator, task.Name)
    75  			}
    76  			netManager, ok := driver.(drivers.DriverNetworkManager)
    77  			if !ok {
    78  				return nil, fmt.Errorf("driver %s does not implement network management RPCs", task.Driver)
    79  			}
    80  
    81  			nm = netManager
    82  			networkInitiator = task.Name
    83  		}
    84  
    85  		// mark this driver's capabilities as checked
    86  		driverCaps[task.Driver] = struct{}{}
    87  	}
    88  
    89  	return nm, nil
    90  }
    91  
    92  // defaultNetworkManager creates a network namespace for the alloc
    93  type defaultNetworkManager struct{}
    94  
    95  func (*defaultNetworkManager) CreateNetwork(allocID string) (*drivers.NetworkIsolationSpec, bool, error) {
    96  	netns, err := nsutil.NewNS(allocID)
    97  	if err != nil {
    98  		// when a client restarts, the namespace will already exist and
    99  		// there will be a namespace file in use by the task process
   100  		if e, ok := err.(*os.PathError); ok && e.Err == syscall.EPERM {
   101  			nsPath := path.Join(nsutil.NetNSRunDir, allocID)
   102  			_, err := os.Stat(nsPath)
   103  			if err == nil {
   104  				return nil, false, nil
   105  			}
   106  		}
   107  		return nil, false, err
   108  	}
   109  
   110  	spec := &drivers.NetworkIsolationSpec{
   111  		Mode:   drivers.NetIsolationModeGroup,
   112  		Path:   netns.Path(),
   113  		Labels: make(map[string]string),
   114  	}
   115  
   116  	return spec, true, nil
   117  }
   118  
   119  func (*defaultNetworkManager) DestroyNetwork(allocID string, spec *drivers.NetworkIsolationSpec) error {
   120  	return nsutil.UnmountNS(spec.Path)
   121  }
   122  
   123  func netModeToIsolationMode(netMode string) drivers.NetIsolationMode {
   124  	switch strings.ToLower(netMode) {
   125  	case "host":
   126  		return drivers.NetIsolationModeHost
   127  	case "bridge", "none":
   128  		return drivers.NetIsolationModeGroup
   129  	case "driver":
   130  		return drivers.NetIsolationModeTask
   131  	default:
   132  		if strings.HasPrefix(strings.ToLower(netMode), "cni/") {
   133  			return drivers.NetIsolationModeGroup
   134  		}
   135  		return drivers.NetIsolationModeHost
   136  	}
   137  }
   138  
   139  func newNetworkConfigurator(log hclog.Logger, alloc *structs.Allocation, config *clientconfig.Config) (NetworkConfigurator, error) {
   140  	tg := alloc.Job.LookupTaskGroup(alloc.TaskGroup)
   141  
   142  	// Check if network stanza is given
   143  	if len(tg.Networks) == 0 {
   144  		return &hostNetworkConfigurator{}, nil
   145  	}
   146  
   147  	netMode := strings.ToLower(tg.Networks[0].Mode)
   148  	ignorePortMappingHostIP := config.BindWildcardDefaultHostNetwork
   149  	if len(config.HostNetworks) > 0 {
   150  		ignorePortMappingHostIP = false
   151  	}
   152  
   153  	switch {
   154  	case netMode == "bridge":
   155  		c, err := newBridgeNetworkConfigurator(log, config.BridgeNetworkName, config.BridgeNetworkAllocSubnet, config.CNIPath, ignorePortMappingHostIP)
   156  		if err != nil {
   157  			return nil, err
   158  		}
   159  		return &synchronizedNetworkConfigurator{c}, nil
   160  	case strings.HasPrefix(netMode, "cni/"):
   161  		c, err := newCNINetworkConfigurator(log, config.CNIPath, config.CNIInterfacePrefix, config.CNIConfigDir, netMode[4:], ignorePortMappingHostIP)
   162  		if err != nil {
   163  			return nil, err
   164  		}
   165  		return &synchronizedNetworkConfigurator{c}, nil
   166  	default:
   167  		return &hostNetworkConfigurator{}, nil
   168  	}
   169  }