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 }