mirror of https://github.com/k3s-io/k3s
Merge pull request #45307 from yujuhong/mv-docker-client
Automatic merge from submit-queue (batch tested with PRs 45453, 45307, 44987) Migrate the docker client code from dockertools to dockershim Move docker client code from dockertools to dockershim/libdocker. This includes DockerInterface (renamed to Interface), FakeDockerClient, etc. This is part of #43234pull/6/head
commit
51a3413371
|
@ -56,8 +56,8 @@ go_library(
|
||||||
"//pkg/kubelet/config:go_default_library",
|
"//pkg/kubelet/config:go_default_library",
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/dockershim:go_default_library",
|
"//pkg/kubelet/dockershim:go_default_library",
|
||||||
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/remote:go_default_library",
|
"//pkg/kubelet/dockershim/remote:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
|
||||||
"//pkg/kubelet/eviction:go_default_library",
|
"//pkg/kubelet/eviction:go_default_library",
|
||||||
"//pkg/kubelet/eviction/api:go_default_library",
|
"//pkg/kubelet/eviction/api:go_default_library",
|
||||||
"//pkg/kubelet/network:go_default_library",
|
"//pkg/kubelet/network:go_default_library",
|
||||||
|
|
|
@ -72,8 +72,8 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubelet/config"
|
"k8s.io/kubernetes/pkg/kubelet/config"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockershim"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
dockerremote "k8s.io/kubernetes/pkg/kubelet/dockershim/remote"
|
dockerremote "k8s.io/kubernetes/pkg/kubelet/dockershim/remote"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/eviction"
|
"k8s.io/kubernetes/pkg/kubelet/eviction"
|
||||||
evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
|
evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/server"
|
"k8s.io/kubernetes/pkg/kubelet/server"
|
||||||
|
@ -143,9 +143,9 @@ func UnsecuredKubeletDeps(s *options.KubeletServer) (*kubelet.KubeletDeps, error
|
||||||
writer = &kubeio.NsenterWriter{}
|
writer = &kubeio.NsenterWriter{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var dockerClient dockertools.DockerInterface
|
var dockerClient libdocker.Interface
|
||||||
if s.ContainerRuntime == "docker" {
|
if s.ContainerRuntime == "docker" {
|
||||||
dockerClient = dockertools.ConnectToDockerOrDie(s.DockerEndpoint, s.RuntimeRequestTimeout.Duration,
|
dockerClient = libdocker.ConnectToDockerOrDie(s.DockerEndpoint, s.RuntimeRequestTimeout.Duration,
|
||||||
s.ImagePullProgressDeadline.Duration)
|
s.ImagePullProgressDeadline.Duration)
|
||||||
} else {
|
} else {
|
||||||
dockerClient = nil
|
dockerClient = nil
|
||||||
|
@ -937,7 +937,7 @@ func parseResourceList(m componentconfig.ConfigurationMap) (v1.ResourceList, err
|
||||||
// TODO(random-liu): Move this to a separate binary.
|
// TODO(random-liu): Move this to a separate binary.
|
||||||
func RunDockershim(c *componentconfig.KubeletConfiguration, dockershimRootDir string) error {
|
func RunDockershim(c *componentconfig.KubeletConfiguration, dockershimRootDir string) error {
|
||||||
// Create docker client.
|
// Create docker client.
|
||||||
dockerClient := dockertools.ConnectToDockerOrDie(c.DockerEndpoint, c.RuntimeRequestTimeout.Duration,
|
dockerClient := libdocker.ConnectToDockerOrDie(c.DockerEndpoint, c.RuntimeRequestTimeout.Duration,
|
||||||
c.ImagePullProgressDeadline.Duration)
|
c.ImagePullProgressDeadline.Duration)
|
||||||
|
|
||||||
// Initialize network plugin settings.
|
// Initialize network plugin settings.
|
||||||
|
|
|
@ -25,7 +25,7 @@ go_library(
|
||||||
"//pkg/client/metrics/prometheus:go_default_library",
|
"//pkg/client/metrics/prometheus:go_default_library",
|
||||||
"//pkg/kubelet/cadvisor/testing:go_default_library",
|
"//pkg/kubelet/cadvisor/testing:go_default_library",
|
||||||
"//pkg/kubelet/cm:go_default_library",
|
"//pkg/kubelet/cm:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubemark:go_default_library",
|
"//pkg/kubemark:go_default_library",
|
||||||
"//pkg/util/iptables/testing:go_default_library",
|
"//pkg/util/iptables/testing:go_default_library",
|
||||||
"//pkg/version/prometheus:go_default_library",
|
"//pkg/version/prometheus:go_default_library",
|
||||||
|
|
|
@ -33,7 +33,7 @@ import (
|
||||||
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
||||||
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
|
cadvisortest "k8s.io/kubernetes/pkg/kubelet/cadvisor/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubemark"
|
"k8s.io/kubernetes/pkg/kubemark"
|
||||||
fakeiptables "k8s.io/kubernetes/pkg/util/iptables/testing"
|
fakeiptables "k8s.io/kubernetes/pkg/util/iptables/testing"
|
||||||
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
||||||
|
@ -113,7 +113,7 @@ func main() {
|
||||||
cadvisorInterface := new(cadvisortest.Fake)
|
cadvisorInterface := new(cadvisortest.Fake)
|
||||||
containerManager := cm.NewStubContainerManager()
|
containerManager := cm.NewStubContainerManager()
|
||||||
|
|
||||||
fakeDockerClient := dockertools.NewFakeDockerClient().WithTraceDisabled()
|
fakeDockerClient := libdocker.NewFakeDockerClient().WithTraceDisabled()
|
||||||
fakeDockerClient.EnableSleep = true
|
fakeDockerClient.EnableSleep = true
|
||||||
|
|
||||||
hollowKubelet := kubemark.NewHollowKubelet(
|
hollowKubelet := kubemark.NewHollowKubelet(
|
||||||
|
|
|
@ -56,8 +56,8 @@ go_library(
|
||||||
"//pkg/kubelet/config:go_default_library",
|
"//pkg/kubelet/config:go_default_library",
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/dockershim:go_default_library",
|
"//pkg/kubelet/dockershim:go_default_library",
|
||||||
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/remote:go_default_library",
|
"//pkg/kubelet/dockershim/remote:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
|
||||||
"//pkg/kubelet/envvars:go_default_library",
|
"//pkg/kubelet/envvars:go_default_library",
|
||||||
"//pkg/kubelet/events:go_default_library",
|
"//pkg/kubelet/events:go_default_library",
|
||||||
"//pkg/kubelet/eviction:go_default_library",
|
"//pkg/kubelet/eviction:go_default_library",
|
||||||
|
|
|
@ -39,8 +39,8 @@ go_library(
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/cm:go_default_library",
|
"//pkg/kubelet/dockershim/cm:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/errors:go_default_library",
|
"//pkg/kubelet/dockershim/errors:go_default_library",
|
||||||
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/securitycontext:go_default_library",
|
"//pkg/kubelet/dockershim/securitycontext:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
|
||||||
"//pkg/kubelet/leaky:go_default_library",
|
"//pkg/kubelet/leaky:go_default_library",
|
||||||
"//pkg/kubelet/network:go_default_library",
|
"//pkg/kubelet/network:go_default_library",
|
||||||
"//pkg/kubelet/network/cni:go_default_library",
|
"//pkg/kubelet/network/cni:go_default_library",
|
||||||
|
@ -96,9 +96,9 @@ go_test(
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/container/testing:go_default_library",
|
"//pkg/kubelet/container/testing:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/errors:go_default_library",
|
"//pkg/kubelet/dockershim/errors:go_default_library",
|
||||||
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/securitycontext:go_default_library",
|
"//pkg/kubelet/dockershim/securitycontext:go_default_library",
|
||||||
"//pkg/kubelet/dockershim/testing:go_default_library",
|
"//pkg/kubelet/dockershim/testing:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
|
||||||
"//pkg/kubelet/network:go_default_library",
|
"//pkg/kubelet/network:go_default_library",
|
||||||
"//pkg/kubelet/network/testing:go_default_library",
|
"//pkg/kubelet/network/testing:go_default_library",
|
||||||
"//pkg/kubelet/types:go_default_library",
|
"//pkg/kubelet/types:go_default_library",
|
||||||
|
@ -128,6 +128,7 @@ filegroup(
|
||||||
":package-srcs",
|
":package-srcs",
|
||||||
"//pkg/kubelet/dockershim/cm:all-srcs",
|
"//pkg/kubelet/dockershim/cm:all-srcs",
|
||||||
"//pkg/kubelet/dockershim/errors:all-srcs",
|
"//pkg/kubelet/dockershim/errors:all-srcs",
|
||||||
|
"//pkg/kubelet/dockershim/libdocker:all-srcs",
|
||||||
"//pkg/kubelet/dockershim/remote:all-srcs",
|
"//pkg/kubelet/dockershim/remote:all-srcs",
|
||||||
"//pkg/kubelet/dockershim/securitycontext:all-srcs",
|
"//pkg/kubelet/dockershim/securitycontext:all-srcs",
|
||||||
"//pkg/kubelet/dockershim/testing:all-srcs",
|
"//pkg/kubelet/dockershim/testing:all-srcs",
|
||||||
|
|
|
@ -16,7 +16,7 @@ go_library(
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/kubelet/cm:go_default_library",
|
"//pkg/kubelet/cm:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/qos:go_default_library",
|
"//pkg/kubelet/qos:go_default_library",
|
||||||
"//pkg/util/version:go_default_library",
|
"//pkg/util/version:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
|
|
|
@ -30,9 +30,10 @@ import (
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
kubecm "k8s.io/kubernetes/pkg/kubelet/cm"
|
kubecm "k8s.io/kubernetes/pkg/kubelet/cm"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -50,7 +51,7 @@ var (
|
||||||
memoryCapacityRegexp = regexp.MustCompile(`MemTotal:\s*([0-9]+) kB`)
|
memoryCapacityRegexp = regexp.MustCompile(`MemTotal:\s*([0-9]+) kB`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewContainerManager(cgroupsName string, client dockertools.DockerInterface) ContainerManager {
|
func NewContainerManager(cgroupsName string, client libdocker.Interface) ContainerManager {
|
||||||
return &containerManager{
|
return &containerManager{
|
||||||
cgroupsName: cgroupsName,
|
cgroupsName: cgroupsName,
|
||||||
client: client,
|
client: client,
|
||||||
|
@ -59,7 +60,7 @@ func NewContainerManager(cgroupsName string, client dockertools.DockerInterface)
|
||||||
|
|
||||||
type containerManager struct {
|
type containerManager struct {
|
||||||
// Docker client.
|
// Docker client.
|
||||||
client dockertools.DockerInterface
|
client libdocker.Interface
|
||||||
// Name of the cgroups.
|
// Name of the cgroups.
|
||||||
cgroupsName string
|
cgroupsName string
|
||||||
// Manager for the cgroups.
|
// Manager for the cgroups.
|
||||||
|
|
|
@ -21,13 +21,13 @@ package cm
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
type unsupportedContainerManager struct {
|
type unsupportedContainerManager struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContainerManager(_ string, _ dockertools.DockerInterface) ContainerManager {
|
func NewContainerManager(_ string, _ libdocker.Interface) ContainerManager {
|
||||||
return &unsupportedContainerManager{}
|
return &unsupportedContainerManager{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,18 +24,12 @@ import (
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file contains helper functions to convert docker API types to runtime
|
// This file contains helper functions to convert docker API types to runtime
|
||||||
// API types, or vice versa.
|
// API types, or vice versa.
|
||||||
|
|
||||||
const (
|
|
||||||
// Status of a container returned by docker ListContainers
|
|
||||||
statusRunningPrefix = "Up"
|
|
||||||
statusCreatedPrefix = "Created"
|
|
||||||
statusExitedPrefix = "Exited"
|
|
||||||
)
|
|
||||||
|
|
||||||
func imageToRuntimeAPIImage(image *dockertypes.Image) (*runtimeapi.Image, error) {
|
func imageToRuntimeAPIImage(image *dockertypes.Image) (*runtimeapi.Image, error) {
|
||||||
if image == nil {
|
if image == nil {
|
||||||
return nil, fmt.Errorf("unable to convert a nil pointer to a runtime API image")
|
return nil, fmt.Errorf("unable to convert a nil pointer to a runtime API image")
|
||||||
|
@ -126,11 +120,11 @@ func toRuntimeAPIContainerState(state string) runtimeapi.ContainerState {
|
||||||
// Parse the state string in dockertypes.Container. This could break when
|
// Parse the state string in dockertypes.Container. This could break when
|
||||||
// we upgrade docker.
|
// we upgrade docker.
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(state, statusRunningPrefix):
|
case strings.HasPrefix(state, libdocker.StatusRunningPrefix):
|
||||||
return runtimeapi.ContainerState_CONTAINER_RUNNING
|
return runtimeapi.ContainerState_CONTAINER_RUNNING
|
||||||
case strings.HasPrefix(state, statusExitedPrefix):
|
case strings.HasPrefix(state, libdocker.StatusExitedPrefix):
|
||||||
return runtimeapi.ContainerState_CONTAINER_EXITED
|
return runtimeapi.ContainerState_CONTAINER_EXITED
|
||||||
case strings.HasPrefix(state, statusCreatedPrefix):
|
case strings.HasPrefix(state, libdocker.StatusCreatedPrefix):
|
||||||
return runtimeapi.ContainerState_CONTAINER_CREATED
|
return runtimeapi.ContainerState_CONTAINER_CREATED
|
||||||
default:
|
default:
|
||||||
return runtimeapi.ContainerState_CONTAINER_UNKNOWN
|
return runtimeapi.ContainerState_CONTAINER_UNKNOWN
|
||||||
|
@ -141,7 +135,7 @@ func toRuntimeAPISandboxState(state string) runtimeapi.PodSandboxState {
|
||||||
// Parse the state string in dockertypes.Container. This could break when
|
// Parse the state string in dockertypes.Container. This could break when
|
||||||
// we upgrade docker.
|
// we upgrade docker.
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(state, statusRunningPrefix):
|
case strings.HasPrefix(state, libdocker.StatusRunningPrefix):
|
||||||
return runtimeapi.PodSandboxState_SANDBOX_READY
|
return runtimeapi.PodSandboxState_SANDBOX_READY
|
||||||
default:
|
default:
|
||||||
return runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
return runtimeapi.PodSandboxState_SANDBOX_NOTREADY
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListContainers lists all containers matching the filter.
|
// ListContainers lists all containers matching the filter.
|
||||||
|
@ -307,15 +307,15 @@ func getContainerTimestamps(r *dockertypes.ContainerJSON) (time.Time, time.Time,
|
||||||
var createdAt, startedAt, finishedAt time.Time
|
var createdAt, startedAt, finishedAt time.Time
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
createdAt, err = dockertools.ParseDockerTimestamp(r.Created)
|
createdAt, err = libdocker.ParseDockerTimestamp(r.Created)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return createdAt, startedAt, finishedAt, err
|
return createdAt, startedAt, finishedAt, err
|
||||||
}
|
}
|
||||||
startedAt, err = dockertools.ParseDockerTimestamp(r.State.StartedAt)
|
startedAt, err = libdocker.ParseDockerTimestamp(r.State.StartedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return createdAt, startedAt, finishedAt, err
|
return createdAt, startedAt, finishedAt, err
|
||||||
}
|
}
|
||||||
finishedAt, err = dockertools.ParseDockerTimestamp(r.State.FinishedAt)
|
finishedAt, err = libdocker.ParseDockerTimestamp(r.State.FinishedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return createdAt, startedAt, finishedAt, err
|
return createdAt, startedAt, finishedAt, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ import (
|
||||||
|
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file implements methods in ImageManagerService.
|
// This file implements methods in ImageManagerService.
|
||||||
|
@ -56,7 +57,7 @@ func (ds *dockerService) ListImages(filter *runtimeapi.ImageFilter) ([]*runtimea
|
||||||
func (ds *dockerService) ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error) {
|
func (ds *dockerService) ImageStatus(image *runtimeapi.ImageSpec) (*runtimeapi.Image, error) {
|
||||||
imageInspect, err := ds.client.InspectImageByRef(image.Image)
|
imageInspect, err := ds.client.InspectImageByRef(image.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if dockertools.IsImageNotFoundError(err) {
|
if libdocker.IsImageNotFoundError(err) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -105,7 +106,7 @@ func (ds *dockerService) RemoveImage(image *runtimeapi.ImageSpec) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getImageRef returns the image digest if exists, or else returns the image ID.
|
// getImageRef returns the image digest if exists, or else returns the image ID.
|
||||||
func getImageRef(client dockertools.DockerInterface, image string) (string, error) {
|
func getImageRef(client libdocker.Interface, image string) (string, error) {
|
||||||
img, err := client.InspectImageByRef(image)
|
img, err := client.InspectImageByRef(image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -22,7 +22,8 @@ import (
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRemoveImage(t *testing.T) {
|
func TestRemoveImage(t *testing.T) {
|
||||||
|
@ -30,8 +31,8 @@ func TestRemoveImage(t *testing.T) {
|
||||||
id := "1111"
|
id := "1111"
|
||||||
fakeDocker.InjectImageInspects([]dockertypes.ImageInspect{{ID: id, RepoTags: []string{"foo"}}})
|
fakeDocker.InjectImageInspects([]dockertypes.ImageInspect{{ID: id, RepoTags: []string{"foo"}}})
|
||||||
ds.RemoveImage(&runtimeapi.ImageSpec{Image: id})
|
ds.RemoveImage(&runtimeapi.ImageSpec{Image: id})
|
||||||
fakeDocker.AssertCallDetails(dockertools.NewCalledDetail("inspect_image", nil),
|
fakeDocker.AssertCallDetails(libdocker.NewCalledDetail("inspect_image", nil),
|
||||||
dockertools.NewCalledDetail("remove_image", []interface{}{id, dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
libdocker.NewCalledDetail("remove_image", []interface{}{id, dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveImageWithMultipleTags(t *testing.T) {
|
func TestRemoveImageWithMultipleTags(t *testing.T) {
|
||||||
|
@ -39,7 +40,7 @@ func TestRemoveImageWithMultipleTags(t *testing.T) {
|
||||||
id := "1111"
|
id := "1111"
|
||||||
fakeDocker.InjectImageInspects([]dockertypes.ImageInspect{{ID: id, RepoTags: []string{"foo", "bar"}}})
|
fakeDocker.InjectImageInspects([]dockertypes.ImageInspect{{ID: id, RepoTags: []string{"foo", "bar"}}})
|
||||||
ds.RemoveImage(&runtimeapi.ImageSpec{Image: id})
|
ds.RemoveImage(&runtimeapi.ImageSpec{Image: id})
|
||||||
fakeDocker.AssertCallDetails(dockertools.NewCalledDetail("inspect_image", nil),
|
fakeDocker.AssertCallDetails(libdocker.NewCalledDetail("inspect_image", nil),
|
||||||
dockertools.NewCalledDetail("remove_image", []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}),
|
libdocker.NewCalledDetail("remove_image", []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}),
|
||||||
dockertools.NewCalledDetail("remove_image", []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
libdocker.NewCalledDetail("remove_image", []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/leaky"
|
"k8s.io/kubernetes/pkg/kubelet/leaky"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ func convertLegacyNameAndLabels(names []string, labels map[string]string) ([]str
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate new dockershim name.
|
// Generate new dockershim name.
|
||||||
m, _, err := dockertools.ParseDockerName(names[0])
|
m, _, err := libdocker.ParseDockerName(names[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,8 +105,8 @@ func TestConvertLegacyNameAndLabels(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFakeLegacyContainers returns a list of fake legacy containers.
|
// getFakeLegacyContainers returns a list of fake legacy containers.
|
||||||
func getFakeLegacyContainers() []*dockertools.FakeContainer {
|
func getFakeLegacyContainers() []*libdocker.FakeContainer {
|
||||||
return []*dockertools.FakeContainer{
|
return []*libdocker.FakeContainer{
|
||||||
{
|
{
|
||||||
ID: "12",
|
ID: "12",
|
||||||
Name: "k8s_POD.hash1_podname_podnamespace_poduid_randomid",
|
Name: "k8s_POD.hash1_podname_podnamespace_poduid_randomid",
|
||||||
|
@ -139,8 +139,8 @@ func getFakeLegacyContainers() []*dockertools.FakeContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFakeNewContainers returns a list of fake new containers.
|
// getFakeNewContainers returns a list of fake new containers.
|
||||||
func getFakeNewContainers() []*dockertools.FakeContainer {
|
func getFakeNewContainers() []*libdocker.FakeContainer {
|
||||||
return []*dockertools.FakeContainer{
|
return []*libdocker.FakeContainer{
|
||||||
{
|
{
|
||||||
ID: "56",
|
ID: "56",
|
||||||
Name: "k8s_POD_podname_podnamespace_poduid_0",
|
Name: "k8s_POD_podname_podnamespace_poduid_0",
|
||||||
|
@ -233,11 +233,11 @@ func TestListLegacyPodSandbox(t *testing.T) {
|
||||||
|
|
||||||
func TestCheckLegacyCleanup(t *testing.T) {
|
func TestCheckLegacyCleanup(t *testing.T) {
|
||||||
for desc, test := range map[string]struct {
|
for desc, test := range map[string]struct {
|
||||||
containers []*dockertools.FakeContainer
|
containers []*libdocker.FakeContainer
|
||||||
done bool
|
done bool
|
||||||
}{
|
}{
|
||||||
"no containers": {
|
"no containers": {
|
||||||
containers: []*dockertools.FakeContainer{},
|
containers: []*libdocker.FakeContainer{},
|
||||||
done: true,
|
done: true,
|
||||||
},
|
},
|
||||||
"only new containers": {
|
"only new containers": {
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockershim/errors"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/errors"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/qos"
|
"k8s.io/kubernetes/pkg/kubelet/qos"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
)
|
)
|
||||||
|
@ -161,7 +161,7 @@ func (ds *dockerService) StopPodSandbox(podSandboxID string) error {
|
||||||
// actions will only have sandbox ID and not have pod namespace and name information.
|
// actions will only have sandbox ID and not have pod namespace and name information.
|
||||||
// Return error if encounter any unexpected error.
|
// Return error if encounter any unexpected error.
|
||||||
if checkpointErr != nil {
|
if checkpointErr != nil {
|
||||||
if dockertools.IsContainerNotFoundError(statusErr) && checkpointErr == errors.CheckpointNotFoundError {
|
if libdocker.IsContainerNotFoundError(statusErr) && checkpointErr == errors.CheckpointNotFoundError {
|
||||||
glog.Warningf("Both sandbox container and checkpoint for id %q could not be found. "+
|
glog.Warningf("Both sandbox container and checkpoint for id %q could not be found. "+
|
||||||
"Proceed without further sandbox information.", podSandboxID)
|
"Proceed without further sandbox information.", podSandboxID)
|
||||||
} else {
|
} else {
|
||||||
|
@ -206,7 +206,7 @@ func (ds *dockerService) StopPodSandbox(podSandboxID string) error {
|
||||||
if err := ds.client.StopContainer(podSandboxID, defaultSandboxGracePeriod); err != nil {
|
if err := ds.client.StopContainer(podSandboxID, defaultSandboxGracePeriod); err != nil {
|
||||||
glog.Errorf("Failed to stop sandbox %q: %v", podSandboxID, err)
|
glog.Errorf("Failed to stop sandbox %q: %v", podSandboxID, err)
|
||||||
// Do not return error if the container does not exist
|
// Do not return error if the container does not exist
|
||||||
if !dockertools.IsContainerNotFoundError(err) {
|
if !libdocker.IsContainerNotFoundError(err) {
|
||||||
errList = append(errList, err)
|
errList = append(errList, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,13 +231,13 @@ func (ds *dockerService) RemovePodSandbox(podSandboxID string) error {
|
||||||
|
|
||||||
// Remove all containers in the sandbox.
|
// Remove all containers in the sandbox.
|
||||||
for i := range containers {
|
for i := range containers {
|
||||||
if err := ds.RemoveContainer(containers[i].ID); err != nil && !dockertools.IsContainerNotFoundError(err) {
|
if err := ds.RemoveContainer(containers[i].ID); err != nil && !libdocker.IsContainerNotFoundError(err) {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the sandbox container.
|
// Remove the sandbox container.
|
||||||
if err := ds.client.RemoveContainer(podSandboxID, dockertypes.ContainerRemoveOptions{RemoveVolumes: true}); err != nil && !dockertools.IsContainerNotFoundError(err) {
|
if err := ds.client.RemoveContainer(podSandboxID, dockertypes.ContainerRemoveOptions{RemoveVolumes: true}); err != nil && !libdocker.IsContainerNotFoundError(err) {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
|
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
)
|
)
|
||||||
|
@ -158,7 +158,7 @@ func TestNetworkPluginInvocation(t *testing.T) {
|
||||||
map[string]string{"label": name},
|
map[string]string{"label": name},
|
||||||
map[string]string{"annotation": ns},
|
map[string]string{"annotation": ns},
|
||||||
)
|
)
|
||||||
cID := kubecontainer.ContainerID{Type: runtimeName, ID: dockertools.GetFakeContainerID(fmt.Sprintf("/%v", makeSandboxName(c)))}
|
cID := kubecontainer.ContainerID{Type: runtimeName, ID: libdocker.GetFakeContainerID(fmt.Sprintf("/%v", makeSandboxName(c)))}
|
||||||
|
|
||||||
mockPlugin.EXPECT().Name().Return("mockNetworkPlugin").AnyTimes()
|
mockPlugin.EXPECT().Name().Return("mockNetworkPlugin").AnyTimes()
|
||||||
setup := mockPlugin.EXPECT().SetUpPod(ns, name, cID)
|
setup := mockPlugin.EXPECT().SetUpPod(ns, name, cID)
|
||||||
|
@ -196,7 +196,7 @@ func TestHostNetworkPluginInvocation(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cID := kubecontainer.ContainerID{Type: runtimeName, ID: dockertools.GetFakeContainerID(fmt.Sprintf("/%v", makeSandboxName(c)))}
|
cID := kubecontainer.ContainerID{Type: runtimeName, ID: libdocker.GetFakeContainerID(fmt.Sprintf("/%v", makeSandboxName(c)))}
|
||||||
|
|
||||||
// No calls to network plugin are expected
|
// No calls to network plugin are expected
|
||||||
_, err := ds.RunPodSandbox(c)
|
_, err := ds.RunPodSandbox(c)
|
||||||
|
@ -219,7 +219,7 @@ func TestSetUpPodFailure(t *testing.T) {
|
||||||
map[string]string{"label": name},
|
map[string]string{"label": name},
|
||||||
map[string]string{"annotation": ns},
|
map[string]string{"annotation": ns},
|
||||||
)
|
)
|
||||||
cID := kubecontainer.ContainerID{Type: runtimeName, ID: dockertools.GetFakeContainerID(fmt.Sprintf("/%v", makeSandboxName(c)))}
|
cID := kubecontainer.ContainerID{Type: runtimeName, ID: libdocker.GetFakeContainerID(fmt.Sprintf("/%v", makeSandboxName(c)))}
|
||||||
mockPlugin.EXPECT().Name().Return("mockNetworkPlugin").AnyTimes()
|
mockPlugin.EXPECT().Name().Return("mockNetworkPlugin").AnyTimes()
|
||||||
mockPlugin.EXPECT().SetUpPod(ns, name, cID).Return(errors.New("setup pod error")).AnyTimes()
|
mockPlugin.EXPECT().SetUpPod(ns, name, cID).Return(errors.New("setup pod error")).AnyTimes()
|
||||||
// Assume network plugin doesn't return error, dockershim should still be able to return not ready correctly.
|
// Assume network plugin doesn't return error, dockershim should still be able to return not ready correctly.
|
||||||
|
|
|
@ -36,23 +36,20 @@ import (
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockershim/cm"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/cm"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockershim/errors"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/errors"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network/cni"
|
"k8s.io/kubernetes/pkg/kubelet/network/cni"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network/hostport"
|
"k8s.io/kubernetes/pkg/kubelet/network/hostport"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network/kubenet"
|
"k8s.io/kubernetes/pkg/kubelet/network/kubenet"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util/cache"
|
"k8s.io/kubernetes/pkg/kubelet/util/cache"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
dockerRuntimeName = "docker"
|
dockerRuntimeName = "docker"
|
||||||
kubeAPIVersion = "0.1.0"
|
kubeAPIVersion = "0.1.0"
|
||||||
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api/
|
|
||||||
// docker version should be at least 1.10.x
|
|
||||||
minimumDockerAPIVersion = "1.22.0"
|
|
||||||
|
|
||||||
// String used to detect docker host mode for various namespaces (e.g.
|
// String used to detect docker host mode for various namespaces (e.g.
|
||||||
// networking). Must match the value returned by docker inspect -f
|
// networking). Must match the value returned by docker inspect -f
|
||||||
// '{{.HostConfig.NetworkMode}}'.
|
// '{{.HostConfig.NetworkMode}}'.
|
||||||
|
@ -148,9 +145,9 @@ type dockerNetworkHost struct {
|
||||||
var internalLabelKeys []string = []string{containerTypeLabelKey, containerLogPathLabelKey, sandboxIDLabelKey}
|
var internalLabelKeys []string = []string{containerTypeLabelKey, containerLogPathLabelKey, sandboxIDLabelKey}
|
||||||
|
|
||||||
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
|
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
|
||||||
func NewDockerService(client dockertools.DockerInterface, seccompProfileRoot string, podSandboxImage string, streamingConfig *streaming.Config,
|
func NewDockerService(client libdocker.Interface, seccompProfileRoot string, podSandboxImage string, streamingConfig *streaming.Config,
|
||||||
pluginSettings *NetworkPluginSettings, cgroupsName string, kubeCgroupDriver string, execHandlerName, dockershimRootDir string, disableSharedPID bool) (DockerService, error) {
|
pluginSettings *NetworkPluginSettings, cgroupsName string, kubeCgroupDriver string, execHandlerName, dockershimRootDir string, disableSharedPID bool) (DockerService, error) {
|
||||||
c := dockertools.NewInstrumentedDockerInterface(client)
|
c := libdocker.NewInstrumentedInterface(client)
|
||||||
checkpointHandler, err := NewPersistentCheckpointHandler(dockershimRootDir)
|
checkpointHandler, err := NewPersistentCheckpointHandler(dockershimRootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -246,7 +243,7 @@ type DockerService interface {
|
||||||
|
|
||||||
type dockerService struct {
|
type dockerService struct {
|
||||||
seccompProfileRoot string
|
seccompProfileRoot string
|
||||||
client dockertools.DockerInterface
|
client libdocker.Interface
|
||||||
os kubecontainer.OSInterface
|
os kubecontainer.OSInterface
|
||||||
podSandboxImage string
|
podSandboxImage string
|
||||||
streamingRuntime *streamingRuntime
|
streamingRuntime *streamingRuntime
|
||||||
|
@ -413,7 +410,7 @@ func (ds *dockerService) checkVersionCompatibility() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
minAPIVersion, err := semver.Parse(minimumDockerAPIVersion)
|
minAPIVersion, err := semver.Parse(libdocker.MinimumDockerAPIVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -421,7 +418,7 @@ func (ds *dockerService) checkVersionCompatibility() error {
|
||||||
// Verify the docker version.
|
// Verify the docker version.
|
||||||
result := apiVersion.Compare(minAPIVersion)
|
result := apiVersion.Compare(minAPIVersion)
|
||||||
if result < 0 {
|
if result < 0 {
|
||||||
return fmt.Errorf("docker API version is older than %s", minimumDockerAPIVersion)
|
return fmt.Errorf("docker API version is older than %s", libdocker.MinimumDockerAPIVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -478,10 +475,10 @@ type DockerLegacyService interface {
|
||||||
// dockerLegacyService implements the DockerLegacyService. We add this for non json-log driver
|
// dockerLegacyService implements the DockerLegacyService. We add this for non json-log driver
|
||||||
// support. (See #41996)
|
// support. (See #41996)
|
||||||
type dockerLegacyService struct {
|
type dockerLegacyService struct {
|
||||||
client dockertools.DockerInterface
|
client libdocker.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerLegacyService(client dockertools.DockerInterface) DockerLegacyService {
|
func NewDockerLegacyService(client libdocker.Interface) DockerLegacyService {
|
||||||
return &dockerLegacyService{client: client}
|
return &dockerLegacyService{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,7 +508,7 @@ func (d *dockerLegacyService) GetContainerLogs(pod *v1.Pod, containerID kubecont
|
||||||
opts.Tail = strconv.FormatInt(*logOptions.TailLines, 10)
|
opts.Tail = strconv.FormatInt(*logOptions.TailLines, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
sopts := dockertools.StreamOptions{
|
sopts := libdocker.StreamOptions{
|
||||||
OutputStream: stdout,
|
OutputStream: stdout,
|
||||||
ErrorStream: stderr,
|
ErrorStream: stderr,
|
||||||
RawTerminal: container.Config.Tty,
|
RawTerminal: container.Config.Tty,
|
||||||
|
@ -524,7 +521,7 @@ var criSupportedLogDrivers = []string{"json-file"}
|
||||||
|
|
||||||
// IsCRISupportedLogDriver checks whether the logging driver used by docker is
|
// IsCRISupportedLogDriver checks whether the logging driver used by docker is
|
||||||
// suppoted by native CRI integration.
|
// suppoted by native CRI integration.
|
||||||
func IsCRISupportedLogDriver(client dockertools.DockerInterface) (bool, error) {
|
func IsCRISupportedLogDriver(client libdocker.Interface) (bool, error) {
|
||||||
info, err := client.Info()
|
info, err := client.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("failed to get docker info: %v", err)
|
return false, fmt.Errorf("failed to get docker info: %v", err)
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"k8s.io/client-go/util/clock"
|
"k8s.io/client-go/util/clock"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/network"
|
"k8s.io/kubernetes/pkg/kubelet/network"
|
||||||
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
|
nettest "k8s.io/kubernetes/pkg/kubelet/network/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util/cache"
|
"k8s.io/kubernetes/pkg/kubelet/util/cache"
|
||||||
|
@ -42,15 +42,15 @@ func newTestNetworkPlugin(t *testing.T) *nettest.MockNetworkPlugin {
|
||||||
return nettest.NewMockNetworkPlugin(ctrl)
|
return nettest.NewMockNetworkPlugin(ctrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestDockerService() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) {
|
func newTestDockerService() (*dockerService, *libdocker.FakeDockerClient, *clock.FakeClock) {
|
||||||
fakeClock := clock.NewFakeClock(time.Time{})
|
fakeClock := clock.NewFakeClock(time.Time{})
|
||||||
c := dockertools.NewFakeDockerClient().WithClock(fakeClock).WithVersion("1.11.2", "1.23")
|
c := libdocker.NewFakeDockerClient().WithClock(fakeClock).WithVersion("1.11.2", "1.23")
|
||||||
pm := network.NewPluginManager(&network.NoopNetworkPlugin{})
|
pm := network.NewPluginManager(&network.NoopNetworkPlugin{})
|
||||||
return &dockerService{client: c, os: &containertest.FakeOS{}, network: pm,
|
return &dockerService{client: c, os: &containertest.FakeOS{}, network: pm,
|
||||||
legacyCleanup: legacyCleanupFlag{done: 1}, checkpointHandler: NewTestPersistentCheckpointHandler()}, c, fakeClock
|
legacyCleanup: legacyCleanupFlag{done: 1}, checkpointHandler: NewTestPersistentCheckpointHandler()}, c, fakeClock
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestDockerServiceWithVersionCache() (*dockerService, *dockertools.FakeDockerClient, *clock.FakeClock) {
|
func newTestDockerServiceWithVersionCache() (*dockerService, *libdocker.FakeDockerClient, *clock.FakeClock) {
|
||||||
ds, c, fakeClock := newTestDockerService()
|
ds, c, fakeClock := newTestDockerService()
|
||||||
ds.versionCache = cache.NewObjectCache(
|
ds.versionCache = cache.NewObjectCache(
|
||||||
func() (interface{}, error) {
|
func() (interface{}, error) {
|
||||||
|
|
|
@ -30,13 +30,14 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
"k8s.io/kubernetes/pkg/kubelet/server/streaming"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/util/ioutils"
|
"k8s.io/kubernetes/pkg/kubelet/util/ioutils"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
type streamingRuntime struct {
|
type streamingRuntime struct {
|
||||||
client dockertools.DockerInterface
|
client libdocker.Interface
|
||||||
execHandler ExecHandler
|
execHandler ExecHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ func (ds *dockerService) PortForward(req *runtimeapi.PortForwardRequest) (*runti
|
||||||
return ds.streamingServer.GetPortForward(req)
|
return ds.streamingServer.GetPortForward(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkContainerStatus(client dockertools.DockerInterface, containerID string) (*dockertypes.ContainerJSON, error) {
|
func checkContainerStatus(client libdocker.Interface, containerID string) (*dockertypes.ContainerJSON, error) {
|
||||||
container, err := client.InspectContainer(containerID)
|
container, err := client.InspectContainer(containerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -133,7 +134,7 @@ func checkContainerStatus(client dockertools.DockerInterface, containerID string
|
||||||
return container, nil
|
return container, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachContainer(client dockertools.DockerInterface, containerID string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
|
func attachContainer(client libdocker.Interface, containerID string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error {
|
||||||
// Have to start this before the call to client.AttachToContainer because client.AttachToContainer is a blocking
|
// Have to start this before the call to client.AttachToContainer because client.AttachToContainer is a blocking
|
||||||
// call :-( Otherwise, resize events don't get processed and the terminal never resizes.
|
// call :-( Otherwise, resize events don't get processed and the terminal never resizes.
|
||||||
kubecontainer.HandleResizing(resize, func(size remotecommand.TerminalSize) {
|
kubecontainer.HandleResizing(resize, func(size remotecommand.TerminalSize) {
|
||||||
|
@ -147,7 +148,7 @@ func attachContainer(client dockertools.DockerInterface, containerID string, std
|
||||||
Stdout: stdout != nil,
|
Stdout: stdout != nil,
|
||||||
Stderr: stderr != nil,
|
Stderr: stderr != nil,
|
||||||
}
|
}
|
||||||
sopts := dockertools.StreamOptions{
|
sopts := libdocker.StreamOptions{
|
||||||
InputStream: stdin,
|
InputStream: stdin,
|
||||||
OutputStream: stdout,
|
OutputStream: stdout,
|
||||||
ErrorStream: stderr,
|
ErrorStream: stderr,
|
||||||
|
@ -156,7 +157,7 @@ func attachContainer(client dockertools.DockerInterface, containerID string, std
|
||||||
return client.AttachToContainer(containerID, opts, sopts)
|
return client.AttachToContainer(containerID, opts, sopts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func portForward(client dockertools.DockerInterface, podInfraContainerID string, port int32, stream io.ReadWriteCloser) error {
|
func portForward(client libdocker.Interface, podInfraContainerID string, port int32, stream io.ReadWriteCloser) error {
|
||||||
container, err := client.InspectContainer(podInfraContainerID)
|
container, err := client.InspectContainer(podInfraContainerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -28,14 +28,15 @@ import (
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
utilexec "k8s.io/kubernetes/pkg/util/exec"
|
||||||
"k8s.io/kubernetes/pkg/util/term"
|
"k8s.io/kubernetes/pkg/util/term"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecHandler knows how to execute a command in a running Docker container.
|
// ExecHandler knows how to execute a command in a running Docker container.
|
||||||
type ExecHandler interface {
|
type ExecHandler interface {
|
||||||
ExecInContainer(client dockertools.DockerInterface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error
|
ExecInContainer(client libdocker.Interface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NsenterExecHandler executes commands in Docker containers using nsenter.
|
// NsenterExecHandler executes commands in Docker containers using nsenter.
|
||||||
|
@ -62,7 +63,7 @@ func (d *dockerExitError) ExitStatus() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO should we support nsenter in a container, running with elevated privs and --pid=host?
|
// TODO should we support nsenter in a container, running with elevated privs and --pid=host?
|
||||||
func (*NsenterExecHandler) ExecInContainer(client dockertools.DockerInterface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error {
|
func (*NsenterExecHandler) ExecInContainer(client libdocker.Interface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error {
|
||||||
nsenter, err := exec.LookPath("nsenter")
|
nsenter, err := exec.LookPath("nsenter")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("exec unavailable - unable to locate nsenter")
|
return fmt.Errorf("exec unavailable - unable to locate nsenter")
|
||||||
|
@ -133,7 +134,7 @@ func (*NsenterExecHandler) ExecInContainer(client dockertools.DockerInterface, c
|
||||||
// NativeExecHandler executes commands in Docker containers using Docker's exec API.
|
// NativeExecHandler executes commands in Docker containers using Docker's exec API.
|
||||||
type NativeExecHandler struct{}
|
type NativeExecHandler struct{}
|
||||||
|
|
||||||
func (*NativeExecHandler) ExecInContainer(client dockertools.DockerInterface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error {
|
func (*NativeExecHandler) ExecInContainer(client libdocker.Interface, container *dockertypes.ContainerJSON, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error {
|
||||||
createOpts := dockertypes.ExecConfig{
|
createOpts := dockertypes.ExecConfig{
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
AttachStdin: stdin != nil,
|
AttachStdin: stdin != nil,
|
||||||
|
@ -153,7 +154,7 @@ func (*NativeExecHandler) ExecInContainer(client dockertools.DockerInterface, co
|
||||||
})
|
})
|
||||||
|
|
||||||
startOpts := dockertypes.ExecStartCheck{Detach: false, Tty: tty}
|
startOpts := dockertypes.ExecStartCheck{Detach: false, Tty: tty}
|
||||||
streamOpts := dockertools.StreamOptions{
|
streamOpts := libdocker.StreamOptions{
|
||||||
InputStream: stdin,
|
InputStream: stdin,
|
||||||
OutputStream: stdout,
|
OutputStream: stdout,
|
||||||
ErrorStream: stderr,
|
ErrorStream: stderr,
|
||||||
|
|
|
@ -36,9 +36,10 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/types"
|
"k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -354,7 +355,7 @@ func getUserFromImageUser(imageUser string) (*int64, string) {
|
||||||
// In that case we have to create the container with a randomized name.
|
// In that case we have to create the container with a randomized name.
|
||||||
// TODO(random-liu): Remove this work around after docker 1.11 is deprecated.
|
// TODO(random-liu): Remove this work around after docker 1.11 is deprecated.
|
||||||
// TODO(#33189): Monitor the tests to see if the fix is sufficient.
|
// TODO(#33189): Monitor the tests to see if the fix is sufficient.
|
||||||
func recoverFromCreationConflictIfNeeded(client dockertools.DockerInterface, createConfig dockertypes.ContainerCreateConfig, err error) (*dockertypes.ContainerCreateResponse, error) {
|
func recoverFromCreationConflictIfNeeded(client libdocker.Interface, createConfig dockertypes.ContainerCreateConfig, err error) (*dockertypes.ContainerCreateResponse, error) {
|
||||||
matches := conflictRE.FindStringSubmatch(err.Error())
|
matches := conflictRE.FindStringSubmatch(err.Error())
|
||||||
if len(matches) != 2 {
|
if len(matches) != 2 {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -368,7 +369,7 @@ func recoverFromCreationConflictIfNeeded(client dockertools.DockerInterface, cre
|
||||||
} else {
|
} else {
|
||||||
glog.Errorf("Failed to remove the conflicting container %q: %v", id, rmErr)
|
glog.Errorf("Failed to remove the conflicting container %q: %v", id, rmErr)
|
||||||
// Return if the error is not container not found error.
|
// Return if the error is not container not found error.
|
||||||
if !dockertools.IsContainerNotFoundError(rmErr) {
|
if !libdocker.IsContainerNotFoundError(rmErr) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,12 +396,12 @@ func getSecurityOptSeparator(v *semver.Version) rune {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensureSandboxImageExists pulls the sandbox image when it's not present.
|
// ensureSandboxImageExists pulls the sandbox image when it's not present.
|
||||||
func ensureSandboxImageExists(client dockertools.DockerInterface, image string) error {
|
func ensureSandboxImageExists(client libdocker.Interface, image string) error {
|
||||||
_, err := client.InspectImageByRef(image)
|
_, err := client.InspectImageByRef(image)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !dockertools.IsImageNotFoundError(err) {
|
if !libdocker.IsImageNotFoundError(err) {
|
||||||
return fmt.Errorf("failed to inspect sandbox image %q: %v", image, err)
|
return fmt.Errorf("failed to inspect sandbox image %q: %v", image, err)
|
||||||
}
|
}
|
||||||
err = client.PullImage(image, dockertypes.AuthConfig{}, dockertypes.ImagePullOptions{})
|
err = client.PullImage(image, dockertypes.AuthConfig{}, dockertypes.ImagePullOptions{})
|
||||||
|
@ -437,7 +438,7 @@ type dockerOpt struct {
|
||||||
msg string
|
msg string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose key/value from dockertools
|
// Expose key/value from dockerOpt.
|
||||||
func (d dockerOpt) GetKV() (string, string) {
|
func (d dockerOpt) GetKV() (string, string) {
|
||||||
return d.key, d.value
|
return d.key, d.value
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,9 @@ import (
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLabelsAndAnnotationsRoundTrip(t *testing.T) {
|
func TestLabelsAndAnnotationsRoundTrip(t *testing.T) {
|
||||||
|
@ -302,7 +303,7 @@ func TestEnsureSandboxImageExists(t *testing.T) {
|
||||||
},
|
},
|
||||||
"should pull image when it doesn't exist": {
|
"should pull image when it doesn't exist": {
|
||||||
injectImage: false,
|
injectImage: false,
|
||||||
injectErr: dockertools.ImageNotFoundError{ID: "image_id"},
|
injectErr: libdocker.ImageNotFoundError{ID: "image_id"},
|
||||||
calls: []string{"inspect_image", "pull"},
|
calls: []string{"inspect_image", "pull"},
|
||||||
},
|
},
|
||||||
"should return error when inspect image fails": {
|
"should return error when inspect image fails": {
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
|
||||||
|
licenses(["notice"])
|
||||||
|
|
||||||
|
load(
|
||||||
|
"@io_bazel_rules_go//go:def.bzl",
|
||||||
|
"go_library",
|
||||||
|
"go_test",
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = [
|
||||||
|
"helpers_test.go",
|
||||||
|
"kube_docker_client_test.go",
|
||||||
|
"legacy_test.go",
|
||||||
|
],
|
||||||
|
library = ":go_default_library",
|
||||||
|
tags = ["automanaged"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api/v1:go_default_library",
|
||||||
|
"//pkg/util/hash:go_default_library",
|
||||||
|
"//vendor/github.com/docker/engine-api/types:go_default_library",
|
||||||
|
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"client.go",
|
||||||
|
"fake_client.go",
|
||||||
|
"helpers.go",
|
||||||
|
"instrumented_client.go",
|
||||||
|
"kube_docker_client.go",
|
||||||
|
"legacy.go",
|
||||||
|
],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/api/v1:go_default_library",
|
||||||
|
"//pkg/kubelet/container:go_default_library",
|
||||||
|
"//pkg/kubelet/metrics:go_default_library",
|
||||||
|
"//vendor/github.com/docker/distribution/digest:go_default_library",
|
||||||
|
"//vendor/github.com/docker/distribution/reference:go_default_library",
|
||||||
|
"//vendor/github.com/docker/docker/pkg/jsonmessage:go_default_library",
|
||||||
|
"//vendor/github.com/docker/docker/pkg/stdcopy:go_default_library",
|
||||||
|
"//vendor/github.com/docker/engine-api/client:go_default_library",
|
||||||
|
"//vendor/github.com/docker/engine-api/types:go_default_library",
|
||||||
|
"//vendor/github.com/docker/engine-api/types/container:go_default_library",
|
||||||
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
|
"//vendor/golang.org/x/net/context:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||||
|
"//vendor/k8s.io/client-go/util/clock:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
)
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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 libdocker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dockerapi "github.com/docker/engine-api/client"
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// https://docs.docker.com/engine/reference/api/docker_remote_api/
|
||||||
|
// docker version should be at least 1.10.x
|
||||||
|
MinimumDockerAPIVersion = "1.22.0"
|
||||||
|
|
||||||
|
// Status of a container returned by ListContainers.
|
||||||
|
StatusRunningPrefix = "Up"
|
||||||
|
StatusCreatedPrefix = "Created"
|
||||||
|
StatusExitedPrefix = "Exited"
|
||||||
|
|
||||||
|
// This is only used by GetKubeletDockerContainers(), and should be removed
|
||||||
|
// along with the function.
|
||||||
|
containerNamePrefix = "k8s"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface is an abstract interface for testability. It abstracts the interface of docker client.
|
||||||
|
type Interface interface {
|
||||||
|
ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error)
|
||||||
|
InspectContainer(id string) (*dockertypes.ContainerJSON, error)
|
||||||
|
CreateContainer(dockertypes.ContainerCreateConfig) (*dockertypes.ContainerCreateResponse, error)
|
||||||
|
StartContainer(id string) error
|
||||||
|
StopContainer(id string, timeout int) error
|
||||||
|
RemoveContainer(id string, opts dockertypes.ContainerRemoveOptions) error
|
||||||
|
InspectImageByRef(imageRef string) (*dockertypes.ImageInspect, error)
|
||||||
|
InspectImageByID(imageID string) (*dockertypes.ImageInspect, error)
|
||||||
|
ListImages(opts dockertypes.ImageListOptions) ([]dockertypes.Image, error)
|
||||||
|
PullImage(image string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error
|
||||||
|
RemoveImage(image string, opts dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDelete, error)
|
||||||
|
ImageHistory(id string) ([]dockertypes.ImageHistory, error)
|
||||||
|
Logs(string, dockertypes.ContainerLogsOptions, StreamOptions) error
|
||||||
|
Version() (*dockertypes.Version, error)
|
||||||
|
Info() (*dockertypes.Info, error)
|
||||||
|
CreateExec(string, dockertypes.ExecConfig) (*dockertypes.ContainerExecCreateResponse, error)
|
||||||
|
StartExec(string, dockertypes.ExecStartCheck, StreamOptions) error
|
||||||
|
InspectExec(id string) (*dockertypes.ContainerExecInspect, error)
|
||||||
|
AttachToContainer(string, dockertypes.ContainerAttachOptions, StreamOptions) error
|
||||||
|
ResizeContainerTTY(id string, height, width int) error
|
||||||
|
ResizeExecTTY(id string, height, width int) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a *dockerapi.Client, either using the endpoint passed in, or using
|
||||||
|
// DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT path per their spec
|
||||||
|
func getDockerClient(dockerEndpoint string) (*dockerapi.Client, error) {
|
||||||
|
if len(dockerEndpoint) > 0 {
|
||||||
|
glog.Infof("Connecting to docker on %s", dockerEndpoint)
|
||||||
|
return dockerapi.NewClient(dockerEndpoint, "", nil, nil)
|
||||||
|
}
|
||||||
|
return dockerapi.NewEnvClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectToDockerOrDie creates docker client connecting to docker daemon.
|
||||||
|
// If the endpoint passed in is "fake://", a fake docker client
|
||||||
|
// will be returned. The program exits if error occurs. The requestTimeout
|
||||||
|
// is the timeout for docker requests. If timeout is exceeded, the request
|
||||||
|
// will be cancelled and throw out an error. If requestTimeout is 0, a default
|
||||||
|
// value will be applied.
|
||||||
|
func ConnectToDockerOrDie(dockerEndpoint string, requestTimeout, imagePullProgressDeadline time.Duration) Interface {
|
||||||
|
if dockerEndpoint == "fake://" {
|
||||||
|
return NewFakeDockerClient()
|
||||||
|
}
|
||||||
|
client, err := getDockerClient(dockerEndpoint)
|
||||||
|
if err != nil {
|
||||||
|
glog.Fatalf("Couldn't connect to docker: %v", err)
|
||||||
|
}
|
||||||
|
glog.Infof("Start docker client with request timeout=%v", requestTimeout)
|
||||||
|
return newKubeDockerClient(client, requestTimeout, imagePullProgressDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKubeletDockerContainers lists all container or just the running ones.
|
||||||
|
// Returns a list of docker containers that we manage
|
||||||
|
// TODO: This function should be deleted after migrating
|
||||||
|
// test/e2e_node/garbage_collector_test.go off of it.
|
||||||
|
func GetKubeletDockerContainers(client Interface, allContainers bool) ([]*dockertypes.Container, error) {
|
||||||
|
result := []*dockertypes.Container{}
|
||||||
|
containers, err := client.ListContainers(dockertypes.ContainerListOptions{All: allContainers})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := range containers {
|
||||||
|
container := &containers[i]
|
||||||
|
if len(container.Names) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Skip containers that we didn't create to allow users to manually
|
||||||
|
// spin up their own containers if they want.
|
||||||
|
if !strings.HasPrefix(container.Names[0], "/"+containerNamePrefix+"_") {
|
||||||
|
glog.V(5).Infof("Docker Container: %s is not managed by kubelet.", container.Names[0])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, container)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dockertools
|
package libdocker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
@ -77,16 +77,16 @@ type FakeDockerClient struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// We don't check docker version now, just set the docker version of fake docker client to 1.8.1.
|
|
||||||
// Notice that if someday we also have minimum docker version requirement, this should also be updated.
|
// Notice that if someday we also have minimum docker version requirement, this should also be updated.
|
||||||
fakeDockerVersion = "1.8.1"
|
fakeDockerVersion = "1.11.2"
|
||||||
|
|
||||||
fakeImageSize = 1024
|
fakeImageSize = 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewFakeDockerClient() *FakeDockerClient {
|
func NewFakeDockerClient() *FakeDockerClient {
|
||||||
return &FakeDockerClient{
|
return &FakeDockerClient{
|
||||||
VersionInfo: dockertypes.Version{Version: fakeDockerVersion, APIVersion: minimumDockerAPIVersion},
|
// Docker's API version does not include the patch number.
|
||||||
|
VersionInfo: dockertypes.Version{Version: fakeDockerVersion, APIVersion: strings.TrimSuffix(MinimumDockerAPIVersion, ".0")},
|
||||||
Errors: make(map[string]error),
|
Errors: make(map[string]error),
|
||||||
ContainerMap: make(map[string]*dockertypes.ContainerJSON),
|
ContainerMap: make(map[string]*dockertypes.ContainerJSON),
|
||||||
Clock: clock.RealClock{},
|
Clock: clock.RealClock{},
|
||||||
|
@ -345,6 +345,14 @@ func (f *FakeDockerClient) AssertImagesPulled(pulled []string) error {
|
||||||
return sortedStringSlicesEqual(pulled, actualPulled)
|
return sortedStringSlicesEqual(pulled, actualPulled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FakeDockerClient) AssertImagesPulledMsgs(expected []string) error {
|
||||||
|
f.Lock()
|
||||||
|
defer f.Unlock()
|
||||||
|
// Copy pulled to avoid modifying it.
|
||||||
|
actual := append([]string{}, f.pulled...)
|
||||||
|
return sortedStringSlicesEqual(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
func sortedStringSlicesEqual(expected, actual []string) error {
|
func sortedStringSlicesEqual(expected, actual []string) error {
|
||||||
sort.StringSlice(expected).Sort()
|
sort.StringSlice(expected).Sort()
|
||||||
sort.StringSlice(actual).Sort()
|
sort.StringSlice(actual).Sort()
|
||||||
|
@ -367,7 +375,7 @@ func (f *FakeDockerClient) popError(op string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListContainers is a test-spy implementation of DockerInterface.ListContainers.
|
// ListContainers is a test-spy implementation of Interface.ListContainers.
|
||||||
// It adds an entry "list" to the internal method call record.
|
// It adds an entry "list" to the internal method call record.
|
||||||
func (f *FakeDockerClient) ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error) {
|
func (f *FakeDockerClient) ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -434,7 +442,7 @@ func (f *FakeDockerClient) ListContainers(options dockertypes.ContainerListOptio
|
||||||
return containerList, err
|
return containerList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// InspectContainer is a test-spy implementation of DockerInterface.InspectContainer.
|
// InspectContainer is a test-spy implementation of Interface.InspectContainer.
|
||||||
// It adds an entry "inspect" to the internal method call record.
|
// It adds an entry "inspect" to the internal method call record.
|
||||||
func (f *FakeDockerClient) InspectContainer(id string) (*dockertypes.ContainerJSON, error) {
|
func (f *FakeDockerClient) InspectContainer(id string) (*dockertypes.ContainerJSON, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -451,7 +459,7 @@ func (f *FakeDockerClient) InspectContainer(id string) (*dockertypes.ContainerJS
|
||||||
return nil, fmt.Errorf("container %q not found", id)
|
return nil, fmt.Errorf("container %q not found", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InspectImageByRef is a test-spy implementation of DockerInterface.InspectImageByRef.
|
// InspectImageByRef is a test-spy implementation of Interface.InspectImageByRef.
|
||||||
// It adds an entry "inspect" to the internal method call record.
|
// It adds an entry "inspect" to the internal method call record.
|
||||||
func (f *FakeDockerClient) InspectImageByRef(name string) (*dockertypes.ImageInspect, error) {
|
func (f *FakeDockerClient) InspectImageByRef(name string) (*dockertypes.ImageInspect, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -466,7 +474,7 @@ func (f *FakeDockerClient) InspectImageByRef(name string) (*dockertypes.ImageIns
|
||||||
return nil, ImageNotFoundError{name}
|
return nil, ImageNotFoundError{name}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InspectImageByID is a test-spy implementation of DockerInterface.InspectImageByID.
|
// InspectImageByID is a test-spy implementation of Interface.InspectImageByID.
|
||||||
// It adds an entry "inspect" to the internal method call record.
|
// It adds an entry "inspect" to the internal method call record.
|
||||||
func (f *FakeDockerClient) InspectImageByID(name string) (*dockertypes.ImageInspect, error) {
|
func (f *FakeDockerClient) InspectImageByID(name string) (*dockertypes.ImageInspect, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -502,7 +510,7 @@ func GetFakeContainerID(name string) string {
|
||||||
return strconv.FormatUint(hash.Sum64(), 16)
|
return strconv.FormatUint(hash.Sum64(), 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateContainer is a test-spy implementation of DockerInterface.CreateContainer.
|
// CreateContainer is a test-spy implementation of Interface.CreateContainer.
|
||||||
// It adds an entry "create" to the internal method call record.
|
// It adds an entry "create" to the internal method call record.
|
||||||
func (f *FakeDockerClient) CreateContainer(c dockertypes.ContainerCreateConfig) (*dockertypes.ContainerCreateResponse, error) {
|
func (f *FakeDockerClient) CreateContainer(c dockertypes.ContainerCreateConfig) (*dockertypes.ContainerCreateResponse, error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -519,7 +527,7 @@ func (f *FakeDockerClient) CreateContainer(c dockertypes.ContainerCreateConfig)
|
||||||
timestamp := f.Clock.Now()
|
timestamp := f.Clock.Now()
|
||||||
// The newest container should be in front, because we assume so in GetPodStatus()
|
// The newest container should be in front, because we assume so in GetPodStatus()
|
||||||
f.RunningContainerList = append([]dockertypes.Container{
|
f.RunningContainerList = append([]dockertypes.Container{
|
||||||
{ID: id, Names: []string{name}, Image: c.Config.Image, Created: timestamp.Unix(), State: statusCreatedPrefix, Labels: c.Config.Labels},
|
{ID: id, Names: []string{name}, Image: c.Config.Image, Created: timestamp.Unix(), State: StatusCreatedPrefix, Labels: c.Config.Labels},
|
||||||
}, f.RunningContainerList...)
|
}, f.RunningContainerList...)
|
||||||
f.ContainerMap[id] = convertFakeContainer(&FakeContainer{
|
f.ContainerMap[id] = convertFakeContainer(&FakeContainer{
|
||||||
ID: id, Name: name, Config: c.Config, HostConfig: c.HostConfig, CreatedAt: timestamp})
|
ID: id, Name: name, Config: c.Config, HostConfig: c.HostConfig, CreatedAt: timestamp})
|
||||||
|
@ -529,7 +537,7 @@ func (f *FakeDockerClient) CreateContainer(c dockertypes.ContainerCreateConfig)
|
||||||
return &dockertypes.ContainerCreateResponse{ID: id}, nil
|
return &dockertypes.ContainerCreateResponse{ID: id}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartContainer is a test-spy implementation of DockerInterface.StartContainer.
|
// StartContainer is a test-spy implementation of Interface.StartContainer.
|
||||||
// It adds an entry "start" to the internal method call record.
|
// It adds an entry "start" to the internal method call record.
|
||||||
func (f *FakeDockerClient) StartContainer(id string) error {
|
func (f *FakeDockerClient) StartContainer(id string) error {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -549,12 +557,12 @@ func (f *FakeDockerClient) StartContainer(id string) error {
|
||||||
container.State.StartedAt = dockerTimestampToString(timestamp)
|
container.State.StartedAt = dockerTimestampToString(timestamp)
|
||||||
container.NetworkSettings.IPAddress = "2.3.4.5"
|
container.NetworkSettings.IPAddress = "2.3.4.5"
|
||||||
f.ContainerMap[id] = container
|
f.ContainerMap[id] = container
|
||||||
f.updateContainerStatus(id, statusRunningPrefix)
|
f.updateContainerStatus(id, StatusRunningPrefix)
|
||||||
f.normalSleep(200, 50, 50)
|
f.normalSleep(200, 50, 50)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopContainer is a test-spy implementation of DockerInterface.StopContainer.
|
// StopContainer is a test-spy implementation of Interface.StopContainer.
|
||||||
// It adds an entry "stop" to the internal method call record.
|
// It adds an entry "stop" to the internal method call record.
|
||||||
func (f *FakeDockerClient) StopContainer(id string, timeout int) error {
|
func (f *FakeDockerClient) StopContainer(id string, timeout int) error {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -565,7 +573,7 @@ func (f *FakeDockerClient) StopContainer(id string, timeout int) error {
|
||||||
}
|
}
|
||||||
f.appendContainerTrace("Stopped", id)
|
f.appendContainerTrace("Stopped", id)
|
||||||
// Container status should be Updated before container moved to ExitedContainerList
|
// Container status should be Updated before container moved to ExitedContainerList
|
||||||
f.updateContainerStatus(id, statusExitedPrefix)
|
f.updateContainerStatus(id, StatusExitedPrefix)
|
||||||
var newList []dockertypes.Container
|
var newList []dockertypes.Container
|
||||||
for _, container := range f.RunningContainerList {
|
for _, container := range f.RunningContainerList {
|
||||||
if container.ID == id {
|
if container.ID == id {
|
||||||
|
@ -615,7 +623,7 @@ func (f *FakeDockerClient) RemoveContainer(id string, opts dockertypes.Container
|
||||||
return fmt.Errorf("container not stopped")
|
return fmt.Errorf("container not stopped")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logs is a test-spy implementation of DockerInterface.Logs.
|
// Logs is a test-spy implementation of Interface.Logs.
|
||||||
// It adds an entry "logs" to the internal method call record.
|
// It adds an entry "logs" to the internal method call record.
|
||||||
func (f *FakeDockerClient) Logs(id string, opts dockertypes.ContainerLogsOptions, sopts StreamOptions) error {
|
func (f *FakeDockerClient) Logs(id string, opts dockertypes.ContainerLogsOptions, sopts StreamOptions) error {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -624,7 +632,7 @@ func (f *FakeDockerClient) Logs(id string, opts dockertypes.ContainerLogsOptions
|
||||||
return f.popError("logs")
|
return f.popError("logs")
|
||||||
}
|
}
|
||||||
|
|
||||||
// PullImage is a test-spy implementation of DockerInterface.PullImage.
|
// PullImage is a test-spy implementation of Interface.PullImage.
|
||||||
// It adds an entry "pull" to the internal method call record.
|
// It adds an entry "pull" to the internal method call record.
|
||||||
func (f *FakeDockerClient) PullImage(image string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error {
|
func (f *FakeDockerClient) PullImage(image string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
|
@ -804,7 +812,7 @@ func (f *FakeDockerClient) InjectImageHistory(data map[string][]dockertypes.Imag
|
||||||
// FakeDockerPuller is meant to be a simple wrapper around FakeDockerClient.
|
// FakeDockerPuller is meant to be a simple wrapper around FakeDockerClient.
|
||||||
// Please do not add more functionalities to it.
|
// Please do not add more functionalities to it.
|
||||||
type FakeDockerPuller struct {
|
type FakeDockerPuller struct {
|
||||||
client DockerInterface
|
client Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDockerPuller) Pull(image string, _ []v1.Secret) error {
|
func (f *FakeDockerPuller) Pull(image string, _ []v1.Secret) error {
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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 libdocker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dockerdigest "github.com/docker/distribution/digest"
|
||||||
|
dockerref "github.com/docker/distribution/reference"
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseDockerTimestamp parses the timestamp returned by Interface from string to time.Time
|
||||||
|
func ParseDockerTimestamp(s string) (time.Time, error) {
|
||||||
|
// Timestamp returned by Docker is in time.RFC3339Nano format.
|
||||||
|
return time.Parse(time.RFC3339Nano, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchImageTagOrSHA checks if the given image specifier is a valid image ref,
|
||||||
|
// and that it matches the given image. It should fail on things like image IDs
|
||||||
|
// (config digests) and other digest-only references, but succeed on image names
|
||||||
|
// (`foo`), tag references (`foo:bar`), and manifest digest references
|
||||||
|
// (`foo@sha256:xyz`).
|
||||||
|
func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool {
|
||||||
|
// The image string follows the grammar specified here
|
||||||
|
// https://github.com/docker/distribution/blob/master/reference/reference.go#L4
|
||||||
|
named, err := dockerref.ParseNamed(image)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, isTagged := named.(dockerref.Tagged)
|
||||||
|
digest, isDigested := named.(dockerref.Digested)
|
||||||
|
if !isTagged && !isDigested {
|
||||||
|
// No Tag or SHA specified, so just return what we have
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isTagged {
|
||||||
|
// Check the RepoTags for a match.
|
||||||
|
for _, tag := range inspected.RepoTags {
|
||||||
|
// An image name (without the tag/digest) can be [hostname '/'] component ['/' component]*
|
||||||
|
// Because either the RepoTag or the name *may* contain the
|
||||||
|
// hostname or not, we only check for the suffix match.
|
||||||
|
if strings.HasSuffix(image, tag) || strings.HasSuffix(tag, image) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDigested {
|
||||||
|
for _, repoDigest := range inspected.RepoDigests {
|
||||||
|
named, err := dockerref.ParseNamed(repoDigest)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("couldn't parse image RepoDigest reference %q: %v", repoDigest, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d, isDigested := named.(dockerref.Digested); isDigested {
|
||||||
|
if digest.Digest().Algorithm().String() == d.Digest().Algorithm().String() &&
|
||||||
|
digest.Digest().Hex() == d.Digest().Hex() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process the ID as a digest
|
||||||
|
id, err := dockerdigest.ParseDigest(inspected.ID)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glog.V(4).Infof("Inspected image (%q) does not match %s", inspected.ID, image)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// matchImageIDOnly checks that the given image specifier is a digest-only
|
||||||
|
// reference, and that it matches the given image.
|
||||||
|
func matchImageIDOnly(inspected dockertypes.ImageInspect, image string) bool {
|
||||||
|
// If the image ref is literally equal to the inspected image's ID,
|
||||||
|
// just return true here (this might be the case for Docker 1.9,
|
||||||
|
// where we won't have a digest for the ID)
|
||||||
|
if inspected.ID == image {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we should try actual parsing to be more correct
|
||||||
|
ref, err := dockerref.Parse(image)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
digest, isDigested := ref.(dockerref.Digested)
|
||||||
|
if !isDigested {
|
||||||
|
glog.V(4).Infof("the image reference %q was not a digest reference")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := dockerdigest.ParseDigest(inspected.ID)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(4).Infof("The reference %s does not directly refer to the given image's ID (%q)", image, inspected.ID)
|
||||||
|
return false
|
||||||
|
}
|
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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 libdocker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMatchImageTagOrSHA(t *testing.T) {
|
||||||
|
for i, testCase := range []struct {
|
||||||
|
Inspected dockertypes.ImageInspect
|
||||||
|
Image string
|
||||||
|
Output bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:latest"}},
|
||||||
|
Image: "ubuntu",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:14.04"}},
|
||||||
|
Image: "ubuntu:latest",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"colemickens/hyperkube-amd64:217.9beff63"}},
|
||||||
|
Image: "colemickens/hyperkube-amd64:217.9beff63",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"colemickens/hyperkube-amd64:217.9beff63"}},
|
||||||
|
Image: "docker.io/colemickens/hyperkube-amd64:217.9beff63",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"docker.io/kubernetes/pause:latest"}},
|
||||||
|
Image: "kubernetes/pause:latest",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:2208f7a29005",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:2208",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// mismatched ID is ignored
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:0000f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// invalid digest is ignored
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:unparseable",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:unparseable",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// v1 schema images can be pulled in one format and returned in another
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{"centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// RepoDigest match is is required
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:000084acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// RepoDigest match is allowed
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// RepoDigest and ID are checked
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// unparseable RepoDigests are skipped
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{
|
||||||
|
"centos/ruby-23-centos7@sha256:unparseable",
|
||||||
|
"docker.io/centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// unparseable RepoDigest is ignored
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:unparseable"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// unparseable image digest is ignored
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:unparseable"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:unparseable",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// prefix match is rejected for ID and RepoDigest
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:unparseable",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:unparseable"},
|
||||||
|
},
|
||||||
|
Image: "sha256:unparseable",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// possible SHA prefix match is rejected for ID and RepoDigest because it is not in the named format
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:0000f247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:0000f247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227"},
|
||||||
|
},
|
||||||
|
Image: "sha256:0000",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
match := matchImageTagOrSHA(testCase.Inspected, testCase.Image)
|
||||||
|
assert.Equal(t, testCase.Output, match, testCase.Image+fmt.Sprintf(" is not a match (%d)", i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchImageIDOnly(t *testing.T) {
|
||||||
|
for i, testCase := range []struct {
|
||||||
|
Inspected dockertypes.ImageInspect
|
||||||
|
Image string
|
||||||
|
Output bool
|
||||||
|
}{
|
||||||
|
// shouldn't match names or tagged names
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:latest"}},
|
||||||
|
Image: "ubuntu",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{RepoTags: []string{"colemickens/hyperkube-amd64:217.9beff63"}},
|
||||||
|
Image: "colemickens/hyperkube-amd64:217.9beff63",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
// should match name@digest refs if they refer to the image ID (but only the full ID)
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:2208f7a29005",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:2208",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
// should match when the IDs are literally the same
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "foobar",
|
||||||
|
},
|
||||||
|
Image: "foobar",
|
||||||
|
Output: true,
|
||||||
|
},
|
||||||
|
// shouldn't match mismatched IDs
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:0000f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
// shouldn't match invalid IDs or refs
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:unparseable",
|
||||||
|
},
|
||||||
|
Image: "myimage@sha256:unparseable",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
// shouldn't match against repo digests
|
||||||
|
{
|
||||||
|
Inspected: dockertypes.ImageInspect{
|
||||||
|
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
||||||
|
RepoDigests: []string{"centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
||||||
|
},
|
||||||
|
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
||||||
|
Output: false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
match := matchImageIDOnly(testCase.Inspected, testCase.Image)
|
||||||
|
assert.Equal(t, testCase.Output, match, fmt.Sprintf("%s is not a match (%d)", testCase.Image, i))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dockertools
|
package libdocker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
@ -23,15 +23,15 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubelet/metrics"
|
"k8s.io/kubernetes/pkg/kubelet/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
// instrumentedDockerInterface wraps the DockerInterface and records the operations
|
// instrumentedInterface wraps the Interface and records the operations
|
||||||
// and errors metrics.
|
// and errors metrics.
|
||||||
type instrumentedDockerInterface struct {
|
type instrumentedInterface struct {
|
||||||
client DockerInterface
|
client Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an instrumented DockerInterface from an existing DockerInterface.
|
// Creates an instrumented Interface from an existing Interface.
|
||||||
func NewInstrumentedDockerInterface(dockerClient DockerInterface) DockerInterface {
|
func NewInstrumentedInterface(dockerClient Interface) Interface {
|
||||||
return instrumentedDockerInterface{
|
return instrumentedInterface{
|
||||||
client: dockerClient,
|
client: dockerClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ func recordError(operation string, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error) {
|
func (in instrumentedInterface) ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error) {
|
||||||
const operation = "list_containers"
|
const operation = "list_containers"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func (in instrumentedDockerInterface) ListContainers(options dockertypes.Contain
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) InspectContainer(id string) (*dockertypes.ContainerJSON, error) {
|
func (in instrumentedInterface) InspectContainer(id string) (*dockertypes.ContainerJSON, error) {
|
||||||
const operation = "inspect_container"
|
const operation = "inspect_container"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func (in instrumentedDockerInterface) InspectContainer(id string) (*dockertypes.
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) CreateContainer(opts dockertypes.ContainerCreateConfig) (*dockertypes.ContainerCreateResponse, error) {
|
func (in instrumentedInterface) CreateContainer(opts dockertypes.ContainerCreateConfig) (*dockertypes.ContainerCreateResponse, error) {
|
||||||
const operation = "create_container"
|
const operation = "create_container"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ func (in instrumentedDockerInterface) CreateContainer(opts dockertypes.Container
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) StartContainer(id string) error {
|
func (in instrumentedInterface) StartContainer(id string) error {
|
||||||
const operation = "start_container"
|
const operation = "start_container"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ func (in instrumentedDockerInterface) StartContainer(id string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) StopContainer(id string, timeout int) error {
|
func (in instrumentedInterface) StopContainer(id string, timeout int) error {
|
||||||
const operation = "stop_container"
|
const operation = "stop_container"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ func (in instrumentedDockerInterface) StopContainer(id string, timeout int) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) RemoveContainer(id string, opts dockertypes.ContainerRemoveOptions) error {
|
func (in instrumentedInterface) RemoveContainer(id string, opts dockertypes.ContainerRemoveOptions) error {
|
||||||
const operation = "remove_container"
|
const operation = "remove_container"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ func (in instrumentedDockerInterface) RemoveContainer(id string, opts dockertype
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) InspectImageByRef(image string) (*dockertypes.ImageInspect, error) {
|
func (in instrumentedInterface) InspectImageByRef(image string) (*dockertypes.ImageInspect, error) {
|
||||||
const operation = "inspect_image"
|
const operation = "inspect_image"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ func (in instrumentedDockerInterface) InspectImageByRef(image string) (*dockerty
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) InspectImageByID(image string) (*dockertypes.ImageInspect, error) {
|
func (in instrumentedInterface) InspectImageByID(image string) (*dockertypes.ImageInspect, error) {
|
||||||
const operation = "inspect_image"
|
const operation = "inspect_image"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ func (in instrumentedDockerInterface) InspectImageByID(image string) (*dockertyp
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) ListImages(opts dockertypes.ImageListOptions) ([]dockertypes.Image, error) {
|
func (in instrumentedInterface) ListImages(opts dockertypes.ImageListOptions) ([]dockertypes.Image, error) {
|
||||||
const operation = "list_images"
|
const operation = "list_images"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ func (in instrumentedDockerInterface) ListImages(opts dockertypes.ImageListOptio
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) PullImage(imageID string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error {
|
func (in instrumentedInterface) PullImage(imageID string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error {
|
||||||
const operation = "pull_image"
|
const operation = "pull_image"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
err := in.client.PullImage(imageID, auth, opts)
|
err := in.client.PullImage(imageID, auth, opts)
|
||||||
|
@ -142,7 +142,7 @@ func (in instrumentedDockerInterface) PullImage(imageID string, auth dockertypes
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) RemoveImage(image string, opts dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDelete, error) {
|
func (in instrumentedInterface) RemoveImage(image string, opts dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDelete, error) {
|
||||||
const operation = "remove_image"
|
const operation = "remove_image"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ func (in instrumentedDockerInterface) RemoveImage(image string, opts dockertypes
|
||||||
return imageDelete, err
|
return imageDelete, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) Logs(id string, opts dockertypes.ContainerLogsOptions, sopts StreamOptions) error {
|
func (in instrumentedInterface) Logs(id string, opts dockertypes.ContainerLogsOptions, sopts StreamOptions) error {
|
||||||
const operation = "logs"
|
const operation = "logs"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ func (in instrumentedDockerInterface) Logs(id string, opts dockertypes.Container
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) Version() (*dockertypes.Version, error) {
|
func (in instrumentedInterface) Version() (*dockertypes.Version, error) {
|
||||||
const operation = "version"
|
const operation = "version"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ func (in instrumentedDockerInterface) Version() (*dockertypes.Version, error) {
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) Info() (*dockertypes.Info, error) {
|
func (in instrumentedInterface) Info() (*dockertypes.Info, error) {
|
||||||
const operation = "info"
|
const operation = "info"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ func (in instrumentedDockerInterface) Info() (*dockertypes.Info, error) {
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) CreateExec(id string, opts dockertypes.ExecConfig) (*dockertypes.ContainerExecCreateResponse, error) {
|
func (in instrumentedInterface) CreateExec(id string, opts dockertypes.ExecConfig) (*dockertypes.ContainerExecCreateResponse, error) {
|
||||||
const operation = "create_exec"
|
const operation = "create_exec"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ func (in instrumentedDockerInterface) CreateExec(id string, opts dockertypes.Exe
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) StartExec(startExec string, opts dockertypes.ExecStartCheck, sopts StreamOptions) error {
|
func (in instrumentedInterface) StartExec(startExec string, opts dockertypes.ExecStartCheck, sopts StreamOptions) error {
|
||||||
const operation = "start_exec"
|
const operation = "start_exec"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ func (in instrumentedDockerInterface) StartExec(startExec string, opts dockertyp
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) InspectExec(id string) (*dockertypes.ContainerExecInspect, error) {
|
func (in instrumentedInterface) InspectExec(id string) (*dockertypes.ContainerExecInspect, error) {
|
||||||
const operation = "inspect_exec"
|
const operation = "inspect_exec"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ func (in instrumentedDockerInterface) InspectExec(id string) (*dockertypes.Conta
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) AttachToContainer(id string, opts dockertypes.ContainerAttachOptions, sopts StreamOptions) error {
|
func (in instrumentedInterface) AttachToContainer(id string, opts dockertypes.ContainerAttachOptions, sopts StreamOptions) error {
|
||||||
const operation = "attach"
|
const operation = "attach"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ func (in instrumentedDockerInterface) AttachToContainer(id string, opts dockerty
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) ImageHistory(id string) ([]dockertypes.ImageHistory, error) {
|
func (in instrumentedInterface) ImageHistory(id string) ([]dockertypes.ImageHistory, error) {
|
||||||
const operation = "image_history"
|
const operation = "image_history"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ func (in instrumentedDockerInterface) ImageHistory(id string) ([]dockertypes.Ima
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) ResizeExecTTY(id string, height, width int) error {
|
func (in instrumentedInterface) ResizeExecTTY(id string, height, width int) error {
|
||||||
const operation = "resize_exec"
|
const operation = "resize_exec"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
||||||
|
@ -232,7 +232,7 @@ func (in instrumentedDockerInterface) ResizeExecTTY(id string, height, width int
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in instrumentedDockerInterface) ResizeContainerTTY(id string, height, width int) error {
|
func (in instrumentedInterface) ResizeContainerTTY(id string, height, width int) error {
|
||||||
const operation = "resize_container"
|
const operation = "resize_container"
|
||||||
defer recordOperation(operation, time.Now())
|
defer recordOperation(operation, time.Now())
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dockertools
|
package libdocker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -38,16 +38,16 @@ import (
|
||||||
|
|
||||||
// kubeDockerClient is a wrapped layer of docker client for kubelet internal use. This layer is added to:
|
// kubeDockerClient is a wrapped layer of docker client for kubelet internal use. This layer is added to:
|
||||||
// 1) Redirect stream for exec and attach operations.
|
// 1) Redirect stream for exec and attach operations.
|
||||||
// 2) Wrap the context in this layer to make the DockerInterface cleaner.
|
// 2) Wrap the context in this layer to make the Interface cleaner.
|
||||||
// 3) Stabilize the DockerInterface. The engine-api is still under active development, the interface
|
// 3) Stabilize the Interface. The engine-api is still under active development, the interface
|
||||||
// is not stabilized yet. However, the DockerInterface is used in many files in Kubernetes, we may
|
// is not stabilized yet. However, the Interface is used in many files in Kubernetes, we may
|
||||||
// not want to change the interface frequently. With this layer, we can port the engine api to the
|
// not want to change the interface frequently. With this layer, we can port the engine api to the
|
||||||
// DockerInterface to avoid changing DockerInterface as much as possible.
|
// Interface to avoid changing Interface as much as possible.
|
||||||
// (See
|
// (See
|
||||||
// * https://github.com/docker/engine-api/issues/89
|
// * https://github.com/docker/engine-api/issues/89
|
||||||
// * https://github.com/docker/engine-api/issues/137
|
// * https://github.com/docker/engine-api/issues/137
|
||||||
// * https://github.com/docker/engine-api/pull/140)
|
// * https://github.com/docker/engine-api/pull/140)
|
||||||
// TODO(random-liu): Swith to new docker interface by refactoring the functions in the old DockerInterface
|
// TODO(random-liu): Swith to new docker interface by refactoring the functions in the old Interface
|
||||||
// one by one.
|
// one by one.
|
||||||
type kubeDockerClient struct {
|
type kubeDockerClient struct {
|
||||||
// timeout is the timeout of short running docker operations.
|
// timeout is the timeout of short running docker operations.
|
||||||
|
@ -59,8 +59,8 @@ type kubeDockerClient struct {
|
||||||
client *dockerapi.Client
|
client *dockerapi.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that kubeDockerClient implemented the DockerInterface.
|
// Make sure that kubeDockerClient implemented the Interface.
|
||||||
var _ DockerInterface = &kubeDockerClient{}
|
var _ Interface = &kubeDockerClient{}
|
||||||
|
|
||||||
// There are 2 kinds of docker operations categorized by running time:
|
// There are 2 kinds of docker operations categorized by running time:
|
||||||
// * Long running operation: The long running operation could run for arbitrary long time, and the running time
|
// * Long running operation: The long running operation could run for arbitrary long time, and the running time
|
||||||
|
@ -83,7 +83,7 @@ const (
|
||||||
|
|
||||||
// newKubeDockerClient creates an kubeDockerClient from an existing docker client. If requestTimeout is 0,
|
// newKubeDockerClient creates an kubeDockerClient from an existing docker client. If requestTimeout is 0,
|
||||||
// defaultTimeout will be applied.
|
// defaultTimeout will be applied.
|
||||||
func newKubeDockerClient(dockerClient *dockerapi.Client, requestTimeout, imagePullProgressDeadline time.Duration) DockerInterface {
|
func newKubeDockerClient(dockerClient *dockerapi.Client, requestTimeout, imagePullProgressDeadline time.Duration) Interface {
|
||||||
if requestTimeout == 0 {
|
if requestTimeout == 0 {
|
||||||
requestTimeout = defaultTimeout
|
requestTimeout = defaultTimeout
|
||||||
}
|
}
|
||||||
|
@ -576,12 +576,6 @@ func (d *kubeDockerClient) getCustomTimeoutContext(timeout time.Duration) (conte
|
||||||
return context.WithTimeout(context.Background(), timeout)
|
return context.WithTimeout(context.Background(), timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDockerTimestamp parses the timestamp returned by DockerInterface from string to time.Time
|
|
||||||
func ParseDockerTimestamp(s string) (time.Time, error) {
|
|
||||||
// Timestamp returned by Docker is in time.RFC3339Nano format.
|
|
||||||
return time.Parse(time.RFC3339Nano, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// contextError checks the context, and returns error if the context is timeout.
|
// contextError checks the context, and returns error if the context is timeout.
|
||||||
func contextError(ctx context.Context) error {
|
func contextError(ctx context.Context) error {
|
||||||
if ctx.Err() == context.DeadlineExceeded {
|
if ctx.Err() == context.DeadlineExceeded {
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package dockertools
|
package libdocker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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 libdocker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This file contains functions used in the non-CRI integration (< 1.6). They
|
||||||
|
// are currently used for recoginzing containers created by pre-1.6 kubelets.
|
||||||
|
// TODO: Remove this file for kubernetes 1.8+.
|
||||||
|
|
||||||
|
// Creates a name which can be reversed to identify both full pod name and container name.
|
||||||
|
// This function returns stable name, unique name and a unique id.
|
||||||
|
// Although rand.Uint32() is not really unique, but it's enough for us because error will
|
||||||
|
// only occur when instances of the same container in the same pod have the same UID. The
|
||||||
|
// chance is really slim.
|
||||||
|
func BuildDockerName(dockerName KubeletContainerName, container *v1.Container) (string, string, string) {
|
||||||
|
containerName := dockerName.ContainerName + "." + strconv.FormatUint(kubecontainer.HashContainerLegacy(container), 16)
|
||||||
|
stableName := fmt.Sprintf("%s_%s_%s_%s",
|
||||||
|
containerNamePrefix,
|
||||||
|
containerName,
|
||||||
|
dockerName.PodFullName,
|
||||||
|
dockerName.PodUID)
|
||||||
|
UID := fmt.Sprintf("%08x", rand.Uint32())
|
||||||
|
return stableName, fmt.Sprintf("%s_%s", stableName, UID), UID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unpacks a container name, returning the pod full name and container name we would have used to
|
||||||
|
// construct the docker name. If we are unable to parse the name, an error is returned.
|
||||||
|
func ParseDockerName(name string) (dockerName *KubeletContainerName, hash uint64, err error) {
|
||||||
|
// For some reason docker appears to be appending '/' to names.
|
||||||
|
// If it's there, strip it.
|
||||||
|
name = strings.TrimPrefix(name, "/")
|
||||||
|
parts := strings.Split(name, "_")
|
||||||
|
if len(parts) == 0 || parts[0] != containerNamePrefix {
|
||||||
|
err = fmt.Errorf("failed to parse Docker container name %q into parts", name)
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if len(parts) < 6 {
|
||||||
|
// We have at least 5 fields. We may have more in the future.
|
||||||
|
// Anything with less fields than this is not something we can
|
||||||
|
// manage.
|
||||||
|
glog.Warningf("found a container with the %q prefix, but too few fields (%d): %q", containerNamePrefix, len(parts), name)
|
||||||
|
err = fmt.Errorf("Docker container name %q has less parts than expected %v", name, parts)
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nameParts := strings.Split(parts[1], ".")
|
||||||
|
containerName := nameParts[0]
|
||||||
|
if len(nameParts) > 1 {
|
||||||
|
hash, err = strconv.ParseUint(nameParts[1], 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
glog.Warningf("invalid container hash %q in container %q", nameParts[1], name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
podFullName := parts[2] + "_" + parts[3]
|
||||||
|
podUID := types.UID(parts[4])
|
||||||
|
|
||||||
|
return &KubeletContainerName{podFullName, podUID, containerName}, hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// KubeletContainerName encapsulates a pod name and a Kubernetes container name.
|
||||||
|
type KubeletContainerName struct {
|
||||||
|
PodFullName string
|
||||||
|
PodUID types.UID
|
||||||
|
ContainerName string
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
Copyright 2014 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 libdocker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"hash/adler32"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
|
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
func verifyCalls(t *testing.T, fakeDocker *FakeDockerClient, calls []string) {
|
||||||
|
assert.New(t).NoError(fakeDocker.AssertCalls(calls))
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyStringArrayEquals(t *testing.T, actual, expected []string) {
|
||||||
|
invalid := len(actual) != len(expected)
|
||||||
|
if !invalid {
|
||||||
|
for ix, value := range actual {
|
||||||
|
if expected[ix] != value {
|
||||||
|
invalid = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if invalid {
|
||||||
|
t.Errorf("Expected: %#v, Actual: %#v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findPodContainer(dockerContainers []*dockertypes.Container, podFullName string, uid types.UID, containerName string) (*dockertypes.Container, bool, uint64) {
|
||||||
|
for _, dockerContainer := range dockerContainers {
|
||||||
|
if len(dockerContainer.Names) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dockerName, hash, err := ParseDockerName(dockerContainer.Names[0])
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dockerName.PodFullName == podFullName &&
|
||||||
|
(uid == "" || dockerName.PodUID == uid) &&
|
||||||
|
dockerName.ContainerName == containerName {
|
||||||
|
return dockerContainer, true, hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetContainerID(t *testing.T) {
|
||||||
|
fakeDocker := NewFakeDockerClient()
|
||||||
|
fakeDocker.SetFakeRunningContainers([]*FakeContainer{
|
||||||
|
{
|
||||||
|
ID: "foobar",
|
||||||
|
Name: "/k8s_foo_qux_ns_1234_42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "barbar",
|
||||||
|
Name: "/k8s_bar_qux_ns_2565_42",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
dockerContainers, err := GetKubeletDockerContainers(fakeDocker, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Expected no error, Got %#v", err)
|
||||||
|
}
|
||||||
|
if len(dockerContainers) != 2 {
|
||||||
|
t.Errorf("Expected %#v, Got %#v", fakeDocker.RunningContainerList, dockerContainers)
|
||||||
|
}
|
||||||
|
verifyCalls(t, fakeDocker, []string{"list"})
|
||||||
|
|
||||||
|
dockerContainer, found, _ := findPodContainer(dockerContainers, "qux_ns", "", "foo")
|
||||||
|
if dockerContainer == nil || !found {
|
||||||
|
t.Errorf("Failed to find container %#v", dockerContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeDocker.ClearCalls()
|
||||||
|
dockerContainer, found, _ = findPodContainer(dockerContainers, "foobar", "", "foo")
|
||||||
|
verifyCalls(t, fakeDocker, []string{})
|
||||||
|
if dockerContainer != nil || found {
|
||||||
|
t.Errorf("Should not have found container %#v", dockerContainer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifyPackUnpack(t *testing.T, podNamespace, podUID, podName, containerName string) {
|
||||||
|
container := &v1.Container{Name: containerName}
|
||||||
|
hasher := adler32.New()
|
||||||
|
hashutil.DeepHashObject(hasher, *container)
|
||||||
|
computedHash := uint64(hasher.Sum32())
|
||||||
|
podFullName := fmt.Sprintf("%s_%s", podName, podNamespace)
|
||||||
|
_, name, _ := BuildDockerName(KubeletContainerName{podFullName, types.UID(podUID), container.Name}, container)
|
||||||
|
returned, hash, err := ParseDockerName(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to parse Docker container name %q: %v", name, err)
|
||||||
|
}
|
||||||
|
if podFullName != returned.PodFullName || podUID != string(returned.PodUID) || containerName != returned.ContainerName || computedHash != hash {
|
||||||
|
t.Errorf("For (%s, %s, %s, %d), unpacked (%s, %s, %s, %d)", podFullName, podUID, containerName, computedHash, returned.PodFullName, returned.PodUID, returned.ContainerName, hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerNaming(t *testing.T) {
|
||||||
|
podUID := "12345678"
|
||||||
|
verifyPackUnpack(t, "file", podUID, "name", "container")
|
||||||
|
verifyPackUnpack(t, "file", podUID, "name-with-dashes", "container")
|
||||||
|
// UID is same as pod name
|
||||||
|
verifyPackUnpack(t, "file", podUID, podUID, "container")
|
||||||
|
// No Container name
|
||||||
|
verifyPackUnpack(t, "other", podUID, "name", "")
|
||||||
|
|
||||||
|
container := &v1.Container{Name: "container"}
|
||||||
|
podName := "foo"
|
||||||
|
podNamespace := "test"
|
||||||
|
name := fmt.Sprintf("k8s_%s_%s_%s_%s_42", container.Name, podName, podNamespace, podUID)
|
||||||
|
podFullName := fmt.Sprintf("%s_%s", podName, podNamespace)
|
||||||
|
|
||||||
|
returned, hash, err := ParseDockerName(name)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to parse Docker container name %q: %v", name, err)
|
||||||
|
}
|
||||||
|
if returned.PodFullName != podFullName || string(returned.PodUID) != podUID || returned.ContainerName != container.Name || hash != 0 {
|
||||||
|
t.Errorf("unexpected parse: %s %s %s %d", returned.PodFullName, returned.PodUID, returned.ContainerName, hash)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,40 +10,23 @@ load(
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = ["docker.go"],
|
||||||
"docker.go",
|
|
||||||
"fake_docker_client.go",
|
|
||||||
"instrumented_docker.go",
|
|
||||||
"kube_docker_client.go",
|
|
||||||
],
|
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/credentialprovider:go_default_library",
|
"//pkg/credentialprovider:go_default_library",
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/images:go_default_library",
|
"//pkg/kubelet/images:go_default_library",
|
||||||
"//pkg/kubelet/metrics:go_default_library",
|
|
||||||
"//vendor/github.com/docker/distribution/digest:go_default_library",
|
|
||||||
"//vendor/github.com/docker/distribution/reference:go_default_library",
|
|
||||||
"//vendor/github.com/docker/docker/pkg/jsonmessage:go_default_library",
|
"//vendor/github.com/docker/docker/pkg/jsonmessage:go_default_library",
|
||||||
"//vendor/github.com/docker/docker/pkg/stdcopy:go_default_library",
|
|
||||||
"//vendor/github.com/docker/engine-api/client:go_default_library",
|
|
||||||
"//vendor/github.com/docker/engine-api/types:go_default_library",
|
"//vendor/github.com/docker/engine-api/types:go_default_library",
|
||||||
"//vendor/github.com/docker/engine-api/types/container:go_default_library",
|
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/golang.org/x/net/context:go_default_library",
|
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/util/clock:go_default_library",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = ["docker_test.go"],
|
||||||
"docker_test.go",
|
|
||||||
"kube_docker_client_test.go",
|
|
||||||
],
|
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = [
|
tags = [
|
||||||
"automanaged",
|
"automanaged",
|
||||||
|
@ -51,12 +34,9 @@ go_test(
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/credentialprovider:go_default_library",
|
"//pkg/credentialprovider:go_default_library",
|
||||||
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/images:go_default_library",
|
"//pkg/kubelet/images:go_default_library",
|
||||||
"//pkg/util/hash:go_default_library",
|
|
||||||
"//vendor/github.com/docker/docker/pkg/jsonmessage:go_default_library",
|
"//vendor/github.com/docker/docker/pkg/jsonmessage:go_default_library",
|
||||||
"//vendor/github.com/docker/engine-api/types:go_default_library",
|
|
||||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
|
||||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -18,86 +18,22 @@ package dockertools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
dockerdigest "github.com/docker/distribution/digest"
|
|
||||||
dockerref "github.com/docker/distribution/reference"
|
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
dockerapi "github.com/docker/engine-api/client"
|
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/credentialprovider"
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/images"
|
"k8s.io/kubernetes/pkg/kubelet/images"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
LogSuffix = "log"
|
|
||||||
ext4MaxFileNameLen = 255
|
|
||||||
|
|
||||||
DockerType = "docker"
|
|
||||||
|
|
||||||
// https://docs.docker.com/engine/reference/api/docker_remote_api/
|
|
||||||
// docker version should be at least 1.10.x
|
|
||||||
minimumDockerAPIVersion = "1.22"
|
|
||||||
|
|
||||||
statusRunningPrefix = "Up"
|
|
||||||
statusExitedPrefix = "Exited"
|
|
||||||
statusCreatedPrefix = "Created"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DockerInterface is an abstract interface for testability. It abstracts the interface of docker client.
|
|
||||||
type DockerInterface interface {
|
|
||||||
ListContainers(options dockertypes.ContainerListOptions) ([]dockertypes.Container, error)
|
|
||||||
InspectContainer(id string) (*dockertypes.ContainerJSON, error)
|
|
||||||
CreateContainer(dockertypes.ContainerCreateConfig) (*dockertypes.ContainerCreateResponse, error)
|
|
||||||
StartContainer(id string) error
|
|
||||||
StopContainer(id string, timeout int) error
|
|
||||||
RemoveContainer(id string, opts dockertypes.ContainerRemoveOptions) error
|
|
||||||
InspectImageByRef(imageRef string) (*dockertypes.ImageInspect, error)
|
|
||||||
InspectImageByID(imageID string) (*dockertypes.ImageInspect, error)
|
|
||||||
ListImages(opts dockertypes.ImageListOptions) ([]dockertypes.Image, error)
|
|
||||||
PullImage(image string, auth dockertypes.AuthConfig, opts dockertypes.ImagePullOptions) error
|
|
||||||
RemoveImage(image string, opts dockertypes.ImageRemoveOptions) ([]dockertypes.ImageDelete, error)
|
|
||||||
ImageHistory(id string) ([]dockertypes.ImageHistory, error)
|
|
||||||
Logs(string, dockertypes.ContainerLogsOptions, StreamOptions) error
|
|
||||||
Version() (*dockertypes.Version, error)
|
|
||||||
Info() (*dockertypes.Info, error)
|
|
||||||
CreateExec(string, dockertypes.ExecConfig) (*dockertypes.ContainerExecCreateResponse, error)
|
|
||||||
StartExec(string, dockertypes.ExecStartCheck, StreamOptions) error
|
|
||||||
InspectExec(id string) (*dockertypes.ContainerExecInspect, error)
|
|
||||||
AttachToContainer(string, dockertypes.ContainerAttachOptions, StreamOptions) error
|
|
||||||
ResizeContainerTTY(id string, height, width int) error
|
|
||||||
ResizeExecTTY(id string, height, width int) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// KubeletContainerName encapsulates a pod name and a Kubernetes container name.
|
|
||||||
type KubeletContainerName struct {
|
|
||||||
PodFullName string
|
|
||||||
PodUID types.UID
|
|
||||||
ContainerName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// containerNamePrefix is used to identify the containers on the node managed by this
|
|
||||||
// process.
|
|
||||||
var containerNamePrefix = "k8s"
|
|
||||||
|
|
||||||
// SetContainerNamePrefix allows the container prefix name for this process to be changed.
|
|
||||||
// This is intended to support testing and bootstrapping experimentation. It cannot be
|
|
||||||
// changed once the Kubelet starts.
|
|
||||||
func SetContainerNamePrefix(prefix string) {
|
|
||||||
containerNamePrefix = prefix
|
|
||||||
}
|
|
||||||
|
|
||||||
// DockerPuller is an abstract interface for testability. It abstracts image pull operations.
|
// DockerPuller is an abstract interface for testability. It abstracts image pull operations.
|
||||||
|
// DockerPuller is *not* in use anywhere in the codebase.
|
||||||
|
// TODO: Examine whether we can migrate the unit tests and remove the code.
|
||||||
type DockerPuller interface {
|
type DockerPuller interface {
|
||||||
Pull(image string, secrets []v1.Secret) error
|
Pull(image string, secrets []v1.Secret) error
|
||||||
GetImageRef(image string) (string, error)
|
GetImageRef(image string) (string, error)
|
||||||
|
@ -105,12 +41,12 @@ type DockerPuller interface {
|
||||||
|
|
||||||
// dockerPuller is the default implementation of DockerPuller.
|
// dockerPuller is the default implementation of DockerPuller.
|
||||||
type dockerPuller struct {
|
type dockerPuller struct {
|
||||||
client DockerInterface
|
client libdocker.Interface
|
||||||
keyring credentialprovider.DockerKeyring
|
keyring credentialprovider.DockerKeyring
|
||||||
}
|
}
|
||||||
|
|
||||||
// newDockerPuller creates a new instance of the default implementation of DockerPuller.
|
// newDockerPuller creates a new instance of the default implementation of DockerPuller.
|
||||||
func newDockerPuller(client DockerInterface) DockerPuller {
|
func newDockerPuller(client libdocker.Interface) DockerPuller {
|
||||||
return &dockerPuller{
|
return &dockerPuller{
|
||||||
client: client,
|
client: client,
|
||||||
keyring: credentialprovider.NewDockerKeyring(),
|
keyring: credentialprovider.NewDockerKeyring(),
|
||||||
|
@ -133,104 +69,6 @@ func filterHTTPError(err error, image string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchImageTagOrSHA checks if the given image specifier is a valid image ref,
|
|
||||||
// and that it matches the given image. It should fail on things like image IDs
|
|
||||||
// (config digests) and other digest-only references, but succeed on image names
|
|
||||||
// (`foo`), tag references (`foo:bar`), and manifest digest references
|
|
||||||
// (`foo@sha256:xyz`).
|
|
||||||
func matchImageTagOrSHA(inspected dockertypes.ImageInspect, image string) bool {
|
|
||||||
// The image string follows the grammar specified here
|
|
||||||
// https://github.com/docker/distribution/blob/master/reference/reference.go#L4
|
|
||||||
named, err := dockerref.ParseNamed(image)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
_, isTagged := named.(dockerref.Tagged)
|
|
||||||
digest, isDigested := named.(dockerref.Digested)
|
|
||||||
if !isTagged && !isDigested {
|
|
||||||
// No Tag or SHA specified, so just return what we have
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if isTagged {
|
|
||||||
// Check the RepoTags for a match.
|
|
||||||
for _, tag := range inspected.RepoTags {
|
|
||||||
// An image name (without the tag/digest) can be [hostname '/'] component ['/' component]*
|
|
||||||
// Because either the RepoTag or the name *may* contain the
|
|
||||||
// hostname or not, we only check for the suffix match.
|
|
||||||
if strings.HasSuffix(image, tag) || strings.HasSuffix(tag, image) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if isDigested {
|
|
||||||
for _, repoDigest := range inspected.RepoDigests {
|
|
||||||
named, err := dockerref.ParseNamed(repoDigest)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(4).Infof("couldn't parse image RepoDigest reference %q: %v", repoDigest, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if d, isDigested := named.(dockerref.Digested); isDigested {
|
|
||||||
if digest.Digest().Algorithm().String() == d.Digest().Algorithm().String() &&
|
|
||||||
digest.Digest().Hex() == d.Digest().Hex() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// process the ID as a digest
|
|
||||||
id, err := dockerdigest.ParseDigest(inspected.ID)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
glog.V(4).Infof("Inspected image (%q) does not match %s", inspected.ID, image)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// matchImageIDOnly checks that the given image specifier is a digest-only
|
|
||||||
// reference, and that it matches the given image.
|
|
||||||
func matchImageIDOnly(inspected dockertypes.ImageInspect, image string) bool {
|
|
||||||
// If the image ref is literally equal to the inspected image's ID,
|
|
||||||
// just return true here (this might be the case for Docker 1.9,
|
|
||||||
// where we won't have a digest for the ID)
|
|
||||||
if inspected.ID == image {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise, we should try actual parsing to be more correct
|
|
||||||
ref, err := dockerref.Parse(image)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(4).Infof("couldn't parse image reference %q: %v", image, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
digest, isDigested := ref.(dockerref.Digested)
|
|
||||||
if !isDigested {
|
|
||||||
glog.V(4).Infof("the image reference %q was not a digest reference")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
id, err := dockerdigest.ParseDigest(inspected.ID)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(4).Infof("couldn't parse image ID reference %q: %v", id, err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if digest.Digest().Algorithm().String() == id.Algorithm().String() && digest.Digest().Hex() == id.Hex() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(4).Infof("The reference %s does not directly refer to the given image's ID (%q)", image, inspected.ID)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p dockerPuller) Pull(image string, secrets []v1.Secret) error {
|
func (p dockerPuller) Pull(image string, secrets []v1.Secret) error {
|
||||||
keyring, err := credentialprovider.MakeDockerKeyring(secrets, p.keyring)
|
keyring, err := credentialprovider.MakeDockerKeyring(secrets, p.keyring)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -296,123 +134,8 @@ func (p dockerPuller) GetImageRef(image string) (string, error) {
|
||||||
}
|
}
|
||||||
return imageRef, nil
|
return imageRef, nil
|
||||||
}
|
}
|
||||||
if IsImageNotFoundError(err) {
|
if libdocker.IsImageNotFoundError(err) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a name which can be reversed to identify both full pod name and container name.
|
|
||||||
// This function returns stable name, unique name and a unique id.
|
|
||||||
// Although rand.Uint32() is not really unique, but it's enough for us because error will
|
|
||||||
// only occur when instances of the same container in the same pod have the same UID. The
|
|
||||||
// chance is really slim.
|
|
||||||
func BuildDockerName(dockerName KubeletContainerName, container *v1.Container) (string, string, string) {
|
|
||||||
containerName := dockerName.ContainerName + "." + strconv.FormatUint(kubecontainer.HashContainerLegacy(container), 16)
|
|
||||||
stableName := fmt.Sprintf("%s_%s_%s_%s",
|
|
||||||
containerNamePrefix,
|
|
||||||
containerName,
|
|
||||||
dockerName.PodFullName,
|
|
||||||
dockerName.PodUID)
|
|
||||||
UID := fmt.Sprintf("%08x", rand.Uint32())
|
|
||||||
return stableName, fmt.Sprintf("%s_%s", stableName, UID), UID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unpacks a container name, returning the pod full name and container name we would have used to
|
|
||||||
// construct the docker name. If we are unable to parse the name, an error is returned.
|
|
||||||
func ParseDockerName(name string) (dockerName *KubeletContainerName, hash uint64, err error) {
|
|
||||||
// For some reason docker appears to be appending '/' to names.
|
|
||||||
// If it's there, strip it.
|
|
||||||
name = strings.TrimPrefix(name, "/")
|
|
||||||
parts := strings.Split(name, "_")
|
|
||||||
if len(parts) == 0 || parts[0] != containerNamePrefix {
|
|
||||||
err = fmt.Errorf("failed to parse Docker container name %q into parts", name)
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
if len(parts) < 6 {
|
|
||||||
// We have at least 5 fields. We may have more in the future.
|
|
||||||
// Anything with less fields than this is not something we can
|
|
||||||
// manage.
|
|
||||||
glog.Warningf("found a container with the %q prefix, but too few fields (%d): %q", containerNamePrefix, len(parts), name)
|
|
||||||
err = fmt.Errorf("Docker container name %q has less parts than expected %v", name, parts)
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nameParts := strings.Split(parts[1], ".")
|
|
||||||
containerName := nameParts[0]
|
|
||||||
if len(nameParts) > 1 {
|
|
||||||
hash, err = strconv.ParseUint(nameParts[1], 16, 32)
|
|
||||||
if err != nil {
|
|
||||||
glog.Warningf("invalid container hash %q in container %q", nameParts[1], name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
podFullName := parts[2] + "_" + parts[3]
|
|
||||||
podUID := types.UID(parts[4])
|
|
||||||
|
|
||||||
return &KubeletContainerName{podFullName, podUID, containerName}, hash, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LogSymlink(containerLogsDir, podFullName, containerName, dockerId string) string {
|
|
||||||
suffix := fmt.Sprintf(".%s", LogSuffix)
|
|
||||||
logPath := fmt.Sprintf("%s_%s-%s", podFullName, containerName, dockerId)
|
|
||||||
// Length of a filename cannot exceed 255 characters in ext4 on Linux.
|
|
||||||
if len(logPath) > ext4MaxFileNameLen-len(suffix) {
|
|
||||||
logPath = logPath[:ext4MaxFileNameLen-len(suffix)]
|
|
||||||
}
|
|
||||||
return path.Join(containerLogsDir, logPath+suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a *dockerapi.Client, either using the endpoint passed in, or using
|
|
||||||
// DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT path per their spec
|
|
||||||
func getDockerClient(dockerEndpoint string) (*dockerapi.Client, error) {
|
|
||||||
if len(dockerEndpoint) > 0 {
|
|
||||||
glog.Infof("Connecting to docker on %s", dockerEndpoint)
|
|
||||||
return dockerapi.NewClient(dockerEndpoint, "", nil, nil)
|
|
||||||
}
|
|
||||||
return dockerapi.NewEnvClient()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnectToDockerOrDie creates docker client connecting to docker daemon.
|
|
||||||
// If the endpoint passed in is "fake://", a fake docker client
|
|
||||||
// will be returned. The program exits if error occurs. The requestTimeout
|
|
||||||
// is the timeout for docker requests. If timeout is exceeded, the request
|
|
||||||
// will be cancelled and throw out an error. If requestTimeout is 0, a default
|
|
||||||
// value will be applied.
|
|
||||||
func ConnectToDockerOrDie(dockerEndpoint string, requestTimeout, imagePullProgressDeadline time.Duration) DockerInterface {
|
|
||||||
if dockerEndpoint == "fake://" {
|
|
||||||
return NewFakeDockerClient()
|
|
||||||
}
|
|
||||||
client, err := getDockerClient(dockerEndpoint)
|
|
||||||
if err != nil {
|
|
||||||
glog.Fatalf("Couldn't connect to docker: %v", err)
|
|
||||||
}
|
|
||||||
glog.Infof("Start docker client with request timeout=%v", requestTimeout)
|
|
||||||
return newKubeDockerClient(client, requestTimeout, imagePullProgressDeadline)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetKubeletDockerContainers lists all container or just the running ones.
|
|
||||||
// Returns a list of docker containers that we manage
|
|
||||||
// TODO: This function should be deleted after migrating
|
|
||||||
// test/e2e_node/garbage_collector_test.go off of it.
|
|
||||||
func GetKubeletDockerContainers(client DockerInterface, allContainers bool) ([]*dockertypes.Container, error) {
|
|
||||||
result := []*dockertypes.Container{}
|
|
||||||
containers, err := client.ListContainers(dockertypes.ContainerListOptions{All: allContainers})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for i := range containers {
|
|
||||||
container := &containers[i]
|
|
||||||
if len(container.Names) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Skip containers that we didn't create to allow users to manually
|
|
||||||
// spin up their own containers if they want.
|
|
||||||
if !strings.HasPrefix(container.Names[0], "/"+containerNamePrefix+"_") {
|
|
||||||
glog.V(5).Infof("Docker Container: %s is not managed by kubelet.", container.Names[0])
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result = append(result, container)
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,372 +18,17 @@ package dockertools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"hash/adler32"
|
|
||||||
"math/rand"
|
|
||||||
"path"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/jsonmessage"
|
"github.com/docker/docker/pkg/jsonmessage"
|
||||||
dockertypes "github.com/docker/engine-api/types"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/credentialprovider"
|
"k8s.io/kubernetes/pkg/credentialprovider"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/images"
|
"k8s.io/kubernetes/pkg/kubelet/images"
|
||||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func verifyCalls(t *testing.T, fakeDocker *FakeDockerClient, calls []string) {
|
// TODO: Examine the tests and see if they can be migrated to kuberuntime.
|
||||||
assert.New(t).NoError(fakeDocker.AssertCalls(calls))
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyStringArrayEquals(t *testing.T, actual, expected []string) {
|
|
||||||
invalid := len(actual) != len(expected)
|
|
||||||
if !invalid {
|
|
||||||
for ix, value := range actual {
|
|
||||||
if expected[ix] != value {
|
|
||||||
invalid = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if invalid {
|
|
||||||
t.Errorf("Expected: %#v, Actual: %#v", expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func findPodContainer(dockerContainers []*dockertypes.Container, podFullName string, uid types.UID, containerName string) (*dockertypes.Container, bool, uint64) {
|
|
||||||
for _, dockerContainer := range dockerContainers {
|
|
||||||
if len(dockerContainer.Names) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
dockerName, hash, err := ParseDockerName(dockerContainer.Names[0])
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if dockerName.PodFullName == podFullName &&
|
|
||||||
(uid == "" || dockerName.PodUID == uid) &&
|
|
||||||
dockerName.ContainerName == containerName {
|
|
||||||
return dockerContainer, true, hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetContainerID(t *testing.T) {
|
|
||||||
fakeDocker := NewFakeDockerClient()
|
|
||||||
fakeDocker.SetFakeRunningContainers([]*FakeContainer{
|
|
||||||
{
|
|
||||||
ID: "foobar",
|
|
||||||
Name: "/k8s_foo_qux_ns_1234_42",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "barbar",
|
|
||||||
Name: "/k8s_bar_qux_ns_2565_42",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
dockerContainers, err := GetKubeletDockerContainers(fakeDocker, false)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Expected no error, Got %#v", err)
|
|
||||||
}
|
|
||||||
if len(dockerContainers) != 2 {
|
|
||||||
t.Errorf("Expected %#v, Got %#v", fakeDocker.RunningContainerList, dockerContainers)
|
|
||||||
}
|
|
||||||
verifyCalls(t, fakeDocker, []string{"list"})
|
|
||||||
|
|
||||||
dockerContainer, found, _ := findPodContainer(dockerContainers, "qux_ns", "", "foo")
|
|
||||||
if dockerContainer == nil || !found {
|
|
||||||
t.Errorf("Failed to find container %#v", dockerContainer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fakeDocker.ClearCalls()
|
|
||||||
dockerContainer, found, _ = findPodContainer(dockerContainers, "foobar", "", "foo")
|
|
||||||
verifyCalls(t, fakeDocker, []string{})
|
|
||||||
if dockerContainer != nil || found {
|
|
||||||
t.Errorf("Should not have found container %#v", dockerContainer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyPackUnpack(t *testing.T, podNamespace, podUID, podName, containerName string) {
|
|
||||||
container := &v1.Container{Name: containerName}
|
|
||||||
hasher := adler32.New()
|
|
||||||
hashutil.DeepHashObject(hasher, *container)
|
|
||||||
computedHash := uint64(hasher.Sum32())
|
|
||||||
podFullName := fmt.Sprintf("%s_%s", podName, podNamespace)
|
|
||||||
_, name, _ := BuildDockerName(KubeletContainerName{podFullName, types.UID(podUID), container.Name}, container)
|
|
||||||
returned, hash, err := ParseDockerName(name)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to parse Docker container name %q: %v", name, err)
|
|
||||||
}
|
|
||||||
if podFullName != returned.PodFullName || podUID != string(returned.PodUID) || containerName != returned.ContainerName || computedHash != hash {
|
|
||||||
t.Errorf("For (%s, %s, %s, %d), unpacked (%s, %s, %s, %d)", podFullName, podUID, containerName, computedHash, returned.PodFullName, returned.PodUID, returned.ContainerName, hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContainerNaming(t *testing.T) {
|
|
||||||
podUID := "12345678"
|
|
||||||
verifyPackUnpack(t, "file", podUID, "name", "container")
|
|
||||||
verifyPackUnpack(t, "file", podUID, "name-with-dashes", "container")
|
|
||||||
// UID is same as pod name
|
|
||||||
verifyPackUnpack(t, "file", podUID, podUID, "container")
|
|
||||||
// No Container name
|
|
||||||
verifyPackUnpack(t, "other", podUID, "name", "")
|
|
||||||
|
|
||||||
container := &v1.Container{Name: "container"}
|
|
||||||
podName := "foo"
|
|
||||||
podNamespace := "test"
|
|
||||||
name := fmt.Sprintf("k8s_%s_%s_%s_%s_42", container.Name, podName, podNamespace, podUID)
|
|
||||||
podFullName := fmt.Sprintf("%s_%s", podName, podNamespace)
|
|
||||||
|
|
||||||
returned, hash, err := ParseDockerName(name)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to parse Docker container name %q: %v", name, err)
|
|
||||||
}
|
|
||||||
if returned.PodFullName != podFullName || string(returned.PodUID) != podUID || returned.ContainerName != container.Name || hash != 0 {
|
|
||||||
t.Errorf("unexpected parse: %s %s %s %d", returned.PodFullName, returned.PodUID, returned.ContainerName, hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMatchImageTagOrSHA(t *testing.T) {
|
|
||||||
for i, testCase := range []struct {
|
|
||||||
Inspected dockertypes.ImageInspect
|
|
||||||
Image string
|
|
||||||
Output bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:latest"}},
|
|
||||||
Image: "ubuntu",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:14.04"}},
|
|
||||||
Image: "ubuntu:latest",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"colemickens/hyperkube-amd64:217.9beff63"}},
|
|
||||||
Image: "colemickens/hyperkube-amd64:217.9beff63",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"colemickens/hyperkube-amd64:217.9beff63"}},
|
|
||||||
Image: "docker.io/colemickens/hyperkube-amd64:217.9beff63",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"docker.io/kubernetes/pause:latest"}},
|
|
||||||
Image: "kubernetes/pause:latest",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:2208f7a29005",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:2208",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// mismatched ID is ignored
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:0000f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// invalid digest is ignored
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:unparseable",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:unparseable",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// v1 schema images can be pulled in one format and returned in another
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{"centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// RepoDigest match is is required
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:000084acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// RepoDigest match is allowed
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// RepoDigest and ID are checked
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// unparseable RepoDigests are skipped
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{
|
|
||||||
"centos/ruby-23-centos7@sha256:unparseable",
|
|
||||||
"docker.io/centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// unparseable RepoDigest is ignored
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:unparseable"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// unparseable image digest is ignored
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:unparseable"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:unparseable",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// prefix match is rejected for ID and RepoDigest
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:unparseable",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:unparseable"},
|
|
||||||
},
|
|
||||||
Image: "sha256:unparseable",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// possible SHA prefix match is rejected for ID and RepoDigest because it is not in the named format
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:0000f247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{"docker.io/centos/ruby-23-centos7@sha256:0000f247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227"},
|
|
||||||
},
|
|
||||||
Image: "sha256:0000",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
match := matchImageTagOrSHA(testCase.Inspected, testCase.Image)
|
|
||||||
assert.Equal(t, testCase.Output, match, testCase.Image+fmt.Sprintf(" is not a match (%d)", i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMatchImageIDOnly(t *testing.T) {
|
|
||||||
for i, testCase := range []struct {
|
|
||||||
Inspected dockertypes.ImageInspect
|
|
||||||
Image string
|
|
||||||
Output bool
|
|
||||||
}{
|
|
||||||
// shouldn't match names or tagged names
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"ubuntu:latest"}},
|
|
||||||
Image: "ubuntu",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{RepoTags: []string{"colemickens/hyperkube-amd64:217.9beff63"}},
|
|
||||||
Image: "colemickens/hyperkube-amd64:217.9beff63",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
// should match name@digest refs if they refer to the image ID (but only the full ID)
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:2208f7a29005",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:2208",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
// should match when the IDs are literally the same
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "foobar",
|
|
||||||
},
|
|
||||||
Image: "foobar",
|
|
||||||
Output: true,
|
|
||||||
},
|
|
||||||
// shouldn't match mismatched IDs
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:2208f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:0000f7a29005d226d1ee33a63e33af1f47af6156c740d7d23c7948e8d282d53d",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
// shouldn't match invalid IDs or refs
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:unparseable",
|
|
||||||
},
|
|
||||||
Image: "myimage@sha256:unparseable",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
// shouldn't match against repo digests
|
|
||||||
{
|
|
||||||
Inspected: dockertypes.ImageInspect{
|
|
||||||
ID: "sha256:9bbdf247c91345f0789c10f50a57e36a667af1189687ad1de88a6243d05a2227",
|
|
||||||
RepoDigests: []string{"centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf"},
|
|
||||||
},
|
|
||||||
Image: "centos/ruby-23-centos7@sha256:940584acbbfb0347272112d2eb95574625c0c60b4e2fdadb139de5859cf754bf",
|
|
||||||
Output: false,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
match := matchImageIDOnly(testCase.Inspected, testCase.Image)
|
|
||||||
assert.Equal(t, testCase.Output, match, fmt.Sprintf("%s is not a match (%d)", testCase.Image, i))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPullWithNoSecrets(t *testing.T) {
|
func TestPullWithNoSecrets(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
imageName string
|
imageName string
|
||||||
|
@ -399,7 +44,7 @@ func TestPullWithNoSecrets(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
fakeKeyring := &credentialprovider.FakeKeyring{}
|
fakeKeyring := &credentialprovider.FakeKeyring{}
|
||||||
fakeClient := NewFakeDockerClient()
|
fakeClient := libdocker.NewFakeDockerClient()
|
||||||
|
|
||||||
dp := dockerPuller{
|
dp := dockerPuller{
|
||||||
client: fakeClient,
|
client: fakeClient,
|
||||||
|
@ -412,13 +57,8 @@ func TestPullWithNoSecrets(t *testing.T) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if e, a := 1, len(fakeClient.pulled); e != a {
|
if err := fakeClient.AssertImagesPulled([]string{test.imageName}); err != nil {
|
||||||
t.Errorf("%s: expected 1 pulled image, got %d: %v", test.imageName, a, fakeClient.pulled)
|
t.Errorf("images pulled do not match the expected: %v", err)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if e, a := test.expectedImage, fakeClient.pulled[0]; e != a {
|
|
||||||
t.Errorf("%s: expected pull of %q, but got %q", test.imageName, e, a)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -442,7 +82,7 @@ func TestPullWithJSONError(t *testing.T) {
|
||||||
}
|
}
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
fakeKeyring := &credentialprovider.FakeKeyring{}
|
fakeKeyring := &credentialprovider.FakeKeyring{}
|
||||||
fakeClient := NewFakeDockerClient()
|
fakeClient := libdocker.NewFakeDockerClient()
|
||||||
fakeClient.InjectError("pull", test.err)
|
fakeClient.InjectError("pull", test.err)
|
||||||
|
|
||||||
puller := &dockerPuller{
|
puller := &dockerPuller{
|
||||||
|
@ -520,7 +160,7 @@ func TestPullWithSecrets(t *testing.T) {
|
||||||
builtInKeyRing := &credentialprovider.BasicDockerKeyring{}
|
builtInKeyRing := &credentialprovider.BasicDockerKeyring{}
|
||||||
builtInKeyRing.Add(test.builtInDockerConfig)
|
builtInKeyRing.Add(test.builtInDockerConfig)
|
||||||
|
|
||||||
fakeClient := NewFakeDockerClient()
|
fakeClient := libdocker.NewFakeDockerClient()
|
||||||
|
|
||||||
dp := dockerPuller{
|
dp := dockerPuller{
|
||||||
client: fakeClient,
|
client: fakeClient,
|
||||||
|
@ -532,35 +172,8 @@ func TestPullWithSecrets(t *testing.T) {
|
||||||
t.Errorf("%s: unexpected non-nil err: %s", i, err)
|
t.Errorf("%s: unexpected non-nil err: %s", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if err := fakeClient.AssertImagesPulledMsgs(test.expectedPulls); err != nil {
|
||||||
if e, a := 1, len(fakeClient.pulled); e != a {
|
t.Errorf("images pulled do not match the expected: %v", err)
|
||||||
t.Errorf("%s: expected 1 pulled image, got %d: %v", i, a, fakeClient.pulled)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if e, a := test.expectedPulls, fakeClient.pulled; !reflect.DeepEqual(e, a) {
|
|
||||||
t.Errorf("%s: expected pull of %v, but got %v", i, e, a)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
|
|
||||||
func randStringBytes(n int) string {
|
|
||||||
b := make([]byte, n)
|
|
||||||
for i := range b {
|
|
||||||
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
|
||||||
}
|
|
||||||
return string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLogSymLink(t *testing.T) {
|
|
||||||
as := assert.New(t)
|
|
||||||
containerLogsDir := "/foo/bar"
|
|
||||||
podFullName := randStringBytes(128)
|
|
||||||
containerName := randStringBytes(70)
|
|
||||||
dockerId := randStringBytes(80)
|
|
||||||
// The file name cannot exceed 255 characters. Since .log suffix is required, the prefix cannot exceed 251 characters.
|
|
||||||
expectedPath := path.Join(containerLogsDir, fmt.Sprintf("%s_%s-%s", podFullName, containerName, dockerId)[:251]+".log")
|
|
||||||
as.Equal(expectedPath, LogSymlink(containerLogsDir, podFullName, containerName, dockerId))
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ go_library(
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/v1:go_default_library",
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/gpu:go_default_library",
|
"//pkg/kubelet/gpu:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||||
|
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/gpu"
|
"k8s.io/kubernetes/pkg/kubelet/gpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,13 +60,13 @@ type nvidiaGPUManager struct {
|
||||||
defaultDevices []string
|
defaultDevices []string
|
||||||
// The interface which could get GPU mapping from all the containers.
|
// The interface which could get GPU mapping from all the containers.
|
||||||
// TODO: Should make this independent of Docker in the future.
|
// TODO: Should make this independent of Docker in the future.
|
||||||
dockerClient dockertools.DockerInterface
|
dockerClient libdocker.Interface
|
||||||
activePodsLister activePodsLister
|
activePodsLister activePodsLister
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNvidiaGPUManager returns a GPUManager that manages local Nvidia GPUs.
|
// NewNvidiaGPUManager returns a GPUManager that manages local Nvidia GPUs.
|
||||||
// TODO: Migrate to use pod level cgroups and make it generic to all runtimes.
|
// TODO: Migrate to use pod level cgroups and make it generic to all runtimes.
|
||||||
func NewNvidiaGPUManager(activePodsLister activePodsLister, dockerClient dockertools.DockerInterface) (gpu.GPUManager, error) {
|
func NewNvidiaGPUManager(activePodsLister activePodsLister, dockerClient libdocker.Interface) (gpu.GPUManager, error) {
|
||||||
if dockerClient == nil {
|
if dockerClient == nil {
|
||||||
return nil, fmt.Errorf("invalid docker client specified")
|
return nil, fmt.Errorf("invalid docker client specified")
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,8 +63,8 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubelet/config"
|
"k8s.io/kubernetes/pkg/kubelet/config"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockershim"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
dockerremote "k8s.io/kubernetes/pkg/kubelet/dockershim/remote"
|
dockerremote "k8s.io/kubernetes/pkg/kubelet/dockershim/remote"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/events"
|
"k8s.io/kubernetes/pkg/kubelet/events"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/eviction"
|
"k8s.io/kubernetes/pkg/kubelet/eviction"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/gpu"
|
"k8s.io/kubernetes/pkg/kubelet/gpu"
|
||||||
|
@ -219,7 +219,7 @@ type KubeletDeps struct {
|
||||||
CAdvisorInterface cadvisor.Interface
|
CAdvisorInterface cadvisor.Interface
|
||||||
Cloud cloudprovider.Interface
|
Cloud cloudprovider.Interface
|
||||||
ContainerManager cm.ContainerManager
|
ContainerManager cm.ContainerManager
|
||||||
DockerClient dockertools.DockerInterface
|
DockerClient libdocker.Interface
|
||||||
EventClient v1core.EventsGetter
|
EventClient v1core.EventsGetter
|
||||||
KubeClient clientset.Interface
|
KubeClient clientset.Interface
|
||||||
ExternalKubeClient clientgoclientset.Interface
|
ExternalKubeClient clientgoclientset.Interface
|
||||||
|
@ -793,7 +793,7 @@ type Kubelet struct {
|
||||||
|
|
||||||
hostname string
|
hostname string
|
||||||
nodeName types.NodeName
|
nodeName types.NodeName
|
||||||
dockerClient dockertools.DockerInterface
|
dockerClient libdocker.Interface
|
||||||
runtimeCache kubecontainer.RuntimeCache
|
runtimeCache kubecontainer.RuntimeCache
|
||||||
kubeClient clientset.Interface
|
kubeClient clientset.Interface
|
||||||
iptClient utilipt.Interface
|
iptClient utilipt.Interface
|
||||||
|
|
|
@ -34,7 +34,6 @@ go_library(
|
||||||
"//pkg/kubelet/api:go_default_library",
|
"//pkg/kubelet/api:go_default_library",
|
||||||
"//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
|
"//pkg/kubelet/api/v1alpha1/runtime:go_default_library",
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
|
||||||
"//pkg/kubelet/events:go_default_library",
|
"//pkg/kubelet/events:go_default_library",
|
||||||
"//pkg/kubelet/images:go_default_library",
|
"//pkg/kubelet/images:go_default_library",
|
||||||
"//pkg/kubelet/lifecycle:go_default_library",
|
"//pkg/kubelet/lifecycle:go_default_library",
|
||||||
|
@ -76,6 +75,7 @@ go_test(
|
||||||
"kuberuntime_manager_test.go",
|
"kuberuntime_manager_test.go",
|
||||||
"kuberuntime_sandbox_test.go",
|
"kuberuntime_sandbox_test.go",
|
||||||
"labels_test.go",
|
"labels_test.go",
|
||||||
|
"legacy_test.go",
|
||||||
],
|
],
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
|
|
@ -17,8 +17,10 @@ limitations under the License.
|
||||||
package kuberuntime
|
package kuberuntime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file implements the functions that are needed for backward
|
// This file implements the functions that are needed for backward
|
||||||
|
@ -30,12 +32,24 @@ const (
|
||||||
// kubelet.containerLogsDir.
|
// kubelet.containerLogsDir.
|
||||||
legacyContainerLogsDir = "/var/log/containers"
|
legacyContainerLogsDir = "/var/log/containers"
|
||||||
// legacyLogSuffix is the legacy log suffix.
|
// legacyLogSuffix is the legacy log suffix.
|
||||||
legacyLogSuffix = dockertools.LogSuffix
|
legacyLogSuffix = "log"
|
||||||
|
|
||||||
|
ext4MaxFileNameLen = 255
|
||||||
)
|
)
|
||||||
|
|
||||||
// legacyLogSymlink composes the legacy container log path. It is only used for legacy cluster
|
// legacyLogSymlink composes the legacy container log path. It is only used for legacy cluster
|
||||||
// logging support.
|
// logging support.
|
||||||
func legacyLogSymlink(containerID string, containerName, podName, podNamespace string) string {
|
func legacyLogSymlink(containerID string, containerName, podName, podNamespace string) string {
|
||||||
return dockertools.LogSymlink(legacyContainerLogsDir, kubecontainer.BuildPodFullName(podName, podNamespace),
|
return logSymlink(legacyContainerLogsDir, kubecontainer.BuildPodFullName(podName, podNamespace),
|
||||||
containerName, containerID)
|
containerName, containerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logSymlink(containerLogsDir, podFullName, containerName, dockerId string) string {
|
||||||
|
suffix := fmt.Sprintf(".%s", legacyLogSuffix)
|
||||||
|
logPath := fmt.Sprintf("%s_%s-%s", podFullName, containerName, dockerId)
|
||||||
|
// Length of a filename cannot exceed 255 characters in ext4 on Linux.
|
||||||
|
if len(logPath) > ext4MaxFileNameLen-len(suffix) {
|
||||||
|
logPath = logPath[:ext4MaxFileNameLen-len(suffix)]
|
||||||
|
}
|
||||||
|
return path.Join(containerLogsDir, logPath+suffix)
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 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 kuberuntime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
func randStringBytes(n int) string {
|
||||||
|
b := make([]byte, n)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = letterBytes[rand.Intn(len(letterBytes))]
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogSymLink(t *testing.T) {
|
||||||
|
as := assert.New(t)
|
||||||
|
containerLogsDir := "/foo/bar"
|
||||||
|
podFullName := randStringBytes(128)
|
||||||
|
containerName := randStringBytes(70)
|
||||||
|
dockerId := randStringBytes(80)
|
||||||
|
// The file name cannot exceed 255 characters. Since .log suffix is required, the prefix cannot exceed 251 characters.
|
||||||
|
expectedPath := path.Join(containerLogsDir, fmt.Sprintf("%s_%s-%s", podFullName, containerName, dockerId)[:251]+".log")
|
||||||
|
as.Equal(expectedPath, logSymlink(containerLogsDir, podFullName, containerName, dockerId))
|
||||||
|
}
|
|
@ -22,7 +22,6 @@ go_library(
|
||||||
"//pkg/api/validation:go_default_library",
|
"//pkg/api/validation:go_default_library",
|
||||||
"//pkg/apis/extensions/validation:go_default_library",
|
"//pkg/apis/extensions/validation:go_default_library",
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
|
||||||
"//pkg/kubelet/lifecycle:go_default_library",
|
"//pkg/kubelet/lifecycle:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
|
|
||||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/container"
|
"k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
|
||||||
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,8 +30,13 @@ const (
|
||||||
// (e.g., 1.24). Append the version with a ".0" so that it works
|
// (e.g., 1.24). Append the version with a ".0" so that it works
|
||||||
// with both the CRI and dockertools comparison logic.
|
// with both the CRI and dockertools comparison logic.
|
||||||
dockerMinimumAPIVersion = "1.24.0"
|
dockerMinimumAPIVersion = "1.24.0"
|
||||||
|
|
||||||
|
dockerTypeName = "docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: The admission logic in this file is runtime-dependent. It should be
|
||||||
|
// changed to be generic and CRI-compatible.
|
||||||
|
|
||||||
type runtimeAdmitHandler struct {
|
type runtimeAdmitHandler struct {
|
||||||
result lifecycle.PodAdmitResult
|
result lifecycle.PodAdmitResult
|
||||||
}
|
}
|
||||||
|
@ -42,7 +46,7 @@ var _ lifecycle.PodAdmitHandler = &runtimeAdmitHandler{}
|
||||||
// NewRuntimeAdmitHandler returns a sysctlRuntimeAdmitHandler which checks whether
|
// NewRuntimeAdmitHandler returns a sysctlRuntimeAdmitHandler which checks whether
|
||||||
// the given runtime support sysctls.
|
// the given runtime support sysctls.
|
||||||
func NewRuntimeAdmitHandler(runtime container.Runtime) (*runtimeAdmitHandler, error) {
|
func NewRuntimeAdmitHandler(runtime container.Runtime) (*runtimeAdmitHandler, error) {
|
||||||
if runtime.Type() == dockertools.DockerType {
|
if runtime.Type() == dockerTypeName {
|
||||||
v, err := runtime.APIVersion()
|
v, err := runtime.APIVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get runtime version: %v", err)
|
return nil, fmt.Errorf("failed to get runtime version: %v", err)
|
||||||
|
|
|
@ -27,7 +27,7 @@ go_library(
|
||||||
"//pkg/kubelet/cadvisor:go_default_library",
|
"//pkg/kubelet/cadvisor:go_default_library",
|
||||||
"//pkg/kubelet/cm:go_default_library",
|
"//pkg/kubelet/cm:go_default_library",
|
||||||
"//pkg/kubelet/container/testing:go_default_library",
|
"//pkg/kubelet/container/testing:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/types:go_default_library",
|
"//pkg/kubelet/types:go_default_library",
|
||||||
"//pkg/util:go_default_library",
|
"//pkg/util:go_default_library",
|
||||||
"//pkg/util/io:go_default_library",
|
"//pkg/util/io:go_default_library",
|
||||||
|
|
|
@ -30,7 +30,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||||
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
containertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
kubeio "k8s.io/kubernetes/pkg/util/io"
|
kubeio "k8s.io/kubernetes/pkg/util/io"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
|
@ -52,7 +52,7 @@ func NewHollowKubelet(
|
||||||
nodeName string,
|
nodeName string,
|
||||||
client *clientset.Clientset,
|
client *clientset.Clientset,
|
||||||
cadvisorInterface cadvisor.Interface,
|
cadvisorInterface cadvisor.Interface,
|
||||||
dockerClient dockertools.DockerInterface,
|
dockerClient libdocker.Interface,
|
||||||
kubeletPort, kubeletReadOnlyPort int,
|
kubeletPort, kubeletReadOnlyPort int,
|
||||||
containerManager cm.ContainerManager,
|
containerManager cm.ContainerManager,
|
||||||
maxPods int, podsPerCore int,
|
maxPods int, podsPerCore int,
|
||||||
|
|
|
@ -101,7 +101,7 @@ go_test(
|
||||||
"//pkg/kubelet/api/v1alpha1/stats:go_default_library",
|
"//pkg/kubelet/api/v1alpha1/stats:go_default_library",
|
||||||
"//pkg/kubelet/cm:go_default_library",
|
"//pkg/kubelet/cm:go_default_library",
|
||||||
"//pkg/kubelet/container:go_default_library",
|
"//pkg/kubelet/container:go_default_library",
|
||||||
"//pkg/kubelet/dockertools:go_default_library",
|
"//pkg/kubelet/dockershim/libdocker:go_default_library",
|
||||||
"//pkg/kubelet/images:go_default_library",
|
"//pkg/kubelet/images:go_default_library",
|
||||||
"//pkg/kubelet/metrics:go_default_library",
|
"//pkg/kubelet/metrics:go_default_library",
|
||||||
"//pkg/kubelet/types:go_default_library",
|
"//pkg/kubelet/types:go_default_library",
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
docker "k8s.io/kubernetes/pkg/kubelet/dockertools"
|
"k8s.io/kubernetes/pkg/kubelet/dockershim/libdocker"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
|
@ -258,16 +258,16 @@ func containerGCTest(f *framework.Framework, test testRun) {
|
||||||
|
|
||||||
// Runs containerGCTest using the docker runtime.
|
// Runs containerGCTest using the docker runtime.
|
||||||
func dockerContainerGCTest(f *framework.Framework, test testRun) {
|
func dockerContainerGCTest(f *framework.Framework, test testRun) {
|
||||||
var runtime docker.DockerInterface
|
var runtime libdocker.Interface
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
runtime = docker.ConnectToDockerOrDie(defaultDockerEndpoint, defaultRuntimeRequestTimeoutDuration, defaultImagePullProgressDeadline)
|
runtime = libdocker.ConnectToDockerOrDie(defaultDockerEndpoint, defaultRuntimeRequestTimeoutDuration, defaultImagePullProgressDeadline)
|
||||||
})
|
})
|
||||||
for _, pod := range test.testPods {
|
for _, pod := range test.testPods {
|
||||||
// Initialize the getContainerNames function to use the dockertools api
|
// Initialize the getContainerNames function to use the dockertools api
|
||||||
thisPrefix := pod.containerPrefix
|
thisPrefix := pod.containerPrefix
|
||||||
pod.getContainerNames = func() ([]string, error) {
|
pod.getContainerNames = func() ([]string, error) {
|
||||||
relevantContainers := []string{}
|
relevantContainers := []string{}
|
||||||
dockerContainers, err := docker.GetKubeletDockerContainers(runtime, true)
|
dockerContainers, err := libdocker.GetKubeletDockerContainers(runtime, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return relevantContainers, err
|
return relevantContainers, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue