Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.

Commit 0cc1a6f

Browse files
authored
Merge pull request #1975 from darfux/remove_bind_dest_when_umount
vc: Remove bind destination when unmounting
2 parents 5ff0ef9 + 7c4e479 commit 0cc1a6f

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

virtcontainers/container.go

+15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/kata-containers/runtime/virtcontainers/utils"
2525
specs "github.com/opencontainers/runtime-spec/specs-go"
2626
opentracing "github.com/opentracing/opentracing-go"
27+
"github.com/pkg/errors"
2728
"github.com/sirupsen/logrus"
2829
"golang.org/x/sys/unix"
2930

@@ -628,6 +629,20 @@ func (c *Container) unmountHostMounts() error {
628629
return err
629630
}
630631

632+
if m.Type == "bind" {
633+
s, err := os.Stat(m.HostPath)
634+
if err != nil {
635+
return errors.Wrapf(err, "Could not stat host-path %v", m.HostPath)
636+
}
637+
// Remove the empty file or directory
638+
if s.Mode().IsRegular() && s.Size() == 0 {
639+
os.Remove(m.HostPath)
640+
}
641+
if s.Mode().IsDir() {
642+
syscall.Rmdir(m.HostPath)
643+
}
644+
}
645+
631646
span.Finish()
632647
}
633648
}

virtcontainers/container_test.go

+114
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,120 @@ func TestContainerRemoveDrive(t *testing.T) {
133133
assert.Nil(t, err, "remove drive should succeed")
134134
}
135135

136+
func TestUnmountHostMountsRemoveBindHostPath(t *testing.T) {
137+
if tc.NotValid(ktu.NeedRoot()) {
138+
t.Skip(testDisabledAsNonRoot)
139+
}
140+
141+
createFakeMountDir := func(t *testing.T, dir, prefix string) string {
142+
name, err := ioutil.TempDir(dir, "test-mnt-"+prefix+"-")
143+
if err != nil {
144+
t.Fatal(err)
145+
}
146+
return name
147+
}
148+
149+
createFakeMountFile := func(t *testing.T, dir, prefix string) string {
150+
f, err := ioutil.TempFile(dir, "test-mnt-"+prefix+"-")
151+
if err != nil {
152+
t.Fatal(err)
153+
}
154+
f.Close()
155+
return f.Name()
156+
}
157+
158+
doUnmountCheck := func(src, dest, hostPath, nonEmptyHostpath, devPath string) {
159+
mounts := []Mount{
160+
{
161+
Source: src,
162+
Destination: dest,
163+
HostPath: hostPath,
164+
Type: "bind",
165+
},
166+
{
167+
Source: src,
168+
Destination: dest,
169+
HostPath: nonEmptyHostpath,
170+
Type: "bind",
171+
},
172+
{
173+
Source: src,
174+
Destination: dest,
175+
HostPath: devPath,
176+
Type: "dev",
177+
},
178+
}
179+
180+
c := Container{
181+
mounts: mounts,
182+
ctx: context.Background(),
183+
}
184+
185+
if err := bindMount(c.ctx, src, hostPath, false); err != nil {
186+
t.Fatal(err)
187+
}
188+
defer syscall.Unmount(hostPath, 0)
189+
if err := bindMount(c.ctx, src, nonEmptyHostpath, false); err != nil {
190+
t.Fatal(err)
191+
}
192+
defer syscall.Unmount(nonEmptyHostpath, 0)
193+
if err := bindMount(c.ctx, src, devPath, false); err != nil {
194+
t.Fatal(err)
195+
}
196+
defer syscall.Unmount(devPath, 0)
197+
198+
err := c.unmountHostMounts()
199+
if err != nil {
200+
t.Fatal(err)
201+
}
202+
203+
for _, path := range [3]string{src, dest, devPath} {
204+
if _, err := os.Stat(path); err != nil {
205+
if os.IsNotExist(err) {
206+
t.Fatalf("path %s should not be removed", path)
207+
} else {
208+
t.Fatal(err)
209+
}
210+
}
211+
}
212+
213+
if _, err := os.Stat(hostPath); err == nil {
214+
t.Fatal("empty host-path should be removed")
215+
} else if !os.IsNotExist(err) {
216+
t.Fatal(err)
217+
}
218+
219+
if _, err := os.Stat(nonEmptyHostpath); err != nil {
220+
if os.IsNotExist(err) {
221+
t.Fatal("non-empty host-path should not be removed")
222+
} else {
223+
t.Fatal(err)
224+
}
225+
}
226+
}
227+
228+
src := createFakeMountDir(t, testDir, "src")
229+
dest := createFakeMountDir(t, testDir, "dest")
230+
hostPath := createFakeMountDir(t, testDir, "host-path")
231+
nonEmptyHostpath := createFakeMountDir(t, testDir, "non-empty-host-path")
232+
devPath := createFakeMountDir(t, testDir, "dev-hostpath")
233+
createFakeMountDir(t, nonEmptyHostpath, "nop")
234+
doUnmountCheck(src, dest, hostPath, nonEmptyHostpath, devPath)
235+
236+
src = createFakeMountFile(t, testDir, "src")
237+
dest = createFakeMountFile(t, testDir, "dest")
238+
hostPath = createFakeMountFile(t, testDir, "host-path")
239+
nonEmptyHostpath = createFakeMountFile(t, testDir, "non-empty-host-path")
240+
devPath = createFakeMountFile(t, testDir, "dev-host-path")
241+
f, err := os.OpenFile(nonEmptyHostpath, os.O_WRONLY, os.FileMode(0640))
242+
if err != nil {
243+
t.Fatal(err)
244+
}
245+
f.WriteString("nop\n")
246+
f.Close()
247+
doUnmountCheck(src, dest, hostPath, nonEmptyHostpath, devPath)
248+
}
249+
136250
func testSetupFakeRootfs(t *testing.T) (testRawFile, loopDev, mntDir string, err error) {
137251
assert := assert.New(t)
138252
if tc.NotValid(ktu.NeedRoot()) {

0 commit comments

Comments
 (0)