Merge pull request #122 from andyzhangx/createvolume-mountoptions

fix: support mountOptions in CreateVolume
This commit is contained in:
Andy Zhang 2020-12-27 21:24:37 +08:00 committed by GitHub
commit c1d04d8eff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 64 deletions

View File

@ -1,28 +0,0 @@
// +build linux darwin
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package mounter
import (
utilexec "k8s.io/utils/exec"
"k8s.io/utils/mount"
)
func NewSafeMounter() (*mount.SafeFormatAndMount, error) {
return &mount.SafeFormatAndMount{
Interface: mount.New(""),
Exec: utilexec.New(),
}, nil
}

View File

@ -29,6 +29,7 @@ import (
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
) )
// ControllerServer controller server setting
type ControllerServer struct { type ControllerServer struct {
Driver *Driver Driver *Driver
// Working directory for the provisioner to temporarily mount nfs shares at // Working directory for the provisioner to temporarily mount nfs shares at
@ -65,13 +66,12 @@ const (
totalIDElements // Always last totalIDElements // Always last
) )
// CreateVolume create a volume
func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) {
// Validate arguments
name := req.GetName() name := req.GetName()
if len(name) == 0 { if len(name) == 0 {
return nil, status.Error(codes.InvalidArgument, "CreateVolume name must be provided") return nil, status.Error(codes.InvalidArgument, "CreateVolume name must be provided")
} }
if err := cs.validateVolumeCapabilities(req.GetVolumeCapabilities()); err != nil { if err := cs.validateVolumeCapabilities(req.GetVolumeCapabilities()); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error()) return nil, status.Error(codes.InvalidArgument, err.Error())
} }
@ -82,8 +82,12 @@ 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())
} }
var volCap *csi.VolumeCapability
if len(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); err != nil { if err = cs.internalMount(ctx, nfsVol, 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() {
@ -103,6 +107,7 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
return &csi.CreateVolumeResponse{Volume: cs.nfsVolToCSI(nfsVol, reqCapacity)}, nil return &csi.CreateVolumeResponse{Volume: cs.nfsVolToCSI(nfsVol, reqCapacity)}, nil
} }
// DeleteVolume delete a volume
func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) {
volumeID := req.GetVolumeId() volumeID := req.GetVolumeId()
if volumeID == "" { if volumeID == "" {
@ -111,12 +116,12 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
nfsVol, err := cs.getNfsVolFromID(volumeID) nfsVol, err := cs.getNfsVolFromID(volumeID)
if err != nil { if err != nil {
// An invalid ID should be treated as doesn't exist // An invalid ID should be treated as doesn't exist
glog.V(5).Infof("failed to get nfs volume for volume id %v deletion: %v", volumeID, err) glog.Warningf("failed to get nfs volume for volume id %v deletion: %v", volumeID, err)
return &csi.DeleteVolumeResponse{}, nil return &csi.DeleteVolumeResponse{}, nil
} }
// 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); err != nil { if err = cs.internalMount(ctx, nfsVol, nil); 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() {
@ -128,7 +133,7 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
// Delete subdirectory under base-dir // Delete subdirectory under base-dir
internalVolumePath := cs.getInternalVolumePath(nfsVol) internalVolumePath := cs.getInternalVolumePath(nfsVol)
glog.V(4).Infof("Removing subdirectory at %v", internalVolumePath) glog.V(2).Infof("Removing subdirectory at %v", internalVolumePath)
if err = os.RemoveAll(internalVolumePath); err != nil { if err = os.RemoveAll(internalVolumePath); err != nil {
return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error()) return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error())
} }
@ -171,8 +176,6 @@ func (cs *ControllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacit
// ControllerGetCapabilities implements the default GRPC callout. // ControllerGetCapabilities implements the default GRPC callout.
// Default supports all capabilities // Default supports all capabilities
func (cs *ControllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { func (cs *ControllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) {
glog.V(5).Infof("Using default ControllerGetCapabilities")
return &csi.ControllerGetCapabilitiesResponse{ return &csi.ControllerGetCapabilitiesResponse{
Capabilities: cs.Driver.cscap, Capabilities: cs.Driver.cscap,
}, nil }, nil
@ -230,13 +233,16 @@ 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) error { func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume, 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)
stdVolCap := csi.VolumeCapability{
AccessType: &csi.VolumeCapability_Mount{ if volCap == nil {
Mount: &csi.VolumeCapability_MountVolume{}, volCap = &csi.VolumeCapability{
}, AccessType: &csi.VolumeCapability_Mount{
Mount: &csi.VolumeCapability_MountVolume{},
},
}
} }
glog.V(4).Infof("internally mounting %v:%v at %v", vol.server, sharePath, targetPath) glog.V(4).Infof("internally mounting %v:%v at %v", vol.server, sharePath, targetPath)
@ -246,7 +252,7 @@ func (cs *ControllerServer) internalMount(ctx context.Context, vol *nfsVolume) e
paramServer: vol.server, paramServer: vol.server,
paramShare: sharePath, paramShare: sharePath,
}, },
VolumeCapability: &stdVolCap, VolumeCapability: volCap,
VolumeId: vol.id, VolumeId: vol.id,
}) })
return err return err

