Skip to content

Commit ba9a0a8

Browse files
authored
Merge pull request #231 from alexander-ding/enh/migrate-v2
Migrate filesystem API Group to library model
2 parents db70477 + 0c1daa6 commit ba9a0a8

File tree

10 files changed

+1040
-14
lines changed

10 files changed

+1040
-14
lines changed

integrationtests/filesystem_test.go

+235-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,245 @@
11
package integrationtests
22

33
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"io/ioutil"
8+
"math/rand"
49
"os"
10+
"path/filepath"
511
"testing"
12+
"time"
13+
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
16+
17+
"github.com/kubernetes-csi/csi-proxy/pkg/filesystem"
18+
filesystemapi "github.com/kubernetes-csi/csi-proxy/pkg/filesystem/api"
619
)
720

8-
func pathExists(path string) (bool, error) {
9-
_, err := os.Stat(path)
10-
if err == nil {
11-
return true, nil
12-
}
13-
if os.IsNotExist(err) {
14-
return false, nil
15-
}
16-
return false, err
21+
func TestFilesystem(t *testing.T) {
22+
t.Run("PathExists positive", func(t *testing.T) {
23+
client, err := filesystem.New(filesystemapi.New())
24+
require.Nil(t, err)
25+
26+
s1 := rand.NewSource(time.Now().UnixNano())
27+
r1 := rand.New(s1)
28+
29+
// simulate FS operations around staging a volume on a node
30+
stagepath := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io\\volume%d", r1.Intn(100), r1.Intn(100)), t)
31+
mkdirReq := &filesystem.MkdirRequest{
32+
Path: stagepath,
33+
}
34+
_, err = client.Mkdir(context.Background(), mkdirReq)
35+
require.NoError(t, err)
36+
37+
exists, err := pathExists(stagepath)
38+
assert.True(t, exists, err)
39+
40+
// simulate operations around publishing a volume to a pod
41+
podpath := getKubeletPathForTest(fmt.Sprintf("test-pod-id\\volumes\\kubernetes.io~csi\\pvc-test%d", r1.Intn(100)), t)
42+
mkdirReq = &filesystem.MkdirRequest{
43+
Path: podpath,
44+
}
45+
_, err = client.Mkdir(context.Background(), mkdirReq)
46+
require.NoError(t, err)
47+
48+
exists, err = pathExists(podpath)
49+
assert.True(t, exists, err)
50+
51+
sourcePath := stagepath
52+
targetPath := filepath.Join(podpath, "rootvol")
53+
// source <- target
54+
linkReq := &filesystem.CreateSymlinkRequest{
55+
SourcePath: sourcePath,
56+
TargetPath: targetPath,
57+
}
58+
_, err = client.CreateSymlink(context.Background(), linkReq)
59+
require.NoError(t, err)
60+
61+
exists, err = pathExists(podpath + "\\rootvol")
62+
assert.True(t, exists, err)
63+
64+
// cleanup pvpath
65+
rmdirReq := &filesystem.RmdirRequest{
66+
Path: podpath,
67+
Force: true,
68+
}
69+
_, err = client.Rmdir(context.Background(), rmdirReq)
70+
require.NoError(t, err)
71+
72+
exists, err = pathExists(podpath)
73+
assert.False(t, exists, err)
74+
75+
// cleanup plugin path
76+
rmdirReq = &filesystem.RmdirRequest{
77+
Path: stagepath,
78+
Force: true,
79+
}
80+
_, err = client.Rmdir(context.Background(), rmdirReq)
81+
require.NoError(t, err)
82+
83+
exists, err = pathExists(stagepath)
84+
assert.False(t, exists, err)
85+
})
86+
t.Run("IsMount", func(t *testing.T) {
87+
client, err := filesystem.New(filesystemapi.New())
88+
require.Nil(t, err)
89+
90+
s1 := rand.NewSource(time.Now().UnixNano())
91+
r1 := rand.New(s1)
92+
rand1 := r1.Intn(100)
93+
rand2 := r1.Intn(100)
94+
95+
testDir := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io", rand1), t)
96+
err = os.MkdirAll(testDir, os.ModeDir)
97+
require.Nil(t, err)
98+
defer os.RemoveAll(testDir)
99+
100+
// 1. Check the isMount on a path which does not exist. Failure scenario.
101+
stagepath := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io\\volume%d", rand1, rand2), t)
102+
IsSymlinkRequest := &filesystem.IsSymlinkRequest{
103+
Path: stagepath,
104+
}
105+
isSymlink, err := client.IsSymlink(context.Background(), IsSymlinkRequest)
106+
require.NotNil(t, err)
107+
108+
// 2. Create the directory. This time its not a mount point. Failure scenario.
109+
err = os.Mkdir(stagepath, os.ModeDir)
110+
require.Nil(t, err)
111+
defer os.Remove(stagepath)
112+
IsSymlinkRequest = &filesystem.IsSymlinkRequest{
113+
Path: stagepath,
114+
}
115+
isSymlink, err = client.IsSymlink(context.Background(), IsSymlinkRequest)
116+
require.Nil(t, err)
117+
require.Equal(t, isSymlink.IsSymlink, false)
118+
119+
err = os.Remove(stagepath)
120+
require.Nil(t, err)
121+
targetStagePath := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io\\volume%d-tgt", rand1, rand2), t)
122+
lnTargetStagePath := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io\\volume%d-tgt-ln", rand1, rand2), t)
123+
124+
// 3. Create soft link to the directory and make sure target exists. Success scenario.
125+
err = os.Mkdir(targetStagePath, os.ModeDir)
126+
require.Nil(t, err)
127+
defer os.Remove(targetStagePath)
128+
// Create a symlink
129+
err = os.Symlink(targetStagePath, lnTargetStagePath)
130+
require.Nil(t, err)
131+
defer os.Remove(lnTargetStagePath)
132+
133+
IsSymlinkRequest = &filesystem.IsSymlinkRequest{
134+
Path: lnTargetStagePath,
135+
}
136+
isSymlink, err = client.IsSymlink(context.Background(), IsSymlinkRequest)
137+
require.Nil(t, err)
138+
require.Equal(t, isSymlink.IsSymlink, true)
139+
140+
// 4. Remove the path. Failure scenario.
141+
err = os.Remove(targetStagePath)
142+
require.Nil(t, err)
143+
IsSymlinkRequest = &filesystem.IsSymlinkRequest{
144+
Path: lnTargetStagePath,
145+
}
146+
isSymlink, err = client.IsSymlink(context.Background(), IsSymlinkRequest)
147+
require.Nil(t, err)
148+
require.Equal(t, isSymlink.IsSymlink, false)
149+
})
150+
t.Run("RmdirContents", func(t *testing.T) {
151+
client, err := filesystem.New(filesystemapi.New())
152+
require.Nil(t, err)
153+
154+
r1 := rand.New(rand.NewSource(time.Now().UnixNano()))
155+
rand1 := r1.Intn(100)
156+
157+
rootPath := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io", rand1), t)
158+
// this line should delete the rootPath because only its content were deleted
159+
defer os.RemoveAll(rootPath)
160+
161+
paths := []string{
162+
filepath.Join(rootPath, "foo/goo/"),
163+
filepath.Join(rootPath, "foo/bar/baz/"),
164+
filepath.Join(rootPath, "alpha/beta/gamma/"),
165+
}
166+
for _, path := range paths {
167+
err = os.MkdirAll(path, os.ModeDir)
168+
require.Nil(t, err)
169+
}
170+
171+
rmdirContentsRequest := &filesystem.RmdirContentsRequest{
172+
Path: rootPath,
173+
}
174+
_, err = client.RmdirContents(context.Background(), rmdirContentsRequest)
175+
require.Nil(t, err)
176+
177+
// the root path should exist
178+
exists, err := pathExists(rootPath)
179+
assert.True(t, exists, err)
180+
// the root path children shouldn't exist
181+
for _, path := range paths {
182+
exists, err = pathExists(path)
183+
assert.False(t, exists, err)
184+
}
185+
})
186+
187+
t.Run("RmdirContentsNoFollowSymlink", func(t *testing.T) {
188+
// RmdirContents should not delete the target of a symlink, only the symlink
189+
client, err := filesystem.New(filesystemapi.New())
190+
require.Nil(t, err)
191+
192+
r1 := rand.New(rand.NewSource(time.Now().UnixNano()))
193+
rand1 := r1.Intn(100)
194+
195+
rootPath := getKubeletPathForTest(fmt.Sprintf("testplugin-%d.csi.io", rand1), t)
196+
// this line should delete the rootPath because only its content were deleted
197+
defer os.RemoveAll(rootPath)
198+
199+
insidePath := filepath.Join(rootPath, "inside/")
200+
outsidePath := filepath.Join(rootPath, "outside/")
201+
paths := []string{
202+
filepath.Join(insidePath, "foo/goo/"),
203+
filepath.Join(insidePath, "foo/bar/baz/"),
204+
filepath.Join(insidePath, "foo/beta/gamma/"),
205+
outsidePath,
206+
}
207+
for _, path := range paths {
208+
err = os.MkdirAll(path, os.ModeDir)
209+
require.Nil(t, err)
210+
}
211+
212+
// create a temp file on the outside and make a symlink from the inside to the outside
213+
outsideFile := filepath.Join(outsidePath, "target")
214+
insideFile := filepath.Join(insidePath, "source")
215+
216+
file, err := os.Create(outsideFile)
217+
require.Nil(t, err)
218+
defer file.Close()
219+
err = os.Symlink(outsideFile, insideFile)
220+
require.Nil(t, err)
221+
222+
rmdirContentsRequest := &filesystem.RmdirContentsRequest{
223+
Path: insidePath,
224+
}
225+
_, err = client.RmdirContents(context.Background(), rmdirContentsRequest)
226+
require.Nil(t, err)
227+
228+
// the inside path should exist
229+
exists, err := pathExists(insidePath)
230+
require.Nil(t, err)
231+
assert.True(t, exists, "The path shouldn't exist")
232+
// it should have no children
233+
children, err := ioutil.ReadDir(insidePath)
234+
require.Nil(t, err)
235+
assert.True(t, len(children) == 0, "The RmdirContents path to delete shouldn't have children")
236+
// the symlink target should exist
237+
_, err = os.Open(outsideFile)
238+
if errors.Is(err, os.ErrNotExist) {
239+
// the file should exist but it was deleted!
240+
t.Fatalf("File outsideFile=%s doesn't exist", outsideFile)
241+
}
242+
})
17243
}
18244

19245
func TestFilesystemAPIGroup(t *testing.T) {

integrationtests/utils.go

+11
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,14 @@ func diskInit(t *testing.T) (*VirtualHardDisk, func()) {
273273

274274
return vhd, cleanup
275275
}
276+
277+
func pathExists(path string) (bool, error) {
278+
_, err := os.Stat(path)
279+
if err == nil {
280+
return true, nil
281+
}
282+
if os.IsNotExist(err) {
283+
return false, nil
284+
}
285+
return false, err
286+
}

0 commit comments

Comments
 (0)