Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/controller/sandbox/sandbox_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ func (r *SandboxReconciler) handlePauseTimeout(ctx context.Context, box *agentsv
// sandbox is preserved for the configured duration after being paused.
if retention, managed := r.resolveRetentionAnnotationOrDefault(box); managed {
if box.Spec.ShutdownTime != nil {
newShutdown := metav1.NewTime(pausedretention.PausedShutdownTime(now.Time, retention))
newShutdown := metav1.NewTime(timeoututils.NormalizeTime(now.Time.Add(retention)))
modified.Spec.ShutdownTime = &newShutdown
// Keep PauseTime aligned so the next connect/resume can preserve auto-pause mode.
modified.Spec.PauseTime = &newShutdown
Expand Down
4 changes: 0 additions & 4 deletions pkg/pausedretention/retention.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,3 @@ func ResolveReservePausedSandboxDurationAnnotation(annotations map[string]string
}
return retention, true, nil
}

func PausedShutdownTime(anchor time.Time, pausedRetention time.Duration) time.Time {
return timeout.NormalizeTime(anchor.Add(pausedRetention))
}
22 changes: 0 additions & 22 deletions pkg/pausedretention/retention_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,3 @@ func TestResolveReservePausedSandboxDurationAnnotation(t *testing.T) {
})
}
}

func TestPausedShutdownTime(t *testing.T) {
tests := []struct {
name string
anchor time.Time
pausedRetention time.Duration
want time.Time
}{
{
name: "adds paused retention",
anchor: time.Date(2026, time.June, 11, 10, 0, 0, 123, time.UTC),
pausedRetention: 30 * time.Minute,
want: time.Date(2026, time.June, 11, 10, 30, 0, 0, time.UTC),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := PausedShutdownTime(tt.anchor, tt.pausedRetention)
assert.Equal(t, tt.want, got)
})
}
}
3 changes: 2 additions & 1 deletion pkg/sandbox-manager/infra/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ type Sandbox interface {
SetPodLabels(labels map[string]string)
GetPodLabels() map[string]string
SetTimeout(opts timeout.Options)
SaveTimeoutWithPolicy(ctx context.Context, opts SaveTimeoutOptions, policy timeout.UpdatePolicy) (TimeoutUpdateResult, error)
// SaveTimeout persists timeout and annotations, retrying conflicts against fresh state.
SaveTimeout(ctx context.Context, opts SaveTimeoutOptions) (TimeoutUpdateResult, error)
GetTimeout() timeout.Options
GetClaimTime() (time.Time, error)
Kill(ctx context.Context) error // Delete the Sandbox resource
Expand Down
2 changes: 1 addition & 1 deletion pkg/sandbox-manager/infra/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (m *mockSandboxForLabels) GetResource() SandboxResource { return SandboxRes
func (m *mockSandboxForLabels) SetImage(string) {}
func (m *mockSandboxForLabels) GetImage() string { return "" }
func (m *mockSandboxForLabels) SetTimeout(timeout.Options) {}
func (m *mockSandboxForLabels) SaveTimeoutWithPolicy(context.Context, SaveTimeoutOptions, timeout.UpdatePolicy) (TimeoutUpdateResult, error) {
func (m *mockSandboxForLabels) SaveTimeout(context.Context, SaveTimeoutOptions) (TimeoutUpdateResult, error) {
return TimeoutUpdateResult{}, nil
}
func (m *mockSandboxForLabels) GetTimeout() timeout.Options { return timeout.Options{} }
Expand Down
13 changes: 13 additions & 0 deletions pkg/sandbox-manager/infra/sandboxcr/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,22 @@ func runClaimPostProcesses(ctx context.Context, sbx *Sandbox, lockType infra.Loc
metrics.Total += metrics.CSIMount
log.Info("csi mount completed", "cost", metrics.CSIMount)
}

if err := processSaveTimeout(ctx, sbx, opts.SaveTimeoutOptions); err != nil {
log.Error(err, "failed to save timeout after claim post processes")
return retriableError{Message: fmt.Sprintf("failed to save timeout: %s", err)}
}
return nil
}

func processSaveTimeout(ctx context.Context, sbx infra.Sandbox, opts *infra.SaveTimeoutOptions) error {
if opts == nil {
return nil
}
_, err := sbx.SaveTimeout(ctx, *opts)
return err
}

// processSecurityToken issues and propagates a sandbox security token when the
// identity provider feature gate and sandbox annotations request it.
func processSecurityToken(ctx context.Context, opts infra.ClaimSandboxOptions, sbx *Sandbox, cache infracache.Provider, metrics *infra.ClaimMetrics) error {
Expand Down
53 changes: 53 additions & 0 deletions pkg/sandbox-manager/infra/sandboxcr/claim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import (
utilfeature "github.com/openkruise/agents/pkg/utils/feature"
"github.com/openkruise/agents/pkg/utils/runtime"
utestutils "github.com/openkruise/agents/pkg/utils/testutils"
timeoututils "github.com/openkruise/agents/pkg/utils/timeout"
testutils "github.com/openkruise/agents/test/utils"
)

Expand Down Expand Up @@ -309,6 +310,9 @@ func TestInfra_ClaimSandbox(t *testing.T) {
defer server.Close()
existTemplate := "test-template"
user := "test-user"
claimTimeoutTarget := timeoututils.Options{
ShutdownTime: time.Date(2026, 7, 9, 10, 0, 0, 0, time.UTC),
}

tmpl := v1alpha1.EmbeddedSandboxTemplate{
Template: &corev1.PodTemplateSpec{
Expand Down Expand Up @@ -384,6 +388,18 @@ func TestInfra_ClaimSandbox(t *testing.T) {
assert.Equal(t, "test-value", sbx.GetAnnotations()["test-annotation"])
},
},
{
name: "claim saves timeout options",
available: 1,
options: infra.ClaimSandboxOptions{
User: user,
Template: existTemplate,
SaveTimeoutOptions: &infra.SaveTimeoutOptions{Timeout: claimTimeoutTarget},
},
postCheck: func(t *testing.T, sbx infra.Sandbox) {
assert.True(t, timeoututils.Equal(claimTimeoutTarget, sbx.GetTimeout()))
},
},
{
name: "all locked",
available: 10,
Expand Down Expand Up @@ -4743,3 +4759,40 @@ func TestTryClaimSandbox_SecurityToken(t *testing.T) {
})
}
}

func TestRunClaimPostProcesses_SaveTimeout(t *testing.T) {
tests := []struct {
name string
expectError string
}{
{
name: "returns save timeout error",
expectError: "not found",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
testInfra, _ := NewTestInfra(t)
target := timeoututils.Options{ShutdownTime: time.Now().Add(time.Hour)}
sbxObj := &v1alpha1.Sandbox{
ObjectMeta: metav1.ObjectMeta{
Name: "claim-post-timeout-" + strings.ReplaceAll(tt.name, " ", "-"),
Namespace: "default",
},
}

sbx := AsSandbox(sbxObj, testInfra.Cache)
metrics := infra.ClaimMetrics{}
err := runClaimPostProcesses(t.Context(), sbx, infra.LockTypeUpdate, infra.ClaimSandboxOptions{
SaveTimeoutOptions: &infra.SaveTimeoutOptions{Timeout: target},
}, testInfra.Cache, &metrics)

if tt.expectError != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.expectError)
assert.Empty(t, metrics)
}
})
}
}
6 changes: 6 additions & 0 deletions pkg/sandbox-manager/infra/sandboxcr/clone.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ func CloneSandbox(ctx context.Context, opts infra.CloneSandboxOptions, cache inf
log.Info("csi mount completed", "cost", metrics.CSIMount)
}

