Skip to content

Commit 74279e7

Browse files
authored
Merge pull request #189 from mauriciopoppe/closest-volume-from-target-path-volume-api
Add GetClosestVolumeIDFromTargetPath API to the Volume API Group
2 parents 50d3996 + c0f1eb7 commit 74279e7

34 files changed

+1041
-259
lines changed

client/api/volume/v2alpha1/api.pb.go

Lines changed: 293 additions & 109 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/api/volume/v2alpha1/api.proto

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ service Volume {
3333
// GetVolumeIDFromTargetPath gets the volume id for a given target path.
3434
rpc GetVolumeIDFromTargetPath(GetVolumeIDFromTargetPathRequest) returns (GetVolumeIDFromTargetPathResponse) {}
3535

36+
// GetClosestVolumeIDFromTargetPath gets the closest volume id for a given target path
37+
// by following symlinks and moving up in the filesystem, if after moving up in the filesystem
38+
// we get to a DriveLetter then the volume corresponding to this drive letter is returned instead.
39+
rpc GetClosestVolumeIDFromTargetPath(GetClosestVolumeIDFromTargetPathRequest) returns (GetClosestVolumeIDFromTargetPathResponse) {}
40+
3641
// WriteVolumeCache write volume cache to disk.
3742
rpc WriteVolumeCache(WriteVolumeCacheRequest) returns (WriteVolumeCacheResponse) {}
3843
}
@@ -133,6 +138,16 @@ message GetVolumeIDFromTargetPathResponse {
133138
string volume_id = 1;
134139
}
135140

