mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #80636 from ebati/issue-80504-test-kubeproxy-mac
Add GetKernelVersion to ipvs.KernelHandler interface
This commit is contained in:
commit
59142b231c
@ -32,6 +32,7 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
iptablesVersion string
|
iptablesVersion string
|
||||||
ipsetVersion string
|
ipsetVersion string
|
||||||
kmods []string
|
kmods []string
|
||||||
|
kernelVersion string
|
||||||
kernelCompat bool
|
kernelCompat bool
|
||||||
iptablesError error
|
iptablesError error
|
||||||
ipsetError error
|
ipsetError error
|
||||||
@ -85,15 +86,24 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
kernelCompat: true,
|
kernelCompat: true,
|
||||||
expected: proxyModeIPTables,
|
expected: proxyModeIPTables,
|
||||||
},
|
},
|
||||||
{ // flag says ipvs, ipset version ok, kernel modules installed
|
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel before 4.19
|
||||||
flag: "ipvs",
|
flag: "ipvs",
|
||||||
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
||||||
|
kernelVersion: "4.18",
|
||||||
|
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||||
|
expected: proxyModeIPVS,
|
||||||
|
},
|
||||||
|
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel 4.19
|
||||||
|
flag: "ipvs",
|
||||||
|
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||||
expected: proxyModeIPVS,
|
expected: proxyModeIPVS,
|
||||||
},
|
},
|
||||||
{ // flag says ipvs, ipset version too low, fallback on iptables mode
|
{ // flag says ipvs, ipset version too low, fallback on iptables mode
|
||||||
flag: "ipvs",
|
flag: "ipvs",
|
||||||
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "0.0",
|
ipsetVersion: "0.0",
|
||||||
iptablesVersion: iptables.MinCheckVersion,
|
iptablesVersion: iptables.MinCheckVersion,
|
||||||
kernelCompat: true,
|
kernelCompat: true,
|
||||||
@ -101,7 +111,8 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{ // flag says ipvs, bad ipset version, fallback on iptables mode
|
{ // flag says ipvs, bad ipset version, fallback on iptables mode
|
||||||
flag: "ipvs",
|
flag: "ipvs",
|
||||||
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "a.b.c",
|
ipsetVersion: "a.b.c",
|
||||||
iptablesVersion: iptables.MinCheckVersion,
|
iptablesVersion: iptables.MinCheckVersion,
|
||||||
kernelCompat: true,
|
kernelCompat: true,
|
||||||
@ -110,6 +121,7 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
{ // flag says ipvs, required kernel modules are not installed, fallback on iptables mode
|
{ // flag says ipvs, required kernel modules are not installed, fallback on iptables mode
|
||||||
flag: "ipvs",
|
flag: "ipvs",
|
||||||
kmods: []string{"foo", "bar", "baz"},
|
kmods: []string{"foo", "bar", "baz"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||||
iptablesVersion: iptables.MinCheckVersion,
|
iptablesVersion: iptables.MinCheckVersion,
|
||||||
kernelCompat: true,
|
kernelCompat: true,
|
||||||
@ -118,6 +130,16 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
{ // flag says ipvs, required kernel modules are not installed, iptables version too old, fallback on userspace mode
|
{ // flag says ipvs, required kernel modules are not installed, iptables version too old, fallback on userspace mode
|
||||||
flag: "ipvs",
|
flag: "ipvs",
|
||||||
kmods: []string{"foo", "bar", "baz"},
|
kmods: []string{"foo", "bar", "baz"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
|
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||||
|
iptablesVersion: "0.0.0",
|
||||||
|
kernelCompat: true,
|
||||||
|
expected: proxyModeUserspace,
|
||||||
|
},
|
||||||
|
{ // flag says ipvs, required kernel modules are not installed, iptables version too old, fallback on userspace mode
|
||||||
|
flag: "ipvs",
|
||||||
|
kmods: []string{"foo", "bar", "baz"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||||
iptablesVersion: "0.0.0",
|
iptablesVersion: "0.0.0",
|
||||||
kernelCompat: true,
|
kernelCompat: true,
|
||||||
@ -125,7 +147,8 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{ // flag says ipvs, ipset version too low, iptables version too old, kernel not compatible, fallback on userspace mode
|
{ // flag says ipvs, ipset version too low, iptables version too old, kernel not compatible, fallback on userspace mode
|
||||||
flag: "ipvs",
|
flag: "ipvs",
|
||||||
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "0.0",
|
ipsetVersion: "0.0",
|
||||||
iptablesVersion: iptables.MinCheckVersion,
|
iptablesVersion: iptables.MinCheckVersion,
|
||||||
kernelCompat: false,
|
kernelCompat: false,
|
||||||
@ -136,7 +159,10 @@ func Test_getProxyMode(t *testing.T) {
|
|||||||
versioner := &fakeIPTablesVersioner{c.iptablesVersion, c.iptablesError}
|
versioner := &fakeIPTablesVersioner{c.iptablesVersion, c.iptablesError}
|
||||||
kcompater := &fakeKernelCompatTester{c.kernelCompat}
|
kcompater := &fakeKernelCompatTester{c.kernelCompat}
|
||||||
ipsetver := &fakeIPSetVersioner{c.ipsetVersion, c.ipsetError}
|
ipsetver := &fakeIPSetVersioner{c.ipsetVersion, c.ipsetError}
|
||||||
khandler := &fakeKernelHandler{c.kmods}
|
khandler := &fakeKernelHandler{
|
||||||
|
modules: c.kmods,
|
||||||
|
kernelVersion: c.kernelVersion,
|
||||||
|
}
|
||||||
r := getProxyMode(c.flag, versioner, khandler, ipsetver, kcompater)
|
r := getProxyMode(c.flag, versioner, khandler, ipsetver, kcompater)
|
||||||
if r != c.expected {
|
if r != c.expected {
|
||||||
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
|
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
|
||||||
|
@ -74,12 +74,17 @@ func (fake *fakeKernelCompatTester) IsCompatible() error {
|
|||||||
// fakeKernelHandler implements KernelHandler.
|
// fakeKernelHandler implements KernelHandler.
|
||||||
type fakeKernelHandler struct {
|
type fakeKernelHandler struct {
|
||||||
modules []string
|
modules []string
|
||||||
|
kernelVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
|
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
|
||||||
return fake.modules, nil
|
return fake.modules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fake *fakeKernelHandler) GetKernelVersion() (string, error) {
|
||||||
|
return fake.kernelVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
// This test verifies that NewProxyServer does not crash when CleanupAndExit is true.
|
// This test verifies that NewProxyServer does not crash when CleanupAndExit is true.
|
||||||
func TestProxyServerWithCleanupAndExit(t *testing.T) {
|
func TestProxyServerWithCleanupAndExit(t *testing.T) {
|
||||||
// Each bind address below is a separate test case
|
// Each bind address below is a separate test case
|
||||||
|
@ -19,8 +19,10 @@ package ipvs
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -28,13 +30,13 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/klog"
|
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/apimachinery/pkg/util/version"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/tools/record"
|
"k8s.io/client-go/tools/record"
|
||||||
|
"k8s.io/klog"
|
||||||
"k8s.io/kubernetes/pkg/proxy"
|
"k8s.io/kubernetes/pkg/proxy"
|
||||||
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
||||||
"k8s.io/kubernetes/pkg/proxy/metrics"
|
"k8s.io/kubernetes/pkg/proxy/metrics"
|
||||||
@ -473,6 +475,7 @@ func newServiceInfo(port *v1.ServicePort, service *v1.Service, baseInfo *proxy.B
|
|||||||
// KernelHandler can handle the current installed kernel modules.
|
// KernelHandler can handle the current installed kernel modules.
|
||||||
type KernelHandler interface {
|
type KernelHandler interface {
|
||||||
GetModules() ([]string, error)
|
GetModules() ([]string, error)
|
||||||
|
GetKernelVersion() (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinuxKernelHandler implements KernelHandler interface.
|
// LinuxKernelHandler implements KernelHandler interface.
|
||||||
@ -490,11 +493,17 @@ func NewLinuxKernelHandler() *LinuxKernelHandler {
|
|||||||
// GetModules returns all installed kernel modules.
|
// GetModules returns all installed kernel modules.
|
||||||
func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
|
func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
|
||||||
// Check whether IPVS required kernel modules are built-in
|
// Check whether IPVS required kernel modules are built-in
|
||||||
kernelVersion, ipvsModules, err := utilipvs.GetKernelVersionAndIPVSMods(handle.executor)
|
kernelVersionStr, err := handle.GetKernelVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
builtinModsFilePath := fmt.Sprintf("/lib/modules/%s/modules.builtin", kernelVersion)
|
kernelVersion, err := version.ParseGeneric(kernelVersionStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parseing kernel version %q: %v", kernelVersionStr, err)
|
||||||
|
}
|
||||||
|
ipvsModules := utilipvs.GetRequiredIPVSModules(kernelVersion)
|
||||||
|
|
||||||
|
builtinModsFilePath := fmt.Sprintf("/lib/modules/%s/modules.builtin", kernelVersionStr)
|
||||||
b, err := ioutil.ReadFile(builtinModsFilePath)
|
b, err := ioutil.ReadFile(builtinModsFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Warningf("Failed to read file %s with error %v. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules", builtinModsFilePath, err)
|
klog.Warningf("Failed to read file %s with error %v. You can ignore this message when kube-proxy is running inside container without mounting /lib/modules", builtinModsFilePath, err)
|
||||||
@ -516,15 +525,49 @@ func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find out loaded kernel modules
|
// Find out loaded kernel modules
|
||||||
out, err := handle.executor.Command("cut", "-f1", "-d", " ", "/proc/modules").CombinedOutput()
|
modulesFile, err := os.Open("/proc/modules")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mods := strings.Split(string(out), "\n")
|
mods, err := getFirstColumn(modulesFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to find loaded kernel modules: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return append(mods, bmods...), nil
|
return append(mods, bmods...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getFirstColumn reads all the content from r into memory and return a
|
||||||
|
// slice which consists of the first word from each line.
|
||||||
|
func getFirstColumn(r io.Reader) ([]string, error) {
|
||||||
|
b, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := strings.Split(string(b), "\n")
|
||||||
|
words := make([]string, 0, len(lines))
|
||||||
|
for i := range lines {
|
||||||
|
fields := strings.Fields(lines[i])
|
||||||
|
if len(fields) > 0 {
|
||||||
|
words = append(words, fields[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return words, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKernelVersion returns currently running kernel version.
|
||||||
|
func (handle *LinuxKernelHandler) GetKernelVersion() (string, error) {
|
||||||
|
kernelVersionFile := "/proc/sys/kernel/osrelease"
|
||||||
|
fileContent, err := ioutil.ReadFile(kernelVersionFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error reading osrelease file %q: %v", kernelVersionFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(string(fileContent)), nil
|
||||||
|
}
|
||||||
|
|
||||||
// CanUseIPVSProxier returns true if we can use the ipvs Proxier.
|
// CanUseIPVSProxier returns true if we can use the ipvs Proxier.
|
||||||
// This is determined by checking if all the required kernel modules can be loaded. It may
|
// This is determined by checking if all the required kernel modules can be loaded. It may
|
||||||
// return an error if it fails to get the kernel modules information without error, in which
|
// return an error if it fails to get the kernel modules information without error, in which
|
||||||
@ -534,12 +577,21 @@ func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner) (bool, err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("error getting installed ipvs required kernel modules: %v", err)
|
return false, fmt.Errorf("error getting installed ipvs required kernel modules: %v", err)
|
||||||
}
|
}
|
||||||
wantModules := sets.NewString()
|
|
||||||
loadModules := sets.NewString()
|
loadModules := sets.NewString()
|
||||||
linuxKernelHandler := NewLinuxKernelHandler()
|
|
||||||
_, ipvsModules, _ := utilipvs.GetKernelVersionAndIPVSMods(linuxKernelHandler.executor)
|
|
||||||
wantModules.Insert(ipvsModules...)
|
|
||||||
loadModules.Insert(mods...)
|
loadModules.Insert(mods...)
|
||||||
|
|
||||||
|
kernelVersionStr, err := handle.GetKernelVersion()
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error determining kernel version to find required kernel modules for ipvs support: %v", err)
|
||||||
|
}
|
||||||
|
kernelVersion, err := version.ParseGeneric(kernelVersionStr)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("error parseing kernel version %q: %v", kernelVersionStr, err)
|
||||||
|
}
|
||||||
|
mods = utilipvs.GetRequiredIPVSModules(kernelVersion)
|
||||||
|
wantModules := sets.NewString()
|
||||||
|
wantModules.Insert(mods...)
|
||||||
|
|
||||||
modules := wantModules.Difference(loadModules).UnsortedList()
|
modules := wantModules.Difference(loadModules).UnsortedList()
|
||||||
var missingMods []string
|
var missingMods []string
|
||||||
ConntrackiMissingCounter := 0
|
ConntrackiMissingCounter := 0
|
||||||
|
@ -24,15 +24,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/kubernetes/pkg/proxy"
|
|
||||||
"k8s.io/utils/exec"
|
|
||||||
fakeexec "k8s.io/utils/exec/testing"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/kubernetes/pkg/proxy"
|
||||||
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
|
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
|
||||||
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
||||||
proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
|
proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
|
||||||
@ -42,6 +39,8 @@ import (
|
|||||||
iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
|
iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
|
||||||
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
|
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
|
||||||
ipvstest "k8s.io/kubernetes/pkg/util/ipvs/testing"
|
ipvstest "k8s.io/kubernetes/pkg/util/ipvs/testing"
|
||||||
|
"k8s.io/utils/exec"
|
||||||
|
fakeexec "k8s.io/utils/exec/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testHostname = "test-hostname"
|
const testHostname = "test-hostname"
|
||||||
@ -91,12 +90,17 @@ func (fake *fakeHealthChecker) SyncEndpoints(newEndpoints map[types.NamespacedNa
|
|||||||
// fakeKernelHandler implements KernelHandler.
|
// fakeKernelHandler implements KernelHandler.
|
||||||
type fakeKernelHandler struct {
|
type fakeKernelHandler struct {
|
||||||
modules []string
|
modules []string
|
||||||
|
kernelVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
|
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
|
||||||
return fake.modules, nil
|
return fake.modules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fake *fakeKernelHandler) GetKernelVersion() (string, error) {
|
||||||
|
return fake.kernelVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
// fakeKernelHandler implements KernelHandler.
|
// fakeKernelHandler implements KernelHandler.
|
||||||
type fakeIPSetVersioner struct {
|
type fakeIPSetVersioner struct {
|
||||||
version string
|
version string
|
||||||
@ -257,6 +261,7 @@ func TestCleanupLeftovers(t *testing.T) {
|
|||||||
func TestCanUseIPVSProxier(t *testing.T) {
|
func TestCanUseIPVSProxier(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
mods []string
|
mods []string
|
||||||
|
kernelVersion string
|
||||||
kernelErr error
|
kernelErr error
|
||||||
ipsetVersion string
|
ipsetVersion string
|
||||||
ipsetErr error
|
ipsetErr error
|
||||||
@ -265,6 +270,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 0, kernel error
|
// case 0, kernel error
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
kernelErr: fmt.Errorf("oops"),
|
kernelErr: fmt.Errorf("oops"),
|
||||||
ipsetVersion: "0.0",
|
ipsetVersion: "0.0",
|
||||||
ok: false,
|
ok: false,
|
||||||
@ -272,6 +278,7 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 1, ipset error
|
// case 1, ipset error
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ipsetErr: fmt.Errorf("oops"),
|
ipsetErr: fmt.Errorf("oops"),
|
||||||
ok: false,
|
ok: false,
|
||||||
@ -279,41 +286,53 @@ func TestCanUseIPVSProxier(t *testing.T) {
|
|||||||
// case 2, missing required kernel modules and ipset version too low
|
// case 2, missing required kernel modules and ipset version too low
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "1.1",
|
ipsetVersion: "1.1",
|
||||||
ok: false,
|
ok: false,
|
||||||
},
|
},
|
||||||
// case 3, missing required ip_vs_* kernel modules
|
// case 3, missing required ip_vs_* kernel modules
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "a", "bc", "def"},
|
mods: []string{"ip_vs", "a", "bc", "def"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ok: false,
|
ok: false,
|
||||||
},
|
},
|
||||||
// case 4, ipset version too low
|
// case 4, ipset version too low
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "4.3.0",
|
ipsetVersion: "4.3.0",
|
||||||
ok: false,
|
ok: false,
|
||||||
},
|
},
|
||||||
// case 5
|
// case 5, ok for linux kernel 4.19
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
// case 6
|
// case 6, ok for linux kernel 4.18
|
||||||
{
|
{
|
||||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4", "foo", "bar"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
||||||
|
kernelVersion: "4.18",
|
||||||
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
|
ok: true,
|
||||||
|
},
|
||||||
|
// case 7. ok when module list has extra modules
|
||||||
|
{
|
||||||
|
mods: []string{"foo", "ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack", "bar"},
|
||||||
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "6.19",
|
ipsetVersion: "6.19",
|
||||||
ok: true,
|
ok: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range testCases {
|
for i := range testCases {
|
||||||
handle := &fakeKernelHandler{modules: testCases[i].mods}
|
handle := &fakeKernelHandler{modules: testCases[i].mods, kernelVersion: testCases[i].kernelVersion}
|
||||||
versioner := &fakeIPSetVersioner{version: testCases[i].ipsetVersion, err: testCases[i].ipsetErr}
|
versioner := &fakeIPSetVersioner{version: testCases[i].ipsetVersion, err: testCases[i].ipsetErr}
|
||||||
ok, _ := CanUseIPVSProxier(handle, versioner)
|
ok, err := CanUseIPVSProxier(handle, versioner)
|
||||||
if ok != testCases[i].ok {
|
if ok != testCases[i].ok {
|
||||||
t.Errorf("Case [%d], expect %v, got %v", i, testCases[i].ok, ok)
|
t.Errorf("Case [%d], expect %v, got %v: err: %v", i, testCases[i].ok, ok, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3140,3 +3159,33 @@ func TestMultiPortServiceBindAddr(t *testing.T) {
|
|||||||
t.Errorf("Expected number of remaining bound addrs after cleanup to be %v. Got %v", 0, len(remainingAddrs))
|
t.Errorf("Expected number of remaining bound addrs after cleanup to be %v. Got %v", 0, len(remainingAddrs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_getFirstColumn(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
fileContent string
|
||||||
|
want []string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid content",
|
||||||
|
fileContent: `libiscsi_tcp 28672 1 iscsi_tcp, Live 0xffffffffc07ae000
|
||||||
|
libiscsi 57344 3 ib_iser,iscsi_tcp,libiscsi_tcp, Live 0xffffffffc079a000
|
||||||
|
raid10 57344 0 - Live 0xffffffffc0597000`,
|
||||||
|
want: []string{"libiscsi_tcp", "libiscsi", "raid10"},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
got, err := getFirstColumn(strings.NewReader(test.fileContent))
|
||||||
|
if (err != nil) != test.wantErr {
|
||||||
|
t.Errorf("getFirstColumn() error = %v, wantErr %v", err, test.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(got, test.want) {
|
||||||
|
t.Errorf("getFirstColumn() = %v, want %v", got, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -13,7 +13,9 @@ go_test(
|
|||||||
"ipvs_test.go",
|
"ipvs_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = select({
|
deps = [
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||||
|
] + select({
|
||||||
"@io_bazel_rules_go//go/platform:linux": [
|
"@io_bazel_rules_go//go/platform:linux": [
|
||||||
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
||||||
],
|
],
|
||||||
@ -32,11 +34,41 @@ go_library(
|
|||||||
importpath = "k8s.io/kubernetes/pkg/util/ipvs",
|
importpath = "k8s.io/kubernetes/pkg/util/ipvs",
|
||||||
deps = [
|
deps = [
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
|
||||||
] + select({
|
] + select({
|
||||||
|
"@io_bazel_rules_go//go/platform:android": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:darwin": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:dragonfly": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:freebsd": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
"@io_bazel_rules_go//go/platform:linux": [
|
"@io_bazel_rules_go//go/platform:linux": [
|
||||||
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:nacl": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:netbsd": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:openbsd": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:plan9": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:solaris": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
|
],
|
||||||
|
"@io_bazel_rules_go//go/platform:windows": [
|
||||||
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
],
|
],
|
||||||
"//conditions:default": [],
|
"//conditions:default": [],
|
||||||
}),
|
}),
|
||||||
|
@ -19,11 +19,8 @@ package ipvs
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"fmt"
|
|
||||||
"k8s.io/apimachinery/pkg/util/version"
|
"k8s.io/apimachinery/pkg/util/version"
|
||||||
"k8s.io/utils/exec"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface is an injectable interface for running ipvs commands. Implementations must be goroutine-safe.
|
// Interface is an injectable interface for running ipvs commands. Implementations must be goroutine-safe.
|
||||||
@ -74,18 +71,18 @@ const (
|
|||||||
|
|
||||||
// IPVS required kernel modules.
|
// IPVS required kernel modules.
|
||||||
const (
|
const (
|
||||||
// ModIPVS is the kernel module "ip_vs"
|
// KernelModuleIPVS is the kernel module "ip_vs"
|
||||||
ModIPVS string = "ip_vs"
|
KernelModuleIPVS string = "ip_vs"
|
||||||
// ModIPVSRR is the kernel module "ip_vs_rr"
|
// KernelModuleIPVSRR is the kernel module "ip_vs_rr"
|
||||||
ModIPVSRR string = "ip_vs_rr"
|
KernelModuleIPVSRR string = "ip_vs_rr"
|
||||||
// ModIPVSWRR is the kernel module "ip_vs_wrr"
|
// KernelModuleIPVSWRR is the kernel module "ip_vs_wrr"
|
||||||
ModIPVSWRR string = "ip_vs_wrr"
|
KernelModuleIPVSWRR string = "ip_vs_wrr"
|
||||||
// ModIPVSSH is the kernel module "ip_vs_sh"
|
// KernelModuleIPVSSH is the kernel module "ip_vs_sh"
|
||||||
ModIPVSSH string = "ip_vs_sh"
|
KernelModuleIPVSSH string = "ip_vs_sh"
|
||||||
// ModNfConntrackIPV4 is the module "nf_conntrack_ipv4"
|
// KernelModuleNfConntrackIPV4 is the module "nf_conntrack_ipv4"
|
||||||
ModNfConntrackIPV4 string = "nf_conntrack_ipv4"
|
KernelModuleNfConntrackIPV4 string = "nf_conntrack_ipv4"
|
||||||
// ModNfConntrack is the kernel module "nf_conntrack"
|
// KernelModuleNfConntrack is the kernel module "nf_conntrack"
|
||||||
ModNfConntrack string = "nf_conntrack"
|
KernelModuleNfConntrack string = "nf_conntrack"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Equal check the equality of virtual server.
|
// Equal check the equality of virtual server.
|
||||||
@ -123,28 +120,13 @@ func (rs *RealServer) Equal(other *RealServer) bool {
|
|||||||
rs.Port == other.Port
|
rs.Port == other.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKernelVersionAndIPVSMods returns the linux kernel version and the required ipvs modules
|
// GetRequiredIPVSModules returns the required ipvs modules for the given linux kernel version.
|
||||||
func GetKernelVersionAndIPVSMods(Executor exec.Interface) (kernelVersion string, ipvsModules []string, err error) {
|
func GetRequiredIPVSModules(kernelVersion *version.Version) []string {
|
||||||
kernelVersionFile := "/proc/sys/kernel/osrelease"
|
|
||||||
out, err := Executor.Command("cut", "-f1", "-d", " ", kernelVersionFile).CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("error getting os release kernel version: %v(%s)", err, out)
|
|
||||||
}
|
|
||||||
kernelVersion = strings.TrimSpace(string(out))
|
|
||||||
// parse kernel version
|
|
||||||
ver1, err := version.ParseGeneric(kernelVersion)
|
|
||||||
if err != nil {
|
|
||||||
return kernelVersion, nil, fmt.Errorf("error parsing kernel version: %v(%s)", err, kernelVersion)
|
|
||||||
}
|
|
||||||
// "nf_conntrack_ipv4" has been removed since v4.19
|
// "nf_conntrack_ipv4" has been removed since v4.19
|
||||||
// see https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
|
// see https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
|
||||||
ver2, _ := version.ParseGeneric("4.19")
|
if kernelVersion.LessThan(version.MustParseGeneric("4.19")) {
|
||||||
// get required ipvs modules
|
return []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrackIPV4}
|
||||||
if ver1.LessThan(ver2) {
|
|
||||||
ipvsModules = append(ipvsModules, ModIPVS, ModIPVSRR, ModIPVSWRR, ModIPVSSH, ModNfConntrackIPV4)
|
|
||||||
} else {
|
|
||||||
ipvsModules = append(ipvsModules, ModIPVS, ModIPVSRR, ModIPVSWRR, ModIPVSSH, ModNfConntrack)
|
|
||||||
}
|
}
|
||||||
|
return []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrack}
|
||||||
|
|
||||||
return kernelVersion, ipvsModules, nil
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,11 @@ package ipvs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/util/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVirtualServerEqual(t *testing.T) {
|
func TestVirtualServerEqual(t *testing.T) {
|
||||||
@ -380,3 +384,32 @@ func TestFrontendDestinationString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetRequiredIPVSModules(t *testing.T) {
|
||||||
|
Tests := []struct {
|
||||||
|
name string
|
||||||
|
kernelVersion *version.Version
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "kernel version < 4.19",
|
||||||
|
kernelVersion: version.MustParseGeneric("4.18"),
|
||||||
|
want: []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrackIPV4},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "kernel version 4.19",
|
||||||
|
kernelVersion: version.MustParseGeneric("4.19"),
|
||||||
|
want: []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrack},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range Tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
got := GetRequiredIPVSModules(test.kernelVersion)
|
||||||
|
sort.Strings(got)
|
||||||
|
sort.Strings(test.want)
|
||||||
|
if !reflect.DeepEqual(got, test.want) {
|
||||||
|
t.Errorf("GetRequiredIPVSMods() = %v for kenel version: %s, want %v", got, test.kernelVersion, test.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user