// getContainerStatus creates the api.containerStatus of a container from the podInfo. // TODO(yifan): Get more detailed info such as Image, ImageID, etc. func (p *podInfo) getContainerStatus(container *kubecontainer.Container) api.ContainerStatus { var status api.ContainerStatus status.Name = container.Name status.Image = container.Image containerID, _ := parseContainerID(string(container.ID)) status.ImageID = containerID.imageID switch p.state { case Running: // TODO(yifan): Get StartedAt. status.State = api.ContainerState{ Running: &api.ContainerStateRunning{ StartedAt: util.Unix(container.Created, 0), }, } case Embryo, Preparing, Prepared: status.State = api.ContainerState{Waiting: &api.ContainerStateWaiting{}} case AbortedPrepare, Deleting, Exited, Garbage: exitCode, ok := p.exitCodes[status.ImageID] if !ok { glog.Warningf("rkt: Cannot get exit code for container %v", container) } exitCode = -1 status.State = api.ContainerState{ Terminated: &api.ContainerStateTerminated{ ExitCode: exitCode, StartedAt: util.Unix(container.Created, 0), }, } default: glog.Warningf("rkt: Unknown pod state: %q", p.state) } return status }
// GetPodStatus returns docker related status for all containers in the pod as // well as the infrastructure container. func (dm *DockerManager) GetPodStatus(pod *api.Pod) (*api.PodStatus, error) { podFullName := kubecontainer.GetPodFullName(pod) uid := pod.UID manifest := pod.Spec oldStatuses := make(map[string]api.ContainerStatus, len(pod.Spec.Containers)) lastObservedTime := make(map[string]util.Time, len(pod.Spec.Containers)) for _, status := range pod.Status.ContainerStatuses { oldStatuses[status.Name] = status if status.LastTerminationState.Termination != nil { lastObservedTime[status.Name] = status.LastTerminationState.Termination.FinishedAt } } var podStatus api.PodStatus statuses := make(map[string]*api.ContainerStatus, len(pod.Spec.Containers)) expectedContainers := make(map[string]api.Container) for _, container := range manifest.Containers { expectedContainers[container.Name] = container } expectedContainers[PodInfraContainerName] = api.Container{} containers, err := dm.client.ListContainers(docker.ListContainersOptions{All: true}) if err != nil { return nil, err } containerDone := util.NewStringSet() // Loop through list of running and exited docker containers to construct // the statuses. We assume docker returns a list of containers sorted in // reverse by time. for _, value := range containers { if len(value.Names) == 0 { continue } dockerName, _, err := ParseDockerName(value.Names[0]) if err != nil { continue } if dockerName.PodFullName != podFullName { continue } if uid != "" && dockerName.PodUID != uid { continue } dockerContainerName := dockerName.ContainerName c, found := expectedContainers[dockerContainerName] if !found { continue } terminationMessagePath := c.TerminationMessagePath if containerDone.Has(dockerContainerName) { continue } var terminationState *api.ContainerState = nil // Inspect the container. result := dm.inspectContainer(value.ID, dockerContainerName, terminationMessagePath) if result.err != nil { return nil, result.err } else if result.status.State.Termination != nil { terminationState = &result.status.State } if containerStatus, found := statuses[dockerContainerName]; found { if containerStatus.LastTerminationState.Termination == nil && terminationState != nil { // Populate the last termination state. containerStatus.LastTerminationState = *terminationState } count := true // Only count dead containers terminated after last time we observed, if lastObservedTime, ok := lastObservedTime[dockerContainerName]; ok { if terminationState != nil && terminationState.Termination.FinishedAt.After(lastObservedTime.Time) { count = false } else { // The container finished before the last observation. No // need to examine/count the older containers. Mark the // container name as done. containerDone.Insert(dockerContainerName) } } if count { containerStatus.RestartCount += 1 } continue } if dockerContainerName == PodInfraContainerName { // Found network container if result.status.State.Running != nil { podStatus.PodIP = result.ip } } else { // Add user container information. if oldStatus, found := oldStatuses[dockerContainerName]; found { // Use the last observed restart count if it's available. result.status.RestartCount = oldStatus.RestartCount } statuses[dockerContainerName] = &result.status } } // Handle the containers for which we cannot find any associated active or // dead docker containers. for _, container := range manifest.Containers { if _, found := statuses[container.Name]; found { continue } var containerStatus api.ContainerStatus containerStatus.Name = container.Name containerStatus.Image = container.Image if oldStatus, found := oldStatuses[container.Name]; found { // Some states may be lost due to GC; apply the last observed // values if possible. containerStatus.RestartCount = oldStatus.RestartCount containerStatus.LastTerminationState = oldStatus.LastTerminationState } //Check image is ready on the node or not. // TODO: If we integrate DockerPuller into DockerManager, we can // record the pull failure and eliminate the image checking below. image := container.Image // TODO(dchen1107): docker/docker/issues/8365 to figure out if the image exists _, err := dm.client.InspectImage(image) if err == nil { containerStatus.State.Waiting = &api.ContainerStateWaiting{ Reason: fmt.Sprintf("Image: %s is ready, container is creating", image), } } else if err == docker.ErrNoSuchImage { containerStatus.State.Waiting = &api.ContainerStateWaiting{ Reason: fmt.Sprintf("Image: %s is not ready on the node", image), } } statuses[container.Name] = &containerStatus } podStatus.ContainerStatuses = make([]api.ContainerStatus, 0) for containerName, status := range statuses { if status.State.Waiting != nil { // For containers in the waiting state, fill in a specific reason if it is recorded. if reason, ok := dm.reasonCache.Get(uid, containerName); ok { status.State.Waiting.Reason = reason } } podStatus.ContainerStatuses = append(podStatus.ContainerStatuses, *status) } return &podStatus, nil }