mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +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
|
||||
ipsetVersion string
|
||||
kmods []string
|
||||
kernelVersion string
|
||||
kernelCompat bool
|
||||
iptablesError error
|
||||
ipsetError error
|
||||
@ -85,15 +86,24 @@ func Test_getProxyMode(t *testing.T) {
|
||||
kernelCompat: true,
|
||||
expected: proxyModeIPTables,
|
||||
},
|
||||
{ // flag says ipvs, ipset version ok, kernel modules installed
|
||||
flag: "ipvs",
|
||||
kmods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
||||
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||
expected: proxyModeIPVS,
|
||||
{ // flag says ipvs, ipset version ok, kernel modules installed for linux kernel before 4.19
|
||||
flag: "ipvs",
|
||||
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,
|
||||
expected: proxyModeIPVS,
|
||||
},
|
||||
{ // flag says ipvs, ipset version too low, fallback on iptables mode
|
||||
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",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
kernelCompat: true,
|
||||
@ -101,7 +111,8 @@ func Test_getProxyMode(t *testing.T) {
|
||||
},
|
||||
{ // flag says ipvs, bad ipset version, fallback on iptables mode
|
||||
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",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
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: "ipvs",
|
||||
kmods: []string{"foo", "bar", "baz"},
|
||||
kernelVersion: "4.19",
|
||||
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
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: "ipvs",
|
||||
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,
|
||||
iptablesVersion: "0.0.0",
|
||||
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: "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",
|
||||
iptablesVersion: iptables.MinCheckVersion,
|
||||
kernelCompat: false,
|
||||
@ -136,7 +159,10 @@ func Test_getProxyMode(t *testing.T) {
|
||||
versioner := &fakeIPTablesVersioner{c.iptablesVersion, c.iptablesError}
|
||||
kcompater := &fakeKernelCompatTester{c.kernelCompat}
|
||||
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)
|
||||
if r != c.expected {
|
||||
t.Errorf("Case[%d] Expected %q, got %q", i, c.expected, r)
|
||||
|
@ -73,13 +73,18 @@ func (fake *fakeKernelCompatTester) IsCompatible() error {
|
||||
|
||||
// fakeKernelHandler implements KernelHandler.
|
||||
type fakeKernelHandler struct {
|
||||
modules []string
|
||||
modules []string
|
||||
kernelVersion string
|
||||
}
|
||||
|
||||
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
|
||||
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.
|
||||
func TestProxyServerWithCleanupAndExit(t *testing.T) {
|
||||
// Each bind address below is a separate test case
|
||||
|
@ -19,8 +19,10 @@ package ipvs
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -28,13 +30,13 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"k8s.io/klog"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/tools/record"
|
||||
"k8s.io/klog"
|
||||
"k8s.io/kubernetes/pkg/proxy"
|
||||
"k8s.io/kubernetes/pkg/proxy/healthcheck"
|
||||
"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.
|
||||
type KernelHandler interface {
|
||||
GetModules() ([]string, error)
|
||||
GetKernelVersion() (string, error)
|
||||
}
|
||||
|
||||
// LinuxKernelHandler implements KernelHandler interface.
|
||||
@ -490,11 +493,17 @@ func NewLinuxKernelHandler() *LinuxKernelHandler {
|
||||
// GetModules returns all installed kernel modules.
|
||||
func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
|
||||
// Check whether IPVS required kernel modules are built-in
|
||||
kernelVersion, ipvsModules, err := utilipvs.GetKernelVersionAndIPVSMods(handle.executor)
|
||||
kernelVersionStr, err := handle.GetKernelVersion()
|
||||
if err != nil {
|
||||
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)
|
||||
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)
|
||||
@ -516,15 +525,49 @@ func (handle *LinuxKernelHandler) GetModules() ([]string, error) {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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
|
||||
@ -534,12 +577,21 @@ func CanUseIPVSProxier(handle KernelHandler, ipsetver IPSetVersioner) (bool, err
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error getting installed ipvs required kernel modules: %v", err)
|
||||
}
|
||||
wantModules := sets.NewString()
|
||||
loadModules := sets.NewString()
|
||||
linuxKernelHandler := NewLinuxKernelHandler()
|
||||
_, ipvsModules, _ := utilipvs.GetKernelVersionAndIPVSMods(linuxKernelHandler.executor)
|
||||
wantModules.Insert(ipvsModules...)
|
||||
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()
|
||||
var missingMods []string
|
||||
ConntrackiMissingCounter := 0
|
||||
|
@ -24,15 +24,12 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"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/kubernetes/pkg/proxy"
|
||||
netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing"
|
||||
utilproxy "k8s.io/kubernetes/pkg/proxy/util"
|
||||
proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing"
|
||||
@ -42,6 +39,8 @@ import (
|
||||
iptablestest "k8s.io/kubernetes/pkg/util/iptables/testing"
|
||||
utilipvs "k8s.io/kubernetes/pkg/util/ipvs"
|
||||
ipvstest "k8s.io/kubernetes/pkg/util/ipvs/testing"
|
||||
"k8s.io/utils/exec"
|
||||
fakeexec "k8s.io/utils/exec/testing"
|
||||
)
|
||||
|
||||
const testHostname = "test-hostname"
|
||||
@ -90,13 +89,18 @@ func (fake *fakeHealthChecker) SyncEndpoints(newEndpoints map[types.NamespacedNa
|
||||
|
||||
// fakeKernelHandler implements KernelHandler.
|
||||
type fakeKernelHandler struct {
|
||||
modules []string
|
||||
modules []string
|
||||
kernelVersion string
|
||||
}
|
||||
|
||||
func (fake *fakeKernelHandler) GetModules() ([]string, error) {
|
||||
return fake.modules, nil
|
||||
}
|
||||
|
||||
func (fake *fakeKernelHandler) GetKernelVersion() (string, error) {
|
||||
return fake.kernelVersion, nil
|
||||
}
|
||||
|
||||
// fakeKernelHandler implements KernelHandler.
|
||||
type fakeIPSetVersioner struct {
|
||||
version string
|
||||
@ -256,64 +260,79 @@ func TestCleanupLeftovers(t *testing.T) {
|
||||
|
||||
func TestCanUseIPVSProxier(t *testing.T) {
|
||||
testCases := []struct {
|
||||
mods []string
|
||||
kernelErr error
|
||||
ipsetVersion string
|
||||
ipsetErr error
|
||||
ok bool
|
||||
mods []string
|
||||
kernelVersion string
|
||||
kernelErr error
|
||||
ipsetVersion string
|
||||
ipsetErr error
|
||||
ok bool
|
||||
}{
|
||||
// case 0, kernel error
|
||||
{
|
||||
mods: []string{"foo", "bar", "baz"},
|
||||
kernelErr: fmt.Errorf("oops"),
|
||||
ipsetVersion: "0.0",
|
||||
ok: false,
|
||||
mods: []string{"foo", "bar", "baz"},
|
||||
kernelVersion: "4.19",
|
||||
kernelErr: fmt.Errorf("oops"),
|
||||
ipsetVersion: "0.0",
|
||||
ok: false,
|
||||
},
|
||||
// case 1, ipset error
|
||||
{
|
||||
mods: []string{"foo", "bar", "baz"},
|
||||
ipsetVersion: MinIPSetCheckVersion,
|
||||
ipsetErr: fmt.Errorf("oops"),
|
||||
ok: false,
|
||||
mods: []string{"foo", "bar", "baz"},
|
||||
kernelVersion: "4.19",
|
||||
ipsetVersion: MinIPSetCheckVersion,
|
||||
ipsetErr: fmt.Errorf("oops"),
|
||||
ok: false,
|
||||
},
|
||||
// case 2, missing required kernel modules and ipset version too low
|
||||
{
|
||||
mods: []string{"foo", "bar", "baz"},
|
||||
ipsetVersion: "1.1",
|
||||
ok: false,
|
||||
mods: []string{"foo", "bar", "baz"},
|
||||
kernelVersion: "4.19",
|
||||
ipsetVersion: "1.1",
|
||||
ok: false,
|
||||
},
|
||||
// case 3, missing required ip_vs_* kernel modules
|
||||
{
|
||||
mods: []string{"ip_vs", "a", "bc", "def"},
|
||||
ipsetVersion: MinIPSetCheckVersion,
|
||||
ok: false,
|
||||
mods: []string{"ip_vs", "a", "bc", "def"},
|
||||
kernelVersion: "4.19",
|
||||
ipsetVersion: MinIPSetCheckVersion,
|
||||
ok: false,
|
||||
},
|
||||
// case 4, ipset version too low
|
||||
{
|
||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
||||
ipsetVersion: "4.3.0",
|
||||
ok: false,
|
||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||
kernelVersion: "4.19",
|
||||
ipsetVersion: "4.3.0",
|
||||
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"},
|
||||
ipsetVersion: MinIPSetCheckVersion,
|
||||
ok: true,
|
||||
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||
kernelVersion: "4.19",
|
||||
ipsetVersion: MinIPSetCheckVersion,
|
||||
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"},
|
||||
ipsetVersion: "6.19",
|
||||
ok: true,
|
||||
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",
|
||||
ok: true,
|
||||
},
|
||||
}
|
||||
|
||||
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}
|
||||
ok, _ := CanUseIPVSProxier(handle, versioner)
|
||||
ok, err := CanUseIPVSProxier(handle, versioner)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
],
|
||||
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": [
|
||||
"//vendor/github.com/docker/libnetwork/ipvs:go_default_library",
|
||||
],
|
||||
@ -32,11 +34,41 @@ go_library(
|
||||
importpath = "k8s.io/kubernetes/pkg/util/ipvs",
|
||||
deps = [
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/version:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
] + 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": [
|
||||
"//vendor/github.com/docker/libnetwork/ipvs: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": [],
|
||||
}),
|
||||
|
@ -19,11 +19,8 @@ package ipvs
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/utils/exec"
|
||||
)
|
||||
|
||||
// Interface is an injectable interface for running ipvs commands. Implementations must be goroutine-safe.
|
||||
@ -74,18 +71,18 @@ const (
|
||||
|
||||
// IPVS required kernel modules.
|
||||
const (
|
||||
// ModIPVS is the kernel module "ip_vs"
|
||||
ModIPVS string = "ip_vs"
|
||||
// ModIPVSRR is the kernel module "ip_vs_rr"
|
||||
ModIPVSRR string = "ip_vs_rr"
|
||||
// ModIPVSWRR is the kernel module "ip_vs_wrr"
|
||||
ModIPVSWRR string = "ip_vs_wrr"
|
||||
// ModIPVSSH is the kernel module "ip_vs_sh"
|
||||
ModIPVSSH string = "ip_vs_sh"
|
||||
// ModNfConntrackIPV4 is the module "nf_conntrack_ipv4"
|
||||
ModNfConntrackIPV4 string = "nf_conntrack_ipv4"
|
||||
// ModNfConntrack is the kernel module "nf_conntrack"
|
||||
ModNfConntrack string = "nf_conntrack"
|
||||
// KernelModuleIPVS is the kernel module "ip_vs"
|
||||
KernelModuleIPVS string = "ip_vs"
|
||||
// KernelModuleIPVSRR is the kernel module "ip_vs_rr"
|
||||
KernelModuleIPVSRR string = "ip_vs_rr"
|
||||
// KernelModuleIPVSWRR is the kernel module "ip_vs_wrr"
|
||||
KernelModuleIPVSWRR string = "ip_vs_wrr"
|
||||
// KernelModuleIPVSSH is the kernel module "ip_vs_sh"
|
||||
KernelModuleIPVSSH string = "ip_vs_sh"
|
||||
// KernelModuleNfConntrackIPV4 is the module "nf_conntrack_ipv4"
|
||||
KernelModuleNfConntrackIPV4 string = "nf_conntrack_ipv4"
|
||||
// KernelModuleNfConntrack is the kernel module "nf_conntrack"
|
||||
KernelModuleNfConntrack string = "nf_conntrack"
|
||||
)
|
||||
|
||||
// Equal check the equality of virtual server.
|
||||
@ -123,28 +120,13 @@ func (rs *RealServer) Equal(other *RealServer) bool {
|
||||
rs.Port == other.Port
|
||||
}
|
||||
|
||||
// GetKernelVersionAndIPVSMods returns the linux kernel version and the required ipvs modules
|
||||
func GetKernelVersionAndIPVSMods(Executor exec.Interface) (kernelVersion string, ipvsModules []string, err error) {
|
||||
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)
|
||||
}
|
||||
// GetRequiredIPVSModules returns the required ipvs modules for the given linux kernel version.
|
||||
func GetRequiredIPVSModules(kernelVersion *version.Version) []string {
|
||||
// "nf_conntrack_ipv4" has been removed since v4.19
|
||||
// see https://github.com/torvalds/linux/commit/a0ae2562c6c4b2721d9fddba63b7286c13517d9f
|
||||
ver2, _ := version.ParseGeneric("4.19")
|
||||
// get required ipvs modules
|
||||
if ver1.LessThan(ver2) {
|
||||
ipvsModules = append(ipvsModules, ModIPVS, ModIPVSRR, ModIPVSWRR, ModIPVSSH, ModNfConntrackIPV4)
|
||||
} else {
|
||||
ipvsModules = append(ipvsModules, ModIPVS, ModIPVSRR, ModIPVSWRR, ModIPVSSH, ModNfConntrack)
|
||||
if kernelVersion.LessThan(version.MustParseGeneric("4.19")) {
|
||||
return []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrackIPV4}
|
||||
}
|
||||
return []string{KernelModuleIPVS, KernelModuleIPVSRR, KernelModuleIPVSWRR, KernelModuleIPVSSH, KernelModuleNfConntrack}
|
||||
|
||||
return kernelVersion, ipvsModules, nil
|
||||
}
|
||||
|
@ -18,7 +18,11 @@ package ipvs
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
)
|
||||
|
||||
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