feat: add mountPermissions parameter in storage class
This commit is contained in:
parent
74791bc947
commit
14275e0be0
@ -8,6 +8,7 @@ Name | Meaning | Example Value | Mandatory | Default value
|
|||||||
--- | --- | --- | --- | ---
|
--- | --- | --- | --- | ---
|
||||||
server | NFS Server address | domain name `nfs-server.default.svc.cluster.local` <br>or IP address `127.0.0.1` | Yes |
|
server | NFS Server address | domain name `nfs-server.default.svc.cluster.local` <br>or IP address `127.0.0.1` | Yes |
|
||||||
share | NFS share path | `/` | Yes |
|
share | NFS share path | `/` | Yes |
|
||||||
|
mountPermissions | mounted folder permissions. The default is `0777` | | No |
|
||||||
|
|
||||||
### PV/PVC usage (static provisioning)
|
### PV/PVC usage (static provisioning)
|
||||||
> [`PersistentVolume` example](../deploy/example/pv-nfs-csi.yaml)
|
> [`PersistentVolume` example](../deploy/example/pv-nfs-csi.yaml)
|
||||||
@ -16,7 +17,7 @@ Name | Meaning | Example Value | Mandatory | Default value
|
|||||||
--- | --- | --- | --- | ---
|
--- | --- | --- | --- | ---
|
||||||
volumeAttributes.server | NFS Server address | domain name `nfs-server.default.svc.cluster.local` <br>or IP address `127.0.0.1` | Yes |
|
volumeAttributes.server | NFS Server address | domain name `nfs-server.default.svc.cluster.local` <br>or IP address `127.0.0.1` | Yes |
|
||||||
volumeAttributes.share | NFS share path | `/` | Yes |
|
volumeAttributes.share | NFS share path | `/` | Yes |
|
||||||
|
volumeAttributes.mountPermissions | mounted folder permissions. The default is `0777` | | No |
|
||||||
|
|
||||||
### Tips
|
### Tips
|
||||||
#### provide `mountOptions` for `DeleteVolume`
|
#### provide `mountOptions` for `DeleteVolume`
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||||
@ -78,8 +79,32 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
|
|||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mountPermissions := cs.Driver.mountPermissions
|
||||||
reqCapacity := req.GetCapacityRange().GetRequiredBytes()
|
reqCapacity := req.GetCapacityRange().GetRequiredBytes()
|
||||||
nfsVol, err := cs.newNFSVolume(name, reqCapacity, req.GetParameters())
|
parameters := req.GetParameters()
|
||||||
|
if parameters == nil {
|
||||||
|
parameters = make(map[string]string)
|
||||||
|
}
|
||||||
|
// validate parameters (case-insensitive)
|
||||||
|
for k, v := range parameters {
|
||||||
|
switch strings.ToLower(k) {
|
||||||
|
case paramServer:
|
||||||
|
// no op
|
||||||
|
case paramShare:
|
||||||
|
// no op
|
||||||
|
case mountPermissionsField:
|
||||||
|
if v != "" {
|
||||||
|
var err error
|
||||||
|
if mountPermissions, err = strconv.ParseUint(v, 8, 32); err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("invalid mountPermissions %s in storage class", v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("invalid parameter %q in storage class", k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nfsVol, err := cs.newNFSVolume(name, reqCapacity, parameters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
@ -89,7 +114,7 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
|
|||||||
volCap = req.GetVolumeCapabilities()[0]
|
volCap = req.GetVolumeCapabilities()[0]
|
||||||
}
|
}
|
||||||
// Mount nfs base share so we can create a subdirectory
|
// Mount nfs base share so we can create a subdirectory
|
||||||
if err = cs.internalMount(ctx, nfsVol, volCap); err != nil {
|
if err = cs.internalMount(ctx, nfsVol, parameters, volCap); err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to mount nfs server: %v", err.Error())
|
return nil, status.Errorf(codes.Internal, "failed to mount nfs server: %v", err.Error())
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -98,7 +123,7 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fileMode := os.FileMode(cs.Driver.mountPermissions)
|
fileMode := os.FileMode(mountPermissions)
|
||||||
// Create subdirectory under base-dir
|
// Create subdirectory under base-dir
|
||||||
internalVolumePath := cs.getInternalVolumePath(nfsVol)
|
internalVolumePath := cs.getInternalVolumePath(nfsVol)
|
||||||
if err = os.Mkdir(internalVolumePath, fileMode); err != nil && !os.IsExist(err) {
|
if err = os.Mkdir(internalVolumePath, fileMode); err != nil && !os.IsExist(err) {
|
||||||
@ -108,7 +133,16 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
|
|||||||
if err = os.Chmod(internalVolumePath, fileMode); err != nil {
|
if err = os.Chmod(internalVolumePath, fileMode); err != nil {
|
||||||
klog.Warningf("failed to chmod subdirectory: %v", err.Error())
|
klog.Warningf("failed to chmod subdirectory: %v", err.Error())
|
||||||
}
|
}
|
||||||
return &csi.CreateVolumeResponse{Volume: cs.nfsVolToCSI(nfsVol)}, nil
|
|
||||||
|
parameters[paramServer] = nfsVol.server
|
||||||
|
parameters[paramShare] = cs.getVolumeSharePath(nfsVol)
|
||||||
|
return &csi.CreateVolumeResponse{
|
||||||
|
Volume: &csi.Volume{
|
||||||
|
VolumeId: nfsVol.id,
|
||||||
|
CapacityBytes: 0, // by setting it to zero, Provisioner will use PVC requested size as PV size
|
||||||
|
VolumeContext: parameters,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteVolume delete a volume
|
// DeleteVolume delete a volume
|
||||||
@ -138,7 +172,7 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mount nfs base share so we can delete the subdirectory
|
// mount nfs base share so we can delete the subdirectory
|
||||||
if err = cs.internalMount(ctx, nfsVol, volCap); err != nil {
|
if err = cs.internalMount(ctx, nfsVol, nil, volCap); err != nil {
|
||||||
return nil, status.Errorf(codes.Internal, "failed to mount nfs server: %v", err.Error())
|
return nil, status.Errorf(codes.Internal, "failed to mount nfs server: %v", err.Error())
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -254,7 +288,7 @@ func (cs *ControllerServer) validateVolumeCapability(c *csi.VolumeCapability) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mount nfs server at base-dir
|
// Mount nfs server at base-dir
|
||||||
func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, volCap *csi.VolumeCapability) error {
|
func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, volumeContext map[string]string, volCap *csi.VolumeCapability) error {
|
||||||
sharePath := filepath.Join(string(filepath.Separator) + vol.baseDir)
|
sharePath := filepath.Join(string(filepath.Separator) + vol.baseDir)
|
||||||
targetPath := cs.getInternalMountPath(vol)
|
targetPath := cs.getInternalMountPath(vol)
|
||||||
|
|
||||||
@ -266,13 +300,16 @@ func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if volumeContext == nil {
|
||||||
|
volumeContext = make(map[string]string)
|
||||||
|
}
|
||||||
|
volumeContext[paramServer] = vol.server
|
||||||
|
volumeContext[paramShare] = sharePath
|
||||||
|
|
||||||
klog.V(2).Infof("internally mounting %v:%v at %v", vol.server, sharePath, targetPath)
|
klog.V(2).Infof("internally mounting %v:%v at %v", vol.server, sharePath, targetPath)
|
||||||
_, err := cs.Driver.ns.NodePublishVolume(ctx, &csi.NodePublishVolumeRequest{
|
_, err := cs.Driver.ns.NodePublishVolume(ctx, &csi.NodePublishVolumeRequest{
|
||||||
TargetPath: targetPath,
|
TargetPath: targetPath,
|
||||||
VolumeContext: map[string]string{
|
VolumeContext: volumeContext,
|
||||||
paramServer: vol.server,
|
|
||||||
paramShare: sharePath,
|
|
||||||
},
|
|
||||||
VolumeCapability: volCap,
|
VolumeCapability: volCap,
|
||||||
VolumeId: vol.id,
|
VolumeId: vol.id,
|
||||||
})
|
})
|
||||||
@ -303,8 +340,6 @@ func (cs *ControllerServer) newNFSVolume(name string, size int64, params map[str
|
|||||||
server = v
|
server = v
|
||||||
case paramShare:
|
case paramShare:
|
||||||
baseDir = v
|
baseDir = v
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid parameter %q", k)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,18 +382,6 @@ func (cs *ControllerServer) getVolumeSharePath(vol *nfsVolume) string {
|
|||||||
return filepath.Join(string(filepath.Separator), vol.baseDir, vol.subDir)
|
return filepath.Join(string(filepath.Separator), vol.baseDir, vol.subDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert into nfsVolume into a csi.Volume
|
|
||||||
func (cs *ControllerServer) nfsVolToCSI(vol *nfsVolume) *csi.Volume {
|
|
||||||
return &csi.Volume{
|
|
||||||
CapacityBytes: 0, // by setting it to zero, Provisioner will use PVC requested size as PV size
|
|
||||||
VolumeId: vol.id,
|
|
||||||
VolumeContext: map[string]string{
|
|
||||||
paramServer: vol.server,
|
|
||||||
paramShare: cs.getVolumeSharePath(vol),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a nfsVolume, return a CSI volume id
|
// Given a nfsVolume, return a CSI volume id
|
||||||
func (cs *ControllerServer) getVolumeIDFromNfsVol(vol *nfsVolume) string {
|
func (cs *ControllerServer) getVolumeIDFromNfsVol(vol *nfsVolume) string {
|
||||||
idElements := make([]string, totalIDElements)
|
idElements := make([]string, totalIDElements)
|
||||||
|
|||||||
@ -55,8 +55,9 @@ const (
|
|||||||
// The base directory must be a direct child of the root directory.
|
// The base directory must be a direct child of the root directory.
|
||||||
// The root directory is omitted from the string, for example:
|
// The root directory is omitted from the string, for example:
|
||||||
// "base" instead of "/base"
|
// "base" instead of "/base"
|
||||||
paramShare = "share"
|
paramShare = "share"
|
||||||
mountOptionsField = "mountoptions"
|
mountOptionsField = "mountoptions"
|
||||||
|
mountPermissionsField = "mountpermissions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewDriver(options *DriverOptions) *Driver {
|
func NewDriver(options *DriverOptions) *Driver {
|
||||||
|
|||||||
@ -19,6 +19,7 @@ package nfs
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||||
@ -56,6 +57,7 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
}
|
}
|
||||||
|
|
||||||
var server, baseDir string
|
var server, baseDir string
|
||||||
|
mountPermissions := ns.Driver.mountPermissions
|
||||||
for k, v := range req.GetVolumeContext() {
|
for k, v := range req.GetVolumeContext() {
|
||||||
switch strings.ToLower(k) {
|
switch strings.ToLower(k) {
|
||||||
case paramServer:
|
case paramServer:
|
||||||
@ -66,6 +68,13 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
if v != "" {
|
if v != "" {
|
||||||
mountOptions = append(mountOptions, v)
|
mountOptions = append(mountOptions, v)
|
||||||
}
|
}
|
||||||
|
case mountPermissionsField:
|
||||||
|
if v != "" {
|
||||||
|
var err error
|
||||||
|
if mountPermissions, err = strconv.ParseUint(v, 8, 32); err != nil {
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, fmt.Sprintf("invalid mountPermissions %s in storage class", v))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +89,7 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
notMnt, err := ns.mounter.IsLikelyNotMountPoint(targetPath)
|
notMnt, err := ns.mounter.IsLikelyNotMountPoint(targetPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(targetPath, os.FileMode(ns.Driver.mountPermissions)); err != nil {
|
if err := os.MkdirAll(targetPath, os.FileMode(mountPermissions)); err != nil {
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
notMnt = true
|
notMnt = true
|
||||||
@ -104,8 +113,8 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
return nil, status.Error(codes.Internal, err.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
klog.V(2).Infof("volumeID(%v): mount targetPath(%s) with permissions(0%o)", volumeID, targetPath, ns.Driver.mountPermissions)
|
klog.V(2).Infof("volumeID(%v): mount targetPath(%s) with permissions(0%o)", volumeID, targetPath, mountPermissions)
|
||||||
if err := os.Chmod(targetPath, os.FileMode(ns.Driver.mountPermissions)); err != nil {
|
if err := os.Chmod(targetPath, os.FileMode(mountPermissions)); err != nil {
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
return &csi.NodePublishVolumeResponse{}, nil
|
return &csi.NodePublishVolumeResponse{}, nil
|
||||||
|
|||||||
@ -50,6 +50,7 @@ var (
|
|||||||
"share": nfsShare,
|
"share": nfsShare,
|
||||||
"csi.storage.k8s.io/provisioner-secret-name": "mount-options",
|
"csi.storage.k8s.io/provisioner-secret-name": "mount-options",
|
||||||
"csi.storage.k8s.io/provisioner-secret-namespace": "default",
|
"csi.storage.k8s.io/provisioner-secret-namespace": "default",
|
||||||
|
"mountPermissions": "0755",
|
||||||
}
|
}
|
||||||
controllerServer *nfs.ControllerServer
|
controllerServer *nfs.ControllerServer
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user