diff --git a/Documentation/ceph-nfs-crd.md b/Documentation/ceph-nfs-crd.md index 01d10b9d0..87826f6ef 100644 --- a/Documentation/ceph-nfs-crd.md +++ b/Documentation/ceph-nfs-crd.md @@ -78,9 +78,11 @@ spec: All daemons within a cluster will share configuration with no exports defined, and that includes a RADOS object via: ```ini -%url rados:////conf-nfs. +%url rados:////conf-nfs.ganesha- ``` +> **NOTE**: This format of nfs-ganesha config object name was introduced in Ceph Octopus Version. In older versions, each daemon has it's own config object and with the name as *conf-.*. The nodeid is a value automatically assigned internally by rook. Nodeids start with "a" and go through "z", at which point they become two letters ("aa" to "az"). + The pool and namespace are configured via the spec's RADOS block. When a server is started, it will create the included object if it does not already exist. It is possible to prepopulate the included objects prior to starting the server. The format for these objects is documented in the [NFS Ganesha](https://github.com/nfs-ganesha/nfs-ganesha/wiki) project. diff --git a/pkg/operator/ceph/nfs/config.go b/pkg/operator/ceph/nfs/config.go index d417cf90f..37c0188d4 100644 --- a/pkg/operator/ceph/nfs/config.go +++ b/pkg/operator/ceph/nfs/config.go @@ -24,6 +24,7 @@ import ( cephclient "github.com/rook/rook/pkg/daemon/ceph/client" "github.com/rook/rook/pkg/operator/ceph/config/keyring" opcontroller "github.com/rook/rook/pkg/operator/ceph/controller" + cephver "github.com/rook/rook/pkg/operator/ceph/version" ) const ( @@ -47,18 +48,21 @@ func getNFSNodeID(n *cephv1.CephNFS, name string) string { return fmt.Sprintf("%s.%s", n.Name, name) } -func getGaneshaConfigObject(clusterName string) string { - return fmt.Sprintf("conf-nfs.%s", clusterName) +func getGaneshaConfigObject(n *cephv1.CephNFS, version cephver.CephVersion, name string) string { + if version.IsAtLeastOctopus() { + return fmt.Sprintf("conf-nfs.ganesha-%s", n.Name) + } + return fmt.Sprintf("conf-%s", getNFSNodeID(n, name)) } -func getRadosURL(n *cephv1.CephNFS) string { +func getRadosURL(n *cephv1.CephNFS, version cephver.CephVersion, name string) string { url := fmt.Sprintf("rados://%s/", n.Spec.RADOS.Pool) if n.Spec.RADOS.Namespace != "" { url += n.Spec.RADOS.Namespace + "/" } - url += getGaneshaConfigObject(n.Name) + url += getGaneshaConfigObject(n, version, name) return url } @@ -88,10 +92,10 @@ func (r *ReconcileCephNFS) generateKeyring(n *cephv1.CephNFS, name string) error return s.CreateOrUpdate(instanceName(n, name), keyring) } -func getGaneshaConfig(n *cephv1.CephNFS, name string) string { +func getGaneshaConfig(n *cephv1.CephNFS, version cephver.CephVersion, name string) string { nodeID := getNFSNodeID(n, name) userID := getNFSUserID(nodeID) - url := getRadosURL(n) + url := getRadosURL(n, version, name) return ` NFS_CORE_PARAM { Enable_NLM = false; diff --git a/pkg/operator/ceph/nfs/controller_test.go b/pkg/operator/ceph/nfs/controller_test.go index cd22a29aa..1c70ca66e 100644 --- a/pkg/operator/ceph/nfs/controller_test.go +++ b/pkg/operator/ceph/nfs/controller_test.go @@ -28,6 +28,7 @@ import ( rookclient "github.com/rook/rook/pkg/client/clientset/versioned/fake" "github.com/rook/rook/pkg/client/clientset/versioned/scheme" "github.com/rook/rook/pkg/clusterd" + cephver "github.com/rook/rook/pkg/operator/ceph/version" "github.com/rook/rook/pkg/operator/k8sutil" "github.com/rook/rook/pkg/operator/test" exectest "github.com/rook/rook/pkg/util/exec/test" @@ -224,6 +225,7 @@ func TestCephNFSController(t *testing.T) { if command == "rados" { logger.Infof("mock execute. %s. %s", command, args) assert.Equal(t, "stat", args[6]) + assert.Equal(t, "conf-my-nfs.a", args[7]) return nil } return errors.New("unknown command") @@ -252,3 +254,26 @@ func TestCephNFSController(t *testing.T) { assert.Equal(t, "Ready", cephNFS.Status.Phase, cephNFS) logger.Info("PHASE 3 DONE") } + +func TestGetGaneshaConfigObject(t *testing.T) { + cephNFS := &cephv1.CephNFS{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + } + nodeid := "a" + expectedName := "conf-nfs.ganesha-my-nfs" + + res := getGaneshaConfigObject(cephNFS, cephver.CephVersion{Major: 16}, nodeid) + logger.Infof("Config Object for Pacific is %s", res) + assert.Equal(t, expectedName, res) + + res = getGaneshaConfigObject(cephNFS, cephver.CephVersion{Major: 15, Minor: 2, Extra: 1}, nodeid) + logger.Infof("Config Object for Octopus is %s", res) + assert.Equal(t, expectedName, res) + + res = getGaneshaConfigObject(cephNFS, cephver.CephVersion{Major: 14, Minor: 2, Extra: 5}, nodeid) + logger.Infof("Config Object for Nautilus is %s", res) + assert.Equal(t, "conf-my-nfs.a", res) +} diff --git a/pkg/operator/ceph/nfs/nfs.go b/pkg/operator/ceph/nfs/nfs.go index 3587286d0..b06930ed9 100644 --- a/pkg/operator/ceph/nfs/nfs.go +++ b/pkg/operator/ceph/nfs/nfs.go @@ -57,7 +57,7 @@ func (r *ReconcileCephNFS) upCephNFS(n *cephv1.CephNFS, oldActive int) error { return errors.Wrap(err, "failed to create config") } - err = r.addRADOSConfigFile(n) + err = r.addRADOSConfigFile(n, id) if err != nil { return errors.Wrap(err, "failed to create RADOS config object") } @@ -125,8 +125,8 @@ func (r *ReconcileCephNFS) upCephNFS(n *cephv1.CephNFS, oldActive int) error { } // Create empty config file for new ganesha server -func (r *ReconcileCephNFS) addRADOSConfigFile(n *cephv1.CephNFS) error { - config := getGaneshaConfigObject(n.Name) +func (r *ReconcileCephNFS) addRADOSConfigFile(n *cephv1.CephNFS, name string) error { + config := getGaneshaConfigObject(n, r.clusterInfo.CephVersion, name) cmd := "rados" args := []string{ "--pool", n.Spec.RADOS.Pool, @@ -173,11 +173,11 @@ func (r *ReconcileCephNFS) runGaneshaRadosGrace(nfs *cephv1.CephNFS, name, actio func (r *ReconcileCephNFS) generateConfigMap(n *cephv1.CephNFS, name string) *v1.ConfigMap { data := map[string]string{ - "config": getGaneshaConfig(n, name), + "config": getGaneshaConfig(n, r.clusterInfo.CephVersion, name), } configMap := &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-%s-%s", AppName, n.Name, name), + Name: instanceName(n, name), Namespace: n.Namespace, Labels: getLabels(n, name, true), },