diff --git a/cmd/integration/integration.go b/cmd/integration/integration.go index 84c8c790f8..5ac214a6f8 100644 --- a/cmd/integration/integration.go +++ b/cmd/integration/integration.go @@ -95,12 +95,9 @@ func (fakeKubeletClient) GetPodStatus(host, podNamespace, podID string) (api.Pod return r, err } r.Status.PodIP = "1.2.3.4" - m := make(api.PodInfo) - for k, v := range r.Status.Info { - v.Ready = true - m[k] = v + for i := range r.Status.ContainerStatuses { + r.Status.ContainerStatuses[i].Ready = true } - r.Status.Info = m return r, nil } diff --git a/pkg/api/resource_helpers.go b/pkg/api/resource_helpers.go index e487d89545..7dff8b9412 100644 --- a/pkg/api/resource_helpers.go +++ b/pkg/api/resource_helpers.go @@ -40,3 +40,21 @@ func (self *ResourceList) Memory() *resource.Quantity { } return &resource.Quantity{} } + +func GetContainerStatus(statuses []ContainerStatus, name string) (ContainerStatus, bool) { + for i := range statuses { + if statuses[i].Name == name { + return statuses[i], true + } + } + return ContainerStatus{}, false +} + +func GetExistingContainerStatus(statuses []ContainerStatus, name string) ContainerStatus { + for i := range statuses { + if statuses[i].Name == name { + return statuses[i] + } + } + return ContainerStatus{} +} diff --git a/pkg/api/types.go b/pkg/api/types.go index 109bb6fc39..273e59ad09 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -593,6 +593,8 @@ type ContainerState struct { } type ContainerStatus struct { + // Each container in a pod must have a unique name. + Name string `name of the container; must be a DNS_LABEL and unique within the pod; cannot be updated"` // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states // defined for container? State ContainerState `json:"state,omitempty"` @@ -646,15 +648,12 @@ type PodCondition struct { Status ConditionStatus `json:"status"` } -// PodInfo contains one entry for every container with available info. -type PodInfo map[string]ContainerStatus - // PodContainerInfo is a wrapper for PodInfo that can be encode/decoded // DEPRECATED: Replaced with PodStatusResult type PodContainerInfo struct { TypeMeta `json:",inline"` ObjectMeta `json:"metadata,omitempty"` - ContainerInfo PodInfo `json:"containerInfo"` + ContainerInfo []ContainerStatus `json:"containerInfo"` } // RestartPolicy describes how the container should be restarted. @@ -726,13 +725,12 @@ type PodStatus struct { HostIP string `json:"hostIP,omitempty"` PodIP string `json:"podIP,omitempty"` - // The key of this map is the *name* of the container within the manifest; it has one - // entry per container in the manifest. The value of this map is currently the output - // of `docker inspect`. This output format is *not* final and should not be relied - // upon. + // The list has one entry per container in the manifest. Each entry is + // currently the output of `docker inspect`. This output format is *not* + // final and should not be relied upon. // TODO: Make real decisions about what our info should look like. Re-enable fuzz test // when we have done this. - Info PodInfo `json:"info,omitempty"` + ContainerStatuses []ContainerStatus `json:"containerStatuses,omitempty"` } // PodStatusResult is a wrapper for PodStatus returned by kubelet that can be encode/decoded diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index da18a18c14..b365b4c09a 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -188,7 +188,7 @@ func init() { if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { return err } - if err := s.Convert(&in.Info, &out.Info, 0); err != nil { + if err := s.Convert(&in.ContainerStatuses, &out.Info, 0); err != nil { return err } out.Message = in.Message @@ -204,7 +204,7 @@ func init() { if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { return err } - if err := s.Convert(&in.Info, &out.Info, 0); err != nil { + if err := s.Convert(&in.Info, &out.ContainerStatuses, 0); err != nil { return err } @@ -229,6 +229,78 @@ func init() { return nil }, + func(in *[]newer.ContainerStatus, out *PodInfo, s conversion.Scope) error { + *out = make(map[string]ContainerStatus) + for _, st := range *in { + v := ContainerStatus{} + if err := s.Convert(&st, &v, 0); err != nil { + return err + } + (*out)[st.Name] = v + } + return nil + }, + func(in *PodInfo, out *[]newer.ContainerStatus, s conversion.Scope) error { + for k, v := range *in { + st := newer.ContainerStatus{} + if err := s.Convert(&v, &st, 0); err != nil { + return err + } + st.Name = k + *out = append(*out, st) + } + return nil + }, + + func(in *newer.ContainerStatus, out *ContainerStatus, s conversion.Scope) error { + if err := s.Convert(&in.State, &out.State, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { + return err + } + if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil { + return err + } + if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil { + return err + } + if err := s.Convert(&in.Image, &out.Image, 0); err != nil { + return err + } + if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil { + return err + } + if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil { + return err + } + return nil + }, + func(in *ContainerStatus, out *newer.ContainerStatus, s conversion.Scope) error { + if err := s.Convert(&in.State, &out.State, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { + return err + } + if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil { + return err + } + if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil { + return err + } + if err := s.Convert(&in.Image, &out.Image, 0); err != nil { + return err + } + if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil { + return err + } + if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil { + return err + } + return nil + }, + // Convert all to the new PodPhase constants func(in *newer.PodPhase, out *PodStatus, s conversion.Scope) error { switch *in { diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index 89b5cd8057..33bf743231 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -484,7 +484,7 @@ func init() { if err := s.Convert(&in.Phase, &out.Status, 0); err != nil { return err } - if err := s.Convert(&in.Info, &out.Info, 0); err != nil { + if err := s.Convert(&in.ContainerStatuses, &out.Info, 0); err != nil { return err } if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { @@ -500,7 +500,7 @@ func init() { if err := s.Convert(&in.Status, &out.Phase, 0); err != nil { return err } - if err := s.Convert(&in.Info, &out.Info, 0); err != nil { + if err := s.Convert(&in.Info, &out.ContainerStatuses, 0); err != nil { return err } if err := s.Convert(&in.Conditions, &out.Conditions, 0); err != nil { @@ -513,6 +513,78 @@ func init() { return nil }, + func(in *[]newer.ContainerStatus, out *PodInfo, s conversion.Scope) error { + *out = make(map[string]ContainerStatus) + for _, st := range *in { + v := ContainerStatus{} + if err := s.Convert(&st, &v, 0); err != nil { + return err + } + (*out)[st.Name] = v + } + return nil + }, + func(in *PodInfo, out *[]newer.ContainerStatus, s conversion.Scope) error { + for k, v := range *in { + st := newer.ContainerStatus{} + if err := s.Convert(&v, &st, 0); err != nil { + return err + } + st.Name = k + *out = append(*out, st) + } + return nil + }, + + func(in *newer.ContainerStatus, out *ContainerStatus, s conversion.Scope) error { + if err := s.Convert(&in.State, &out.State, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { + return err + } + if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil { + return err + } + if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil { + return err + } + if err := s.Convert(&in.Image, &out.Image, 0); err != nil { + return err + } + if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil { + return err + } + if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil { + return err + } + return nil + }, + func(in *ContainerStatus, out *newer.ContainerStatus, s conversion.Scope) error { + if err := s.Convert(&in.State, &out.State, 0); err != nil { + return err + } + if err := s.Convert(&in.LastTerminationState, &out.LastTerminationState, 0); err != nil { + return err + } + if err := s.Convert(&in.Ready, &out.Ready, 0); err != nil { + return err + } + if err := s.Convert(&in.RestartCount, &out.RestartCount, 0); err != nil { + return err + } + if err := s.Convert(&in.Image, &out.Image, 0); err != nil { + return err + } + if err := s.Convert(&in.ImageID, &out.ImageID, 0); err != nil { + return err + } + if err := s.Convert(&in.ContainerID, &out.ContainerID, 0); err != nil { + return err + } + return nil + }, + func(in *newer.PodStatusResult, out *PodStatusResult, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err diff --git a/pkg/api/v1beta3/types.go b/pkg/api/v1beta3/types.go index 41b4be8991..ca8105bdcf 100644 --- a/pkg/api/v1beta3/types.go +++ b/pkg/api/v1beta3/types.go @@ -607,6 +607,8 @@ type ContainerState struct { } type ContainerStatus struct { + // Required: This must be a DNS_LABEL. Each container in a pod must have a unique name. + Name string `json:"name" description:"name of the container; must be a DNS_LABEL and unique within the pod; cannot be updated"` // TODO(dchen1107): Should we rename PodStatus to a more generic name or have a separate states // defined for container? State ContainerState `json:"state,omitempty" description:"details about the container's current condition"` @@ -663,9 +665,6 @@ type PodCondition struct { Status ConditionStatus `json:"status" description:"status of the condition, one of Full, None, Unknown"` } -// PodInfo contains one entry for every container with available info. -type PodInfo map[string]ContainerStatus - // RestartPolicy describes how the container should be restarted. // Only one of the following restart policies may be specified. // If none of the following policies is specified, the default one @@ -727,13 +726,12 @@ type PodStatus struct { HostIP string `json:"hostIP,omitempty" description:"IP address of the host to which the pod is assigned; empty if not yet scheduled"` PodIP string `json:"podIP,omitempty" description:"IP address allocated to the pod; routable at least within the cluster; empty if not yet allocated"` - // The key of this map is the *name* of the container within the manifest; it has one - // entry per container in the manifest. The value of this map is currently the output + // The list has one entry per container in the manifest. Each entry is currently the output // of `docker inspect`. This output format is *not* final and should not be relied // upon. // TODO: Make real decisions about what our info should look like. Re-enable fuzz test // when we have done this. - Info PodInfo `json:"info,omitempty" description:"map of container name to container status"` + ContainerStatuses []ContainerStatus `json:"containerStatuses,omitempty" description:"list of container statuses"` } // PodStatusResult is a wrapper for PodStatus returned by kubelet that can be encode/decoded diff --git a/pkg/client/kubelet_test.go b/pkg/client/kubelet_test.go index 41ad4b1ab3..98411bbfd9 100644 --- a/pkg/client/kubelet_test.go +++ b/pkg/client/kubelet_test.go @@ -33,9 +33,9 @@ import ( func TestHTTPKubeletClient(t *testing.T) { expectObj := api.PodStatusResult{ Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "myID1": {}, - "myID2": {}, + ContainerStatuses: []api.ContainerStatus{ + {Name: "myID1"}, + {Name: "myID2"}, }, }, } @@ -73,15 +73,17 @@ func TestHTTPKubeletClient(t *testing.T) { } // reflect.DeepEqual(expectObj, gotObj) doesn't handle blank times well - if len(gotObj.Status.Info) != len(expectObj.Status.Info) { + if len(gotObj.Status.ContainerStatuses) != len(expectObj.Status.ContainerStatuses) { t.Errorf("Unexpected response. Expected: %#v, received %#v", expectObj, gotObj) } } func TestHTTPKubeletClientNotFound(t *testing.T) { expectObj := api.PodContainerInfo{ - ContainerInfo: map[string]api.ContainerStatus{ - "myID": {}, + ContainerInfo: []api.ContainerStatus{ + { + Name: "myID", + }, }, } _, err := json.Marshal(expectObj) @@ -120,8 +122,10 @@ func TestHTTPKubeletClientNotFound(t *testing.T) { func TestHTTPKubeletClientError(t *testing.T) { expectObj := api.PodContainerInfo{ - ContainerInfo: map[string]api.ContainerStatus{ - "myID": {}, + ContainerInfo: []api.ContainerStatus{ + { + Name: "myID", + }, }, } _, err := json.Marshal(expectObj) diff --git a/pkg/kubectl/resource_printer_test.go b/pkg/kubectl/resource_printer_test.go index 208ab219c6..c5bd47d5dd 100644 --- a/pkg/kubectl/resource_printer_test.go +++ b/pkg/kubectl/resource_printer_test.go @@ -327,11 +327,15 @@ func TestTemplateStrings(t *testing.T) { expect string }{ "nilInfo": {api.Pod{}, "false"}, - "emptyInfo": {api.Pod{Status: api.PodStatus{Info: api.PodInfo{}}}, "false"}, + "emptyInfo": {api.Pod{Status: api.PodStatus{ContainerStatuses: []api.ContainerStatus{}}}, "false"}, "fooExists": { api.Pod{ Status: api.PodStatus{ - Info: api.PodInfo{"foo": api.ContainerStatus{}}, + ContainerStatuses: []api.ContainerStatus{ + { + Name: "foo", + }, + }, }, }, "false", @@ -339,7 +343,11 @@ func TestTemplateStrings(t *testing.T) { "barExists": { api.Pod{ Status: api.PodStatus{ - Info: api.PodInfo{"bar": api.ContainerStatus{}}, + ContainerStatuses: []api.ContainerStatus{ + { + Name: "bar", + }, + }, }, }, "false", @@ -347,9 +355,13 @@ func TestTemplateStrings(t *testing.T) { "bothExist": { api.Pod{ Status: api.PodStatus{ - Info: api.PodInfo{ - "foo": api.ContainerStatus{}, - "bar": api.ContainerStatus{}, + ContainerStatuses: []api.ContainerStatus{ + { + Name: "foo", + }, + { + Name: "bar", + }, }, }, }, @@ -358,9 +370,12 @@ func TestTemplateStrings(t *testing.T) { "oneValid": { api.Pod{ Status: api.PodStatus{ - Info: api.PodInfo{ - "foo": api.ContainerStatus{}, - "bar": api.ContainerStatus{ + ContainerStatuses: []api.ContainerStatus{ + { + Name: "foo", + }, + { + Name: "bar", State: api.ContainerState{ Running: &api.ContainerStateRunning{ StartedAt: util.Time{}, @@ -375,15 +390,17 @@ func TestTemplateStrings(t *testing.T) { "bothValid": { api.Pod{ Status: api.PodStatus{ - Info: api.PodInfo{ - "foo": api.ContainerStatus{ + ContainerStatuses: []api.ContainerStatus{ + { + Name: "foo", State: api.ContainerState{ Running: &api.ContainerStateRunning{ StartedAt: util.Time{}, }, }, }, - "bar": api.ContainerStatus{ + { + Name: "bar", State: api.ContainerState{ Running: &api.ContainerStateRunning{ StartedAt: util.Time{}, diff --git a/pkg/kubelet/dockertools/docker.go b/pkg/kubelet/dockertools/docker.go index 68edb4368b..8e3f5a99f8 100644 --- a/pkg/kubelet/dockertools/docker.go +++ b/pkg/kubelet/dockertools/docker.go @@ -558,6 +558,7 @@ func inspectContainer(client DockerInterface, dockerID, containerName, tPath str glog.V(3).Infof("Container inspect result: %+v", *inspectResult) result.status = api.ContainerStatus{ + Name: containerName, Image: inspectResult.Config.Image, ImageID: DockerPrefix + inspectResult.Image, ContainerID: DockerPrefix + dockerID, @@ -618,7 +619,7 @@ func inspectContainer(client DockerInterface, dockerID, containerName, tPath str // infrastructure container func GetDockerPodStatus(client DockerInterface, manifest api.PodSpec, podFullName string, uid types.UID) (*api.PodStatus, error) { var podStatus api.PodStatus - podStatus.Info = api.PodInfo{} + statuses := make(map[string]api.ContainerStatus) expectedContainers := make(map[string]api.Container) for _, container := range manifest.Containers { @@ -655,9 +656,9 @@ func GetDockerPodStatus(client DockerInterface, manifest api.PodSpec, podFullNam terminationMessagePath = c.TerminationMessagePath } // We assume docker return us a list of containers in time order - if containerStatus, found := podStatus.Info[dockerContainerName]; found { + if containerStatus, found := statuses[dockerContainerName]; found { containerStatus.RestartCount += 1 - podStatus.Info[dockerContainerName] = containerStatus + statuses[dockerContainerName] = containerStatus continue } @@ -670,20 +671,20 @@ func GetDockerPodStatus(client DockerInterface, manifest api.PodSpec, podFullNam // Found network container podStatus.PodIP = result.ip } else { - podStatus.Info[dockerContainerName] = result.status + statuses[dockerContainerName] = result.status } } - if len(podStatus.Info) == 0 && podStatus.PodIP == "" { + if len(statuses) == 0 && podStatus.PodIP == "" { return nil, ErrNoContainersInPod } // Not all containers expected are created, check if there are // image related issues - if len(podStatus.Info) < len(manifest.Containers) { + if len(statuses) < len(manifest.Containers) { var containerStatus api.ContainerStatus for _, container := range manifest.Containers { - if _, found := podStatus.Info[container.Name]; found { + if _, found := statuses[container.Name]; found { continue } @@ -705,10 +706,15 @@ func GetDockerPodStatus(client DockerInterface, manifest api.PodSpec, podFullNam } } - podStatus.Info[container.Name] = containerStatus + statuses[container.Name] = containerStatus } } + podStatus.ContainerStatuses = make([]api.ContainerStatus, 0) + for _, status := range statuses { + podStatus.ContainerStatuses = append(podStatus.ContainerStatuses, status) + } + return &podStatus, nil } diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index fb02f36621..efa748edb2 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -1770,15 +1770,14 @@ func (kl *Kubelet) validatePodPhase(podStatus *api.PodStatus) error { } func (kl *Kubelet) validateContainerStatus(podStatus *api.PodStatus, containerName string) (dockerID string, err error) { - for cName, cStatus := range podStatus.Info { - if containerName == cName { - if cStatus.State.Waiting != nil { - return "", fmt.Errorf("container %q is in waiting state.", containerName) - } - return strings.Replace(podStatus.Info[containerName].ContainerID, dockertools.DockerPrefix, "", 1), nil - } + cStatus, found := api.GetContainerStatus(podStatus.ContainerStatuses, containerName) + if !found { + return "", fmt.Errorf("container %q not found in pod", containerName) } - return "", fmt.Errorf("container %q not found in pod", containerName) + if cStatus.State.Waiting != nil { + return "", fmt.Errorf("container %q is in waiting state.", containerName) + } + return strings.Replace(cStatus.ContainerID, dockertools.DockerPrefix, "", 1), nil } // GetKubeletContainerLogs returns logs from the container @@ -1908,7 +1907,7 @@ func (kl *Kubelet) tryUpdateNodeStatus() error { } // getPhase returns the phase of a pod given its container info. -func getPhase(spec *api.PodSpec, info api.PodInfo) api.PodPhase { +func getPhase(spec *api.PodSpec, info []api.ContainerStatus) api.PodPhase { running := 0 waiting := 0 stopped := 0 @@ -1916,7 +1915,7 @@ func getPhase(spec *api.PodSpec, info api.PodInfo) api.PodPhase { succeeded := 0 unknown := 0 for _, container := range spec.Containers { - if containerStatus, ok := info[container.Name]; ok { + if containerStatus, ok := api.GetContainerStatus(info, container.Name); ok { if containerStatus.State.Running != nil { running++ } else if containerStatus.State.Termination != nil { @@ -1970,7 +1969,7 @@ func getPhase(spec *api.PodSpec, info api.PodInfo) api.PodPhase { } // getPodReadyCondition returns ready condition if all containers in a pod are ready, else it returns an unready condition. -func getPodReadyCondition(spec *api.PodSpec, info api.PodInfo) []api.PodCondition { +func getPodReadyCondition(spec *api.PodSpec, statuses []api.ContainerStatus) []api.PodCondition { ready := []api.PodCondition{{ Type: api.PodReady, Status: api.ConditionTrue, @@ -1979,11 +1978,11 @@ func getPodReadyCondition(spec *api.PodSpec, info api.PodInfo) []api.PodConditio Type: api.PodReady, Status: api.ConditionFalse, }} - if info == nil { + if statuses == nil { return unready } for _, container := range spec.Containers { - if containerStatus, ok := info[container.Name]; ok { + if containerStatus, ok := api.GetContainerStatus(statuses, container.Name); ok { if !containerStatus.Ready { return unready } @@ -2038,13 +2037,16 @@ func (kl *Kubelet) generatePodStatusByPod(pod *api.Pod) (api.PodStatus, error) { } // Assume info is ready to process - podStatus.Phase = getPhase(spec, podStatus.Info) + podStatus.Phase = getPhase(spec, podStatus.ContainerStatuses) for _, c := range spec.Containers { - containerStatus := podStatus.Info[c.Name] - containerStatus.Ready = kl.readiness.IsReady(containerStatus) - podStatus.Info[c.Name] = containerStatus + for i, st := range podStatus.ContainerStatuses { + if st.Name == c.Name { + podStatus.ContainerStatuses[i].Ready = kl.readiness.IsReady(st) + break + } + } } - podStatus.Conditions = append(podStatus.Conditions, getPodReadyCondition(spec, podStatus.Info)...) + podStatus.Conditions = append(podStatus.Conditions, getPodReadyCondition(spec, podStatus.ContainerStatuses)...) podStatus.Host = kl.GetHostname() hostIP, err := kl.GetHostIP() if err != nil { diff --git a/pkg/kubelet/kubelet_test.go b/pkg/kubelet/kubelet_test.go index 2ae292f729..bef220876f 100644 --- a/pkg/kubelet/kubelet_test.go +++ b/pkg/kubelet/kubelet_test.go @@ -2183,6 +2183,43 @@ func TestMakeEnvironmentVariables(t *testing.T) { } } +func runningState(cName string) api.ContainerStatus { + return api.ContainerStatus{ + Name: cName, + State: api.ContainerState{ + Running: &api.ContainerStateRunning{}, + }, + } +} +func stoppedState(cName string) api.ContainerStatus { + return api.ContainerStatus{ + Name: cName, + State: api.ContainerState{ + Termination: &api.ContainerStateTerminated{}, + }, + } +} +func succeededState(cName string) api.ContainerStatus { + return api.ContainerStatus{ + Name: cName, + State: api.ContainerState{ + Termination: &api.ContainerStateTerminated{ + ExitCode: 0, + }, + }, + } +} +func failedState(cName string) api.ContainerStatus { + return api.ContainerStatus{ + Name: cName, + State: api.ContainerState{ + Termination: &api.ContainerStateTerminated{ + ExitCode: -1, + }, + }, + } +} + func TestPodPhaseWithRestartAlways(t *testing.T) { desiredState := api.PodSpec{ Containers: []api.Container{ @@ -2194,16 +2231,6 @@ func TestPodPhaseWithRestartAlways(t *testing.T) { currentState := api.PodStatus{ Host: "machine", } - runningState := api.ContainerStatus{ - State: api.ContainerState{ - Running: &api.ContainerStateRunning{}, - }, - } - stoppedState := api.ContainerStatus{ - State: api.ContainerState{ - Termination: &api.ContainerStateTerminated{}, - }, - } tests := []struct { pod *api.Pod @@ -2215,9 +2242,9 @@ func TestPodPhaseWithRestartAlways(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, - "containerB": runningState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), + runningState("containerB"), }, Host: "machine", }, @@ -2229,9 +2256,9 @@ func TestPodPhaseWithRestartAlways(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": stoppedState, - "containerB": stoppedState, + ContainerStatuses: []api.ContainerStatus{ + stoppedState("containerA"), + stoppedState("containerB"), }, Host: "machine", }, @@ -2243,9 +2270,9 @@ func TestPodPhaseWithRestartAlways(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, - "containerB": stoppedState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), + stoppedState("containerB"), }, Host: "machine", }, @@ -2257,8 +2284,8 @@ func TestPodPhaseWithRestartAlways(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), }, Host: "machine", }, @@ -2268,7 +2295,7 @@ func TestPodPhaseWithRestartAlways(t *testing.T) { }, } for _, test := range tests { - if status := getPhase(&test.pod.Spec, test.pod.Status.Info); status != test.status { + if status := getPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status { t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status) } } @@ -2285,25 +2312,6 @@ func TestPodPhaseWithRestartNever(t *testing.T) { currentState := api.PodStatus{ Host: "machine", } - runningState := api.ContainerStatus{ - State: api.ContainerState{ - Running: &api.ContainerStateRunning{}, - }, - } - succeededState := api.ContainerStatus{ - State: api.ContainerState{ - Termination: &api.ContainerStateTerminated{ - ExitCode: 0, - }, - }, - } - failedState := api.ContainerStatus{ - State: api.ContainerState{ - Termination: &api.ContainerStateTerminated{ - ExitCode: -1, - }, - }, - } tests := []struct { pod *api.Pod @@ -2315,9 +2323,9 @@ func TestPodPhaseWithRestartNever(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, - "containerB": runningState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), + runningState("containerB"), }, Host: "machine", }, @@ -2329,9 +2337,9 @@ func TestPodPhaseWithRestartNever(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": succeededState, - "containerB": succeededState, + ContainerStatuses: []api.ContainerStatus{ + succeededState("containerA"), + succeededState("containerB"), }, Host: "machine", }, @@ -2343,9 +2351,9 @@ func TestPodPhaseWithRestartNever(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": failedState, - "containerB": failedState, + ContainerStatuses: []api.ContainerStatus{ + failedState("containerA"), + failedState("containerB"), }, Host: "machine", }, @@ -2357,9 +2365,9 @@ func TestPodPhaseWithRestartNever(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, - "containerB": succeededState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), + succeededState("containerB"), }, Host: "machine", }, @@ -2371,8 +2379,8 @@ func TestPodPhaseWithRestartNever(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), }, Host: "machine", }, @@ -2382,7 +2390,7 @@ func TestPodPhaseWithRestartNever(t *testing.T) { }, } for _, test := range tests { - if status := getPhase(&test.pod.Spec, test.pod.Status.Info); status != test.status { + if status := getPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status { t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status) } } @@ -2399,25 +2407,6 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { currentState := api.PodStatus{ Host: "machine", } - runningState := api.ContainerStatus{ - State: api.ContainerState{ - Running: &api.ContainerStateRunning{}, - }, - } - succeededState := api.ContainerStatus{ - State: api.ContainerState{ - Termination: &api.ContainerStateTerminated{ - ExitCode: 0, - }, - }, - } - failedState := api.ContainerStatus{ - State: api.ContainerState{ - Termination: &api.ContainerStateTerminated{ - ExitCode: -1, - }, - }, - } tests := []struct { pod *api.Pod @@ -2429,9 +2418,9 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, - "containerB": runningState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), + runningState("containerB"), }, Host: "machine", }, @@ -2443,9 +2432,9 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": succeededState, - "containerB": succeededState, + ContainerStatuses: []api.ContainerStatus{ + succeededState("containerA"), + succeededState("containerB"), }, Host: "machine", }, @@ -2457,9 +2446,9 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": failedState, - "containerB": failedState, + ContainerStatuses: []api.ContainerStatus{ + failedState("containerA"), + failedState("containerB"), }, Host: "machine", }, @@ -2471,9 +2460,9 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, - "containerB": succeededState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), + succeededState("containerB"), }, Host: "machine", }, @@ -2485,8 +2474,8 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { &api.Pod{ Spec: desiredState, Status: api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "containerA": runningState, + ContainerStatuses: []api.ContainerStatus{ + runningState("containerA"), }, Host: "machine", }, @@ -2496,12 +2485,25 @@ func TestPodPhaseWithRestartOnFailure(t *testing.T) { }, } for _, test := range tests { - if status := getPhase(&test.pod.Spec, test.pod.Status.Info); status != test.status { + if status := getPhase(&test.pod.Spec, test.pod.Status.ContainerStatuses); status != test.status { t.Errorf("In test %s, expected %v, got %v", test.test, test.status, status) } } } +func getReadyStatus(cName string) api.ContainerStatus { + return api.ContainerStatus{ + Name: cName, + Ready: true, + } +} +func getNotReadyStatus(cName string) api.ContainerStatus { + return api.ContainerStatus{ + Name: cName, + Ready: false, + } +} + func TestGetPodReadyCondition(t *testing.T) { ready := []api.PodCondition{{ Type: api.PodReady, @@ -2513,7 +2515,7 @@ func TestGetPodReadyCondition(t *testing.T) { }} tests := []struct { spec *api.PodSpec - info api.PodInfo + info []api.ContainerStatus expected []api.PodCondition }{ { @@ -2523,7 +2525,7 @@ func TestGetPodReadyCondition(t *testing.T) { }, { spec: &api.PodSpec{}, - info: api.PodInfo{}, + info: []api.ContainerStatus{}, expected: ready, }, { @@ -2532,7 +2534,7 @@ func TestGetPodReadyCondition(t *testing.T) { {Name: "1234"}, }, }, - info: api.PodInfo{}, + info: []api.ContainerStatus{}, expected: unready, }, { @@ -2541,8 +2543,8 @@ func TestGetPodReadyCondition(t *testing.T) { {Name: "1234"}, }, }, - info: api.PodInfo{ - "1234": api.ContainerStatus{Ready: true}, + info: []api.ContainerStatus{ + getReadyStatus("1234"), }, expected: ready, }, @@ -2553,9 +2555,9 @@ func TestGetPodReadyCondition(t *testing.T) { {Name: "5678"}, }, }, - info: api.PodInfo{ - "1234": api.ContainerStatus{Ready: true}, - "5678": api.ContainerStatus{Ready: true}, + info: []api.ContainerStatus{ + getReadyStatus("1234"), + getReadyStatus("5678"), }, expected: ready, }, @@ -2566,8 +2568,8 @@ func TestGetPodReadyCondition(t *testing.T) { {Name: "5678"}, }, }, - info: api.PodInfo{ - "1234": api.ContainerStatus{Ready: true}, + info: []api.ContainerStatus{ + getReadyStatus("1234"), }, expected: unready, }, @@ -2578,9 +2580,9 @@ func TestGetPodReadyCondition(t *testing.T) { {Name: "5678"}, }, }, - info: api.PodInfo{ - "1234": api.ContainerStatus{Ready: true}, - "5678": api.ContainerStatus{Ready: false}, + info: []api.ContainerStatus{ + getReadyStatus("1234"), + getNotReadyStatus("5678"), }, expected: unready, }, @@ -3085,26 +3087,47 @@ func TestValidateContainerStatus(t *testing.T) { kubelet := testKubelet.kubelet containerName := "x" testCases := []struct { - podInfo api.PodInfo - success bool + statuses []api.ContainerStatus + success bool }{ { - podInfo: api.PodInfo{containerName: api.ContainerStatus{State: api.ContainerState{Running: &api.ContainerStateRunning{}}}}, + statuses: []api.ContainerStatus{ + { + Name: containerName, + State: api.ContainerState{ + Running: &api.ContainerStateRunning{}, + }, + }, + }, success: true, }, { - podInfo: api.PodInfo{containerName: api.ContainerStatus{State: api.ContainerState{Termination: &api.ContainerStateTerminated{}}}}, + statuses: []api.ContainerStatus{ + { + Name: containerName, + State: api.ContainerState{ + Termination: &api.ContainerStateTerminated{}, + }, + }, + }, success: true, }, { - podInfo: api.PodInfo{containerName: api.ContainerStatus{State: api.ContainerState{Waiting: &api.ContainerStateWaiting{}}}}, + statuses: []api.ContainerStatus{ + { + Name: containerName, + State: api.ContainerState{ + Waiting: &api.ContainerStateWaiting{}, + }, + }, + }, success: false, }, } for i, tc := range testCases { _, err := kubelet.validateContainerStatus(&api.PodStatus{ - Info: tc.podInfo, + ContainerStatuses: tc.statuses, }, containerName) if tc.success { if err != nil { @@ -3115,7 +3138,7 @@ func TestValidateContainerStatus(t *testing.T) { } } if _, err := kubelet.validateContainerStatus(&api.PodStatus{ - Info: testCases[0].podInfo, + ContainerStatuses: testCases[0].statuses, }, "blah"); err == nil { t.Errorf("expected error with invalid container name") } diff --git a/pkg/kubelet/server_test.go b/pkg/kubelet/server_test.go index cc54bb7ddb..ab62834807 100644 --- a/pkg/kubelet/server_test.go +++ b/pkg/kubelet/server_test.go @@ -166,8 +166,8 @@ func getPodName(name, namespace string) string { func TestPodStatus(t *testing.T) { fw := newServerTest() expected := api.PodStatus{ - Info: map[string]api.ContainerStatus{ - "goodpod": {}, + ContainerStatuses: []api.ContainerStatus{ + {Name: "goodpod"}, }, } fw.fakeKubelet.statusFunc = func(name string) (api.PodStatus, error) { diff --git a/test/e2e/pods.go b/test/e2e/pods.go index 024483167b..9d16a950ba 100644 --- a/test/e2e/pods.go +++ b/test/e2e/pods.go @@ -57,7 +57,7 @@ func runLivenessTest(c *client.Client, podDescr *api.Pod) { By("checking the pod's current state and verifying that restartCount is present") pod, err := c.Pods(ns).Get(podDescr.Name) expectNoError(err, fmt.Sprintf("getting pod %s in namespace %s", podDescr.Name, ns)) - initialRestartCount := pod.Status.Info["liveness"].RestartCount + initialRestartCount := api.GetExistingContainerStatus(pod.Status.ContainerStatuses, "liveness").RestartCount By(fmt.Sprintf("Initial restart count of pod %s is %d", podDescr.Name, initialRestartCount)) // Wait for at most 48 * 5 = 240s = 4 minutes until restartCount is incremented @@ -67,7 +67,7 @@ func runLivenessTest(c *client.Client, podDescr *api.Pod) { time.Sleep(5 * time.Second) pod, err = c.Pods(ns).Get(podDescr.Name) expectNoError(err, fmt.Sprintf("getting pod %s", podDescr.Name)) - restartCount := pod.Status.Info["liveness"].RestartCount + restartCount := api.GetExistingContainerStatus(pod.Status.ContainerStatuses, "liveness").RestartCount By(fmt.Sprintf("Restart count of pod %s in namespace %s is now %d", podDescr.Name, ns, restartCount)) if restartCount > initialRestartCount { By(fmt.Sprintf("Restart count of pod %s in namespace %s increased from %d to %d during the test", podDescr.Name, ns, initialRestartCount, restartCount)) diff --git a/test/e2e/util.go b/test/e2e/util.go index 93d846f7ed..dcc7c7f876 100644 --- a/test/e2e/util.go +++ b/test/e2e/util.go @@ -101,7 +101,7 @@ func waitForPodNotPending(c *client.Client, ns, podName string) error { func waitForPodSuccessInNamespace(c *client.Client, podName string, contName string, namespace string) error { return waitForPodCondition(c, namespace, podName, "success or failure", func(pod *api.Pod) (bool, error) { // Cannot use pod.Status.Phase == api.PodSucceeded/api.PodFailed due to #2632 - ci, ok := pod.Status.Info[contName] + ci, ok := api.GetContainerStatus(pod.Status.ContainerStatuses, contName) if !ok { Logf("No Status.Info for container %s in pod %s yet", contName, podName) } else {