diff --git a/controllers/devbox/api/v1alpha1/devbox_types.go b/controllers/devbox/api/v1alpha1/devbox_types.go index 940b74c64ad..facdbe59f9b 100644 --- a/controllers/devbox/api/v1alpha1/devbox_types.go +++ b/controllers/devbox/api/v1alpha1/devbox_types.go @@ -179,8 +179,11 @@ type DevboxStatus struct { CommitHistory []*CommitHistory `json:"commitHistory"` // +kubebuilder:validation:Optional Phase DevboxPhase `json:"phase"` + + // +kubebuilder:validation:Optional + State corev1.ContainerState `json:"state"` // +kubebuilder:validation:Optional - LastTerminatedState *corev1.ContainerStateTerminated `json:"lastTerminatedState"` + LastTerminationState corev1.ContainerState `json:"lastState"` } // +kubebuilder:object:root=true diff --git a/controllers/devbox/api/v1alpha1/zz_generated.deepcopy.go b/controllers/devbox/api/v1alpha1/zz_generated.deepcopy.go index ae821980094..a62954292b7 100644 --- a/controllers/devbox/api/v1alpha1/zz_generated.deepcopy.go +++ b/controllers/devbox/api/v1alpha1/zz_generated.deepcopy.go @@ -375,11 +375,8 @@ func (in *DevboxStatus) DeepCopyInto(out *DevboxStatus) { } } } - if in.LastTerminatedState != nil { - in, out := &in.LastTerminatedState, &out.LastTerminatedState - *out = new(v1.ContainerStateTerminated) - (*in).DeepCopyInto(*out) - } + in.State.DeepCopyInto(&out.State) + in.LastTerminationState.DeepCopyInto(&out.LastTerminationState) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevboxStatus. diff --git a/controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml b/controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml index 86dc9522f50..7c585d60f50 100644 --- a/controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml +++ b/controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml @@ -2768,37 +2768,66 @@ spec: - time type: object type: array - lastTerminatedState: - description: ContainerStateTerminated is a terminated state of a container. + lastState: + description: |- + ContainerState holds a possible state of container. + Only one of its members may be specified. + If none of them is specified, the default one is ContainerStateWaiting. properties: - containerID: - description: Container's ID in the format '://' - type: string - exitCode: - description: Exit status from the last termination of the container - format: int32 - type: integer - finishedAt: - description: Time at which the container last terminated - format: date-time - type: string - message: - description: Message regarding the last termination of the container - type: string - reason: - description: (brief) reason from the last termination of the container - type: string - signal: - description: Signal from the last termination of the container - format: int32 - type: integer - startedAt: - description: Time at which previous execution of the container - started - format: date-time - type: string - required: - - exitCode + running: + description: Details about a running container + properties: + startedAt: + description: Time at which the container was last (re-)started + format: date-time + type: string + type: object + terminated: + description: Details about a terminated container + properties: + containerID: + description: Container's ID in the format '://' + type: string + exitCode: + description: Exit status from the last termination of the + container + format: int32 + type: integer + finishedAt: + description: Time at which the container last terminated + format: date-time + type: string + message: + description: Message regarding the last termination of the + container + type: string + reason: + description: (brief) reason from the last termination of the + container + type: string + signal: + description: Signal from the last termination of the container + format: int32 + type: integer + startedAt: + description: Time at which previous execution of the container + started + format: date-time + type: string + required: + - exitCode + type: object + waiting: + description: Details about a waiting container + properties: + message: + description: Message regarding why the container is not yet + running. + type: string + reason: + description: (brief) reason the container is not yet running. + type: string + type: object type: object network: properties: @@ -2823,6 +2852,67 @@ spec: description: PodPhase is a label for the condition of a pod at the current time. type: string + state: + description: |- + ContainerState holds a possible state of container. + Only one of its members may be specified. + If none of them is specified, the default one is ContainerStateWaiting. + properties: + running: + description: Details about a running container + properties: + startedAt: + description: Time at which the container was last (re-)started + format: date-time + type: string + type: object + terminated: + description: Details about a terminated container + properties: + containerID: + description: Container's ID in the format '://' + type: string + exitCode: + description: Exit status from the last termination of the + container + format: int32 + type: integer + finishedAt: + description: Time at which the container last terminated + format: date-time + type: string + message: + description: Message regarding the last termination of the + container + type: string + reason: + description: (brief) reason from the last termination of the + container + type: string + signal: + description: Signal from the last termination of the container + format: int32 + type: integer + startedAt: + description: Time at which previous execution of the container + started + format: date-time + type: string + required: + - exitCode + type: object + waiting: + description: Details about a waiting container + properties: + message: + description: Message regarding why the container is not yet + running. + type: string + reason: + description: (brief) reason the container is not yet running. + type: string + type: object + type: object type: object type: object served: true diff --git a/controllers/devbox/internal/controller/devbox_controller.go b/controllers/devbox/internal/controller/devbox_controller.go index ea0acf6ad89..765c8d50199 100644 --- a/controllers/devbox/internal/controller/devbox_controller.go +++ b/controllers/devbox/internal/controller/devbox_controller.go @@ -215,7 +215,6 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D logger.Info("updating devbox status") logger.Info("merge commit history", "devbox", devbox.Status.CommitHistory, "latestDevbox", latestDevbox.Status.CommitHistory) helper.UpdateDevboxStatus(devbox, latestDevbox) - logger.Info("devbox latest terminated state", "state", devbox.Status.LastTerminatedState) return r.Status().Update(ctx, latestDevbox) }); err != nil { logger.Error(err, "sync pod failed") @@ -255,8 +254,7 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D case 1: pod := &podList.Items[0] devbox.Status.DevboxPodPhase = pod.Status.Phase - devbox.Status.LastTerminatedState = helper.GetLastTerminatedState(devbox, pod) - logger.Info("last terminated state", "state", devbox.Status.LastTerminatedState) + devbox.Status.State = pod.Status.ContainerStatuses[0].State // update commit predicated status by pod status, this should be done once find a pod helper.UpdatePredicatedCommitStatus(devbox, pod) // pod has been deleted, handle it, next reconcile will create a new pod, and we will update commit history status by predicated status @@ -298,8 +296,8 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D case 1: pod := &podList.Items[0] devbox.Status.DevboxPodPhase = pod.Status.Phase - devbox.Status.LastTerminatedState = helper.GetLastTerminatedState(devbox, pod) - logger.Info("last terminated state", "state", devbox.Status.LastTerminatedState) + // update state to empty since devbox is stopped + devbox.Status.State = corev1.ContainerState{} // update commit predicated status by pod status, this should be done once find a pod helper.UpdatePredicatedCommitStatus(devbox, pod) // pod has been deleted, handle it, next reconcile will create a new pod, and we will update commit history status by predicated status @@ -440,6 +438,7 @@ func (r *DevboxReconciler) deletePod(ctx context.Context, devbox *devboxv1alpha1 return err } // update commit history status because pod has been deleted + devbox.Status.LastTerminationState = pod.Status.ContainerStatuses[0].State helper.UpdateCommitHistory(devbox, pod, true) return nil } @@ -453,6 +452,7 @@ func (r *DevboxReconciler) handlePodDeleted(ctx context.Context, devbox *devboxv } // update commit history status because pod has been deleted helper.UpdateCommitHistory(devbox, pod, true) + devbox.Status.LastTerminationState = pod.Status.ContainerStatuses[0].State return nil } diff --git a/controllers/devbox/internal/controller/helper/devbox.go b/controllers/devbox/internal/controller/helper/devbox.go index 875db77a134..f9f3633f22d 100644 --- a/controllers/devbox/internal/controller/helper/devbox.go +++ b/controllers/devbox/internal/controller/helper/devbox.go @@ -89,6 +89,10 @@ func MergeCommitHistory(devbox *devboxv1alpha1.Devbox, latestDevbox *devboxv1alp for _, c := range historyMap { res = append(res, c) } + // sort commit history by time in descending order + sort.Slice(res, func(i, j int) bool { + return res[i].Time.After(res[j].Time.Time) + }) return res } @@ -119,22 +123,13 @@ func UpdatePredicatedCommitStatus(devbox *devboxv1alpha1.Devbox, pod *corev1.Pod } } -func GetLastTerminatedState(devbox *devboxv1alpha1.Devbox, pod *corev1.Pod) *corev1.ContainerStateTerminated { - if len(pod.Status.ContainerStatuses) == 0 { - return nil - } - if pod.Status.ContainerStatuses[0].State.Terminated != nil { - return pod.Status.ContainerStatuses[0].State.Terminated - } - return devbox.Status.LastTerminatedState -} - // UpdateDevboxStatus updates the devbox status, including phase, pod phase, last terminated state and commit history, maybe we need update more fields in the future // TODO: move this function to devbox types.go func UpdateDevboxStatus(current, latest *devboxv1alpha1.Devbox) { latest.Status.Phase = current.Status.Phase latest.Status.DevboxPodPhase = current.Status.DevboxPodPhase - latest.Status.LastTerminatedState = current.Status.LastTerminatedState + latest.Status.State = current.Status.State + latest.Status.LastTerminationState = current.Status.LastTerminationState latest.Status.CommitHistory = MergeCommitHistory(current, latest) }