Skip to content

Commit

Permalink
Changes for fstype validation
Browse files Browse the repository at this point in the history
  • Loading branch information
vdkotkar committed Jan 24, 2023
1 parent a3287db commit eb2dcdd
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 60 deletions.
6 changes: 6 additions & 0 deletions pkg/csi/service/common/constants.go
Expand Up @@ -79,6 +79,12 @@ const (
// Ext4FsType represents the default filesystem type for block volume.
Ext4FsType = "ext4"

// Ext3FsType represents the ext3 filesystem type for block volume.
Ext3FsType = "ext3"

// XFSType represents the xfs filesystem type for block volume.
XFSType = "xfs"

// NfsV4FsType represents nfs4 mount type.
NfsV4FsType = "nfs4"

Expand Down
46 changes: 24 additions & 22 deletions pkg/csi/service/common/util.go
Expand Up @@ -163,25 +163,6 @@ func IsFileVolumeRequest(ctx context.Context, capabilities []*csi.VolumeCapabili
return false
}

// GetVolumeCapabilityFsType retrieves fstype from VolumeCapability.
// Defaults to nfs4 for file volume and ext4 for block volume when empty string
// is observed. This function also ignores default ext4 fstype supplied by
// external-provisioner when none is specified in the StorageClass
func GetVolumeCapabilityFsType(ctx context.Context, capability *csi.VolumeCapability) string {
log := logger.GetLogger(ctx)
fsType := strings.ToLower(capability.GetMount().GetFsType())
log.Debugf("FsType received from Volume Capability: %q", fsType)
isFileVolume := IsFileVolumeRequest(ctx, []*csi.VolumeCapability{capability})
if isFileVolume && (fsType == "" || fsType == "ext4") {
log.Infof("empty string or ext4 fstype observed for file volume. Defaulting to: %s", NfsV4FsType)
fsType = NfsV4FsType
} else if !isFileVolume && fsType == "" {
log.Infof("empty string fstype observed for block volume. Defaulting to: %s", Ext4FsType)
fsType = Ext4FsType
}
return fsType
}

// IsVolumeReadOnly checks the access mode in Volume Capability and decides
// if volume is readonly or not.
func IsVolumeReadOnly(capability *csi.VolumeCapability) bool {
Expand Down Expand Up @@ -211,10 +192,31 @@ func validateVolumeCapabilities(volCaps []*csi.VolumeCapability,
return fmt.Errorf("%s access mode is not supported for %q volumes",
csi.VolumeCapability_AccessMode_Mode_name[int32(volCap.AccessMode.GetMode())], volumeType)
}

if volCap.AccessMode.Mode == csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER {
if volCap.GetMount() != nil && (volCap.GetMount().FsType == NfsV4FsType ||
volCap.GetMount().FsType == NfsFsType) {
return fmt.Errorf("NFS fstype not supported for ReadWriteOnce volume creation")
// For ReadWriteOnce access mode we only support following filesystems:
// ext3, ext4, xfs for Linux and ntfs for Windows.
if volCap.GetMount() != nil && !(volCap.GetMount().FsType == Ext4FsType ||
volCap.GetMount().FsType == Ext3FsType || volCap.GetMount().FsType == XFSType ||
volCap.GetMount().FsType == NTFSFsType || volCap.GetMount().FsType == "") {
return fmt.Errorf("fstype %s not supported for ReadWriteOnce volume creation",
volCap.GetMount().FsType)
}
} else if volCap.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY ||
volCap.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_SINGLE_WRITER ||
volCap.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER {
// For ReadWriteMany or ReadOnlyMany access modes we only support nfs or nfs4 filesystem.
// external-provisioner sets default fstype as ext4 when none is specified in StorageClass,
// but we overwrite it to nfs4 while mounting the volume.
if volCap.GetMount() != nil && !(volCap.GetMount().FsType == NfsV4FsType ||
volCap.GetMount().FsType == NfsFsType || volCap.GetMount().FsType == Ext4FsType ||
volCap.GetMount().FsType == "") {
return fmt.Errorf("fstype %s not supported for ReadWriteMany or ReadOnlyMany volume creation",
volCap.GetMount().FsType)
} else if volCap.GetBlock() != nil {
// Raw Block volumes are not supported with ReadWriteMany or ReadOnlyMany access modes,
return fmt.Errorf("block volume mode is not supported for ReadWriteMany or ReadOnlyMany " +
"volume creation")
}
}
}
Expand Down
63 changes: 53 additions & 10 deletions pkg/csi/service/common/util_test.go
Expand Up @@ -138,6 +138,36 @@ func TestValidVolumeCapabilitiesForBlock(t *testing.T) {
if err := IsValidVolumeCapabilities(ctx, volCap); err != nil {
t.Errorf("Block VolCap = %+v failed validation!", volCap)
}
// fstype=xfs and mode=SINGLE_NODE_WRITER
volCap = []*csi.VolumeCapability{
{
AccessType: &csi.VolumeCapability_Mount{
Mount: &csi.VolumeCapability_MountVolume{
FsType: "xfs",
},
},
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
},
},
}
if err := IsValidVolumeCapabilities(ctx, volCap); err != nil {
t.Errorf("Block VolCap = %+v failed validation!", volCap)
}
// volumeMode=block and accessMode=SINGLE_NODE_WRITER
volCap = []*csi.VolumeCapability{
{
AccessType: &csi.VolumeCapability_Block{
Block: &csi.VolumeCapability_BlockVolume{},
},
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
},
},
}
if err := IsValidVolumeCapabilities(ctx, volCap); err != nil {
t.Errorf("Block VolCap = %+v failed validation!", volCap)
}
}

