Skip to content

Commit 7ee9449

Browse files
committed
Use WMI instead of PowerShell for OS operations
1 parent 67871ec commit 7ee9449

File tree

1,711 files changed

+477778
-400
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,711 files changed

+477778
-400
lines changed

go.mod

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
module github.com/kubernetes-csi/csi-proxy
22

3-
go 1.20
3+
go 1.22
4+
5+
toolchain go1.23.2
46

57
require (
68
github.com/Microsoft/go-winio v0.6.1
9+
github.com/go-ole/go-ole v1.3.0
710
github.com/google/go-cmp v0.6.0
811
github.com/iancoleman/strcase v0.3.0
912
github.com/kubernetes-csi/csi-proxy/client v0.0.0-00010101000000-000000000000
13+
github.com/microsoft/wmi v0.23.0
1014
github.com/pkg/errors v0.9.1
1115
github.com/sergi/go-diff v1.3.1
1216
github.com/spf13/pflag v1.0.5

go.sum

+6
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
1616
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
1717
github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
1818
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
19+
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
20+
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
1921
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
2022
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
2123
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -50,6 +52,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
5052
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
5153
github.com/mauriciopoppe/gengo v0.0.0-20210525224835-9c78f58f3486 h1:+l047vEi0SyAzdVToIaAcfoY5DwwGW+OyqTdH/P3TTg=
5254
github.com/mauriciopoppe/gengo v0.0.0-20210525224835-9c78f58f3486/go.mod h1:xXv3T4UXTLta31wMhVezwVkc26OLei4hMbLeBJbPmxc=
55+
github.com/microsoft/wmi v0.23.0 h1:EbgjakKBOfb4QaTJNiGkfKrb2RWv7wpyicI2g3DHWkw=
56+
github.com/microsoft/wmi v0.23.0/go.mod h1:PNc5VFG7cpB7VOb3ILZNuWMWsqFfYLPyzpoiFkA6fAQ=
5357
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
5458
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
5559
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -85,10 +89,12 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
8589
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
8690
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
8791
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
92+
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
8893
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
8994
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
9095
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
9196
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
97+
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9298
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
9399
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
94100
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

pkg/cim/disk.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package cim
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
7+
"github.com/microsoft/wmi/pkg/base/query"
8+
"github.com/microsoft/wmi/server2019/root/microsoft/windows/storage"
9+
)
10+
11+
const (
12+
// PartitionStyleUnknown indicates an unknown partition table format
13+
PartitionStyleUnknown = 0
14+
// PartitionStyleGPT indicates the disk uses GUID Partition Table (GPT) format
15+
PartitionStyleGPT = 2
16+
17+
// GPTPartitionTypeBasicData is the GUID for basic data partitions in GPT
18+
// Used for general purpose storage partitions
19+
GPTPartitionTypeBasicData = "{ebd0a0a2-b9e5-4433-87c0-68b6b72699c7}"
20+
// GPTPartitionTypeMicrosoftReserved is the GUID for Microsoft Reserved Partition (MSR)
21+
// Reserved by Windows for system use
22+
GPTPartitionTypeMicrosoftReserved = "{e3c9e316-0b5c-4db8-817d-f92df00215ae}"
23+
)
24+
25+
// QueryDiskByNumber retrieves disk information for a specific disk identified by its number.
26+
func QueryDiskByNumber(diskNumber uint32, selectorList []string) (*storage.MSFT_Disk, error) {
27+
diskQuery := query.NewWmiQueryWithSelectList("MSFT_Disk", selectorList, "Number", strconv.Itoa(int(diskNumber)))
28+
instances, err := QueryInstances(WMINamespaceStorage, diskQuery)
29+
if err != nil {
30+
return nil, err
31+
}
32+
33+
disk, err := storage.NewMSFT_DiskEx1(instances[0])
34+
if err != nil {
35+
return nil, fmt.Errorf("failed to query disk %d. error: %v", diskNumber, err)
36+
}
37+
38+
return disk, nil
39+
}
40+
41+
// ListDisks retrieves information about all available disks.
42+
func ListDisks(selectorList []string) ([]*storage.MSFT_Disk, error) {
43+
diskQuery := query.NewWmiQueryWithSelectList("MSFT_Disk", selectorList)
44+
instances, err := QueryInstances(WMINamespaceStorage, diskQuery)
45+
if IgnoreNotFound(err) != nil {
46+
return nil, err
47+
}
48+
49+
var disks []*storage.MSFT_Disk
50+
for _, instance := range instances {
51+
disk, err := storage.NewMSFT_DiskEx1(instance)
52+
if err != nil {
53+
return nil, fmt.Errorf("failed to query disk %v. error: %v", instance, err)
54+
}
55+
56+
disks = append(disks, disk)
57+
}
58+
59+
return disks, nil
60+
}

