Skip to content
Merged
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
32 changes: 32 additions & 0 deletions extensions/api/v1alpha1/sandboxclaim_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@ const (
ClaimExpiredReason = "ClaimExpired"
)

// WarmPoolPolicy describes the policy for using warm pools.
// It can be one of the following:
// - "none": Do not use any warm pool, always create fresh sandboxes
// - "default": Select from all available warm pools that match the template (default)
// - A warm pool name: Select only from the specified warm pool (e.g., "fast-pool", "secure-pool")
type WarmPoolPolicy string

const (
// WarmPoolPolicyNone indicates that no warm pool should be used.
// A fresh sandbox will always be created.
WarmPoolPolicyNone WarmPoolPolicy = "none"

// WarmPoolPolicyDefault indicates the default behavior: select from all
// available warm pools that match the template. This is the default behavior
// if warmpool is not specified.
WarmPoolPolicyDefault WarmPoolPolicy = "default"
)

// IsSpecificPool returns true if the policy specifies a specific warm pool name
// (not "none" or "default").
func (p WarmPoolPolicy) IsSpecificPool() bool {
return p != WarmPoolPolicyNone && p != WarmPoolPolicyDefault && p != ""
}

// ShutdownPolicy describes the policy for shutting down the underlying Sandbox when the SandboxClaim expires.
// +kubebuilder:validation:Enum=Delete;DeleteForeground;Retain
type ShutdownPolicy string
Expand Down Expand Up @@ -80,6 +104,14 @@ type SandboxClaimSpec struct {
// lifecycle defines when and how the SandboxClaim should be shut down.
// +optional
Lifecycle *Lifecycle `json:"lifecycle,omitempty"`

// warmpool specifies the warm pool policy for sandbox adoption.
// - "none": Do not use any warm pool, always create fresh sandboxes
// - "default": Use default behavior, select from all matching warm pools (default)
// - A warm pool name: Select only from the specified warm pool (e.g., "fast-pool", "secure-pool")
// +optional
// +kubebuilder:default=default
WarmPool *WarmPoolPolicy `json:"warmpool,omitempty"`
}

// SandboxClaimStatus defines the observed state of Sandbox.
Expand Down
5 changes: 5 additions & 0 deletions extensions/api/v1alpha1/zz_generated.deepcopy.go

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

31 changes: 31 additions & 0 deletions extensions/controllers/sandboxclaim_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ import (
// ErrTemplateNotFound is a sentinel error indicating a SandboxTemplate was not found.
var ErrTemplateNotFound = errors.New("SandboxTemplate not found")

// getWarmPoolPolicy returns the effective warm pool policy for a claim.
func getWarmPoolPolicy(claim *extensionsv1alpha1.SandboxClaim) extensionsv1alpha1.WarmPoolPolicy {
if claim.Spec.WarmPool != nil {
return *claim.Spec.WarmPool
}
return extensionsv1alpha1.WarmPoolPolicyDefault
}

// SandboxClaimReconciler reconciles a SandboxClaim object
type SandboxClaimReconciler struct {
client.Client
Expand Down Expand Up @@ -604,6 +612,7 @@ func (r *SandboxClaimReconciler) getOrCreateSandbox(ctx context.Context, claim *
return nil, fmt.Errorf("failed to list sandboxes: %w", err)
}

policy := getWarmPoolPolicy(claim)
templateHash := sandboxcontrollers.NameHash(claim.Spec.TemplateRef.Name)
var adoptionCandidates []*v1alpha1.Sandbox

Expand All @@ -619,6 +628,11 @@ func (r *SandboxClaimReconciler) getOrCreateSandbox(ctx context.Context, claim *
return sb, nil
}

// Skip warm pool adoption entirely if policy is "none"
if policy == extensionsv1alpha1.WarmPoolPolicyNone {
continue
}

// Collect adoption candidates from warm pool
if _, ok := sb.Labels[warmPoolSandboxLabel]; !ok {
continue
Expand All @@ -630,18 +644,35 @@ func (r *SandboxClaimReconciler) getOrCreateSandbox(ctx context.Context, claim *
if controllerRef != nil && controllerRef.Kind != "SandboxWarmPool" {
continue
}

// If a specific pool is requested, only consider sandboxes from that pool
if policy.IsSpecificPool() {
specificPoolHash := sandboxcontrollers.NameHash(string(policy))
if sb.Labels[warmPoolSandboxLabel] != specificPoolHash {
continue
}
}

adoptionCandidates = append(adoptionCandidates, sb)
}

if policy == extensionsv1alpha1.WarmPoolPolicyNone {
logger.Info("Skipping warm pool adoption based on warmpool policy", "claim", claim.Name, "warmpool", policy)
return nil, nil
}

// Try to adopt from warm pool
if len(adoptionCandidates) > 0 {
logger.V(1).Info("Found warm pool adoption candidates", "count", len(adoptionCandidates), "claim", claim.Name, "warmpool", policy)
adopted, err := r.adoptSandboxFromCandidates(ctx, claim, adoptionCandidates)
if err != nil {
return nil, err
}
if adopted != nil {
return adopted, nil
}
} else if policy.IsSpecificPool() {
logger.Info("No available sandboxes in specified warm pool", "warmPool", string(policy), "claim", claim.Name)
}

// No warm pool sandbox available; caller decides whether to create
Expand Down
Loading