mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +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
|
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"},
|
||||||
ipsetVersion: ipvs.MinIPSetCheckVersion,
|
kernelVersion: "4.18",
|
||||||
expected: proxyModeIPVS,
|
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 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)
|
||||||
|
@ -73,13 +73,18 @@ 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"
|
||||||
@ -90,13 +89,18 @@ 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
|
||||||
@ -256,64 +260,79 @@ func TestCleanupLeftovers(t *testing.T) {
|
|||||||
|
|
||||||
func TestCanUseIPVSProxier(t *testing.T) {
|
func TestCanUseIPVSProxier(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
mods []string
|
mods []string
|
||||||
kernelErr error
|
kernelVersion string
|
||||||
ipsetVersion string
|
kernelErr error
|
||||||
ipsetErr error
|
ipsetVersion string
|
||||||
ok bool
|
ipsetErr error
|
||||||
|
ok bool
|
||||||
}{
|
}{
|
||||||
// case 0, kernel error
|
// case 0, kernel error
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
kernelErr: fmt.Errorf("oops"),
|
kernelVersion: "4.19",
|
||||||
ipsetVersion: "0.0",
|
kernelErr: fmt.Errorf("oops"),
|
||||||
ok: false,
|
ipsetVersion: "0.0",
|
||||||
|
ok: false,
|
||||||
},
|
},
|
||||||
// case 1, ipset error
|
// case 1, ipset error
|
||||||
{
|
{
|
||||||
mods: []string{"foo", "bar", "baz"},
|
mods: []string{"foo", "bar", "baz"},
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
kernelVersion: "4.19",
|
||||||
ipsetErr: fmt.Errorf("oops"),
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
ok: false,
|
ipsetErr: fmt.Errorf("oops"),
|
||||||
|
ok: false,
|
||||||
},
|
},
|
||||||
// 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"},
|
||||||
ipsetVersion: "1.1",
|
kernelVersion: "4.19",
|
||||||
ok: false,
|
ipsetVersion: "1.1",
|
||||||
|
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"},
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
kernelVersion: "4.19",
|
||||||
ok: false,
|
ipsetVersion: MinIPSetCheckVersion,
|
||||||
|
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"},
|
||||||
ipsetVersion: "4.3.0",
|
kernelVersion: "4.19",
|
||||||
ok: false,
|
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"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack"},
|
||||||
ipsetVersion: MinIPSetCheckVersion,
|
kernelVersion: "4.19",
|
||||||
ok: true,
|
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"},
|
mods: []string{"ip_vs", "ip_vs_rr", "ip_vs_wrr", "ip_vs_sh", "nf_conntrack_ipv4"},
|
||||||
ipsetVersion: "6.19",
|
kernelVersion: "4.18",
|
||||||
ok: true,
|
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 {
|
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