pkg/cim/iscsi.go

+271
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
package cim
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
7+
"github.com/microsoft/wmi/pkg/base/query"
8+
cim "github.com/microsoft/wmi/pkg/wmiinstance"
9+
"github.com/microsoft/wmi/server2019/root/microsoft/windows/storage"
10+
)
11+
12+
// ListISCSITargetPortals retrieves a list of iSCSI target portals.
13+
func ListISCSITargetPortals(selectorList []string) ([]*storage.MSFT_iSCSITargetPortal, error) {
14+
q := query.NewWmiQueryWithSelectList("MSFT_IscsiTargetPortal", selectorList)
15+
instances, err := QueryInstances(WMINamespaceStorage, q)
16+
if IgnoreNotFound(err) != nil {
17+
return nil, err
18+
}
19+
20+
var targetPortals []*storage.MSFT_iSCSITargetPortal
21+
for _, instance := range instances {
22+
portal, err := storage.NewMSFT_iSCSITargetPortalEx1(instance)
23+
if err != nil {
24+
return nil, fmt.Errorf("failed to query iSCSI target portal %v. error: %v", instance, err)
25+
}
26+
27+
targetPortals = append(targetPortals, portal)
28+
}
29+
30+
return targetPortals, nil
31+
}
32+
33+
// QueryISCSITargetPortal retrieves information about a specific iSCSI target portal
34+
// identified by its network address and port number.
35+
func QueryISCSITargetPortal(address string, port uint32, selectorList []string) (*storage.MSFT_iSCSITargetPortal, error) {
36+
portalQuery := query.NewWmiQueryWithSelectList(
37+
"MSFT_iSCSITargetPortal", selectorList,
38+
"TargetPortalAddress", address,
39+
"TargetPortalPortNumber", strconv.Itoa(int(port)))
40+
instances, err := QueryInstances(WMINamespaceStorage, portalQuery)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
targetPortal, err := storage.NewMSFT_iSCSITargetPortalEx1(instances[0])
46+
if err != nil {
47+
return nil, fmt.Errorf("failed to query iSCSI target portal at (%s:%d). error: %v", address, port, err)
48+
}
49+
50+
return targetPortal, nil
51+
}
52+
53+
// NewISCSITargetPortal creates a new iSCSI target portal.
54+
func NewISCSITargetPortal(targetPortalAddress string,
55+
targetPortalPortNumber uint32,
56+
initiatorInstanceName *string,
57+
initiatorPortalAddress *string,
58+
isHeaderDigest *bool,
59+
isDataDigest *bool) (*storage.MSFT_iSCSITargetPortal, error) {
60+
params := map[string]interface{}{
61+
"TargetPortalAddress": targetPortalAddress,
62+
"TargetPortalPortNumber": targetPortalPortNumber,
63+
}
64+
if initiatorInstanceName != nil {
65+
params["InitiatorInstanceName"] = *initiatorInstanceName
66+
}
67+
if initiatorPortalAddress != nil {
68+
params["InitiatorPortalAddress"] = *initiatorPortalAddress
69+
}
70+
if isHeaderDigest != nil {
71+
params["IsHeaderDigest"] = *isHeaderDigest
72+
}
73+
if isDataDigest != nil {
74+
params["IsDataDigest"] = *isDataDigest
75+
}
76+
result, _, err := InvokeCimMethod(WMINamespaceStorage, "MSFT_iSCSITargetPortal", "New", params)
77+
if err != nil {
78+
return nil, fmt.Errorf("failed to create iSCSI target portal with %v. result: %d, error: %v", params, result, err)
79+
}
80+
81+
return QueryISCSITargetPortal(targetPortalAddress, targetPortalPortNumber, nil)
82+
}
83+
84+
var (
85+
// Indexes iSCSI targets by their Object ID specified in node address
86+
mappingISCSITargetIndexer = mappingObjectRefIndexer("iSCSITarget", "MSFT_iSCSITarget", "NodeAddress")
87+
// Indexes iSCSI target portals by their Object ID specified in portal address
88+
mappingISCSITargetPortalIndexer = mappingObjectRefIndexer("iSCSITargetPortal", "MSFT_iSCSITargetPortal", "TargetPortalAddress")
89+
// Indexes iSCSI connections by their Object ID specified in connection identifier
90+
mappingISCSIConnectionIndexer = mappingObjectRefIndexer("iSCSIConnection", "MSFT_iSCSIConnection", "ConnectionIdentifier")
91+
// Indexes iSCSI sessions by their Object ID specified in session identifier
92+
mappingISCSISessionIndexer = mappingObjectRefIndexer("iSCSISession", "MSFT_iSCSISession", "SessionIdentifier")
93+
94+
// Indexes iSCSI targets by their node address
95+
iscsiTargetIndexer = stringPropertyIndexer("NodeAddress")
96+
// Indexes iSCSI targets by their target portal address
97+
iscsiTargetPortalIndexer = stringPropertyIndexer("TargetPortalAddress")
98+
// Indexes iSCSI connections by their connection identifier
99+
iscsiConnectionIndexer = stringPropertyIndexer("ConnectionIdentifier")
100+
// Indexes iSCSI sessions by their session identifier
101+
iscsiSessionIndexer = stringPropertyIndexer("SessionIdentifier")
102+
)
103+
104+
// ListISCSITargetToISCSITargetPortalMapping builds a mapping between iSCSI target and iSCSI target portal with iSCSI target as the key.
105+
func ListISCSITargetToISCSITargetPortalMapping() (map[string]string, error) {
106+
return ListWMIInstanceMappings(WMINamespaceStorage, "MSFT_iSCSITargetToiSCSITargetPortal", nil, mappingISCSITargetIndexer, mappingISCSITargetPortalIndexer)
107+
}
108+
109+
// ListISCSIConnectionToISCSITargetMapping builds a mapping between iSCSI connection and iSCSI target with iSCSI connection as the key.
110+
func ListISCSIConnectionToISCSITargetMapping() (map[string]string, error) {
111+
return ListWMIInstanceMappings(WMINamespaceStorage, "MSFT_iSCSITargetToiSCSIConnection", nil, mappingISCSIConnectionIndexer, mappingISCSITargetIndexer)
112+
}
113+
114+
// ListISCSISessionToISCSITargetMapping builds a mapping between iSCSI session and iSCSI target with iSCSI session as the key.
115+
func ListISCSISessionToISCSITargetMapping() (map[string]string, error) {
116+
return ListWMIInstanceMappings(WMINamespaceStorage, "MSFT_iSCSITargetToiSCSISession", nil, mappingISCSISessionIndexer, mappingISCSITargetIndexer)
117+
}
118+
119+
// ListDiskToISCSIConnectionMapping builds a mapping between disk and iSCSI connection with disk Object ID as the key.
120+
func ListDiskToISCSIConnectionMapping() (map[string]string, error) {
121+
return ListWMIInstanceMappings(WMINamespaceStorage, "MSFT_iSCSIConnectionToDisk", nil, mappingObjectRefIndexer("Disk", "MSFT_Disk", "ObjectId"), mappingISCSIConnectionIndexer)
122+
}
123+
124+
// ListISCSITargetsByTargetPortalWithFilters retrieves all iSCSI targets from the specified iSCSI target portal and conditions by query filters.
125+
func ListISCSITargetsByTargetPortalWithFilters(targetSelectorList []string, portals []*storage.MSFT_iSCSITargetPortal, filters ...*query.WmiQueryFilter) ([]*storage.MSFT_iSCSITarget, error) {
126+
targetQuery := query.NewWmiQueryWithSelectList("MSFT_iSCSITarget", targetSelectorList)
127+
targetQuery.Filters = append(targetQuery.Filters, filters...)
128+
instances, err := QueryInstances(WMINamespaceStorage, targetQuery)
129+
if err != nil {
130+
return nil, err
131+
}
132+
133+
var portalInstances []*cim.WmiInstance
134+
for _, portal := range portals {
135+
portalInstances = append(portalInstances, portal.WmiInstance)
136+
}
137+
138+
targetToTargetPortalMapping, err := ListISCSITargetToISCSITargetPortalMapping()
139+
if err != nil {
140+
return nil, err
141+
}
142+
143+
targetInstances, err := FindInstancesByMapping(instances, iscsiTargetIndexer, portalInstances, iscsiTargetPortalIndexer, targetToTargetPortalMapping)
144+
if err != nil {
145+
return nil, err
146+
}
147+
148+
var targets []*storage.MSFT_iSCSITarget
149+
for _, instance := range targetInstances {
150+
target, err := storage.NewMSFT_iSCSITargetEx1(instance)
151+
if err != nil {
152+
return nil, fmt.Errorf("failed to query iSCSI target %v. %v", instance, err)
153+
}
154+
155+
targets = append(targets, target)
156+
}
157+
158+
return targets, nil
159+
}
160+
161+
// QueryISCSITarget retrieves the iSCSI target from the specified portal address, portal and node address.
162+
func QueryISCSITarget(address string, port uint32, nodeAddress string, selectorList []string) (*storage.MSFT_iSCSITarget, error) {
163+
portal, err := QueryISCSITargetPortal(address, port, nil)
164+
if err != nil {
165+
return nil, err
166+
}
167+
168+
targets, err := ListISCSITargetsByTargetPortalWithFilters(selectorList, []*storage.MSFT_iSCSITargetPortal{portal},
169+
query.NewWmiQueryFilter("NodeAddress", nodeAddress, query.Equals))
170+
if err != nil {
171+
return nil, err
172+
}
173+
174+
return targets[0], nil
175+
}
176+
177+
// QueryISCSISessionByTarget retrieves the iSCSI session from the specified iSCSI target.
178+
func QueryISCSISessionByTarget(target *storage.MSFT_iSCSITarget, selectorList []string) (*storage.MSFT_iSCSISession, error) {
179+
sessionQuery := query.NewWmiQueryWithSelectList("MSFT_iSCSISession", selectorList)
180+
sessionInstances, err := QueryInstances(WMINamespaceStorage, sessionQuery)
181+
if err != nil {
182+
return nil, err
183+
}
184+
185+
targetToTargetSessionMapping, err := ListISCSISessionToISCSITargetMapping()
186+
if err != nil {
187+
return nil, err
188+
}
189+
190+
filtered, err := FindInstancesByMapping(sessionInstances, iscsiSessionIndexer, []*cim.WmiInstance{target.WmiInstance}, iscsiTargetIndexer, targetToTargetSessionMapping)
191+
if err != nil {
192+
return nil, err
193+
}
194+
195+
session, err := storage.NewMSFT_iSCSISessionEx1(filtered[0])
196+
return session, err
197+
}
198+
199+
// ListDisksByTarget lists all the disks on the specified iSCSI target.
200+
func ListDisksByTarget(target *storage.MSFT_iSCSITarget, selectorList []string) ([]*storage.MSFT_Disk, error) {
201+
// list connections to the given iSCSI target
202+
connectionQuery := query.NewWmiQueryWithSelectList("MSFT_iSCSIConnection", selectorList)
203+
connectionInstances, err := QueryInstances(WMINamespaceStorage, connectionQuery)
204+
if err != nil {
205+
return nil, err
206+
}
207+
208+
connectionToTargetMapping, err := ListISCSIConnectionToISCSITargetMapping()
209+
if err != nil {
210+
return nil, err
211+
}
212+
213+
connectionsToTarget, err := FindInstancesByMapping(connectionInstances, iscsiConnectionIndexer, []*cim.WmiInstance{target.WmiInstance}, iscsiTargetIndexer, connectionToTargetMapping)
214+
if err != nil {
215+
return nil, err
216+
}
217+
218+
disks, err := ListDisks(selectorList)
219+
if err != nil {
220+
return nil, err
221+
}
222+
223+
var diskInstances []*cim.WmiInstance
224+
for _, disk := range disks {
225+
diskInstances = append(diskInstances, disk.WmiInstance)
226+
}
227+
228+
diskToConnectionMapping, err := ListDiskToISCSIConnectionMapping()
229+
if err != nil {
230+
return nil, err
231+
}
232+
233+
filtered, err := FindInstancesByMapping(diskInstances, objectIDPropertyIndexer, connectionsToTarget, iscsiConnectionIndexer, diskToConnectionMapping)
234+
if err != nil {
235+
return nil, err
236+
}
237+
238+
var filteredDisks []*storage.MSFT_Disk
239+
for _, instance := range filtered {
240+
disk, err := storage.NewMSFT_DiskEx1(instance)
241+
if err != nil {
242+
return nil, fmt.Errorf("failed to query disk %v. error: %v", disk, err)
243+
}
244+
245+
filteredDisks = append(filteredDisks, disk)
246+
}
247+
return filteredDisks, err
248+
}
249+
250+
// ConnectISCSITarget establishes a connection to an iSCSI target with optional CHAP authentication credential.
251+
func ConnectISCSITarget(portalAddress string, portalPortNumber uint32, nodeAddress string, authType string, chapUsername *string, chapSecret *string) (int, map[string]interface{}, error) {
252+
inParams := map[string]interface{}{
253+
"NodeAddress": nodeAddress,
254+
"TargetPortalAddress": portalAddress,
255+
"TargetPortalPortNumber": int(portalPortNumber),
256+
"AuthenticationType": authType,
257+
}
258+
// InitiatorPortalAddress
259+
// IsDataDigest
260+
// IsHeaderDigest
261+
// ReportToPnP
262+
if chapUsername != nil {
263+
inParams["ChapUsername"] = *chapUsername
264+
}
265+
if chapSecret != nil {
266+
inParams["ChapSecret"] = *chapSecret
267+
}
268+
269+
result, outParams, err := InvokeCimMethod(WMINamespaceStorage, "MSFT_iSCSITarget", "Connect", inParams)
270+
return result, outParams, err
271+
}

0 commit comments

Comments
 (0)