if err = processSaveTimeout(ctx, sbx, opts.SaveTimeoutOptions); err != nil {
log.Error(err, "failed to save timeout after clone post processes")
err = retriableError{Message: fmt.Sprintf("failed to save timeout: %s", err)}
return
}

cloned = sbx
return
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/sandbox-manager/infra/sandboxcr/clone_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"github.com/openkruise/agents/pkg/sandbox-manager/infra"
"github.com/openkruise/agents/pkg/servers/e2b/models"
utestutils "github.com/openkruise/agents/pkg/utils/testutils"
timeoututils "github.com/openkruise/agents/pkg/utils/timeout"
testutils "github.com/openkruise/agents/test/utils"
)

Expand Down Expand Up @@ -1080,6 +1081,30 @@ func TestCloneSandbox(t *testing.T) {
assert.GreaterOrEqual(t, metrics.Total, time.Duration(0))
},
},
{
name: "successful clone saves timeout",
opts: infra.CloneSandboxOptions{
User: user,
CheckPointID: checkpointID,
WaitReadyTimeout: 30 * time.Second,
SaveTimeoutOptions: &infra.SaveTimeoutOptions{Timeout: timeoututils.Options{
ShutdownTime: time.Date(2030, 1, 2, 3, 4, 5, 0, time.UTC),
}},
},
serverOpts: testutils.TestRuntimeServerOptions{
RunCommandResult: runtime.RunCommandResult{
PID: 1,
Exited: true,
},
RunCommandImmediately: true,
},
sbxOverride: sbxOverride{Name: "test-sandbox-clone-timeout"},
postCheck: func(t *testing.T, sbx infra.Sandbox, metrics infra.CloneMetrics) {
assert.True(t, timeoututils.Equal(timeoututils.Options{
ShutdownTime: time.Date(2030, 1, 2, 3, 4, 5, 0, time.UTC),
}, sbx.GetTimeout()))
},
},
{
name: "clone with modifier",
opts: infra.CloneSandboxOptions{
Expand Down
Loading