mirror of https://github.com/k3s-io/k3s
Add image-related methods to DockerManager
This change is part of the efforts to make DockerManager implement the Runtime interface. The change also modifies the interface slightly to work with existing code, and aggregates the type converting functions to convert.go.pull/6/head
parent
2d37650c65
commit
83c599e4d4
|
@ -54,18 +54,18 @@ type Runtime interface {
|
|||
KillContainerInPod(api.Container, *api.Pod) error
|
||||
// GetPodStatus retrieves the status of the pod, including the information of
|
||||
// all containers in the pod.
|
||||
GetPodStatus(*api.Pod) (api.PodStatus, error)
|
||||
GetPodStatus(*api.Pod) (*api.PodStatus, error)
|
||||
// TODO(vmarmol): Merge RunInContainer and ExecInContainer.
|
||||
// Runs the command in the container of the specified pod using nsinit.
|
||||
// TODO(yifan): Use strong type for containerID.
|
||||
RunInContainer(containerID string, cmd []string) error
|
||||
RunInContainer(containerID string, cmd []string) ([]byte, error)
|
||||
// Runs the command in the container of the specified pod using nsenter.
|
||||
// Attaches the processes stdin, stdout, and stderr. Optionally uses a
|
||||
// tty.
|
||||
// TODO(yifan): Use strong type for containerID.
|
||||
ExecInContainer(containerID string, cmd []string, stdin io.Reader, stdout, stderr io.WriteCloser, tty bool) error
|
||||
// Forward the specified port from the specified pod to the stream.
|
||||
PortForward(pod Pod, port uint16, stream io.ReadWriteCloser) error
|
||||
PortForward(pod *Pod, port uint16, stream io.ReadWriteCloser) error
|
||||
// PullImage pulls an image from the network to local storage.
|
||||
PullImage(image string) error
|
||||
// IsImagePresent checks whether the container image is already in the local storage.
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
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 dockertools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
// This file contains helper functions to convert docker API types to runtime
|
||||
// (kubecontainer) types.
|
||||
|
||||
// Converts docker.APIContainers to kubecontainer.Container.
|
||||
func toRuntimeContainer(c *docker.APIContainers) (*kubecontainer.Container, error) {
|
||||
if c == nil {
|
||||
return nil, fmt.Errorf("unable to convert a nil pointer to a runtime container")
|
||||
}
|
||||
|
||||
dockerName, hash, err := getDockerContainerNameInfo(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &kubecontainer.Container{
|
||||
ID: types.UID(c.ID),
|
||||
Name: dockerName.ContainerName,
|
||||
Image: c.Image,
|
||||
Hash: hash,
|
||||
Created: c.Created,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Converts docker.APIImages to kubecontainer.Image.
|
||||
func toRuntimeImage(image *docker.APIImages) (*kubecontainer.Image, error) {
|
||||
if image == nil {
|
||||
return nil, fmt.Errorf("unable to convert a nil pointer to a runtime image")
|
||||
}
|
||||
|
||||
return &kubecontainer.Image{
|
||||
ID: image.ID,
|
||||
Tags: image.RepoTags,
|
||||
Size: image.Size,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
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 dockertools
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
func TestToRuntimeContainer(t *testing.T) {
|
||||
original := &docker.APIContainers{
|
||||
ID: "ab2cdf",
|
||||
Image: "bar_image",
|
||||
Created: 12345,
|
||||
Names: []string{"/k8s_bar.5678_foo_ns_1234_42"},
|
||||
}
|
||||
expected := &kubecontainer.Container{
|
||||
ID: types.UID("ab2cdf"),
|
||||
Name: "bar",
|
||||
Image: "bar_image",
|
||||
Hash: 0x5678,
|
||||
Created: 12345,
|
||||
}
|
||||
|
||||
actual, err := toRuntimeContainer(original)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected %#v, got %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestToRuntimeImage(t *testing.T) {
|
||||
original := &docker.APIImages{
|
||||
ID: "aeeea",
|
||||
RepoTags: []string{"abc", "def"},
|
||||
Size: 1234,
|
||||
}
|
||||
expected := &kubecontainer.Image{
|
||||
ID: "aeeea",
|
||||
Tags: []string{"abc", "def"},
|
||||
Size: 1234,
|
||||
}
|
||||
|
||||
actual, err := toRuntimeImage(original)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected %#v, got %#v", expected, actual)
|
||||
}
|
||||
}
|
|
@ -53,8 +53,8 @@ const (
|
|||
maxReasonCacheEntries = 200
|
||||
)
|
||||
|
||||
// TODO: Eventually DockerManager should implement kubecontainer.Runtime
|
||||
// interface.
|
||||
// TODO(yjhong): DockerManager should implement the Runtime interface.
|
||||
|
||||
type DockerManager struct {
|
||||
client DockerInterface
|
||||
recorder record.EventRecorder
|
||||
|
@ -640,21 +640,6 @@ func getDockerContainerNameInfo(c *docker.APIContainers) (*KubeletContainerName,
|
|||
return dockerName, hash, nil
|
||||
}
|
||||
|
||||
// Converts docker.APIContainers to kubecontainer.Container.
|
||||
func convertDockerToRuntimeContainer(c *docker.APIContainers) (*kubecontainer.Container, error) {
|
||||
dockerName, hash, err := getDockerContainerNameInfo(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &kubecontainer.Container{
|
||||
ID: types.UID(c.ID),
|
||||
Name: dockerName.ContainerName,
|
||||
Image: c.Image,
|
||||
Hash: hash,
|
||||
Created: c.Created,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Get pod UID, name, and namespace by examining the container names.
|
||||
func getPodInfoFromContainer(c *docker.APIContainers) (types.UID, string, string, error) {
|
||||
dockerName, _, err := getDockerContainerNameInfo(c)
|
||||
|
@ -678,7 +663,7 @@ func (dm *DockerManager) GetContainers(all bool) ([]*kubecontainer.Container, er
|
|||
// Convert DockerContainers to []*kubecontainer.Container
|
||||
result := make([]*kubecontainer.Container, 0, len(containers))
|
||||
for _, c := range containers {
|
||||
converted, err := convertDockerToRuntimeContainer(c)
|
||||
converted, err := toRuntimeContainer(c)
|
||||
if err != nil {
|
||||
glog.Errorf("Error examining the container: %v", err)
|
||||
continue
|
||||
|
@ -699,7 +684,7 @@ func (dm *DockerManager) GetPods(all bool) ([]*kubecontainer.Pod, error) {
|
|||
|
||||
// Group containers by pod.
|
||||
for _, c := range containers {
|
||||
converted, err := convertDockerToRuntimeContainer(c)
|
||||
converted, err := toRuntimeContainer(c)
|
||||
if err != nil {
|
||||
glog.Errorf("Error examining the container: %v", err)
|
||||
continue
|
||||
|
@ -730,14 +715,40 @@ func (dm *DockerManager) GetPods(all bool) ([]*kubecontainer.Pod, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (dm *DockerManager) Pull(image string) error {
|
||||
// List all images in the local storage.
|
||||
func (dm *DockerManager) ListImages() ([]kubecontainer.Image, error) {
|
||||
var images []kubecontainer.Image
|
||||
|
||||
dockerImages, err := dm.client.ListImages(docker.ListImagesOptions{})
|
||||
if err != nil {
|
||||
return images, err
|
||||
}
|
||||
|
||||
for _, di := range dockerImages {
|
||||
image, err := toRuntimeImage(&di)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
images = append(images, *image)
|
||||
}
|
||||
return images, nil
|
||||
}
|
||||
|
||||
// PullImage pulls an image from network to local storage.
|
||||
func (dm *DockerManager) PullImage(image string) error {
|
||||
return dm.Puller.Pull(image)
|
||||
}
|
||||
|
||||
// IsImagePresent checks whether the container image is already in the local storage.
|
||||
func (dm *DockerManager) IsImagePresent(image string) (bool, error) {
|
||||
return dm.Puller.IsImagePresent(image)
|
||||
}
|
||||
|
||||
// Removes the specified image.
|
||||
func (dm *DockerManager) RemoveImage(image string) error {
|
||||
return dm.client.RemoveImage(image)
|
||||
}
|
||||
|
||||
// podInfraContainerChanged returns true if the pod infra container has changed.
|
||||
func (dm *DockerManager) podInfraContainerChanged(pod *api.Pod, podInfraContainer *kubecontainer.Container) (bool, error) {
|
||||
networkMode := ""
|
||||
|
@ -1128,7 +1139,7 @@ func (dm *DockerManager) CreatePodInfraContainer(pod *api.Pod, generator kubecon
|
|||
return "", err
|
||||
}
|
||||
if !ok {
|
||||
if err := dm.Pull(container.Image); err != nil {
|
||||
if err := dm.PullImage(container.Image); err != nil {
|
||||
if ref != nil {
|
||||
dm.recorder.Eventf(ref, "failed", "Failed to pull image %q: %v", container.Image, err)
|
||||
}
|
||||
|
|
|
@ -116,30 +116,6 @@ func TestSetEntrypointAndCommand(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConvertDockerToRuntimeContainer(t *testing.T) {
|
||||
dockerContainer := &docker.APIContainers{
|
||||
ID: "ab2cdf",
|
||||
Image: "bar_image",
|
||||
Created: 12345,
|
||||
Names: []string{"/k8s_bar.5678_foo_ns_1234_42"},
|
||||
}
|
||||
expected := &kubecontainer.Container{
|
||||
ID: types.UID("ab2cdf"),
|
||||
Name: "bar",
|
||||
Image: "bar_image",
|
||||
Hash: 0x5678,
|
||||
Created: 12345,
|
||||
}
|
||||
|
||||
actual, err := convertDockerToRuntimeContainer(dockerContainer)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(expected, actual) {
|
||||
t.Errorf("expected %#v, got %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
// verifyPods returns true if the two pod slices are equal.
|
||||
func verifyPods(a, b []*kubecontainer.Pod) bool {
|
||||
if len(a) != len(b) {
|
||||
|
@ -179,11 +155,10 @@ func TestGetPods(t *testing.T) {
|
|||
}
|
||||
|
||||
// Convert the docker containers. This does not affect the test coverage
|
||||
// because the conversion is tested separately in
|
||||
// TestConvertDockerToRuntimeContainer.
|
||||
// because the conversion is tested separately in convert_test.go
|
||||
containers := make([]*kubecontainer.Container, len(dockerContainers))
|
||||
for i := range containers {
|
||||
c, err := convertDockerToRuntimeContainer(&dockerContainers[i])
|
||||
c, err := toRuntimeContainer(&dockerContainers[i])
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
@ -214,3 +189,24 @@ func TestGetPods(t *testing.T) {
|
|||
t.Errorf("expected %#v, got %#v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListImages(t *testing.T) {
|
||||
manager, fakeDocker := NewFakeDockerManager()
|
||||
dockerImages := []docker.APIImages{{ID: "1111"}, {ID: "2222"}, {ID: "3333"}}
|
||||
expected := util.NewStringSet([]string{"1111", "2222", "3333"}...)
|
||||
|
||||
fakeDocker.Images = dockerImages
|
||||
actualImages, err := manager.ListImages()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
actual := util.NewStringSet()
|
||||
for _, i := range actualImages {
|
||||
actual.Insert(i.ID)
|
||||
}
|
||||
// We can compare the two sets directly because util.StringSet.List()
|
||||
// returns a "sorted" list.
|
||||
if !reflect.DeepEqual(expected.List(), actual.List()) {
|
||||
t.Errorf("expected %#v, got %#v", expected.List(), actual.List())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -887,7 +887,7 @@ func (kl *Kubelet) pullImage(pod *api.Pod, container *api.Container) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
err = kl.containerManager.Pull(container.Image)
|
||||
err = kl.containerManager.PullImage(container.Image)
|
||||
kl.runtimeHooks.ReportImagePull(pod, container, err)
|
||||
return err
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue