Skip to content

Commit 6655e6b

Browse files
committed
WIP: Support GCEPD driver for Windows
WIP
1 parent a38158b commit 6655e6b

File tree

9 files changed

+545
-98
lines changed

9 files changed

+545
-98
lines changed

cmd/main.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ func handle() {
9090
//Initialize requirements for the node service
9191
var nodeServer *driver.GCENodeServer
9292
if *runNodeService {
93-
mounter := mountmanager.NewSafeMounter()
93+
mounter, err := mountmanager.NewSafeMounter()
94+
if err != nil {
95+
klog.Fatalln("Failed to get safe mounter. Error: %v", err)
96+
}
9497
deviceUtils := mountmanager.NewDeviceUtils()
9598
statter := mountmanager.NewStatter()
9699
meta, err := metadataservice.NewMetadataService()

pkg/gce-pd-csi-driver/node.go

+55-36
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package gceGCEDriver
1717
import (
1818
"fmt"
1919
"os"
20+
"runtime"
2021
"strconv"
2122
"strings"
2223

@@ -57,10 +58,20 @@ var _ csi.NodeServer = &GCENodeServer{}
5758
// node boot disk is considered an attachable disk so effective attach limit is
5859
// one less.
5960
const (
60-
volumeLimitSmall int64 = 15
61-
volumeLimitBig int64 = 127
61+
volumeLimitSmall int64 = 15
62+
volumeLimitBig int64 = 127
63+
defaultLinuxFsType = "ext4"
64+
defaultWindowsFsType = "ntfs"
6265
)
6366

67+
func getDefaultFsType() string {
68+
if runtime.GOOS == "windows" {
69+
return defaultWindowsFsType
70+
} else {
71+
return defaultLinuxFsType
72+
}
73+
}
74+
6475
func (ns *GCENodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) {
6576
// Validate Arguments
6677
targetPath := req.GetTargetPath()
@@ -129,10 +140,12 @@ func (ns *GCENodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePub
129140
}
130141

131142
sourcePath = stagingTargetPath
132-
133-
if err := os.MkdirAll(targetPath, 0750); err != nil {
134-
return nil, status.Error(codes.Internal, fmt.Sprintf("mkdir failed on disk %s (%v)", targetPath, err))
135-
}
143+
/*if runtime.GOOS != "windows" {
144+
if err := os.MkdirAll(targetPath, 0750); err != nil {
145+
return nil, status.Error(codes.Internal, fmt.Sprintf("mkdir failed on disk %s (%v)", targetPath, err))
146+
}
147+
}*/
148+
preparePublishPath(targetPath, ns.Mounter)
136149
} else if blk := volumeCapability.GetBlock(); blk != nil {
137150
klog.V(4).Infof("NodePublishVolume with block volume mode")
138151

@@ -218,11 +231,9 @@ func (ns *GCENodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeU
218231
}
219232
defer ns.volumeLocks.Release(volumeID)
220233

221-
err := mount.CleanupMountPoint(targetPath, ns.Mounter.Interface, false /* bind mount */)
222-
if err != nil {
234+
if err := cleanupPublishPath(targetPath, ns.Mounter); err != nil {
223235
return nil, status.Error(codes.Internal, fmt.Sprintf("Unmount failed: %v\nUnmounting arguments: %s\n", err, targetPath))
224236
}
225-
226237
klog.V(4).Infof("NodeUnpublishVolume succeded on %v from %s", volumeID, targetPath)
227238
return &csi.NodeUnpublishVolumeResponse{}, nil
228239
}
@@ -265,43 +276,51 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage
265276
partition = part
266277
}
267278

268-
devicePath, err := ns.getDevicePath(volumeID, partition)
279+
deviceName, err := common.GetDeviceName(volumeKey)
280+
if err != nil {
281+
return nil, fmt.Errorf("error getting device name: %v", err)
282+
}
283+
284+
devicePath, err := GetDevicePath(ns, deviceName, partition, volumeKey.Name, ns.Mounter)
285+
//devicePath, err := ns.getDevicePath(volumeID, partition)
286+
269287
if err != nil {
270288
return nil, status.Error(codes.Internal, fmt.Sprintf("Error when getting device path: %v", err))
271289
}
272290

273291
klog.V(4).Infof("Successfully found attached GCE PD %q at device path %s.", volumeKey.Name, devicePath)
274292

275-
// Part 2: Check if mount already exists at targetpath
276-
notMnt, err := ns.Mounter.Interface.IsLikelyNotMountPoint(stagingTargetPath)
277-
if err != nil {
278-
if os.IsNotExist(err) {
279-
if err := os.MkdirAll(stagingTargetPath, 0750); err != nil {
280-
return nil, status.Error(codes.Internal, fmt.Sprintf("Failed to create directory (%q): %v", stagingTargetPath, err))
293+
if runtime.GOOS != "windows" {
294+
// Part 2: Check if mount already exists at targetpath
295+
notMnt, err := ns.Mounter.Interface.IsLikelyNotMountPoint(stagingTargetPath)
296+
if err != nil {
297+
if os.IsNotExist(err) {
298+
if err := os.MkdirAll(stagingTargetPath, 0750); err != nil {
299+
return nil, status.Error(codes.Internal, fmt.Sprintf("Failed to create directory (%q): %v", stagingTargetPath, err))
300+
}
301+
notMnt = true
302+
} else {
303+
return nil, status.Error(codes.Internal, fmt.Sprintf("Unknown error when checking mount point (%q): %v", stagingTargetPath, err))
281304
}
282-
notMnt = true
283-
} else {
284-
return nil, status.Error(codes.Internal, fmt.Sprintf("Unknown error when checking mount point (%q): %v", stagingTargetPath, err))
285305
}
286-
}
287306

288-
if !notMnt {
289-
// TODO(#95): Check who is mounted here. No error if its us
290-
/*
291-
1) Target Path MUST be the vol referenced by vol ID
292-
2) VolumeCapability MUST match
293-
3) Readonly MUST match
307+
if !notMnt {
308+
// TODO(#95): Check who is mounted here. No error if its us
309+
/*
310+
1) Target Path MUST be the vol referenced by vol ID
311+
2) VolumeCapability MUST match
312+
3) Readonly MUST match
294313
295-
*/
314+
*/
296315

297-
klog.V(4).Infof("NodeStageVolume succeded on %v to %s, mount already exists.", volumeID, stagingTargetPath)
298-
return &csi.NodeStageVolumeResponse{}, nil
316+
klog.V(4).Infof("NodeStageVolume succeded on %v to %s, mount already exists.", volumeID, stagingTargetPath)
317+
return &csi.NodeStageVolumeResponse{}, nil
299318

319+
}
300320
}
301-
302321
// Part 3: Mount device to stagingTargetPath
303-
// Default fstype is ext4
304-
fstype := "ext4"
322+
fstype := getDefaultFsType()
323+
305324
options := []string{}
306325
if mnt := volumeCapability.GetMount(); mnt != nil {
307326
if mnt.FsType != "" {
@@ -316,7 +335,8 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage
316335
return &csi.NodeStageVolumeResponse{}, nil
317336
}
318337

319-
err = ns.Mounter.FormatAndMount(devicePath, stagingTargetPath, fstype, options)
338+
//err = ns.Mounter.FormatAndMount(devicePath, stagingTargetPath, fstype, options)
339+
err = FormatAndMount(devicePath, stagingTargetPath, fstype, options, ns.Mounter)
320340
if err != nil {
321341
return nil, status.Error(codes.Internal,
322342
fmt.Sprintf("Failed to format and mount device from (%q) to (%q) with fstype (%q) and options (%q): %v",
@@ -343,9 +363,8 @@ func (ns *GCENodeServer) NodeUnstageVolume(ctx context.Context, req *csi.NodeUns
343363
}
344364
defer ns.volumeLocks.Release(volumeID)
345365

346-
err := mount.CleanupMountPoint(stagingTargetPath, ns.Mounter.Interface, false /* bind mount */)
347-
if err != nil {
348-
return nil, status.Error(codes.Internal, fmt.Sprintf("NodeUnstageVolume failed to unmount at path %s: %v", stagingTargetPath, err))
366+
if err := cleanupPublishPath(stagingTargetPath, ns.Mounter); err != nil {
367+
return nil, status.Error(codes.Internal, fmt.Sprintf("NodeUnstageVolume failed: %v\nUnmounting arguments: %s\n", err, stagingTargetPath))
349368
}
350369

351370
klog.V(4).Infof("NodeUnstageVolume succeded on %v from %s", volumeID, stagingTargetPath)

pkg/gce-pd-csi-driver/utils_linux.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
// +build !windows
15+
16+
package gceGCEDriver
17+
18+
import (
19+
"fmt"
20+
21+
"google.golang.org/grpc/codes"
22+
"google.golang.org/grpc/status"
23+
"k8s.io/utils/mount"
24+
)
25+
26+
func GetDevicePath(ns *GCENodeServer, deviceName string, partition string, volumeKey string) (string, error) {
27+
devicePaths := ns.DeviceUtils.GetDiskByIdPaths(deviceName, partition)
28+
devicePath, err := ns.DeviceUtils.VerifyDevicePath(devicePaths, volumeKey)
29+
if err != nil {
30+
return "", status.Error(codes.Internal, fmt.Sprintf("Error verifying GCE PD (%q) is attached: %v", volumeKey, err))
31+
}
32+
if devicePath == "" {
33+
return "", status.Error(codes.Internal, fmt.Sprintf("Unable to find device path out of attempted paths: %v", devicePaths))
34+
}
35+
return devicePath, nil
36+
}
37+
38+
/*func FormatAndMount(ns *GCENodeServer, source string, target string, fstype string, options []string) error {
39+
return ns.Mounter.FormatAndMount(source, target, fstype, options)
40+
}*/
41+
42+
func FormatAndMount(source, target, fstype string, options []string, m *mount.SafeFormatAndMount) error {
43+
return m.FormatAndMount(source, target, fstype, options)
44+
}
45+
46+
func preparePublishPath(path string, m *mount.SafeFormatAndMount) error {
47+
return nil
48+
}
49+
50+
func cleanupPublishPath(path string, m *mount.SafeFormatAndMount) error {
51+
return mount.CleanupMountPoint(path, m, false /* bind mount */)
52+
}
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
// +build windows
15+
16+
package gceGCEDriver
17+
18+
import (
19+
//"encoding/json"
20+
//"errors"
21+
"fmt"
22+
"os/exec"
23+
//"strconv"
24+
//"strings"
25+
//winutils "github.com/ddebroy/csi-proxy/pkg/api/v1alpha1"
26+
//"google.golang.org/grpc/codes"
27+
//"google.golang.org/grpc/status"
28+
"k8s.io/klog"
29+
"k8s.io/utils/mount"
30+
mounter "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/mount-manager"
31+
)
32+
33+
func FormatAndMount(source, target, fstype string, options []string, m *mount.SafeFormatAndMount) error {
34+
proxy, ok := m.Interface.(*mounter.CSIProxyMounter)
35+
if !ok {
36+
return fmt.Errorf("could not cast to csi proxy class")
37+
}
38+
return proxy.FormatAndMount(source, target, fstype, options)
39+
}
40+
41+
func preparePublishPath(path string, m *mount.SafeFormatAndMount) error {
42+
proxy, ok := m.Interface.(*mounter.CSIProxyMounter)
43+
if !ok {
44+
return fmt.Errorf("could not cast to csi proxy class")
45+
}
46+
exists, err := proxy.ExistsPath(path)
47+
if err != nil {
48+
return err
49+
}
50+
if exists {
51+
return proxy.Unmount(path)
52+
}
53+
return nil
54+
}
55+
56+
func cleanupPublishPath(path string, m *mount.SafeFormatAndMount) error {
57+
proxy, ok := m.Interface.(*mounter.CSIProxyMounter)
58+
if !ok {
59+
return fmt.Errorf("could not cast to csi proxy class")
60+
}
61+
return proxy.Unmount(path)
62+
}
63+
64+
// search Windows disk number by LUN
65+
func GetDevicePath(ns *GCENodeServer, deviceName string, partition string, volumeKey string, m *mount.SafeFormatAndMount) (string, error) {
66+
proxy, ok := m.Interface.(*mounter.CSIProxyMounter)
67+
if !ok {
68+
return "", fmt.Errorf("could not cast to csi proxy class")
69+
}
70+
return proxy.GetDevicePath(deviceName, partition, volumeKey)
71+
}
72+
73+
func runExec(cmd string) ([]byte, error) {
74+
klog.V(5).Infof("Running command: %s", cmd)
75+
out, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
76+
klog.V(5).Infof("Result: %s. Len: %d. Error: %v.", string(out), len(string(out)), err)
77+
return out, err
78+
}

pkg/mount-manager/safe-mounter.go renamed to pkg/mount-manager/safe-mounter_linux.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// +build linux
2+
13
/*
24
Copyright 2018 The Kubernetes Authors.
35
@@ -19,12 +21,12 @@ import (
1921
"k8s.io/utils/mount"
2022
)
2123

22-
func NewSafeMounter() *mount.SafeFormatAndMount {
24+
func NewSafeMounter() (*mount.SafeFormatAndMount, error) {
2325
realMounter := mount.New("")
2426
realExec := exec.New()
2527
return &mount.SafeFormatAndMount{
2628
Interface: realMounter,
2729
Exec: realExec,
28-
}
30+
}, nil
2931

3032
}

0 commit comments

Comments
 (0)