Skip to content

Commit 950421d

Browse files
authored
Merge pull request #3985 from tstromberg/mount-intr
More reliable unmount w/ SIGINT, particularly on kvm2
2 parents ca51bad + 807963a commit 950421d

File tree

3 files changed

+60
-24
lines changed

3 files changed

+60
-24
lines changed

cmd/minikube/cmd/mount.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ var mountCmd = &cobra.Command{
9898
}
9999
defer api.Close()
100100
host, err := api.Load(config.GetMachineName())
101+
101102
if err != nil {
102103
exit.WithError("Error loading api", err)
103104
}
@@ -163,22 +164,32 @@ var mountCmd = &cobra.Command{
163164
go func() {
164165
console.OutStyle("fileserver", "Userspace file server: ")
165166
ufs.StartServer(net.JoinHostPort(ip.String(), strconv.Itoa(port)), debugVal, hostPath)
167+
console.OutStyle("stopped", "Userspace file server is shutdown")
166168
wg.Done()
167169
}()
168170
}
169171

172+
// Use CommandRunner, as the native docker ssh service dies when Ctrl-C is received.
173+
runner, err := machine.CommandRunner(host)
174+
if err != nil {
175+
exit.WithError("Failed to get command runner", err)
176+
}
177+
170178
// Unmount if Ctrl-C or kill request is received.
171179
c := make(chan os.Signal, 1)
172180
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
173181
go func() {
174182
for sig := range c {
175183
console.OutStyle("unmount", "Unmounting %s ...", vmPath)
176-
cluster.Unmount(host, vmPath)
184+
err := cluster.Unmount(runner, vmPath)
185+
if err != nil {
186+
console.ErrStyle("failure", "Failed unmount: %v", err)
187+
}
177188
exit.WithCode(exit.Interrupted, "Exiting due to %s signal", sig)
178189
}
179190
}()
180191

181-
err = cluster.Mount(host, ip.String(), vmPath, cfg)
192+
err = cluster.Mount(runner, ip.String(), vmPath, cfg)
182193
if err != nil {
183194
exit.WithError("mount failed", err)
184195
}

pkg/minikube/cluster/mount.go

+33-8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strconv"
2424
"strings"
2525

26+
"github.com/golang/glog"
2627
"github.com/pkg/errors"
2728
)
2829

@@ -46,19 +47,21 @@ type MountConfig struct {
4647
Options map[string]string
4748
}
4849

