mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Add GetKernelVersion to ipvs.KernelHandler interface
ipvs `getProxyMode` test fails on mac as `utilipvs.GetRequiredIPVSMods` try to reach `/proc/sys/kernel/osrelease` to find version of the running linux kernel. Linux kernel version is used to determine the list of required kernel modules for ipvs. Logic to determine kernel version is moved to GetKernelVersion method in LinuxKernelHandler which implements ipvs.KernelHandler. Mock KernelHandler is used in the test cases. Read and parse file is converted to go function instead of execing cut.
This commit is contained in:
parent
a9a68c5e44
commit
90ce2d50d3
@ -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