cni: convert "vendor" option to multiple plugin binary search paths

It's only used for the test code and after talking with Rajat, the
vendor stuff was never really used anyway.  So convert the vendor
code into a plain array of plugin binary search paths, which is all
the vendor code was doing anyway.
pull/8/head
Dan Williams 2018-01-23 13:27:38 -06:00
parent 16eaaaed83
commit 69ac723b78
6 changed files with 71 additions and 78 deletions

View File

@ -118,7 +118,7 @@ func ProbeNetworkPlugins(cniConfDir, cniBinDir string) []network.NetworkPlugin {
allPlugins := []network.NetworkPlugin{} allPlugins := []network.NetworkPlugin{}
// for each existing plugin, add to the list // for each existing plugin, add to the list
allPlugins = append(allPlugins, cni.ProbeNetworkPlugins(cniConfDir, cniBinDir)...) allPlugins = append(allPlugins, cni.ProbeNetworkPlugins(cniConfDir, []string{cniBinDir})...)
allPlugins = append(allPlugins, kubenet.NewPlugin(cniBinDir)) allPlugins = append(allPlugins, kubenet.NewPlugin(cniBinDir))
return allPlugins return allPlugins

View File

@ -229,7 +229,7 @@ func NewDockerService(config *ClientConfig, podSandboxImage string, streamingCon
} }
} }
// dockershim currently only supports CNI plugins. // dockershim currently only supports CNI plugins.
cniPlugins := cni.ProbeNetworkPlugins(pluginSettings.PluginConfDir, pluginSettings.PluginBinDir) cniPlugins := cni.ProbeNetworkPlugins(pluginSettings.PluginConfDir, []string{pluginSettings.PluginBinDir})
cniPlugins = append(cniPlugins, kubenet.NewPlugin(pluginSettings.PluginBinDir)) cniPlugins = append(cniPlugins, kubenet.NewPlugin(pluginSettings.PluginBinDir))
netHost := &dockerNetworkHost{ netHost := &dockerNetworkHost{
pluginSettings.LegacyRuntimeHost, pluginSettings.LegacyRuntimeHost,

View File

@ -33,10 +33,9 @@ import (
) )
const ( const (
CNIPluginName = "cni" CNIPluginName = "cni"
DefaultConfDir = "/etc/cni/net.d" DefaultConfDir = "/etc/cni/net.d"
DefaultBinDir = "/opt/cni/bin" DefaultBinDir = "/opt/cni/bin"
VendorCNIDirTemplate = "%s/opt/%s/bin"
) )
type cniNetworkPlugin struct { type cniNetworkPlugin struct {
@ -47,12 +46,11 @@ type cniNetworkPlugin struct {
sync.RWMutex sync.RWMutex
defaultNetwork *cniNetwork defaultNetwork *cniNetwork
host network.Host host network.Host
execer utilexec.Interface execer utilexec.Interface
nsenterPath string nsenterPath string
confDir string confDir string
binDir string binDirs []string
vendorCNIDirPrefix string
} }
type cniNetwork struct { type cniNetwork struct {
@ -70,17 +68,28 @@ type cniPortMapping struct {
HostIP string `json:"hostIP"` HostIP string `json:"hostIP"`
} }
func probeNetworkPluginsWithVendorCNIDirPrefix(confDir, binDir, vendorCNIDirPrefix string) []network.NetworkPlugin { func ProbeNetworkPlugins(confDir string, binDirs []string) []network.NetworkPlugin {
if binDir == "" { old := binDirs
binDir = DefaultBinDir binDirs = make([]string, len(binDirs))
for _, dir := range old {
if dir != "" {
binDirs = append(binDirs, dir)
}
} }
if len(binDirs) == 0 {
binDirs = []string{DefaultBinDir}
}
if confDir == "" {
confDir = DefaultConfDir
}
plugin := &cniNetworkPlugin{ plugin := &cniNetworkPlugin{
defaultNetwork: nil, defaultNetwork: nil,
loNetwork: getLoNetwork(binDir, vendorCNIDirPrefix), loNetwork: getLoNetwork(binDirs),
execer: utilexec.New(), execer: utilexec.New(),
confDir: confDir, confDir: confDir,
binDir: binDir, binDirs: binDirs,
vendorCNIDirPrefix: vendorCNIDirPrefix,
} }
// sync NetworkConfig in best effort during probing. // sync NetworkConfig in best effort during probing.
@ -88,14 +97,7 @@ func probeNetworkPluginsWithVendorCNIDirPrefix(confDir, binDir, vendorCNIDirPref
return []network.NetworkPlugin{plugin} return []network.NetworkPlugin{plugin}
} }
func ProbeNetworkPlugins(confDir, binDir string) []network.NetworkPlugin { func getDefaultCNINetwork(confDir string, binDirs []string) (*cniNetwork, error) {
return probeNetworkPluginsWithVendorCNIDirPrefix(confDir, binDir, "")
}
func getDefaultCNINetwork(confDir, binDir, vendorCNIDirPrefix string) (*cniNetwork, error) {
if confDir == "" {
confDir = DefaultConfDir
}
files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"}) files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"})
switch { switch {
case err != nil: case err != nil:
@ -136,23 +138,17 @@ func getDefaultCNINetwork(confDir, binDir, vendorCNIDirPrefix string) (*cniNetwo
glog.Warningf("CNI config list %s has no networks, skipping", confFile) glog.Warningf("CNI config list %s has no networks, skipping", confFile)
continue continue
} }
confType := confList.Plugins[0].Network.Type
// Search for vendor-specific plugins as well as default plugins in the CNI codebase. network := &cniNetwork{
vendorDir := vendorCNIDir(vendorCNIDirPrefix, confType) name: confList.Name,
cninet := &libcni.CNIConfig{ NetworkConfig: confList,
Path: []string{vendorDir, binDir}, CNIConfig: &libcni.CNIConfig{Path: binDirs},
} }
network := &cniNetwork{name: confList.Name, NetworkConfig: confList, CNIConfig: cninet}
return network, nil return network, nil
} }
return nil, fmt.Errorf("No valid networks found in %s", confDir) return nil, fmt.Errorf("No valid networks found in %s", confDir)
} }
func vendorCNIDir(prefix, pluginType string) string {
return fmt.Sprintf(VendorCNIDirTemplate, prefix, pluginType)
}
func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error { func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
err := plugin.platformInit() err := plugin.platformInit()
if err != nil { if err != nil {
@ -166,7 +162,7 @@ func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode kubeletconfi
} }
func (plugin *cniNetworkPlugin) syncNetworkConfig() { func (plugin *cniNetworkPlugin) syncNetworkConfig() {
network, err := getDefaultCNINetwork(plugin.confDir, plugin.binDir, plugin.vendorCNIDirPrefix) network, err := getDefaultCNINetwork(plugin.confDir, plugin.binDirs)
if err != nil { if err != nil {
glog.Warningf("Unable to update cni config: %s", err) glog.Warningf("Unable to update cni config: %s", err)
return return

View File

@ -26,7 +26,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/network" "k8s.io/kubernetes/pkg/kubelet/network"
) )
func getLoNetwork(binDir, vendorDirPrefix string) *cniNetwork { func getLoNetwork(binDirs []string) *cniNetwork {
loConfig, err := libcni.ConfListFromBytes([]byte(`{ loConfig, err := libcni.ConfListFromBytes([]byte(`{
"cniVersion": "0.2.0", "cniVersion": "0.2.0",
"name": "cni-loopback", "name": "cni-loopback",
@ -39,13 +39,10 @@ func getLoNetwork(binDir, vendorDirPrefix string) *cniNetwork {
// catch this // catch this
panic(err) panic(err)
} }
cninet := &libcni.CNIConfig{
Path: []string{vendorCNIDir(vendorDirPrefix, "loopback"), binDir},
}
loNetwork := &cniNetwork{ loNetwork := &cniNetwork{
name: "lo", name: "lo",
NetworkConfig: loConfig, NetworkConfig: loConfig,
CNIConfig: cninet, CNIConfig: &libcni.CNIConfig{Path: binDirs},
} }
return loNetwork return loNetwork

View File

@ -47,31 +47,28 @@ import (
fakeexec "k8s.io/utils/exec/testing" fakeexec "k8s.io/utils/exec/testing"
) )
func installPluginUnderTest(t *testing.T, testVendorCNIDirPrefix, testNetworkConfigPath, vendorName string, plugName string) { // Returns .in file path, .out file path, and .env file path
pluginDir := path.Join(testNetworkConfigPath, plugName) func installPluginUnderTest(t *testing.T, testBinDir, testConfDir, testDataDir, binName string, confName string) (string, string, string) {
err := os.MkdirAll(pluginDir, 0777) for _, dir := range []string{testBinDir, testConfDir, testDataDir} {
if err != nil { err := os.MkdirAll(dir, 0777)
t.Fatalf("Failed to create plugin config dir: %v", err) if err != nil {
t.Fatalf("Failed to create test plugin dir %s: %v", dir, err)
}
} }
pluginConfig := path.Join(pluginDir, plugName+".conf")
f, err := os.Create(pluginConfig)
if err != nil {
t.Fatalf("Failed to install plugin")
}
networkConfig := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true} }`, plugName, vendorName)
confFile := path.Join(testConfDir, confName+".conf")
f, err := os.Create(confFile)
if err != nil {
t.Fatalf("Failed to install plugin %s: %v", confFile, err)
}
networkConfig := fmt.Sprintf(`{ "name": "%s", "type": "%s", "capabilities": {"portMappings": true} }`, confName, binName)
_, err = f.WriteString(networkConfig) _, err = f.WriteString(networkConfig)
if err != nil { if err != nil {
t.Fatalf("Failed to write network config file (%v)", err) t.Fatalf("Failed to write network config file (%v)", err)
} }
f.Close() f.Close()
vendorCNIDir := fmt.Sprintf(VendorCNIDirTemplate, testVendorCNIDirPrefix, vendorName) pluginExec := path.Join(testBinDir, binName)
err = os.MkdirAll(vendorCNIDir, 0777)
if err != nil {
t.Fatalf("Failed to create plugin dir: %v", err)
}
pluginExec := path.Join(vendorCNIDir, vendorName)
f, err = os.Create(pluginExec) f, err = os.Create(pluginExec)
const execScriptTempl = `#!/bin/bash const execScriptTempl = `#!/bin/bash
@ -83,11 +80,14 @@ mkdir -p {{.OutputDir}} &> /dev/null
echo -n "$CNI_COMMAND $CNI_NETNS $K8S_POD_NAMESPACE $K8S_POD_NAME $K8S_POD_INFRA_CONTAINER_ID" >& {{.OutputFile}} echo -n "$CNI_COMMAND $CNI_NETNS $K8S_POD_NAMESPACE $K8S_POD_NAME $K8S_POD_INFRA_CONTAINER_ID" >& {{.OutputFile}}
echo -n "{ \"ip4\": { \"ip\": \"10.1.0.23/24\" } }" echo -n "{ \"ip4\": { \"ip\": \"10.1.0.23/24\" } }"
` `
inputFile := path.Join(testDataDir, binName+".in")
outputFile := path.Join(testDataDir, binName+".out")
envFile := path.Join(testDataDir, binName+".env")
execTemplateData := &map[string]interface{}{ execTemplateData := &map[string]interface{}{
"InputFile": path.Join(pluginDir, plugName+".in"), "InputFile": inputFile,
"OutputFile": path.Join(pluginDir, plugName+".out"), "OutputFile": outputFile,
"OutputEnv": path.Join(pluginDir, plugName+".env"), "OutputEnv": envFile,
"OutputDir": pluginDir, "OutputDir": testDataDir,
} }
tObj := template.Must(template.New("test").Parse(execScriptTempl)) tObj := template.Must(template.New("test").Parse(execScriptTempl))
@ -107,6 +107,8 @@ echo -n "{ \"ip4\": { \"ip\": \"10.1.0.23/24\" } }"
} }
f.Close() f.Close()
return inputFile, outputFile, envFile
} }
func tearDownPlugin(tmpDir string) { func tearDownPlugin(tmpDir string) {
@ -155,8 +157,8 @@ func (fnh *fakeNetworkHost) SupportsLegacyFeatures() bool {
func TestCNIPlugin(t *testing.T) { func TestCNIPlugin(t *testing.T) {
// install some random plugin // install some random plugin
pluginName := fmt.Sprintf("test%d", rand.Intn(1000)) netName := fmt.Sprintf("test%d", rand.Intn(1000))
vendorName := fmt.Sprintf("test_vendor%d", rand.Intn(1000)) binName := fmt.Sprintf("test_vendor%d", rand.Intn(1000))
podIP := "10.0.0.2" podIP := "10.0.0.2"
podIPOutput := fmt.Sprintf("4: eth0 inet %s/24 scope global dynamic eth0\\ valid_lft forever preferred_lft forever", podIP) podIPOutput := fmt.Sprintf("4: eth0 inet %s/24 scope global dynamic eth0\\ valid_lft forever preferred_lft forever", podIP)
@ -183,10 +185,11 @@ func TestCNIPlugin(t *testing.T) {
// TODO mock for the test plugin too // TODO mock for the test plugin too
tmpDir := utiltesting.MkTmpdirOrDie("cni-test") tmpDir := utiltesting.MkTmpdirOrDie("cni-test")
testNetworkConfigPath := path.Join(tmpDir, "plugins", "net", "cni") testConfDir := path.Join(tmpDir, "etc", "cni", "net.d")
testVendorCNIDirPrefix := tmpDir testBinDir := path.Join(tmpDir, "opt", "cni", "bin")
testDataDir := path.Join(tmpDir, "output")
defer tearDownPlugin(tmpDir) defer tearDownPlugin(tmpDir)
installPluginUnderTest(t, testVendorCNIDirPrefix, testNetworkConfigPath, vendorName, pluginName) inputFile, outputFile, outputEnv := installPluginUnderTest(t, testBinDir, testConfDir, testDataDir, binName, netName)
containerID := kubecontainer.ContainerID{Type: "test", ID: "test_infra_container"} containerID := kubecontainer.ContainerID{Type: "test", ID: "test_infra_container"}
pods := []*containertest.FakePod{{ pods := []*containertest.FakePod{{
@ -198,7 +201,7 @@ func TestCNIPlugin(t *testing.T) {
NetnsPath: "/proc/12345/ns/net", NetnsPath: "/proc/12345/ns/net",
}} }}
plugins := probeNetworkPluginsWithVendorCNIDirPrefix(path.Join(testNetworkConfigPath, pluginName), "", testVendorCNIDirPrefix) plugins := ProbeNetworkPlugins(testConfDir, []string{testBinDir})
if len(plugins) != 1 { if len(plugins) != 1 {
t.Fatalf("Expected only one network plugin, got %d", len(plugins)) t.Fatalf("Expected only one network plugin, got %d", len(plugins))
} }
@ -238,9 +241,7 @@ func TestCNIPlugin(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Expected nil: %v", err) t.Errorf("Expected nil: %v", err)
} }
outputEnv := path.Join(testNetworkConfigPath, pluginName, pluginName+".env")
eo, eerr := ioutil.ReadFile(outputEnv) eo, eerr := ioutil.ReadFile(outputEnv)
outputFile := path.Join(testNetworkConfigPath, pluginName, pluginName+".out")
output, err := ioutil.ReadFile(outputFile) output, err := ioutil.ReadFile(outputFile)
if err != nil || eerr != nil { if err != nil || eerr != nil {
t.Errorf("Failed to read output file %s: %v (env %s err %v)", outputFile, err, eo, eerr) t.Errorf("Failed to read output file %s: %v (env %s err %v)", outputFile, err, eo, eerr)
@ -257,7 +258,6 @@ func TestCNIPlugin(t *testing.T) {
PortMappings []map[string]interface{} `json:"portMappings"` PortMappings []map[string]interface{} `json:"portMappings"`
} `json:"runtimeConfig"` } `json:"runtimeConfig"`
}{} }{}
inputFile := path.Join(testNetworkConfigPath, pluginName, pluginName+".in")
inputBytes, inerr := ioutil.ReadFile(inputFile) inputBytes, inerr := ioutil.ReadFile(inputFile)
parseerr := json.Unmarshal(inputBytes, &inputConfig) parseerr := json.Unmarshal(inputBytes, &inputConfig)
if inerr != nil || parseerr != nil { if inerr != nil || parseerr != nil {
@ -285,7 +285,7 @@ func TestCNIPlugin(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Expected nil: %v", err) t.Errorf("Expected nil: %v", err)
} }
output, err = ioutil.ReadFile(path.Join(testNetworkConfigPath, pluginName, pluginName+".out")) output, err = ioutil.ReadFile(outputFile)
expectedOutput = "DEL /proc/12345/ns/net podNamespace podName test_infra_container" expectedOutput = "DEL /proc/12345/ns/net podNamespace podName test_infra_container"
if string(output) != expectedOutput { if string(output) != expectedOutput {
t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output)) t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
@ -295,7 +295,7 @@ func TestCNIPlugin(t *testing.T) {
} }
func TestLoNetNonNil(t *testing.T) { func TestLoNetNonNil(t *testing.T) {
if conf := getLoNetwork("", ""); conf == nil { if conf := getLoNetwork(nil); conf == nil {
t.Error("Expected non-nil lo network") t.Error("Expected non-nil lo network")
} }
} }

View File

@ -27,7 +27,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/network" "k8s.io/kubernetes/pkg/kubelet/network"
) )
func getLoNetwork(binDir, vendorDirPrefix string) *cniNetwork { func getLoNetwork(binDirs []string) *cniNetwork {
return nil return nil
} }