package driver import ( "context" "os" "strings" "github.com/chrislusf/seaweedfs/weed/glog" "github.com/container-storage-interface/spec/lib/go/csi" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "k8s.io/utils/mount" ) type NodeServer struct { Driver *SeaweedFsDriver mounter mount.Interface } var _ = csi.NodeServer(&NodeServer{}) func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { volumeID := req.GetVolumeId() // mount the fs here targetPath := req.GetTargetPath() glog.V(0).Infof("NodePublishVolume volume %s to %s", volumeID, targetPath) // Check arguments if req.GetVolumeCapability() == nil { return nil, status.Error(codes.InvalidArgument, "Volume capability missing in request") } if !isValidVolumeCapabilities(ns.Driver.vcap, []*csi.VolumeCapability{req.GetVolumeCapability()}) { // return nil, status.Error(codes.InvalidArgument, "Volume capability not supported") } if volumeID == "" { return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } if targetPath == "" { return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } // check whether it can be mounted notMnt, err := checkMount(targetPath) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } if !notMnt { return &csi.NodePublishVolumeResponse{}, nil } mo := req.GetVolumeCapability().GetMount().GetMountFlags() if req.GetReadonly() { mo = append(mo, "ro") } volContext := req.GetVolumeContext() mounter, err := newMounter(volumeID, ns.Driver, volContext) if err != nil { return nil, err } if err := mounter.Mount(targetPath); err != nil { if os.IsPermission(err) { return nil, status.Error(codes.PermissionDenied, err.Error()) } if strings.Contains(err.Error(), "invalid argument") { return nil, status.Error(codes.InvalidArgument, err.Error()) } return nil, status.Error(codes.Internal, err.Error()) } glog.V(0).Infof("volume %s successfully mounted to %s", volumeID, targetPath) return &csi.NodePublishVolumeResponse{}, nil } func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpublishVolumeRequest) (*csi.NodeUnpublishVolumeResponse, error) { targetPath := req.GetTargetPath() if targetPath == "" { return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } if err := fuseUnmount(targetPath); err != nil { return nil, status.Error(codes.Internal, err.Error()) } err := os.Remove(targetPath) if err != nil && !os.IsNotExist(err) { return nil, status.Error(codes.Internal, err.Error()) } return &csi.NodeUnpublishVolumeResponse{}, nil } func (ns *NodeServer) NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest) (*csi.NodeGetInfoResponse, error) { glog.V(3).Infof("Using default NodeGetInfo: nodeID %s", ns.Driver.nodeID) return &csi.NodeGetInfoResponse{ NodeId: ns.Driver.nodeID, }, nil } func (ns *NodeServer) NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest) (*csi.NodeGetCapabilitiesResponse, error) { glog.V(3).Infof("Using default NodeGetCapabilities") return &csi.NodeGetCapabilitiesResponse{ Capabilities: []*csi.NodeServiceCapability{ { Type: &csi.NodeServiceCapability_Rpc{ Rpc: &csi.NodeServiceCapability_RPC{ // Type: csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME, Type: csi.NodeServiceCapability_RPC_UNKNOWN, }, }, }, }, }, nil } func (ns *NodeServer) NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest) (*csi.NodeGetVolumeStatsResponse, error) { return nil, status.Error(codes.Unimplemented, "") } func (ns *NodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { // Check arguments if req.GetVolumeId() == "" { return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } if req.GetStagingTargetPath() == "" { return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } return &csi.NodeUnstageVolumeResponse{}, nil } func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { // Check arguments if req.GetVolumeId() == "" { return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") } if req.GetStagingTargetPath() == "" { return nil, status.Error(codes.InvalidArgument, "Target path missing in request") } return &csi.NodeStageVolumeResponse{}, nil } func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) { return &csi.NodeExpandVolumeResponse{}, status.Error(codes.Unimplemented, "NodeExpandVolume is not implemented") } func checkMount(targetPath string) (bool, error) { notMnt, err := mount.New("").IsLikelyNotMountPoint(targetPath) if err != nil { if os.IsNotExist(err) { if err = os.MkdirAll(targetPath, 0750); err != nil { return false, err } notMnt = true } else { return false, err } } return notMnt, nil }