253 lines
7.5 KiB
Go
253 lines
7.5 KiB
Go
//go:build !dockerless
|
|
// +build !dockerless
|
|
|
|
/*
|
|
Copyright 2014 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package testing
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
|
|
utilsets "k8s.io/apimachinery/pkg/util/sets"
|
|
sysctltest "k8s.io/component-helpers/node/util/sysctl/testing"
|
|
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
|
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/network"
|
|
netutils "k8s.io/utils/net"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestSelectDefaultPlugin(t *testing.T) {
|
|
all_plugins := []network.NetworkPlugin{}
|
|
plug, err := network.InitNetworkPlugin(all_plugins, "", NewFakeHost(nil), kubeletconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error in selecting default plugin: %v", err)
|
|
}
|
|
if plug == nil {
|
|
t.Fatalf("Failed to select the default plugin.")
|
|
}
|
|
if plug.Name() != network.DefaultPluginName {
|
|
t.Errorf("Failed to select the default plugin. Expected %s. Got %s", network.DefaultPluginName, plug.Name())
|
|
}
|
|
}
|
|
|
|
func TestInit(t *testing.T) {
|
|
tests := []struct {
|
|
setting string
|
|
expectedLen int
|
|
}{
|
|
{
|
|
setting: "net/bridge/bridge-nf-call-iptables",
|
|
expectedLen: 1,
|
|
},
|
|
{
|
|
setting: "net/bridge/bridge-nf-call-ip6tables",
|
|
expectedLen: 2,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
sysctl := sysctltest.NewFake()
|
|
sysctl.Settings[tt.setting] = 0
|
|
plug := &network.NoopNetworkPlugin{}
|
|
plug.Sysctl = sysctl
|
|
plug.Init(NewFakeHost(nil), kubeletconfig.HairpinNone, "10.0.0.0/8", network.UseDefaultMTU)
|
|
// Verify the sysctl specified is set
|
|
assert.Equal(t, 1, sysctl.Settings[tt.setting], tt.setting+" sysctl should have been set")
|
|
// Verify iptables is always set
|
|
assert.Equal(t, 1, sysctl.Settings["net/bridge/bridge-nf-call-iptables"], "net/bridge/bridge-nf-call-iptables sysctl should have been set")
|
|
// Verify ip6tables is only set if it existed
|
|
assert.Len(t, sysctl.Settings, tt.expectedLen, "length wrong for "+tt.setting)
|
|
}
|
|
}
|
|
|
|
func TestPluginManager(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
fnp := NewMockNetworkPlugin(ctrl)
|
|
defer ctrl.Finish()
|
|
pm := network.NewPluginManager(fnp)
|
|
|
|
fnp.EXPECT().Name().Return("someNetworkPlugin").AnyTimes()
|
|
|
|
allCreatedWg := sync.WaitGroup{}
|
|
allCreatedWg.Add(1)
|
|
allDoneWg := sync.WaitGroup{}
|
|
|
|
// 10 pods, 4 setup/status/teardown runs each. Ensure that network locking
|
|
// works and the pod map isn't concurrently accessed
|
|
for i := 0; i < 10; i++ {
|
|
podName := fmt.Sprintf("pod%d", i)
|
|
containerID := kubecontainer.ContainerID{ID: podName}
|
|
|
|
fnp.EXPECT().SetUpPod("", podName, containerID, nil, nil).Return(nil).Times(4)
|
|
fnp.EXPECT().GetPodNetworkStatus("", podName, containerID).Return(&network.PodNetworkStatus{IP: netutils.ParseIPSloppy("1.2.3.4")}, nil).Times(4)
|
|
fnp.EXPECT().TearDownPod("", podName, containerID).Return(nil).Times(4)
|
|
|
|
for x := 0; x < 4; x++ {
|
|
allDoneWg.Add(1)
|
|
go func(name string, id kubecontainer.ContainerID, num int) {
|
|
defer allDoneWg.Done()
|
|
|
|
// Block all goroutines from running until all have
|
|
// been created and are ready. This ensures we
|
|
// have more pod network operations running
|
|
// concurrently.
|
|
allCreatedWg.Wait()
|
|
|
|
if err := pm.SetUpPod("", name, id, nil, nil); err != nil {
|
|
t.Errorf("Failed to set up pod %q: %v", name, err)
|
|
return
|
|
}
|
|
|
|
if _, err := pm.GetPodNetworkStatus("", name, id); err != nil {
|
|
t.Errorf("Failed to inspect pod %q: %v", name, err)
|
|
return
|
|
}
|
|
|
|
if err := pm.TearDownPod("", name, id); err != nil {
|
|
t.Errorf("Failed to tear down pod %q: %v", name, err)
|
|
return
|
|
}
|
|
}(podName, containerID, x)
|
|
}
|
|
}
|
|
// Block all goroutines from running until all have been created and started
|
|
allCreatedWg.Done()
|
|
|
|
// Wait for them all to finish
|
|
allDoneWg.Wait()
|
|
}
|
|
|
|
type hookableFakeNetworkPluginSetupHook func(namespace, name string, id kubecontainer.ContainerID)
|
|
|
|
type hookableFakeNetworkPlugin struct {
|
|
setupHook hookableFakeNetworkPluginSetupHook
|
|
}
|
|
|
|
func newHookableFakeNetworkPlugin(setupHook hookableFakeNetworkPluginSetupHook) *hookableFakeNetworkPlugin {
|
|
return &hookableFakeNetworkPlugin{
|
|
setupHook: setupHook,
|
|
}
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) Init(host network.Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
|
|
return nil
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) Event(name string, details map[string]interface{}) {
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) Name() string {
|
|
return "fakeplugin"
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) Capabilities() utilsets.Int {
|
|
return utilsets.NewInt()
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID, annotations, options map[string]string) error {
|
|
if p.setupHook != nil {
|
|
p.setupHook(namespace, name, id)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) TearDownPod(string, string, kubecontainer.ContainerID) error {
|
|
return nil
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) GetPodNetworkStatus(string, string, kubecontainer.ContainerID) (*network.PodNetworkStatus, error) {
|
|
return &network.PodNetworkStatus{IP: netutils.ParseIPSloppy("10.1.2.3")}, nil
|
|
}
|
|
|
|
func (p *hookableFakeNetworkPlugin) Status() error {
|
|
return nil
|
|
}
|
|
|
|
// Ensure that one pod's network operations don't block another's. If the
|
|
// test is successful (eg, first pod doesn't block on second) the test
|
|
// will complete. If unsuccessful, it will hang and get killed.
|
|
func TestMultiPodParallelNetworkOps(t *testing.T) {
|
|
podWg := sync.WaitGroup{}
|
|
podWg.Add(1)
|
|
|
|
// Can't do this with MockNetworkPlugin because the gomock controller
|
|
// has its own locks which don't allow the parallel network operation
|
|
// to proceed.
|
|
didWait := false
|
|
fakePlugin := newHookableFakeNetworkPlugin(func(podNamespace, podName string, id kubecontainer.ContainerID) {
|
|
if podName == "waiter" {
|
|
podWg.Wait()
|
|
didWait = true
|
|
}
|
|
})
|
|
pm := network.NewPluginManager(fakePlugin)
|
|
|
|
opsWg := sync.WaitGroup{}
|
|
|
|
// Start the pod that will wait for the other to complete
|
|
opsWg.Add(1)
|
|
go func() {
|
|
defer opsWg.Done()
|
|
|
|
podName := "waiter"
|
|
containerID := kubecontainer.ContainerID{ID: podName}
|
|
|
|
// Setup will block on the runner pod completing. If network
|
|
// operations locking isn't correct (eg pod network operations
|
|
// block other pods) setUpPod() will never return.
|
|
if err := pm.SetUpPod("", podName, containerID, nil, nil); err != nil {
|
|
t.Errorf("Failed to set up waiter pod: %v", err)
|
|
return
|
|
}
|
|
|
|
if err := pm.TearDownPod("", podName, containerID); err != nil {
|
|
t.Errorf("Failed to tear down waiter pod: %v", err)
|
|
return
|
|
}
|
|
}()
|
|
|
|
opsWg.Add(1)
|
|
go func() {
|
|
defer opsWg.Done()
|
|
// Let other pod proceed
|
|
defer podWg.Done()
|
|
|
|
podName := "runner"
|
|
containerID := kubecontainer.ContainerID{ID: podName}
|
|
|
|
if err := pm.SetUpPod("", podName, containerID, nil, nil); err != nil {
|
|
t.Errorf("Failed to set up runner pod: %v", err)
|
|
return
|
|
}
|
|
|
|
if err := pm.TearDownPod("", podName, containerID); err != nil {
|
|
t.Errorf("Failed to tear down runner pod: %v", err)
|
|
return
|
|
}
|
|
}()
|
|
|
|
opsWg.Wait()
|
|
|
|
if !didWait {
|
|
t.Errorf("waiter pod didn't wait for runner pod!")
|
|
}
|
|
}
|