Skip to content

Commit cd6e3a3

Browse files
committed
Add support for shutdownAt in sandbox.spec
* Add .spec.shutdownAt string in RFC 3339 format that parses to a time * The sandbox is deleted once the current time >= shutdownAt time
1 parent 606399b commit cd6e3a3

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

api/v1alpha1/sandbox_types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ type SandboxSpec struct {
6666
// PodTemplate describes the pod spec that will be used to create an agent sandbox.
6767
// +kubebuilder:validation:Required
6868
PodTemplate PodTemplate `json:"podTemplate" protobuf:"bytes,3,opt,name=podTemplate"`
69+
70+
//ShutdownAt - Absolute time (RFC 3339) when the sandbox is deleted.
71+
ShutdownAt string `json:"shutdownAt,omitempty"`
6972
}
7073

7174
// SandboxStatus defines the observed state of Sandbox.

controllers/sandbox_controller.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"hash/fnv"
2222
"reflect"
23+
"time"
2324

2425
corev1 "k8s.io/api/core/v1"
2526
k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -33,6 +34,7 @@ import (
3334
"sigs.k8s.io/controller-runtime/pkg/handler"
3435
"sigs.k8s.io/controller-runtime/pkg/log"
3536
"sigs.k8s.io/controller-runtime/pkg/predicate"
37+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
3638

3739
sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1"
3840
)
@@ -98,12 +100,15 @@ func (r *SandboxReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
98100
readyCondition := r.computeReadyCondition(sandbox.Generation, allErrors, svc, pod)
99101
meta.SetStatusCondition(&sandbox.Status.Conditions, readyCondition)
100102

103+
result, err := r.ReconcileSandboxTTL(ctx, sandbox)
104+
allErrors = errors.Join(allErrors, err)
105+
101106
// Update status
102107
err = r.updateStatus(ctx, oldStatus, sandbox)
103108
allErrors = errors.Join(allErrors, err)
104109

105110
// return errors seen
106-
return ctrl.Result{}, allErrors
111+
return result, allErrors
107112
}
108113

109114
func (r *SandboxReconciler) computeReadyCondition(generation int64, err error, svc *corev1.Service, pod *corev1.Pod) metav1.Condition {
@@ -291,6 +296,42 @@ func (r *SandboxReconciler) mutatedPodSpec(originalSpec *corev1.PodSpec) *corev1
291296
return spec
292297
}
293298

299+
// ReconcileSandboxTTL will check if a sandbox has expired, and if so, delete it.
300+
// If the sandbox has not expired, it will requeue the request for the remaining time.
301+
302+
func (r *SandboxReconciler) ReconcileSandboxTTL(ctx context.Context, sandbox *sandboxv1alpha1.Sandbox) (ctrl.Result, error) {
303+
log := log.FromContext(ctx)
304+
305+
var expiryTime time.Time
306+
if sandbox.Spec.ShutdownAt != "" {
307+
var err error
308+
// Try parsing the endtime as a RFC 3339 string
309+
expiryTime, err = time.Parse(time.RFC3339, sandbox.Spec.ShutdownAt)
310+
if err != nil {
311+
log.Error(err, "Failed to parse TTLFromTime as RFC3339 string", "ShutdownAt", sandbox.Spec.ShutdownAt)
312+
return reconcile.Result{}, err
313+
}
314+
} else {
315+
log.Info("Sandbox TTL is not set, skipping TTL check.")
316+
return reconcile.Result{}, nil
317+
}
318+
319+
// Calculate remaining time
320+
remainingTime := time.Until(expiryTime)
321+
if remainingTime <= 0 {
322+
log.Info("Sandbox has expired, deleting")
323+
if err := r.Delete(ctx, sandbox); err != nil {
324+
return ctrl.Result{}, fmt.Errorf("failed to delete sandbox: %w", err)
325+
}
326+
return ctrl.Result{}, nil
327+
}
328+
329+
requeueAfter := max(remainingTime/2, 2*time.Second) // Requeue at most every 2 seconds
330+
log.Info("Requeuing sandbox for TTL", "remaining time", remainingTime, "requeue after", requeueAfter,
331+
"expiry time", expiryTime)
332+
return reconcile.Result{RequeueAfter: requeueAfter}, nil
333+
}
334+
294335
// SetupWithManager sets up the controller with the Manager.
295336
func (r *SandboxReconciler) SetupWithManager(mgr ctrl.Manager) error {
296337
labelSelectorPredicate, err := predicate.LabelSelectorPredicate(metav1.LabelSelector{

k8s/crds/agents.x-k8s.io_sandboxes.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3814,6 +3814,8 @@ spec:
38143814
required:
38153815
- spec
38163816
type: object
3817+
shutdownAt:
3818+
type: string
38173819
required:
38183820
- podTemplate
38193821
type: object

0 commit comments

Comments
 (0)