diff --git a/controllers/devbox/.gitignore b/controllers/devbox/.gitignore index ada68ff086c..fa6acefb0a0 100644 --- a/controllers/devbox/.gitignore +++ b/controllers/devbox/.gitignore @@ -25,3 +25,6 @@ go.work *.swp *.swo *~ + +# ignore deploy.yaml +deploy/manifests/deploy.yaml diff --git a/controllers/devbox/api/v1alpha1/devbox_types.go b/controllers/devbox/api/v1alpha1/devbox_types.go index facdbe59f9b..5c82533e142 100644 --- a/controllers/devbox/api/v1alpha1/devbox_types.go +++ b/controllers/devbox/api/v1alpha1/devbox_types.go @@ -163,16 +163,16 @@ const ( DevboxPhasePending DevboxPhase = "Pending" //DevboxPhaseStopped means Devbox is stop and stopped success DevboxPhaseStopped DevboxPhase = "Stopped" - //DevboxPhaseStopping means Devbox is stop and not stopped success + //DevboxPhaseStopping means Devbox is stopping DevboxPhaseStopping DevboxPhase = "Stopping" //DevboxPhaseError means Devbox is error DevboxPhaseError DevboxPhase = "Error" + //DevboxPhaseUnknown means Devbox is unknown + DevboxPhaseUnknown DevboxPhase = "Unknown" ) // DevboxStatus defines the observed state of Devbox type DevboxStatus struct { - // +kubebuilder:validation:Optional - DevboxPodPhase corev1.PodPhase `json:"podPhase"` // +kubebuilder:validation:Optional Network NetworkStatus `json:"network"` // +kubebuilder:validation:Optional 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 7c585d60f50..eaf11b9e577 100644 --- a/controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml +++ b/controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml @@ -2848,10 +2848,6 @@ spec: type: object phase: type: string - podPhase: - 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. diff --git a/controllers/devbox/deploy/manifests/deploy.yaml.tmpl b/controllers/devbox/deploy/manifests/deploy.yaml.tmpl index 753ca75c462..92d3b7c6a9d 100644 --- a/controllers/devbox/deploy/manifests/deploy.yaml.tmpl +++ b/controllers/devbox/deploy/manifests/deploy.yaml.tmpl @@ -2856,10 +2856,6 @@ spec: type: object phase: type: string - podPhase: - 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. @@ -5639,7 +5635,7 @@ metadata: name: devbox-controller-manager namespace: devbox-system spec: - replicas: 1 + replicas: 2 selector: matchLabels: control-plane: controller-manager diff --git a/controllers/devbox/internal/controller/devbox_controller.go b/controllers/devbox/internal/controller/devbox_controller.go index a9e15005f92..a74fef4893e 100644 --- a/controllers/devbox/internal/controller/devbox_controller.go +++ b/controllers/devbox/internal/controller/devbox_controller.go @@ -202,6 +202,17 @@ func (r *DevboxReconciler) syncSecret(ctx context.Context, devbox *devboxv1alpha func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.Devbox, recLabels map[string]string) error { logger := log.FromContext(ctx) + + var podList corev1.PodList + if err := r.List(ctx, &podList, client.InNamespace(devbox.Namespace), client.MatchingLabels(recLabels)); err != nil { + return err + } + // only one pod is allowed, if more than one pod found, return error + if len(podList.Items) > 1 { + return fmt.Errorf("more than one pod found") + } + logger.Info("pod list", "length", len(podList.Items)) + // update devbox status after pod is created or updated defer func() { if err := retry.RetryOnConflict(retry.DefaultRetry, func() error { @@ -214,6 +225,7 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D // update devbox status with latestDevbox status logger.Info("updating devbox status") logger.Info("merge commit history", "devbox", devbox.Status.CommitHistory, "latestDevbox", latestDevbox.Status.CommitHistory) + devbox.Status.Phase = helper.GenerateDevboxPhase(devbox, podList) helper.UpdateDevboxStatus(devbox, latestDevbox) return r.Status().Update(ctx, latestDevbox) }); err != nil { @@ -225,17 +237,6 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D r.Recorder.Eventf(devbox, corev1.EventTypeNormal, "Sync pod success", "Sync pod success") }() - var podList corev1.PodList - if err := r.List(ctx, &podList, client.InNamespace(devbox.Namespace), client.MatchingLabels(recLabels)); err != nil { - return err - } - // only one pod is allowed, if more than one pod found, return error - if len(podList.Items) > 1 { - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseError - return fmt.Errorf("more than one pod found") - } - logger.Info("pod list", "length", len(podList.Items)) - switch devbox.Spec.State { case devboxv1alpha1.DevboxStateRunning: runtimecr, err := r.getRuntime(ctx, devbox) @@ -249,14 +250,11 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D case 0: logger.Info("create pod") logger.Info("next commit history", "commit", nextCommitHistory) - devbox.Status.Phase = devboxv1alpha1.DevboxPhasePending return r.createPod(ctx, devbox, expectPod, nextCommitHistory) case 1: pod := &podList.Items[0] - devbox.Status.DevboxPodPhase = pod.Status.Phase // check pod container size, if it is 0, it means the pod is not running, return an error if len(pod.Status.ContainerStatuses) == 0 { - devbox.Status.Phase = devboxv1alpha1.DevboxPhasePending return fmt.Errorf("pod container size is 0") } devbox.Status.State = pod.Status.ContainerStatuses[0].State @@ -275,32 +273,26 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D case corev1.PodPending, corev1.PodRunning: // pod is running or pending, do nothing here logger.Info("pod is running or pending") - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseRunning // update commit history status by pod status helper.UpdateCommitHistory(devbox, pod, false) return nil case corev1.PodFailed, corev1.PodSucceeded: // pod failed or succeeded, we need delete pod and remove finalizer - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseStopped logger.Info("pod failed or succeeded, recreate pod") return r.deletePod(ctx, devbox, pod) } case false: // pod not match expectations, delete pod anyway logger.Info("pod not match expectations, recreate pod") - devbox.Status.Phase = devboxv1alpha1.DevboxPhasePending return r.deletePod(ctx, devbox, pod) } } case devboxv1alpha1.DevboxStateStopped: switch len(podList.Items) { case 0: - // update devbox status to stopped, no pod found, do nothing - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseStopped return nil case 1: pod := &podList.Items[0] - devbox.Status.DevboxPodPhase = pod.Status.Phase // 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 @@ -309,7 +301,6 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D if !pod.DeletionTimestamp.IsZero() { return r.handlePodDeleted(ctx, devbox, pod) } - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseStopped // we need delete pod because devbox state is stopped // we don't care about the pod status, just delete it return r.deletePod(ctx, devbox, pod) @@ -422,7 +413,6 @@ func (r *DevboxReconciler) createPod(ctx context.Context, devbox *devboxv1alpha1 nextCommitHistory.PredicatedStatus = devboxv1alpha1.CommitStatusPending if err := r.Create(ctx, expectPod); err != nil { logger.Error(err, "create pod failed") - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseError return err } devbox.Status.CommitHistory = append(devbox.Status.CommitHistory, nextCommitHistory) @@ -439,7 +429,6 @@ func (r *DevboxReconciler) deletePod(ctx context.Context, devbox *devboxv1alpha1 } if err := r.Delete(ctx, pod); err != nil { logger.Error(err, "delete pod failed") - devbox.Status.Phase = devboxv1alpha1.DevboxPhaseError return err } // update commit history status because pod has been deleted diff --git a/controllers/devbox/internal/controller/helper/devbox.go b/controllers/devbox/internal/controller/helper/devbox.go index 055763ac1cf..7ce9ac497f5 100644 --- a/controllers/devbox/internal/controller/helper/devbox.go +++ b/controllers/devbox/internal/controller/helper/devbox.go @@ -76,6 +76,32 @@ func GeneratePodAnnotations(devbox *devboxv1alpha1.Devbox, runtime *devboxv1alph return annotations } +func GenerateDevboxPhase(devbox *devboxv1alpha1.Devbox, podList corev1.PodList) devboxv1alpha1.DevboxPhase { + if len(podList.Items) > 1 { + return devboxv1alpha1.DevboxPhaseError + } + switch devbox.Spec.State { + case devboxv1alpha1.DevboxStateRunning: + if len(podList.Items) == 0 { + return devboxv1alpha1.DevboxPhasePending + } + switch podList.Items[0].Status.Phase { + case corev1.PodFailed, corev1.PodSucceeded: + return devboxv1alpha1.DevboxPhaseStopped + case corev1.PodPending: + return devboxv1alpha1.DevboxPhasePending + case corev1.PodRunning: + return devboxv1alpha1.DevboxPhaseRunning + } + case devboxv1alpha1.DevboxStateStopped: + if len(podList.Items) == 0 { + return devboxv1alpha1.DevboxPhaseStopped + } + return devboxv1alpha1.DevboxPhaseStopping + } + return devboxv1alpha1.DevboxPhaseUnknown +} + func MergeCommitHistory(devbox *devboxv1alpha1.Devbox, latestDevbox *devboxv1alpha1.Devbox) []*devboxv1alpha1.CommitHistory { res := make([]*devboxv1alpha1.CommitHistory, 0) historyMap := make(map[string]*devboxv1alpha1.CommitHistory) @@ -127,7 +153,6 @@ func UpdatePredicatedCommitStatus(devbox *devboxv1alpha1.Devbox, pod *corev1.Pod // 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.State = current.Status.State latest.Status.LastTerminationState = current.Status.LastTerminationState latest.Status.CommitHistory = MergeCommitHistory(current, latest)