mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 09:22:44 +00:00
* Add docker pullable support.
* Fix inspect image bug. * Fix remove image bug.
This commit is contained in:
parent
ead65fc25f
commit
afa3414779
@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
@ -89,11 +88,7 @@ func (r *FakeImageService) ImageStatus(image *runtimeApi.ImageSpec) (*runtimeApi
|
|||||||
|
|
||||||
r.Called = append(r.Called, "ImageStatus")
|
r.Called = append(r.Called, "ImageStatus")
|
||||||
|
|
||||||
if img, ok := r.Images[image.GetImage()]; ok {
|
return r.Images[image.GetImage()], nil
|
||||||
return img, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("image %q not found", image.GetImage())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *FakeImageService) PullImage(image *runtimeApi.ImageSpec, auth *runtimeApi.AuthConfig) error {
|
func (r *FakeImageService) PullImage(image *runtimeApi.ImageSpec, auth *runtimeApi.AuthConfig) error {
|
||||||
|
@ -2963,7 +2963,8 @@ var _RuntimeService_serviceDesc = grpc.ServiceDesc{
|
|||||||
type ImageServiceClient interface {
|
type ImageServiceClient interface {
|
||||||
// ListImages lists existing images.
|
// ListImages lists existing images.
|
||||||
ListImages(ctx context.Context, in *ListImagesRequest, opts ...grpc.CallOption) (*ListImagesResponse, error)
|
ListImages(ctx context.Context, in *ListImagesRequest, opts ...grpc.CallOption) (*ListImagesResponse, error)
|
||||||
// ImageStatus returns the status of the image.
|
// ImageStatus returns the status of the image. If the image is not
|
||||||
|
// present, returns nil.
|
||||||
ImageStatus(ctx context.Context, in *ImageStatusRequest, opts ...grpc.CallOption) (*ImageStatusResponse, error)
|
ImageStatus(ctx context.Context, in *ImageStatusRequest, opts ...grpc.CallOption) (*ImageStatusResponse, error)
|
||||||
// PullImage pulls an image with authentication config.
|
// PullImage pulls an image with authentication config.
|
||||||
PullImage(ctx context.Context, in *PullImageRequest, opts ...grpc.CallOption) (*PullImageResponse, error)
|
PullImage(ctx context.Context, in *PullImageRequest, opts ...grpc.CallOption) (*PullImageResponse, error)
|
||||||
@ -3021,7 +3022,8 @@ func (c *imageServiceClient) RemoveImage(ctx context.Context, in *RemoveImageReq
|
|||||||
type ImageServiceServer interface {
|
type ImageServiceServer interface {
|
||||||
// ListImages lists existing images.
|
// ListImages lists existing images.
|
||||||
ListImages(context.Context, *ListImagesRequest) (*ListImagesResponse, error)
|
ListImages(context.Context, *ListImagesRequest) (*ListImagesResponse, error)
|
||||||
// ImageStatus returns the status of the image.
|
// ImageStatus returns the status of the image. If the image is not
|
||||||
|
// present, returns nil.
|
||||||
ImageStatus(context.Context, *ImageStatusRequest) (*ImageStatusResponse, error)
|
ImageStatus(context.Context, *ImageStatusRequest) (*ImageStatusResponse, error)
|
||||||
// PullImage pulls an image with authentication config.
|
// PullImage pulls an image with authentication config.
|
||||||
PullImage(context.Context, *PullImageRequest) (*PullImageResponse, error)
|
PullImage(context.Context, *PullImageRequest) (*PullImageResponse, error)
|
||||||
|
@ -46,7 +46,8 @@ service RuntimeService {
|
|||||||
service ImageService {
|
service ImageService {
|
||||||
// ListImages lists existing images.
|
// ListImages lists existing images.
|
||||||
rpc ListImages(ListImagesRequest) returns (ListImagesResponse) {}
|
rpc ListImages(ListImagesRequest) returns (ListImagesResponse) {}
|
||||||
// ImageStatus returns the status of the image.
|
// ImageStatus returns the status of the image. If the image is not
|
||||||
|
// present, returns nil.
|
||||||
rpc ImageStatus(ImageStatusRequest) returns (ImageStatusResponse) {}
|
rpc ImageStatus(ImageStatusRequest) returns (ImageStatusResponse) {}
|
||||||
// PullImage pulls an image with authentication config.
|
// PullImage pulls an image with authentication config.
|
||||||
rpc PullImage(PullImageRequest) returns (PullImageResponse) {}
|
rpc PullImage(PullImageRequest) returns (PullImageResponse) {}
|
||||||
|
@ -36,7 +36,7 @@ const (
|
|||||||
statusExitedPrefix = "Exited"
|
statusExitedPrefix = "Exited"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toRuntimeAPIImage(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")
|
||||||
}
|
}
|
||||||
@ -50,6 +50,31 @@ func toRuntimeAPIImage(image *dockertypes.Image) (*runtimeApi.Image, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func imageInspectToRuntimeAPIImage(image *dockertypes.ImageInspect) (*runtimeApi.Image, error) {
|
||||||
|
if image == nil {
|
||||||
|
return nil, fmt.Errorf("unable to convert a nil pointer to a runtime API image")
|
||||||
|
}
|
||||||
|
|
||||||
|
size := uint64(image.VirtualSize)
|
||||||
|
return &runtimeApi.Image{
|
||||||
|
Id: &image.ID,
|
||||||
|
RepoTags: image.RepoTags,
|
||||||
|
RepoDigests: image.RepoDigests,
|
||||||
|
Size_: &size,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPullableImageID(id string, image *dockertypes.ImageInspect) string {
|
||||||
|
// Default to the image ID, but if RepoDigests is not empty, use
|
||||||
|
// the first digest instead.
|
||||||
|
imageID := DockerImageIDPrefix + id
|
||||||
|
if len(image.RepoDigests) > 0 {
|
||||||
|
imageID = DockerPullableImageIDPrefix + image.RepoDigests[0]
|
||||||
|
}
|
||||||
|
return imageID
|
||||||
|
}
|
||||||
|
|
||||||
func toRuntimeAPIContainer(c *dockertypes.Container) (*runtimeApi.Container, error) {
|
func toRuntimeAPIContainer(c *dockertypes.Container) (*runtimeApi.Container, error) {
|
||||||
state := toRuntimeAPIContainerState(c.Status)
|
state := toRuntimeAPIContainerState(c.Status)
|
||||||
metadata, err := parseContainerName(c.Names[0])
|
metadata, err := parseContainerName(c.Names[0])
|
||||||
|
@ -19,6 +19,7 @@ package dockershim
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
@ -40,3 +41,31 @@ func TestConvertDockerStatusToRuntimeAPIState(t *testing.T) {
|
|||||||
assert.Equal(t, test.expected, actual)
|
assert.Equal(t, test.expected, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertToPullableImageID(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
id string
|
||||||
|
image *dockertypes.ImageInspect
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
id: "image-1",
|
||||||
|
image: &dockertypes.ImageInspect{
|
||||||
|
RepoDigests: []string{"digest-1"},
|
||||||
|
},
|
||||||
|
expected: DockerPullableImageIDPrefix + "digest-1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "image-2",
|
||||||
|
image: &dockertypes.ImageInspect{
|
||||||
|
RepoDigests: []string{},
|
||||||
|
},
|
||||||
|
expected: DockerImageIDPrefix + "image-2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
actual := toPullableImageID(test.id, test.image)
|
||||||
|
assert.Equal(t, test.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -229,6 +229,13 @@ func (ds *dockerService) ContainerStatus(containerID string) (*runtimeApi.Contai
|
|||||||
return nil, fmt.Errorf("failed to parse timestamp for container %q: %v", containerID, err)
|
return nil, fmt.Errorf("failed to parse timestamp for container %q: %v", containerID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the image id to pullable id.
|
||||||
|
ir, err := ds.client.InspectImageByID(r.Image)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to inspect docker image %q while inspecting docker container %q: %v", r.Image, containerID, err)
|
||||||
|
}
|
||||||
|
imageID := toPullableImageID(r.Image, ir)
|
||||||
|
|
||||||
// Convert the mounts.
|
// Convert the mounts.
|
||||||
mounts := []*runtimeApi.Mount{}
|
mounts := []*runtimeApi.Mount{}
|
||||||
for i := range r.Mounts {
|
for i := range r.Mounts {
|
||||||
@ -293,7 +300,7 @@ func (ds *dockerService) ContainerStatus(containerID string) (*runtimeApi.Contai
|
|||||||
Id: &r.ID,
|
Id: &r.ID,
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
Image: &runtimeApi.ImageSpec{Image: &r.Config.Image},
|
Image: &runtimeApi.ImageSpec{Image: &r.Config.Image},
|
||||||
ImageRef: &r.Image,
|
ImageRef: &imageID,
|
||||||
Mounts: mounts,
|
Mounts: mounts,
|
||||||
ExitCode: &exitCode,
|
ExitCode: &exitCode,
|
||||||
State: &state,
|
State: &state,
|
||||||
|
@ -105,7 +105,7 @@ func TestContainerStatus(t *testing.T) {
|
|||||||
ct, st, ft := dt, dt, dt
|
ct, st, ft := dt, dt, dt
|
||||||
state := runtimeApi.ContainerState_CREATED
|
state := runtimeApi.ContainerState_CREATED
|
||||||
// The following variables are not set in FakeDockerClient.
|
// The following variables are not set in FakeDockerClient.
|
||||||
imageRef := ""
|
imageRef := DockerImageIDPrefix + ""
|
||||||
exitCode := int32(0)
|
exitCode := int32(0)
|
||||||
var reason, message string
|
var reason, message string
|
||||||
|
|
||||||
|
@ -17,10 +17,9 @@ limitations under the License.
|
|||||||
package dockershim
|
package dockershim
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This file implements methods in ImageManagerService.
|
// This file implements methods in ImageManagerService.
|
||||||
@ -41,7 +40,7 @@ func (ds *dockerService) ListImages(filter *runtimeApi.ImageFilter) ([]*runtimeA
|
|||||||
|
|
||||||
result := []*runtimeApi.Image{}
|
result := []*runtimeApi.Image{}
|
||||||
for _, i := range images {
|
for _, i := range images {
|
||||||
apiImage, err := toRuntimeAPIImage(&i)
|
apiImage, err := imageToRuntimeAPIImage(&i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: log an error message?
|
// TODO: log an error message?
|
||||||
continue
|
continue
|
||||||
@ -51,16 +50,16 @@ func (ds *dockerService) ListImages(filter *runtimeApi.ImageFilter) ([]*runtimeA
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageStatus returns the status of the image.
|
// ImageStatus returns the status of the image, returns nil if the image doesn't present.
|
||||||
func (ds *dockerService) ImageStatus(image *runtimeApi.ImageSpec) (*runtimeApi.Image, error) {
|
func (ds *dockerService) ImageStatus(image *runtimeApi.ImageSpec) (*runtimeApi.Image, error) {
|
||||||
images, err := ds.ListImages(&runtimeApi.ImageFilter{Image: image})
|
imageInspect, err := ds.client.InspectImageByRef(image.GetImage())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if dockertools.IsImageNotFoundError(err) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(images) != 1 {
|
return imageInspectToRuntimeAPIImage(imageInspect)
|
||||||
return nil, fmt.Errorf("ImageStatus returned more than one image: %+v", images)
|
|
||||||
}
|
|
||||||
return images[0], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PullImage pulls an image with authentication config.
|
// PullImage pulls an image with authentication config.
|
||||||
@ -79,6 +78,19 @@ func (ds *dockerService) PullImage(image *runtimeApi.ImageSpec, auth *runtimeApi
|
|||||||
|
|
||||||
// RemoveImage removes the image.
|
// RemoveImage removes the image.
|
||||||
func (ds *dockerService) RemoveImage(image *runtimeApi.ImageSpec) error {
|
func (ds *dockerService) RemoveImage(image *runtimeApi.ImageSpec) error {
|
||||||
_, err := ds.client.RemoveImage(image.GetImage(), dockertypes.ImageRemoveOptions{PruneChildren: true})
|
// If the image has multiple tags, we need to remove all the tags
|
||||||
|
// TODO: We assume image.Image is image ID here, which is true in the current implementation
|
||||||
|
// of kubelet, but we should still clarify this in CRI.
|
||||||
|
imageInspect, err := ds.client.InspectImageByID(image.GetImage())
|
||||||
|
if err == nil && imageInspect != nil && len(imageInspect.RepoTags) > 1 {
|
||||||
|
for _, tag := range imageInspect.RepoTags {
|
||||||
|
if _, err := ds.client.RemoveImage(tag, dockertypes.ImageRemoveOptions{PruneChildren: true}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = ds.client.RemoveImage(image.GetImage(), dockertypes.ImageRemoveOptions{PruneChildren: true})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
45
pkg/kubelet/dockershim/docker_image_test.go
Normal file
45
pkg/kubelet/dockershim/docker_image_test.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 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 dockershim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
dockertypes "github.com/docker/engine-api/types"
|
||||||
|
|
||||||
|
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/kubelet/dockertools"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRemoveImage(t *testing.T) {
|
||||||
|
ds, fakeDocker, _ := newTestDockerService()
|
||||||
|
id := "1111"
|
||||||
|
fakeDocker.Image = &dockertypes.ImageInspect{ID: id, RepoTags: []string{"foo"}}
|
||||||
|
ds.RemoveImage(&runtimeApi.ImageSpec{Image: &id})
|
||||||
|
fakeDocker.AssertCallDetails(dockertools.NewCalledDetail("inspect_image", nil),
|
||||||
|
dockertools.NewCalledDetail("remove_image", []interface{}{id, dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemoveImageWithMultipleTags(t *testing.T) {
|
||||||
|
ds, fakeDocker, _ := newTestDockerService()
|
||||||
|
id := "1111"
|
||||||
|
fakeDocker.Image = &dockertypes.ImageInspect{ID: id, RepoTags: []string{"foo", "bar"}}
|
||||||
|
ds.RemoveImage(&runtimeApi.ImageSpec{Image: &id})
|
||||||
|
fakeDocker.AssertCallDetails(dockertools.NewCalledDetail("inspect_image", nil),
|
||||||
|
dockertools.NewCalledDetail("remove_image", []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}),
|
||||||
|
dockertools.NewCalledDetail("remove_image", []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
||||||
|
}
|
@ -22,6 +22,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
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/leaky"
|
"k8s.io/kubernetes/pkg/kubelet/leaky"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,6 +49,10 @@ const (
|
|||||||
sandboxContainerName = leaky.PodInfraContainerName
|
sandboxContainerName = leaky.PodInfraContainerName
|
||||||
// Delimiter used to construct docker container names.
|
// Delimiter used to construct docker container names.
|
||||||
nameDelimiter = "_"
|
nameDelimiter = "_"
|
||||||
|
// DockerImageIDPrefix is the prefix of image id in container status.
|
||||||
|
DockerImageIDPrefix = dockertools.DockerPrefix
|
||||||
|
// DockerPullableImageIDPrefix is the prefix of pullable image id in container status.
|
||||||
|
DockerPullableImageIDPrefix = dockertools.DockerPullablePrefix
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeSandboxName(s *runtimeApi.PodSandboxConfig) string {
|
func makeSandboxName(s *runtimeApi.PodSandboxConfig) string {
|
||||||
|
@ -401,7 +401,7 @@ func (dm *DockerManager) inspectContainer(id string, podName, podNamespace strin
|
|||||||
imageID := DockerPrefix + iResult.Image
|
imageID := DockerPrefix + iResult.Image
|
||||||
imgInspectResult, err := dm.client.InspectImageByID(iResult.Image)
|
imgInspectResult, err := dm.client.InspectImageByID(iResult.Image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(fmt.Errorf("unable to inspect docker image %q while inspecting docker container %q: %v", containerName, iResult.Image, err))
|
utilruntime.HandleError(fmt.Errorf("unable to inspect docker image %q while inspecting docker container %q: %v", iResult.Image, containerName, err))
|
||||||
} else {
|
} else {
|
||||||
if len(imgInspectResult.RepoDigests) > 1 {
|
if len(imgInspectResult.RepoDigests) > 1 {
|
||||||
glog.V(4).Infof("Container %q had more than one associated RepoDigest (%v), only using the first", containerName, imgInspectResult.RepoDigests)
|
glog.V(4).Infof("Container %q had more than one associated RepoDigest (%v), only using the first", containerName, imgInspectResult.RepoDigests)
|
||||||
|
@ -425,17 +425,17 @@ func TestDeleteImage(t *testing.T) {
|
|||||||
manager, fakeDocker := newTestDockerManager()
|
manager, fakeDocker := newTestDockerManager()
|
||||||
fakeDocker.Image = &dockertypes.ImageInspect{ID: "1111", RepoTags: []string{"foo"}}
|
fakeDocker.Image = &dockertypes.ImageInspect{ID: "1111", RepoTags: []string{"foo"}}
|
||||||
manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
|
manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
|
||||||
fakeDocker.AssertCallDetails([]calledDetail{{name: "inspect_image"}, {name: "remove_image",
|
fakeDocker.AssertCallDetails(NewCalledDetail("inspect_image", nil), NewCalledDetail("remove_image",
|
||||||
arguments: []interface{}{"1111", dockertypes.ImageRemoveOptions{PruneChildren: true}}}})
|
[]interface{}{"1111", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteImageWithMultipleTags(t *testing.T) {
|
func TestDeleteImageWithMultipleTags(t *testing.T) {
|
||||||
manager, fakeDocker := newTestDockerManager()
|
manager, fakeDocker := newTestDockerManager()
|
||||||
fakeDocker.Image = &dockertypes.ImageInspect{ID: "1111", RepoTags: []string{"foo", "bar"}}
|
fakeDocker.Image = &dockertypes.ImageInspect{ID: "1111", RepoTags: []string{"foo", "bar"}}
|
||||||
manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
|
manager.RemoveImage(kubecontainer.ImageSpec{Image: "1111"})
|
||||||
fakeDocker.AssertCallDetails([]calledDetail{{name: "inspect_image"},
|
fakeDocker.AssertCallDetails(NewCalledDetail("inspect_image", nil),
|
||||||
{name: "remove_image", arguments: []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}},
|
NewCalledDetail("remove_image", []interface{}{"foo", dockertypes.ImageRemoveOptions{PruneChildren: true}}),
|
||||||
{name: "remove_image", arguments: []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}}})
|
NewCalledDetail("remove_image", []interface{}{"bar", dockertypes.ImageRemoveOptions{PruneChildren: true}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKillContainerInPod(t *testing.T) {
|
func TestKillContainerInPod(t *testing.T) {
|
||||||
@ -1409,6 +1409,7 @@ func TestVerifyNonRoot(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"nil image in inspect": {
|
"nil image in inspect": {
|
||||||
container: &api.Container{},
|
container: &api.Container{},
|
||||||
|
inspectImage: nil,
|
||||||
expectedError: "unable to inspect image",
|
expectedError: "unable to inspect image",
|
||||||
},
|
},
|
||||||
"nil config in image inspect": {
|
"nil config in image inspect": {
|
||||||
|
@ -38,6 +38,11 @@ type calledDetail struct {
|
|||||||
arguments []interface{}
|
arguments []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCalledDetail create a new call detail item.
|
||||||
|
func NewCalledDetail(name string, arguments []interface{}) calledDetail {
|
||||||
|
return calledDetail{name: name, arguments: arguments}
|
||||||
|
}
|
||||||
|
|
||||||
// FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup.
|
// FakeDockerClient is a simple fake docker client, so that kubelet can be run for testing without requiring a real docker setup.
|
||||||
type FakeDockerClient struct {
|
type FakeDockerClient struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
@ -86,7 +91,6 @@ func newClientWithVersionAndClock(version, apiVersion string, c clock.Clock) *Fa
|
|||||||
Errors: make(map[string]error),
|
Errors: make(map[string]error),
|
||||||
ContainerMap: make(map[string]*dockertypes.ContainerJSON),
|
ContainerMap: make(map[string]*dockertypes.ContainerJSON),
|
||||||
Clock: c,
|
Clock: c,
|
||||||
|
|
||||||
// default this to an empty result, so that we never have a nil non-error response from InspectImage
|
// default this to an empty result, so that we never have a nil non-error response from InspectImage
|
||||||
Image: &dockertypes.ImageInspect{},
|
Image: &dockertypes.ImageInspect{},
|
||||||
}
|
}
|
||||||
@ -213,7 +217,7 @@ func (f *FakeDockerClient) AssertCalls(calls []string) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *FakeDockerClient) AssertCallDetails(calls []calledDetail) (err error) {
|
func (f *FakeDockerClient) AssertCallDetails(calls ...calledDetail) (err error) {
|
||||||
f.Lock()
|
f.Lock()
|
||||||
defer f.Unlock()
|
defer f.Unlock()
|
||||||
|
|
||||||
|
@ -626,3 +626,10 @@ type imageNotFoundError struct {
|
|||||||
func (e imageNotFoundError) Error() string {
|
func (e imageNotFoundError) Error() string {
|
||||||
return fmt.Sprintf("no such image: %q", e.ID)
|
return fmt.Sprintf("no such image: %q", e.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsImageNotFoundError checks whether the error is image not found error. This is exposed
|
||||||
|
// to share with dockershim.
|
||||||
|
func IsImageNotFoundError(err error) bool {
|
||||||
|
_, ok := err.(imageNotFoundError)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
@ -80,17 +80,12 @@ func (m *kubeGenericRuntimeManager) PullImage(image kubecontainer.ImageSpec, pul
|
|||||||
|
|
||||||
// IsImagePresent checks whether the container image is already in the local storage.
|
// IsImagePresent checks whether the container image is already in the local storage.
|
||||||
func (m *kubeGenericRuntimeManager) IsImagePresent(image kubecontainer.ImageSpec) (bool, error) {
|
func (m *kubeGenericRuntimeManager) IsImagePresent(image kubecontainer.ImageSpec) (bool, error) {
|
||||||
images, err := m.imageService.ListImages(&runtimeApi.ImageFilter{
|
status, err := m.imageService.ImageStatus(&runtimeApi.ImageSpec{Image: &image.Image})
|
||||||
Image: &runtimeApi.ImageSpec{
|
|
||||||
Image: &image.Image,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("ListImages failed: %v", err)
|
glog.Errorf("ImageStatus for image %q failed: %v", image, err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
return status != nil, nil
|
||||||
return len(images) > 0, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListImages gets all images currently on the machine.
|
// ListImages gets all images currently on the machine.
|
||||||
|
Loading…
Reference in New Issue
Block a user