183 lines
6.0 KiB
Go
183 lines
6.0 KiB
Go
/*
|
|
Copyright 2018 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package util
|
|
|
|
import (
|
|
"path/filepath"
|
|
goruntime "runtime"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
errorsutil "k8s.io/apimachinery/pkg/util/errors"
|
|
kubeadmapiv1beta1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta1"
|
|
utilsexec "k8s.io/utils/exec"
|
|
)
|
|
|
|
// ContainerRuntime is an interface for working with container runtimes
|
|
type ContainerRuntime interface {
|
|
IsDocker() bool
|
|
IsRunning() error
|
|
ListKubeContainers() ([]string, error)
|
|
RemoveContainers(containers []string) error
|
|
PullImage(image string) error
|
|
ImageExists(image string) (bool, error)
|
|
}
|
|
|
|
// CRIRuntime is a struct that interfaces with the CRI
|
|
type CRIRuntime struct {
|
|
exec utilsexec.Interface
|
|
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 != kubeadmapiv1beta1.DefaultCRISocket {
|
|
toolName = "crictl"
|
|
// !!! temporary work around crictl warning:
|
|
// Using "/var/run/crio/crio.sock" as endpoint is deprecated,
|
|
// please consider using full url format "unix:///var/run/crio/crio.sock"
|
|
if filepath.IsAbs(criSocket) && goruntime.GOOS != "windows" {
|
|
criSocket = "unix://" + criSocket
|
|
}
|
|
runtime = &CRIRuntime{execer, criSocket}
|
|
} else {
|
|
toolName = "docker"
|
|
runtime = &DockerRuntime{execer}
|
|
}
|
|
|
|
if _, err := execer.LookPath(toolName); err != nil {
|
|
return nil, errors.Wrapf(err, "%s is required for 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
|
|
}
|
|
|
|
// IsRunning checks if runtime is running
|
|
func (runtime *CRIRuntime) IsRunning() error {
|
|
if out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "info").CombinedOutput(); err != nil {
|
|
return errors.Wrapf(err, "container runtime is not running: output: %s, error", string(out))
|
|
}
|
|
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()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "output: %s, error", string(out))
|
|
}
|
|
pods := []string{}
|
|
for _, pod := range strings.Fields(string(out)) {
|
|
pods = append(pods, pod)
|
|
}
|
|
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{}
|
|
for _, container := range containers {
|
|
out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "stopp", 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 pod %s: output: %s, error", container, string(out)))
|
|
} else {
|
|
out, err = runtime.exec.Command("crictl", "-r", runtime.criSocket, "rmp", 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)
|
|
}
|
|
|
|
// RemoveContainers removes running containers
|
|
func (runtime *DockerRuntime) RemoveContainers(containers []string) error {
|
|
errs := []error{}
|
|
for _, container := range containers {
|
|
out, err := runtime.exec.Command("docker", "rm", "--force", "--volumes", 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 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 {
|
|
out, err := runtime.exec.Command("crictl", "-r", runtime.criSocket, "pull", image).CombinedOutput()
|
|
if err != nil {
|
|
return errors.Wrapf(err, "output: %s, error", string(out))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PullImage pulls the image
|
|
func (runtime *DockerRuntime) PullImage(image string) error {
|
|
out, err := runtime.exec.Command("docker", "pull", image).CombinedOutput()
|
|
if err != nil {
|
|
return errors.Wrapf(err, "output: %s, error", string(out))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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
|
|
}
|