diff --git a/deploy/csi-config-map-sample.yaml b/deploy/csi-config-map-sample.yaml index 1766d3227..706980825 100644 --- a/deploy/csi-config-map-sample.yaml +++ b/deploy/csi-config-map-sample.yaml @@ -24,6 +24,12 @@ kind: ConfigMap # The "cephFS.netNamespaceFilePath" fields are the various network namespace # path for the Ceph cluster identified by the , This will be used # by the CephFS CSI plugin to execute the mount -t in the +# The "cephFS.kernelMountOptions" fields are comma separated mount options +# for `Ceph kernel client`. Setting this will override the kernelmountoptions +# command line flag. +# The "cephFS.fuseMountOptions" fields are common separated mount options +# for `Ceph FUSE driver`. Setting this will override the fusemountoptions +# command line flag. # network namespace specified by the "cephFS.netNamespaceFilePath". # The "nfs.netNamespaceFilePath" fields are the various network namespace # path for the Ceph cluster identified by the , This will be used @@ -68,6 +74,8 @@ data: "cephFS": { "subvolumeGroup": "" "netNamespaceFilePath": "/plugins/cephfs.csi.ceph.com/net", + "kernelMountOptions": "", + "fuseMountOptions": "" } "nfs": { "netNamespaceFilePath": "/plugins/nfs.csi.ceph.com/net", diff --git a/internal/util/csiconfig.go b/internal/util/csiconfig.go index abacab329..f2355fabd 100644 --- a/internal/util/csiconfig.go +++ b/internal/util/csiconfig.go @@ -43,30 +43,40 @@ type ClusterInfo struct { // Monitors is monitor list for corresponding cluster ID Monitors []string `json:"monitors"` // CephFS contains CephFS specific options - CephFS struct { - // symlink filepath for the network namespace where we need to execute commands. - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - // SubvolumeGroup contains the name of the SubvolumeGroup for CSI volumes - SubvolumeGroup string `json:"subvolumeGroup"` - } `json:"cephFS"` - + CephFS CephFS `json:"cephFS"` // RBD Contains RBD specific options - RBD struct { - // symlink filepath for the network namespace where we need to execute commands. - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - // RadosNamespace is a rados namespace in the pool - RadosNamespace string `json:"radosNamespace"` - } `json:"rbd"` + RBD RBD `json:"rbd"` // NFS contains NFS specific options - NFS struct { - // symlink filepath for the network namespace where we need to execute commands. - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - } `json:"nfs"` + NFS NFS `json:"nfs"` // Read affinity map options - ReadAffinity struct { - Enabled bool `json:"enabled"` - CrushLocationLabels []string `json:"crushLocationLabels"` - } `json:"readAffinity"` + ReadAffinity ReadAffinity `json:"readAffinity"` +} + +type CephFS struct { + // symlink filepath for the network namespace where we need to execute commands. + NetNamespaceFilePath string `json:"netNamespaceFilePath"` + // SubvolumeGroup contains the name of the SubvolumeGroup for CSI volumes + SubvolumeGroup string `json:"subvolumeGroup"` + // KernelMountOptions contains the kernel mount options for CephFS volumes + KernelMountOptions string `json:"kernelMountOptions"` + // FuseMountOptions contains the fuse mount options for CephFS volumes + FuseMountOptions string `json:"fuseMountOptions"` +} +type RBD struct { + // symlink filepath for the network namespace where we need to execute commands. + NetNamespaceFilePath string `json:"netNamespaceFilePath"` + // RadosNamespace is a rados namespace in the pool + RadosNamespace string `json:"radosNamespace"` +} + +type NFS struct { + // symlink filepath for the network namespace where we need to execute commands. + NetNamespaceFilePath string `json:"netNamespaceFilePath"` +} + +type ReadAffinity struct { + Enabled bool `json:"enabled"` + CrushLocationLabels []string `json:"crushLocationLabels"` } // Expected JSON structure in the passed in config file is, @@ -226,3 +236,13 @@ func GetCrushLocationLabels(pathToConfig, clusterID string) (bool, string, error return true, crushLocationLabels, nil } + +// GetCephFSMountOptions returns the `kernelMountOptions` and `fuseMountOptions` for CephFS volumes. +func GetCephFSMountOptions(pathToConfig, clusterID string) (string, string, error) { + cluster, err := readClusterInfo(pathToConfig, clusterID) + if err != nil { + return "", "", err + } + + return cluster.CephFS.KernelMountOptions, cluster.CephFS.FuseMountOptions, nil +} diff --git a/internal/util/csiconfig_test.go b/internal/util/csiconfig_test.go index 40e1b4d5e..1e00f80aa 100644 --- a/internal/util/csiconfig_test.go +++ b/internal/util/csiconfig_test.go @@ -168,20 +168,14 @@ func TestGetRBDNetNamespaceFilePath(t *testing.T) { { ClusterID: "cluster-1", Monitors: []string{"ip-1", "ip-2"}, - RBD: struct { - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - RadosNamespace string `json:"radosNamespace"` - }{ + RBD: RBD{ NetNamespaceFilePath: "/var/lib/kubelet/plugins/rbd.ceph.csi.com/cluster1-net", }, }, { ClusterID: "cluster-2", Monitors: []string{"ip-3", "ip-4"}, - RBD: struct { - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - RadosNamespace string `json:"radosNamespace"` - }{ + RBD: RBD{ NetNamespaceFilePath: "/var/lib/kubelet/plugins/rbd.ceph.csi.com/cluster2-net", }, }, @@ -244,20 +238,14 @@ func TestGetCephFSNetNamespaceFilePath(t *testing.T) { { ClusterID: "cluster-1", Monitors: []string{"ip-1", "ip-2"}, - CephFS: struct { - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - SubvolumeGroup string `json:"subvolumeGroup"` - }{ + CephFS: CephFS{ NetNamespaceFilePath: "/var/lib/kubelet/plugins/cephfs.ceph.csi.com/cluster1-net", }, }, { ClusterID: "cluster-2", Monitors: []string{"ip-3", "ip-4"}, - CephFS: struct { - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - SubvolumeGroup string `json:"subvolumeGroup"` - }{ + CephFS: CephFS{ NetNamespaceFilePath: "/var/lib/kubelet/plugins/cephfs.ceph.csi.com/cluster2-net", }, }, @@ -320,18 +308,14 @@ func TestGetNFSNetNamespaceFilePath(t *testing.T) { { ClusterID: "cluster-1", Monitors: []string{"ip-1", "ip-2"}, - NFS: struct { - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - }{ + NFS: NFS{ NetNamespaceFilePath: "/var/lib/kubelet/plugins/nfs.ceph.csi.com/cluster1-net", }, }, { ClusterID: "cluster-2", Monitors: []string{"ip-3", "ip-4"}, - NFS: struct { - NetNamespaceFilePath string `json:"netNamespaceFilePath"` - }{ + NFS: NFS{ NetNamespaceFilePath: "/var/lib/kubelet/plugins/nfs.ceph.csi.com/cluster2-net", }, }, @@ -413,10 +397,7 @@ func TestGetReadAffinityOptions(t *testing.T) { csiConfig := []ClusterInfo{ { ClusterID: "cluster-1", - ReadAffinity: struct { - Enabled bool `json:"enabled"` - CrushLocationLabels []string `json:"crushLocationLabels"` - }{ + ReadAffinity: ReadAffinity{ Enabled: true, CrushLocationLabels: []string{ "topology.kubernetes.io/region", @@ -427,10 +408,7 @@ func TestGetReadAffinityOptions(t *testing.T) { }, { ClusterID: "cluster-2", - ReadAffinity: struct { - Enabled bool `json:"enabled"` - CrushLocationLabels []string `json:"crushLocationLabels"` - }{ + ReadAffinity: ReadAffinity{ Enabled: true, CrushLocationLabels: []string{ "topology.kubernetes.io/region", @@ -439,10 +417,7 @@ func TestGetReadAffinityOptions(t *testing.T) { }, { ClusterID: "cluster-3", - ReadAffinity: struct { - Enabled bool `json:"enabled"` - CrushLocationLabels []string `json:"crushLocationLabels"` - }{ + ReadAffinity: ReadAffinity{ Enabled: false, CrushLocationLabels: []string{ "topology.io/rack", @@ -478,3 +453,78 @@ func TestGetReadAffinityOptions(t *testing.T) { }) } } + +func TestGetCephFSMountOptions(t *testing.T) { + t.Parallel() + tests := []struct { + name string + clusterID string + wantKernelMntOptions string + wantFuseMntOptions string + }{ + { + name: "cluster-1 with non-empty mount options", + clusterID: "cluster-1", + wantKernelMntOptions: "crc", + wantFuseMntOptions: "ro", + }, + { + name: "cluster-2 with empty mount options", + clusterID: "cluster-2", + wantKernelMntOptions: "", + wantFuseMntOptions: "", + }, + { + name: "cluster-3 with no mount options", + clusterID: "cluster-3", + wantKernelMntOptions: "", + wantFuseMntOptions: "", + }, + } + + csiConfig := []ClusterInfo{ + { + ClusterID: "cluster-1", + CephFS: CephFS{ + KernelMountOptions: "crc", + FuseMountOptions: "ro", + }, + }, + { + ClusterID: "cluster-2", + CephFS: CephFS{ + KernelMountOptions: "", + FuseMountOptions: "", + }, + }, + { + ClusterID: "cluster-3", + CephFS: CephFS{}, + }, + } + csiConfigFileContent, err := json.Marshal(csiConfig) + if err != nil { + t.Errorf("failed to marshal csi config info %v", err) + } + tmpConfPath := t.TempDir() + "/ceph-csi.json" + err = os.WriteFile(tmpConfPath, csiConfigFileContent, 0o600) + if err != nil { + t.Errorf("failed to write %s file content: %v", CsiConfigFile, err) + } + + for _, tt := range tests { + tc := tt + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + kernelMntOptions, fuseMntOptions, err := GetCephFSMountOptions(tmpConfPath, tc.clusterID) + if err != nil { + t.Errorf("GetCephFSMountOptions() error = %v", err) + } + if kernelMntOptions != tc.wantKernelMntOptions || fuseMntOptions != tc.wantFuseMntOptions { + t.Errorf("GetCephFSMountOptions() = (%v, %v), want (%v, %v)", + kernelMntOptions, fuseMntOptions, tc.wantKernelMntOptions, tc.wantFuseMntOptions, + ) + } + }) + } +}