Skip to content

Commit 8c70512

Browse files
committed
Use WMI to implement System API to reduce PowerShell overhead
1 parent 2b4087a commit 8c70512

File tree

1,391 files changed

+423394
-27
lines changed

Some content is hidden

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

1,391 files changed

+423394
-27
lines changed

pkg/cim/system.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//go:build windows
2+
// +build windows
3+
4+
package cim
5+
6+
import (
7+
"fmt"
8+
9+
"github.com/microsoft/wmi/pkg/base/query"
10+
"github.com/microsoft/wmi/server2019/root/cimv2"
11+
)
12+
13+
// QueryBIOSElement retrieves the BIOS element.
14+
//
15+
// The equivalent WMI query is:
16+
//
17+
// SELECT [selectors] FROM CIM_BIOSElement
18+
//
19+
// Refer to https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/cim-bioselement
20+
// for the WMI class definition.
21+
func QueryBIOSElement(selectorList []string) (*cimv2.CIM_BIOSElement, error) {
22+
biosQuery := query.NewWmiQueryWithSelectList("CIM_BIOSElement", selectorList)
23+
instances, err := QueryInstances("", biosQuery)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
bios, err := cimv2.NewCIM_BIOSElementEx1(instances[0])
29+
if err != nil {
30+
return nil, fmt.Errorf("failed to get BIOS element: %w", err)
31+
}
32+
33+
return bios, err
34+
}
35+
36+
// QueryServiceByName retrieves a specific service by its name.
37+
//
38+
// The equivalent WMI query is:
39+
//
40+
// SELECT [selectors] FROM Win32_Service
41+
//
42+
// Refer to https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-service
43+
// for the WMI class definition.
44+
func QueryServiceByName(name string, selectorList []string) (*cimv2.Win32_Service, error) {
45+
serviceQuery := query.NewWmiQueryWithSelectList("Win32_Service", selectorList, "Name", name)
46+
instances, err := QueryInstances("", serviceQuery)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
service, err := cimv2.NewWin32_ServiceEx1(instances[0])
52+
if err != nil {
53+
return nil, fmt.Errorf("failed to get service %s: %w", name, err)
54+
}
55+
56+
return service, err
57+
}

pkg/os/system/api.go

+59-27
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package system
22

33
import (
4-
"encoding/json"
54
"fmt"
6-
"os/exec"
7-
"strings"
85

6+
"github.com/kubernetes-csi/csi-proxy/pkg/cim"
7+
"github.com/kubernetes-csi/csi-proxy/pkg/server/system/impl"
98
"github.com/kubernetes-csi/csi-proxy/pkg/utils"
109
)
1110

@@ -25,52 +24,85 @@ type ServiceInfo struct {
2524
Status uint32 `json:"Status"`
2625
}
2726

27+
var (
28+
startModeMappings = map[string]uint32{
29+
"Boot": impl.START_TYPE_BOOT,
30+
"System": impl.START_TYPE_SYSTEM,
31+
"Auto": impl.START_TYPE_AUTOMATIC,
32+
"Manual": impl.START_TYPE_MANUAL,
33+
"Disabled": impl.START_TYPE_DISABLED,
34+
}
35+
36+
statusMappings = map[string]uint32{
37+
"Unknown": impl.SERVICE_STATUS_UNKNOWN,
38+
"Stopped": impl.SERVICE_STATUS_STOPPED,
39+
"Start Pending": impl.SERVICE_STATUS_START_PENDING,
40+
"Stop Pending": impl.SERVICE_STATUS_STOP_PENDING,
41+
"Running": impl.SERVICE_STATUS_RUNNING,
42+
"Continue Pending": impl.SERVICE_STATUS_CONTINUE_PENDING,
43+
"Pause Pending": impl.SERVICE_STATUS_PAUSE_PENDING,
44+
"Paused": impl.SERVICE_STATUS_PAUSED,
45+
}
46+
)
47+
48+
func serviceStartModeToStartType(startMode string) uint32 {
49+
return startModeMappings[startMode]
50+
}
51+
52+
func serviceState(status string) uint32 {
53+
return statusMappings[status]
54+
}
55+
2856
type APIImplementor struct{}
2957

3058
func New() APIImplementor {
3159
return APIImplementor{}
3260
}
3361

3462
func (APIImplementor) GetBIOSSerialNumber() (string, error) {
35-
// Taken from Kubernetes vSphere cloud provider
36-
// https://github.com/kubernetes/kubernetes/blob/103e926604de6f79161b78af3e792d0ed282bc06/staging/src/k8s.io/legacy-cloud-providers/vsphere/vsphere_util_windows.go#L28
37-
result, err := exec.Command("wmic", "bios", "get", "serialnumber").Output()
63+
bios, err := cim.QueryBIOSElement([]string{"SerialNumber"})
3864
if err != nil {
39-
return "", err
65+
return "", fmt.Errorf("failed to get BIOS element: %w", err)
4066
}
41-
lines := strings.FieldsFunc(string(result), func(r rune) bool {
42-
switch r {
43-
case '\n', '\r':
44-
return true
45-
default:
46-
return false
47-
}
48-
})
49-
if len(lines) != 2 {
50-
return "", fmt.Errorf("received unexpected value retrieving host uuid: %q", string(result))
67+
68+
sn, err := bios.GetPropertySerialNumber()
69+
if err != nil {
70+
return "", fmt.Errorf("failed to get BIOS serial number property: %w", err)
5171
}
52-
return lines[1], nil
72+
73+
return sn, nil
5374
}
5475

5576
func (APIImplementor) GetService(name string) (*ServiceInfo, error) {
56-
script := `Get-Service -Name $env:ServiceName | Select-Object DisplayName, Status, StartType | ` +
57-
`ConvertTo-JSON`
58-
cmdEnv := fmt.Sprintf("ServiceName=%s", name)
59-
out, err := utils.RunPowershellCmd(script, cmdEnv)
77+
service, err := cim.QueryServiceByName(name, []string{"DisplayName", "State", "StartMode"})
78+
if err != nil {
79+
return nil, fmt.Errorf("failed to get service %s: %w", name, err)
80+
}
81+
82+
displayName, err := service.GetPropertyDisplayName()
83+
if err != nil {
84+
return nil, fmt.Errorf("failed to get displayName property of service %s: %w", name, err)
85+
}
86+
87+
state, err := service.GetPropertyState()
6088
if err != nil {
61-
return nil, fmt.Errorf("error querying service name=%s. cmd: %s, output: %s, error: %v", name, script, string(out), err)
89+
return nil, fmt.Errorf("failed to get state property of service %s: %w", name, err)
6290
}
6391

64-
var serviceInfo ServiceInfo
65-
err = json.Unmarshal(out, &serviceInfo)
92+
startMode, err := service.GetPropertyStartMode()
6693
if err != nil {
67-
return nil, err
94+
return nil, fmt.Errorf("failed to get startMode property of service %s: %w", name, err)
6895
}
6996

70-
return &serviceInfo, nil
97+
return &ServiceInfo{
98+
DisplayName: displayName,
99+
StartType: serviceStartModeToStartType(startMode),
100+
Status: serviceState(state),
101+
}, nil
71102
}
72103

73104
func (APIImplementor) StartService(name string) error {
105+
// Note: both StartService and StopService are not implemented by WMI
74106
script := `Start-Service -Name $env:ServiceName`
75107
cmdEnv := fmt.Sprintf("ServiceName=%s", name)
76108
out, err := utils.RunPowershellCmd(script, cmdEnv)

0 commit comments

Comments
 (0)