diff --git a/config/rbac/controller-manager/role.yaml b/config/rbac/controller-manager/role.yaml index dac8c0b08..4688a78d5 100644 --- a/config/rbac/controller-manager/role.yaml +++ b/config/rbac/controller-manager/role.yaml @@ -308,3 +308,10 @@ rules: - list - update - watch +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list \ No newline at end of file diff --git a/pkg/controller/rayclusterreplicaset/rayclusterreplicaset_controller.go b/pkg/controller/rayclusterreplicaset/rayclusterreplicaset_controller.go index 72cd0b88a..24d648e17 100644 --- a/pkg/controller/rayclusterreplicaset/rayclusterreplicaset_controller.go +++ b/pkg/controller/rayclusterreplicaset/rayclusterreplicaset_controller.go @@ -22,21 +22,22 @@ import ( "sync" "time" - "github.com/vllm-project/aibrix/pkg/controller/util/expectation" - apierrors "k8s.io/apimachinery/pkg/api/errors" - rayclusterv1 "github.com/ray-project/kuberay/ray-operator/apis/ray/v1" + orchestrationv1alpha1 "github.com/vllm-project/aibrix/api/orchestration/v1alpha1" "github.com/vllm-project/aibrix/pkg/config" - "k8s.io/client-go/tools/record" - "k8s.io/klog/v2" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/vllm-project/aibrix/pkg/controller/util/expectation" - orchestrationv1alpha1 "github.com/vllm-project/aibrix/api/orchestration/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" + "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" ) var ( @@ -45,11 +46,16 @@ var ( controllerKind = orchestrationv1alpha1.GroupVersion.WithKind("RayClusterReplicaSet") ) -// Add creates a new RayClusterReplicaSet Controller and adds it to the Manager with default RBAC. +// Add first validates that the required Ray CRD (e.g., "rayclusters.ray.io") exists in the cluster. +// If the CRD is not found, the function fails early with an error. +// If the CRD exists, this function creates a new RayClusterReplicaSet Controller and adds it to the Manager with default RBAC. // The Manager will set fields on the Controller and Start it when the Manager is Started. func Add(mgr manager.Manager, runtimeConfig config.RuntimeConfig) error { - // TODO: check crd exists or not. If not, we should fail here directly without moving forward. - // This is used to validate whether kuberay is installed now. + // Check if the CRD exists. If not, fail directly. + crdName := "rayclusters.ray.io" + if err := checkCRDExists(mgr.GetClient(), crdName); err != nil { + return fmt.Errorf("failed to validate CRD: %v", err) + } r, err := newReconciler(mgr, runtimeConfig) if err != nil { @@ -58,6 +64,29 @@ func Add(mgr manager.Manager, runtimeConfig config.RuntimeConfig) error { return add(mgr, r) } +// checkCRDExists checks if the specified CRD exists in the cluster. +func checkCRDExists(c client.Client, crdName string) error { + gvk := schema.GroupVersionKind{ + Group: "apiextensions.k8s.io", + Version: "v1", + Kind: "CustomResourceDefinition", + } + + // Create an unstructured object to represent the CRD. + crd := &unstructured.Unstructured{} + crd.SetGroupVersionKind(gvk) + crd.SetName(crdName) + + err := c.Get(context.TODO(), client.ObjectKey{Name: crdName}, crd) + if err != nil { + if apierrors.IsNotFound(err) { + return fmt.Errorf("CRD %q not found. Please ensure %q is installed", crdName, crdName) + } + return fmt.Errorf("error checking CRD %q: %v", crdName, err) + } + return nil +} + // newReconciler returns a new reconcile.Reconciler func newReconciler(mgr manager.Manager, runtimeConfig config.RuntimeConfig) (reconcile.Reconciler, error) { reconciler := &RayClusterReplicaSetReconciler{