mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
vendor update for CSI 0.3.0
This commit is contained in:
10
vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/BUILD
generated
vendored
10
vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/BUILD
generated
vendored
@ -49,21 +49,19 @@ go_library(
|
||||
}),
|
||||
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/preflight",
|
||||
deps = [
|
||||
"//cmd/kube-apiserver/app/options:go_default_library",
|
||||
"//cmd/kube-controller-manager/app/options:go_default_library",
|
||||
"//cmd/kube-scheduler/app:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm:go_default_library",
|
||||
"//cmd/kubeadm/app/apis/kubeadm/v1alpha1:go_default_library",
|
||||
"//cmd/kubeadm/app/constants:go_default_library",
|
||||
"//pkg/apis/core/validation:go_default_library",
|
||||
"//pkg/kubeapiserver/authorizer/modes:go_default_library",
|
||||
"//cmd/kubeadm/app/images:go_default_library",
|
||||
"//pkg/registry/core/service/ipallocator:go_default_library",
|
||||
"//pkg/util/initsystem:go_default_library",
|
||||
"//pkg/util/ipvs:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//pkg/version:go_default_library",
|
||||
"//test/e2e_node/system:go_default_library",
|
||||
"//vendor/github.com/PuerkitoBio/purell:go_default_library",
|
||||
"//vendor/github.com/blang/semver:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/net:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||
|
384
vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks.go
generated
vendored
384
vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks.go
generated
vendored
@ -19,6 +19,8 @@ package preflight
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -26,32 +28,26 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
||||
"github.com/PuerkitoBio/purell"
|
||||
"github.com/blang/semver"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"net/url"
|
||||
"github.com/golang/glog"
|
||||
|
||||
netutil "k8s.io/apimachinery/pkg/util/net"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
apiservoptions "k8s.io/kubernetes/cmd/kube-apiserver/app/options"
|
||||
cmoptions "k8s.io/kubernetes/cmd/kube-controller-manager/app/options"
|
||||
schedulerapp "k8s.io/kubernetes/cmd/kube-scheduler/app"
|
||||
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
|
||||
kubeadmdefaults "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1alpha1"
|
||||
kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants"
|
||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||
authzmodes "k8s.io/kubernetes/pkg/kubeapiserver/authorizer/modes"
|
||||
"k8s.io/kubernetes/cmd/kubeadm/app/images"
|
||||
"k8s.io/kubernetes/pkg/registry/core/service/ipallocator"
|
||||
"k8s.io/kubernetes/pkg/util/initsystem"
|
||||
ipvsutil "k8s.io/kubernetes/pkg/util/ipvs"
|
||||
versionutil "k8s.io/kubernetes/pkg/util/version"
|
||||
kubeadmversion "k8s.io/kubernetes/pkg/version"
|
||||
"k8s.io/kubernetes/test/e2e_node/system"
|
||||
@ -61,6 +57,8 @@ import (
|
||||
const (
|
||||
bridgenf = "/proc/sys/net/bridge/bridge-nf-call-iptables"
|
||||
bridgenf6 = "/proc/sys/net/bridge/bridge-nf-call-ip6tables"
|
||||
ipv4Forward = "/proc/sys/net/ipv4/ip_forward"
|
||||
ipv6DefaultForwarding = "/proc/sys/net/ipv6/conf/default/forwarding"
|
||||
externalEtcdRequestTimeout = time.Duration(10 * time.Second)
|
||||
externalEtcdRequestRetries = 3
|
||||
externalEtcdRequestInterval = time.Duration(5 * time.Second)
|
||||
@ -75,10 +73,16 @@ type Error struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
// Error implements the standard error interface
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("[preflight] Some fatal errors occurred:\n%s%s", e.Msg, "[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`")
|
||||
}
|
||||
|
||||
// Preflight identifies this error as a preflight error
|
||||
func (e *Error) Preflight() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Checker validates the state of the system to ensure kubeadm will be
|
||||
// successful as often as possible.
|
||||
type Checker interface {
|
||||
@ -99,12 +103,13 @@ func (CRICheck) Name() string {
|
||||
|
||||
// Check validates the container runtime through the CRI.
|
||||
func (criCheck CRICheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("validating the container runtime through the CRI")
|
||||
crictlPath, err := criCheck.exec.LookPath("crictl")
|
||||
if err != nil {
|
||||
errors = append(errors, fmt.Errorf("unable to find command crictl: %s", err))
|
||||
return warnings, errors
|
||||
}
|
||||
if err := criCheck.exec.Command(fmt.Sprintf("%s -r %s info", crictlPath, criCheck.socket)).Run(); err != nil {
|
||||
if err := criCheck.exec.Command(crictlPath, "-r", criCheck.socket, "info").Run(); err != nil {
|
||||
errors = append(errors, fmt.Errorf("unable to check if the container runtime at %q is running: %s", criCheck.socket, err))
|
||||
return warnings, errors
|
||||
}
|
||||
@ -130,6 +135,7 @@ func (sc ServiceCheck) Name() string {
|
||||
|
||||
// Check validates if the service is enabled and active.
|
||||
func (sc ServiceCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("validating if the service is enabled and active")
|
||||
initSystem, err := initsystem.GetInitSystem()
|
||||
if err != nil {
|
||||
return []error{err}, nil
|
||||
@ -170,6 +176,7 @@ func (FirewalldCheck) Name() string {
|
||||
|
||||
// Check validates if the firewall is enabled and active.
|
||||
func (fc FirewalldCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("validating if the firewall is enabled and active")
|
||||
initSystem, err := initsystem.GetInitSystem()
|
||||
if err != nil {
|
||||
return []error{err}, nil
|
||||
@ -206,6 +213,7 @@ func (poc PortOpenCheck) Name() string {
|
||||
|
||||
// Check validates if the particular port is available.
|
||||
func (poc PortOpenCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infof("validating availability of port %d", poc.port)
|
||||
errors = []error{}
|
||||
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", poc.port))
|
||||
if err != nil {
|
||||
@ -242,6 +250,7 @@ func (dac DirAvailableCheck) Name() string {
|
||||
|
||||
// Check validates if a directory does not exist or empty.
|
||||
func (dac DirAvailableCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infof("validating the existence and emptiness of directory %s", dac.Path)
|
||||
errors = []error{}
|
||||
// If it doesn't exist we are good:
|
||||
if _, err := os.Stat(dac.Path); os.IsNotExist(err) {
|
||||
@ -279,6 +288,7 @@ func (fac FileAvailableCheck) Name() string {
|
||||
|
||||
// Check validates if the given file does not already exist.
|
||||
func (fac FileAvailableCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infof("validating the existence of file %s", fac.Path)
|
||||
errors = []error{}
|
||||
if _, err := os.Stat(fac.Path); err == nil {
|
||||
errors = append(errors, fmt.Errorf("%s already exists", fac.Path))
|
||||
@ -302,6 +312,7 @@ func (fac FileExistingCheck) Name() string {
|
||||
|
||||
// Check validates if the given file already exists.
|
||||
func (fac FileExistingCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infof("validating the existence of file %s", fac.Path)
|
||||
errors = []error{}
|
||||
if _, err := os.Stat(fac.Path); err != nil {
|
||||
errors = append(errors, fmt.Errorf("%s doesn't exist", fac.Path))
|
||||
@ -326,6 +337,7 @@ func (fcc FileContentCheck) Name() string {
|
||||
|
||||
// Check validates if the given file contains the given content.
|
||||
func (fcc FileContentCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infof("validating the contents of file %s", fcc.Path)
|
||||
f, err := os.Open(fcc.Path)
|
||||
if err != nil {
|
||||
return nil, []error{fmt.Errorf("%s does not exist", fcc.Path)}
|
||||
@ -366,6 +378,7 @@ func (ipc InPathCheck) Name() string {
|
||||
|
||||
// Check validates if the given executable is present in the path.
|
||||
func (ipc InPathCheck) Check() (warnings, errs []error) {
|
||||
glog.V(1).Infof("validating the presence of executable %s", ipc.executable)
|
||||
_, err := ipc.exec.LookPath(ipc.executable)
|
||||
if err != nil {
|
||||
if ipc.mandatory {
|
||||
@ -395,11 +408,9 @@ func (HostnameCheck) Name() string {
|
||||
|
||||
// Check validates if hostname match dns sub domain regex.
|
||||
func (hc HostnameCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infof("checking whether the given node name is reachable using net.LookupHost")
|
||||
errors = []error{}
|
||||
warnings = []error{}
|
||||
for _, msg := range validation.ValidateNodeName(hc.nodeName, false) {
|
||||
errors = append(errors, fmt.Errorf("hostname \"%s\" %s", hc.nodeName, msg))
|
||||
}
|
||||
addr, err := net.LookupHost(hc.nodeName)
|
||||
if addr == nil {
|
||||
warnings = append(warnings, fmt.Errorf("hostname \"%s\" could not be reached", hc.nodeName))
|
||||
@ -424,7 +435,7 @@ func (hst HTTPProxyCheck) Name() string {
|
||||
|
||||
// Check validates http connectivity type, direct or via proxy.
|
||||
func (hst HTTPProxyCheck) Check() (warnings, errors []error) {
|
||||
|
||||
glog.V(1).Infof("validating if the connectivity type is via proxy or direct")
|
||||
u := (&url.URL{Scheme: hst.Proto, Host: hst.Host}).String()
|
||||
|
||||
req, err := http.NewRequest("GET", u, nil)
|
||||
@ -460,7 +471,7 @@ func (HTTPProxyCIDRCheck) Name() string {
|
||||
// Check validates http connectivity to first IP address in the CIDR.
|
||||
// If it is not directly connected and goes via proxy it will produce warning.
|
||||
func (subnet HTTPProxyCIDRCheck) Check() (warnings, errors []error) {
|
||||
|
||||
glog.V(1).Infoln("validating http connectivity to first IP address in the CIDR")
|
||||
if len(subnet.CIDR) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@ -497,55 +508,6 @@ func (subnet HTTPProxyCIDRCheck) Check() (warnings, errors []error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ExtraArgsCheck checks if arguments are valid.
|
||||
type ExtraArgsCheck struct {
|
||||
APIServerExtraArgs map[string]string
|
||||
ControllerManagerExtraArgs map[string]string
|
||||
SchedulerExtraArgs map[string]string
|
||||
}
|
||||
|
||||
// Name will return ExtraArgs as name for ExtraArgsCheck
|
||||
func (ExtraArgsCheck) Name() string {
|
||||
return "ExtraArgs"
|
||||
}
|
||||
|
||||
// Check validates additional arguments of the control plane components.
|
||||
func (eac ExtraArgsCheck) Check() (warnings, errors []error) {
|
||||
argsCheck := func(name string, args map[string]string, f *pflag.FlagSet) []error {
|
||||
errs := []error{}
|
||||
for k, v := range args {
|
||||
if err := f.Set(k, v); err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s: failed to parse extra argument --%s=%s", name, k, v))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
warnings = []error{}
|
||||
if len(eac.APIServerExtraArgs) > 0 {
|
||||
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
s := apiservoptions.NewServerRunOptions()
|
||||
s.AddFlags(flags)
|
||||
warnings = append(warnings, argsCheck("kube-apiserver", eac.APIServerExtraArgs, flags)...)
|
||||
}
|
||||
if len(eac.ControllerManagerExtraArgs) > 0 {
|
||||
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
s := cmoptions.NewKubeControllerManagerOptions()
|
||||
s.AddFlags(flags, []string{}, []string{})
|
||||
warnings = append(warnings, argsCheck("kube-controller-manager", eac.ControllerManagerExtraArgs, flags)...)
|
||||
}
|
||||
if len(eac.SchedulerExtraArgs) > 0 {
|
||||
opts, err := schedulerapp.NewOptions()
|
||||
if err != nil {
|
||||
warnings = append(warnings, err)
|
||||
}
|
||||
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
opts.AddFlags(flags)
|
||||
warnings = append(warnings, argsCheck("kube-scheduler", eac.SchedulerExtraArgs, flags)...)
|
||||
}
|
||||
return warnings, nil
|
||||
}
|
||||
|
||||
// SystemVerificationCheck defines struct used for for running the system verification node check in test/e2e_node/system
|
||||
type SystemVerificationCheck struct {
|
||||
CRISocket string
|
||||
@ -558,6 +520,7 @@ func (SystemVerificationCheck) Name() string {
|
||||
|
||||
// Check runs all individual checks
|
||||
func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("running all checks")
|
||||
// Create a buffered writer and choose a quite large value (1M) and suppose the output from the system verification test won't exceed the limit
|
||||
// Run the system verification check, but write to out buffered writer instead of stdout
|
||||
bufw := bufio.NewWriterSize(os.Stdout, 1*1024*1024)
|
||||
@ -570,7 +533,7 @@ func (sysver SystemVerificationCheck) Check() (warnings, errors []error) {
|
||||
&system.KernelValidator{Reporter: reporter}}
|
||||
|
||||
// run the docker validator only with dockershim
|
||||
if sysver.CRISocket == "/var/run/dockershim.sock" {
|
||||
if sysver.CRISocket == kubeadmdefaults.DefaultCRISocket {
|
||||
// https://github.com/kubernetes/kubeadm/issues/533
|
||||
validators = append(validators, &system.DockerValidator{Reporter: reporter})
|
||||
}
|
||||
@ -615,7 +578,7 @@ func (KubernetesVersionCheck) Name() string {
|
||||
|
||||
// Check validates kubernetes and kubeadm versions
|
||||
func (kubever KubernetesVersionCheck) Check() (warnings, errors []error) {
|
||||
|
||||
glog.V(1).Infoln("validating kubernetes and kubeadm version")
|
||||
// Skip this check for "super-custom builds", where apimachinery/the overall codebase version is not set.
|
||||
if strings.HasPrefix(kubever.KubeadmVersion, "v0.0.0") {
|
||||
return nil, nil
|
||||
@ -656,6 +619,7 @@ func (KubeletVersionCheck) Name() string {
|
||||
|
||||
// Check validates kubelet version. It should be not less than minimal supported version
|
||||
func (kubever KubeletVersionCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("validating kubelet version")
|
||||
kubeletVersion, err := GetKubeletVersion(kubever.exec)
|
||||
if err != nil {
|
||||
return nil, []error{fmt.Errorf("couldn't get kubelet version: %v", err)}
|
||||
@ -686,6 +650,7 @@ func (SwapCheck) Name() string {
|
||||
|
||||
// Check validates whether swap is enabled or not
|
||||
func (swc SwapCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("validating whether swap is enabled or not")
|
||||
f, err := os.Open("/proc/swaps")
|
||||
if err != nil {
|
||||
// /proc/swaps not available, thus no reasons to warn
|
||||
@ -724,7 +689,15 @@ func (ExternalEtcdVersionCheck) Name() string {
|
||||
}
|
||||
|
||||
// Check validates external etcd version
|
||||
// TODO: Use the official etcd Golang client for this instead?
|
||||
func (evc ExternalEtcdVersionCheck) Check() (warnings, errors []error) {
|
||||
glog.V(1).Infoln("validating the external etcd version")
|
||||
|
||||
// Return quickly if the user isn't using external etcd
|
||||
if evc.Etcd.External.Endpoints == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var config *tls.Config
|
||||
var err error
|
||||
if config, err = evc.configRootCAs(config); err != nil {
|
||||
@ -737,7 +710,7 @@ func (evc ExternalEtcdVersionCheck) Check() (warnings, errors []error) {
|
||||
}
|
||||
|
||||
client := evc.getHTTPClient(config)
|
||||
for _, endpoint := range evc.Etcd.Endpoints {
|
||||
for _, endpoint := range evc.Etcd.External.Endpoints {
|
||||
if _, err := url.Parse(endpoint); err != nil {
|
||||
errors = append(errors, fmt.Errorf("failed to parse external etcd endpoint %s : %v", endpoint, err))
|
||||
continue
|
||||
@ -773,10 +746,10 @@ func (evc ExternalEtcdVersionCheck) Check() (warnings, errors []error) {
|
||||
// configRootCAs configures and returns a reference to tls.Config instance if CAFile is provided
|
||||
func (evc ExternalEtcdVersionCheck) configRootCAs(config *tls.Config) (*tls.Config, error) {
|
||||
var CACertPool *x509.CertPool
|
||||
if evc.Etcd.CAFile != "" {
|
||||
CACert, err := ioutil.ReadFile(evc.Etcd.CAFile)
|
||||
if evc.Etcd.External.CAFile != "" {
|
||||
CACert, err := ioutil.ReadFile(evc.Etcd.External.CAFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load external etcd's server certificate %s: %v", evc.Etcd.CAFile, err)
|
||||
return nil, fmt.Errorf("couldn't load external etcd's server certificate %s: %v", evc.Etcd.External.CAFile, err)
|
||||
}
|
||||
CACertPool = x509.NewCertPool()
|
||||
CACertPool.AppendCertsFromPEM(CACert)
|
||||
@ -793,11 +766,11 @@ func (evc ExternalEtcdVersionCheck) configRootCAs(config *tls.Config) (*tls.Conf
|
||||
// configCertAndKey configures and returns a reference to tls.Config instance if CertFile and KeyFile pair is provided
|
||||
func (evc ExternalEtcdVersionCheck) configCertAndKey(config *tls.Config) (*tls.Config, error) {
|
||||
var cert tls.Certificate
|
||||
if evc.Etcd.CertFile != "" && evc.Etcd.KeyFile != "" {
|
||||
if evc.Etcd.External.CertFile != "" && evc.Etcd.External.KeyFile != "" {
|
||||
var err error
|
||||
cert, err = tls.LoadX509KeyPair(evc.Etcd.CertFile, evc.Etcd.KeyFile)
|
||||
cert, err = tls.LoadX509KeyPair(evc.Etcd.External.CertFile, evc.Etcd.External.KeyFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't load external etcd's certificate and key pair %s, %s: %v", evc.Etcd.CertFile, evc.Etcd.KeyFile, err)
|
||||
return nil, fmt.Errorf("couldn't load external etcd's certificate and key pair %s, %s: %v", evc.Etcd.External.CertFile, evc.Etcd.External.KeyFile, err)
|
||||
}
|
||||
if config == nil {
|
||||
config = &tls.Config{}
|
||||
@ -832,13 +805,13 @@ func getEtcdVersionResponse(client *http.Client, url string, target interface{})
|
||||
r, err := client.Get(url)
|
||||
if err != nil {
|
||||
loopCount--
|
||||
return false, nil
|
||||
return false, err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
if r != nil && r.StatusCode >= 500 && r.StatusCode <= 599 {
|
||||
loopCount--
|
||||
return false, nil
|
||||
return false, fmt.Errorf("server responded with non-successful status: %s", r.Status)
|
||||
}
|
||||
return true, json.NewDecoder(r.Body).Decode(target)
|
||||
|
||||
@ -850,6 +823,31 @@ func getEtcdVersionResponse(client *http.Client, url string, target interface{})
|
||||
return err
|
||||
}
|
||||
|
||||
// ImagePullCheck will pull container images used by kubeadm
|
||||
type ImagePullCheck struct {
|
||||
Images images.Images
|
||||
ImageList []string
|
||||
}
|
||||
|
||||
// Name returns the label for ImagePullCheck
|
||||
func (ImagePullCheck) Name() string {
|
||||
return "ImagePull"
|
||||
}
|
||||
|
||||
// Check pulls images required by kubeadm. This is a mutating check
|
||||
func (i ImagePullCheck) Check() (warnings, errors []error) {
|
||||
for _, image := range i.ImageList {
|
||||
glog.V(1).Infoln("pulling ", image)
|
||||
if err := i.Images.Exists(image); err == nil {
|
||||
continue
|
||||
}
|
||||
if err := i.Images.Pull(image); err != nil {
|
||||
errors = append(errors, fmt.Errorf("failed to pull image [%s]: %v", image, err))
|
||||
}
|
||||
}
|
||||
return warnings, errors
|
||||
}
|
||||
|
||||
// RunInitMasterChecks executes all individual, applicable to Master node checks.
|
||||
func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfiguration, ignorePreflightErrors sets.String) error {
|
||||
// First, check if we're root separately from the other preflight checks and fail fast
|
||||
@ -857,91 +855,57 @@ func RunInitMasterChecks(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfi
|
||||
return err
|
||||
}
|
||||
|
||||
// check if we can use crictl to perform checks via the CRI
|
||||
criCtlChecker := InPathCheck{
|
||||
executable: "crictl",
|
||||
mandatory: false,
|
||||
exec: execer,
|
||||
suggestion: fmt.Sprintf("go get %v", kubeadmconstants.CRICtlPackage),
|
||||
}
|
||||
|
||||
manifestsDir := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName)
|
||||
|
||||
checks := []Checker{
|
||||
KubernetesVersionCheck{KubernetesVersion: cfg.KubernetesVersion, KubeadmVersion: kubeadmversion.Get().GitVersion},
|
||||
SystemVerificationCheck{CRISocket: cfg.CRISocket},
|
||||
IsPrivilegedUserCheck{},
|
||||
HostnameCheck{nodeName: cfg.NodeName},
|
||||
KubeletVersionCheck{KubernetesVersion: cfg.KubernetesVersion, exec: execer},
|
||||
ServiceCheck{Service: "kubelet", CheckIfActive: false},
|
||||
ServiceCheck{Service: "docker", CheckIfActive: true}, // assume docker
|
||||
FirewalldCheck{ports: []int{int(cfg.API.BindPort), 10250}},
|
||||
PortOpenCheck{port: int(cfg.API.BindPort)},
|
||||
PortOpenCheck{port: 10250},
|
||||
PortOpenCheck{port: 10251},
|
||||
PortOpenCheck{port: 10252},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, manifestsDir)},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeControllerManager, manifestsDir)},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeScheduler, manifestsDir)},
|
||||
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, manifestsDir)},
|
||||
FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
|
||||
SwapCheck{},
|
||||
InPathCheck{executable: "ip", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "iptables", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "mount", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "nsenter", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "ebtables", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "ethtool", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "socat", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "tc", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "touch", mandatory: false, exec: execer},
|
||||
criCtlChecker,
|
||||
ExtraArgsCheck{
|
||||
APIServerExtraArgs: cfg.APIServerExtraArgs,
|
||||
ControllerManagerExtraArgs: cfg.ControllerManagerExtraArgs,
|
||||
SchedulerExtraArgs: cfg.SchedulerExtraArgs,
|
||||
},
|
||||
HTTPProxyCheck{Proto: "https", Host: cfg.API.AdvertiseAddress},
|
||||
HTTPProxyCIDRCheck{Proto: "https", CIDR: cfg.Networking.ServiceSubnet},
|
||||
HTTPProxyCIDRCheck{Proto: "https", CIDR: cfg.Networking.PodSubnet},
|
||||
}
|
||||
checks = addCommonChecks(execer, cfg, checks)
|
||||
|
||||
if len(cfg.Etcd.Endpoints) == 0 {
|
||||
// Only do etcd related checks when no external endpoints were specified
|
||||
// Check ipvs required kernel module once we use ipvs kube-proxy mode
|
||||
if cfg.KubeProxy.Config != nil && cfg.KubeProxy.Config.Mode == ipvsutil.IPVSProxyMode {
|
||||
checks = append(checks,
|
||||
PortOpenCheck{port: 2379},
|
||||
DirAvailableCheck{Path: cfg.Etcd.DataDir},
|
||||
)
|
||||
} else {
|
||||
// Only check etcd version when external endpoints are specified
|
||||
if cfg.Etcd.CAFile != "" {
|
||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.CAFile})
|
||||
}
|
||||
if cfg.Etcd.CertFile != "" {
|
||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.CertFile})
|
||||
}
|
||||
if cfg.Etcd.KeyFile != "" {
|
||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.KeyFile})
|
||||
}
|
||||
checks = append(checks,
|
||||
ExternalEtcdVersionCheck{Etcd: cfg.Etcd},
|
||||
ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer},
|
||||
)
|
||||
}
|
||||
|
||||
// Check the config for authorization mode
|
||||
for _, authzMode := range cfg.AuthorizationModes {
|
||||
switch authzMode {
|
||||
case authzmodes.ModeABAC:
|
||||
checks = append(checks, FileExistingCheck{Path: kubeadmconstants.AuthorizationPolicyPath})
|
||||
case authzmodes.ModeWebhook:
|
||||
checks = append(checks, FileExistingCheck{Path: kubeadmconstants.AuthorizationWebhookConfigPath})
|
||||
if cfg.Etcd.Local != nil {
|
||||
// Only do etcd related checks when no external endpoints were specified
|
||||
checks = append(checks,
|
||||
PortOpenCheck{port: 2379},
|
||||
DirAvailableCheck{Path: cfg.Etcd.Local.DataDir},
|
||||
)
|
||||
}
|
||||
|
||||
if cfg.Etcd.External != nil {
|
||||
// Only check etcd version when external endpoints are specified
|
||||
if cfg.Etcd.External.CAFile != "" {
|
||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.CAFile, Label: "ExternalEtcdClientCertificates"})
|
||||
}
|
||||
if cfg.Etcd.External.CertFile != "" {
|
||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.CertFile, Label: "ExternalEtcdClientCertificates"})
|
||||
}
|
||||
if cfg.Etcd.External.KeyFile != "" {
|
||||
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.KeyFile, Label: "ExternalEtcdClientCertificates"})
|
||||
}
|
||||
checks = append(checks, ExternalEtcdVersionCheck{Etcd: cfg.Etcd})
|
||||
}
|
||||
|
||||
if ip := net.ParseIP(cfg.API.AdvertiseAddress); ip != nil {
|
||||
if ip.To4() == nil && ip.To16() != nil {
|
||||
checks = append(checks,
|
||||
FileContentCheck{Path: bridgenf6, Content: []byte{'1'}},
|
||||
FileContentCheck{Path: ipv6DefaultForwarding, Content: []byte{'1'}},
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -955,39 +919,58 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.NodeConfigura
|
||||
return err
|
||||
}
|
||||
|
||||
// check if we can use crictl to perform checks via the CRI
|
||||
criCtlChecker := InPathCheck{
|
||||
executable: "crictl",
|
||||
mandatory: false,
|
||||
exec: execer,
|
||||
suggestion: fmt.Sprintf("go get %v", kubeadmconstants.CRICtlPackage),
|
||||
}
|
||||
warns, _ := criCtlChecker.Check()
|
||||
useCRI := len(warns) == 0
|
||||
|
||||
checks := []Checker{
|
||||
SystemVerificationCheck{CRISocket: cfg.CRISocket},
|
||||
IsPrivilegedUserCheck{},
|
||||
HostnameCheck{cfg.NodeName},
|
||||
KubeletVersionCheck{exec: execer},
|
||||
ServiceCheck{Service: "kubelet", CheckIfActive: false},
|
||||
PortOpenCheck{port: 10250},
|
||||
DirAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName)},
|
||||
FileAvailableCheck{Path: cfg.CACertPath},
|
||||
FileAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletKubeConfigFileName)},
|
||||
FileAvailableCheck{Path: filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.KubeletBootstrapKubeConfigFileName)},
|
||||
ipvsutil.RequiredIPVSKernelModulesAvailableCheck{Executor: execer},
|
||||
}
|
||||
if useCRI {
|
||||
checks = append(checks, CRICheck{socket: cfg.CRISocket, exec: execer})
|
||||
checks = addCommonChecks(execer, cfg, checks)
|
||||
|
||||
addIPv6Checks := false
|
||||
for _, server := range cfg.DiscoveryTokenAPIServers {
|
||||
ipstr, _, err := net.SplitHostPort(server)
|
||||
if err == nil {
|
||||
checks = append(checks,
|
||||
HTTPProxyCheck{Proto: "https", Host: ipstr},
|
||||
)
|
||||
if !addIPv6Checks {
|
||||
if ip := net.ParseIP(ipstr); ip != nil {
|
||||
if ip.To4() == nil && ip.To16() != nil {
|
||||
addIPv6Checks = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if addIPv6Checks {
|
||||
checks = append(checks,
|
||||
FileContentCheck{Path: bridgenf6, Content: []byte{'1'}},
|
||||
FileContentCheck{Path: ipv6DefaultForwarding, Content: []byte{'1'}},
|
||||
)
|
||||
}
|
||||
|
||||
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
||||
}
|
||||
|
||||
// addCommonChecks is a helper function to deplicate checks that are common between both the
|
||||
// kubeadm init and join commands
|
||||
func addCommonChecks(execer utilsexec.Interface, cfg kubeadmapi.CommonConfiguration, checks []Checker) []Checker {
|
||||
// Check whether or not the CRI socket defined is the default
|
||||
if cfg.GetCRISocket() != kubeadmdefaults.DefaultCRISocket {
|
||||
checks = append(checks, CRICheck{socket: cfg.GetCRISocket(), exec: execer})
|
||||
} else {
|
||||
// assume docker
|
||||
checks = append(checks, ServiceCheck{Service: "docker", CheckIfActive: true})
|
||||
}
|
||||
//non-windows checks
|
||||
|
||||
// non-windows checks
|
||||
if runtime.GOOS == "linux" {
|
||||
checks = append(checks,
|
||||
FileContentCheck{Path: bridgenf, Content: []byte{'1'}},
|
||||
FileContentCheck{Path: ipv4Forward, Content: []byte{'1'}},
|
||||
SwapCheck{},
|
||||
InPathCheck{executable: "crictl", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "ip", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "iptables", mandatory: true, exec: execer},
|
||||
InPathCheck{executable: "mount", mandatory: true, exec: execer},
|
||||
@ -996,32 +979,16 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.NodeConfigura
|
||||
InPathCheck{executable: "ethtool", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "socat", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "tc", mandatory: false, exec: execer},
|
||||
InPathCheck{executable: "touch", mandatory: false, exec: execer},
|
||||
criCtlChecker)
|
||||
InPathCheck{executable: "touch", mandatory: false, exec: execer})
|
||||
}
|
||||
|
||||
var bridgenf6Check Checker
|
||||
for _, server := range cfg.DiscoveryTokenAPIServers {
|
||||
ipstr, _, err := net.SplitHostPort(server)
|
||||
if err == nil {
|
||||
checks = append(checks,
|
||||
HTTPProxyCheck{Proto: "https", Host: ipstr},
|
||||
)
|
||||
if bridgenf6Check == nil {
|
||||
if ip := net.ParseIP(ipstr); ip != nil {
|
||||
if ip.To4() == nil && ip.To16() != nil {
|
||||
// This check should be added only once
|
||||
bridgenf6Check = FileContentCheck{Path: bridgenf6, Content: []byte{'1'}}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if bridgenf6Check != nil {
|
||||
checks = append(checks, bridgenf6Check)
|
||||
}
|
||||
|
||||
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
||||
checks = append(checks,
|
||||
SystemVerificationCheck{CRISocket: cfg.GetCRISocket()},
|
||||
IsPrivilegedUserCheck{},
|
||||
HostnameCheck{nodeName: cfg.GetNodeName()},
|
||||
KubeletVersionCheck{KubernetesVersion: cfg.GetKubernetesVersion(), exec: execer},
|
||||
ServiceCheck{Service: "kubelet", CheckIfActive: false},
|
||||
PortOpenCheck{port: 10250})
|
||||
return checks
|
||||
}
|
||||
|
||||
// RunRootCheckOnly initializes checks slice of structs and call RunChecks
|
||||
@ -1033,6 +1000,19 @@ func RunRootCheckOnly(ignorePreflightErrors sets.String) error {
|
||||
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
||||
}
|
||||
|
||||
// RunPullImagesCheck will pull images kubeadm needs if the are not found on the system
|
||||
func RunPullImagesCheck(execer utilsexec.Interface, cfg *kubeadmapi.MasterConfiguration, ignorePreflightErrors sets.String) error {
|
||||
criInterfacer, err := images.NewCRInterfacer(execer, cfg.GetCRISocket())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
checks := []Checker{
|
||||
ImagePullCheck{Images: criInterfacer, ImageList: images.GetAllImages(cfg)},
|
||||
}
|
||||
return RunChecks(checks, os.Stderr, ignorePreflightErrors)
|
||||
}
|
||||
|
||||
// RunChecks runs each check, displays it's warnings/errors, and once all
|
||||
// are processed will exit if any errors occurred.
|
||||
func RunChecks(checks []Checker, ww io.Writer, ignorePreflightErrors sets.String) error {
|
||||
@ -1072,21 +1052,43 @@ func RunChecks(checks []Checker, ww io.Writer, ignorePreflightErrors sets.String
|
||||
}
|
||||
|
||||
// TryStartKubelet attempts to bring up kubelet service
|
||||
func TryStartKubelet(ignorePreflightErrors sets.String) {
|
||||
if setHasItemOrAll(ignorePreflightErrors, "StartKubelet") {
|
||||
return
|
||||
}
|
||||
// TODO: Move these kubelet start/stop functions to some other place, e.g. phases/kubelet
|
||||
func TryStartKubelet() {
|
||||
// If we notice that the kubelet service is inactive, try to start it
|
||||
initSystem, err := initsystem.GetInitSystem()
|
||||
if err != nil {
|
||||
fmt.Println("[preflight] No supported init system detected, won't ensure kubelet is running.")
|
||||
} else if initSystem.ServiceExists("kubelet") && !initSystem.ServiceIsActive("kubelet") {
|
||||
fmt.Println("[preflight] no supported init system detected, won't make sure the kubelet is running properly.")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("[preflight] Starting the kubelet service")
|
||||
if err := initSystem.ServiceStart("kubelet"); err != nil {
|
||||
fmt.Printf("[preflight] WARNING: Unable to start the kubelet service: [%v]\n", err)
|
||||
fmt.Println("[preflight] WARNING: Please ensure kubelet is running manually.")
|
||||
}
|
||||
if !initSystem.ServiceExists("kubelet") {
|
||||
fmt.Println("[preflight] couldn't detect a kubelet service, can't make sure the kubelet is running properly.")
|
||||
}
|
||||
|
||||
fmt.Println("[preflight] Activating the kubelet service")
|
||||
// This runs "systemctl daemon-reload && systemctl restart kubelet"
|
||||
if err := initSystem.ServiceRestart("kubelet"); err != nil {
|
||||
fmt.Printf("[preflight] WARNING: unable to start the kubelet service: [%v]\n", err)
|
||||
fmt.Printf("[preflight] please ensure kubelet is reloaded and running manually.\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TryStopKubelet attempts to bring down the kubelet service momentarily
|
||||
func TryStopKubelet() {
|
||||
// If we notice that the kubelet service is inactive, try to start it
|
||||
initSystem, err := initsystem.GetInitSystem()
|
||||
if err != nil {
|
||||
fmt.Println("[preflight] no supported init system detected, won't make sure the kubelet not running for a short period of time while setting up configuration for it.")
|
||||
return
|
||||
}
|
||||
|
||||
if !initSystem.ServiceExists("kubelet") {
|
||||
fmt.Println("[preflight] couldn't detect a kubelet service, can't make sure the kubelet not running for a short period of time while setting up configuration for it.")
|
||||
}
|
||||
|
||||
// This runs "systemctl daemon-reload && systemctl stop kubelet"
|
||||
if err := initSystem.ServiceStop("kubelet"); err != nil {
|
||||
fmt.Printf("[preflight] WARNING: unable to stop the kubelet service momentarily: [%v]\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
75
vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks_test.go
generated
vendored
75
vendor/k8s.io/kubernetes/cmd/kubeadm/app/preflight/checks_test.go
generated
vendored
@ -18,6 +18,7 @@ package preflight
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
@ -196,21 +197,21 @@ func TestRunInitMasterChecks(t *testing.T) {
|
||||
{
|
||||
name: "Test CA file exists if specfied",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{CAFile: "/foo"},
|
||||
Etcd: kubeadmapi.Etcd{External: &kubeadmapi.ExternalEtcd{CAFile: "/foo"}},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Test Cert file exists if specfied",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{CertFile: "/foo"},
|
||||
Etcd: kubeadmapi.Etcd{External: &kubeadmapi.ExternalEtcd{CertFile: "/foo"}},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Test Key file exists if specfied",
|
||||
cfg: &kubeadmapi.MasterConfiguration{
|
||||
Etcd: kubeadmapi.Etcd{CertFile: "/foo"},
|
||||
Etcd: kubeadmapi.Etcd{External: &kubeadmapi.ExternalEtcd{CertFile: "/foo"}},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
@ -288,17 +289,6 @@ func TestRunChecks(t *testing.T) {
|
||||
{[]Checker{FileContentCheck{Path: "/", Content: []byte("does not exist")}}, false, ""},
|
||||
{[]Checker{InPathCheck{executable: "foobarbaz", exec: exec.New()}}, true, "\t[WARNING FileExisting-foobarbaz]: foobarbaz not found in system path\n"},
|
||||
{[]Checker{InPathCheck{executable: "foobarbaz", mandatory: true, exec: exec.New()}}, false, ""},
|
||||
{[]Checker{ExtraArgsCheck{
|
||||
APIServerExtraArgs: map[string]string{"secure-port": "1234"},
|
||||
ControllerManagerExtraArgs: map[string]string{"use-service-account-credentials": "true"},
|
||||
SchedulerExtraArgs: map[string]string{"leader-elect": "true"},
|
||||
}}, true, ""},
|
||||
{[]Checker{ExtraArgsCheck{
|
||||
APIServerExtraArgs: map[string]string{"secure-port": "foo"},
|
||||
}}, true, "\t[WARNING ExtraArgs]: kube-apiserver: failed to parse extra argument --secure-port=foo\n"},
|
||||
{[]Checker{ExtraArgsCheck{
|
||||
APIServerExtraArgs: map[string]string{"invalid-argument": "foo"},
|
||||
}}, true, "\t[WARNING ExtraArgs]: kube-apiserver: failed to parse extra argument --invalid-argument=foo\n"},
|
||||
{[]Checker{InPathCheck{executable: "foobar", mandatory: false, exec: exec.New(), suggestion: "install foobar"}}, true, "\t[WARNING FileExisting-foobar]: foobar not found in system path\nSuggestion: install foobar\n"},
|
||||
}
|
||||
for _, rt := range tokenTest {
|
||||
@ -330,7 +320,7 @@ func TestConfigRootCAs(t *testing.T) {
|
||||
t.Errorf("failed configRootCAs:\n\texpected: succeed writing contents to temp CA file %s\n\tactual:%v", f.Name(), err)
|
||||
}
|
||||
|
||||
c := ExternalEtcdVersionCheck{Etcd: kubeadmapi.Etcd{CAFile: f.Name()}}
|
||||
c := ExternalEtcdVersionCheck{Etcd: kubeadmapi.Etcd{External: &kubeadmapi.ExternalEtcd{CAFile: f.Name()}}}
|
||||
|
||||
config, err := c.configRootCAs(nil)
|
||||
if err != nil {
|
||||
@ -378,10 +368,14 @@ func TestConfigCertAndKey(t *testing.T) {
|
||||
err,
|
||||
)
|
||||
}
|
||||
c := ExternalEtcdVersionCheck{Etcd: kubeadmapi.Etcd{
|
||||
CertFile: certFile.Name(),
|
||||
KeyFile: keyFile.Name(),
|
||||
}}
|
||||
c := ExternalEtcdVersionCheck{
|
||||
Etcd: kubeadmapi.Etcd{
|
||||
External: &kubeadmapi.ExternalEtcd{
|
||||
CertFile: certFile.Name(),
|
||||
KeyFile: keyFile.Name(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
config, err := c.configCertAndKey(nil)
|
||||
if err != nil {
|
||||
@ -638,13 +632,13 @@ func TestKubeletVersionCheck(t *testing.T) {
|
||||
expectErrors bool
|
||||
expectWarnings bool
|
||||
}{
|
||||
{"v1.10.2", "", false, false}, // check minimally supported version when there is no information about control plane
|
||||
{"v1.7.3", "v1.7.8", true, false}, // too old kubelet (older than kubeadmconstants.MinimumKubeletVersion), should fail.
|
||||
{"v1.9.0", "v1.9.5", false, false}, // kubelet within same major.minor as control plane
|
||||
{"v1.9.5", "v1.9.1", false, false}, // kubelet is newer, but still within same major.minor as control plane
|
||||
{"v1.9.0", "v1.10.1", false, false}, // kubelet is lower than control plane, but newer than minimally supported
|
||||
{"v1.10.0-alpha.1", "v1.9.1", true, false}, // kubelet is newer (development build) than control plane, should fail.
|
||||
{"v1.10.0", "v1.9.5", true, false}, // kubelet is newer (release) than control plane, should fail.
|
||||
{"v1.11.2", "", false, false}, // check minimally supported version when there is no information about control plane
|
||||
{"v1.8.3", "v1.8.8", true, false}, // too old kubelet (older than kubeadmconstants.MinimumKubeletVersion), should fail.
|
||||
{"v1.10.0", "v1.10.5", false, false}, // kubelet within same major.minor as control plane
|
||||
{"v1.10.5", "v1.10.1", false, false}, // kubelet is newer, but still within same major.minor as control plane
|
||||
{"v1.10.0", "v1.11.1", false, false}, // kubelet is lower than control plane, but newer than minimally supported
|
||||
{"v1.11.0-alpha.1", "v1.10.1", true, false}, // kubelet is newer (development build) than control plane, should fail.
|
||||
{"v1.11.0", "v1.10.5", true, false}, // kubelet is newer (release) than control plane, should fail.
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@ -703,3 +697,32 @@ func TestSetHasItemOrAll(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type imgs struct{}
|
||||
|
||||
func (i *imgs) Pull(image string) error {
|
||||
if image == "bad pull" {
|
||||
return errors.New("pull error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (i *imgs) Exists(image string) error {
|
||||
if image == "found" {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error")
|
||||
}
|
||||
|
||||
func TestImagePullCheck(t *testing.T) {
|
||||
i := ImagePullCheck{
|
||||
Images: &imgs{},
|
||||
ImageList: []string{"found", "not found", "bad pull"},
|
||||
}
|
||||
warnings, errors := i.Check()
|
||||
if len(warnings) != 0 {
|
||||
t.Fatalf("did not expect any warnings but got %q", warnings)
|
||||
}
|
||||
if len(errors) != 1 {
|
||||
t.Fatalf("expected 1 errors but got %d: %q", len(errors), errors)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user