diff --git a/pkg/controller/inference/playground_controller.go b/pkg/controller/inference/playground_controller.go index a332febd..8b1df8e2 100644 --- a/pkg/controller/inference/playground_controller.go +++ b/pkg/controller/inference/playground_controller.go @@ -119,6 +119,32 @@ func (r *PlaygroundReconciler) Reconcile(ctx context.Context, req ctrl.Request) // SetupWithManager sets up the controller with the Manager. func (r *PlaygroundReconciler) SetupWithManager(mgr ctrl.Manager) error { + mapFn := func(ctx context.Context, obj client.Object) []ctrl.Request { + logger := log.FromContext(ctx) + + modelName := obj.GetName() + + playgrounds := &inferenceapi.PlaygroundList{} + err := r.List(ctx, playgrounds, client.MatchingLabels{coreapi.ModelNameLabelKey: modelName}) + if err != nil { + logger.Error(err, "failed to list playgrounds") + return nil + } + + var reqs []ctrl.Request + for _, playground := range playgrounds.Items { + reqs = append(reqs, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Name: playground.Name, + }, + }) + } + + // TODO: handle MultiModelsClaims in the future. + + return reqs + } + return ctrl.NewControllerManagedBy(mgr). For(&inferenceapi.Playground{}). Watches(&inferenceapi.Service{}, &handler.EnqueueRequestForObject{}, @@ -129,6 +155,12 @@ func (r *PlaygroundReconciler) SetupWithManager(mgr ctrl.Manager) error { return !reflect.DeepEqual(oldBar.Status, newBar.Status) }, })). + Watches(&coreapi.OpenModel{}, handler.EnqueueRequestsFromMapFunc(mapFn), + builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(e event.UpdateEvent) bool { return false }, + DeleteFunc: func(e event.DeleteEvent) bool { return false }, + GenericFunc: func(e event.GenericEvent) bool { return false }, + })). Complete(r) } diff --git a/test/integration/controller/inference/playground_test.go b/test/integration/controller/inference/playground_test.go index c823297e..0e83d383 100644 --- a/test/integration/controller/inference/playground_test.go +++ b/test/integration/controller/inference/playground_test.go @@ -18,10 +18,12 @@ package inference import ( "context" + "fmt" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" @@ -155,5 +157,54 @@ var _ = ginkgo.Describe("playground controller test", func() { }, }, }), + ginkgo.Entry("create the model after playground is created", &testValidatingCase{ + makePlayground: func() *inferenceapi.Playground { + return util.MockASamplePlayground(ns.Name) + }, + updates: []*update{ + { + playgroundUpdateFn: func(playground *inferenceapi.Playground) { + // Delete the pre-provision model before creating playground. + gomega.Expect(k8sClient.Delete(ctx, model)).To(gomega.Succeed()) + // To make sure model not exists. + gomega.Eventually(func() error { + oldModel := &coreapi.OpenModel{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: model.Name, Namespace: model.Namespace}, oldModel); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + return fmt.Errorf("model %s/%s still exists", model.Namespace, model.Name) + }, util.IntegrationTimeout, util.Interval).Should(gomega.Succeed()) + + gomega.Expect(k8sClient.Create(ctx, playground)).To(gomega.Succeed()) + }, + checkPlayground: func(ctx context.Context, k8sClient client.Client, playground *inferenceapi.Playground) { + gomega.Consistently(func() error { + updatePlayground := inferenceapi.Playground{} + if err := k8sClient.Get(ctx, types.NamespacedName{Name: playground.Name, Namespace: playground.Namespace}, &updatePlayground); err != nil { + return err + } + if len(updatePlayground.Status.Conditions) != 0 { + return fmt.Errorf("playground status conditions should be empty, got %v", updatePlayground.Status.Conditions) + } + return nil + }, 3*util.Interval, util.Interval).Should(gomega.Succeed()) + }, + }, + { + // create the model after playground is created. + playgroundUpdateFn: func(_ *inferenceapi.Playground) { + model = util.MockASampleModel() + gomega.Expect(k8sClient.Create(ctx, model)).To(gomega.Succeed()) + }, + checkPlayground: func(ctx context.Context, k8sClient client.Client, playground *inferenceapi.Playground) { + validation.ValidatePlayground(ctx, k8sClient, playground) + validation.ValidatePlaygroundStatusEqualTo(ctx, k8sClient, playground, inferenceapi.PlaygroundProgressing, "Pending", metav1.ConditionTrue) + }, + }, + }, + }), ) })