From 27ca7dc71eff2b3b1abf7374e4e22ee38ed1ca59 Mon Sep 17 00:00:00 2001 From: harry zhang Date: Wed, 2 Dec 2015 16:53:56 +0800 Subject: [PATCH] Expose image list in node status Change image manager to use repotag --- pkg/api/types.go | 10 ++++ pkg/api/v1/types.go | 11 +++++ pkg/kubelet/container/runtime.go | 2 +- pkg/kubelet/dockertools/convert.go | 6 +-- pkg/kubelet/dockertools/convert_test.go | 6 +-- pkg/kubelet/image_manager.go | 14 +++++- pkg/kubelet/image_manager_test.go | 6 +-- pkg/kubelet/kubelet.go | 19 ++++++++ pkg/kubelet/kubelet_test.go | 63 +++++++++++++++++++++++++ pkg/kubelet/rkt/image.go | 4 +- pkg/kubelet/rkt/rkt_test.go | 12 ++--- 11 files changed, 134 insertions(+), 19 deletions(-) diff --git a/pkg/api/types.go b/pkg/api/types.go index 744a498c547..bb81f2f9510 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -1544,6 +1544,16 @@ type NodeStatus struct { DaemonEndpoints NodeDaemonEndpoints `json:"daemonEndpoints,omitempty"` // Set of ids/uuids to uniquely identify the node. NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty"` + // List of container images on this node + Images []ContainerImage `json:"images",omitempty` +} + +// Describe a container image +type ContainerImage struct { + // Names by which this image is known. + RepoTags []string `json:"repoTags"` + // The size of the image in bytes. + Size int64 `json:"size,omitempty"` } type NodePhase string diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index 6f8e10034d4..cdc8dce9b38 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -1911,6 +1911,17 @@ type NodeStatus struct { // Set of ids/uuids to uniquely identify the node. // More info: http://releases.k8s.io/HEAD/docs/admin/node.md#node-info NodeInfo NodeSystemInfo `json:"nodeInfo,omitempty"` + // List of container images on this node + Images []ContainerImage `json:"images",omitempty` +} + +// Describe a container image +type ContainerImage struct { + // Names by which this image is known. + // e.g. ["gcr.io/google_containers/hyperkube:v1.0.7", "dockerhub.io/google_containers/hyperkube:v1.0.7"] + RepoTags []string `json:"repoTags"` + // The size of the image in bytes. + Size int64 `json:"size,omitempty"` } type NodePhase string diff --git a/pkg/kubelet/container/runtime.go b/pkg/kubelet/container/runtime.go index bc8a3b36a8d..e75a1021822 100644 --- a/pkg/kubelet/container/runtime.go +++ b/pkg/kubelet/container/runtime.go @@ -319,7 +319,7 @@ type Image struct { // ID of the image. ID string // Other names by which this image is known. - Tags []string + RepoTags []string // The size of the image in bytes. Size int64 } diff --git a/pkg/kubelet/dockertools/convert.go b/pkg/kubelet/dockertools/convert.go index b3d69d41b8a..f5cfd3f9623 100644 --- a/pkg/kubelet/dockertools/convert.go +++ b/pkg/kubelet/dockertools/convert.go @@ -75,9 +75,9 @@ func toRuntimeImage(image *docker.APIImages) (*kubecontainer.Image, error) { } return &kubecontainer.Image{ - ID: image.ID, - Tags: image.RepoTags, - Size: image.VirtualSize, + ID: image.ID, + RepoTags: image.RepoTags, + Size: image.VirtualSize, }, nil } diff --git a/pkg/kubelet/dockertools/convert_test.go b/pkg/kubelet/dockertools/convert_test.go index 7d1a0b029bd..793f7f47677 100644 --- a/pkg/kubelet/dockertools/convert_test.go +++ b/pkg/kubelet/dockertools/convert_test.go @@ -75,9 +75,9 @@ func TestToRuntimeImage(t *testing.T) { VirtualSize: 1234, } expected := &kubecontainer.Image{ - ID: "aeeea", - Tags: []string{"abc", "def"}, - Size: 1234, + ID: "aeeea", + RepoTags: []string{"abc", "def"}, + Size: 1234, } actual, err := toRuntimeImage(original) diff --git a/pkg/kubelet/image_manager.go b/pkg/kubelet/image_manager.go index ab356d1b290..cb8e6bfd190 100644 --- a/pkg/kubelet/image_manager.go +++ b/pkg/kubelet/image_manager.go @@ -27,6 +27,7 @@ import ( "k8s.io/kubernetes/pkg/client/record" "k8s.io/kubernetes/pkg/kubelet/cadvisor" "k8s.io/kubernetes/pkg/kubelet/container" + kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" "k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util/sets" ) @@ -42,6 +43,8 @@ type imageManager interface { // Start async garbage collection of images. Start() error + GetImageList() ([]kubecontainer.Image, error) + // TODO(vmarmol): Have this subsume pulls as well. } @@ -135,6 +138,15 @@ func (im *realImageManager) Start() error { return nil } +// Get a list of images on this node +func (im *realImageManager) GetImageList() ([]kubecontainer.Image, error) { + images, err := im.runtime.ListImages() + if err != nil { + return nil, err + } + return images, nil +} + func (im *realImageManager) detectImages(detected time.Time) error { images, err := im.runtime.ListImages() if err != nil { @@ -298,7 +310,7 @@ func isImageUsed(image container.Image, imagesInUse sets.String) bool { if _, ok := imagesInUse[image.ID]; ok { return true } - for _, tag := range image.Tags { + for _, tag := range image.RepoTags { if _, ok := imagesInUse[tag]; ok { return true } diff --git a/pkg/kubelet/image_manager_test.go b/pkg/kubelet/image_manager_test.go index 73a19678546..abd21a26462 100644 --- a/pkg/kubelet/image_manager_test.go +++ b/pkg/kubelet/image_manager_test.go @@ -312,9 +312,9 @@ func TestFreeSpaceImagesAlsoDoesLookupByRepoTags(t *testing.T) { fakeRuntime.ImageList = []container.Image{ makeImage(0, 1024), { - ID: "5678", - Tags: []string{"potato", "salad"}, - Size: 2048, + ID: "5678", + RepoTags: []string{"potato", "salad"}, + Size: 2048, }, } fakeRuntime.AllPodList = []*container.Pod{ diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index fadebd93826..dff6a3d8134 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -2818,11 +2818,30 @@ func (kl *Kubelet) setNodeStatusDaemonEndpoints(node *api.Node) { node.Status.DaemonEndpoints = *kl.daemonEndpoints } +// Set images list fot this node +func (kl *Kubelet) setNodeStatusImages(node *api.Node) { + // Update image list of this node + var imagesOnNode []api.ContainerImage + containerImages, err := kl.imageManager.GetImageList() + if err != nil { + glog.Errorf("Error getting image list: %v", err) + } else { + for _, image := range containerImages { + imagesOnNode = append(imagesOnNode, api.ContainerImage{ + RepoTags: image.RepoTags, + Size: image.Size, + }) + } + } + node.Status.Images = imagesOnNode +} + // Set status for the node. func (kl *Kubelet) setNodeStatusInfo(node *api.Node) { kl.setNodeStatusMachineInfo(node) kl.setNodeStatusVersionInfo(node) kl.setNodeStatusDaemonEndpoints(node) + kl.setNodeStatusImages(node) } // Set Readycondition for the node. diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 4cf4ec15dd8..83f29247084 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -91,6 +91,18 @@ type TestKubelet struct { func newTestKubelet(t *testing.T) *TestKubelet { fakeRuntime := &kubecontainer.FakeRuntime{} fakeRuntime.VersionInfo = "1.15" + fakeRuntime.ImageList = []kubecontainer.Image{ + { + ID: "abc", + RepoTags: []string{"gcr.io/google_containers:v1", "gcr.io/google_containers:v2"}, + Size: 123, + }, + { + ID: "efg", + RepoTags: []string{"gcr.io/google_containers:v3", "gcr.io/google_containers:v4"}, + Size: 456, + }, + } fakeRecorder := &record.FakeRecorder{} fakeKubeClient := &testclient.Fake{} kubelet := &Kubelet{} @@ -144,6 +156,17 @@ func newTestKubelet(t *testing.T) *TestKubelet { kubelet.volumeManager = newVolumeManager() kubelet.containerManager = cm.NewStubContainerManager() + fakeNodeRef := &api.ObjectReference{ + Kind: "Node", + Name: testKubeletHostname, + UID: types.UID(testKubeletHostname), + Namespace: "", + } + fakeImageGCPolicy := ImageGCPolicy{ + HighThresholdPercent: 90, + LowThresholdPercent: 80, + } + kubelet.imageManager, err = newImageManager(fakeRuntime, mockCadvisor, fakeRecorder, fakeNodeRef, fakeImageGCPolicy) fakeClock := &util.FakeClock{Time: time.Now()} kubelet.backOff = util.NewBackOff(time.Second, time.Minute) kubelet.backOff.Clock = fakeClock @@ -2557,6 +2580,16 @@ func TestUpdateNewNodeStatus(t *testing.T) { {Type: api.NodeLegacyHostIP, Address: "127.0.0.1"}, {Type: api.NodeInternalIP, Address: "127.0.0.1"}, }, + Images: []api.ContainerImage{ + { + RepoTags: []string{"gcr.io/google_containers:v1", "gcr.io/google_containers:v2"}, + Size: 123, + }, + { + RepoTags: []string{"gcr.io/google_containers:v3", "gcr.io/google_containers:v4"}, + Size: 456, + }, + }, }, } @@ -2745,6 +2778,16 @@ func testDockerRuntimeVersion(t *testing.T) { {Type: api.NodeLegacyHostIP, Address: "127.0.0.1"}, {Type: api.NodeInternalIP, Address: "127.0.0.1"}, }, + Images: []api.ContainerImage{ + { + RepoTags: []string{"gcr.io/google_containers:v1", "gcr.io/google_containers:v2"}, + Size: 123, + }, + { + RepoTags: []string{"gcr.io/google_containers:v3", "gcr.io/google_containers:v4"}, + Size: 456, + }, + }, }, } @@ -2905,6 +2948,16 @@ func TestUpdateExistingNodeStatus(t *testing.T) { {Type: api.NodeLegacyHostIP, Address: "127.0.0.1"}, {Type: api.NodeInternalIP, Address: "127.0.0.1"}, }, + Images: []api.ContainerImage{ + { + RepoTags: []string{"gcr.io/google_containers:v1", "gcr.io/google_containers:v2"}, + Size: 123, + }, + { + RepoTags: []string{"gcr.io/google_containers:v3", "gcr.io/google_containers:v4"}, + Size: 456, + }, + }, }, } @@ -3173,6 +3226,16 @@ func TestUpdateNodeStatusWithoutContainerRuntime(t *testing.T) { {Type: api.NodeLegacyHostIP, Address: "127.0.0.1"}, {Type: api.NodeInternalIP, Address: "127.0.0.1"}, }, + Images: []api.ContainerImage{ + { + RepoTags: []string{"gcr.io/google_containers:v1", "gcr.io/google_containers:v2"}, + Size: 123, + }, + { + RepoTags: []string{"gcr.io/google_containers:v3", "gcr.io/google_containers:v4"}, + Size: 456, + }, + }, }, } kubelet.runtimeState = newRuntimeState(time.Duration(0), false, "" /* Pod CIDR */, func() error { return nil }) diff --git a/pkg/kubelet/rkt/image.go b/pkg/kubelet/rkt/image.go index 3257d948479..54e5ff231e5 100644 --- a/pkg/kubelet/rkt/image.go +++ b/pkg/kubelet/rkt/image.go @@ -86,8 +86,8 @@ func (r *Runtime) ListImages() ([]kubecontainer.Image, error) { images := make([]kubecontainer.Image, len(listResp.Images)) for i, image := range listResp.Images { images[i] = kubecontainer.Image{ - ID: image.Id, - Tags: []string{buildImageName(image)}, + ID: image.Id, + RepoTags: []string{buildImageName(image)}, //TODO: fill in the size of the image } } diff --git a/pkg/kubelet/rkt/rkt_test.go b/pkg/kubelet/rkt/rkt_test.go index 3eca21e41bc..2be0f976ecb 100644 --- a/pkg/kubelet/rkt/rkt_test.go +++ b/pkg/kubelet/rkt/rkt_test.go @@ -283,8 +283,8 @@ func TestListImages(t *testing.T) { }, []kubecontainer.Image{ { - ID: "sha512-a2fb8f390702", - Tags: []string{"quay.io/coreos/alpine-sh:latest"}, + ID: "sha512-a2fb8f390702", + RepoTags: []string{"quay.io/coreos/alpine-sh:latest"}, }, }, }, @@ -303,12 +303,12 @@ func TestListImages(t *testing.T) { }, []kubecontainer.Image{ { - ID: "sha512-a2fb8f390702", - Tags: []string{"quay.io/coreos/alpine-sh:latest"}, + ID: "sha512-a2fb8f390702", + RepoTags: []string{"quay.io/coreos/alpine-sh:latest"}, }, { - ID: "sha512-c6b597f42816", - Tags: []string{"coreos.com/rkt/stage1-coreos:0.10.0"}, + ID: "sha512-c6b597f42816", + RepoTags: []string{"coreos.com/rkt/stage1-coreos:0.10.0"}, }, }, },