Skip to content
Open
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
52 changes: 52 additions & 0 deletions cmd/agent-sandbox-controller/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ import (
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"

"k8s.io/apimachinery/pkg/types"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1"
"sigs.k8s.io/agent-sandbox/controllers"
extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1"
extensionscontrollers "sigs.k8s.io/agent-sandbox/extensions/controllers"
Expand Down Expand Up @@ -222,11 +226,29 @@ func main() {
}

if extensions {
// 1. Initialize the Assigner
assigner := &extensionscontrollers.WarmPoolAssigner{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add NewWarmPoolAssigner(client) method. Pools is internal field - can be initialized with a constructor method

Client: mgr.GetClient(),
Pools: make(map[string]chan types.NamespacedName),
}

// 2. Add it to the Manager so it runs in the background
if err := mgr.Add(assigner); err != nil {
setupLog.Error(err, "unable to set up WarmPool Assigner")
os.Exit(1)
}

if err := assigner.SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to set up pure-push watcher")
os.Exit(1)
}

if err = (&extensionscontrollers.SandboxClaimReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
Recorder: mgr.GetEventRecorderFor("sandboxclaim-controller"),
Tracer: instrumenter,
Assigner: assigner,
}).SetupWithManager(mgr, sandboxClaimConcurrentWorkers); err != nil {
setupLog.Error(err, "unable to create controller", "controller", "SandboxClaim")
os.Exit(1)
Expand Down Expand Up @@ -262,6 +284,36 @@ func main() {
os.Exit(1)
}

// Index Sandboxes by their Phase and Ownership status
if err := mgr.GetFieldIndexer().IndexField(ctx, &sandboxv1alpha1.Sandbox{}, "status.readyAndUnowned", func(rawObj client.Object) []string {
sandbox := rawObj.(*sandboxv1alpha1.Sandbox)

// 1. Check if it has an owner (already claimed)
if metav1.GetControllerOf(sandbox) != nil && metav1.GetControllerOf(sandbox).Kind == "SandboxClaim" {
return nil
}

// 2. Check if it's actually Ready
isReady := false
for _, cond := range sandbox.Status.Conditions {
if cond.Type == string(sandboxv1alpha1.SandboxConditionReady) && cond.Status == metav1.ConditionTrue {
isReady = true
break
}
}

if isReady {
templateName := sandbox.Labels["agents.x-k8s.io/sandbox-template-ref"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use constant SandboxTemplateRefAnnotation

if templateName != "" {
return []string{"true-" + templateName}
}
}
return nil
}); err != nil {
setupLog.Error(err, "unable to set up field indexer for Sandboxes")
os.Exit(1)
}

setupLog.Info("starting manager")
if err := mgr.Start(ctx); err != nil {
setupLog.Error(err, "problem running manager")
Expand Down
21 changes: 16 additions & 5 deletions controllers/sandbox_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import (
"errors"
"fmt"
"hash/fnv"
"reflect"
"time"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -254,16 +254,27 @@ func (r *SandboxReconciler) computeReadyCondition(sandbox *sandboxv1alpha1.Sandb
func (r *SandboxReconciler) updateStatus(ctx context.Context, oldStatus *sandboxv1alpha1.SandboxStatus, sandbox *sandboxv1alpha1.Sandbox) error {
log := log.FromContext(ctx)

if reflect.DeepEqual(oldStatus, &sandbox.Status) {
// Use equality.Semantic.DeepEqual for robust comparison of Kubernetes objects
if equality.Semantic.DeepEqual(oldStatus, &sandbox.Status) {
return nil
}

if err := r.Status().Update(ctx, sandbox); err != nil {
log.Error(err, "Failed to update sandbox status")
// Create a copy of the sandbox to use as the base for the patch.
oldSandbox := sandbox.DeepCopy()
// Set the status of the copy to the *original* status.
oldSandbox.Status = *oldStatus

// Create a merge patch by comparing the oldSandbox (with oldStatus)
// with the current state of sandbox (which has the new desired status).
patch := client.MergeFrom(oldSandbox)

// Apply the patch to the status subresource.
if err := r.Status().Patch(ctx, sandbox, patch); err != nil {
log.Error(err, "Failed to patch sandbox status")
return err
}

// Surface error
log.Info("Successfully patched sandbox status")
return nil
}

Expand Down
Loading