Skip to content

Commit

Permalink
nfs: add support for clients in the StorageClass
Browse files Browse the repository at this point in the history
The clients parameter in the storage class is used to limit access to
the export to the set of hostnames, networks or ip addresses specified.

Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
  • Loading branch information
spuiuk committed Jun 30, 2023
1 parent 37f1d72 commit 6df0f7e
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 0 deletions.
33 changes: 33 additions & 0 deletions e2e/nfs.go
Expand Up @@ -440,6 +440,39 @@ var _ = Describe("nfs", func() {
}
})

By("create a storageclass with a restricted set of clients allowed to mount it", func() {
clientExample := "192.168.49.29"
err := createNFSStorageClass(f.ClientSet, f, false, map[string]string{
"clients": clientExample,
})
if err != nil {
framework.Failf("failed to create NFS storageclass: %v", err)
}
pvc, err := loadPVC(pvcPath)
if err != nil {
framework.Failf("Could not create PVC: %v", err)
}
pvc.Namespace = f.UniqueName
err = createPVCAndvalidatePV(f.ClientSet, pvc, deployTimeout)
if err != nil {
framework.Failf("failed to create PVC: %v", err)

}

if !checkExports(f, "my-nfs", clientExample) {
framework.Failf("failed in testing exports")
}

err = deletePVCAndValidatePV(f.ClientSet, pvc, deployTimeout)
if err != nil {
framework.Failf("failed to delete PVC: %v", err)
}
err = deleteResource(nfsExamplePath + "storageclass.yaml")
if err != nil {
framework.Failf("failed to delete NFS storageclass: %v", err)
}
})

By("create a PVC and bind it to an app", func() {
err := createNFSStorageClass(f.ClientSet, f, false, nil)
if err != nil {
Expand Down
97 changes: 97 additions & 0 deletions e2e/utils.go
Expand Up @@ -129,6 +129,56 @@ func listCephFSFileSystems(f *framework.Framework) ([]cephfsFilesystem, error) {
return fsList, nil
}

type nfsExportsFSAL struct {
Name string `json:"name"`
UserID string `json:"user_id"`
FSName string `json:"fs_name"`
}

type nfsExportsClients struct {
Addresses []string `json:"addresses"`
AccessType string `json:"access_type"`
Squash string `json:"squash"`
}

type cephNFSExport struct {
ExportID string `json:"export_id"`
Path string `json:"path"`
ClusterID string `json:"cluster_id"`
Pseudo string `json:"pseudo"`
AccessType string `json:"access_type"`
Squash string `json:"squash"`
SecurityLabel string `json:"security_label"`
Protocols []int `json:"protocols"`
Transports []string `json:"transports"`
FSAL nfsExportsFSAL `json:"fsal"`
Clients []nfsExportsClients `json:"clients"`
SecTypes []string `json:"secTypes"`
}

// Get list of exports for a cluster_id
func listExports(f *framework.Framework, clusterID string) ([]cephNFSExport, error) {
var exportList []cephNFSExport

stdout, stdErr, err := execCommandInToolBoxPod(
f,
"ceph nfs export ls "+clusterID+" --detailed",
rookNamespace)
if err != nil {
return exportList, err
}
if stdErr != "" {
return exportList, fmt.Errorf("error listing exports in clusterID %v", stdErr)
}

err = json.Unmarshal([]byte(stdout), &exportList)
if err != nil {
return exportList, err
}

return exportList, nil
}

// getCephFSMetadataPoolName get CephFS pool name from filesystem name.
func getCephFSMetadataPoolName(f *framework.Framework, filesystem string) (string, error) {
fsList, err := listCephFSFileSystems(f)
Expand Down Expand Up @@ -1743,3 +1793,50 @@ func getConfigFile(filename, preferred, fallback string) string {

return configFile
}

// Check the export for a listed ip address and confirm that the export has
// been setup correctly.
func checkExports(f *framework.Framework, clusterID string, clientString string) bool {
exportList, err := listExports(f, clusterID)
if err != nil {
framework.Logf("failed to fetch list of exports: %v", err)
return false
}
framework.Logf("exports %v", exportList)

found := false
for _, export := range exportList {
for _, client := range export.Clients {
for _, address := range client.Addresses {
if address == clientString {
found = true

break
}
}
if found {
if client.AccessType != "rw" {
framework.Logf("Unexpected value for client AccessType: %s", client.AccessType)
return false
}

break
}
}
if found {
if export.AccessType != "none" {
framework.Logf("Unexpected value for default AccessType: %s", export.AccessType)
return false
}

break
}
}

if !found {
framework.Logf("Could not find the configured clients in the list of exports")
return false
}

return true
}
6 changes: 6 additions & 0 deletions examples/nfs/storageclass.yaml
Expand Up @@ -51,5 +51,11 @@ parameters:
# This option is available with Ceph v17.2.6 and newer.
# secTypes: <sectype-list>

# (optional) The clients parameter in the storage class is used to limit
# access to the export to the set of hostnames, networks or ip addresses
# specified. The <client-list> is a comma delimited string,
# for example: "192.168.0.10,192.168.1.0/8"
# clients: <client-list>

reclaimPolicy: Delete
allowVolumeExpansion: true
5 changes: 5 additions & 0 deletions internal/nfs/controller/volume.go
Expand Up @@ -132,6 +132,7 @@ func (nv *NFSVolume) CreateExport(backend *csi.Volume) error {
nfsCluster := backend.VolumeContext["nfsCluster"]
path := backend.VolumeContext["subvolumePath"]
secTypes := backend.VolumeContext["secTypes"]
clients := backend.VolumeContext["clients"]

err := nv.setNFSCluster(nfsCluster)
if err != nil {
Expand All @@ -157,6 +158,10 @@ func (nv *NFSVolume) CreateExport(backend *csi.Volume) error {
}
}

if clients != "" {
export.ClientAddr = strings.Split(clients, ",")
}

_, err = nfsa.CreateCephFSExport(export)
switch {
case err == nil:
Expand Down

0 comments on commit 6df0f7e

Please sign in to comment.