Browse code

pkg/mount: testing for linux sharedsubtree mounts

* shared
* shared/slave
* unbindable
* private

Signed-off-by: Vincent Batts <vbatts@redhat.com>

Vincent Batts authored on 2014/11/01 02:12:31
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,331 @@
0
+// +build linux
1
+
2
+package mount
3
+
4
+import (
5
+	"os"
6
+	"path"
7
+	"syscall"
8
+	"testing"
9
+)
10
+
11
+// nothing is propogated in or out
12
+func TestSubtreePrivate(t *testing.T) {
13
+	tmp := path.Join(os.TempDir(), "mount-tests")
14
+	if err := os.MkdirAll(tmp, 0777); err != nil {
15
+		t.Fatal(err)
16
+	}
17
+	defer os.RemoveAll(tmp)
18
+
19
+	var (
20
+		sourceDir   = path.Join(tmp, "source")
21
+		targetDir   = path.Join(tmp, "target")
22
+		outside1Dir = path.Join(tmp, "outside1")
23
+		outside2Dir = path.Join(tmp, "outside2")
24
+
25
+		outside1Path      = path.Join(outside1Dir, "file.txt")
26
+		outside2Path      = path.Join(outside2Dir, "file.txt")
27
+		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
28
+		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
29
+	)
30
+	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
31
+		t.Fatal(err)
32
+	}
33
+	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
34
+		t.Fatal(err)
35
+	}
36
+	if err := os.Mkdir(targetDir, 0777); err != nil {
37
+		t.Fatal(err)
38
+	}
39
+	if err := os.Mkdir(outside1Dir, 0777); err != nil {
40
+		t.Fatal(err)
41
+	}
42
+	if err := os.Mkdir(outside2Dir, 0777); err != nil {
43
+		t.Fatal(err)
44
+	}
45
+
46
+	if err := createFile(outside1Path); err != nil {
47
+		t.Fatal(err)
48
+	}
49
+	if err := createFile(outside2Path); err != nil {
50
+		t.Fatal(err)
51
+	}
52
+
53
+	// mount the shared directory to a target
54
+	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
55
+		t.Fatal(err)
56
+	}
57
+	defer func() {
58
+		if err := Unmount(targetDir); err != nil {
59
+			t.Fatal(err)
60
+		}
61
+	}()
62
+
63
+	// next, make the target private
64
+	if err := MakePrivate(targetDir); err != nil {
65
+		t.Fatal(err)
66
+	}
67
+	defer func() {
68
+		if err := Unmount(targetDir); err != nil {
69
+			t.Fatal(err)
70
+		}
71
+	}()
72
+
73
+	// mount in an outside path to a mounted path inside the _source_
74
+	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
75
+		t.Fatal(err)
76
+	}
77
+	defer func() {
78
+		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
79
+			t.Fatal(err)
80
+		}
81
+	}()
82
+
83
+	// check that this file _does_not_ show in the _target_
84
+	if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
85
+		t.Fatal(err)
86
+	} else if err == nil {
87
+		t.Fatalf("%q should not be visible, but is", outside1CheckPath)
88
+	}
89
+
90
+	// next mount outside2Dir into the _target_
91
+	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
92
+		t.Fatal(err)
93
+	}
94
+	defer func() {
95
+		if err := Unmount(path.Join(targetDir, "b")); err != nil {
96
+			t.Fatal(err)
97
+		}
98
+	}()
99
+
100
+	// check that this file _does_not_ show in the _source_
101
+	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
102
+		t.Fatal(err)
103
+	} else if err == nil {
104
+		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
105
+	}
106
+}
107
+
108
+// Testing that when a target is a shared mount,
109
+// then child mounts propogate to the source
110
+func TestSubtreeShared(t *testing.T) {
111
+	tmp := path.Join(os.TempDir(), "mount-tests")
112
+	if err := os.MkdirAll(tmp, 0777); err != nil {
113
+		t.Fatal(err)
114
+	}
115
+	defer os.RemoveAll(tmp)
116
+
117
+	var (
118
+		sourceDir  = path.Join(tmp, "source")
119
+		targetDir  = path.Join(tmp, "target")
120
+		outsideDir = path.Join(tmp, "outside")
121
+
122
+		outsidePath     = path.Join(outsideDir, "file.txt")
123
+		sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
124
+	)
125
+
126
+	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
127
+		t.Fatal(err)
128
+	}
129
+	if err := os.Mkdir(targetDir, 0777); err != nil {
130
+		t.Fatal(err)
131
+	}
132
+	if err := os.Mkdir(outsideDir, 0777); err != nil {
133
+		t.Fatal(err)
134
+	}
135
+
136
+	if err := createFile(outsidePath); err != nil {
137
+		t.Fatal(err)
138
+	}
139
+
140
+	// mount the source as shared
141
+	if err := MakeShared(sourceDir); err != nil {
142
+		t.Fatal(err)
143
+	}
144
+	defer func() {
145
+		if err := Unmount(sourceDir); err != nil {
146
+			t.Fatal(err)
147
+		}
148
+	}()
149
+
150
+	// mount the shared directory to a target
151
+	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
152
+		t.Fatal(err)
153
+	}
154
+	defer func() {
155
+		if err := Unmount(targetDir); err != nil {
156
+			t.Fatal(err)
157
+		}
158
+	}()
159
+
160
+	// mount in an outside path to a mounted path inside the target
161
+	if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
162
+		t.Fatal(err)
163
+	}
164
+	defer func() {
165
+		if err := Unmount(path.Join(targetDir, "a")); err != nil {
166
+			t.Fatal(err)
167
+		}
168
+	}()
169
+
170
+	// NOW, check that the file from the outside directory is avaible in the source directory
171
+	if _, err := os.Stat(sourceCheckPath); err != nil {
172
+		t.Fatal(err)
173
+	}
174
+}
175
+
176
+// testing that mounts to a shared source show up in the slave target,
177
+// and that mounts into a slave target do _not_ show up in the shared source
178
+func TestSubtreeSharedSlave(t *testing.T) {
179
+	tmp := path.Join(os.TempDir(), "mount-tests")
180
+	if err := os.MkdirAll(tmp, 0777); err != nil {
181
+		t.Fatal(err)
182
+	}
183
+	defer os.RemoveAll(tmp)
184
+
185
+	var (
186
+		sourceDir   = path.Join(tmp, "source")
187
+		targetDir   = path.Join(tmp, "target")
188
+		outside1Dir = path.Join(tmp, "outside1")
189
+		outside2Dir = path.Join(tmp, "outside2")
190
+
191
+		outside1Path      = path.Join(outside1Dir, "file.txt")
192
+		outside2Path      = path.Join(outside2Dir, "file.txt")
193
+		outside1CheckPath = path.Join(targetDir, "a", "file.txt")
194
+		outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
195
+	)
196
+	if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
197
+		t.Fatal(err)
198
+	}
199
+	if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
200
+		t.Fatal(err)
201
+	}
202
+	if err := os.Mkdir(targetDir, 0777); err != nil {
203
+		t.Fatal(err)
204
+	}
205
+	if err := os.Mkdir(outside1Dir, 0777); err != nil {
206
+		t.Fatal(err)
207
+	}
208
+	if err := os.Mkdir(outside2Dir, 0777); err != nil {
209
+		t.Fatal(err)
210
+	}
211
+
212
+	if err := createFile(outside1Path); err != nil {
213
+		t.Fatal(err)
214
+	}
215
+	if err := createFile(outside2Path); err != nil {
216
+		t.Fatal(err)
217
+	}
218
+
219
+	// mount the source as shared
220
+	if err := MakeShared(sourceDir); err != nil {
221
+		t.Fatal(err)
222
+	}
223
+	defer func() {
224
+		if err := Unmount(sourceDir); err != nil {
225
+			t.Fatal(err)
226
+		}
227
+	}()
228
+
229
+	// mount the shared directory to a target
230
+	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
231
+		t.Fatal(err)
232
+	}
233
+	defer func() {
234
+		if err := Unmount(targetDir); err != nil {
235
+			t.Fatal(err)
236
+		}
237
+	}()
238
+
239
+	// next, make the target slave
240
+	if err := MakeSlave(targetDir); err != nil {
241
+		t.Fatal(err)
242
+	}
243
+	defer func() {
244
+		if err := Unmount(targetDir); err != nil {
245
+			t.Fatal(err)
246
+		}
247
+	}()
248
+
249
+	// mount in an outside path to a mounted path inside the _source_
250
+	if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
251
+		t.Fatal(err)
252
+	}
253
+	defer func() {
254
+		if err := Unmount(path.Join(sourceDir, "a")); err != nil {
255
+			t.Fatal(err)
256
+		}
257
+	}()
258
+
259
+	// check that this file _does_ show in the _target_
260
+	if _, err := os.Stat(outside1CheckPath); err != nil {
261
+		t.Fatal(err)
262
+	}
263
+
264
+	// next mount outside2Dir into the _target_
265
+	if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
266
+		t.Fatal(err)
267
+	}
268
+	defer func() {
269
+		if err := Unmount(path.Join(targetDir, "b")); err != nil {
270
+			t.Fatal(err)
271
+		}
272
+	}()
273
+
274
+	// check that this file _does_not_ show in the _source_
275
+	if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
276
+		t.Fatal(err)
277
+	} else if err == nil {
278
+		t.Fatalf("%q should not be visible, but is", outside2CheckPath)
279
+	}
280
+}
281
+
282
+func TestSubtreeUnbindable(t *testing.T) {
283
+	tmp := path.Join(os.TempDir(), "mount-tests")
284
+	if err := os.MkdirAll(tmp, 0777); err != nil {
285
+		t.Fatal(err)
286
+	}
287
+	defer os.RemoveAll(tmp)
288
+
289
+	var (
290
+		sourceDir = path.Join(tmp, "source")
291
+		targetDir = path.Join(tmp, "target")
292
+	)
293
+	if err := os.MkdirAll(sourceDir, 0777); err != nil {
294
+		t.Fatal(err)
295
+	}
296
+	if err := os.MkdirAll(targetDir, 0777); err != nil {
297
+		t.Fatal(err)
298
+	}
299
+
300
+	// next, make the source unbindable
301
+	if err := MakeUnbindable(sourceDir); err != nil {
302
+		t.Fatal(err)
303
+	}
304
+	defer func() {
305
+		if err := Unmount(sourceDir); err != nil {
306
+			t.Fatal(err)
307
+		}
308
+	}()
309
+
310
+	// then attempt to mount it to target. It should fail
311
+	if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && err != syscall.EINVAL {
312
+		t.Fatal(err)
313
+	} else if err == nil {
314
+		t.Fatalf("%q should not have been bindable")
315
+	}
316
+	defer func() {
317
+		if err := Unmount(targetDir); err != nil {
318
+			t.Fatal(err)
319
+		}
320
+	}()
321
+}
322
+
323
+func createFile(path string) error {
324
+	f, err := os.Create(path)
325
+	if err != nil {
326
+		return err
327
+	}
328
+	f.WriteString("hello world!")
329
+	return f.Close()
330
+}