Skip to content

Commit 7b2a546

Browse files
committed
Use WMI to implement SMB API to reduce PowerShell overhead
1 parent a9bd679 commit 7b2a546

File tree

3 files changed

+83
-11
lines changed

3 files changed

+83
-11
lines changed

pkg/cim/smb.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package cim
5+
6+
import (
7+
"github.com/microsoft/wmi/pkg/base/query"
8+
cim "github.com/microsoft/wmi/pkg/wmiinstance"
9+
)
10+
11+
// Refer to https://learn.microsoft.com/en-us/previous-versions/windows/desktop/smb/msft-smbmapping
12+
const (
13+
SmbMappingStatusOK int32 = iota
14+
SmbMappingStatusPaused
15+
SmbMappingStatusDisconnected
16+
SmbMappingStatusNetworkError
17+
SmbMappingStatusConnecting
18+
SmbMappingStatusReconnecting
19+
SmbMappingStatusUnavailable
20+
)
21+
22+
// QuerySmbGlobalMappingByRemotePath retrieves the SMB global mapping from its remote path.
23+
//
24+
// The equivalent WMI query is:
25+
//
26+
// SELECT [selectors] FROM MSFT_SmbGlobalMapping
27+
//
28+
// Refer to https://pkg.go.dev/github.com/microsoft/wmi/server2019/root/microsoft/windows/smb#MSFT_SmbGlobalMapping
29+
// for the WMI class definition.
30+
func QuerySmbGlobalMappingByRemotePath(remotePath string) (*cim.WmiInstance, error) {
31+
smbQuery := query.NewWmiQuery("MSFT_SmbGlobalMapping", "RemotePath", remotePath)
32+
instances, err := QueryInstances(WMINamespaceSmb, smbQuery)
33+
if err != nil {
34+
return nil, err
35+
}
36+
37+
return instances[0], err
38+
}
39+
40+
// RemoveSmbGlobalMappingByRemotePath removes a SMB global mapping matching to the remote path.
41+
//
42+
// Refer to https://pkg.go.dev/github.com/microsoft/wmi/server2019/root/microsoft/windows/smb#MSFT_SmbGlobalMapping
43+
// for the WMI class definition.
44+
func RemoveSmbGlobalMappingByRemotePath(remotePath string) error {
45+
smbQuery := query.NewWmiQuery("MSFT_SmbGlobalMapping", "RemotePath", remotePath)
46+
instances, err := QueryInstances(WMINamespaceSmb, smbQuery)
47+
if err != nil {
48+
return err
49+
}
50+
51+
_, err = instances[0].InvokeMethod("Remove", true)
52+
return err
53+
}

pkg/cim/wmi.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
const (
1919
WMINamespaceRoot = "Root\\CimV2"
2020
WMINamespaceStorage = "Root\\Microsoft\\Windows\\Storage"
21+
WMINamespaceSmb = "Root\\Microsoft\\Windows\\Smb"
2122
)
2223

2324
type InstanceHandler func(instance *cim.WmiInstance) (bool, error)

pkg/os/smb/api.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"strings"
66

7+
"github.com/kubernetes-csi/csi-proxy/pkg/cim"
78
"github.com/kubernetes-csi/csi-proxy/pkg/utils"
89
)
910

@@ -26,18 +27,22 @@ func New(requirePrivacy bool) *SmbAPI {
2627
}
2728
}
2829

30+
func remotePathForQuery(remotePath string) string {
31+
return strings.ReplaceAll(remotePath, "\\", "\\\\")
32+
}
33+
2934
func (*SmbAPI) IsSmbMapped(remotePath string) (bool, error) {
30-
cmdLine := `$(Get-SmbGlobalMapping -RemotePath $Env:smbremotepath -ErrorAction Stop).Status `
31-
cmdEnv := fmt.Sprintf("smbremotepath=%s", remotePath)
32-
out, err := utils.RunPowershellCmd(cmdLine, cmdEnv)
35+
inst, err := cim.QuerySmbGlobalMappingByRemotePath(remotePathForQuery(remotePath))
3336
if err != nil {
34-
return false, fmt.Errorf("error checking smb mapping. cmd %s, output: %s, err: %v", remotePath, string(out), err)
37+
return false, cim.IgnoreNotFound(err)
3538
}
3639

37-
if len(out) == 0 || !strings.EqualFold(strings.TrimSpace(string(out)), "OK") {
38-
return false, nil
40+
status, err := inst.GetProperty("Status")
41+
if err != nil {
42+
return false, err
3943
}
40-
return true, nil
44+
45+
return status.(int32) == cim.SmbMappingStatusOK, nil
4146
}
4247

4348
// NewSmbLink - creates a directory symbolic link to the remote share.
@@ -48,7 +53,6 @@ func (*SmbAPI) IsSmbMapped(remotePath string) (bool, error) {
4853
// alpha to merge the paths.
4954
// TODO (for beta release): Merge the link paths - os.Symlink and Powershell link path.
5055
func (*SmbAPI) NewSmbLink(remotePath, localPath string) error {
51-
5256
if !strings.HasSuffix(remotePath, "\\") {
5357
// Golang has issues resolving paths mapped to file shares if they do not end in a trailing \
5458
// so add one if needed.
@@ -78,12 +82,26 @@ func (api *SmbAPI) NewSmbGlobalMapping(remotePath, username, password string) er
7882
return fmt.Errorf("NewSmbGlobalMapping failed. output: %q, err: %v", string(output), err)
7983
}
8084
return nil
85+
//TODO: move to use WMI when the credentials could be correctly handled
86+
//params := map[string]interface{}{
87+
// "RemotePath": remotePath,
88+
// "RequirePrivacy": api.RequirePrivacy,
89+
//}
90+
//if username != "" {
91+
// params["Credential"] = fmt.Sprintf("%s:%s", username, password)
92+
//}
93+
//result, _, err := cim.InvokeCimMethod(cim.WMINamespaceSmb, "MSFT_SmbGlobalMapping", "Create", params)
94+
//if err != nil {
95+
// return fmt.Errorf("NewSmbGlobalMapping failed. result: %d, err: %v", result, err)
96+
//}
97+
//return nil
8198
}
8299

83100
func (*SmbAPI) RemoveSmbGlobalMapping(remotePath string) error {
84-
cmd := `Remove-SmbGlobalMapping -RemotePath $Env:smbremotepath -Force`
85-
if output, err := utils.RunPowershellCmd(cmd, fmt.Sprintf("smbremotepath=%s", remotePath)); err != nil {
86-
return fmt.Errorf("UnmountSmbShare failed. output: %q, err: %v", string(output), err)
101+
err := cim.RemoveSmbGlobalMappingByRemotePath(remotePathForQuery(remotePath))
102+
if err != nil {
103+
return fmt.Errorf("error remove smb mapping '%s'. err: %v", remotePath, err)
87104
}
105+
88106
return nil
89107
}

0 commit comments

Comments
 (0)