mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	* Add docker pullable support.
* Fix inspect image bug. * Fix remove image bug.
This commit is contained in:
		@@ -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.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user