Skip to content

Commit

Permalink
support to enable windows process
Browse files Browse the repository at this point in the history
Signed-off-by: Ji An Liu <jiliu8@microsoft.com>
  • Loading branch information
ZeroMagic committed Feb 16, 2023
1 parent 5d5ef9d commit bcc6818
Show file tree
Hide file tree
Showing 11 changed files with 782 additions and 7 deletions.
5 changes: 4 additions & 1 deletion pkg/azurefile/azurefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ type DriverOptions struct {
FSGroupChangePolicy string
KubeAPIQPS float64
KubeAPIBurst int
EnableWindowsHostProcess bool
}

// Driver implements all interfaces of CSI drivers
Expand All @@ -216,6 +217,7 @@ type Driver struct {
mountPermissions uint64
kubeAPIQPS float64
kubeAPIBurst int
enableWindowsHostProcess bool
fileClient *azureFileClient
mounter *mount.SafeFormatAndMount
// lock per volume attach (only for vhd disk feature)
Expand Down Expand Up @@ -261,6 +263,7 @@ func NewDriver(options *DriverOptions) *Driver {
driver.fsGroupChangePolicy = options.FSGroupChangePolicy
driver.kubeAPIQPS = options.KubeAPIQPS
driver.kubeAPIBurst = options.KubeAPIBurst
driver.enableWindowsHostProcess = options.EnableWindowsHostProcess
driver.volLockMap = newLockMap()
driver.subnetLockMap = newLockMap()
driver.volumeLocks = newVolumeLocks()
Expand Down Expand Up @@ -310,7 +313,7 @@ func (d *Driver) Run(endpoint, kubeconfig string, testBool bool) {
// todo: set backoff from cloud provider config
d.fileClient = newAzureFileClient(&d.cloud.Environment, &retry.Backoff{Steps: 1})

d.mounter, err = mounter.NewSafeMounter()
d.mounter, err = mounter.NewSafeMounter(d.enableWindowsHostProcess)
if err != nil {
klog.Fatalf("Failed to get safe mounter. Error: %v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/azurefile/fake_mounter.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (f *fakeMounter) IsMountPoint(file string) (bool, error) {
// NewFakeMounter fake mounter
func NewFakeMounter() (*mount.SafeFormatAndMount, error) {
if runtime.GOOS == "windows" {
return mounter.NewSafeMounter()
return mounter.NewSafeMounter(false)
}
return &mount.SafeFormatAndMount{
Interface: &fakeMounter{},
Expand Down
2 changes: 2 additions & 0 deletions pkg/azurefileplugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ var (
kubeAPIQPS = flag.Float64("kube-api-qps", 25.0, "QPS to use while communicating with the kubernetes apiserver.")
kubeAPIBurst = flag.Int("kube-api-burst", 50, "Burst to use while communicating with the kubernetes apiserver.")
appendMountErrorHelpLink = flag.Bool("append-mount-error-help-link", true, "Whether to include a link for help with mount errors when a mount error occurs.")
enableWindowsHostProcess = flag.Bool("enable-windows-host-process", false, "enable windows host process")
)

func main() {
Expand Down Expand Up @@ -95,6 +96,7 @@ func handle() {
AppendMountErrorHelpLink: *appendMountErrorHelpLink,
KubeAPIQPS: *kubeAPIQPS,
KubeAPIBurst: *kubeAPIBurst,
EnableWindowsHostProcess: *enableWindowsHostProcess,
}
driver := azurefile.NewDriver(&driverOptions)
if driver == nil {
Expand Down
268 changes: 268 additions & 0 deletions pkg/mounter/safe_mounter_host_process_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
//go:build windows
// +build windows

/*
Copyright 2022 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 (
"context"
"fmt"
"os"
filepath "path/filepath"
"strings"

"k8s.io/klog/v2"
mount "k8s.io/mount-utils"

"sigs.k8s.io/azurefile-csi-driver/pkg/os/filesystem"
"sigs.k8s.io/azurefile-csi-driver/pkg/os/smb"
)

var _ CSIProxyMounter = &winMounter{}

type winMounter struct{}

func NewWinMounter() *winMounter {
return &winMounter{}
}

func (mounter *winMounter) SMBMount(source, target, fsType string, mountOptions, sensitiveMountOptions []string) error {
klog.V(2).Infof("SMBMount: remote path: %s local path: %s", source, target)

if len(mountOptions) == 0 || len(sensitiveMountOptions) == 0 {
return fmt.Errorf("empty mountOptions(len: %d) or sensitiveMountOptions(len: %d) is not allowed", len(mountOptions), len(sensitiveMountOptions))
}

parentDir := filepath.Dir(target)
parentExists, err := mounter.ExistsPath(parentDir)
if err != nil {
return fmt.Errorf("parent dir: %s exist check failed with err: %v", parentDir, err)
}

if !parentExists {
klog.V(2).Infof("Parent directory %s does not exists. Creating the directory", parentDir)
if err := mounter.MakeDir(parentDir); err != nil {
return fmt.Errorf("create of parent dir: %s dailed with error: %v", parentDir, err)
}
}

source = strings.Replace(source, "/", "\\", -1)
normalizedTarget := normalizeWindowsPath(target)

klog.V(2).Infof("begin to mount %s on %s", source, normalizedTarget)

remotePath := source
localPath := normalizedTarget

if remotePath == "" {
klog.Errorf("remote path is empty")
return fmt.Errorf("remote path is empty")
}

isMapped, err := smb.IsSmbMapped(remotePath)
if err != nil {
isMapped = false
}

if isMapped {
valid, err := filesystem.PathValid(context.Background(), remotePath)
if err != nil {
klog.Warningf("PathValid(%s) failed with %v, ignore error", remotePath, err)
}

if !valid {
klog.V(4).Infof("RemotePath %s is not valid, removing now", remotePath)
err := smb.RemoveSmbGlobalMapping(remotePath)
if err != nil {
klog.Errorf("RemoveSmbGlobalMapping(%s) failed with %v", remotePath, err)
return err
}
isMapped = false
}
}

if !isMapped {
klog.V(4).Infof("Remote %s not mapped. Mapping now!", remotePath)
username := mountOptions[0]
password := sensitiveMountOptions[0]
err := smb.NewSmbGlobalMapping(remotePath, username, password)
if err != nil {
klog.Errorf("failed NewSmbGlobalMapping %v", err)
return err
}
}

if len(localPath) != 0 {
err = filesystem.ValidatePathWindows(localPath)
if err != nil {
klog.Errorf("failed validate plugin path %v", err)
return err
}
err = smb.NewSmbLink(remotePath, localPath)
if err != nil {
klog.Errorf("failed NewSmbLink %v", err)
return fmt.Errorf("creating link %s to %s failed with error: %v", localPath, remotePath, err)
}
}

klog.V(2).Infof("mount %s on %s successfully", source, normalizedTarget)

return nil
}

func (mounter *winMounter) SMBUnmount(target string) error {
klog.V(4).Infof("SMBUnmount: local path: %s", target)
return mounter.Rmdir(target)
}

// Mount just creates a soft link at target pointing to source.
func (mounter *winMounter) Mount(source string, target string, fstype string, options []string) error {
klog.V(4).Infof("Mount: old name: %s. new name: %s", source, target)
// Mount is called after the format is done.
// TODO: Confirm that fstype is empty.
linkRequest := &filesystem.LinkPathRequest{
SourcePath: normalizeWindowsPath(source),
TargetPath: normalizeWindowsPath(target),
}
if err := filesystem.LinkPath(context.Background(), linkRequest); err != nil {
return err
}
return nil
}

// Rmdir - delete the given directory
func (mounter *winMounter) Rmdir(path string) error {
klog.V(4).Infof("Remove directory: %s", path)
rmdirRequest := &filesystem.RmdirRequest{
Path: normalizeWindowsPath(path),
Force: true,
}
if err := filesystem.Rmdir(context.Background(), rmdirRequest); err != nil {
return err
}
return nil
}

// Unmount - Removes the directory - equivalent to unmount on Linux.
func (mounter *winMounter) Unmount(target string) error {
klog.V(4).Infof("Unmount: %s", target)
return mounter.Rmdir(target)
}

func (mounter *winMounter) List() ([]mount.MountPoint, error) {
return []mount.MountPoint{}, fmt.Errorf("List not implemented for CSIProxyMounter")
}

func (mounter *winMounter) IsMountPoint(file string) (bool, error) {
isNotMnt, err := mounter.IsLikelyNotMountPoint(file)
if err != nil {
return false, err
}
return !isNotMnt, nil
}

func (mounter *winMounter) IsMountPointMatch(mp mount.MountPoint, dir string) bool {
return mp.Path == dir
}

// IsLikelyMountPoint - If the directory does not exists, the function will return os.ErrNotExist error.
// If the path exists, will check if its a link, if its a link then existence of target path is checked.
func (mounter *winMounter) IsLikelyNotMountPoint(path string) (bool, error) {
klog.V(4).Infof("IsLikelyNotMountPoint: %s", path)
isExists, err := mounter.ExistsPath(path)
if err != nil {
return false, err
}
if !isExists {
return true, os.ErrNotExist
}

response, err := filesystem.IsMountPoint(context.Background(),
&filesystem.IsMountPointRequest{
Path: normalizeWindowsPath(path),
})
if err != nil {
return false, err
}
return !response, nil
}

// MakeDir - Creates a directory.
// Currently the make dir is only used from the staging code path, hence we call it
// with Plugin context..
func (mounter *winMounter) MakeDir(path string) error {
klog.V(4).Infof("Make directory: %s", path)
mkdirReq := &filesystem.MkdirRequest{
Path: normalizeWindowsPath(path),
}
if err := filesystem.Mkdir(context.Background(), mkdirReq); err != nil {
return err
}

return nil
}

// ExistsPath - Checks if a path exists. Unlike util ExistsPath, this call does not perform follow link.
func (mounter *winMounter) ExistsPath(path string) (bool, error) {
klog.V(4).Infof("Exists path: %s", path)
return filesystem.PathExists(context.Background(),
&filesystem.PathExistsRequest{
Path: normalizeWindowsPath(path),
})
}

func (mounter *winMounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
return fmt.Errorf("MountSensitive not implemented for winMounter")
}

func (mounter *winMounter) MountSensitiveWithoutSystemd(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
return fmt.Errorf("MountSensitiveWithoutSystemd not implemented for winMounter")
}

func (mounter *winMounter) MountSensitiveWithoutSystemdWithMountFlags(source string, target string, fstype string, options []string, sensitiveOptions []string, mountFlags []string) error {
return mounter.MountSensitive(source, target, fstype, options, sensitiveOptions /* sensitiveOptions */)
}

func (mounter *winMounter) GetMountRefs(pathname string) ([]string, error) {
return []string{}, fmt.Errorf("GetMountRefs not implemented for winMounter")
}

func (mounter *winMounter) EvalHostSymlinks(pathname string) (string, error) {
return "", fmt.Errorf("EvalHostSymlinks not implemented for winMounter")
}

func (mounter *winMounter) GetFSGroup(pathname string) (int64, error) {
return -1, fmt.Errorf("GetFSGroup not implemented for winMounter")
}

func (mounter *winMounter) GetSELinuxSupport(pathname string) (bool, error) {
return false, fmt.Errorf("GetSELinuxSupport not implemented for winMounter")
}

func (mounter *winMounter) GetMode(pathname string) (os.FileMode, error) {
return 0, fmt.Errorf("GetMode not implemented for winMounter")
}

// GetAPIVersions returns the versions of the client APIs this mounter is using.
func (mounter *winMounter) GetAPIVersions() string {
return ""
}

func (mounter *winMounter) CanSafelySkipMountPointCheck() bool {
return false
}
2 changes: 1 addition & 1 deletion pkg/mounter/safe_mounter_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
utilexec "k8s.io/utils/exec"
)

func NewSafeMounter() (*mount.SafeFormatAndMount, error) {
func NewSafeMounter(enableWindowsHostProcess bool) (*mount.SafeFormatAndMount, error) {
return &mount.SafeFormatAndMount{
Interface: mount.New(""),
Exec: utilexec.New(),
Expand Down
5 changes: 3 additions & 2 deletions pkg/mounter/safe_mounter_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ limitations under the License.
package mounter

import (
"github.com/stretchr/testify/assert"
"testing"

"github.com/stretchr/testify/assert"
)

func TestNewSafeMounter(t *testing.T) {
resp, err := NewSafeMounter()
resp, err := NewSafeMounter(false)
assert.NotNil(t, resp)
assert.Nil(t, err)
}
9 changes: 8 additions & 1 deletion pkg/mounter/safe_mounter_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,14 @@ func NewCSIProxyMounter() (*csiProxyMounter, error) {
}, nil
}

func NewSafeMounter() (*mount.SafeFormatAndMount, error) {
func NewSafeMounter(enableWindowsHostProcess bool) (*mount.SafeFormatAndMount, error) {
if enableWindowsHostProcess {
klog.V(2).Infof("using windows host process mounter")
return &mount.SafeFormatAndMount{
Interface: NewWinMounter(),
Exec: utilexec.New(),
}, nil
}
csiProxyMounter, err := NewCSIProxyMounter()
if err == nil {
klog.V(2).Infof("using CSIProxyMounterV1, %s", csiProxyMounter.GetAPIVersions())
Expand Down
Loading

0 comments on commit bcc6818

Please # to comment.