diff --git a/deploy/charts/rook-ceph/templates/clusterrole.yaml b/deploy/charts/rook-ceph/templates/clusterrole.yaml index b525da6cb..09280f285 100644 --- a/deploy/charts/rook-ceph/templates/clusterrole.yaml +++ b/deploy/charts/rook-ceph/templates/clusterrole.yaml @@ -27,6 +27,9 @@ rules: - apiGroups: ["csi.ceph.io"] resources: ["cephconnections"] verbs: ["create", "delete", "get", "list","update", "watch"] + - apiGroups: ["csi.ceph.io"] + resources: ["clientprofiles"] + verbs: ["create", "delete", "get", "list", "update", "watch"] --- # The cluster role for managing all the cluster-specific resources in a namespace apiVersion: rbac.authorization.k8s.io/v1 diff --git a/deploy/examples/common.yaml b/deploy/examples/common.yaml index 8dce9be2c..4c8eb689a 100644 --- a/deploy/examples/common.yaml +++ b/deploy/examples/common.yaml @@ -609,6 +609,9 @@ rules: - apiGroups: ["csi.ceph.io"] resources: ["cephconnections"] verbs: ["create", "delete", "get", "list", "update", "watch"] + - apiGroups: ["csi.ceph.io"] + resources: ["clientprofiles"] + verbs: ["create", "delete", "get", "list", "update", "watch"] --- # This is required by operator-sdk to map the cluster/clusterrolebindings with SA # otherwise operator-sdk will create a individual file for these. diff --git a/pkg/operator/ceph/cluster/mon/mon.go b/pkg/operator/ceph/cluster/mon/mon.go index 2a9a9a843..d80839d65 100644 --- a/pkg/operator/ceph/cluster/mon/mon.go +++ b/pkg/operator/ceph/cluster/mon/mon.go @@ -1117,6 +1117,10 @@ func (c *Cluster) saveMonConfig() error { if err != nil { return errors.Wrap(err, "failed to create/update cephConnection") } + err = csi.CreateDefaultClientProfile(c.context.Client, c.ClusterInfo, c.ClusterInfo.NamespacedName()) + if err != nil { + return errors.Wrap(err, "failed to create/update default client profile") + } } return nil diff --git a/pkg/operator/ceph/csi/config.go b/pkg/operator/ceph/csi/config.go new file mode 100644 index 000000000..482c71545 --- /dev/null +++ b/pkg/operator/ceph/csi/config.go @@ -0,0 +1,174 @@ +/* +Copyright 2024 The Rook Authors. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package csi + +import ( + "context" + "strings" + + cephclient "github.com/rook/rook/pkg/daemon/ceph/client" + + csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1" + "github.com/pkg/errors" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func CreateUpdateClientProfileRadosNamespace(ctx context.Context, c client.Client, clusterInfo *cephclient.ClusterInfo, cephBlockPoolRadosNamespacedName types.NamespacedName, clusterID, clusterName string) error { + + logger.Info("creating ceph-csi clientProfile CR for rados namespace") + + csiOpClientProfile := &csiopv1a1.ClientProfile{} + csiOpClientProfile.Name = clusterID + csiOpClientProfile.Namespace = cephBlockPoolRadosNamespacedName.Namespace + csiOpClientProfile.Spec = csiopv1a1.ClientProfileSpec{ + CephConnectionRef: v1.LocalObjectReference{ + Name: clusterName, + }, + Rbd: &csiopv1a1.RbdConfigSpec{ + RadosNamespace: cephBlockPoolRadosNamespacedName.Name, + }, + } + + err := clusterInfo.OwnerInfo.SetOwnerReference(csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to set owner reference for clientProfile CR %q for radosNamespace", csiOpClientProfile.Name) + } + + err = c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile) + if err != nil { + if apierrors.IsNotFound(err) { + err = c.Create(ctx, csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for RBD %q", csiOpClientProfile.Name) + } + logger.Infof("successfully created ceph-csi clientProfile CR for RBD %q", csiOpClientProfile.Name) + return nil + } + return err + } + + err = c.Update(ctx, csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for RBD %q", csiOpClientProfile.Name) + } + logger.Infof("successfully updated ceph-csi clientProfile CR for RBD %q", csiOpClientProfile.Name) + + return nil +} + +func CreateUpdateClientProfileSubVolumeGroup(ctx context.Context, c client.Client, clusterInfo *cephclient.ClusterInfo, cephFilesystemNamespacedName types.NamespacedName, clusterID, clusterName string) error { + + logger.Info("Creating ceph-csi clientProfile CR for subvolume group") + + csiOpClientProfile := generateProfileSubVolumeGroupSpec(clusterInfo, cephFilesystemNamespacedName, clusterID, clusterName) + + err := clusterInfo.OwnerInfo.SetOwnerReference(csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to set owner reference for clientProfile CR %q for subVolGrp", csiOpClientProfile.Name) + } + + err = c.Get(ctx, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile) + if err != nil { + if apierrors.IsNotFound(err) { + err = c.Create(ctx, csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for subVolGrp %q", csiOpClientProfile.Name) + } + logger.Infof("successfully created ceph-csi clientProfile CR for subVolGrp %q", csiOpClientProfile.Name) + return nil + } + return err + } + + err = c.Update(ctx, csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to create ceph-csi clientProfile cr for subVolGrp %q", csiOpClientProfile.Name) + } + logger.Infof("successfully updated ceph-csi clientProfile CR for subVolGrp %q", csiOpClientProfile.Name) + + return nil +} + +func generateProfileSubVolumeGroupSpec(clusterInfo *cephclient.ClusterInfo, cephFilesystemNamespacedName types.NamespacedName, clusterID, clusterName string) *csiopv1a1.ClientProfile { + csiOpClientProfile := &csiopv1a1.ClientProfile{} + csiOpClientProfile.Name = clusterID + csiOpClientProfile.Namespace = cephFilesystemNamespacedName.Namespace + csiOpClientProfile.Spec = csiopv1a1.ClientProfileSpec{ + CephConnectionRef: v1.LocalObjectReference{ + Name: clusterName, + }, + CephFs: &csiopv1a1.CephFsConfigSpec{ + SubVolumeGroup: cephFilesystemNamespacedName.Name, + }, + } + + kernelMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.KernelMountOptions, "=") + fuseMountKeyVal := strings.Split(clusterInfo.CSIDriverSpec.CephFS.FuseMountOptions, "=") + + if len(kernelMountKeyVal) == 2 { + csiOpClientProfile.Spec.CephFs.KernelMountOptions = map[string]string{kernelMountKeyVal[0]: kernelMountKeyVal[1]} + } + + if len(fuseMountKeyVal) == 2 { + csiOpClientProfile.Spec.CephFs.FuseMountOptions = map[string]string{fuseMountKeyVal[0]: fuseMountKeyVal[1]} + } + + return csiOpClientProfile +} + +// CreateDefaultClientProfile creates a default client profile for csi-operator to connect driver +func CreateDefaultClientProfile(c client.Client, clusterInfo *cephclient.ClusterInfo, namespaced types.NamespacedName) error { + logger.Info("Creating ceph-csi clientProfile default CR") + + csiOpClientProfile := &csiopv1a1.ClientProfile{} + csiOpClientProfile.Name = clusterInfo.Namespace + csiOpClientProfile.Namespace = clusterInfo.Namespace + csiOpClientProfile.Spec = csiopv1a1.ClientProfileSpec{ + CephConnectionRef: v1.LocalObjectReference{ + Name: namespaced.Name, + }, + } + + err := clusterInfo.OwnerInfo.SetOwnerReference(csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to set owner reference for default clientProfile CR %q", csiOpClientProfile.Name) + } + + err = c.Get(clusterInfo.Context, types.NamespacedName{Name: csiOpClientProfile.Name, Namespace: csiOpClientProfile.Namespace}, csiOpClientProfile) + if err != nil { + if apierrors.IsNotFound(err) { + err = c.Create(clusterInfo.Context, csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to create ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + } + logger.Infof("successfully created ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + return nil + } + return err + } + + err = c.Update(clusterInfo.Context, csiOpClientProfile) + if err != nil { + return errors.Wrapf(err, "failed to create ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + } + logger.Infof("successfully updated ceph-csi for default clientProfile CR %q", csiOpClientProfile.Name) + + return nil +} diff --git a/pkg/operator/ceph/file/subvolumegroup/controller.go b/pkg/operator/ceph/file/subvolumegroup/controller.go index cf7fb7564..5e7cb80f7 100644 --- a/pkg/operator/ceph/file/subvolumegroup/controller.go +++ b/pkg/operator/ceph/file/subvolumegroup/controller.go @@ -25,6 +25,7 @@ import ( "syscall" "time" + csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1" "github.com/pkg/errors" cephclient "github.com/rook/rook/pkg/daemon/ceph/client" "github.com/rook/rook/pkg/util/exec" @@ -106,6 +107,11 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } + err = csiopv1a1.AddToScheme(mgr.GetScheme()) + if err != nil { + return err + } + return nil } @@ -265,6 +271,14 @@ func (r *ReconcileCephFilesystemSubVolumeGroup) reconcile(request reconcile.Requ } r.updateStatus(observedGeneration, request.NamespacedName, cephv1.ConditionReady) + + if csi.EnableCSIOperator() { + err = csi.CreateUpdateClientProfileSubVolumeGroup(r.clusterInfo.Context, r.client, r.clusterInfo, cephFilesystemNamespacedName, buildClusterID(cephFilesystemSubVolumeGroup), cephCluster.Name) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to create ceph csi-op config CR for subVolGrp ns") + } + } + // Return and do not requeue logger.Debugf("done reconciling cephFilesystemSubVolumeGroup %q", namespacedName) return reconcile.Result{}, nil diff --git a/pkg/operator/ceph/pool/radosnamespace/controller.go b/pkg/operator/ceph/pool/radosnamespace/controller.go index 7811818f8..cd8e6fe7d 100644 --- a/pkg/operator/ceph/pool/radosnamespace/controller.go +++ b/pkg/operator/ceph/pool/radosnamespace/controller.go @@ -24,6 +24,7 @@ import ( "strings" "time" + csiopv1a1 "github.com/ceph/ceph-csi-operator/api/v1alpha1" cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1" "github.com/rook/rook/pkg/clusterd" cephclient "github.com/rook/rook/pkg/daemon/ceph/client" @@ -104,6 +105,11 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error { return err } + err = csiopv1a1.AddToScheme(mgr.GetScheme()) + if err != nil { + return err + } + return nil } @@ -256,6 +262,14 @@ func (r *ReconcileCephBlockPoolRadosNamespace) reconcile(request reconcile.Reque } r.updateStatus(r.client, namespacedName, cephv1.ConditionReady) + + if csi.EnableCSIOperator() { + err = csi.CreateUpdateClientProfileRadosNamespace(r.clusterInfo.Context, r.client, r.clusterInfo, cephBlockPoolRadosNamespacedName, buildClusterID(cephBlockPoolRadosNamespace), cephCluster.Name) + if err != nil { + return reconcile.Result{}, errors.Wrap(err, "failed to create ceph csi-op config CR for RadosNamespace") + } + } + // Return and do not requeue logger.Debugf("done reconciling cephBlockPoolRadosNamespace %q", namespacedName) return reconcile.Result{}, nil