Skip to content

Commit

Permalink
add LastTerminatedState and improve squash logic for devbox. (#5080)
Browse files Browse the repository at this point in the history
* add LastTerminatedState for devbox.

Signed-off-by: yy <[email protected]>

* fix makefile.

Signed-off-by: yy <[email protected]>

* fix requeue.

* fix enqueue logic

* add state and rename last state

* add check pod container size

* add squash check.

---------

Signed-off-by: yy <[email protected]>
  • Loading branch information
lingdie authored Sep 19, 2024
1 parent c23bad8 commit bcb8ab4
Show file tree
Hide file tree
Showing 9 changed files with 296 additions and 21 deletions.
4 changes: 4 additions & 0 deletions controllers/devbox/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ build: ## Build manager binary.
run: manifests generate fmt vet ## Run a controller from your host.
go run ./cmd/main.go

.PHONY: debug
debug:
go run ./cmd/main.go --debug

.PHONY: docker-build
docker-build: ## Build docker image with the manager.
mv bin/manager bin/controller-devbox-${TARGETARCH}
Expand Down
5 changes: 5 additions & 0 deletions controllers/devbox/api/v1alpha1/devbox_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +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
LastTerminationState corev1.ContainerState `json:"lastState"`
}

// +kubebuilder:object:root=true
Expand Down
12 changes: 12 additions & 0 deletions controllers/devbox/api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

122 changes: 122 additions & 0 deletions controllers/devbox/config/crd/bases/devbox.sealos.io_devboxes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,67 @@ spec:
- time
type: object
type: array
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:
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>://<container_id>'
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:
nodePort:
Expand All @@ -2791,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>://<container_id>'
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
Expand Down
44 changes: 44 additions & 0 deletions controllers/devbox/config/samples/test/devbox_v1alpha1_devbox.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright © 2024 sealos.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: devbox.sealos.io/v1alpha1
kind: Devbox
metadata:
labels:
app.kubernetes.io/name: devbox
app.kubernetes.io/managed-by: kustomize
name: devbox-sample
spec:
state: Running
resource:
cpu: 1000m
memory: 1024Mi
runtimeRef:
name: go-1-22-5
namespace: devbox-system
command:
- /bin/bash
args:
- -c
- |
apt-get update
apt-get install -y tini
tini -- /bin/bash -c "echo 'DevBox is ready for testing'; tail -f /dev/null"
network:
type: NodePort
extraPorts:
- containerPort: 443
name: 'https'
- containerPort: 80
name: 'http'
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright © 2024 sealos.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

apiVersion: devbox.sealos.io/v1alpha1
kind: Runtime
metadata:
name: go-1-22-5
namespace: devbox-system
spec:
classRef: go
version: go1.22.5
description: go1.22.5
config:
image: ubuntu
workingDir: /home/sealos/project
releaseCommand:
- /bin/bash
- -c
releaseArgs:
- /home/sealos/project/entrypoint.sh
category:
- ubuntu
- go
32 changes: 32 additions & 0 deletions controllers/devbox/deploy/manifests/deploy.yaml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -2776,6 +2776,38 @@ spec:
- time
type: object
type: array
lastTerminatedState:
description: ContainerStateTerminated is a terminated state of a container.
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
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
network:
properties:
nodePort:
Expand Down
37 changes: 17 additions & 20 deletions controllers/devbox/internal/controller/devbox_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/predicate"
)
Expand Down Expand Up @@ -212,12 +211,10 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D
logger.Error(err, "get latest devbox failed")
return err
}
// compare devbox status with latestDevbox status
latestDevbox.Status.Phase = devbox.Status.Phase
latestDevbox.Status.DevboxPodPhase = devbox.Status.DevboxPodPhase
// merge commit history, up coming commit history will be added to the latest devbox
// update devbox status with latestDevbox status
logger.Info("updating devbox status")
logger.Info("merge commit history", "devbox", devbox.Status.CommitHistory, "latestDevbox", latestDevbox.Status.CommitHistory)
latestDevbox.Status.CommitHistory = helper.MergeCommitHistory(devbox, latestDevbox)
helper.UpdateDevboxStatus(devbox, latestDevbox)
return r.Status().Update(ctx, latestDevbox)
}); err != nil {
logger.Error(err, "sync pod failed")
Expand Down Expand Up @@ -257,6 +254,12 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D
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
// 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
Expand Down Expand Up @@ -298,6 +301,8 @@ func (r *DevboxReconciler) syncPod(ctx context.Context, devbox *devboxv1alpha1.D
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
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
Expand Down Expand Up @@ -438,6 +443,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
}
Expand All @@ -451,6 +457,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
}

Expand Down Expand Up @@ -576,19 +583,9 @@ func (r *DevboxReconciler) generateImageName(devbox *devboxv1alpha1.Devbox) stri
// SetupWithManager sets up the controller with the Manager.
func (r *DevboxReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&devboxv1alpha1.Devbox{}).
Owns(&corev1.Pod{}).
Owns(&corev1.Service{}).
Watches(
&corev1.Pod{},
handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &devboxv1alpha1.Devbox{}),
builder.WithPredicates(predicate.And(
predicate.ResourceVersionChangedPredicate{},
predicate.NewPredicateFuncs(func(object client.Object) bool {
pod := object.(*corev1.Pod)
return pod.Labels[label.AppManagedBy] == label.DefaultManagedBy && pod.Labels[label.AppPartOf] == devboxv1alpha1.DevBoxPartOf
}),
)),
).
For(&devboxv1alpha1.Devbox{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Owns(&corev1.Pod{}, builder.WithPredicates(predicate.ResourceVersionChangedPredicate{})). // enqueue request if pod spec/status is updated
Owns(&corev1.Service{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Owns(&corev1.Secret{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Complete(r)
}
Loading

0 comments on commit bcb8ab4

Please sign in to comment.