Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up dockertools/manager.go and add more unit tests #7533

Merged
merged 1 commit into from
Apr 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 74 additions & 20 deletions pkg/kubelet/dockertools/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,67 @@ func makeCapabilites(capAdd []api.CapabilityType, capDrop []api.CapabilityType)
return addCaps, dropCaps
}

// A helper function to get the KubeletContainerName and hash from a docker
// container.
func getDockerContainerNameInfo(c *docker.APIContainers) (*KubeletContainerName, uint64, error) {
if len(c.Names) == 0 {
return nil, 0, fmt.Errorf("cannot parse empty docker container name: %#v", c.Names)
}
dockerName, hash, err := ParseDockerName(c.Names[0])
if err != nil {
return nil, 0, fmt.Errorf("parse docker container name %q error: %v", c.Names[0], err)
}
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)
if err != nil {
return types.UID(""), "", "", err
}
name, namespace, err := kubecontainer.ParsePodFullName(dockerName.PodFullName)
if err != nil {
return types.UID(""), "", "", fmt.Errorf("parse pod full name %q error: %v", dockerName.PodFullName, err)
}
return dockerName.PodUID, name, namespace, nil
}

// GetContainers returns a list of running containers if |all| is false;
// otherwise, it returns all containers.
func (dm *DockerManager) GetContainers(all bool) ([]*kubecontainer.Container, error) {
containers, err := GetKubeletDockerContainers(dm.client, all)
if err != nil {
return nil, err
}
// Convert DockerContainers to []*kubecontainer.Container
result := make([]*kubecontainer.Container, 0, len(containers))
for _, c := range containers {
converted, err := convertDockerToRuntimeContainer(c)
if err != nil {
glog.Errorf("Error examining the container: %v", err)
continue
}
result = append(result, converted)
}
return result, nil
}

func (dm *DockerManager) GetPods(all bool) ([]*kubecontainer.Pod, error) {
pods := make(map[types.UID]*kubecontainer.Pod)
var result []*kubecontainer.Pod
Expand All @@ -638,35 +699,28 @@ func (dm *DockerManager) GetPods(all bool) ([]*kubecontainer.Pod, error) {

// Group containers by pod.
for _, c := range containers {
if len(c.Names) == 0 {
glog.Warningf("Cannot parse empty docker container name: %#v", c.Names)
converted, err := convertDockerToRuntimeContainer(c)
if err != nil {
glog.Errorf("Error examining the container: %v", err)
continue
}
dockerName, hash, err := ParseDockerName(c.Names[0])

podUID, podName, podNamespace, err := getPodInfoFromContainer(c)
if err != nil {
glog.Warningf("Parse docker container name %q error: %v", c.Names[0], err)
glog.Errorf("Error examining the container: %v", err)
continue
}
pod, found := pods[dockerName.PodUID]

pod, found := pods[podUID]
if !found {
name, namespace, err := kubecontainer.ParsePodFullName(dockerName.PodFullName)
if err != nil {
glog.Warningf("Parse pod full name %q error: %v", dockerName.PodFullName, err)
continue
}
pod = &kubecontainer.Pod{
ID: dockerName.PodUID,
Name: name,
Namespace: namespace,
ID: podUID,
Name: podName,
Namespace: podNamespace,
}
pods[dockerName.PodUID] = pod
pods[podUID] = pod
}
pod.Containers = append(pod.Containers, &kubecontainer.Container{
ID: types.UID(c.ID),
Name: dockerName.ContainerName,
Hash: hash,
Created: c.Created,
})
pod.Containers = append(pod.Containers, converted)
}

// Convert map to list.
Expand Down
127 changes: 127 additions & 0 deletions pkg/kubelet/dockertools/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,40 @@ limitations under the License.
package dockertools

import (
"reflect"
"sort"
"testing"

"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/record"
kubecontainer "github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/container"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubelet/network"
"github.com/GoogleCloudPlatform/kubernetes/pkg/types"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/fsouza/go-dockerclient"
)

func NewFakeDockerManager() (*DockerManager, *FakeDockerClient) {
fakeDocker := &FakeDockerClient{Errors: make(map[string]error), RemovedImages: util.StringSet{}}
fakeRecorder := &record.FakeRecorder{}
readinessManager := kubecontainer.NewReadinessManager()
containerRefManager := kubecontainer.NewRefManager()
networkPlugin, _ := network.InitNetworkPlugin([]network.NetworkPlugin{}, "", network.NewFakeHost(nil))

dockerManager := NewDockerManager(
fakeDocker,
fakeRecorder,
readinessManager,
containerRefManager,
PodInfraContainerImage,
0, 0, "",
kubecontainer.FakeOS{},
networkPlugin,
nil)

return dockerManager, fakeDocker
}

func TestSetEntrypointAndCommand(t *testing.T) {
cases := []struct {
name string
Expand Down Expand Up @@ -87,3 +115,102 @@ 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) {
return false
}

// Sort the containers within a pod.
for i := range a {
sort.Sort(containersByID(a[i].Containers))
}
for i := range b {
sort.Sort(containersByID(b[i].Containers))
}

// Sort the pods by UID.
sort.Sort(podsByID(a))
sort.Sort(podsByID(b))

return reflect.DeepEqual(a, b)
}

func TestGetPods(t *testing.T) {
manager, fakeDocker := NewFakeDockerManager()
dockerContainers := []docker.APIContainers{
{
ID: "1111",
Names: []string{"/k8s_foo_qux_new_1234_42"},
},
{
ID: "2222",
Names: []string{"/k8s_bar_qux_new_1234_42"},
},
{
ID: "3333",
Names: []string{"/k8s_bar_jlk_wen_5678_42"},
},
}

// Convert the docker containers. This does not affect the test coverage
// because the conversion is tested separately in
// TestConvertDockerToRuntimeContainer.
containers := make([]*kubecontainer.Container, len(dockerContainers))
for i := range containers {
c, err := convertDockerToRuntimeContainer(&dockerContainers[i])
if err != nil {
t.Fatalf("unexpected error %v", err)
}
containers[i] = c
}

expected := []*kubecontainer.Pod{
{
ID: types.UID("1234"),
Name: "qux",
Namespace: "new",
Containers: []*kubecontainer.Container{containers[0], containers[1]},
},
{
ID: types.UID("5678"),
Name: "jlk",
Namespace: "wen",
Containers: []*kubecontainer.Container{containers[2]},
},
}

fakeDocker.ContainerList = dockerContainers
actual, err := manager.GetPods(false)
if err != nil {
t.Fatalf("unexpected error %v", err)
}
if !verifyPods(expected, actual) {
t.Errorf("expected %#v, got %#v", expected, actual)
}
}