49-
// hostRunner is the subset of host.Host used for mounting
50-
type hostRunner interface {
51-
RunSSHCommand(cmd string) (string, error)
50+
// mountRunner is the subset of CommandRunner used for mounting
51+
type mountRunner interface {
52+
CombinedOutput(string) (string, error)
5253
}
5354

5455
// Mount runs the mount command from the 9p client on the VM to the 9p server on the host
55-
func Mount(h hostRunner, source string, target string, c *MountConfig) error {
56-
if err := Unmount(h, target); err != nil {
56+
func Mount(r mountRunner, source string, target string, c *MountConfig) error {
57+
if err := Unmount(r, target); err != nil {
5758
return errors.Wrap(err, "umount")
5859
}
5960

6061
cmd := fmt.Sprintf("sudo mkdir -m %o -p %s && %s", c.Mode, target, mntCmd(source, target, c))
61-
out, err := h.RunSSHCommand(cmd)
62+
glog.Infof("Will run: %s", cmd)
63+
out, err := r.CombinedOutput(cmd)
64+
glog.Infof("mount err=%s, out=%s", err, out)
6265
if err != nil {
6366
return errors.Wrap(err, out)
6467
}
@@ -127,9 +130,31 @@ func mntCmd(source string, target string, c *MountConfig) string {
127130
return fmt.Sprintf("sudo mount -t %s -o %s %s %s", c.Type, strings.Join(opts, ","), source, target)
128131
}
129132

133+
// umountCmd returns a command for unmounting
134+
func umountCmd(target string, force bool) string {
135+
flag := ""
136+
if force {
137+
flag = "-f "
138+
}
139+
// grep because findmnt will also display the parent!
140+
return fmt.Sprintf("findmnt -T %s | grep %s && sudo umount %s%s || true", target, target, flag, target)
141+
}
142+
130143
// Unmount unmounts a path
131-
func Unmount(h hostRunner, target string) error {
132-
out, err := h.RunSSHCommand(fmt.Sprintf("findmnt -T %s && sudo umount %s || true", target, target))
144+
func Unmount(r mountRunner, target string) error {
145+
cmd := umountCmd(target, false)
146+
glog.Infof("Will run: %s", cmd)
147+
out, err := r.CombinedOutput(cmd)
148+
if err == nil {
149+
return nil
150+
}
151+
glog.Warningf("initial unmount error: %v, out: %s", err, out)
152+
153+
// Try again, using force if needed.
154+
cmd = umountCmd(target, true)
155+
glog.Infof("Will run: %s", cmd)
156+
out, err = r.CombinedOutput(cmd)
157+
glog.Infof("unmount force err=%v, out=%s", err, out)
133158
if err != nil {
134159
return errors.Wrap(err, out)
135160
}

pkg/minikube/cluster/mount_test.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ import (
2323
"github.com/google/go-cmp/cmp"
2424
)
2525

26-
type mockMountHost struct {
26+
type mockMountRunner struct {
2727
cmds []string
2828
T *testing.T
2929
}
3030

31-
func newMockMountHost(t *testing.T) *mockMountHost {
32-
return &mockMountHost{
31+
func newMockMountRunner(t *testing.T) *mockMountRunner {
32+
return &mockMountRunner{
3333
T: t,
3434
cmds: []string{},
3535
}
3636
}
3737

38-
func (m *mockMountHost) RunSSHCommand(cmd string) (string, error) {
38+
func (m *mockMountRunner) CombinedOutput(cmd string) (string, error) {
3939
m.cmds = append(m.cmds, cmd)
4040
return "", nil
4141
}
@@ -54,7 +54,7 @@ func TestMount(t *testing.T) {
5454
target: "target",
5555
cfg: &MountConfig{Type: "9p", Mode: os.FileMode(0700)},
5656
want: []string{
57-
"findmnt -T target && sudo umount target || true",
57+
"findmnt -T target | grep target && sudo umount target || true",
5858
"sudo mkdir -m 700 -p target && sudo mount -t 9p -o dfltgid=0,dfltuid=0 src target",
5959
},
6060
},
@@ -77,7 +77,7 @@ func TestMount(t *testing.T) {
7777
"cache": "fscache",
7878
}},
7979
want: []string{
80-
"findmnt -T /target && sudo umount /target || true",
80+
"findmnt -T /target | grep /target && sudo umount /target || true",
8181
"sudo mkdir -m 777 -p /target && sudo mount -t 9p -o cache=fscache,dfltgid=72,dfltuid=82,noextend,version=9p2000.u 10.0.0.1 /target",
8282
},
8383
},
@@ -89,34 +89,34 @@ func TestMount(t *testing.T) {
8989
"version": "9p2000.L",
9090
}},
9191
want: []string{
92-
"findmnt -T tgt && sudo umount tgt || true",
92+
"findmnt -T tgt | grep tgt && sudo umount tgt || true",
9393
"sudo mkdir -m 700 -p tgt && sudo mount -t 9p -o dfltgid=0,dfltuid=0,version=9p2000.L src tgt",
9494
},
9595
},
9696
}
9797
for _, tc := range tests {
9898
t.Run(tc.name, func(t *testing.T) {
99-
h := newMockMountHost(t)
100-
err := Mount(h, tc.source, tc.target, tc.cfg)
99+
r := newMockMountRunner(t)
100+
err := Mount(r, tc.source, tc.target, tc.cfg)
101101
if err != nil {
102102
t.Fatalf("Mount(%s, %s, %+v): %v", tc.source, tc.target, tc.cfg, err)
103103
}
104-
if diff := cmp.Diff(h.cmds, tc.want); diff != "" {
104+
if diff := cmp.Diff(r.cmds, tc.want); diff != "" {
105105
t.Errorf("command diff (-want +got): %s", diff)
106106
}
107107
})
108108
}
109109
}
110110

111111
func TestUnmount(t *testing.T) {
112-
h := newMockMountHost(t)
113-
err := Unmount(h, "/mnt")
112+
r := newMockMountRunner(t)
113+
err := Unmount(r, "/mnt")
114114
if err != nil {
115115
t.Fatalf("Unmount(/mnt): %v", err)
116116
}
117117

118-
want := []string{"findmnt -T /mnt && sudo umount /mnt || true"}
119-
if diff := cmp.Diff(h.cmds, want); diff != "" {
118+
want := []string{"findmnt -T /mnt | grep /mnt && sudo umount /mnt || true"}
119+
if diff := cmp.Diff(r.cmds, want); diff != "" {
120120
t.Errorf("command diff (-want +got): %s", diff)
121121
}
122122
}

0 commit comments

Comments
 (0)