Skip to content

Commit 9dc5046

Browse files
authored
Merge pull request #384 from laozc/wmi-doc
Add doc for WMI
2 parents 0138982 + 6805b8a commit 9dc5046

File tree

2 files changed

+209
-0
lines changed

2 files changed

+209
-0
lines changed

docs/IMPLEMENTATION.md

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# CSI Proxy API Implementation with WMI
2+
<a name="top"></a>
3+
4+
## Table of Contents
5+
6+
- [Windows Management Instrumentation](#wmi)
7+
- [microsoft/wmi library](#microsoft-wmi-library)
8+
- [How to make WMI queries and debug with PowerShell](#debug-powershell)
9+
10+
11+
<a name="wmi"></a>
12+
## Windows Management Instrumentation
13+
14+
Windows Management Instrumentation (WMI) is the infrastructure for management data and operations on Windows-based operating systems.
15+
Refer to [WMI start page](https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmi-start-page) for more details.
16+
17+
The purpose of WMI is to define a proprietary set of environment-independent specifications that enable sharing management information between management apps.
18+
19+
CSI-proxy makes WMI queries using `microsoft/wmi` library. Refer to for the call graph below.
20+
21+
<a name="microsoft-wmi-library"></a>
22+
## microsoft/wmi library
23+
24+
![WMI based implementation](./WMI.png)
25+
26+
`microsoft/wmi` library leverages the traditional COM interfaces (`IDispatch`) to call the WMI.
27+
28+
COM interfaces wrap the parameters and return value in a `VARIANT` struct.
29+
`microsoft/wmi` library converts the `VARIANT` to native Go types and struct.
30+
31+
A typical WMI query may need to obtain a WMI session of the target machine first, which
32+
can be done by the helper methods `NewWMISession` and `QueryFromWMI` in `pkg/cim`.
33+
34+
A query like `SELECT * FROM MSFT_Volume` may return all the volumes on the current node.
35+
36+
### Queries
37+
38+
The query may return a list of WMI objects of the generic type `cim.WmiInstance`. You may further cast
39+
the object down to a specific WMI class (e.g. `MSFT_Disk`). You may find the WMI class definition
40+
from the API doc.
41+
42+
For example, the property `PartitionStyle` on [MSFT_Disk](https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-disk#properties) is defined as
43+
44+
| API constraints | Settings |
45+
|-----------------|---------------------------------------|
46+
| Property | PartitionStyle |
47+
| Data type | UInt16 |
48+
| Access type | Read-only |
49+
| Qualifiers | Required |
50+
| Description | The partition style used by the disk. |
51+
52+
You may use `GetProperty` to get the value of `PartitionStyle` to get the value from the `VARAINT` and
53+
converts it back to Go types.
54+
55+
```go
56+
retValue, err := disk.GetProperty("PartitionStyle")
57+
if err != nil {
58+
return false, fmt.Errorf("failed to query partition style of disk %d: %w", diskNumber, err)
59+
}
60+
61+
partitionStyle = retValue.(int32)
62+
```
63+
64+
Note that some auto-generated wrapper methods in `microsoft/wmi` may have wrong data types mapping to Go native types.
65+
It's always recommended to use `GetProperty` instead of these pre-defined wrapper methods.
66+
67+
### Class Method
68+
69+
A WMI class may have some Class Method to call for a specific operation (e.g., creating a new partition).
70+
71+
You may use the method `InvokeMethodWithReturn`.
72+
73+
```go
74+
result, err := disk.InvokeMethodWithReturn(
75+
"CreatePartition",
76+
nil, // Size
77+
true, // UseMaximumSize
78+
nil, // Offset
79+
nil, // Alignment
80+
nil, // DriveLetter
81+
false, // AssignDriveLetter
82+
nil, // MbrType,
83+
cim.GPTPartitionTypeBasicData, // GPT Type
84+
false, // IsHidden
85+
false, // IsActive,
86+
)
87+
// 42002 is returned by driver letter failed to assign after partition
88+
if (result != 0 && result != 42002) || err != nil {
89+
return fmt.Errorf("error creating partition on disk %d. result: %d, err: %v", diskNumber, result, err)
90+
}
91+
```
92+
93+
Both input and output parameters can be found in the [CreatePartition API doc](https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/createpartition-msft-disk).
94+
95+
```c
96+
UInt32 CreatePartition(
97+
[in] UInt64 Size,
98+
[in] Boolean UseMaximumSize,
99+
[in] UInt64 Offset,
100+
[in] UInt32 Alignment,
101+
[in] Char16 DriveLetter,
102+
[in] Boolean AssignDriveLetter,
103+
[in] UInt16 MbrType,
104+
[in] String GptType,
105+
[in] Boolean IsHidden,
106+
[in] Boolean IsActive,
107+
[out] String CreatedPartition,
108+
[out] String ExtendedStatus
109+
);
110+
```
111+
112+
There parameters will be wrapped in `VARIANT` with the corresponding types.
113+
114+
Eventually the method `CreatePartition` on the WMI object will be called via `IDispatch` interface in native COM/OLE calls.
115+
116+
Refer to [CallMethod](https://github.com/go-ole/go-ole/blob/master/oleutil/oleutil.go#L49-L52) if you need to know the details of a COM/OLE call.
117+
118+
```go
119+
func CallMethod(disp *ole.IDispatch, name string, params ...interface{}) (result *ole.VARIANT, err error) {
120+
return disp.InvokeWithOptionalArgs(name, ole.DISPATCH_METHOD, params)
121+
}
122+
```
123+
124+
<a name="debug-powershell"></a>
125+
## Debug with PowerShell
126+
127+
### How to make WMI call with PowerShell
128+
129+
You will find the `Query` for each method in `pkg/cim` package.
130+
For example, this is the comment of `ListVolume`
131+
132+
```go
133+
// ListVolumes retrieves all available volumes on the system.
134+
//
135+
// The equivalent WMI query is:
136+
//
137+
// SELECT [selectors] FROM MSFT_Volume
138+
//
139+
// Refer to https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/msft-volume
140+
// for the WMI class definition.
141+
```
142+
143+
You may use the same query with PowerShell cmdlet `Get-CimInstance` targeting
144+
the corresponding namespace `Root\Microsoft\Windows\Storage`.
145+
146+
The return result will be an object of `MSFT_Volume` WMI class.
147+
148+
e.g. if we're going to list the details of the first volume on Windows system:
149+
150+
```powershell
151+
PS C:\Users\Administrator> $vol = (Get-CimInstance -Namespace "Root\Microsoft\Windows\Storage" -Query "SELECT * FROM MSFT_Volume")[0]
152+
PS C:\Users\Administrator> $vol
153+
154+
ObjectId : {1}\\WIN-8E2EVAQ9QSB\root/Microsoft/Windows/Storage/Providers_v2\WSP_Volume.ObjectId=
155+
"{b65bb3cd-da86-11ee-854b-806e6f6e6963}:VO:\\?\Volume{1781d1eb-2c0a-47ed-987f-c229b9c
156+
02527}\"
157+
PassThroughClass :
158+
PassThroughIds :
159+
PassThroughNamespace :
160+
PassThroughServer :
161+
UniqueId : \\?\Volume{1781d1eb-2c0a-47ed-987f-c229b9c02527}\
162+
AllocationUnitSize : 4096
163+
DedupMode : 4
164+
DriveLetter : C
165+
DriveType : 3
166+
FileSystem : NTFS
167+
FileSystemLabel :
168+
FileSystemType : 14
169+
HealthStatus : 1
170+
OperationalStatus : {53261}
171+
Path : \\?\Volume{1781d1eb-2c0a-47ed-987f-c229b9c02527}\
172+
Size : 536198770688
173+
SizeRemaining : 407553982464
174+
PSComputerName :
175+
```
176+
177+
Then you may use `obj.FileSystem` to get the file system of the volume.
178+
179+
```powershell
180+
PS C:\Users\Administrator> $vol.FileSystem
181+
NTFS
182+
```
183+
184+
### Call Class Method
185+
186+
You may get Class Methods for a single CIM class using `$class.CimClassMethods`.
187+
188+
```powershell
189+
190+
PS C:\Users\Administrator> $class = Get-CimClass -ClassName MSFT_StorageSetting -Namespace "Root\Microsoft\Windows\Storage"
191+
PS C:\Users\Administrator> $class.CimClassMethods
192+
193+
Name ReturnType Parameters Qualifiers
194+
---- ---------- ---------- ----------
195+
Get UInt32 {StorageSetting} {implemented, static}
196+
Set UInt32 {NewDiskPolicy, ScrubPolicy} {implemented, static}
197+
UpdateHostStorageCache UInt32 {} {implemented, static}
198+
```
199+
200+
You may use `Invoke-CimMethod` to invoke those static methods on the `CimClass` object.
201+
202+
```powershell
203+
PS C:\Users\Administrator> Invoke-CimMethod -CimClass $class -MethodName UpdateHostStorageCache @{}
204+
205+
ReturnValue PSComputerName
206+
----------- --------------
207+
0
208+
209+
```

docs/WMI.png

1.75 MB
Loading

0 commit comments

Comments
 (0)