141+
message GetClosestVolumeIDFromTargetPathRequest {
142+
// The target path.
143+
string target_path = 1;
144+
}
145+
146+
message GetClosestVolumeIDFromTargetPathResponse {
147+
// The volume device ID.
148+
string volume_id = 1;
149+
}
150+
136151
message WriteVolumeCacheRequest {
137152
// Volume device ID of the volume to flush the cache.
138153
string volume_id = 1;

client/groups/disk/v1/client_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/groups/filesystem/v1/client_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/groups/smb/v1/client_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/groups/volume/v1/client_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/groups/volume/v2alpha1/client_generated.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integrationtests/apigroups/client/dummy/v1/client_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integrationtests/apigroups/server/dummy/api_group_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integrationtests/apigroups/server/dummy/impl/v1/server_generated.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

integrationtests/utils.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,16 @@ type VirtualHardDisk struct {
201201
InitialSize int64
202202
}
203203

204-
func diskInit(t *testing.T) (*VirtualHardDisk, func()) {
204+
func getTestPluginPath() (string, int) {
205205
s1 := rand.NewSource(time.Now().UTC().UnixNano())
206206
r1 := rand.New(s1)
207207

208-
testId := r1.Intn(10000000)
209-
testPluginPath := fmt.Sprintf("C:\\var\\lib\\kubelet\\plugins\\testplugin-%d.csi.io\\", testId)
208+
testId := r1.Intn(1000000)
209+
return fmt.Sprintf("C:\\var\\lib\\kubelet\\plugins\\testplugin-%d.csi.io\\", testId), testId
210+
}
211+
212+
func diskInit(t *testing.T) (*VirtualHardDisk, func()) {
213+
testPluginPath, testId := getTestPluginPath()
210214
mountPath := fmt.Sprintf("%smount-%d", testPluginPath, testId)
211215
vhdxPath := fmt.Sprintf("%sdisk-%d.vhdx", testPluginPath, testId)
212216

@@ -240,7 +244,8 @@ func diskInit(t *testing.T) (*VirtualHardDisk, func()) {
240244
if diskNumUnparsed, err = runPowershellCmd(t, cmd); err != nil {
241245
t.Fatalf("Error: %v. Command: %s", err, cmd)
242246
}
243-
if diskNum, err = strconv.ParseUint(strings.TrimRight(diskNumUnparsed, "\r\n"), 10, 32); err != nil {
247+
diskNumUnparsed = strings.TrimSpace(diskNumUnparsed)
248+
if diskNum, err = strconv.ParseUint(diskNumUnparsed, 10, 32); err != nil {
244249
t.Fatalf("Error: %v", err)
245250
}
246251

integrationtests/volume_v2alpha1_test.go

Lines changed: 170 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ package integrationtests
33
import (
44
"context"
55
"fmt"
6+
"os"
7+
"os/exec"
8+
"path/filepath"
9+
"strings"
610
"testing"
711

812
diskv1 "github.com/kubernetes-csi/csi-proxy/client/api/disk/v1"
@@ -11,23 +15,10 @@ import (
1115
v2alpha1client "github.com/kubernetes-csi/csi-proxy/client/groups/volume/v2alpha1"
1216
)
1317

14-
func v2alpha1VolumeTests(t *testing.T) {
15-
var volumeClient *v2alpha1client.Client
16-
var diskClient *diskv1client.Client
17-
var err error
18-
19-
if volumeClient, err = v2alpha1client.NewClient(); err != nil {
20-
t.Fatalf("Client new error: %v", err)
21-
}
22-
defer volumeClient.Close()
23-
24-
if diskClient, err = diskv1client.NewClient(); err != nil {
25-
t.Fatalf("DiskClient new error: %v", err)
26-
}
27-
defer diskClient.Close()
28-
18+
// volumeInit initializes a volume, it creates a VHD, initializes it,
19+
// creates a partition with the max size and formats the volume corresponding to that partition
20+
func volumeInit(volumeClient *v2alpha1client.Client, t *testing.T) (*VirtualHardDisk, string, func()) {
2921
vhd, vhdCleanup := diskInit(t)
30-
defer vhdCleanup()
3122

3223
listRequest := &v2alpha1.ListVolumesOnDiskRequest{
3324
DiskNumber: vhd.DiskNumber,
@@ -42,6 +33,7 @@ func v2alpha1VolumeTests(t *testing.T) {
4233
t.Fatalf("Number of volumes not equal to 1: %d", volumeIDsLen)
4334
}
4435
volumeID := listResponse.VolumeIds[0]
36+
t.Logf("VolumeId %v", volumeID)
4537

4638
isVolumeFormattedRequest := &v2alpha1.IsVolumeFormattedRequest{
4739
VolumeId: volumeID,
@@ -69,8 +61,146 @@ func v2alpha1VolumeTests(t *testing.T) {
6961
if !isVolumeFormattedResponse.Formatted {
7062
t.Fatal("Volume should be formatted. Unexpected !!")
7163
}
64+
return vhd, volumeID, vhdCleanup
65+
}
66+
67+
func v2alpha1GetClosestVolumeFromTargetPathTests(diskClient *diskv1client.Client, volumeClient *v2alpha1client.Client, t *testing.T) {
68+
t.Run("DriveLetterVolume", func(t *testing.T) {
69+
vhd, _, vhdCleanup := volumeInit(volumeClient, t)
70+
defer vhdCleanup()
71+
72+
// vhd.Mount dir exists, because there are no volumes above it should return the C:\ volume
73+
var request *v2alpha1.GetClosestVolumeIDFromTargetPathRequest
74+
var response *v2alpha1.GetClosestVolumeIDFromTargetPathResponse
75+
request = &v2alpha1.GetClosestVolumeIDFromTargetPathRequest{
76+
TargetPath: vhd.Mount,
77+
}
78+
response, err := volumeClient.GetClosestVolumeIDFromTargetPath(context.TODO(), request)
79+
if err != nil {
80+
t.Fatalf("GetClosestVolumeIDFromTargetPath request error, err=%v", err)
81+
}
82+
83+
// the C drive volume
84+
cmd := exec.Command("powershell", "/c", `(Get-Partition -DriveLetter C | Get-Volume).UniqueId`)
85+
targetb, err := cmd.Output()
86+
if err != nil {
87+
t.Fatalf("Failed to get the C: drive volume")
88+
}
89+
cDriveVolume := strings.TrimSpace(string(targetb))
90+
91+
if response.VolumeId != cDriveVolume {
92+
t.Fatalf("The volume from GetClosestVolumeIDFromTargetPath doesn't match the C: drive volume")
93+
}
94+
})
95+
t.Run("AncestorVolumeFromNestedDirectory", func(t *testing.T) {
96+
var err error
97+
vhd, volumeID, vhdCleanup := volumeInit(volumeClient, t)
98+
defer vhdCleanup()
99+
100+
// Mount the volume
101+
mountVolumeRequest := &v2alpha1.MountVolumeRequest{
102+
VolumeId: volumeID,
103+
TargetPath: vhd.Mount,
104+
}
105+
_, err = volumeClient.MountVolume(context.TODO(), mountVolumeRequest)
106+
if err != nil {
107+
t.Fatalf("Volume id %s mount to path %s failed. Error: %v", volumeID, vhd.Mount, err)
108+
}
109+
110+
// Unmount the volume
111+
defer func() {
112+
unmountVolumeRequest := &v2alpha1.UnmountVolumeRequest{
113+
VolumeId: volumeID,
114+
TargetPath: vhd.Mount,
115+
}
116+
_, err = volumeClient.UnmountVolume(context.TODO(), unmountVolumeRequest)
117+
if err != nil {
118+
t.Fatalf("Volume id %s mount to path %s failed. Error: %v", volumeID, vhd.Mount, err)
119+
}
120+
}()
121+
122+
nestedDirectory := filepath.Join(vhd.Mount, "foo/bar")
123+
err = os.MkdirAll(nestedDirectory, os.ModeDir)
124+
if err != nil {
125+
t.Fatalf("Failed to create directory=%s", nestedDirectory)
126+
}
127+
128+
// the volume returned should be the VHD volume
129+
var request *v2alpha1.GetClosestVolumeIDFromTargetPathRequest
130+
var response *v2alpha1.GetClosestVolumeIDFromTargetPathResponse
131+
request = &v2alpha1.GetClosestVolumeIDFromTargetPathRequest{
132+
TargetPath: nestedDirectory,
133+
}
134+
response, err = volumeClient.GetClosestVolumeIDFromTargetPath(context.TODO(), request)
135+
if err != nil {
136+
t.Fatalf("GetClosestVolumeIDFromTargetPath request error, err=%v", err)
137+
}
138+
139+
if response.VolumeId != volumeID {
140+
t.Fatalf("The volume from GetClosestVolumeIDFromTargetPath doesn't match the VHD volume=%s", volumeID)
141+
}
142+
})
143+
144+
t.Run("SymlinkToVolume", func(t *testing.T) {
145+
var err error
146+
vhd, volumeID, vhdCleanup := volumeInit(volumeClient, t)
147+
defer vhdCleanup()
148+
149+
// Mount the volume
150+
mountVolumeRequest := &v2alpha1.MountVolumeRequest{
151+
VolumeId: volumeID,
152+
TargetPath: vhd.Mount,
153+
}
154+
_, err = volumeClient.MountVolume(context.TODO(), mountVolumeRequest)
155+
if err != nil {
156+
t.Fatalf("Volume id %s mount to path %s failed. Error: %v", volumeID, vhd.Mount, err)
157+
}
158+
159+
// Unmount the volume
160+
defer func() {
161+
unmountVolumeRequest := &v2alpha1.UnmountVolumeRequest{
162+
VolumeId: volumeID,
163+
TargetPath: vhd.Mount,
164+
}
165+
_, err = volumeClient.UnmountVolume(context.TODO(), unmountVolumeRequest)
166+
if err != nil {
167+
t.Fatalf("Volume id %s mount to path %s failed. Error: %v", volumeID, vhd.Mount, err)
168+
}
169+
}()
170+
171+
testPluginPath, _ := getTestPluginPath()
172+
err = os.MkdirAll(testPluginPath, os.ModeDir)
173+
if err != nil {
174+
t.Fatalf("Failed to create directory=%s", testPluginPath)
175+
}
176+
177+
sourceSymlink := filepath.Join(testPluginPath, "source")
178+
err = os.Symlink(vhd.Mount, sourceSymlink)
179+
if err != nil {
180+
t.Fatalf("Failed to create the symlink=%s", sourceSymlink)
181+
}
182+
183+
// the volume returned should be the VHD volume
184+
var request *v2alpha1.GetClosestVolumeIDFromTargetPathRequest
185+
var response *v2alpha1.GetClosestVolumeIDFromTargetPathResponse
186+
request = &v2alpha1.GetClosestVolumeIDFromTargetPathRequest{
187+
TargetPath: sourceSymlink,
188+
}
189+
response, err = volumeClient.GetClosestVolumeIDFromTargetPath(context.TODO(), request)
190+
if err != nil {
191+
t.Fatalf("GetClosestVolumeIDFromTargetPath request error, err=%v", err)
192+
}
193+
194+
if response.VolumeId != volumeID {
195+
t.Fatalf("The volume from GetClosestVolumeIDFromTargetPath doesn't match the VHD volume=%s", volumeID)
196+
}
197+
})
198+
}
199+
200+
func v2alpha1MountVolumeTests(diskClient *diskv1client.Client, volumeClient *v2alpha1client.Client, t *testing.T) {
201+
vhd, volumeID, vhdCleanup := volumeInit(volumeClient, t)
202+
defer vhdCleanup()
72203

73-
t.Logf("VolumeId %v", volumeID)
74204
volumeStatsRequest := &v2alpha1.GetVolumeStatsRequest{
75205
VolumeId: volumeID,
76206
}
@@ -167,3 +297,26 @@ func v2alpha1VolumeTests(t *testing.T) {
167297
t.Fatalf("Volume id %s mount to path %s failed. Error: %v", volumeID, vhd.Mount, err)
168298
}
169299
}
300+
301+
func v2alpha1VolumeTests(t *testing.T) {
302+
var volumeClient *v2alpha1client.Client
303+
var diskClient *diskv1client.Client
304+
var err error
305+
306+
if volumeClient, err = v2alpha1client.NewClient(); err != nil {
307+
t.Fatalf("Client new error: %v", err)
308+
}
309+
defer volumeClient.Close()
310+
311+
if diskClient, err = diskv1client.NewClient(); err != nil {
312+
t.Fatalf("DiskClient new error: %v", err)
313+
}
314+
defer diskClient.Close()
315+
316+
t.Run("MountVolume", func(t *testing.T) {
317+
v2alpha1MountVolumeTests(diskClient, volumeClient, t)
318+
})
319+
t.Run("GetClosestVolumeFromTargetPath", func(t *testing.T) {
320+
v2alpha1GetClosestVolumeFromTargetPathTests(diskClient, volumeClient, t)
321+
})
322+
}

0 commit comments

Comments
 (0)