func TestInvalidVolumeCapabilitiesForBlock(t *testing.T) {
Expand Down Expand Up @@ -194,7 +224,22 @@ func TestValidVolumeCapabilitiesForFile(t *testing.T) {
t.Errorf("File VolCap = %+v failed validation!", volCap)
}

// fstype=nfsv4 and mode=MULTI_NODE_READER_ONLY
// fstype=empty and mode=MULTI_NODE_MULTI_WRITER
volCap = []*csi.VolumeCapability{
{
AccessType: &csi.VolumeCapability_Mount{
Mount: &csi.VolumeCapability_MountVolume{},
},
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
},
},
}
if err := IsValidVolumeCapabilities(ctx, volCap); err != nil {
t.Errorf("File VolCap = %+v failed validation!", volCap)
}

// fstype=nfs and mode=MULTI_NODE_READER_ONLY
volCap = []*csi.VolumeCapability{
{
AccessType: &csi.VolumeCapability_Mount{
Expand Down Expand Up @@ -230,33 +275,31 @@ func TestValidVolumeCapabilitiesForFile(t *testing.T) {
}

func TestInvalidVolumeCapabilitiesForFile(t *testing.T) {
// Invalid case: fstype=nfs4 and mode=SINGLE_NODE_WRITER
// Invalid case: fstype=xfs and mode=MULTI_NODE_MULTI_WRITER
volCap := []*csi.VolumeCapability{
{
AccessType: &csi.VolumeCapability_Mount{
Mount: &csi.VolumeCapability_MountVolume{
FsType: "nfs4",
FsType: "xfs",
},
},
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
},
},
}
if err := IsValidVolumeCapabilities(ctx, volCap); err == nil {
t.Errorf("Invalid file VolCap = %+v passed validation!", volCap)
}

// Invalid case: fstype=nfs and mode=SINGLE_NODE_WRITER
// Invalid case: volumeMode=block and accessMode=MULTI_NODE_MULTI_WRITER
volCap = []*csi.VolumeCapability{
{
AccessType: &csi.VolumeCapability_Mount{
Mount: &csi.VolumeCapability_MountVolume{
FsType: "nfs",
},
AccessType: &csi.VolumeCapability_Block{
Block: &csi.VolumeCapability_BlockVolume{},
},
AccessMode: &csi.VolumeCapability_AccessMode{
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER,
},
},
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/csi/service/node.go
Expand Up @@ -87,7 +87,7 @@ func (driver *vsphereCSIDriver) NodeStageVolume(
// Mount Volume.
// Extract mount volume details.
log.Debug("NodeStageVolume: Volume detected as a mount volume")
params.FsType, params.MntFlags, err = driver.osUtils.EnsureMountVol(ctx, log, volCap)
params.FsType, params.MntFlags, err = driver.osUtils.EnsureMountVol(ctx, volCap)
if err != nil {
return nil, err
}
Expand Down
41 changes: 29 additions & 12 deletions pkg/csi/service/osutils/linux_os_utils.go
Expand Up @@ -390,7 +390,7 @@ func (osUtils *OsUtils) PublishMountVol(
log.Infof("PublishMountVolume called with args: %+v", params)

// Extract fs details.
_, mntFlags, err := osUtils.EnsureMountVol(ctx, log, req.GetVolumeCapability())
_, mntFlags, err := osUtils.EnsureMountVol(ctx, req.GetVolumeCapability())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -533,7 +533,7 @@ func (osUtils *OsUtils) PublishFileVol(
log.Infof("PublishFileVolume called with args: %+v", params)

// Extract mount details.
fsType, mntFlags, err := osUtils.EnsureMountVol(ctx, log, req.GetVolumeCapability())
fsType, mntFlags, err := osUtils.EnsureMountVol(ctx, req.GetVolumeCapability())
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -954,19 +954,36 @@ func (osUtils *OsUtils) IsTargetInMounts(ctx context.Context, path string) (bool
// Defaults to nfs4 for file volume and ext4 for block volume when empty string
// is observed. This function also ignores default ext4 fstype supplied by
// external-provisioner when none is specified in the StorageClass
func (osUtils *OsUtils) GetVolumeCapabilityFsType(ctx context.Context, capability *csi.VolumeCapability) string {
func (osUtils *OsUtils) GetVolumeCapabilityFsType(ctx context.Context,
capability *csi.VolumeCapability) (string, error) {
log := logger.GetLogger(ctx)
fsType := strings.ToLower(capability.GetMount().GetFsType())
log.Debugf("FsType received from Volume Capability: %q", fsType)
log.Infof("FsType received from Volume Capability: %q", fsType)
isFileVolume := common.IsFileVolumeRequest(ctx, []*csi.VolumeCapability{capability})
if isFileVolume && (fsType == "" || fsType == "ext4") {
log.Infof("empty string or ext4 fstype observed for file volume. Defaulting to: %s", common.NfsV4FsType)
fsType = common.NfsV4FsType
} else if !isFileVolume && fsType == "" {
log.Infof("empty string fstype observed for block volume. Defaulting to: %s", common.Ext4FsType)
fsType = common.Ext4FsType
}
return fsType
if isFileVolume {
// For File volumes we only support nfs or nfs4 filesystem. External-provisioner sets default fstype
// as ext4 when none is specified in StorageClass, hence overwrite it to nfs4 while mounting the volume.
if fsType == "" || fsType == "ext4" {
log.Infof("empty string or ext4 fstype observed for file volume. Defaulting to: %s",
common.NfsV4FsType)
fsType = common.NfsV4FsType
} else if !(fsType == common.NfsFsType || fsType == common.NfsV4FsType) {
return "", logger.LogNewErrorCodef(log, codes.FailedPrecondition,
"unsupported fsType %q observed for file volume", fsType)
}
} else {
// For Block volumes we only support following filesystems:
// ext3, ext4 and xfs for Linux.
if fsType == "" {
log.Infof("empty string fstype observed for block volume. Defaulting to: %s",
common.Ext4FsType)
fsType = common.Ext4FsType
} else if !(fsType == common.Ext4FsType || fsType == common.Ext3FsType || fsType == common.XFSType) {
return "", logger.LogNewErrorCodef(log, codes.FailedPrecondition,
"unsupported fsType %q observed for block volume", fsType)
}
}
return fsType, nil
}

// ResizeVolume resizes the volume
Expand Down
14 changes: 9 additions & 5 deletions pkg/csi/service/osutils/os_utils.go
Expand Up @@ -82,18 +82,22 @@ func (osUtils *OsUtils) GetDiskID(pubCtx map[string]string, log *zap.SugaredLogg

// EnsureMountVol ensures that VolumeCapability has mount option
// and returns fstype, mount flags
func (osUtils *OsUtils) EnsureMountVol(ctx context.Context, log *zap.SugaredLogger,
volCap *csi.VolumeCapability) (string, []string, error) {
func (osUtils *OsUtils) EnsureMountVol(ctx context.Context, volCap *csi.VolumeCapability) (string, []string, error) {
log := logger.GetLogger(ctx)
mountVol := volCap.GetMount()
if mountVol == nil {
return "", nil, logger.LogNewErrorCode(log, codes.InvalidArgument, "access type missing")
}
fs := osUtils.GetVolumeCapabilityFsType(ctx, volCap)
mntFlags := mountVol.GetMountFlags()
fs, err := osUtils.GetVolumeCapabilityFsType(ctx, volCap)
if err != nil {
log.Errorf("GetVolumeCapabilityFsType failed with err: %v", err)
return "", nil, err
}

mntFlags := mountVol.GetMountFlags()
// By default, xfs does not allow mounting of two volumes with the same filesystem uuid.
// Force ignore this uuid to be able to mount volume + its clone / restored snapshot on the same node.
if fs == "xfs" {
if fs == common.XFSType {
mntFlags = append(mntFlags, "nouuid")
}

Expand Down
31 changes: 21 additions & 10 deletions pkg/csi/service/osutils/windows_os_utils.go
Expand Up @@ -364,19 +364,30 @@ func (osUtils *OsUtils) IsTargetInMounts(ctx context.Context, path string) (bool
// Defaults to nfs4 for file volume and ntfs for block volume when empty string
// is observed. This function also ignores default ext4 fstype supplied by
// external-provisioner when none is specified in the StorageClass
func (osUtils *OsUtils) GetVolumeCapabilityFsType(ctx context.Context, capability *csi.VolumeCapability) string {
func (osUtils *OsUtils) GetVolumeCapabilityFsType(ctx context.Context,
capability *csi.VolumeCapability) (string, error) {
log := logger.GetLogger(ctx)
fsType := strings.ToLower(capability.GetMount().GetFsType())
log.Debugf("FsType received from Volume Capability: %q", fsType)
log.Infof("FsType received from Volume Capability: %q", fsType)
isFileVolume := common.IsFileVolumeRequest(ctx, []*csi.VolumeCapability{capability})
if isFileVolume && (fsType == "" || fsType == "ext4") {
log.Infof("empty string or ext4 fstype observed for file volume. Defaulting to: %s", common.NfsV4FsType)
fsType = common.NfsV4FsType
} else if !isFileVolume && fsType == "" {
log.Infof("empty string fstype observed for block volume. Defaulting to: %s", common.NTFSFsType)
fsType = common.NTFSFsType
}
return fsType
if isFileVolume {
// Volumes with RWM or ROM access modes are not supported on Windows
return "", logger.LogNewErrorCode(log, codes.FailedPrecondition,
"vSAN file service volume can not be mounted on windows node")
}

// On Windows we only support ntfs filesystem. External-provisioner sets default fstype as ext4
// when none is specified in StorageClass, hence overwrite it to ntfs while mounting the volume.
if fsType == common.NTFSFsType {
return fsType, nil
} else if fsType == "" || fsType == "ext4" {
log.Infof("replacing fsType: %q received from volume "+
"capability with %q", fsType, common.NTFSFsType)
return common.NTFSFsType, nil
} else {
return "", logger.LogNewErrorCodef(log, codes.FailedPrecondition,
"unsupported fsType %q observed", fsType)
}
}

// ResizeVolume resizes the volume
Expand Down

0 comments on commit eb2dcdd

Please sign in to comment.