Merge pull request #80636 from ebati/issue-80504-test-kubeproxy-mac

Add GetKernelVersion to ipvs.KernelHandler interface
This commit is contained in:
Kubernetes Prow Robot 2019-07-31 16:56:13 -07:00 committed by GitHub
commit 59142b231c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 275 additions and 96 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)
}
})
}
}

View File

@ -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": [],
}), }),

View File

@ -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
} }

View File

@ -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)
}
})
}
}