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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: controller
newName: inftyai/llmaz-test
newTag: 0901-04
newName: inftyai/llmaz
newTag: main
4 changes: 2 additions & 2 deletions docs/examples/llamacpp/playground.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
apiVersion: inference.llmaz.io/v1alpha1
kind: Playground
metadata:
name: qwen2-0-5b
name: qwen2-0--5b
spec:
replicas: 1
modelClaim:
modelName: qwen2-0-5b-gguf
modelName: qwen2-0--5b-gguf
backendConfig:
name: llamacpp
args:
Expand Down
83 changes: 52 additions & 31 deletions pkg/controller/inference/playground_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"reflect"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
Expand All @@ -33,7 +34,6 @@ import (
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -84,19 +84,13 @@ func (r *PlaygroundReconciler) Reconcile(ctx context.Context, req ctrl.Request)

service := &inferenceapi.Service{}
if err := r.Get(ctx, types.NamespacedName{Name: playground.Name, Namespace: playground.Namespace}, service); err == nil {
if !controllerutil.HasControllerReference(service) {
condition := metav1.Condition{
Type: inferenceapi.PlaygroundProgressing,
Status: metav1.ConditionFalse,
Reason: "AbortProcessing",
Message: "Playground owns the same name with an existing Service",
if !metav1.IsControlledBy(service, playground) {
logger.Info("failed to construct inference Service as a Service with the same exists", "Playground", klog.KObj(playground))
if changed := handleUnexpectedCondition(playground, true, true); changed {
err = r.Client.Status().Update(ctx, playground)
}
apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
if err := r.Client.Status().Update(ctx, playground); err != nil {
return ctrl.Result{}, err
}
// No need to requeue. Once the Service is deleted, the Playground will be reconciled.
return ctrl.Result{}, nil
// if update successfully, err will be nil and we'll hanging here until Playground or Service deleted.
return ctrl.Result{}, err
}
}

Expand All @@ -106,13 +100,19 @@ func (r *PlaygroundReconciler) Reconcile(ctx context.Context, req ctrl.Request)
if playground.Spec.ModelClaim != nil {
model := &coreapi.OpenModel{}
if err := r.Get(ctx, types.NamespacedName{Name: string(playground.Spec.ModelClaim.ModelName)}, model); err != nil {
if apierrors.IsNotFound(err) && handleUnexpectedCondition(playground, false, false) {
return ctrl.Result{}, r.Client.Status().Update(ctx, playground)
}
return ctrl.Result{}, err
}
models = append(models, model)
} else if playground.Spec.MultiModelsClaim != nil {
for _, modelName := range playground.Spec.MultiModelsClaim.ModelNames {
model := &coreapi.OpenModel{}
if err := r.Get(ctx, types.NamespacedName{Name: string(modelName)}, model); err != nil {
if apierrors.IsNotFound(err) && handleUnexpectedCondition(playground, false, false) {
return ctrl.Result{}, r.Client.Status().Update(ctx, playground)
}
return ctrl.Result{}, err
}
models = append(models, model)
Expand All @@ -130,11 +130,6 @@ func (r *PlaygroundReconciler) Reconcile(ctx context.Context, req ctrl.Request)
}

// Handle status.
service = &inferenceapi.Service{}
if err := r.Get(ctx, types.NamespacedName{Name: playground.Name, Namespace: playground.Namespace}, service); err != nil {
return ctrl.Result{}, err
}

setPlaygroundCondition(playground, service)
if err := r.Client.Status().Update(ctx, playground); err != nil {
return ctrl.Result{}, err
Expand Down Expand Up @@ -308,17 +303,40 @@ func buildWorkerTemplate(models []*coreapi.OpenModel, playground *inferenceapi.P
return template
}

func setPlaygroundCondition(playground *inferenceapi.Playground, service *inferenceapi.Service) {
// For the start up.
if len(playground.Status.Conditions) == 0 || !apimeta.IsStatusConditionTrue(service.Status.Conditions, inferenceapi.PlaygroundProgressing) {
func handleUnexpectedCondition(playground *inferenceapi.Playground, modelExists bool, serviceWithSameNameExists bool) (changed bool) {
// Put it in the first place as more serious.
if serviceWithSameNameExists {
condition := metav1.Condition{
Type: inferenceapi.PlaygroundProgressing,
Status: metav1.ConditionFalse,
Reason: "AbortProcessing",
Message: "Playground owns the same name with an existing Service",
}
return apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
}

if !modelExists {
condition := metav1.Condition{
Type: inferenceapi.PlaygroundProgressing,
Status: metav1.ConditionFalse,
Reason: "AbortProcessing",
Message: "Waiting for model creation",
}
return apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
}
return false
}

func setPlaygroundCondition(playground *inferenceapi.Playground, service *inferenceapi.Service) (changed bool) {
// For the start up or Playground is recovered from AbortProcessing.
if len(playground.Status.Conditions) == 0 || apimeta.IsStatusConditionFalse(playground.Status.Conditions, inferenceapi.PlaygroundProgressing) {
condition := metav1.Condition{
Type: inferenceapi.PlaygroundProgressing,
Status: metav1.ConditionTrue,
Reason: "Pending",
Message: "Waiting for inferenceService ready",
Message: "Waiting for inference Service ready",
}
apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
return
return apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
}

if apimeta.IsStatusConditionTrue(service.Status.Conditions, inferenceapi.ServiceAvailable) {
Expand All @@ -328,27 +346,30 @@ func setPlaygroundCondition(playground *inferenceapi.Playground, service *infere
Reason: "PlaygroundReady",
Message: "Playground is ready",
}
apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
return apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
} else {
// Still in starting up, no need to populate the condition.
if apimeta.FindStatusCondition(playground.Status.Conditions, inferenceapi.PlaygroundAvailable) == nil {
return
return false
}

condition := metav1.Condition{
Type: inferenceapi.PlaygroundProgressing,
Status: metav1.ConditionTrue,
Reason: "PlaygroundInProgress",
Message: "Playground is progressing",
Message: "Waiting for inference Service progressing",
}
apimeta.SetStatusCondition(&playground.Status.Conditions, condition)
changed = apimeta.SetStatusCondition(&playground.Status.Conditions, condition) || changed

// Set the available to false
new_condition := metav1.Condition{
Type: inferenceapi.PlaygroundAvailable,
Status: metav1.ConditionFalse,
Type: inferenceapi.PlaygroundAvailable,
Status: metav1.ConditionFalse,
Reason: "PlaygroundNotReady",
Message: "Waiting for inference Service ready",
}
apimeta.SetStatusCondition(&playground.Status.Conditions, new_condition)
changed = apimeta.SetStatusCondition(&playground.Status.Conditions, new_condition) || changed
return changed
}
}

Expand Down
6 changes: 3 additions & 3 deletions pkg/controller/inference/service_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,15 @@ func setServiceCondition(service *inferenceapi.Service, workload *lws.LeaderWork
Type: inferenceapi.ServiceAvailable,
Status: metav1.ConditionTrue,
Reason: "ServiceReady",
Message: "InferenceService is ready",
Message: "Inference Service is ready",
}
apimeta.SetStatusCondition(&service.Status.Conditions, condition)
} else {
condition := metav1.Condition{
Type: inferenceapi.ServiceProgressing,
Status: metav1.ConditionTrue,
Reason: "ServiceInProgress",
Message: "InferenceService is progressing",
Message: "Inference Service is progressing",
}
apimeta.SetStatusCondition(&service.Status.Conditions, condition)

Expand All @@ -240,7 +240,7 @@ func setServiceCondition(service *inferenceapi.Service, workload *lws.LeaderWork
Type: inferenceapi.ServiceAvailable,
Status: metav1.ConditionFalse,
Reason: "ServiceNotReady",
Message: "InferenceService not ready",
Message: "Waiting for leaderWorkerSet ready",
}
apimeta.SetStatusCondition(&service.Status.Conditions, new_condition)
}
Expand Down
2 changes: 2 additions & 0 deletions test/e2e/suit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package e2e

import (
"context"
"os"
"testing"
"time"

Expand Down Expand Up @@ -81,6 +82,7 @@ var _ = BeforeSuite(func() {
Expect(k8sClient).NotTo(BeNil())

readyForTesting(k8sClient)
Expect(os.Setenv("TEST_TYPE", "E2E")).Should(Succeed())
})

var _ = AfterSuite(func() {
Expand Down
Loading