From a53441f23b0df0fdd01bccfc0a1c5d43cd921ed1 Mon Sep 17 00:00:00 2001 From: safiya2610 Date: Fri, 17 Jul 2026 15:42:03 +0530 Subject: [PATCH] Upgrade agent-sandbox to v0.5.2 and migrate to v1beta1 - Upgrade agent-sandbox dependency to v0.5.2 - Migrate integration from v1alpha1 to v1beta1 APIs - Update workload manager for WarmPool semantics - Regenerate generated client-go and CRD artifacts - Update code generation and Docker images - Fix informer startup, lint, and E2E issues - Address PR review comments Signed-off-by: Safiya <147792763+safiya2610@users.noreply.github.com> --- .../versioned/fake/clientset_generated.go | 2 +- .../informers/externalversions/factory.go | 110 +++++++++++++--- .../internalinterfaces/factory_interfaces.go | 19 +++ .../runtime/v1alpha1/agentruntime.go | 51 +++++--- .../runtime/v1alpha1/codeinterpreter.go | 51 +++++--- cmd/workload-manager/main.go | 10 +- docs/getting-started.md | 33 ++++- go.mod | 54 ++++---- go.sum | 120 +++++++++--------- hack/update-codegen.sh | 34 ++++- ...me.agentcube.volcano.sh_agentruntimes.yaml | 85 ++++++------- .../runtime/v1alpha1/groupversion_info.go | 2 +- pkg/router/server.go | 4 +- .../codeinterpreter_controller.go | 46 +++---- .../codeinterpreter_controller_test.go | 38 +++--- pkg/workloadmanager/handlers.go | 28 ++-- pkg/workloadmanager/handlers_test.go | 86 ++++++------- pkg/workloadmanager/informers.go | 4 +- pkg/workloadmanager/k8s_client.go | 22 ++-- pkg/workloadmanager/sandbox_controller.go | 6 +- pkg/workloadmanager/sandbox_helper.go | 10 +- pkg/workloadmanager/sandbox_helper_test.go | 118 ++++++++--------- pkg/workloadmanager/server.go | 4 +- pkg/workloadmanager/workload_builder.go | 72 ++++++----- pkg/workloadmanager/workload_builder_test.go | 54 ++++---- test/e2e/e2e_test.go | 30 ++--- test/e2e/run_e2e.sh | 8 +- 27 files changed, 641 insertions(+), 460 deletions(-) diff --git a/client-go/clientset/versioned/fake/clientset_generated.go b/client-go/clientset/versioned/fake/clientset_generated.go index f3a7b1ba9..f0b1a3f8d 100644 --- a/client-go/clientset/versioned/fake/clientset_generated.go +++ b/client-go/clientset/versioned/fake/clientset_generated.go @@ -79,7 +79,7 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } -// IsWatchListSemanticsSupported informs the reflector that this client +// IsWatchListSemanticsUnSupported informs the reflector that this client // doesn't support WatchList semantics. // // This is a synthetic method whose sole purpose is to satisfy the optional diff --git a/client-go/informers/externalversions/factory.go b/client-go/informers/externalversions/factory.go index 33e5338a6..1d5c517f4 100644 --- a/client-go/informers/externalversions/factory.go +++ b/client-go/informers/externalversions/factory.go @@ -19,6 +19,7 @@ limitations under the License. package externalversions import ( + context "context" reflect "reflect" sync "sync" time "time" @@ -29,6 +30,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" + wait "k8s.io/apimachinery/pkg/util/wait" cache "k8s.io/client-go/tools/cache" ) @@ -43,6 +45,7 @@ type sharedInformerFactory struct { defaultResync time.Duration customResync map[reflect.Type]time.Duration transform cache.TransformFunc + informerName *cache.InformerName informers map[reflect.Type]cache.SharedIndexInformer // startedInformers is used for tracking which informers have been started. @@ -89,6 +92,21 @@ func WithTransform(transform cache.TransformFunc) SharedInformerOption { } } +// WithInformerName sets the InformerName for informer identity used in metrics. +// The InformerName must be created via cache.NewInformerName() at startup, +// which validates global uniqueness. Each informer type will register its +// GVR under this name. +func WithInformerName(informerName *cache.InformerName) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.informerName = informerName + return factory + } +} + +func (f *sharedInformerFactory) InformerName() *cache.InformerName { + return f.informerName +} + // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { return NewSharedInformerFactoryWithOptions(client, defaultResync) @@ -123,6 +141,10 @@ func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResy } func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.StartWithContext(wait.ContextForChannel(stopCh)) +} + +func (f *sharedInformerFactory) StartWithContext(ctx context.Context) { f.lock.Lock() defer f.lock.Unlock() @@ -133,14 +155,10 @@ func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { for informerType, informer := range f.informers { if !f.startedInformers[informerType] { f.wg.Add(1) - // We need a new variable in each loop iteration, - // otherwise the goroutine would use the loop variable - // and that keeps changing. - informer := informer - go func() { + go func(informer cache.SharedIndexInformer) { defer f.wg.Done() - informer.Run(stopCh) - }() + informer.RunWithContext(ctx) + }(informer) f.startedInformers[informerType] = true } } @@ -153,9 +171,17 @@ func (f *sharedInformerFactory) Shutdown() { // Will return immediately if there is nothing to wait for. f.wg.Wait() + if f.informerName != nil { + f.informerName.Release() + } } func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + result := f.WaitForCacheSyncWithContext(wait.ContextForChannel(stopCh)) + return result.Synced +} + +func (f *sharedInformerFactory) WaitForCacheSyncWithContext(ctx context.Context) cache.SyncResult { informers := func() map[reflect.Type]cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() @@ -169,10 +195,31 @@ func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[ref return informers }() - res := map[reflect.Type]bool{} + // Wait for informers to sync, without polling. + cacheSyncs := make([]cache.DoneChecker, 0, len(informers)) + for _, informer := range informers { + cacheSyncs = append(cacheSyncs, informer.HasSyncedChecker()) + } + cache.WaitFor(ctx, "" /* no logging */, cacheSyncs...) + + res := cache.SyncResult{ + Synced: make(map[reflect.Type]bool, len(informers)), + } + failed := false for informType, informer := range informers { - res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + hasSynced := informer.HasSynced() + if !hasSynced { + failed = true + } + res.Synced[informType] = hasSynced } + if failed { + // context.Cause is more informative than ctx.Err(). + // This must be non-nil, otherwise WaitFor wouldn't have stopped + // prematurely. + res.Err = context.Cause(ctx) + } + return res } @@ -194,7 +241,9 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal } informer = newFunc(f.client, resyncPeriod) - informer.SetTransform(f.transform) + if f.transform != nil { + informer.SetTransform(f.transform) + } f.informers[informerType] = informer return informer @@ -211,27 +260,46 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal // defer factory.WaitForStop() // Returns immediately if nothing was started. // genericInformer := factory.ForResource(resource) // typedInformer := factory.SomeAPIGroup().V1().SomeType() -// factory.Start(ctx.Done()) // Start processing these informers. -// synced := factory.WaitForCacheSync(ctx.Done()) -// for v, ok := range synced { -// if !ok { -// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) -// return -// } +// handle, err := typeInformer.Informer().AddEventHandler(...) +// if err != nil { +// return fmt.Errorf("register event handler: %v", err) +// } +// defer typeInformer.Informer().RemoveEventHandler(handle) // Avoids leaking goroutines. +// factory.StartWithContext(ctx) // Start processing these informers. +// synced := factory.WaitForCacheSyncWithContext(ctx) +// if err := synced.AsError(); err != nil { +// return err +// } +// for v := range synced { +// // Only if desired log some information similar to this. +// fmt.Fprintf(os.Stdout, "cache synced: %s", v) +// } +// +// // Also make sure that all of the initial cache events have been delivered. +// if !WaitFor(ctx, "event handler sync", handle.HasSyncedChecker()) { +// // Must have failed because of context. +// return fmt.Errorf("sync event handler: %w", context.Cause(ctx)) // } // // // Creating informers can also be created after Start, but then // // Start must be called again: // anotherGenericInformer := factory.ForResource(resource) -// factory.Start(ctx.Done()) +// factory.StartWithContext(ctx) type SharedInformerFactory interface { internalinterfaces.SharedInformerFactory // Start initializes all requested informers. They are handled in goroutines // which run until the stop channel gets closed. // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + // + // Contextual logging: StartWithContext should be used instead of Start in code which supports contextual logging. Start(stopCh <-chan struct{}) + // StartWithContext initializes all requested informers. They are handled in goroutines + // which run until the context gets canceled. + // Warning: StartWithContext does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + StartWithContext(ctx context.Context) + // Shutdown marks a factory as shutting down. At that point no new // informers can be started anymore and Start will return without // doing anything. @@ -246,8 +314,14 @@ type SharedInformerFactory interface { // WaitForCacheSync blocks until all started informers' caches were synced // or the stop channel gets closed. + // + // Contextual logging: WaitForCacheSync should be used instead of WaitForCacheSync in code which supports contextual logging. It also returns a more useful result. WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + // WaitForCacheSyncWithContext blocks until all started informers' caches were synced + // or the context gets canceled. + WaitForCacheSyncWithContext(ctx context.Context) cache.SyncResult + // ForResource gives generic access to a shared informer of the matching type. ForResource(resource schema.GroupVersionResource) (GenericInformer, error) diff --git a/client-go/informers/externalversions/internalinterfaces/factory_interfaces.go b/client-go/informers/externalversions/internalinterfaces/factory_interfaces.go index abd4ae2b9..423cf1862 100644 --- a/client-go/informers/externalversions/internalinterfaces/factory_interfaces.go +++ b/client-go/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -34,7 +34,26 @@ type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexI type SharedInformerFactory interface { Start(stopCh <-chan struct{}) InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer + InformerName() *cache.InformerName } // TweakListOptionsFunc is a function that transforms a v1.ListOptions. type TweakListOptionsFunc func(*v1.ListOptions) + +// InformerOptions holds the options for creating an informer. +type InformerOptions struct { + // ResyncPeriod is the resync period for this informer. + // If not set, defaults to 0 (no resync). + ResyncPeriod time.Duration + + // Indexers are the indexers for this informer. + Indexers cache.Indexers + + // InformerName is used to uniquely identify this informer for metrics. + // If not set, metrics will not be published for this informer. + // Use cache.NewInformerName() to create an InformerName at startup. + InformerName *cache.InformerName + + // TweakListOptions is an optional function to modify the list options. + TweakListOptions TweakListOptionsFunc +} diff --git a/client-go/informers/externalversions/runtime/v1alpha1/agentruntime.go b/client-go/informers/externalversions/runtime/v1alpha1/agentruntime.go index 1c8743892..9ac38da2d 100644 --- a/client-go/informers/externalversions/runtime/v1alpha1/agentruntime.go +++ b/client-go/informers/externalversions/runtime/v1alpha1/agentruntime.go @@ -28,6 +28,7 @@ import ( apisruntimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" watch "k8s.io/apimachinery/pkg/watch" cache "k8s.io/client-go/tools/cache" ) @@ -49,48 +50,64 @@ type agentRuntimeInformer struct { // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewAgentRuntimeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredAgentRuntimeInformer(client, namespace, resyncPeriod, indexers, nil) + return NewAgentRuntimeInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers}) } // NewFilteredAgentRuntimeInformer constructs a new informer for AgentRuntime type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewFilteredAgentRuntimeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( + return NewAgentRuntimeInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions}) +} + +// NewAgentRuntimeInformerWithOptions constructs a new informer for AgentRuntime type with additional options. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewAgentRuntimeInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer { + gvr := schema.GroupVersionResource{Group: "runtime", Version: "v1alpha1", Resource: "agentruntimes"} + var identifier cache.InformerNameAndResource + if options.InformerName != nil { + identifier = options.InformerName.WithResource(gvr) + } + tweakListOptions := options.TweakListOptions + return cache.NewSharedIndexInformerWithOptions( cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + ListFunc: func(opts v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().AgentRuntimes(namespace).List(context.Background(), options) + return client.RuntimeV1alpha1().AgentRuntimes(namespace).List(context.Background(), opts) }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().AgentRuntimes(namespace).Watch(context.Background(), options) + return client.RuntimeV1alpha1().AgentRuntimes(namespace).Watch(context.Background(), opts) }, - ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().AgentRuntimes(namespace).List(ctx, options) + return client.RuntimeV1alpha1().AgentRuntimes(namespace).List(ctx, opts) }, - WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().AgentRuntimes(namespace).Watch(ctx, options) + return client.RuntimeV1alpha1().AgentRuntimes(namespace).Watch(ctx, opts) }, }, client), &apisruntimev1alpha1.AgentRuntime{}, - resyncPeriod, - indexers, + cache.SharedIndexInformerOptions{ + ResyncPeriod: options.ResyncPeriod, + Indexers: options.Indexers, + Identifier: identifier, + }, ) } func (f *agentRuntimeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredAgentRuntimeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) + return NewAgentRuntimeInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions}) } func (f *agentRuntimeInformer) Informer() cache.SharedIndexInformer { diff --git a/client-go/informers/externalversions/runtime/v1alpha1/codeinterpreter.go b/client-go/informers/externalversions/runtime/v1alpha1/codeinterpreter.go index 41c71b1ac..ac11726c5 100644 --- a/client-go/informers/externalversions/runtime/v1alpha1/codeinterpreter.go +++ b/client-go/informers/externalversions/runtime/v1alpha1/codeinterpreter.go @@ -28,6 +28,7 @@ import ( apisruntimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" watch "k8s.io/apimachinery/pkg/watch" cache "k8s.io/client-go/tools/cache" ) @@ -49,48 +50,64 @@ type codeInterpreterInformer struct { // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewCodeInterpreterInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredCodeInterpreterInformer(client, namespace, resyncPeriod, indexers, nil) + return NewCodeInterpreterInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers}) } // NewFilteredCodeInterpreterInformer constructs a new informer for CodeInterpreter type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewFilteredCodeInterpreterInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( + return NewCodeInterpreterInformerWithOptions(client, namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: indexers, TweakListOptions: tweakListOptions}) +} + +// NewCodeInterpreterInformerWithOptions constructs a new informer for CodeInterpreter type with additional options. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewCodeInterpreterInformerWithOptions(client versioned.Interface, namespace string, options internalinterfaces.InformerOptions) cache.SharedIndexInformer { + gvr := schema.GroupVersionResource{Group: "runtime", Version: "v1alpha1", Resource: "codeinterpreters"} + var identifier cache.InformerNameAndResource + if options.InformerName != nil { + identifier = options.InformerName.WithResource(gvr) + } + tweakListOptions := options.TweakListOptions + return cache.NewSharedIndexInformerWithOptions( cache.ToListWatcherWithWatchListSemantics(&cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + ListFunc: func(opts v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().CodeInterpreters(namespace).List(context.Background(), options) + return client.RuntimeV1alpha1().CodeInterpreters(namespace).List(context.Background(), opts) }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + WatchFunc: func(opts v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().CodeInterpreters(namespace).Watch(context.Background(), options) + return client.RuntimeV1alpha1().CodeInterpreters(namespace).Watch(context.Background(), opts) }, - ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + ListWithContextFunc: func(ctx context.Context, opts v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().CodeInterpreters(namespace).List(ctx, options) + return client.RuntimeV1alpha1().CodeInterpreters(namespace).List(ctx, opts) }, - WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + WatchFuncWithContext: func(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { - tweakListOptions(&options) + tweakListOptions(&opts) } - return client.RuntimeV1alpha1().CodeInterpreters(namespace).Watch(ctx, options) + return client.RuntimeV1alpha1().CodeInterpreters(namespace).Watch(ctx, opts) }, }, client), &apisruntimev1alpha1.CodeInterpreter{}, - resyncPeriod, - indexers, + cache.SharedIndexInformerOptions{ + ResyncPeriod: options.ResyncPeriod, + Indexers: options.Indexers, + Identifier: identifier, + }, ) } func (f *codeInterpreterInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredCodeInterpreterInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) + return NewCodeInterpreterInformerWithOptions(client, f.namespace, internalinterfaces.InformerOptions{ResyncPeriod: resyncPeriod, Indexers: cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, InformerName: f.factory.InformerName(), TweakListOptions: f.tweakListOptions}) } func (f *codeInterpreterInformer) Informer() cache.SharedIndexInformer { diff --git a/cmd/workload-manager/main.go b/cmd/workload-manager/main.go index 7cfe2ea0e..399182144 100644 --- a/cmd/workload-manager/main.go +++ b/cmd/workload-manager/main.go @@ -29,8 +29,8 @@ import ( utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes/scheme" "k8s.io/klog/v2" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" @@ -46,8 +46,8 @@ var ( func init() { utilruntime.Must(scheme.AddToScheme(schemeBuilder)) - utilruntime.Must(sandboxv1alpha1.AddToScheme(schemeBuilder)) - utilruntime.Must(extensionsv1alpha1.AddToScheme(schemeBuilder)) + utilruntime.Must(sandboxv1beta1.AddToScheme(schemeBuilder)) + utilruntime.Must(extensionsv1beta1.AddToScheme(schemeBuilder)) utilruntime.Must(runtimev1alpha1.AddToScheme(schemeBuilder)) } @@ -187,7 +187,7 @@ func main() { func setupControllers(mgr ctrl.Manager, sandboxReconciler *workloadmanager.SandboxReconciler, codeInterpreterReconciler *workloadmanager.CodeInterpreterReconciler) error { // Setup Sandbox controller if err := ctrl.NewControllerManagedBy(mgr). - For(&sandboxv1alpha1.Sandbox{}). + For(&sandboxv1beta1.Sandbox{}). Complete(sandboxReconciler); err != nil { return fmt.Errorf("unable to create sandbox controller: %w", err) } diff --git a/docs/getting-started.md b/docs/getting-started.md index c4eeb3c7e..d6cd2b05e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -28,9 +28,8 @@ AgentCube relies on the [kubernetes-sigs/agent-sandbox](https://github.com/kuber ```bash # Install agent-sandbox CRDs and controller -AGENT_SANDBOX_VERSION=v0.1.1 -kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/manifest.yaml -kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/extensions.yaml +AGENT_SANDBOX_VERSION=v0.5.2 +kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/sandbox-with-extensions.yaml ``` Verify the installation: @@ -234,6 +233,29 @@ For detailed SDK usage, see the [Python SDK Guide](devguide/code-interpreter-pyt - [Using LangChain with CodeInterpreter](devguide/code-interpreter-using-langchain.md) - Integration guide - [Design Proposal](design/agentcube-proposal.md) - Architecture details +## Upgrading AgentCube and Agent Sandbox + +If you are upgrading from an older version of AgentCube that relied on `agent-sandbox` v0.4.6 to the new version that uses `v0.5.2` (and the `v1beta1` API), follow these steps to ensure active warm-started claims are preserved. + +> [!WARNING] +> Do not use `agent-sandbox` v0.5.0 or v0.5.1 during the upgrade. They contain known bugs that disrupt active warm-started claims. The target version must be `v0.5.2` or later. + +1. **Upgrade Agent Sandbox** + Apply the new `v0.5.2` all-in-one manifest. The old `manifest.yaml` and `extensions.yaml` have been consolidated into `sandbox-with-extensions.yaml`: + + ```bash + kubectl apply --server-side -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v0.5.2/sandbox-with-extensions.yaml + ``` + +2. **Upgrade AgentCube** + Upgrade your Helm release so AgentCube uses the `agent-sandbox` `v1beta1` resources (e.g., `Sandbox` / `SandboxClaim` / warm pool objects): + + ```bash + helm upgrade agentcube ./manifests/charts/base -n agentcube + ``` + +Because `agent-sandbox` v0.5.2 maintains backward compatibility with `v1alpha1` owner references from older SandboxClaims (via [issue #1124](https://github.com/kubernetes-sigs/agent-sandbox/pull/1124)), your active `CodeInterpreter` and `SandboxClaim` sessions will smoothly transition to the `v1beta1` API without cold-starting. + ## Cleanup To remove AgentCube from your cluster: @@ -241,7 +263,6 @@ To remove AgentCube from your cluster: ```bash helm uninstall agentcube -n agentcube kubectl delete namespace agentcube -AGENT_SANDBOX_VERSION=v0.1.1 -kubectl delete -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/extensions.yaml -kubectl delete -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/manifest.yaml +AGENT_SANDBOX_VERSION=v0.5.2 +kubectl delete -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/sandbox-with-extensions.yaml ``` diff --git a/go.mod b/go.mod index a2326605f..622553c64 100644 --- a/go.mod +++ b/go.mod @@ -6,22 +6,22 @@ require ( github.com/agiledragon/gomonkey/v2 v2.13.0 github.com/alicebob/miniredis/v2 v2.35.0 github.com/coreos/go-oidc/v3 v3.14.1 - github.com/fsnotify/fsnotify v1.9.0 + github.com/fsnotify/fsnotify v1.10.1 github.com/gin-contrib/gzip v1.0.1 github.com/gin-gonic/gin v1.10.0 - github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/uuid v1.6.0 github.com/redis/go-redis/v9 v9.17.1 github.com/stretchr/testify v1.11.1 github.com/valkey-io/valkey-go v1.0.69 - golang.org/x/net v0.52.0 - k8s.io/api v0.35.4 - k8s.io/apimachinery v0.35.4 - k8s.io/client-go v0.35.4 + golang.org/x/net v0.57.0 + k8s.io/api v0.36.2 + k8s.io/apimachinery v0.36.2 + k8s.io/client-go v0.36.2 k8s.io/klog/v2 v2.140.0 - k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 - sigs.k8s.io/agent-sandbox v0.4.6 - sigs.k8s.io/controller-runtime v0.23.3 + k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 + sigs.k8s.io/agent-sandbox v0.5.2 + sigs.k8s.io/controller-runtime v0.24.1 ) require ( @@ -31,7 +31,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect @@ -59,9 +59,7 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/goccy/go-json v0.10.2 // indirect - github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.7.0 // indirect - github.com/google/go-cmp v0.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -70,37 +68,37 @@ require ( github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.1 // indirect - github.com/prometheus/procfs v0.17.0 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - go.yaml.in/yaml/v2 v2.4.3 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.8.0 // indirect - golang.org/x/crypto v0.49.0 // indirect - golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/term v0.41.0 // indirect - golang.org/x/text v0.35.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/crypto v0.54.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.40.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/protobuf v1.36.11 // indirect + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.35.4 // indirect - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/apiextensions-apiserver v0.36.2 // indirect + k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index 3843ab4f6..4b3e1af83 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,9 @@ github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQ github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk= github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= @@ -33,8 +34,8 @@ github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8 github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho= +github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= @@ -93,10 +94,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= -github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -136,24 +135,25 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= -github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= -github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= -github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= +github.com/onsi/ginkgo/v2 v2.27.4 h1:fcEcQW/A++6aZAZQNUmNjvA9PSOzefMJBerHJ4t8v8Y= +github.com/onsi/ginkgo/v2 v2.27.4/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.39.0 h1:y2ROC3hKFmQZJNFeGAMeHZKkjBL65mIZcvrLQBF9k6Q= +github.com/onsi/gomega v1.39.0/go.mod h1:ZCU1pkQcXDO5Sl9/VVEGlDyp+zm0m1cmeG5TOzLgdh4= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= -github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= -github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= -github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEycfc= +github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/redis/go-redis/v9 v9.17.1 h1:7tl732FjYPRT9H9aNfyTwKg9iTETjWjGKEJ2t/5iWTs= github.com/redis/go-redis/v9 v9.17.1/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= @@ -190,46 +190,46 @@ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= -go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= -golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= +golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= -golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= -golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= -golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= -golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -240,31 +240,31 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.35.4 h1:P7nFYKl5vo9AGUp1Z+Pmd3p2tA7bX2wbFWCvDeRv988= -k8s.io/api v0.35.4/go.mod h1:yl4lqySWOgYJJf9RERXKUwE9g2y+CkuwG+xmcOK8wXU= -k8s.io/apiextensions-apiserver v0.35.4 h1:HeP+Upp7ItdvnyGmub0yoix+2z5+ev4M5cE5TCgtOUU= -k8s.io/apiextensions-apiserver v0.35.4/go.mod h1:ogQlk+stIE8mnoRthSYCwlOS12fVqgWFiErMwPaXA7c= -k8s.io/apimachinery v0.35.4 h1:xtdom9RG7e+yDp71uoXoJDWEE2eOiHgeO4GdBzwWpds= -k8s.io/apimachinery v0.35.4/go.mod h1:NNi1taPOpep0jOj+oRha3mBJPqvi0hGdaV8TCqGQ+cc= -k8s.io/client-go v0.35.4 h1:DN6fyaGuzK64UvnKO5fOA6ymSjvfGAnCAHAR0C66kD8= -k8s.io/client-go v0.35.4/go.mod h1:2Pg9WpsS4NeOpoYTfHHfMxBG8zFMSAUi4O/qoiJC3nY= +k8s.io/api v0.36.2 h1:TF6YDLIzKfccK7cq9YpTcGX8TJmEkHVRv78DM51fRYY= +k8s.io/api v0.36.2/go.mod h1:F4LbMO4brjZYh7yFkXWhynSvtB7YauxV4c+HHkNRGNg= +k8s.io/apiextensions-apiserver v0.36.2 h1:3O5gqOj/dt2XWWbpMe+TXWpE9yU6pjM/tXxtHHJT/K4= +k8s.io/apiextensions-apiserver v0.36.2/go.mod h1:cL1tBWe8XSaP1H30iWKGo7hf6iAUUUJPEU70dskmAnA= +k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= +k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= +k8s.io/client-go v0.36.2 h1:bfgxmFKc9CgqsgX4xKLAAdmTQlWee7Ob/HlDOrJ5TBI= +k8s.io/client-go v0.36.2/go.mod h1:1vgO4OAlfPnoLcb+Rze2GF5rAr14w8qjrYMoyXJzQj0= k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= -k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= -k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= -k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= -k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU= +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/agent-sandbox v0.4.6 h1:dUUvQ+rlv4kT3CB9p2MgnPcNSMAQg6eTBrWyCiYgxYs= -sigs.k8s.io/agent-sandbox v0.4.6/go.mod h1:rrBXoA+nKZO2MIs3pTG+qOuKadX5gzMvO/nrlwC9W1w= -sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80= -sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0= +sigs.k8s.io/agent-sandbox v0.5.2 h1:ghR6uyWAfC6fI1rZZPse6Y4phr6Sfx7ywzv9LAWQC54= +sigs.k8s.io/agent-sandbox v0.5.2/go.mod h1:mHia5bO+cL9jMqqcqjNBQOdraOfiQ+7Jwz6eq8nwS/0= +sigs.k8s.io/controller-runtime v0.24.1 h1:miPEwrmirImAvgME1L9qebGHrOnGJoVmVdtOU9fRfo4= +sigs.k8s.io/controller-runtime v0.24.1/go.mod h1:vFkfY5fGt5xAC/sKb8IBFKgWPNKG9OUG29dR8Y2wImw= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482 h1:2WOzJpHUBVrrkDjU4KBT8n5LDcj824eX0I5UKcgeRUs= -sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index ae3a10dcc..9e751371b 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -12,7 +12,7 @@ export GO111MODULE=on # Find code-generator CODEGEN_PKG="" -CODEGEN_VERSION="v0.35.4" +CODEGEN_VERSION="v0.36.2" # Try vendor directory first if [ -d "vendor/k8s.io/code-generator" ]; then @@ -77,4 +77,36 @@ find "${SCRIPT_ROOT}/client-go/listers" -name "*.go" -type f | while read -r fil fi done +echo "Applying informer-gen compatibility fixes..." +python3 - "$SCRIPT_ROOT" <<'PY' +import sys +from pathlib import Path + +root = Path(sys.argv[1]) + +factory_path = root / "client-go/informers/externalversions/factory.go" +factory_text = factory_path.read_text() +factory_text = factory_text.replace( + 'f.wg.Go(func() {\n\t\t\t\tinformer.RunWithContext(ctx)\n\t\t\t})', + 'f.wg.Add(1)\n\t\t\tgo func(informer cache.SharedIndexInformer) {\n\t\t\t\tdefer f.wg.Done()\n\t\t\t\tinformer.RunWithContext(ctx)\n\t\t\t}(informer)', +) +factory_text = factory_text.replace( + '\tf.informerName.Release()\n', + '\tif f.informerName != nil {\n\t\tf.informerName.Release()\n\t}\n', +) +factory_path.write_text(factory_text) + +for rel_path in [ + "client-go/informers/externalversions/runtime/v1alpha1/agentruntime.go", + "client-go/informers/externalversions/runtime/v1alpha1/codeinterpreter.go", +]: + path = root / rel_path + text = path.read_text() + text = text.replace( + 'identifier := options.InformerName.WithResource(gvr)\n', + 'var identifier cache.InformerNameAndResource\n\tif options.InformerName != nil {\n\t\tidentifier = options.InformerName.WithResource(gvr)\n\t}\n', + ) + path.write_text(text) +PY + echo "Client-go code generation completed!" diff --git a/manifests/charts/base/crds/runtime.agentcube.volcano.sh_agentruntimes.yaml b/manifests/charts/base/crds/runtime.agentcube.volcano.sh_agentruntimes.yaml index de219e65d..0bd45a4d6 100644 --- a/manifests/charts/base/crds/runtime.agentcube.volcano.sh_agentruntimes.yaml +++ b/manifests/charts/base/crds/runtime.agentcube.volcano.sh_agentruntimes.yaml @@ -2117,7 +2117,6 @@ spec: procMount denotes the type of proc mount to use for the containers. The default value is Default which uses the container runtime defaults for readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. type: string readOnlyRootFilesystem: @@ -3688,7 +3687,6 @@ spec: procMount denotes the type of proc mount to use for the containers. The default value is Default which uses the container runtime defaults for readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. type: string readOnlyRootFilesystem: @@ -4172,7 +4170,6 @@ spec: When set to false, a new userns is created for the pod. Setting false is useful for mitigating container breakout vulnerabilities even allowing users to run their containers as root without actually having root privileges on the host. - This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. type: boolean hostname: description: |- @@ -5342,7 +5339,6 @@ spec: procMount denotes the type of proc mount to use for the containers. The default value is Default which uses the container runtime defaults for readonly paths and masked paths. - This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows. type: string readOnlyRootFilesystem: @@ -5911,6 +5907,14 @@ spec: It adds a name to it that uniquely identifies the ResourceClaim inside the Pod. Containers that need access to the ResourceClaim reference it with this name. + + When the DRAWorkloadResourceClaims feature gate is enabled and this Pod + belongs to a PodGroup, a PodResourceClaim is matched to a + PodGroupResourceClaim if all of their fields are equal (Name, + ResourceClaimName, and ResourceClaimTemplateName). A matched claim references + a single ResourceClaim shared across all Pods in the PodGroup, reserved for + the PodGroup in ResourceClaimStatus.ReservedFor rather than for individual + Pods. properties: name: description: |- @@ -5936,6 +5940,16 @@ spec: generated component, will be used to form a unique name for the ResourceClaim, which will be recorded in pod.status.resourceClaimStatuses. + When the DRAWorkloadResourceClaims feature gate is enabled and the pod + belongs to a PodGroup that defines a PodGroupResourceClaim with the same + Name and ResourceClaimTemplateName, this PodResourceClaim resolves to the + ResourceClaim generated for the PodGroup. All pods in the group that + define an equivalent PodResourceClaim matching the + PodGroupResourceClaim's Name and ResourceClaimTemplateName share the same + generated ResourceClaim. ResourceClaims generated for a PodGroup are + owned by the PodGroup and their lifecycles are tied to the PodGroup + instead of any individual pod. + This field is immutable and no changes will be made to the corresponding ResourceClaim by the control plane after creating the ResourceClaim. @@ -6061,6 +6075,28 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map + schedulingGroup: + description: |- + SchedulingGroup provides a reference to the immediate scheduling runtime + grouping object that this Pod belongs to. + This field is used by the scheduler to identify the group and apply the + correct group scheduling policies. The association with a group also + impacts other lifecycle aspects of a Pod that are relevant in a wider context + of scheduling like preemption, resource attachment, etc. If not specified, + the Pod is treated as a single unit in all of these aspects. + The group object referenced by this field may not exist at the time the + Pod is created. + This field is immutable, but a group object with the same name may be + recreated with different policies. Doing this during pod scheduling + may result in the placement not conforming to the expected policies. + properties: + podGroupName: + description: |- + PodGroupName specifies the name of the standalone PodGroup object + that represents the runtime instance of this group. + Must be a DNS subdomain. + type: string + type: object securityContext: description: |- SecurityContext holds pod-level security attributes and common container settings. @@ -7489,7 +7525,7 @@ spec: A failure to resolve or pull the image during pod startup will block containers from starting and may add significant latency. Failures will be retried using normal volume backoff and will be reported on the pod reason and message. The types of objects that may be mounted by this volume are defined by the container runtime implementation on a host machine and at minimum must include all valid types supported by the container image field. The OCI object gets mounted in a single directory (spec.containers[*].volumeMounts.mountPath) by merging the manifest layers in the same way as for container images. - The volume will be mounted read-only (ro) and non-executable files (noexec). + The volume will be mounted read-only (ro). Sub path mounts for containers are not supported (spec.containers[*].volumeMounts.subpath) before 1.33. The field spec.securityContext.fsGroupChangePolicy has no effect on this volume type. properties: @@ -7661,8 +7697,7 @@ spec: description: |- portworxVolume represents a portworx volume attached and mounted on kubelets host machine. Deprecated: PortworxVolume is deprecated. All operations for the in-tree portworxVolume type - are redirected to the pxd.portworx.com CSI driver when the CSIMigrationPortworx feature-gate - is on. + are redirected to the pxd.portworx.com CSI driver. properties: fsType: description: |- @@ -8485,42 +8520,6 @@ spec: x-kubernetes-list-map-keys: - name x-kubernetes-list-type: map - workloadRef: - description: |- - WorkloadRef provides a reference to the Workload object that this Pod belongs to. - This field is used by the scheduler to identify the PodGroup and apply the - correct group scheduling policies. The Workload object referenced - by this field may not exist at the time the Pod is created. - This field is immutable, but a Workload object with the same name - may be recreated with different policies. Doing this during pod scheduling - may result in the placement not conforming to the expected policies. - properties: - name: - description: |- - Name defines the name of the Workload object this Pod belongs to. - Workload must be in the same namespace as the Pod. - If it doesn't match any existing Workload, the Pod will remain unschedulable - until a Workload object is created and observed by the kube-scheduler. - It must be a DNS subdomain. - type: string - podGroup: - description: |- - PodGroup is the name of the PodGroup within the Workload that this Pod - belongs to. If it doesn't match any existing PodGroup within the Workload, - the Pod will remain unschedulable until the Workload object is recreated - and observed by the kube-scheduler. It must be a DNS label. - type: string - podGroupReplicaKey: - description: |- - PodGroupReplicaKey specifies the replica key of the PodGroup to which this - Pod belongs. It is used to distinguish pods belonging to different replicas - of the same pod group. The pod group policy is applied separately to each replica. - When set, it must be a DNS label. - type: string - required: - - name - - podGroup - type: object required: - containers type: object diff --git a/pkg/apis/runtime/v1alpha1/groupversion_info.go b/pkg/apis/runtime/v1alpha1/groupversion_info.go index 83cfd29e9..c97ae32fa 100644 --- a/pkg/apis/runtime/v1alpha1/groupversion_info.go +++ b/pkg/apis/runtime/v1alpha1/groupversion_info.go @@ -30,7 +30,7 @@ var ( GroupVersion = schema.GroupVersion{Group: "runtime.agentcube.volcano.sh", Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} //nolint:staticcheck // SA1019: controller-runtime scheme.Builder is deprecated; kept for compatibility with kubebuilder-style scheme registration // AddToScheme adds the types in this group-version to the given scheme. AddToScheme = SchemeBuilder.AddToScheme diff --git a/pkg/router/server.go b/pkg/router/server.go index 53107fcdc..b50e4287a 100644 --- a/pkg/router/server.go +++ b/pkg/router/server.go @@ -27,7 +27,7 @@ import ( "github.com/volcano-sh/agentcube/pkg/store" "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" + "golang.org/x/net/http2/h2c" //nolint:staticcheck // SA1019: required for h2c (HTTP/2 cleartext) support; no stdlib alternative exists in current architecture ) // Server is the main structure for Router apiserver @@ -188,7 +188,7 @@ func (s *Server) Start(ctx context.Context) error { h2s := &http2.Server{} // Wrap handler with h2c for HTTP/2 cleartext support - h2cHandler := h2c.NewHandler(s.engine, h2s) + h2cHandler := h2c.NewHandler(s.engine, h2s) //nolint:staticcheck // SA1019: required for h2c (HTTP/2 cleartext) support; no stdlib alternative exists in current architecture s.httpServer = &http.Server{ Addr: addr, diff --git a/pkg/workloadmanager/codeinterpreter_controller.go b/pkg/workloadmanager/codeinterpreter_controller.go index bce73a0d5..948a220df 100644 --- a/pkg/workloadmanager/codeinterpreter_controller.go +++ b/pkg/workloadmanager/codeinterpreter_controller.go @@ -36,11 +36,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" runtimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ) -const codeInterpreterNetworkPolicyManagement = extensionsv1alpha1.NetworkPolicyManagementUnmanaged +const codeInterpreterNetworkPolicyManagement = extensionsv1beta1.NetworkPolicyManagementUnmanaged // CodeInterpreterReconciler reconciles a CodeInterpreter object type CodeInterpreterReconciler struct { @@ -143,7 +143,7 @@ func (r *CodeInterpreterReconciler) ensureSandboxTemplate(ctx context.Context, c } templateName := ci.Name - sandboxTemplate := &extensionsv1alpha1.SandboxTemplate{} + sandboxTemplate := &extensionsv1beta1.SandboxTemplate{} err := r.Get(ctx, types.NamespacedName{Name: templateName, Namespace: ci.Namespace}, sandboxTemplate) // Convert CodeInterpreterSandboxTemplate to PodTemplate @@ -151,13 +151,15 @@ func (r *CodeInterpreterReconciler) ensureSandboxTemplate(ctx context.Context, c if errors.IsNotFound(err) { // Create new SandboxTemplate - sandboxTemplate = &extensionsv1alpha1.SandboxTemplate{ + sandboxTemplate = &extensionsv1beta1.SandboxTemplate{ ObjectMeta: metav1.ObjectMeta{ Name: templateName, Namespace: ci.Namespace, }, - Spec: extensionsv1alpha1.SandboxTemplateSpec{ - PodTemplate: podTemplate, + Spec: extensionsv1beta1.SandboxTemplateSpec{ + SandboxBlueprint: sandboxv1beta1.SandboxBlueprint{ + PodTemplate: podTemplate, + }, NetworkPolicyManagement: codeInterpreterNetworkPolicyManagement, }, } @@ -179,8 +181,8 @@ func (r *CodeInterpreterReconciler) ensureSandboxTemplate(ctx context.Context, c // Update existing SandboxTemplate if needed. needsUpdate := false - if !r.podTemplateEqual(sandboxTemplate.Spec.PodTemplate, podTemplate) { - sandboxTemplate.Spec.PodTemplate = podTemplate + if !r.podTemplateEqual(sandboxTemplate.Spec.SandboxBlueprint.PodTemplate, podTemplate) { + sandboxTemplate.Spec.SandboxBlueprint.PodTemplate = podTemplate needsUpdate = true } if sandboxTemplate.Spec.NetworkPolicyManagement != codeInterpreterNetworkPolicyManagement { @@ -204,19 +206,19 @@ func (r *CodeInterpreterReconciler) ensureSandboxWarmPool(ctx context.Context, c templateName := ci.Name warmPoolName := ci.Name - warmPool := &extensionsv1alpha1.SandboxWarmPool{} + warmPool := &extensionsv1beta1.SandboxWarmPool{} err := r.Get(ctx, types.NamespacedName{Name: warmPoolName, Namespace: ci.Namespace}, warmPool) if errors.IsNotFound(err) { // Create new SandboxWarmPool - warmPool = &extensionsv1alpha1.SandboxWarmPool{ + warmPool = &extensionsv1beta1.SandboxWarmPool{ ObjectMeta: metav1.ObjectMeta{ Name: warmPoolName, Namespace: ci.Namespace, }, - Spec: extensionsv1alpha1.SandboxWarmPoolSpec{ - Replicas: *ci.Spec.WarmPoolSize, - TemplateRef: extensionsv1alpha1.SandboxTemplateRef{ + Spec: extensionsv1beta1.SandboxWarmPoolSpec{ + Replicas: ci.Spec.WarmPoolSize, + TemplateRef: extensionsv1beta1.SandboxTemplateRef{ Name: templateName, }, }, @@ -239,8 +241,8 @@ func (r *CodeInterpreterReconciler) ensureSandboxWarmPool(ctx context.Context, c // Update existing SandboxWarmPool if needed needsUpdate := false - if warmPool.Spec.Replicas != *ci.Spec.WarmPoolSize { - warmPool.Spec.Replicas = *ci.Spec.WarmPoolSize + if warmPool.Spec.Replicas == nil || *warmPool.Spec.Replicas != *ci.Spec.WarmPoolSize { + warmPool.Spec.Replicas = ci.Spec.WarmPoolSize needsUpdate = true } if warmPool.Spec.TemplateRef.Name != templateName { @@ -260,7 +262,7 @@ func (r *CodeInterpreterReconciler) ensureSandboxWarmPool(ctx context.Context, c // deleteSandboxWarmPool deletes the SandboxWarmPool if it exists func (r *CodeInterpreterReconciler) deleteSandboxWarmPool(ctx context.Context, ci *runtimev1alpha1.CodeInterpreter) error { warmPoolName := ci.Name - warmPool := &extensionsv1alpha1.SandboxWarmPool{} + warmPool := &extensionsv1beta1.SandboxWarmPool{} err := r.Get(ctx, types.NamespacedName{Name: warmPoolName, Namespace: ci.Namespace}, warmPool) if errors.IsNotFound(err) { return nil @@ -280,7 +282,7 @@ func (r *CodeInterpreterReconciler) deleteSandboxWarmPool(ctx context.Context, c // deleteSandboxTemplate deletes the SandboxTemplate if it exists func (r *CodeInterpreterReconciler) deleteSandboxTemplate(ctx context.Context, ci *runtimev1alpha1.CodeInterpreter) error { templateName := ci.Name - sandboxTemplate := &extensionsv1alpha1.SandboxTemplate{} + sandboxTemplate := &extensionsv1beta1.SandboxTemplate{} err := r.Get(ctx, types.NamespacedName{Name: templateName, Namespace: ci.Namespace}, sandboxTemplate) if errors.IsNotFound(err) { return nil @@ -297,8 +299,8 @@ func (r *CodeInterpreterReconciler) deleteSandboxTemplate(ctx context.Context, c return nil } -// convertToPodTemplate converts CodeInterpreterSandboxTemplate to sandboxv1alpha1.PodTemplate -func (r *CodeInterpreterReconciler) convertToPodTemplate(template *runtimev1alpha1.CodeInterpreterSandboxTemplate, ci *runtimev1alpha1.CodeInterpreter) sandboxv1alpha1.PodTemplate { +// convertToPodTemplate converts CodeInterpreterSandboxTemplate to sandboxv1beta1.PodTemplate +func (r *CodeInterpreterReconciler) convertToPodTemplate(template *runtimev1alpha1.CodeInterpreterSandboxTemplate, ci *runtimev1alpha1.CodeInterpreter) sandboxv1beta1.PodTemplate { // Normalize RuntimeClassName: if it's an empty string, set it to nil runtimeClassName := template.RuntimeClassName if runtimeClassName != nil && *runtimeClassName == "" { @@ -333,13 +335,13 @@ func (r *CodeInterpreterReconciler) convertToPodTemplate(template *runtimev1alph RuntimeClassName: runtimeClassName, } - return sandboxv1alpha1.PodTemplate{ + return sandboxv1beta1.PodTemplate{ Spec: podSpec, } } // podTemplateEqual checks if two PodTemplates are equal -func (r *CodeInterpreterReconciler) podTemplateEqual(a, b sandboxv1alpha1.PodTemplate) bool { +func (r *CodeInterpreterReconciler) podTemplateEqual(a, b sandboxv1beta1.PodTemplate) bool { // Use reflect.DeepEqual for a comprehensive comparison. return reflect.DeepEqual(a.Spec, b.Spec) } diff --git a/pkg/workloadmanager/codeinterpreter_controller_test.go b/pkg/workloadmanager/codeinterpreter_controller_test.go index b33c65b2e..44eee7d1e 100644 --- a/pkg/workloadmanager/codeinterpreter_controller_test.go +++ b/pkg/workloadmanager/codeinterpreter_controller_test.go @@ -28,14 +28,14 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" runtimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ) func setupTestReconciler() *CodeInterpreterReconciler { scheme := runtime.NewScheme() _ = runtimev1alpha1.AddToScheme(scheme) - _ = sandboxv1alpha1.AddToScheme(scheme) + _ = sandboxv1beta1.AddToScheme(scheme) _ = corev1.AddToScheme(scheme) client := fake.NewClientBuilder().WithScheme(scheme).Build() @@ -49,8 +49,8 @@ func setupTestReconciler() *CodeInterpreterReconciler { func newTestReconcilerWithObjects(objects ...runtime.Object) *CodeInterpreterReconciler { scheme := runtime.NewScheme() _ = runtimev1alpha1.AddToScheme(scheme) - _ = sandboxv1alpha1.AddToScheme(scheme) - _ = extensionsv1alpha1.AddToScheme(scheme) + _ = sandboxv1beta1.AddToScheme(scheme) + _ = extensionsv1beta1.AddToScheme(scheme) _ = corev1.AddToScheme(scheme) client := fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(objects...).Build() @@ -90,30 +90,32 @@ func TestEnsureSandboxTemplateDisablesAgentSandboxDefaultNetworkPolicy(t *testin _, err := reconciler.ensureSandboxTemplate(context.Background(), ci) assert.NoError(t, err) - sandboxTemplate := &extensionsv1alpha1.SandboxTemplate{} + sandboxTemplate := &extensionsv1beta1.SandboxTemplate{} err = reconciler.Get(context.Background(), types.NamespacedName{ Name: ci.Name, Namespace: ci.Namespace, }, sandboxTemplate) assert.NoError(t, err) - assert.Equal(t, extensionsv1alpha1.NetworkPolicyManagementUnmanaged, sandboxTemplate.Spec.NetworkPolicyManagement) + assert.Equal(t, extensionsv1beta1.NetworkPolicyManagementUnmanaged, sandboxTemplate.Spec.NetworkPolicyManagement) } func TestEnsureSandboxTemplateUpdatesManagedNetworkPolicyToUnmanaged(t *testing.T) { ci := testCodeInterpreterWithWarmPool() - existing := &extensionsv1alpha1.SandboxTemplate{ + existing := &extensionsv1beta1.SandboxTemplate{ ObjectMeta: metav1.ObjectMeta{ Name: ci.Name, Namespace: ci.Namespace, }, - Spec: extensionsv1alpha1.SandboxTemplateSpec{ - NetworkPolicyManagement: extensionsv1alpha1.NetworkPolicyManagementManaged, - PodTemplate: sandboxv1alpha1.PodTemplate{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{{ - Name: "codeinterpreter", - Image: "stale-image", - }}, + Spec: extensionsv1beta1.SandboxTemplateSpec{ + NetworkPolicyManagement: extensionsv1beta1.NetworkPolicyManagementManaged, + SandboxBlueprint: sandboxv1beta1.SandboxBlueprint{ + PodTemplate: sandboxv1beta1.PodTemplate{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "codeinterpreter", + Image: "stale-image", + }}, + }, }, }, }, @@ -123,13 +125,13 @@ func TestEnsureSandboxTemplateUpdatesManagedNetworkPolicyToUnmanaged(t *testing. _, err := reconciler.ensureSandboxTemplate(context.Background(), ci) assert.NoError(t, err) - sandboxTemplate := &extensionsv1alpha1.SandboxTemplate{} + sandboxTemplate := &extensionsv1beta1.SandboxTemplate{} err = reconciler.Get(context.Background(), types.NamespacedName{ Name: ci.Name, Namespace: ci.Namespace, }, sandboxTemplate) assert.NoError(t, err) - assert.Equal(t, extensionsv1alpha1.NetworkPolicyManagementUnmanaged, sandboxTemplate.Spec.NetworkPolicyManagement) + assert.Equal(t, extensionsv1beta1.NetworkPolicyManagementUnmanaged, sandboxTemplate.Spec.NetworkPolicyManagement) } func TestConvertToPodTemplate_RuntimeClassName_TableDriven(t *testing.T) { diff --git a/pkg/workloadmanager/handlers.go b/pkg/workloadmanager/handlers.go index 52f85eb2e..ae4de8668 100644 --- a/pkg/workloadmanager/handlers.go +++ b/pkg/workloadmanager/handlers.go @@ -29,8 +29,8 @@ import ( utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/client-go/dynamic" "k8s.io/klog/v2" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" "github.com/volcano-sh/agentcube/pkg/api" "github.com/volcano-sh/agentcube/pkg/common/types" @@ -158,8 +158,8 @@ func (s *Server) handleSandboxCreate(c *gin.Context, kind string) { return } - var sandbox *sandboxv1alpha1.Sandbox - var sandboxClaim *extensionsv1alpha1.SandboxClaim + var sandbox *sandboxv1beta1.Sandbox + var sandboxClaim *extensionsv1beta1.SandboxClaim var sandboxEntry *sandboxEntry var err error @@ -240,7 +240,7 @@ func resolveSandboxOwnerID(r *http.Request) (string, int, string) { return "", http.StatusUnauthorized, "invalid identity token" } -func (s *Server) respondSandboxCreateError(c *gin.Context, sandbox *sandboxv1alpha1.Sandbox, err error) { +func (s *Server) respondSandboxCreateError(c *gin.Context, sandbox *sandboxv1beta1.Sandbox, err error) { if errors.Is(err, context.Canceled) { klog.Warningf("create sandbox aborted %s/%s: client disconnected", sandbox.Namespace, sandbox.Name) c.AbortWithStatus(499) @@ -273,7 +273,7 @@ func isInternalSandboxCreateError(err error) bool { } // createK8sResources creates the K8s sandbox or sandbox claim resource. -func (s *Server) createK8sResources(ctx context.Context, dynamicClient dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox, sandboxClaim *extensionsv1alpha1.SandboxClaim) error { +func (s *Server) createK8sResources(ctx context.Context, dynamicClient dynamic.Interface, sandbox *sandboxv1beta1.Sandbox, sandboxClaim *extensionsv1beta1.SandboxClaim) error { if sandboxClaim != nil { if err := createSandboxClaim(ctx, dynamicClient, sandboxClaim); err != nil { if isContextError(err) { @@ -292,7 +292,7 @@ func (s *Server) createK8sResources(ctx context.Context, dynamicClient dynamic.I return nil } -func (s *Server) waitForDirectSandboxReady(ctx context.Context, sandbox *sandboxv1alpha1.Sandbox, resultChan <-chan SandboxStatusUpdate) (*sandboxv1alpha1.Sandbox, error) { +func (s *Server) waitForDirectSandboxReady(ctx context.Context, sandbox *sandboxv1beta1.Sandbox, resultChan <-chan SandboxStatusUpdate) (*sandboxv1beta1.Sandbox, error) { if resultChan == nil { return nil, errSandboxReadyWatcherNotRegistered } @@ -324,11 +324,11 @@ func (s *Server) waitForDirectSandboxReady(ctx context.Context, sandbox *sandbox } } -func (s *Server) waitForClaimSandboxReady(ctx context.Context, dynamicClient dynamic.Interface, sandboxClaim *extensionsv1alpha1.SandboxClaim) (*sandboxv1alpha1.Sandbox, error) { +func (s *Server) waitForClaimSandboxReady(ctx context.Context, dynamicClient dynamic.Interface, sandboxClaim *extensionsv1beta1.SandboxClaim) (*sandboxv1beta1.Sandbox, error) { return s.waitForClaimSandboxReadyWithTimeout(ctx, dynamicClient, sandboxClaim, sandboxCreationTimeout) } -func (s *Server) waitForClaimSandboxReadyWithTimeout(ctx context.Context, dynamicClient dynamic.Interface, sandboxClaim *extensionsv1alpha1.SandboxClaim, timeout time.Duration) (*sandboxv1alpha1.Sandbox, error) { +func (s *Server) waitForClaimSandboxReadyWithTimeout(ctx context.Context, dynamicClient dynamic.Interface, sandboxClaim *extensionsv1beta1.SandboxClaim, timeout time.Duration) (*sandboxv1beta1.Sandbox, error) { waitCtx, cancel := context.WithTimeoutCause(ctx, timeout, errSandboxCreationTimeout) defer cancel() ticker := time.NewTicker(1 * time.Second) @@ -380,7 +380,7 @@ func (s *Server) waitForClaimSandboxReadyWithTimeout(ctx context.Context, dynami } } -func (s *Server) waitForCreatedSandbox(ctx context.Context, dynamicClient dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox, sandboxClaim *extensionsv1alpha1.SandboxClaim, resultChan <-chan SandboxStatusUpdate) (*sandboxv1alpha1.Sandbox, error) { +func (s *Server) waitForCreatedSandbox(ctx context.Context, dynamicClient dynamic.Interface, sandbox *sandboxv1beta1.Sandbox, sandboxClaim *extensionsv1beta1.SandboxClaim, resultChan <-chan SandboxStatusUpdate) (*sandboxv1beta1.Sandbox, error) { if sandboxClaim != nil { return s.waitForClaimSandboxReady(ctx, dynamicClient, sandboxClaim) } @@ -388,7 +388,7 @@ func (s *Server) waitForCreatedSandbox(ctx context.Context, dynamicClient dynami } // createSandbox performs sandbox creation and returns the response payload or an error with an HTTP status code. -func (s *Server) createSandbox(ctx context.Context, dynamicClient dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox, sandboxClaim *extensionsv1alpha1.SandboxClaim, sandboxEntry *sandboxEntry, resultChan <-chan SandboxStatusUpdate) (*types.CreateSandboxResponse, error) { +func (s *Server) createSandbox(ctx context.Context, dynamicClient dynamic.Interface, sandbox *sandboxv1beta1.Sandbox, sandboxClaim *extensionsv1beta1.SandboxClaim, sandboxEntry *sandboxEntry, resultChan <-chan SandboxStatusUpdate) (*types.CreateSandboxResponse, error) { placeholder := buildSandboxPlaceHolder(sandbox, sandboxEntry) if err := s.storeClient.StoreSandbox(ctx, placeholder); err != nil { if isContextError(err) { @@ -418,10 +418,10 @@ func (s *Server) createSandbox(ctx context.Context, dynamicClient dynamic.Interf // agent-sandbox creates a Pod with the same name as the Sandbox if no warm pool is used. // If a warm pool is used, the adopted Pod name is stored in - // sandboxv1alpha1.SandboxPodNameAnnotation. + // sandboxv1beta1.SandboxPodNameAnnotation. sandboxNameForPod := createdSandbox.Name sandboxPodName := createdSandbox.Name - if podName, exists := createdSandbox.Annotations[sandboxv1alpha1.SandboxPodNameAnnotation]; exists { + if podName, exists := createdSandbox.Annotations[sandboxv1beta1.SandboxPodNameAnnotation]; exists { sandboxPodName = podName } @@ -472,7 +472,7 @@ func (s *Server) createSandbox(ctx context.Context, dynamicClient dynamic.Interf // rollbackSandboxCreation deletes the sandbox (or sandbox claim) and its store // placeholder when creation fails. It runs in a fresh context so that a // canceled request context does not prevent cleanup. -func (s *Server) rollbackSandboxCreation(dynamicClient dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox, sandboxClaim *extensionsv1alpha1.SandboxClaim, sessionID string) { +func (s *Server) rollbackSandboxCreation(dynamicClient dynamic.Interface, sandbox *sandboxv1beta1.Sandbox, sandboxClaim *extensionsv1beta1.SandboxClaim, sessionID string) { ctxTimeout, cancel := context.WithTimeout(context.Background(), storeCleanupTimeout) defer cancel() if sandboxClaim != nil { diff --git a/pkg/workloadmanager/handlers_test.go b/pkg/workloadmanager/handlers_test.go index 2105967d5..2b5c5c42c 100644 --- a/pkg/workloadmanager/handlers_test.go +++ b/pkg/workloadmanager/handlers_test.go @@ -46,8 +46,8 @@ import ( dynamicfake "k8s.io/client-go/dynamic/fake" "k8s.io/client-go/rest" k8stesting "k8s.io/client-go/testing" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ) type fakeStore struct { @@ -86,17 +86,17 @@ func (f *fakeStore) UpdateSessionLastActivity(_ context.Context, _ string, _ tim } func (f *fakeStore) Close() error { return nil } -func readySandbox() *sandboxv1alpha1.Sandbox { - return &sandboxv1alpha1.Sandbox{ +func readySandbox() *sandboxv1beta1.Sandbox { + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "sandbox-1", Namespace: "ns-1", UID: "uid-123", - Annotations: map[string]string{sandboxv1alpha1.SandboxPodNameAnnotation: "pod-1"}, + Annotations: map[string]string{sandboxv1beta1.SandboxPodNameAnnotation: "pod-1"}, CreationTimestamp: metav1.Now(), }, - Status: sandboxv1alpha1.SandboxStatus{Conditions: []metav1.Condition{{ - Type: string(sandboxv1alpha1.SandboxConditionReady), + Status: sandboxv1beta1.SandboxStatus{Conditions: []metav1.Condition{{ + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }}}, } @@ -224,14 +224,14 @@ func TestServerCreateSandbox(t *testing.T) { patches := gomonkey.NewPatches() defer patches.Reset() - patches.ApplyFunc(createSandbox, func(_ context.Context, _ dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox) (*SandboxInfo, error) { + patches.ApplyFunc(createSandbox, func(_ context.Context, _ dynamic.Interface, sandbox *sandboxv1beta1.Sandbox) (*SandboxInfo, error) { createCalls++ if cur.createSandboxErr != nil { return nil, cur.createSandboxErr } return &SandboxInfo{Name: sandbox.Name, Namespace: sandbox.Namespace}, nil }) - patches.ApplyFunc(createSandboxClaim, func(_ context.Context, _ dynamic.Interface, _ *extensionsv1alpha1.SandboxClaim) error { + patches.ApplyFunc(createSandboxClaim, func(_ context.Context, _ dynamic.Interface, _ *extensionsv1beta1.SandboxClaim) error { claimCalls++ return cur.createClaimErr }) @@ -252,7 +252,7 @@ func TestServerCreateSandbox(t *testing.T) { patches.ApplyPrivateMethod(reflect.TypeOf(server), "waitForSandboxEntryPointsReady", func(_ *Server, _ context.Context, _ string, _ *sandboxEntry) error { return cur.readyErr }) - patches.ApplyPrivateMethod(reflect.TypeOf(server), "waitForCreatedSandbox", func(_ *Server, _ context.Context, _ dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox, _ *extensionsv1alpha1.SandboxClaim, resultChan <-chan SandboxStatusUpdate) (*sandboxv1alpha1.Sandbox, error) { + patches.ApplyPrivateMethod(reflect.TypeOf(server), "waitForCreatedSandbox", func(_ *Server, _ context.Context, _ dynamic.Interface, sandbox *sandboxv1beta1.Sandbox, _ *extensionsv1beta1.SandboxClaim, resultChan <-chan SandboxStatusUpdate) (*sandboxv1beta1.Sandbox, error) { if resultChan == nil { return readySandbox(), nil } @@ -281,9 +281,9 @@ func TestServerCreateSandbox(t *testing.T) { resultChan <- SandboxStatusUpdate{Sandbox: sb.DeepCopy()} } - claim := (*extensionsv1alpha1.SandboxClaim)(nil) + claim := (*extensionsv1beta1.SandboxClaim)(nil) if tt.sandboxClaim { - claim = &extensionsv1alpha1.SandboxClaim{ObjectMeta: metav1.ObjectMeta{Name: sb.Name, Namespace: sb.Namespace}} + claim = &extensionsv1beta1.SandboxClaim{ObjectMeta: metav1.ObjectMeta{Name: sb.Name, Namespace: sb.Namespace}} } resp, err := server.createSandbox(context.Background(), nil, sb, claim, makeEntry(), resultChan) @@ -316,17 +316,17 @@ func TestServerCreateSandbox(t *testing.T) { } func TestServerCreateSandboxClaimUsesAdoptedSandboxButStoresClaimName(t *testing.T) { - claim := &extensionsv1alpha1.SandboxClaim{ + claim := &extensionsv1beta1.SandboxClaim{ TypeMeta: metav1.TypeMeta{ - APIVersion: "extensions.agents.x-k8s.io/v1alpha1", + APIVersion: "extensions.agents.x-k8s.io/v1beta1", Kind: types.SandboxClaimsKind, }, ObjectMeta: metav1.ObjectMeta{ Name: "ci-claim", Namespace: "ns-1", }, - Status: extensionsv1alpha1.SandboxClaimStatus{ - SandboxStatus: extensionsv1alpha1.SandboxStatus{ + Status: extensionsv1beta1.SandboxClaimStatus{ + SandboxStatus: extensionsv1beta1.SandboxStatus{ Name: "warm-pool-sandbox-abc", }, }, @@ -337,7 +337,7 @@ func TestServerCreateSandboxClaimUsesAdoptedSandboxButStoresClaimName(t *testing adoptedSandboxUnstructured := &unstructured.Unstructured{ Object: map[string]interface{}{ - "apiVersion": "agents.x-k8s.io/v1alpha1", + "apiVersion": "agents.x-k8s.io/v1beta1", "kind": types.SandboxKind, "metadata": map[string]interface{}{ "name": "warm-pool-sandbox-abc", @@ -345,13 +345,13 @@ func TestServerCreateSandboxClaimUsesAdoptedSandboxButStoresClaimName(t *testing "uid": "adopted-uid", "creationTimestamp": metav1.Now().Format(time.RFC3339), "annotations": map[string]interface{}{ - sandboxv1alpha1.SandboxPodNameAnnotation: "warm-pool-pod-abc", + sandboxv1beta1.SandboxPodNameAnnotation: "warm-pool-pod-abc", }, }, "status": map[string]interface{}{ "conditions": []interface{}{ map[string]interface{}{ - "type": string(sandboxv1alpha1.SandboxConditionReady), + "type": string(sandboxv1beta1.SandboxConditionReady), "status": string(metav1.ConditionTrue), }, }, @@ -380,7 +380,7 @@ func TestServerCreateSandboxClaimUsesAdoptedSandboxButStoresClaimName(t *testing patches := gomonkey.NewPatches() defer patches.Reset() - patches.ApplyFunc(createSandboxClaim, func(_ context.Context, _ dynamic.Interface, _ *extensionsv1alpha1.SandboxClaim) error { + patches.ApplyFunc(createSandboxClaim, func(_ context.Context, _ dynamic.Interface, _ *extensionsv1beta1.SandboxClaim) error { return nil }) patches.ApplyFunc(deleteSandboxClaim, func(_ context.Context, _ dynamic.Interface, _, _ string) error { @@ -396,7 +396,7 @@ func TestServerCreateSandboxClaimUsesAdoptedSandboxButStoresClaimName(t *testing return nil }) - templateSandbox := &sandboxv1alpha1.Sandbox{ + templateSandbox := &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: claim.Name, Namespace: claim.Namespace, @@ -447,7 +447,7 @@ func TestWaitForDirectSandboxReadyWatcherFailures(t *testing.T) { } func TestWaitForClaimSandboxReadyReturnsForbidden(t *testing.T) { - claim := &extensionsv1alpha1.SandboxClaim{ + claim := &extensionsv1beta1.SandboxClaim{ ObjectMeta: metav1.ObjectMeta{Name: "ci-claim", Namespace: "ns-1"}, } dynamicClient := dynamicfake.NewSimpleDynamicClient(runtime.NewScheme()) @@ -474,10 +474,10 @@ func TestWaitForClaimSandboxReadyReturnsForbidden(t *testing.T) { } func TestWaitForClaimSandboxReadyReturnsSandboxForbidden(t *testing.T) { - claim := &extensionsv1alpha1.SandboxClaim{ + claim := &extensionsv1beta1.SandboxClaim{ ObjectMeta: metav1.ObjectMeta{Name: "ci-claim", Namespace: "ns-1"}, - Status: extensionsv1alpha1.SandboxClaimStatus{ - SandboxStatus: extensionsv1alpha1.SandboxStatus{Name: "adopted-sandbox"}, + Status: extensionsv1beta1.SandboxClaimStatus{ + SandboxStatus: extensionsv1beta1.SandboxStatus{Name: "adopted-sandbox"}, }, } claimObject, err := runtime.DefaultUnstructuredConverter.ToUnstructured(claim) @@ -516,12 +516,12 @@ func TestWaitForClaimSandboxReadyReturnsSandboxForbidden(t *testing.T) { } func TestWaitForClaimSandboxReadyReturnsConversionError(t *testing.T) { - claim := &extensionsv1alpha1.SandboxClaim{ + claim := &extensionsv1beta1.SandboxClaim{ ObjectMeta: metav1.ObjectMeta{Name: "ci-claim", Namespace: "ns-1"}, } malformedClaim := &unstructured.Unstructured{Object: map[string]interface{}{ - "apiVersion": "extensions.agents.x-k8s.io/v1alpha1", - "kind": "SandboxClaim", + "apiVersion": "extensions.agents.x-k8s.io/v1beta1", + "kind": types.SandboxClaimsKind, "metadata": map[string]interface{}{ "name": claim.Name, "namespace": claim.Namespace, @@ -593,14 +593,14 @@ func TestWaitForClaimSandboxReadyCancelsInFlightGet(t *testing.T) { apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if tt.blockSandbox && strings.Contains(r.URL.Path, "/sandboxclaims/") { w.Header().Set("Content-Type", "application/json") - _ = json.NewEncoder(w).Encode(&extensionsv1alpha1.SandboxClaim{ + _ = json.NewEncoder(w).Encode(&extensionsv1beta1.SandboxClaim{ TypeMeta: metav1.TypeMeta{ APIVersion: SandboxClaimGVR.Group + "/" + SandboxClaimGVR.Version, Kind: "SandboxClaim", }, ObjectMeta: metav1.ObjectMeta{Name: "ci-claim", Namespace: "ns-1"}, - Status: extensionsv1alpha1.SandboxClaimStatus{ - SandboxStatus: extensionsv1alpha1.SandboxStatus{Name: "sandbox-1"}, + Status: extensionsv1beta1.SandboxClaimStatus{ + SandboxStatus: extensionsv1beta1.SandboxStatus{Name: "sandbox-1"}, }, }) return @@ -616,7 +616,7 @@ func TestWaitForClaimSandboxReadyCancelsInFlightGet(t *testing.T) { dynamicClient, err := dynamic.NewForConfig(&rest.Config{Host: apiServer.URL}) require.NoError(t, err) - claim := &extensionsv1alpha1.SandboxClaim{ + claim := &extensionsv1beta1.SandboxClaim{ ObjectMeta: metav1.ObjectMeta{Name: "ci-claim", Namespace: "ns-1"}, } @@ -640,10 +640,10 @@ func TestWaitForClaimSandboxReadyCancelsInFlightGet(t *testing.T) { } func TestWaitForClaimSandboxReadyRejectsLateReadySandbox(t *testing.T) { - claim := &extensionsv1alpha1.SandboxClaim{ + claim := &extensionsv1beta1.SandboxClaim{ ObjectMeta: metav1.ObjectMeta{Name: "ci-claim", Namespace: "ns-1"}, - Status: extensionsv1alpha1.SandboxClaimStatus{ - SandboxStatus: extensionsv1alpha1.SandboxStatus{Name: "sandbox-1"}, + Status: extensionsv1beta1.SandboxClaimStatus{ + SandboxStatus: extensionsv1beta1.SandboxStatus{Name: "sandbox-1"}, }, } claimObject, err := runtime.DefaultUnstructuredConverter.ToUnstructured(claim) @@ -711,7 +711,7 @@ func newFakeServer() *Server { } } -func makeSandbox(kind, ns, name string) (*sandboxv1alpha1.Sandbox, *sandboxEntry) { +func makeSandbox(kind, ns, name string) (*sandboxv1beta1.Sandbox, *sandboxEntry) { entry := &sandboxEntry{ Kind: kind, SessionID: "sess-1", @@ -719,10 +719,10 @@ func makeSandbox(kind, ns, name string) (*sandboxv1alpha1.Sandbox, *sandboxEntry {Port: 8080, Protocol: runtimev1alpha1.ProtocolTypeHTTP, PathPrefix: "/api"}, }, } - return &sandboxv1alpha1.Sandbox{ + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns}, - Status: sandboxv1alpha1.SandboxStatus{Conditions: []metav1.Condition{{ - Type: string(sandboxv1alpha1.SandboxConditionReady), + Status: sandboxv1beta1.SandboxStatus{Conditions: []metav1.Condition{{ + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }}}, }, entry @@ -848,12 +848,12 @@ func TestHandleSandboxCreate(t *testing.T) { c.Request = req sb, entry := makeSandbox(tc.kind, "ns", "sandbox-1") - claim := &extensionsv1alpha1.SandboxClaim{ObjectMeta: metav1.ObjectMeta{Name: sb.Name, Namespace: sb.Namespace}} + claim := &extensionsv1beta1.SandboxClaim{ObjectMeta: metav1.ObjectMeta{Name: sb.Name, Namespace: sb.Namespace}} patches := gomonkey.NewPatches() defer patches.Reset() - patches.ApplyFunc(buildSandboxByAgentRuntime, func(_, _, _ string, _ *Informers) (*sandboxv1alpha1.Sandbox, *sandboxEntry, error) { + patches.ApplyFunc(buildSandboxByAgentRuntime, func(_, _, _ string, _ *Informers) (*sandboxv1beta1.Sandbox, *sandboxEntry, error) { if tc.kind != types.AgentRuntimeKind { return nil, nil, errors.New("unexpected kind") } @@ -863,7 +863,7 @@ func TestHandleSandboxCreate(t *testing.T) { return sb, entry, nil }) - patches.ApplyFunc(buildSandboxByCodeInterpreter, func(_, _, _ string, _ *Informers) (*sandboxv1alpha1.Sandbox, *extensionsv1alpha1.SandboxClaim, *sandboxEntry, error) { + patches.ApplyFunc(buildSandboxByCodeInterpreter, func(_, _, _ string, _ *Informers) (*sandboxv1beta1.Sandbox, *extensionsv1beta1.SandboxClaim, *sandboxEntry, error) { if tc.kind != types.CodeInterpreterKind { return nil, nil, nil, errors.New("unexpected kind") } @@ -874,7 +874,7 @@ func TestHandleSandboxCreate(t *testing.T) { }) createCalls := 0 - patches.ApplyPrivateMethod(reflect.TypeOf(fakeServer), "createSandbox", func(_ *Server, _ context.Context, _ dynamic.Interface, _ *sandboxv1alpha1.Sandbox, _ *extensionsv1alpha1.SandboxClaim, _ *sandboxEntry, _ <-chan SandboxStatusUpdate) (*types.CreateSandboxResponse, error) { + patches.ApplyPrivateMethod(reflect.TypeOf(fakeServer), "createSandbox", func(_ *Server, _ context.Context, _ dynamic.Interface, _ *sandboxv1beta1.Sandbox, _ *extensionsv1beta1.SandboxClaim, _ *sandboxEntry, _ <-chan SandboxStatusUpdate) (*types.CreateSandboxResponse, error) { createCalls++ if tc.createErr != nil { return nil, tc.createErr diff --git a/pkg/workloadmanager/informers.go b/pkg/workloadmanager/informers.go index 22ed6c882..519490984 100644 --- a/pkg/workloadmanager/informers.go +++ b/pkg/workloadmanager/informers.go @@ -41,12 +41,12 @@ var ( } SandboxGVR = schema.GroupVersionResource{ Group: "agents.x-k8s.io", - Version: "v1alpha1", + Version: "v1beta1", Resource: "sandboxes", } SandboxClaimGVR = schema.GroupVersionResource{ Group: "extensions.agents.x-k8s.io", - Version: "v1alpha1", + Version: "v1beta1", Resource: "sandboxclaims", } ) diff --git a/pkg/workloadmanager/k8s_client.go b/pkg/workloadmanager/k8s_client.go index 1d241693d..32e097fbe 100644 --- a/pkg/workloadmanager/k8s_client.go +++ b/pkg/workloadmanager/k8s_client.go @@ -38,8 +38,8 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ) const ( @@ -126,7 +126,7 @@ func NewK8sClient() (*K8sClient, error) { // Create scheme and register agent-sandbox types scheme := runtime.NewScheme() - if err := sandboxv1alpha1.AddToScheme(scheme); err != nil { + if err := sandboxv1beta1.AddToScheme(scheme); err != nil { return nil, fmt.Errorf("failed to add agent-sandbox scheme: %w", err) } @@ -212,7 +212,7 @@ func (c *K8sClient) GetOrCreateUserK8sClient(userToken, namespace, serviceAccoun } // createSandbox creates a Sandbox using the provided dynamic client -func createSandbox(ctx context.Context, client dynamic.Interface, sandbox *sandboxv1alpha1.Sandbox) (*SandboxInfo, error) { +func createSandbox(ctx context.Context, client dynamic.Interface, sandbox *sandboxv1beta1.Sandbox) (*SandboxInfo, error) { // Convert to unstructured for dynamic client unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(sandbox) if err != nil { @@ -238,13 +238,13 @@ func createSandbox(ctx context.Context, client dynamic.Interface, sandbox *sandb } // getSandbox gets a Sandbox using the provided dynamic client. -func getSandbox(ctx context.Context, client dynamic.Interface, namespace, sandboxName string) (*sandboxv1alpha1.Sandbox, error) { +func getSandbox(ctx context.Context, client dynamic.Interface, namespace, sandboxName string) (*sandboxv1beta1.Sandbox, error) { obj, err := client.Resource(SandboxGVR).Namespace(namespace).Get(ctx, sandboxName, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("failed to get sandbox %s/%s: %w", namespace, sandboxName, err) } - sandbox := &sandboxv1alpha1.Sandbox{} + sandbox := &sandboxv1beta1.Sandbox{} if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, sandbox); err != nil { return nil, fmt.Errorf("failed to convert sandbox %s/%s: %w", namespace, sandboxName, err) } @@ -252,7 +252,7 @@ func getSandbox(ctx context.Context, client dynamic.Interface, namespace, sandbo } // createSandboxClaim creates a SandboxClaim using the provided dynamic client -func createSandboxClaim(ctx context.Context, client dynamic.Interface, sandboxClaim *extensionsv1alpha1.SandboxClaim) error { +func createSandboxClaim(ctx context.Context, client dynamic.Interface, sandboxClaim *extensionsv1beta1.SandboxClaim) error { // Convert to unstructured for dynamic client unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(sandboxClaim) if err != nil { @@ -275,13 +275,13 @@ func createSandboxClaim(ctx context.Context, client dynamic.Interface, sandboxCl } // getSandboxClaim gets a SandboxClaim using the provided dynamic client. -func getSandboxClaim(ctx context.Context, client dynamic.Interface, namespace, sandboxClaimName string) (*extensionsv1alpha1.SandboxClaim, error) { +func getSandboxClaim(ctx context.Context, client dynamic.Interface, namespace, sandboxClaimName string) (*extensionsv1beta1.SandboxClaim, error) { obj, err := client.Resource(SandboxClaimGVR).Namespace(namespace).Get(ctx, sandboxClaimName, metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("failed to get sandbox claim %s/%s: %w", namespace, sandboxClaimName, err) } - sandboxClaim := &extensionsv1alpha1.SandboxClaim{} + sandboxClaim := &extensionsv1beta1.SandboxClaim{} if err := runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, sandboxClaim); err != nil { return nil, fmt.Errorf("failed to convert sandbox claim %s/%s: %w", namespace, sandboxClaimName, err) } @@ -317,12 +317,12 @@ func deleteSandboxClaim(ctx context.Context, client dynamic.Interface, namespace } // CreateSandboxClaim creates a new SandboxClaim using user's permissions -func (u *UserK8sClient) CreateSandboxClaim(ctx context.Context, sandboxClaim *extensionsv1alpha1.SandboxClaim) error { +func (u *UserK8sClient) CreateSandboxClaim(ctx context.Context, sandboxClaim *extensionsv1beta1.SandboxClaim) error { return createSandboxClaim(ctx, u.dynamicClient, sandboxClaim) } // CreateSandbox creates a new Sandbox using user's permissions -func (u *UserK8sClient) CreateSandbox(ctx context.Context, sandbox *sandboxv1alpha1.Sandbox) (*SandboxInfo, error) { +func (u *UserK8sClient) CreateSandbox(ctx context.Context, sandbox *sandboxv1beta1.Sandbox) (*SandboxInfo, error) { return createSandbox(ctx, u.dynamicClient, sandbox) } diff --git a/pkg/workloadmanager/sandbox_controller.go b/pkg/workloadmanager/sandbox_controller.go index ccc4632c5..91a6b1e09 100644 --- a/pkg/workloadmanager/sandbox_controller.go +++ b/pkg/workloadmanager/sandbox_controller.go @@ -26,7 +26,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" ) type SandboxReconciler struct { @@ -39,11 +39,11 @@ type SandboxReconciler struct { } type SandboxStatusUpdate struct { - Sandbox *sandboxv1alpha1.Sandbox + Sandbox *sandboxv1beta1.Sandbox } func (r *SandboxReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - sandbox := &sandboxv1alpha1.Sandbox{} + sandbox := &sandboxv1beta1.Sandbox{} if err := r.Get(ctx, req.NamespacedName, sandbox); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } diff --git a/pkg/workloadmanager/sandbox_helper.go b/pkg/workloadmanager/sandbox_helper.go index 8d412004e..8a28adfda 100644 --- a/pkg/workloadmanager/sandbox_helper.go +++ b/pkg/workloadmanager/sandbox_helper.go @@ -26,7 +26,7 @@ import ( runtimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1" "github.com/volcano-sh/agentcube/pkg/common/types" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" ) const ( @@ -47,7 +47,7 @@ var sandboxEntrypointDial = func(ctx context.Context, endpoint string, timeout t return conn.Close() } -func buildSandboxPlaceHolder(sandboxCR *sandboxv1alpha1.Sandbox, entry *sandboxEntry) *types.SandboxInfo { +func buildSandboxPlaceHolder(sandboxCR *sandboxv1beta1.Sandbox, entry *sandboxEntry) *types.SandboxInfo { createdAt := sandboxCR.GetCreationTimestamp().Time if createdAt.IsZero() { createdAt = time.Now() @@ -75,7 +75,7 @@ func buildSandboxPlaceHolder(sandboxCR *sandboxv1alpha1.Sandbox, entry *sandboxE } } -func buildSandboxInfo(sandbox *sandboxv1alpha1.Sandbox, podIP string, entry *sandboxEntry) *types.SandboxInfo { +func buildSandboxInfo(sandbox *sandboxv1beta1.Sandbox, podIP string, entry *sandboxEntry) *types.SandboxInfo { createdAt := sandbox.GetCreationTimestamp().Time expiresAt := createdAt.Add(DefaultSandboxTTL) if sandbox.Spec.Lifecycle.ShutdownTime != nil { @@ -110,9 +110,9 @@ func buildSandboxInfo(sandbox *sandboxv1alpha1.Sandbox, podIP string, entry *san // getSandboxStatus extracts status from Sandbox CRD conditions. // Returns sandboxStatusReady when the sandbox is ready, sandboxStatusNotReady otherwise. -func getSandboxStatus(sandbox *sandboxv1alpha1.Sandbox) string { +func getSandboxStatus(sandbox *sandboxv1beta1.Sandbox) string { for _, condition := range sandbox.Status.Conditions { - if condition.Type == string(sandboxv1alpha1.SandboxConditionReady) && condition.Status == metav1.ConditionTrue { + if condition.Type == string(sandboxv1beta1.SandboxConditionReady) && condition.Status == metav1.ConditionTrue { return sandboxStatusReady } } diff --git a/pkg/workloadmanager/sandbox_helper_test.go b/pkg/workloadmanager/sandbox_helper_test.go index 1c8fc9176..01deee517 100644 --- a/pkg/workloadmanager/sandbox_helper_test.go +++ b/pkg/workloadmanager/sandbox_helper_test.go @@ -22,7 +22,7 @@ import ( "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" runtimev1alpha1 "github.com/volcano-sh/agentcube/pkg/apis/runtime/v1alpha1" "github.com/volcano-sh/agentcube/pkg/common/types" @@ -35,14 +35,14 @@ func TestBuildSandboxPlaceHolder_TableDriven(t *testing.T) { tests := []struct { name string - setupSandbox func() *sandboxv1alpha1.Sandbox + setupSandbox func() *sandboxv1beta1.Sandbox entry *sandboxEntry validate func(t *testing.T, result *types.SandboxInfo) }{ { name: "no ShutdownTime falls back to DefaultSandboxTTL", - setupSandbox: func() *sandboxv1alpha1.Sandbox { - return &sandboxv1alpha1.Sandbox{ + setupSandbox: func() *sandboxv1beta1.Sandbox { + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", @@ -62,15 +62,15 @@ func TestBuildSandboxPlaceHolder_TableDriven(t *testing.T) { }, { name: "ShutdownTime set to 24h is used as ExpiresAt", - setupSandbox: func() *sandboxv1alpha1.Sandbox { + setupSandbox: func() *sandboxv1beta1.Sandbox { shutdownTime := now.Add(24 * time.Hour) - return &sandboxv1alpha1.Sandbox{ + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", }, - Spec: sandboxv1alpha1.SandboxSpec{ - Lifecycle: sandboxv1alpha1.Lifecycle{ + Spec: sandboxv1beta1.SandboxSpec{ + Lifecycle: sandboxv1beta1.Lifecycle{ ShutdownTime: &metav1.Time{Time: shutdownTime}, }, }, @@ -87,15 +87,15 @@ func TestBuildSandboxPlaceHolder_TableDriven(t *testing.T) { }, { name: "ShutdownTime set to 30m overrides DefaultSandboxTTL", - setupSandbox: func() *sandboxv1alpha1.Sandbox { + setupSandbox: func() *sandboxv1beta1.Sandbox { shutdownTime := now.Add(30 * time.Minute) - return &sandboxv1alpha1.Sandbox{ + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "short-sandbox", Namespace: "default", }, - Spec: sandboxv1alpha1.SandboxSpec{ - Lifecycle: sandboxv1alpha1.Lifecycle{ + Spec: sandboxv1beta1.SandboxSpec{ + Lifecycle: sandboxv1beta1.Lifecycle{ ShutdownTime: &metav1.Time{Time: shutdownTime}, }, }, @@ -115,11 +115,11 @@ func TestBuildSandboxPlaceHolder_TableDriven(t *testing.T) { }, { name: "warm-pool path: ShutdownTime set on simpleSandbox reflects MaxSessionDuration", - setupSandbox: func() *sandboxv1alpha1.Sandbox { + setupSandbox: func() *sandboxv1beta1.Sandbox { // Simulates the simpleSandbox built by the warm-pool CodeInterpreter path // after the fix in workload_builder.go sets ShutdownTime from MaxSessionDuration. shutdownTime := now.Add(24 * time.Hour) - return &sandboxv1alpha1.Sandbox{ + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", Name: "ci-warmpool-abc", @@ -127,8 +127,8 @@ func TestBuildSandboxPlaceHolder_TableDriven(t *testing.T) { SessionIdLabelKey: "session-wp-001", }, }, - Spec: sandboxv1alpha1.SandboxSpec{ - Lifecycle: sandboxv1alpha1.Lifecycle{ + Spec: sandboxv1beta1.SandboxSpec{ + Lifecycle: sandboxv1beta1.Lifecycle{ ShutdownTime: &metav1.Time{Time: shutdownTime}, }, }, @@ -162,25 +162,25 @@ func TestBuildSandboxInfo_TableDriven(t *testing.T) { tests := []struct { name string - setupSandbox func() *sandboxv1alpha1.Sandbox + setupSandbox func() *sandboxv1beta1.Sandbox podIP string entry *sandboxEntry validateResult func(t *testing.T, result *types.SandboxInfo) }{ { name: "basic sandbox with ports", - setupSandbox: func() *sandboxv1alpha1.Sandbox { - return &sandboxv1alpha1.Sandbox{ + setupSandbox: func() *sandboxv1beta1.Sandbox { + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", UID: "test-uid-123", CreationTimestamp: metav1.NewTime(now), }, - Status: sandboxv1alpha1.SandboxStatus{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }, }, @@ -215,24 +215,24 @@ func TestBuildSandboxInfo_TableDriven(t *testing.T) { }, { name: "sandbox with shutdown time", - setupSandbox: func() *sandboxv1alpha1.Sandbox { + setupSandbox: func() *sandboxv1beta1.Sandbox { shutdownTime := now.Add(2 * time.Hour) - return &sandboxv1alpha1.Sandbox{ + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", UID: "test-uid-123", CreationTimestamp: metav1.NewTime(now), }, - Spec: sandboxv1alpha1.SandboxSpec{ - Lifecycle: sandboxv1alpha1.Lifecycle{ + Spec: sandboxv1beta1.SandboxSpec{ + Lifecycle: sandboxv1beta1.Lifecycle{ ShutdownTime: &metav1.Time{Time: shutdownTime}, }, }, - Status: sandboxv1alpha1.SandboxStatus{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }, }, @@ -253,18 +253,18 @@ func TestBuildSandboxInfo_TableDriven(t *testing.T) { }, { name: "sandbox with no ports", - setupSandbox: func() *sandboxv1alpha1.Sandbox { - return &sandboxv1alpha1.Sandbox{ + setupSandbox: func() *sandboxv1beta1.Sandbox { + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", UID: "test-uid-123", CreationTimestamp: metav1.NewTime(now), }, - Status: sandboxv1alpha1.SandboxStatus{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }, }, @@ -283,18 +283,18 @@ func TestBuildSandboxInfo_TableDriven(t *testing.T) { }, { name: "sandbox with empty pod IP", - setupSandbox: func() *sandboxv1alpha1.Sandbox { - return &sandboxv1alpha1.Sandbox{ + setupSandbox: func() *sandboxv1beta1.Sandbox { + return &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", UID: "test-uid-123", CreationTimestamp: metav1.NewTime(now), }, - Status: sandboxv1alpha1.SandboxStatus{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }, }, @@ -331,16 +331,16 @@ func TestBuildSandboxInfo_TableDriven(t *testing.T) { func TestGetSandboxStatus_TableDriven(t *testing.T) { tests := []struct { name string - sandbox *sandboxv1alpha1.Sandbox + sandbox *sandboxv1beta1.Sandbox expected string }{ { name: "ready condition true", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }, }, @@ -350,11 +350,11 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "ready condition false without reason", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionFalse, }, }, @@ -364,11 +364,11 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "ready condition false with reason is not-ready", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionFalse, Reason: "ErrImagePull", Message: "Back-off pulling image", @@ -380,11 +380,11 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "ready condition unknown", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionUnknown, }, }, @@ -394,8 +394,8 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "no conditions", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{}, }, }, @@ -403,8 +403,8 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "nil conditions", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: nil, }, }, @@ -412,8 +412,8 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "other condition type", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { Type: "OtherCondition", @@ -426,15 +426,15 @@ func TestGetSandboxStatus_TableDriven(t *testing.T) { }, { name: "multiple conditions with ready true", - sandbox: &sandboxv1alpha1.Sandbox{ - Status: sandboxv1alpha1.SandboxStatus{ + sandbox: &sandboxv1beta1.Sandbox{ + Status: sandboxv1beta1.SandboxStatus{ Conditions: []metav1.Condition{ { Type: "OtherCondition", Status: metav1.ConditionFalse, }, { - Type: string(sandboxv1alpha1.SandboxConditionReady), + Type: string(sandboxv1beta1.SandboxConditionReady), Status: metav1.ConditionTrue, }, }, @@ -463,7 +463,7 @@ func TestBuildSandboxPlaceHolder_OwnerID(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sandbox := &sandboxv1alpha1.Sandbox{ + sandbox := &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", @@ -493,7 +493,7 @@ func TestBuildSandboxInfo_OwnerID(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - sandbox := &sandboxv1alpha1.Sandbox{ + sandbox := &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Name: "test-sandbox", Namespace: "default", diff --git a/pkg/workloadmanager/server.go b/pkg/workloadmanager/server.go index f77c157e4..2c19ccfc6 100644 --- a/pkg/workloadmanager/server.go +++ b/pkg/workloadmanager/server.go @@ -31,7 +31,7 @@ import ( "github.com/volcano-sh/agentcube/pkg/mtls" "github.com/volcano-sh/agentcube/pkg/store" "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" + "golang.org/x/net/http2/h2c" //nolint:staticcheck // SA1019: required for h2c (HTTP/2 cleartext) support; no stdlib alternative exists in current architecture ) // Server is the main structure for workload manager @@ -178,7 +178,7 @@ func (s *Server) Start(ctx context.Context) error { } else { // Plain HTTP with h2c (HTTP/2 cleartext) support h2s := &http2.Server{} - s.httpServer.Handler = h2c.NewHandler(s.router, h2s) + s.httpServer.Handler = h2c.NewHandler(s.router, h2s) //nolint:staticcheck // SA1019: required for h2c (HTTP/2 cleartext) support; no stdlib alternative exists in current architecture err = s.httpServer.ListenAndServe() } diff --git a/pkg/workloadmanager/workload_builder.go b/pkg/workloadmanager/workload_builder.go index 2a42e4f07..d702eb0f2 100644 --- a/pkg/workloadmanager/workload_builder.go +++ b/pkg/workloadmanager/workload_builder.go @@ -33,9 +33,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/klog/v2" - "k8s.io/utils/ptr" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ) // Constants for Router's identity resources @@ -142,18 +142,18 @@ type buildSandboxParams struct { } type buildSandboxClaimParams struct { - namespace string - name string - sandboxTemplateName string - sessionID string - ownerID string - idleTimeout time.Duration + namespace string + name string + warmPoolName string + sessionID string + ownerID string + idleTimeout time.Duration // ownerReference is the reference to the CodeInterpreter that creates this SandboxClaim ownerReference *metav1.OwnerReference } // buildSandboxObject builds a Sandbox object from parameters -func buildSandboxObject(params *buildSandboxParams) *sandboxv1alpha1.Sandbox { +func buildSandboxObject(params *buildSandboxParams) *sandboxv1beta1.Sandbox { if params.ttl == 0 { params.ttl = DefaultSandboxTTL } @@ -174,9 +174,9 @@ func buildSandboxObject(params *buildSandboxParams) *sandboxv1alpha1.Sandbox { maps.Copy(podAnnotations, params.podAnnotations) // Create Sandbox object using agent-sandbox types - sandbox := &sandboxv1alpha1.Sandbox{ + sandbox := &sandboxv1beta1.Sandbox{ TypeMeta: metav1.TypeMeta{ - APIVersion: "agents.x-k8s.io/v1alpha1", + APIVersion: "agents.x-k8s.io/v1beta1", Kind: types.SandboxKind, }, ObjectMeta: metav1.ObjectMeta{ @@ -191,18 +191,20 @@ func buildSandboxObject(params *buildSandboxParams) *sandboxv1alpha1.Sandbox { IdleTimeoutAnnotationKey: params.idleTimeout.String(), }, }, - Spec: sandboxv1alpha1.SandboxSpec{ - PodTemplate: sandboxv1alpha1.PodTemplate{ - Spec: params.podSpec, - ObjectMeta: sandboxv1alpha1.PodMetadata{ - Labels: podLabels, - Annotations: podAnnotations, + Spec: sandboxv1beta1.SandboxSpec{ + SandboxBlueprint: sandboxv1beta1.SandboxBlueprint{ + PodTemplate: sandboxv1beta1.PodTemplate{ + Spec: params.podSpec, + ObjectMeta: sandboxv1beta1.PodMetadata{ + Labels: podLabels, + Annotations: podAnnotations, + }, }, }, - Lifecycle: sandboxv1alpha1.Lifecycle{ + Lifecycle: sandboxv1beta1.Lifecycle{ ShutdownTime: &shutdownTime, }, - Replicas: ptr.To[int32](1), + OperatingMode: sandboxv1beta1.SandboxOperatingModeRunning, }, } @@ -215,14 +217,14 @@ func buildSandboxObject(params *buildSandboxParams) *sandboxv1alpha1.Sandbox { return sandbox } -func buildSandboxClaimObject(params *buildSandboxClaimParams) *extensionsv1alpha1.SandboxClaim { +func buildSandboxClaimObject(params *buildSandboxClaimParams) *extensionsv1beta1.SandboxClaim { idleTimeout := params.idleTimeout if idleTimeout == 0 { idleTimeout = DefaultSandboxIdleTimeout } - sandboxClaim := &extensionsv1alpha1.SandboxClaim{ + sandboxClaim := &extensionsv1beta1.SandboxClaim{ TypeMeta: metav1.TypeMeta{ - APIVersion: "extensions.agents.x-k8s.io/v1alpha1", + APIVersion: "extensions.agents.x-k8s.io/v1beta1", Kind: types.SandboxClaimsKind, }, ObjectMeta: metav1.ObjectMeta{ @@ -236,9 +238,9 @@ func buildSandboxClaimObject(params *buildSandboxClaimParams) *extensionsv1alpha IdleTimeoutAnnotationKey: idleTimeout.String(), }, }, - Spec: extensionsv1alpha1.SandboxClaimSpec{ - TemplateRef: extensionsv1alpha1.SandboxTemplateRef{ - Name: params.sandboxTemplateName, + Spec: extensionsv1beta1.SandboxClaimSpec{ + WarmPoolRef: extensionsv1beta1.SandboxWarmPoolRef{ + Name: params.warmPoolName, }, }, } @@ -256,7 +258,7 @@ func buildSandboxClaimObject(params *buildSandboxClaimParams) *extensionsv1alpha return sandboxClaim } -func buildSandboxByAgentRuntime(namespace string, name string, ownerID string, ifm *Informers) (*sandboxv1alpha1.Sandbox, *sandboxEntry, error) { +func buildSandboxByAgentRuntime(namespace string, name string, ownerID string, ifm *Informers) (*sandboxv1beta1.Sandbox, *sandboxEntry, error) { agentRuntimeObj, err := ifm.AgentRuntimeLister.AgentRuntimes(namespace).Get(name) if err != nil { if apierrors.IsNotFound(err) { @@ -322,7 +324,7 @@ func buildCodeInterpreterEnvVars(templateEnv []corev1.EnvVar, authMode runtimev1 return envVars } -func buildSandboxByCodeInterpreter(namespace string, codeInterpreterName string, ownerID string, informer *Informers) (*sandboxv1alpha1.Sandbox, *extensionsv1alpha1.SandboxClaim, *sandboxEntry, error) { +func buildSandboxByCodeInterpreter(namespace string, codeInterpreterName string, ownerID string, informer *Informers) (*sandboxv1beta1.Sandbox, *extensionsv1beta1.SandboxClaim, *sandboxEntry, error) { codeInterpreterObj, err := informer.CodeInterpreterLister.CodeInterpreters(namespace).Get(codeInterpreterName) if err != nil { if apierrors.IsNotFound(err) { @@ -364,12 +366,12 @@ func buildSandboxByCodeInterpreter(namespace string, codeInterpreterName string, if codeInterpreterObj.Spec.WarmPoolSize != nil && *codeInterpreterObj.Spec.WarmPoolSize > 0 { sandboxClaim := buildSandboxClaimObject(&buildSandboxClaimParams{ - namespace: namespace, - name: sandboxName, - sandboxTemplateName: codeInterpreterName, - sessionID: sessionID, - ownerID: ownerID, - idleTimeout: idleTimeout, + namespace: namespace, + name: sandboxName, + warmPoolName: codeInterpreterName, + sessionID: sessionID, + ownerID: ownerID, + idleTimeout: idleTimeout, ownerReference: &metav1.OwnerReference{ APIVersion: runtimev1alpha1.CodeInterpreterGroupVersionKind.GroupVersion().String(), Kind: runtimev1alpha1.CodeInterpreterKind, @@ -377,7 +379,7 @@ func buildSandboxByCodeInterpreter(namespace string, codeInterpreterName string, UID: codeInterpreterObj.UID, }, }) - simpleSandbox := &sandboxv1alpha1.Sandbox{ + simpleSandbox := &sandboxv1beta1.Sandbox{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: sandboxName, diff --git a/pkg/workloadmanager/workload_builder_test.go b/pkg/workloadmanager/workload_builder_test.go index 035dd5c6b..8db9eaa67 100644 --- a/pkg/workloadmanager/workload_builder_test.go +++ b/pkg/workloadmanager/workload_builder_test.go @@ -69,7 +69,7 @@ func TestBuildSandboxObject_DoesNotMutateCallerLabels(t *testing.T) { } // The sandbox pod-template labels must contain both original and injected keys. - podLabels := sandbox.Spec.PodTemplate.ObjectMeta.Labels + podLabels := sandbox.Spec.SandboxBlueprint.PodTemplate.ObjectMeta.Labels if podLabels["app"] != "my-app" { t.Errorf("expected pod label app=my-app, got %q", podLabels["app"]) } @@ -106,7 +106,7 @@ func TestBuildSandboxObject_NilLabels(t *testing.T) { sandbox := buildSandboxObject(params) - podLabels := sandbox.Spec.PodTemplate.ObjectMeta.Labels + podLabels := sandbox.Spec.SandboxBlueprint.PodTemplate.ObjectMeta.Labels if podLabels[SessionIdLabelKey] != "session-456" { t.Errorf("expected %s=session-456, got %q", SessionIdLabelKey, podLabels[SessionIdLabelKey]) } @@ -167,12 +167,12 @@ func TestBuildSandboxClaimObject(t *testing.T) { UID: "test-uid-123", } params := &buildSandboxClaimParams{ - namespace: "test-ns", - name: "claim-abc", - sandboxTemplateName: "my-ci", - sessionID: "session-claim-test", - idleTimeout: 10 * time.Minute, - ownerReference: ownerRef, + namespace: "test-ns", + name: "claim-abc", + warmPoolName: "my-ci", + sessionID: "session-claim-test", + idleTimeout: 10 * time.Minute, + ownerReference: ownerRef, } claim := buildSandboxClaimObject(params) @@ -182,8 +182,8 @@ func TestBuildSandboxClaimObject(t *testing.T) { if claim.Name != "claim-abc" { t.Errorf("expected name claim-abc, got %q", claim.Name) } - if claim.Spec.TemplateRef.Name != "my-ci" { - t.Errorf("expected templateRef name my-ci, got %q", claim.Spec.TemplateRef.Name) + if claim.Spec.WarmPoolRef.Name != "my-ci" { + t.Errorf("expected warmPoolRef name my-ci, got %q", claim.Spec.WarmPoolRef.Name) } if claim.Labels[SessionIdLabelKey] != "session-claim-test" { t.Errorf("expected label %s=session-claim-test, got %q", SessionIdLabelKey, claim.Labels[SessionIdLabelKey]) @@ -201,11 +201,11 @@ func TestBuildSandboxClaimObject(t *testing.T) { t.Run("without owner reference", func(t *testing.T) { params := &buildSandboxClaimParams{ - namespace: "default", - name: "claim-no-owner", - sandboxTemplateName: "template-1", - sessionID: "session-no-owner", - idleTimeout: 0, + namespace: "default", + name: "claim-no-owner", + warmPoolName: "template-1", + sessionID: "session-no-owner", + idleTimeout: 0, } claim := buildSandboxClaimObject(params) @@ -416,7 +416,7 @@ func TestBuildSandboxByAgentRuntime_Success(t *testing.T) { } assertSandboxMetadata(t, sandbox.Labels, sandbox.Name, sandbox.Namespace, testAgentRuntimeName+"-", testAgentRuntimeName, entry.SessionID) - assertAgentRuntimePodLabels(t, sandbox.Spec.PodTemplate.ObjectMeta.Labels, sandbox.Name, entry.SessionID) + assertAgentRuntimePodLabels(t, sandbox.Spec.SandboxBlueprint.PodTemplate.ObjectMeta.Labels, sandbox.Name, entry.SessionID) // Validate TTL (MaxSessionDuration) if sandbox.Spec.Lifecycle.ShutdownTime == nil { @@ -473,7 +473,7 @@ func TestBuildSandboxByAgentRuntime_DefaultTimeouts(t *testing.T) { assert.Equal(t, types.SandboxKind, entry.Kind) assert.Equal(t, DefaultSandboxIdleTimeout, entry.IdleTimeout) - assert.Equal(t, sandbox.Name, sandbox.Spec.PodTemplate.ObjectMeta.Labels[SandboxNameLabelKey]) + assert.Equal(t, sandbox.Name, sandbox.Spec.SandboxBlueprint.PodTemplate.ObjectMeta.Labels[SandboxNameLabelKey]) } func TestBuildSandboxByAgentRuntime_CustomTimeouts(t *testing.T) { @@ -515,7 +515,7 @@ func TestBuildSandboxByAgentRuntime_CustomTimeouts(t *testing.T) { assert.NotNil(t, entry) assert.Equal(t, 30*time.Minute, entry.IdleTimeout) - assert.Nil(t, sandbox.Spec.PodTemplate.Spec.RuntimeClassName) + assert.Nil(t, sandbox.Spec.SandboxBlueprint.PodTemplate.Spec.RuntimeClassName) } func TestBuildSandboxByCodeInterpreter_NotFound(t *testing.T) { @@ -621,7 +621,7 @@ func TestBuildSandboxByCodeInterpreter_SuccessNoWarmPool(t *testing.T) { if entry.Kind != types.SandboxKind { t.Errorf("expected entry.Kind to be %q, got %q", types.SandboxKind, entry.Kind) } - podSpec := sandbox.Spec.PodTemplate.Spec + podSpec := sandbox.Spec.SandboxBlueprint.PodTemplate.Spec if len(podSpec.Containers) != 1 || podSpec.Containers[0].Image != "my-ci-image:latest" { t.Errorf("expected pod container image 'my-ci-image:latest', got %+v", podSpec.Containers) } @@ -677,8 +677,8 @@ func TestBuildSandboxByCodeInterpreter_SuccessWithWarmPool(t *testing.T) { if entry.Kind != types.SandboxClaimsKind { t.Errorf("expected entry.Kind to be %q, got %q", types.SandboxClaimsKind, entry.Kind) } - if claim.Spec.TemplateRef.Name != testCodeInterpreterWarmPool { - t.Errorf("expected templateRef name %q, got %q", testCodeInterpreterWarmPool, claim.Spec.TemplateRef.Name) + if claim.Spec.WarmPoolRef.Name != testCodeInterpreterWarmPool { + t.Errorf("expected warmPoolRef name %q, got %q", testCodeInterpreterWarmPool, claim.Spec.WarmPoolRef.Name) } if len(claim.OwnerReferences) != 1 { t.Fatalf("expected 1 owner reference, got %d", len(claim.OwnerReferences)) @@ -766,12 +766,12 @@ func TestBuildSandboxClaimObject_OwnershipLabels(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { params := &buildSandboxClaimParams{ - namespace: "default", - name: "claim-owner-test", - sandboxTemplateName: "my-ci", - sessionID: "session-claim-owner", - ownerID: tt.ownerID, - idleTimeout: 10 * time.Minute, + namespace: "default", + name: "claim-owner-test", + warmPoolName: "my-ci", + sessionID: "session-claim-owner", + ownerID: tt.ownerID, + idleTimeout: 10 * time.Minute, } claim := buildSandboxClaimObject(params) diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 166379107..18489ab47 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -47,8 +47,8 @@ import ( "k8s.io/client-go/tools/clientcmd" "sigs.k8s.io/controller-runtime/pkg/client" - sandboxv1alpha1 "sigs.k8s.io/agent-sandbox/api/v1alpha1" - extensionsv1alpha1 "sigs.k8s.io/agent-sandbox/extensions/api/v1alpha1" + sandboxv1beta1 "sigs.k8s.io/agent-sandbox/api/v1beta1" + extensionsv1beta1 "sigs.k8s.io/agent-sandbox/extensions/api/v1beta1" ) const ( @@ -79,8 +79,8 @@ type claimedSandboxResources struct { func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(sandboxv1alpha1.AddToScheme(scheme)) - utilruntime.Must(extensionsv1alpha1.AddToScheme(scheme)) + utilruntime.Must(sandboxv1beta1.AddToScheme(scheme)) + utilruntime.Must(extensionsv1beta1.AddToScheme(scheme)) utilruntime.Must(v1alpha1.AddToScheme(scheme)) } @@ -1036,10 +1036,10 @@ func (ctx *e2eTestContext) cleanupCodeInterpreter(t *testing.T, namespace, name, func (ctx *e2eTestContext) verifyClaimedResourcesDeleted(t *testing.T, namespace string, claimedResources *claimedSandboxResources) { t.Helper() require.Eventually(t, func() bool { - return ctx.objectUIDGone(namespace, claimedResources.claimName, claimedResources.claimUID, &extensionsv1alpha1.SandboxClaim{}) + return ctx.objectUIDGone(namespace, claimedResources.claimName, claimedResources.claimUID, &extensionsv1beta1.SandboxClaim{}) }, 30*time.Second, time.Second, "adopting SandboxClaim %s/%s should be deleted", namespace, claimedResources.claimName) require.Eventually(t, func() bool { - return ctx.objectUIDGone(namespace, claimedResources.sandboxName, claimedResources.sandboxUID, &sandboxv1alpha1.Sandbox{}) + return ctx.objectUIDGone(namespace, claimedResources.sandboxName, claimedResources.sandboxUID, &sandboxv1beta1.Sandbox{}) }, 30*time.Second, time.Second, "adopted Sandbox %s/%s should be deleted", namespace, claimedResources.sandboxName) require.Eventually(t, func() bool { return ctx.objectUIDGone(namespace, claimedResources.podName, claimedResources.podUID, &corev1.Pod{}) @@ -1236,7 +1236,7 @@ func (ctx *e2eTestContext) deleteYamlFile(yamlPath string) error { // countSandboxClaims counts the number of SandboxClaim resources owned by a CodeInterpreter func (ctx *e2eTestContext) countSandboxClaims(namespace, codeInterpreterName string) (int, error) { - sandboxClaimList := &extensionsv1alpha1.SandboxClaimList{} + sandboxClaimList := &extensionsv1beta1.SandboxClaimList{} err := ctx.ctrlClient.List(context.Background(), sandboxClaimList, client.InNamespace(namespace)) if err != nil { if apierrors.IsNotFound(err) { @@ -1292,7 +1292,7 @@ func (ctx *e2eTestContext) getWarmPoolPodIdentities(namespace, codeInterpreterNa func (ctx *e2eTestContext) listWarmPoolPods(namespace, codeInterpreterName string) ([]corev1.Pod, error) { listCtx := context.Background() - sandboxList := &sandboxv1alpha1.SandboxList{} + sandboxList := &sandboxv1beta1.SandboxList{} if err := ctx.ctrlClient.List(listCtx, sandboxList, client.InNamespace(namespace)); err != nil { return nil, fmt.Errorf("failed to list sandboxes: %w", err) } @@ -1329,7 +1329,7 @@ func (ctx *e2eTestContext) listWarmPoolPods(namespace, codeInterpreterName strin return pods, nil } -func isWarmPoolSandbox(sandbox sandboxv1alpha1.Sandbox, codeInterpreterName string) bool { +func isWarmPoolSandbox(sandbox sandboxv1beta1.Sandbox, codeInterpreterName string) bool { if sandbox.DeletionTimestamp != nil || sandbox.UID == "" { return false } @@ -1406,14 +1406,14 @@ func (ctx *e2eTestContext) arePodsReady(namespace, codeInterpreterName string) ( } // getSandboxClaimByOwner finds exactly one SandboxClaim owned by the specified owner -func (ctx *e2eTestContext) getSandboxClaimByOwner(namespace, ownerKind, ownerName string) (*extensionsv1alpha1.SandboxClaim, error) { - sandboxClaimList := &extensionsv1alpha1.SandboxClaimList{} +func (ctx *e2eTestContext) getSandboxClaimByOwner(namespace, ownerKind, ownerName string) (*extensionsv1beta1.SandboxClaim, error) { + sandboxClaimList := &extensionsv1beta1.SandboxClaimList{} err := ctx.ctrlClient.List(context.Background(), sandboxClaimList, client.InNamespace(namespace)) if err != nil { return nil, fmt.Errorf("failed to list sandboxclaims: %w", err) } - var found *extensionsv1alpha1.SandboxClaim + var found *extensionsv1beta1.SandboxClaim for i := range sandboxClaimList.Items { claim := &sandboxClaimList.Items[i] for _, ownerRef := range claim.OwnerReferences { @@ -1431,14 +1431,14 @@ func (ctx *e2eTestContext) getSandboxClaimByOwner(namespace, ownerKind, ownerNam } // getSandboxByOwner finds exactly one Sandbox owned by the specified owner -func (ctx *e2eTestContext) getSandboxByOwner(namespace, ownerKind, ownerName string) (*sandboxv1alpha1.Sandbox, error) { - sandboxList := &sandboxv1alpha1.SandboxList{} +func (ctx *e2eTestContext) getSandboxByOwner(namespace, ownerKind, ownerName string) (*sandboxv1beta1.Sandbox, error) { + sandboxList := &sandboxv1beta1.SandboxList{} err := ctx.ctrlClient.List(context.Background(), sandboxList, client.InNamespace(namespace)) if err != nil { return nil, fmt.Errorf("failed to list sandboxes: %w", err) } - var found *sandboxv1alpha1.Sandbox + var found *sandboxv1beta1.Sandbox for i := range sandboxList.Items { sandbox := &sandboxList.Items[i] for _, ownerRef := range sandbox.OwnerReferences { diff --git a/test/e2e/run_e2e.sh b/test/e2e/run_e2e.sh index d667303e1..4f30aa342 100755 --- a/test/e2e/run_e2e.sh +++ b/test/e2e/run_e2e.sh @@ -13,7 +13,7 @@ if [ -z "${MTLS_ENABLED+x}" ]; then MTLS_ENABLED=true fi fi -AGENT_SANDBOX_VERSION=${AGENT_SANDBOX_VERSION:-v0.4.6} +AGENT_SANDBOX_VERSION=${AGENT_SANDBOX_VERSION:-v0.5.2} E2E_REQUIRE_CODEINTERPRETER=${E2E_REQUIRE_CODEINTERPRETER:-false} WORKLOAD_MANAGER_IMAGE=${WORKLOAD_MANAGER_IMAGE:-workloadmanager:latest} ROUTER_IMAGE=${ROUTER_IMAGE:-agentcube-router:latest} @@ -31,7 +31,7 @@ REPO_ROOT="$(cd "$_SCRIPT_DIR/../.." && pwd)" # Images that need to be pre-pulled and loaded into kind cluster # Based on agent-sandbox manifest analysis, only these images are needed: -# - agent-sandbox-controller (used in both agentsandbox manifest.yaml and extensions.yaml) +# - agent-sandbox-controller (used in sandbox-with-extensions.yaml) # - python:3.9-slim (used by echo-agent) PRE_PULL_IMAGES=( "registry.k8s.io/agent-sandbox/agent-sandbox-controller:${AGENT_SANDBOX_VERSION}" @@ -333,9 +333,7 @@ run_setup() { done step "Installing agent-sandbox (${AGENT_SANDBOX_VERSION})..." - # Download then apply to avoid URL parsing issues / improve debuggability. - kubectl_apply_url "https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/manifest.yaml" - kubectl_apply_url "https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/extensions.yaml" + kubectl_apply_url "https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/sandbox-with-extensions.yaml" verify_agent_sandbox_controller step "Building images..."