mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
kubeadm: skip ipv4 check if the cluster is using IPv6 address
Signed-off-by: Dave Chen <dave.chen@arm.com>
This commit is contained in:
parent
7b243cef1a
commit
66f043f650
@ -883,15 +883,11 @@ func (MemCheck) Name() string {
|
|||||||
return "Mem"
|
return "Mem"
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunInitNodeChecks executes all individual, applicable to control-plane node checks.
|
func InitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfiguration, ignorePreflightErrors sets.Set[string], isSecondaryControlPlane bool, downloadCerts bool) ([]Checker, error) {
|
||||||
// The boolean flag 'isSecondaryControlPlane' controls whether we are running checks in a --join-control-plane scenario.
|
|
||||||
// The boolean flag 'downloadCerts' controls whether we should skip checks on certificates because we are downloading them.
|
|
||||||
// If the flag is set to true we should skip checks already executed by RunJoinNodeChecks.
|
|
||||||
func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfiguration, ignorePreflightErrors sets.Set[string], isSecondaryControlPlane bool, downloadCerts bool) error {
|
|
||||||
if !isSecondaryControlPlane {
|
if !isSecondaryControlPlane {
|
||||||
// First, check if we're root separately from the other preflight checks and fail fast
|
// First, check if we're root separately from the other preflight checks and fail fast
|
||||||
if err := RunRootCheckOnly(ignorePreflightErrors); err != nil {
|
if err := RunRootCheckOnly(ignorePreflightErrors); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -912,13 +908,36 @@ func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfigura
|
|||||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, manifestsDir)},
|
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, manifestsDir)},
|
||||||
HTTPProxyCheck{Proto: "https", Host: cfg.LocalAPIEndpoint.AdvertiseAddress},
|
HTTPProxyCheck{Proto: "https", Host: cfg.LocalAPIEndpoint.AdvertiseAddress},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File content check for IPV4 and IPV6 are needed if it is:
|
||||||
|
// (dual stack) `--service-cidr` or `--pod-network-cidr` is set with an IPV4 and IPV6 CIDR, `--apiserver-advertise-address` is optional as it can be auto detected.
|
||||||
|
// (single stack) which is decided by the `--apiserver-advertise-address`.
|
||||||
|
// Note that for the case of dual stack, user might only give IPV6 CIDR for `--service-cidr` and leave the `--apiserver-advertise-address` a default value which will be
|
||||||
|
// auto detected and properly bound to an IPV4 address, this will make the cluster non-functional eventually. The case like this should be avoided by the validation instead,
|
||||||
|
// i.e. We don't care whether the input values for those parameters are set correctly here but if it's an IPV4 scoped CIDR or address we will add the file content check for IPV4,
|
||||||
|
// as does the IPV6.
|
||||||
|
IPV4Check := false
|
||||||
|
IPV6Check := false
|
||||||
cidrs := strings.Split(cfg.Networking.ServiceSubnet, ",")
|
cidrs := strings.Split(cfg.Networking.ServiceSubnet, ",")
|
||||||
for _, cidr := range cidrs {
|
for _, cidr := range cidrs {
|
||||||
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
|
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
|
||||||
|
if !IPV4Check && netutils.IsIPv4CIDRString(cidr) {
|
||||||
|
IPV4Check = true
|
||||||
|
}
|
||||||
|
if !IPV6Check && netutils.IsIPv6CIDRString(cidr) {
|
||||||
|
IPV6Check = true
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
cidrs = strings.Split(cfg.Networking.PodSubnet, ",")
|
cidrs = strings.Split(cfg.Networking.PodSubnet, ",")
|
||||||
for _, cidr := range cidrs {
|
for _, cidr := range cidrs {
|
||||||
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
|
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
|
||||||
|
if !IPV4Check && netutils.IsIPv4CIDRString(cidr) {
|
||||||
|
IPV4Check = true
|
||||||
|
}
|
||||||
|
if !IPV6Check && netutils.IsIPv6CIDRString(cidr) {
|
||||||
|
IPV6Check = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isSecondaryControlPlane {
|
if !isSecondaryControlPlane {
|
||||||
@ -926,9 +945,19 @@ func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfigura
|
|||||||
|
|
||||||
// Check if Bridge-netfilter and IPv6 relevant flags are set
|
// Check if Bridge-netfilter and IPv6 relevant flags are set
|
||||||
if ip := netutils.ParseIPSloppy(cfg.LocalAPIEndpoint.AdvertiseAddress); ip != nil {
|
if ip := netutils.ParseIPSloppy(cfg.LocalAPIEndpoint.AdvertiseAddress); ip != nil {
|
||||||
if netutils.IsIPv6(ip) {
|
if !IPV4Check && netutils.IsIPv4(ip) {
|
||||||
checks = addIPv6Checks(checks)
|
IPV4Check = true
|
||||||
}
|
}
|
||||||
|
if !IPV6Check && netutils.IsIPv6(ip) {
|
||||||
|
IPV6Check = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if IPV4Check {
|
||||||
|
checks = addIPv4Checks(checks)
|
||||||
|
}
|
||||||
|
if IPV6Check {
|
||||||
|
checks = addIPv6Checks(checks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if using an external etcd
|
// if using an external etcd
|
||||||
@ -959,15 +988,25 @@ func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfigura
|
|||||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.KeyFile, Label: "ExternalEtcdClientCertificates"})
|
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.KeyFile, Label: "ExternalEtcdClientCertificates"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return checks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunInitNodeChecks executes all individual, applicable to control-plane node checks.
|
||||||
|
// The boolean flag 'isSecondaryControlPlane' controls whether we are running checks in a --join-control-plane scenario.
|
||||||
|
// The boolean flag 'downloadCerts' controls whether we should skip checks on certificates because we are downloading them.
|
||||||
|
// If the flag is set to true we should skip checks already executed by RunJoinNodeChecks.
|
||||||
|
func RunInitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfiguration, ignorePreflightErrors sets.Set[string], isSecondaryControlPlane bool, downloadCerts bool) error {
|
||||||
|
checks, err := InitNodeChecks(execer, cfg, ignorePreflightErrors, isSecondaryControlPlane, downloadCerts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunJoinNodeChecks executes all individual, applicable to node checks.
|
func JoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfiguration, ignorePreflightErrors sets.Set[string]) ([]Checker, error) {
|
||||||
func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfiguration, ignorePreflightErrors sets.Set[string]) error {
|
|
||||||
// First, check if we're root separately from the other preflight checks and fail fast
|
// First, check if we're root separately from the other preflight checks and fail fast
|
||||||
if err := RunRootCheckOnly(ignorePreflightErrors); err != nil {
|
if err := RunRootCheckOnly(ignorePreflightErrors); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
checks := []Checker{
|
checks := []Checker{
|
||||||
@ -986,13 +1025,24 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfigura
|
|||||||
HTTPProxyCheck{Proto: "https", Host: ipstr},
|
HTTPProxyCheck{Proto: "https", Host: ipstr},
|
||||||
)
|
)
|
||||||
if ip := netutils.ParseIPSloppy(ipstr); ip != nil {
|
if ip := netutils.ParseIPSloppy(ipstr); ip != nil {
|
||||||
|
if netutils.IsIPv4(ip) {
|
||||||
|
checks = addIPv4Checks(checks)
|
||||||
|
}
|
||||||
if netutils.IsIPv6(ip) {
|
if netutils.IsIPv6(ip) {
|
||||||
checks = addIPv6Checks(checks)
|
checks = addIPv6Checks(checks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return checks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunJoinNodeChecks executes all individual, applicable to node checks.
|
||||||
|
func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfiguration, ignorePreflightErrors sets.Set[string]) error {
|
||||||
|
checks, err := JoinNodeChecks(execer, cfg, ignorePreflightErrors)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1007,7 +1057,6 @@ func addCommonChecks(execer utilsexec.Interface, k8sVersion string, nodeReg *kub
|
|||||||
}
|
}
|
||||||
|
|
||||||
// non-windows checks
|
// non-windows checks
|
||||||
checks = addIPv4Checks(checks)
|
|
||||||
checks = addSwapCheck(checks)
|
checks = addSwapCheck(checks)
|
||||||
checks = addExecChecks(checks, execer)
|
checks = addExecChecks(checks, execer)
|
||||||
checks = append(checks,
|
checks = append(checks,
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/lithammer/dedent"
|
"github.com/lithammer/dedent"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@ -36,7 +37,9 @@ import (
|
|||||||
fakeexec "k8s.io/utils/exec/testing"
|
fakeexec "k8s.io/utils/exec/testing"
|
||||||
|
|
||||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||||
|
kubeadmapiv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
|
||||||
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
"k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||||
|
configutil "k8s.io/kubernetes/cmd/kubeadm/app/util/config"
|
||||||
utilruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime"
|
utilruntime "k8s.io/kubernetes/cmd/kubeadm/app/util/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1005,3 +1008,134 @@ func TestMemCheck(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInitIPCheck(t *testing.T) {
|
||||||
|
// skip this test, if OS in not Linux, since it will ONLY pass on Linux.
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
t.Skip("unsupported OS")
|
||||||
|
}
|
||||||
|
// should be a privileged user for the `init` command, otherwise just skip it.
|
||||||
|
isPrivileged := IsPrivilegedUserCheck{}
|
||||||
|
if _, err := isPrivileged.Check(); err != nil {
|
||||||
|
t.Skip("not a privileged user")
|
||||||
|
}
|
||||||
|
internalcfg, err := configutil.DefaultedStaticInitConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected failure when defaulting InitConfiguration: %v", err)
|
||||||
|
}
|
||||||
|
internalcfg.LocalAPIEndpoint.AdvertiseAddress = "" // AdvertiseAddress is optional, it could be auto-detected.
|
||||||
|
ipv4File := "FileContent--proc-sys-net-ipv4-ip_forward"
|
||||||
|
ipv6File := "FileContent--proc-sys-net-ipv6-conf-default-forwarding"
|
||||||
|
var tests = []struct {
|
||||||
|
testName string
|
||||||
|
PodSubnet string
|
||||||
|
serviceCidr string
|
||||||
|
expStr []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testName: "dual stack",
|
||||||
|
PodSubnet: "fda9:d324:354d:0::/56",
|
||||||
|
serviceCidr: "10.96.0.0/16,fda9:d324:354d:1::/112",
|
||||||
|
expStr: []string{"FileContent--proc-sys-net-ipv4-ip_forward", "FileContent--proc-sys-net-ipv6-conf-default-forwarding"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "single stack ipv4",
|
||||||
|
PodSubnet: "10.244.0.0/16",
|
||||||
|
serviceCidr: "10.96.0.0/16",
|
||||||
|
expStr: []string{"FileContent--proc-sys-net-ipv4-ip_forward"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "single stack ipv6",
|
||||||
|
PodSubnet: "fda9:d324:354d:0::/56",
|
||||||
|
serviceCidr: "fda9:d324:354d:1::/112",
|
||||||
|
expStr: []string{"FileContent--proc-sys-net-ipv6-conf-default-forwarding"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rt := range tests {
|
||||||
|
t.Run(rt.testName, func(t *testing.T) {
|
||||||
|
checkList := []string{}
|
||||||
|
internalcfg.Networking.ServiceSubnet = rt.serviceCidr
|
||||||
|
internalcfg.Networking.PodSubnet = rt.PodSubnet
|
||||||
|
checks, err := InitNodeChecks(exec.New(), internalcfg, nil, false, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
for _, check := range checks {
|
||||||
|
if check.Name() == ipv4File {
|
||||||
|
checkList = append(checkList, ipv4File)
|
||||||
|
}
|
||||||
|
if check.Name() == ipv6File {
|
||||||
|
checkList = append(checkList, ipv6File)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(checkList, rt.expStr); diff != "" {
|
||||||
|
t.Fatalf("unexpected file content check (-want,+got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJoinIPCheck(t *testing.T) {
|
||||||
|
// skip this test, if OS in not Linux, since it will ONLY pass on Linux.
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
t.Skip("unsupported OS")
|
||||||
|
}
|
||||||
|
// should be a privileged user for the `join` command, otherwise just skip it.
|
||||||
|
isPrivileged := IsPrivilegedUserCheck{}
|
||||||
|
if _, err := isPrivileged.Check(); err != nil {
|
||||||
|
t.Skip("not a privileged user")
|
||||||
|
}
|
||||||
|
internalcfg, err := configutil.DefaultedJoinConfiguration(&kubeadmapiv1.JoinConfiguration{
|
||||||
|
Discovery: kubeadmapiv1.Discovery{
|
||||||
|
BootstrapToken: &kubeadmapiv1.BootstrapTokenDiscovery{
|
||||||
|
Token: configutil.PlaceholderToken.Token.String(),
|
||||||
|
APIServerEndpoint: "kube-apiserver:6443",
|
||||||
|
UnsafeSkipCAVerification: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected failure when defaulting JoinConfiguration: %v", err)
|
||||||
|
}
|
||||||
|
ipv4File := "FileContent--proc-sys-net-ipv4-ip_forward"
|
||||||
|
ipv6File := "FileContent--proc-sys-net-ipv6-conf-default-forwarding"
|
||||||
|
var tests = []struct {
|
||||||
|
testName string
|
||||||
|
endpoint string
|
||||||
|
expStr []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
testName: "single stack ipv4",
|
||||||
|
endpoint: "10.244.0.0:1234",
|
||||||
|
expStr: []string{"FileContent--proc-sys-net-ipv4-ip_forward"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
testName: "single stack ipv6",
|
||||||
|
endpoint: "[fda9:d324:354d:0::]:1234",
|
||||||
|
expStr: []string{"FileContent--proc-sys-net-ipv6-conf-default-forwarding"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rt := range tests {
|
||||||
|
t.Run(rt.testName, func(t *testing.T) {
|
||||||
|
checkList := []string{}
|
||||||
|
internalcfg.Discovery.BootstrapToken.APIServerEndpoint = rt.endpoint
|
||||||
|
checks, err := JoinNodeChecks(exec.New(), internalcfg, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
for _, check := range checks {
|
||||||
|
if check.Name() == ipv4File {
|
||||||
|
checkList = append(checkList, ipv4File)
|
||||||
|
}
|
||||||
|
if check.Name() == ipv6File {
|
||||||
|
checkList = append(checkList, ipv6File)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(checkList, rt.expStr); diff != "" {
|
||||||
|
t.Fatalf("unexpected file content check (-want,+got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user