Skip to content

Commit cb6e280

Browse files
authored
Merge pull request #2595 from k8s-infra-cherrypick-robot/cherry-pick-2532-to-release-1.33
[release-1.33] feat: Use WMI to implement Volume API to reduce PowerShell overhead
2 parents 40a8c8b + 4e9c271 commit cb6e280

File tree

107 files changed

+7563
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+7563
-16
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ require (
1313
github.com/Azure/azure-sdk-for-go/sdk/storage/azfile v1.5.1
1414
github.com/container-storage-interface/spec v1.10.0
1515
github.com/fsnotify/fsnotify v1.9.0
16+
github.com/go-ole/go-ole v1.3.0
1617
github.com/golang/protobuf v1.5.4
1718
github.com/google/uuid v1.6.0
1819
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1
1920
github.com/kata-containers/kata-containers/src/runtime v0.0.0-20240702121346-ef3f6515cf8a
2021
github.com/kubernetes-csi/csi-lib-utils v0.14.1
2122
github.com/kubernetes-csi/csi-proxy/client v1.0.1
2223
github.com/kubernetes-csi/external-snapshotter/client/v4 v4.2.0
24+
github.com/microsoft/wmi v0.31.1
2325
github.com/onsi/ginkgo/v2 v2.23.4
2426
github.com/onsi/gomega v1.37.0
2527
github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
162162
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
163163
github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
164164
github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
165+
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
166+
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
165167
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
166168
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
167169
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
@@ -314,6 +316,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
314316
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
315317
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
316318
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
319+
github.com/microsoft/wmi v0.31.1 h1:PULwDNxRF2T/hOolcOpvJ2+9z0//MybOVja4tXTBSTw=
320+
github.com/microsoft/wmi v0.31.1/go.mod h1:1zbdSF0A+5OwTUII5p3hN7/K6KF2m3o27pSG6Y51VU8=
317321
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible h1:aKW/4cBs+yK6gpqU3K/oIwk9Q/XICqd3zOX/UFuvqmk=
318322
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
319323
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=

pkg/azurefile/azurefile.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ type Driver struct {
253253
appendActimeoOption bool
254254
printVolumeStatsCallLogs bool
255255
enableKataCCMount bool
256+
useWinCIMAPI bool
256257
mounter *mount.SafeFormatAndMount
257258
server *grpc.Server
258259
// lock per volume attach (only for vhd disk feature)
@@ -342,6 +343,7 @@ func NewDriver(options *DriverOptions) *Driver {
342343
driver.resolver = new(NetResolver)
343344
driver.directVolume = new(directVolume)
344345
driver.isKataNode = false
346+
driver.useWinCIMAPI = options.UseWinCIMAPI
345347

346348
var err error
347349
getter := func(_ context.Context, _ string) (interface{}, error) { return nil, nil }
@@ -416,7 +418,7 @@ func (d *Driver) Run(ctx context.Context) error {
416418
}
417419
klog.V(2).Infof("cloud: %s, location: %s, rg: %s, VnetName: %s, VnetResourceGroup: %s, SubnetName: %s", d.cloud.Cloud, d.cloud.Location, d.cloud.ResourceGroup, d.cloud.VnetName, d.cloud.VnetResourceGroup, d.cloud.SubnetName)
418420

419-
d.mounter, err = mounter.NewSafeMounter(d.enableWindowsHostProcess)
421+
d.mounter, err = mounter.NewSafeMounter(d.enableWindowsHostProcess, d.useWinCIMAPI)
420422
if err != nil {
421423
klog.Fatalf("Failed to get safe mounter. Error: %v", err)
422424
}

pkg/azurefile/azurefile_options.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type DriverOptions struct {
4545
AppendNoShareSockOption bool
4646
AppendNoResvPortOption bool
4747
AppendActimeoOption bool
48+
UseWinCIMAPI bool
4849
SkipMatchingTagCacheExpireInMinutes int
4950
VolStatsCacheExpireInMinutes int
5051
PrintVolumeStatsCallLogs bool
@@ -85,6 +86,7 @@ func (o *DriverOptions) AddFlags() *flag.FlagSet {
8586
fs.BoolVar(&o.AppendNoShareSockOption, "append-nosharesock-option", true, "Whether appending nosharesock option to smb mount command")
8687
fs.BoolVar(&o.AppendNoResvPortOption, "append-noresvport-option", true, "Whether appending noresvport option to nfs mount command")
8788
fs.BoolVar(&o.AppendActimeoOption, "append-actimeo-option", true, "Whether appending actimeo=0 option to nfs mount command")
89+
fs.BoolVar(&o.UseWinCIMAPI, "use-win-cim-api", true, "Whether performing azure file operations using CIM API or Powershell command on Windows node")
8890
fs.IntVar(&o.SkipMatchingTagCacheExpireInMinutes, "skip-matching-tag-cache-expire-in-minutes", 30, "The cache expire time in minutes for skipMatchingTagCache")
8991
fs.IntVar(&o.VolStatsCacheExpireInMinutes, "vol-stats-cache-expire-in-minutes", 10, "The cache expire time in minutes for volume stats cache")
9092
fs.BoolVar(&o.PrintVolumeStatsCallLogs, "print-volume-stats-call-logs", false, "Whether to print volume statfs call logs with log level 2")

pkg/azurefile/fake_mounter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func (f *fakeMounter) IsMountPoint(file string) (bool, error) {
7474
// NewFakeMounter fake mounter
7575
func NewFakeMounter() (*mount.SafeFormatAndMount, error) {
7676
if runtime.GOOS == "windows" {
77-
return mounter.NewSafeMounter(true)
77+
return mounter.NewSafeMounter(true, true)
7878
}
7979
return &mount.SafeFormatAndMount{
8080
Interface: &fakeMounter{},

pkg/mounter/safe_mounter_host_process_windows.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,20 @@ var driverGlobalMountPath = "C:\\var\\lib\\kubelet\\plugins\\kubernetes.io\\csi\
3737

3838
var _ CSIProxyMounter = &winMounter{}
3939

40-
type winMounter struct{}
40+
type winMounter struct {
41+
smbAPI smb.SMBAPI
42+
}
4143

42-
func NewWinMounter() *winMounter {
43-
return &winMounter{}
44+
func NewWinMounter(useWinCIMAPI bool) *winMounter {
45+
var smbAPI smb.SMBAPI
46+
if useWinCIMAPI {
47+
smbAPI = smb.NewCimSMBAPI()
48+
} else {
49+
smbAPI = smb.NewPowerShellSMBAPI()
50+
}
51+
return &winMounter{
52+
smbAPI: smbAPI,
53+
}
4454
}
4555

4656
func (mounter *winMounter) SMBMount(source, target, fsType string, mountOptions, sensitiveMountOptions []string) error {
@@ -75,7 +85,7 @@ func (mounter *winMounter) SMBMount(source, target, fsType string, mountOptions,
7585
return fmt.Errorf("remote path is empty")
7686
}
7787

78-
isMapped, err := smb.IsSmbMapped(remotePath)
88+
isMapped, err := mounter.smbAPI.IsSmbMapped(remotePath)
7989
if err != nil {
8090
isMapped = false
8191
}
@@ -88,7 +98,7 @@ func (mounter *winMounter) SMBMount(source, target, fsType string, mountOptions,
8898

8999
if !valid {
90100
klog.Warningf("RemotePath %s is not valid, removing now", remotePath)
91-
if err := smb.RemoveSmbGlobalMapping(remotePath); err != nil {
101+
if err := mounter.smbAPI.RemoveSmbGlobalMapping(remotePath); err != nil {
92102
klog.Errorf("RemoveSmbGlobalMapping(%s) failed with %v", remotePath, err)
93103
return err
94104
}
@@ -100,7 +110,7 @@ func (mounter *winMounter) SMBMount(source, target, fsType string, mountOptions,
100110
klog.V(2).Infof("Remote %s not mapped. Mapping now!", remotePath)
101111
username := mountOptions[0]
102112
password := sensitiveMountOptions[0]
103-
if err := smb.NewSmbGlobalMapping(remotePath, username, password); err != nil {
113+
if err := mounter.smbAPI.NewSmbGlobalMapping(remotePath, username, password); err != nil {
104114
klog.Errorf("NewSmbGlobalMapping(%s) failed with %v", remotePath, err)
105115
return err
106116
}
@@ -136,7 +146,7 @@ func (mounter *winMounter) Unmount(target string) error {
136146
klog.V(2).Infof("remote server path: %s, local path: %s", remoteServer, target)
137147
if hasDupSMBMount, err := smb.CheckForDuplicateSMBMounts(driverGlobalMountPath, target, remoteServer); err == nil {
138148
if !hasDupSMBMount {
139-
if err := smb.RemoveSmbGlobalMapping(remoteServer); err != nil {
149+
if err := mounter.smbAPI.RemoveSmbGlobalMapping(remoteServer); err != nil {
140150
klog.Errorf("RemoveSmbGlobalMapping(%s) failed with %v", target, err)
141151
}
142152
} else {

pkg/mounter/safe_mounter_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import (
2424
utilexec "k8s.io/utils/exec"
2525
)
2626

27-
func NewSafeMounter(_ bool) (*mount.SafeFormatAndMount, error) {
27+
func NewSafeMounter(_, _ bool) (*mount.SafeFormatAndMount, error) {
2828
return &mount.SafeFormatAndMount{
2929
Interface: mount.New(""),
3030
Exec: utilexec.New(),

pkg/mounter/safe_mounter_unix_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
)
2424

2525
func TestNewSafeMounter(t *testing.T) {
26-
resp, err := NewSafeMounter(true)
26+
resp, err := NewSafeMounter(true, true)
2727
assert.NotNil(t, resp)
2828
assert.Nil(t, err)
2929
}

pkg/mounter/safe_mounter_windows.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,11 +291,11 @@ func NewCSIProxyMounter() (*csiProxyMounter, error) {
291291
}, nil
292292
}
293293

294-
func NewSafeMounter(enableWindowsHostProcess bool) (*mount.SafeFormatAndMount, error) {
294+
func NewSafeMounter(enableWindowsHostProcess, useWinCIMAPI bool) (*mount.SafeFormatAndMount, error) {
295295
if enableWindowsHostProcess {
296296
klog.V(2).Infof("using windows host process mounter")
297297
return &mount.SafeFormatAndMount{
298-
Interface: NewWinMounter(),
298+
Interface: NewWinMounter(useWinCIMAPI),
299299
Exec: utilexec.New(),
300300
}, nil
301301
}

pkg/os/cim/smb.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//go:build windows
2+
// +build windows
3+
4+
/*
5+
Copyright 2025 The Kubernetes Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
*/
19+
20+
package cim
21+
22+
import (
23+
"github.com/microsoft/wmi/pkg/base/query"
24+
cim "github.com/microsoft/wmi/pkg/wmiinstance"
25+
)
26+
27+
// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/smb/msft-smbmapping
28+
const (
29+
SmbMappingStatusOK int32 = iota
30+
SmbMappingStatusPaused
31+
SmbMappingStatusDisconnected
32+
SmbMappingStatusNetworkError
33+
SmbMappingStatusConnecting
34+
SmbMappingStatusReconnecting
35+
SmbMappingStatusUnavailable
36+
)
37+
38+
// QuerySmbGlobalMappingByRemotePath retrieves the SMB global mapping from its remote path.
39+
//
40+
// The equivalent WMI query is:
41+
//
42+
// SELECT [selectors] FROM MSFT_SmbGlobalMapping
43+
//
44+
// Refer to https://pkg.go.dev/github.com/microsoft/wmi/server2019/root/microsoft/windows/smb#MSFT_SmbGlobalMapping
45+
// for the WMI class definition.
46+
func QuerySmbGlobalMappingByRemotePath(remotePath string) (*cim.WmiInstance, error) {
47+
smbQuery := query.NewWmiQuery("MSFT_SmbGlobalMapping", "RemotePath", remotePath)
48+
instances, err := QueryInstances(WMINamespaceSmb, smbQuery)
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
return instances[0], err
54+
}
55+
56+
// RemoveSmbGlobalMappingByRemotePath removes a SMB global mapping matching to the remote path.
57+
//
58+
// Refer to https://pkg.go.dev/github.com/microsoft/wmi/server2019/root/microsoft/windows/smb#MSFT_SmbGlobalMapping
59+
// for the WMI class definition.
60+
func RemoveSmbGlobalMappingByRemotePath(remotePath string) error {
61+
smbQuery := query.NewWmiQuery("MSFT_SmbGlobalMapping", "RemotePath", remotePath)
62+
instances, err := QueryInstances(WMINamespaceSmb, smbQuery)
63+
if err != nil {
64+
return err
65+
}
66+
67+
_, err = instances[0].InvokeMethod("Remove", true)
68+
return err
69+
}

0 commit comments

Comments
 (0)