Merge pull request #107317 from neolit123/1.24-change-kubeadm-cr-auto-detection
kubeadm: adapt CRI detection and defaults after the dockershim removal
This commit is contained in:
		| @@ -169,7 +169,7 @@ limitations under the License. | ||||
| // 	  - system:bootstrappers:kubeadm:default-node-token | ||||
| // 	nodeRegistration: | ||||
| // 	  name: "ec2-10-100-0-1" | ||||
| // 	  criSocket: "unix:///var/run/dockershim.sock" | ||||
| // 	  criSocket: "unix:///var/run/containerd/containerd.sock" | ||||
| // 	  taints: | ||||
| // 	  - key: "kubeadmNode" | ||||
| // 	    value: "master" | ||||
|   | ||||
| @@ -173,7 +173,7 @@ limitations under the License. | ||||
| // 	  - system:bootstrappers:kubeadm:default-node-token | ||||
| // 	nodeRegistration: | ||||
| // 	  name: "ec2-10-100-0-1" | ||||
| // 	  criSocket: "unix:///var/run/dockershim.sock" | ||||
| // 	  criSocket: "unix:///var/run/containerd/containerd.sock" | ||||
| // 	  taints: | ||||
| // 	  - key: "kubeadmNode" | ||||
| // 	    value: "master" | ||||
|   | ||||
| @@ -579,7 +579,7 @@ func TestValidateJoinConfiguration(t *testing.T) { | ||||
| 			}, | ||||
| 			NodeRegistration: kubeadmapi.NodeRegistrationOptions{ | ||||
| 				Name:      "aaa", | ||||
| 				CRISocket: "unix:///var/run/dockershim.sock", | ||||
| 				CRISocket: "unix:///var/run/containerd/containerd.sock", | ||||
| 			}, | ||||
| 		}, true}, | ||||
| 		{&kubeadmapi.JoinConfiguration{ // Pass with JoinControlPlane | ||||
| @@ -594,7 +594,7 @@ func TestValidateJoinConfiguration(t *testing.T) { | ||||
| 			}, | ||||
| 			NodeRegistration: kubeadmapi.NodeRegistrationOptions{ | ||||
| 				Name:      "aaa", | ||||
| 				CRISocket: "unix:///var/run/dockershim.sock", | ||||
| 				CRISocket: "unix:///var/run/containerd/containerd.sock", | ||||
| 			}, | ||||
| 			ControlPlane: &kubeadmapi.JoinControlPlane{ | ||||
| 				LocalAPIEndpoint: kubeadmapi.APIEndpoint{ | ||||
| @@ -615,7 +615,7 @@ func TestValidateJoinConfiguration(t *testing.T) { | ||||
| 			}, | ||||
| 			NodeRegistration: kubeadmapi.NodeRegistrationOptions{ | ||||
| 				Name:      "aaa", | ||||
| 				CRISocket: "unix:///var/run/dockershim.sock", | ||||
| 				CRISocket: "unix:///var/run/containerd/containerd.sock", | ||||
| 			}, | ||||
| 			ControlPlane: &kubeadmapi.JoinControlPlane{ | ||||
| 				LocalAPIEndpoint: kubeadmapi.APIEndpoint{ | ||||
| @@ -636,7 +636,7 @@ func TestValidateJoinConfiguration(t *testing.T) { | ||||
| 			}, | ||||
| 			NodeRegistration: kubeadmapi.NodeRegistrationOptions{ | ||||
| 				Name:      "aaa", | ||||
| 				CRISocket: "/var/run/dockershim.sock", | ||||
| 				CRISocket: "unix:///var/run/containerd/containerd.sock", | ||||
| 			}, | ||||
| 			ControlPlane: &kubeadmapi.JoinControlPlane{ | ||||
| 				LocalAPIEndpoint: kubeadmapi.APIEndpoint{ | ||||
|   | ||||
| @@ -359,7 +359,7 @@ kind: InitConfiguration | ||||
| localAPIEndpoint: | ||||
|   advertiseAddress: 192.0.2.1 | ||||
| nodeRegistration: | ||||
|   criSocket: /path/to/dockershim.sock | ||||
|   criSocket: "unix:///var/run/containerd/containerd.sock" | ||||
| --- | ||||
| apiVersion: %[1]s | ||||
| kind: ClusterConfiguration | ||||
|   | ||||
| @@ -211,7 +211,7 @@ func getDefaultNodeConfigBytes() ([]byte, error) { | ||||
| 			}, | ||||
| 		}, | ||||
| 		NodeRegistration: kubeadmapiv1.NodeRegistrationOptions{ | ||||
| 			CRISocket: constants.DefaultDockerCRISocket, // avoid CRI detection | ||||
| 			CRISocket: constants.DefaultCRISocket, // avoid CRI detection | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
|   | ||||
| @@ -363,10 +363,10 @@ func TestImagesPull(t *testing.T) { | ||||
| 			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, | ||||
| 			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, | ||||
| 		}, | ||||
| 		LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/docker", nil }, | ||||
| 		LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil }, | ||||
| 	} | ||||
|  | ||||
| 	containerRuntime, err := utilruntime.NewContainerRuntime(&fexec, constants.DefaultDockerCRISocket) | ||||
| 	containerRuntime, err := utilruntime.NewContainerRuntime(&fexec, constants.DefaultCRISocket) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("unexpected NewContainerRuntime error: %v", err) | ||||
| 	} | ||||
|   | ||||
| @@ -29,7 +29,6 @@ import ( | ||||
| 	"k8s.io/klog/v2" | ||||
|  | ||||
| 	"k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow" | ||||
| 	kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" | ||||
| 	"k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" | ||||
| 	dryrunutil "k8s.io/kubernetes/cmd/kubeadm/app/util/dryrun" | ||||
| ) | ||||
| @@ -49,17 +48,10 @@ var ( | ||||
|  | ||||
| 	Additionally, a control plane component may have crashed or exited when started by the container runtime. | ||||
| 	To troubleshoot, list all containers using your preferred container runtimes CLI. | ||||
| {{ if .IsDocker }} | ||||
| 	Here is one example how you may list all Kubernetes containers running in docker: | ||||
| 		- 'docker ps -a | grep kube | grep -v pause' | ||||
| 		Once you have found the failing container, you can inspect its logs with: | ||||
| 		- 'docker logs CONTAINERID' | ||||
| {{ else }} | ||||
| 	Here is one example how you may list all Kubernetes containers running in cri-o/containerd using crictl: | ||||
| 	Here is one example how you may list all running Kubernetes containers by using crictl: | ||||
| 		- 'crictl --runtime-endpoint {{ .Socket }} ps -a | grep kube | grep -v pause' | ||||
| 		Once you have found the failing container, you can inspect its logs with: | ||||
| 		- 'crictl --runtime-endpoint {{ .Socket }} logs CONTAINERID' | ||||
| {{ end }} | ||||
| 	`))) | ||||
| ) | ||||
|  | ||||
| @@ -107,11 +99,9 @@ func runWaitControlPlanePhase(c workflow.RunData) error { | ||||
| 		context := struct { | ||||
| 			Error  string | ||||
| 			Socket string | ||||
| 			IsDocker bool | ||||
| 		}{ | ||||
| 			Error:  fmt.Sprintf("%v", err), | ||||
| 			Socket: data.Cfg().NodeRegistration.CRISocket, | ||||
| 			IsDocker: data.Cfg().NodeRegistration.CRISocket == kubeadmconstants.DefaultDockerCRISocket, | ||||
| 		} | ||||
|  | ||||
| 		kubeletFailTempl.Execute(data.OutputWriter(), context) | ||||
|   | ||||
| @@ -96,6 +96,8 @@ func runCleanupNode(c workflow.RunData) error { | ||||
| 		fmt.Println("[reset] Would remove Kubernetes-managed containers") | ||||
| 	} | ||||
|  | ||||
| 	// TODO: remove the dockershim directory cleanup in 1.25 | ||||
| 	// https://github.com/kubernetes/kubeadm/issues/2626 | ||||
| 	r.AddDirsToClean("/var/lib/dockershim", "/var/run/kubernetes", "/var/lib/cni") | ||||
|  | ||||
| 	// Remove contents from the config and pki directories | ||||
|   | ||||
| @@ -20,6 +20,13 @@ limitations under the License. | ||||
| package constants | ||||
|  | ||||
| const ( | ||||
| 	// DefaultDockerCRISocket defines the default Docker CRI socket | ||||
| 	DefaultDockerCRISocket = "unix:///var/run/dockershim.sock" | ||||
| 	// CRISocketContainerd is the containerd CRI endpoint | ||||
| 	CRISocketContainerd = "unix:///var/run/containerd/containerd.sock" | ||||
| 	// CRISocketCRIO is the cri-o CRI endpoint | ||||
| 	CRISocketCRIO = "unix:///var/run/crio/crio.sock" | ||||
| 	// CRISocketDocker is the cri-dockerd CRI endpoint | ||||
| 	CRISocketDocker = "unix:///var/run/cri-dockerd.sock" | ||||
|  | ||||
| 	// DefaultCRISocket defines the default CRI socket | ||||
| 	DefaultCRISocket = CRISocketContainerd | ||||
| ) | ||||
|   | ||||
| @@ -20,6 +20,14 @@ limitations under the License. | ||||
| package constants | ||||
|  | ||||
| const ( | ||||
| 	// DefaultDockerCRISocket defines the default Docker CRI socket | ||||
| 	DefaultDockerCRISocket = "npipe:////./pipe/docker_engine" | ||||
| 	// CRISocketContainerd is the containerd CRI endpoint | ||||
| 	CRISocketContainerd = "npipe:////./pipe/containerd-containerd" | ||||
| 	// CRISocketCRIO is the cri-o CRI endpoint | ||||
| 	// NOTE: this is a placeholder as CRI-O does not support Windows | ||||
| 	CRISocketCRIO = "npipe:////./pipe/cri-o" | ||||
| 	// CRISocketDocker is the cri-dockerd CRI endpoint | ||||
| 	CRISocketDocker = "npipe:////./pipe/cri-dockerd" | ||||
|  | ||||
| 	// DefaultCRISocket defines the default CRI socket | ||||
| 	DefaultCRISocket = CRISocketContainerd | ||||
| ) | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -102,7 +103,13 @@ func buildKubeletArgMapCommon(opts kubeletFlagsOpts) map[string]string { | ||||
| 	// Once that happens only the "remote" branch option should be left. | ||||
| 	// TODO: https://github.com/kubernetes/kubeadm/issues/2626 | ||||
| 	hasDockershim := opts.kubeletVersion.Major() == 1 && opts.kubeletVersion.Minor() < 24 | ||||
| 	if opts.nodeRegOpts.CRISocket == constants.DefaultDockerCRISocket && hasDockershim { | ||||
| 	var dockerSocket string | ||||
| 	if runtime.GOOS == "windows" { | ||||
| 		dockerSocket = "npipe:////./pipe/dockershim" | ||||
| 	} else { | ||||
| 		dockerSocket = "unix:///var/run/dockershim.sock" | ||||
| 	} | ||||
| 	if opts.nodeRegOpts.CRISocket == dockerSocket && hasDockershim { | ||||
| 		kubeletFlags["network-plugin"] = "cni" | ||||
| 	} else { | ||||
| 		kubeletFlags["container-runtime"] = "remote" | ||||
|   | ||||
| @@ -52,7 +52,7 @@ func TestAnnotateCRISocket(t *testing.T) { | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:                       "CRI-socket annotation needs to be updated", | ||||
| 			currentCRISocketAnnotation: "unix:///var/run/dockershim.sock", | ||||
| 			currentCRISocketAnnotation: "unix:///foo/bar", | ||||
| 			newCRISocketAnnotation:     "unix:///run/containerd/containerd.sock", | ||||
| 			expectedPatch:              `{"metadata":{"annotations":{"kubeadm.alpha.kubernetes.io/cri-socket":"unix:///run/containerd/containerd.sock"}}}`, | ||||
| 		}, | ||||
|   | ||||
| @@ -507,9 +507,7 @@ func (subnet HTTPProxyCIDRCheck) Check() (warnings, errorList []error) { | ||||
| } | ||||
|  | ||||
| // SystemVerificationCheck defines struct used for running the system verification node check in test/e2e_node/system | ||||
| type SystemVerificationCheck struct { | ||||
| 	IsDocker bool | ||||
| } | ||||
| type SystemVerificationCheck struct{} | ||||
|  | ||||
| // Name will return SystemVerification as name for SystemVerificationCheck | ||||
| func (SystemVerificationCheck) Name() string { | ||||
| @@ -530,11 +528,6 @@ func (sysver SystemVerificationCheck) Check() (warnings, errorList []error) { | ||||
| 	var validators = []system.Validator{ | ||||
| 		&system.KernelValidator{Reporter: reporter}} | ||||
|  | ||||
| 	// run the docker validator only with docker runtime | ||||
| 	if sysver.IsDocker { | ||||
| 		validators = append(validators, &system.DockerValidator{Reporter: reporter}) | ||||
| 	} | ||||
|  | ||||
| 	if runtime.GOOS == "linux" { | ||||
| 		//add linux validators | ||||
| 		validators = append(validators, | ||||
| @@ -1025,26 +1018,19 @@ func RunJoinNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.JoinConfigura | ||||
| // kubeadm init and join commands | ||||
| func addCommonChecks(execer utilsexec.Interface, k8sVersion string, nodeReg *kubeadmapi.NodeRegistrationOptions, checks []Checker) []Checker { | ||||
| 	containerRuntime, err := utilruntime.NewContainerRuntime(execer, nodeReg.CRISocket) | ||||
| 	isDocker := false | ||||
| 	if err != nil { | ||||
| 		klog.Warningf("[preflight] WARNING: Couldn't create the interface used for talking to the container runtime: %v\n", err) | ||||
| 	} else { | ||||
| 		checks = append(checks, ContainerRuntimeCheck{runtime: containerRuntime}) | ||||
| 		if containerRuntime.IsDocker() { | ||||
| 			isDocker = true | ||||
| 			checks = append(checks, ServiceCheck{Service: "docker", CheckIfActive: true}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// non-windows checks | ||||
| 	if runtime.GOOS == "linux" { | ||||
| 		if !isDocker { | ||||
| 			checks = append(checks, InPathCheck{executable: "crictl", mandatory: true, exec: execer}) | ||||
| 		} | ||||
| 		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: "conntrack", mandatory: true, exec: execer}, | ||||
| 			InPathCheck{executable: "ip", mandatory: true, exec: execer}, | ||||
| 			InPathCheck{executable: "iptables", mandatory: true, exec: execer}, | ||||
| @@ -1057,7 +1043,7 @@ func addCommonChecks(execer utilsexec.Interface, k8sVersion string, nodeReg *kub | ||||
| 			InPathCheck{executable: "touch", mandatory: false, exec: execer}) | ||||
| 	} | ||||
| 	checks = append(checks, | ||||
| 		SystemVerificationCheck{IsDocker: isDocker}, | ||||
| 		SystemVerificationCheck{}, | ||||
| 		HostnameCheck{nodeName: nodeReg.Name}, | ||||
| 		KubeletVersionCheck{KubernetesVersion: k8sVersion, exec: execer}, | ||||
| 		ServiceCheck{Service: "kubelet", CheckIfActive: false}, | ||||
|   | ||||
| @@ -917,10 +917,10 @@ func TestImagePullCheck(t *testing.T) { | ||||
| 			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, | ||||
| 			func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, | ||||
| 		}, | ||||
| 		LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/docker", nil }, | ||||
| 		LookPathFunc: func(cmd string) (string, error) { return "/usr/bin/crictl", nil }, | ||||
| 	} | ||||
|  | ||||
| 	containerRuntime, err := utilruntime.NewContainerRuntime(&fexec, constants.DefaultDockerCRISocket) | ||||
| 	containerRuntime, err := utilruntime.NewContainerRuntime(&fexec, constants.DefaultCRISocket) | ||||
| 	if err != nil { | ||||
| 		t.Errorf("unexpected NewContainerRuntime error: %v", err) | ||||
| 	} | ||||
|   | ||||
| @@ -195,7 +195,7 @@ func DefaultedStaticInitConfiguration() (*kubeadmapi.InitConfiguration, error) { | ||||
| 		LocalAPIEndpoint: kubeadmapiv1.APIEndpoint{AdvertiseAddress: "1.2.3.4"}, | ||||
| 		BootstrapTokens:  []bootstraptokenv1.BootstrapToken{PlaceholderToken}, | ||||
| 		NodeRegistration: kubeadmapiv1.NodeRegistrationOptions{ | ||||
| 			CRISocket: kubeadmconstants.DefaultDockerCRISocket, // avoid CRI detection | ||||
| 			CRISocket: kubeadmconstants.DefaultCRISocket, // avoid CRI detection | ||||
| 			Name:      "node", | ||||
| 		}, | ||||
| 	} | ||||
|   | ||||
| @@ -27,9 +27,16 @@ import ( | ||||
| 	"k8s.io/kubernetes/cmd/kubeadm/app/constants" | ||||
| ) | ||||
|  | ||||
| // defaultKnownCRISockets holds the set of known CRI endpoints | ||||
| var defaultKnownCRISockets = []string{ | ||||
| 	constants.CRISocketContainerd, | ||||
| 	constants.CRISocketCRIO, | ||||
| 	constants.CRISocketDocker, | ||||
| } | ||||
|  | ||||
| // ContainerRuntime is an interface for working with container runtimes | ||||
| type ContainerRuntime interface { | ||||
| 	IsDocker() bool | ||||
| 	Socket() string | ||||
| 	IsRunning() error | ||||
| 	ListKubeContainers() ([]string, error) | ||||
| 	RemoveContainers(containers []string) error | ||||
| @@ -43,39 +50,19 @@ type CRIRuntime struct { | ||||
| 	criSocket string | ||||
| } | ||||
|  | ||||
| // DockerRuntime is a struct that interfaces with the Docker daemon | ||||
| type DockerRuntime struct { | ||||
| 	exec utilsexec.Interface | ||||
| } | ||||
|  | ||||
| // NewContainerRuntime sets up and returns a ContainerRuntime struct | ||||
| func NewContainerRuntime(execer utilsexec.Interface, criSocket string) (ContainerRuntime, error) { | ||||
| 	var toolName string | ||||
| 	var runtime ContainerRuntime | ||||
|  | ||||
| 	if criSocket != constants.DefaultDockerCRISocket { | ||||
| 		toolName = "crictl" | ||||
| 		runtime = &CRIRuntime{execer, criSocket} | ||||
| 	} else { | ||||
| 		toolName = "docker" | ||||
| 		runtime = &DockerRuntime{execer} | ||||
| 	} | ||||
|  | ||||
| 	toolName := "crictl" | ||||
| 	runtime := &CRIRuntime{execer, criSocket} | ||||
| 	if _, err := execer.LookPath(toolName); err != nil { | ||||
| 		return nil, errors.Wrapf(err, "%s is required for container runtime", toolName) | ||||
| 		return nil, errors.Wrapf(err, "%s is required by the container runtime", toolName) | ||||
| 	} | ||||
|  | ||||
| 	return runtime, nil | ||||
| } | ||||
|  | ||||
| // IsDocker returns true if the runtime is docker | ||||
| func (runtime *CRIRuntime) IsDocker() bool { | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // IsDocker returns true if the runtime is docker | ||||
| func (runtime *DockerRuntime) IsDocker() bool { | ||||
| 	return true | ||||
| // Socket returns the CRI socket endpoint | ||||
| func (runtime *CRIRuntime) Socket() string { | ||||
| 	return runtime.criSocket | ||||
| } | ||||
|  | ||||
| // IsRunning checks if runtime is running | ||||
| @@ -86,14 +73,6 @@ func (runtime *CRIRuntime) IsRunning() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // IsRunning checks if runtime is running | ||||
| func (runtime *DockerRuntime) IsRunning() error { | ||||
| 	if out, err := runtime.exec.Command("docker", "info").CombinedOutput(); err != nil { | ||||
| 		return errors.Wrapf(err, "container runtime is not running: output: %s, error", string(out)) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ListKubeContainers lists running k8s CRI pods | ||||
| func (runtime *CRIRuntime) ListKubeContainers() ([]string, error) { | ||||
| 	out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "pods", "-q").CombinedOutput() | ||||
| @@ -105,12 +84,6 @@ func (runtime *CRIRuntime) ListKubeContainers() ([]string, error) { | ||||
| 	return pods, nil | ||||
| } | ||||
|  | ||||
| // ListKubeContainers lists running k8s containers | ||||
| func (runtime *DockerRuntime) ListKubeContainers() ([]string, error) { | ||||
| 	output, err := runtime.exec.Command("docker", "ps", "-a", "--filter", "name=k8s_", "-q").CombinedOutput() | ||||
| 	return strings.Fields(string(output)), err | ||||
| } | ||||
|  | ||||
| // RemoveContainers removes running k8s pods | ||||
| func (runtime *CRIRuntime) RemoveContainers(containers []string) error { | ||||
| 	errs := []error{} | ||||
| @@ -129,24 +102,6 @@ func (runtime *CRIRuntime) RemoveContainers(containers []string) error { | ||||
| 	return errorsutil.NewAggregate(errs) | ||||
| } | ||||
|  | ||||
| // RemoveContainers removes running containers | ||||
| func (runtime *DockerRuntime) RemoveContainers(containers []string) error { | ||||
| 	errs := []error{} | ||||
| 	for _, container := range containers { | ||||
| 		out, err := runtime.exec.Command("docker", "stop", container).CombinedOutput() | ||||
| 		if err != nil { | ||||
| 			// don't stop on errors, try to remove as many containers as possible | ||||
| 			errs = append(errs, errors.Wrapf(err, "failed to stop running container %s: output: %s, error", container, string(out))) | ||||
| 		} else { | ||||
| 			out, err = runtime.exec.Command("docker", "rm", "--volumes", container).CombinedOutput() | ||||
| 			if err != nil { | ||||
| 				errs = append(errs, errors.Wrapf(err, "failed to remove running container %s: output: %s, error", container, string(out))) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return errorsutil.NewAggregate(errs) | ||||
| } | ||||
|  | ||||
| // PullImage pulls the image | ||||
| func (runtime *CRIRuntime) PullImage(image string) error { | ||||
| 	var err error | ||||
| @@ -160,47 +115,15 @@ func (runtime *CRIRuntime) PullImage(image string) error { | ||||
| 	return errors.Wrapf(err, "output: %s, error", out) | ||||
| } | ||||
|  | ||||
| // PullImage pulls the image | ||||
| func (runtime *DockerRuntime) PullImage(image string) error { | ||||
| 	var err error | ||||
| 	var out []byte | ||||
| 	for i := 0; i < constants.PullImageRetry; i++ { | ||||
| 		out, err = runtime.exec.Command("docker", "pull", image).CombinedOutput() | ||||
| 		if err == nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return errors.Wrapf(err, "output: %s, error", out) | ||||
| } | ||||
|  | ||||
| // ImageExists checks to see if the image exists on the system | ||||
| func (runtime *CRIRuntime) ImageExists(image string) (bool, error) { | ||||
| 	err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "inspecti", image).Run() | ||||
| 	return err == nil, nil | ||||
| } | ||||
|  | ||||
| // ImageExists checks to see if the image exists on the system | ||||
| func (runtime *DockerRuntime) ImageExists(image string) (bool, error) { | ||||
| 	err := runtime.exec.Command("docker", "inspect", image).Run() | ||||
| 	return err == nil, nil | ||||
| } | ||||
|  | ||||
| // detectCRISocketImpl is separated out only for test purposes, DON'T call it directly, use DetectCRISocket instead | ||||
| func detectCRISocketImpl(isSocket func(string) bool) (string, error) { | ||||
| func detectCRISocketImpl(isSocket func(string) bool, knownCRISockets []string) (string, error) { | ||||
| 	foundCRISockets := []string{} | ||||
| 	knownCRISockets := []string{ | ||||
| 		// Docker and containerd sockets are special cased below, hence not to be included here | ||||
| 		"unix:///var/run/crio/crio.sock", | ||||
| 	} | ||||
|  | ||||
| 	if isSocket(dockerSocket) { | ||||
| 		// the path in dockerSocket is not CRI compatible, hence we should replace it with a CRI compatible socket | ||||
| 		foundCRISockets = append(foundCRISockets, constants.DefaultDockerCRISocket) | ||||
| 	} else if isSocket(containerdSocket) { | ||||
| 		// Docker 18.09 gets bundled together with containerd, thus having both dockerSocket and containerdSocket present. | ||||
| 		// For compatibility reasons, we use the containerd socket only if Docker is not detected. | ||||
| 		foundCRISockets = append(foundCRISockets, containerdSocket) | ||||
| 	} | ||||
|  | ||||
| 	for _, socket := range knownCRISockets { | ||||
| 		if isSocket(socket) { | ||||
| @@ -210,18 +133,20 @@ func detectCRISocketImpl(isSocket func(string) bool) (string, error) { | ||||
|  | ||||
| 	switch len(foundCRISockets) { | ||||
| 	case 0: | ||||
| 		// Fall back to Docker if no CRI is detected, we can error out later on if we need it | ||||
| 		return constants.DefaultDockerCRISocket, nil | ||||
| 		// Fall back to the default socket if no CRI is detected, we can error out later on if we need it | ||||
| 		return constants.DefaultCRISocket, nil | ||||
| 	case 1: | ||||
| 		// Precisely one CRI found, use that | ||||
| 		return foundCRISockets[0], nil | ||||
| 	default: | ||||
| 		// Multiple CRIs installed? | ||||
| 		return "", errors.Errorf("Found multiple CRI sockets, please use --cri-socket to select one: %s", strings.Join(foundCRISockets, ", ")) | ||||
| 		return "", errors.Errorf("Found multiple CRI endpoints on the host. Please define which one do you wish "+ | ||||
| 			"to use by setting the 'criSocket' field in the kubeadm configuration file: %s", | ||||
| 			strings.Join(foundCRISockets, ", ")) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DetectCRISocket uses a list of known CRI sockets to detect one. If more than one or none is discovered, an error is returned. | ||||
| func DetectCRISocket() (string, error) { | ||||
| 	return detectCRISocketImpl(isExistingSocket) | ||||
| 	return detectCRISocketImpl(isExistingSocket, defaultKnownCRISockets) | ||||
| } | ||||
|   | ||||
| @@ -42,30 +42,23 @@ func TestNewContainerRuntime(t *testing.T) { | ||||
| 	cases := []struct { | ||||
| 		name    string | ||||
| 		execer  fakeexec.FakeExec | ||||
| 		criSocket string | ||||
| 		isDocker  bool | ||||
| 		isError bool | ||||
| 	}{ | ||||
| 		{"valid: default cri socket", execLookPathOK, constants.DefaultDockerCRISocket, true, false}, | ||||
| 		{"valid: cri-o socket url", execLookPathOK, "unix:///var/run/crio/crio.sock", false, false}, | ||||
| 		{"invalid: no crictl", execLookPathErr, "unix:///var/run/crio/crio.sock", false, true}, | ||||
| 		{"valid: crictl present", execLookPathOK, false}, | ||||
| 		{"invalid: no crictl", execLookPathErr, true}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range cases { | ||||
| 		t.Run(tc.name, func(t *testing.T) { | ||||
| 			runtime, err := NewContainerRuntime(&tc.execer, tc.criSocket) | ||||
| 			_, err := NewContainerRuntime(&tc.execer, "unix:///some/socket.sock") | ||||
| 			if err != nil { | ||||
| 				if !tc.isError { | ||||
| 					t.Fatalf("unexpected NewContainerRuntime error. criSocket: %s, error: %v", tc.criSocket, err) | ||||
| 					t.Fatalf("unexpected NewContainerRuntime error. error: %v", err) | ||||
| 				} | ||||
| 				return // expected error occurs, impossible to test runtime further | ||||
| 			} | ||||
| 			if tc.isError && err == nil { | ||||
| 				t.Fatalf("unexpected NewContainerRuntime success. criSocket: %s", tc.criSocket) | ||||
| 			} | ||||
| 			isDocker := runtime.IsDocker() | ||||
| 			if tc.isDocker != isDocker { | ||||
| 				t.Fatalf("unexpected isDocker() result %v for the criSocket %s", isDocker, tc.criSocket) | ||||
| 				t.Fatal("unexpected NewContainerRuntime success") | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| @@ -96,11 +89,6 @@ func TestIsRunning(t *testing.T) { | ||||
| 		LookPathFunc:  func(cmd string) (string, error) { return "/usr/bin/crictl", nil }, | ||||
| 	} | ||||
|  | ||||
| 	dockerExecer := fakeexec.FakeExec{ | ||||
| 		CommandScript: genFakeActions(&fcmd, len(fcmd.CombinedOutputScript)), | ||||
| 		LookPathFunc:  func(cmd string) (string, error) { return "/usr/bin/docker", nil }, | ||||
| 	} | ||||
|  | ||||
| 	cases := []struct { | ||||
| 		name      string | ||||
| 		criSocket string | ||||
| @@ -109,8 +97,6 @@ func TestIsRunning(t *testing.T) { | ||||
| 	}{ | ||||
| 		{"valid: CRI-O is running", "unix:///var/run/crio/crio.sock", criExecer, false}, | ||||
| 		{"invalid: CRI-O is not running", "unix:///var/run/crio/crio.sock", criExecer, true}, | ||||
| 		{"valid: docker is running", constants.DefaultDockerCRISocket, dockerExecer, false}, | ||||
| 		{"invalid: docker is not running", constants.DefaultDockerCRISocket, dockerExecer, true}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range cases { | ||||
| @@ -150,7 +136,6 @@ func TestListKubeContainers(t *testing.T) { | ||||
| 	}{ | ||||
| 		{"valid: list containers using CRI socket url", "unix:///var/run/crio/crio.sock", false}, | ||||
| 		{"invalid: list containers using CRI socket url", "unix:///var/run/crio/crio.sock", true}, | ||||
| 		{"valid: list containers using docker", constants.DefaultDockerCRISocket, false}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range cases { | ||||
| @@ -204,9 +189,6 @@ func TestRemoveContainers(t *testing.T) { | ||||
| 		{"valid: remove containers using CRI", "unix:///var/run/crio/crio.sock", []string{"k8s_p1", "k8s_p2", "k8s_p3"}, false}, // Test case 1 | ||||
| 		{"invalid: CRI rmp failure", "unix:///var/run/crio/crio.sock", []string{"k8s_p1", "k8s_p2", "k8s_p3"}, true}, | ||||
| 		{"invalid: CRI stopp failure", "unix:///var/run/crio/crio.sock", []string{"k8s_p1", "k8s_p2", "k8s_p3"}, true}, | ||||
| 		{"valid: remove containers using docker", constants.DefaultDockerCRISocket, []string{"k8s_c1", "k8s_c2", "k8s_c3"}, false}, | ||||
| 		{"invalid: docker rm failure", constants.DefaultDockerCRISocket, []string{"k8s_c1", "k8s_c2", "k8s_c3"}, true}, | ||||
| 		{"invalid: docker stop failure", constants.DefaultDockerCRISocket, []string{"k8s_c1", "k8s_c2", "k8s_c3"}, true}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range cases { | ||||
| @@ -259,8 +241,6 @@ func TestPullImage(t *testing.T) { | ||||
| 	}{ | ||||
| 		{"valid: pull image using CRI", "unix:///var/run/crio/crio.sock", "image1", false}, | ||||
| 		{"invalid: CRI pull error", "unix:///var/run/crio/crio.sock", "image2", true}, | ||||
| 		{"valid: pull image using docker", constants.DefaultDockerCRISocket, "image1", false}, | ||||
| 		{"invalid: docker pull error", constants.DefaultDockerCRISocket, "image2", true}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range cases { | ||||
| @@ -302,9 +282,7 @@ func TestImageExists(t *testing.T) { | ||||
| 		result    bool | ||||
| 	}{ | ||||
| 		{"valid: test if image exists using CRI", "unix:///var/run/crio/crio.sock", "image1", false}, | ||||
| 		{"invalid: CRI inspecti failure", "unix:///var/run/crio/crio.sock", "image2", true}, | ||||
| 		{"valid: test if image exists using docker", constants.DefaultDockerCRISocket, "image1", false}, | ||||
| 		{"invalid: docker inspect failure", constants.DefaultDockerCRISocket, "image2", true}, | ||||
| 		{"invalid: CRI inspect failure", "unix:///var/run/crio/crio.sock", "image2", true}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tc := range cases { | ||||
| @@ -395,45 +373,22 @@ func TestDetectCRISocketImpl(t *testing.T) { | ||||
| 		expectedSocket  string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name:            "No existing sockets, use Docker", | ||||
| 			name:            "No existing sockets, use default", | ||||
| 			existingSockets: []string{}, | ||||
| 			expectedError:   false, | ||||
| 			expectedSocket:  constants.DefaultDockerCRISocket, | ||||
| 			expectedSocket:  constants.DefaultCRISocket, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:            "One valid CRI socket leads to success", | ||||
| 			existingSockets: []string{"unix:///var/run/crio/crio.sock"}, | ||||
| 			existingSockets: []string{"unix:///foo/bar.sock"}, | ||||
| 			expectedError:   false, | ||||
| 			expectedSocket:  "unix:///var/run/crio/crio.sock", | ||||
| 			expectedSocket:  "unix:///foo/bar.sock", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:            "Correct Docker CRI socket is returned", | ||||
| 			existingSockets: []string{"unix:///var/run/docker.sock"}, | ||||
| 			expectedError:   false, | ||||
| 			expectedSocket:  constants.DefaultDockerCRISocket, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "CRI and Docker sockets lead to an error", | ||||
| 			name: "Multiple CRI sockets lead to an error", | ||||
| 			existingSockets: []string{ | ||||
| 				"unix:///var/run/docker.sock", | ||||
| 				"unix:///var/run/crio/crio.sock", | ||||
| 			}, | ||||
| 			expectedError: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "Docker and containerd lead to Docker being used", | ||||
| 			existingSockets: []string{ | ||||
| 				"unix:///var/run/docker.sock", | ||||
| 				"unix:///run/containerd/containerd.sock", | ||||
| 			}, | ||||
| 			expectedError:  false, | ||||
| 			expectedSocket: constants.DefaultDockerCRISocket, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "A couple of CRI sockets lead to an error", | ||||
| 			existingSockets: []string{ | ||||
| 				"unix:///var/run/crio/crio.sock", | ||||
| 				"unix:///run/containerd/containerd.sock", | ||||
| 				"unix:///foo/bar.sock", | ||||
| 				"unix:///foo/baz.sock", | ||||
| 			}, | ||||
| 			expectedError: true, | ||||
| 		}, | ||||
| @@ -447,9 +402,9 @@ func TestDetectCRISocketImpl(t *testing.T) { | ||||
| 						return true | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				return false | ||||
| 			}) | ||||
| 			}, test.existingSockets) | ||||
|  | ||||
| 			if (err != nil) != test.expectedError { | ||||
| 				t.Fatalf("detectCRISocketImpl returned unexpected result\n\tExpected error: %t\n\tGot error: %t", test.expectedError, err != nil) | ||||
| 			} | ||||
|   | ||||
| @@ -24,11 +24,6 @@ import ( | ||||
| 	"net/url" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	dockerSocket     = "unix:///var/run/docker.sock" // The Docker socket is not CRI compatible | ||||
| 	containerdSocket = "unix:///run/containerd/containerd.sock" | ||||
| ) | ||||
|  | ||||
| // isExistingSocket checks if path exists and is domain socket | ||||
| func isExistingSocket(path string) bool { | ||||
| 	u, err := url.Parse(path) | ||||
|   | ||||
| @@ -25,11 +25,6 @@ import ( | ||||
| 	winio "github.com/Microsoft/go-winio" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	dockerSocket     = "npipe:////./pipe/docker_engine"         // The Docker socket is not CRI compatible | ||||
| 	containerdSocket = "npipe:////./pipe/containerd-containerd" // Proposed containerd named pipe for Windows | ||||
| ) | ||||
|  | ||||
| // isExistingSocket checks if path exists and is domain socket | ||||
| func isExistingSocket(path string) bool { | ||||
| 	u, err := url.Parse(path) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Prow Robot
					Kubernetes Prow Robot