View File

@ -18,11 +18,8 @@ package nfs
import ( import (
"fmt" "fmt"
"runtime"
"strings" "strings"
"github.com/kubernetes-csi/csi-driver-nfs/pkg/mounter"
"k8s.io/utils/mount" "k8s.io/utils/mount"
) )
@ -64,9 +61,6 @@ func (f *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
} }
func NewFakeMounter() (*mount.SafeFormatAndMount, error) { func NewFakeMounter() (*mount.SafeFormatAndMount, error) {
if runtime.GOOS == "windows" {
return mounter.NewSafeMounter()
}
return &mount.SafeFormatAndMount{ return &mount.SafeFormatAndMount{
Interface: &fakeMounter{}, Interface: &fakeMounter{},
}, nil }, nil

View File

@ -21,28 +21,29 @@ import (
"os" "os"
"strings" "strings"
"github.com/golang/glog"
"github.com/container-storage-interface/spec/lib/go/csi" "github.com/container-storage-interface/spec/lib/go/csi"
"github.com/golang/glog"
"golang.org/x/net/context" "golang.org/x/net/context"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"k8s.io/utils/mount" "k8s.io/utils/mount"
) )
// NodeServer driver
type NodeServer struct { type NodeServer struct {
Driver *Driver Driver *Driver
mounter mount.Interface mounter mount.Interface
} }
// NodePublishVolume mount the volume
func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
if req.GetVolumeCapability() == nil { if req.GetVolumeCapability() == nil {
return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request") return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request")
} }
if len(req.GetVolumeId()) == 0 { volumeID := req.GetVolumeId()
if len(volumeID) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
} }
targetPath := req.GetTargetPath() targetPath := req.GetTargetPath()
if len(targetPath) == 0 { if len(targetPath) == 0 {
return nil, status.Error(codes.InvalidArgument, "Target path not provided") return nil, status.Error(codes.InvalidArgument, "Target path not provided")
@ -59,21 +60,21 @@ 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())
} }
} }
if !notMnt { if !notMnt {
return &csi.NodePublishVolumeResponse{}, nil return &csi.NodePublishVolumeResponse{}, nil
} }
mo := req.GetVolumeCapability().GetMount().GetMountFlags() mountOptions := req.GetVolumeCapability().GetMount().GetMountFlags()
if req.GetReadonly() { if req.GetReadonly() {
mo = append(mo, "ro") mountOptions = append(mountOptions, "ro")
} }
s := req.GetVolumeContext()[paramServer] s := req.GetVolumeContext()[paramServer]
ep := req.GetVolumeContext()[paramShare] ep := req.GetVolumeContext()[paramShare]
source := fmt.Sprintf("%s:%s", s, ep) source := fmt.Sprintf("%s:%s", s, ep)
err = ns.mounter.Mount(source, targetPath, "nfs", mo) glog.V(2).Infof("NodePublishVolume: volumeID(%v) source(%s) targetPath(%s) mountflags(%v)", volumeID, source, targetPath, mountOptions)
err = ns.mounter.Mount(source, targetPath, "nfs", mountOptions)
if err != nil { if err != nil {
if os.IsPermission(err) { if os.IsPermission(err) {
return nil, status.Error(codes.PermissionDenied, err.Error()) return nil, status.Error(codes.PermissionDenied, err.Error())
@ -93,14 +94,16 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
return &csi.NodePublishVolumeResponse{}, nil return &csi.NodePublishVolumeResponse{}, nil
} }
// NodeUnpublishVolume unmount the volume
func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) {
if len(req.GetVolumeId()) == 0 { volumeID := req.GetVolumeId()
if len(volumeID) == 0 {
return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request")
} }
if len(req.GetTargetPath()) == 0 { targetPath := req.GetTargetPath()
if len(targetPath) == 0 {
return nil, status.Error(codes.InvalidArgument, "Target path missing in request") return nil, status.Error(codes.InvalidArgument, "Target path missing in request")
} }
targetPath := req.GetTargetPath()
notMnt, err := ns.mounter.IsLikelyNotMountPoint(targetPath) notMnt, err := ns.mounter.IsLikelyNotMountPoint(targetPath)
if err != nil { if err != nil {
@ -113,7 +116,8 @@ func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
return nil, status.Error(codes.NotFound, "Volume not mounted") return nil, status.Error(codes.NotFound, "Volume not mounted")
} }
err = mount.CleanupMountPoint(req.GetTargetPath(), ns.mounter, false) glog.V(2).Infof("NodeUnpublishVolume: CleanupMountPoint %s on volumeID(%s)", targetPath, volumeID)
err = mount.CleanupMountPoint(targetPath, ns.mounter, false)
if err != nil { if err != nil {
return nil, status.Error(codes.Internal, err.Error()) return nil, status.Error(codes.Internal, err.Error())
} }
@ -121,17 +125,15 @@ func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
return &csi.NodeUnpublishVolumeResponse{}, nil return &csi.NodeUnpublishVolumeResponse{}, nil
} }
// NodeGetInfo return info of the node on which this plugin is running
func (ns *NodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { func (ns *NodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) {
glog.V(5).Infof("Using default NodeGetInfo")
return &csi.NodeGetInfoResponse{ return &csi.NodeGetInfoResponse{
NodeId: ns.Driver.nodeID, NodeId: ns.Driver.nodeID,
}, nil }, nil
} }
// NodeGetCapabilities return the capabilities of the Node plugin
func (ns *NodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { func (ns *NodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) {
glog.V(5).Infof("Using default NodeGetCapabilities")
return &csi.NodeGetCapabilitiesResponse{ return &csi.NodeGetCapabilitiesResponse{
Capabilities: []*csi.NodeServiceCapability{ Capabilities: []*csi.NodeServiceCapability{
{ {
@ -145,18 +147,22 @@ func (ns *NodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetC
}, nil }, nil
} }
// NodeGetVolumeStats get volume stats
func (ns *NodeServer) NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { func (ns *NodeServer) NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) {
return nil, status.Error(codes.Unimplemented, "") return nil, status.Error(codes.Unimplemented, "")
} }
// NodeUnstageVolume unstage volume
func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) {
return &csi.NodeUnstageVolumeResponse{}, nil return &csi.NodeUnstageVolumeResponse{}, nil
} }
// NodeStageVolume stage volume
func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) {
return &csi.NodeStageVolumeResponse{}, nil return &csi.NodeStageVolumeResponse{}, nil
} }
// NodeExpandVolume node expand volume
func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) {
return nil, status.Error(codes.Unimplemented, "") return nil, status.Error(codes.Unimplemented, "")
} }