Merge pull request #29310 from euank/cni-lo

Automatic merge from submit-queue

network/cni: Unconditionally bring up `lo` interface

This is already done in kubenet. This specifically fixes an issue where a kubelet-managed network for the rkt runtime does not have an "UP" lo interface.

Fixes #28561

If this fix doesn't seem right, it could also be implemented by rkt effectively managing two "cni" network plugins, one for the user requested network, one for lo.

Followup CRs can improve unit testing further and then possibly remove the vendor directory logic (which seems like dead code)

cc @kubernetes/sig-rktnetes @kubernetes/sig-network @dcbw
This commit is contained in:
k8s-merge-robot 2016-07-25 15:43:21 -07:00 committed by GitHub
commit 4251ebd1eb
2 changed files with 58 additions and 5 deletions

View File

@ -39,6 +39,7 @@ const (
type cniNetworkPlugin struct {
network.NoopNetworkPlugin
loNetwork *cniNetwork
defaultNetwork *cniNetwork
host network.Host
execer utilexec.Interface
@ -48,7 +49,7 @@ type cniNetworkPlugin struct {
type cniNetwork struct {
name string
NetworkConfig *libcni.NetworkConfig
CNIConfig *libcni.CNIConfig
CNIConfig libcni.CNI
}
func probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir, vendorCNIDirPrefix string) []network.NetworkPlugin {
@ -59,6 +60,7 @@ func probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir, vendorCNIDirPrefix str
}
return append(configList, &cniNetworkPlugin{
defaultNetwork: network,
loNetwork: getLoNetwork(vendorCNIDirPrefix),
execer: utilexec.New(),
})
}
@ -87,9 +89,9 @@ func getDefaultCNINetwork(pluginDir, vendorCNIDirPrefix string) (*cniNetwork, er
continue
}
// Search for vendor-specific plugins as well as default plugins in the CNI codebase.
vendorCNIDir := fmt.Sprintf(VendorCNIDirTemplate, vendorCNIDirPrefix, conf.Network.Type)
vendorDir := vendorCNIDir(vendorCNIDirPrefix, conf.Network.Type)
cninet := &libcni.CNIConfig{
Path: []string{DefaultCNIDir, vendorCNIDir},
Path: []string{DefaultCNIDir, vendorDir},
}
network := &cniNetwork{name: conf.Network.Name, NetworkConfig: conf, CNIConfig: cninet}
return network, nil
@ -97,6 +99,33 @@ func getDefaultCNINetwork(pluginDir, vendorCNIDirPrefix string) (*cniNetwork, er
return nil, fmt.Errorf("No valid networks found in %s", pluginDir)
}
func vendorCNIDir(prefix, pluginType string) string {
return fmt.Sprintf(VendorCNIDirTemplate, prefix, pluginType)
}
func getLoNetwork(vendorDirPrefix string) *cniNetwork {
loConfig, err := libcni.ConfFromBytes([]byte(`{
"cniVersion": "0.1.0",
"name": "cni-loopback",
"type": "loopback"
}`))
if err != nil {
// The hardcoded config above should always be valid and unit tests will
// catch this
panic(err)
}
cninet := &libcni.CNIConfig{
Path: []string{vendorCNIDir(vendorDirPrefix, loConfig.Network.Type), DefaultCNIDir},
}
loNetwork := &cniNetwork{
name: "lo",
NetworkConfig: loConfig,
CNIConfig: cninet,
}
return loNetwork
}
func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode componentconfig.HairpinMode, nonMasqueradeCIDR string) error {
var err error
plugin.nsenterPath, err = plugin.execer.LookPath("nsenter")
@ -118,6 +147,12 @@ func (plugin *cniNetworkPlugin) SetUpPod(namespace string, name string, id kubec
return fmt.Errorf("CNI failed to retrieve network namespace path: %v", err)
}
_, err = plugin.loNetwork.addToNetwork(name, namespace, id, netnsPath)
if err != nil {
glog.Errorf("Error while adding to cni lo network: %s", err)
return err
}
_, err = plugin.defaultNetwork.addToNetwork(name, namespace, id, netnsPath)
if err != nil {
glog.Errorf("Error while adding to cni network: %s", err)
@ -160,7 +195,7 @@ func (network *cniNetwork) addToNetwork(podName string, podNamespace string, pod
}
netconf, cninet := network.NetworkConfig, network.CNIConfig
glog.V(4).Infof("About to run with conf.Network.Type=%v, c.Path=%v", netconf.Network.Type, cninet.Path)
glog.V(4).Infof("About to run with conf.Network.Type=%v", netconf.Network.Type)
res, err := cninet.AddNetwork(netconf, rt)
if err != nil {
glog.Errorf("Error adding network: %v", err)
@ -178,7 +213,7 @@ func (network *cniNetwork) deleteFromNetwork(podName string, podNamespace string
}
netconf, cninet := network.NetworkConfig, network.CNIConfig
glog.V(4).Infof("About to run with conf.Network.Type=%v, c.Path=%v", netconf.Network.Type, cninet.Path)
glog.V(4).Infof("About to run with conf.Network.Type=%v", netconf.Network.Type)
err = cninet.DelNetwork(netconf, rt)
if err != nil {
glog.Errorf("Error deleting network: %v", err)

View File

@ -23,6 +23,7 @@ import (
"fmt"
"io/ioutil"
"math/rand"
"net"
"os"
"path"
"testing"
@ -30,11 +31,14 @@ import (
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
cnitypes "github.com/appc/cni/pkg/types"
"github.com/stretchr/testify/mock"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/componentconfig"
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
"k8s.io/kubernetes/pkg/kubelet/network"
"k8s.io/kubernetes/pkg/kubelet/network/cni/testing"
utilexec "k8s.io/kubernetes/pkg/util/exec"
utiltesting "k8s.io/kubernetes/pkg/util/testing"
)
@ -160,6 +164,9 @@ func TestCNIPlugin(t *testing.T) {
},
}
mockLoCNI := &mock_cni.MockCNI{}
// TODO mock for the test plugin too
tmpDir := utiltesting.MkTmpdirOrDie("cni-test")
testNetworkConfigPath := path.Join(tmpDir, "plugins", "net", "cni")
testVendorCNIDirPrefix := tmpDir
@ -189,6 +196,9 @@ func TestCNIPlugin(t *testing.T) {
t.Fatalf("Not a CNI network plugin!")
}
cniPlugin.execer = fexec
cniPlugin.loNetwork.CNIConfig = mockLoCNI
mockLoCNI.On("AddNetwork", cniPlugin.loNetwork.NetworkConfig, mock.AnythingOfType("*libcni.RuntimeConf")).Return(&cnitypes.Result{IP4: &cnitypes.IPConfig{IP: net.IPNet{IP: []byte{127, 0, 0, 1}}}}, nil)
plug, err := network.InitNetworkPlugin(plugins, "cni", NewFakeHost(nil, pods), componentconfig.HairpinNone, "10.0.0.0/8")
if err != nil {
@ -231,4 +241,12 @@ func TestCNIPlugin(t *testing.T) {
if string(output) != expectedOutput {
t.Errorf("Mismatch in expected output for setup hook. Expected '%s', got '%s'", expectedOutput, string(output))
}
mockLoCNI.AssertExpectations(t)
}
func TestLoNetNonNil(t *testing.T) {
if conf := getLoNetwork(""); conf == nil {
t.Error("Expected non-nil lo network")
}
}