diff --git a/pkg/kubelet/dockertools/manager.go b/pkg/kubelet/dockertools/manager.go index f1c3e8e5751..372db12efad 100644 --- a/pkg/kubelet/dockertools/manager.go +++ b/pkg/kubelet/dockertools/manager.go @@ -25,6 +25,7 @@ import ( "os" "os/exec" "path" + "sort" "strconv" "strings" "sync" @@ -470,7 +471,9 @@ func (dm *DockerManager) GetPodStatus(pod *api.Pod) (*api.PodStatus, error) { } podStatus.ContainerStatuses = append(podStatus.ContainerStatuses, *status) } - + // TODO: Move this to a custom equals method on the pod status. A container manager + // shouldn't have to guarantee order. + sort.Sort(kubeletTypes.SortedContainerStatuses(podStatus.ContainerStatuses)) return &podStatus, nil } diff --git a/pkg/kubelet/dockertools/manager_test.go b/pkg/kubelet/dockertools/manager_test.go index fd5ba06d0e2..061a8daa384 100644 --- a/pkg/kubelet/dockertools/manager_test.go +++ b/pkg/kubelet/dockertools/manager_test.go @@ -1992,3 +1992,61 @@ func TestSyncPodWithTerminationLog(t *testing.T) { t.Errorf("Unexpected container path: %s", parts[1]) } } + +func TestGetPodStatusSortedContainers(t *testing.T) { + dm, fakeDocker := newTestDockerManager() + dockerInspect := map[string]*docker.Container{} + dockerList := []docker.APIContainers{} + specContainerList := []api.Container{} + expectedOrder := []string{} + + numContainers := 10 + podName := "foo" + podNs := "test" + podUID := "uid1" + fakeConfig := &docker.Config{ + Image: "some:latest", + } + + for i := 0; i < numContainers; i++ { + id := fmt.Sprintf("%v", i) + containerName := fmt.Sprintf("%vcontainer", id) + expectedOrder = append(expectedOrder, containerName) + dockerInspect[id] = &docker.Container{ + ID: id, + Name: containerName, + Config: fakeConfig, + Image: fmt.Sprintf("%vimageid", id), + } + dockerList = append(dockerList, docker.APIContainers{ + ID: id, + Names: []string{fmt.Sprintf("/k8s_%v_%v_%v_%v_42", containerName, podName, podNs, podUID)}, + }) + specContainerList = append(specContainerList, api.Container{Name: containerName}) + } + + fakeDocker.ContainerMap = dockerInspect + fakeDocker.ContainerList = dockerList + fakeDocker.ClearCalls() + pod := &api.Pod{ + ObjectMeta: api.ObjectMeta{ + UID: types.UID(podUID), + Name: podName, + Namespace: podNs, + }, + Spec: api.PodSpec{ + Containers: specContainerList, + }, + } + for i := 0; i < 5; i++ { + status, err := dm.GetPodStatus(pod) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + for i, c := range status.ContainerStatuses { + if expectedOrder[i] != c.Name { + t.Fatalf("Container status not sorted, expected %v at index %d, but found %v", expectedOrder[i], i, c.Name) + } + } + } +} diff --git a/pkg/kubelet/types/types.go b/pkg/kubelet/types/types.go index 172c84ae1ab..55ba55c8397 100644 --- a/pkg/kubelet/types/types.go +++ b/pkg/kubelet/types/types.go @@ -19,8 +19,12 @@ package types import ( "net/http" "time" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" ) +// TODO: Reconcile custom types in kubelet/types and this subpackage + // DockerID is an ID of docker container. It is a type to make it clear when we're working with docker container Ids type DockerID string @@ -56,3 +60,13 @@ func (t *Timestamp) Get() time.Time { func (t *Timestamp) GetString() string { return t.time.Format(time.RFC3339Nano) } + +// A type to help sort container statuses based on container names. +type SortedContainerStatuses []api.ContainerStatus + +func (s SortedContainerStatuses) Len() int { return len(s) } +func (s SortedContainerStatuses) Swap(i, j int) { s[i], s[j] = s[j], s[i] } + +func (s SortedContainerStatuses) Less(i, j int) bool { + return s[i].Name < s[j].Name +}