Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/hostagent/mount.go
2611 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package hostagent
5
6
import (
7
"context"
8
"errors"
9
"fmt"
10
"os"
11
"runtime"
12
13
"github.com/lima-vm/sshocker/pkg/reversesshfs"
14
"github.com/sirupsen/logrus"
15
16
"github.com/lima-vm/lima/v2/pkg/ioutilx"
17
"github.com/lima-vm/lima/v2/pkg/limatype"
18
"github.com/lima-vm/lima/v2/pkg/sshutil"
19
)
20
21
type mount struct {
22
close func() error
23
}
24
25
func (a *HostAgent) setupMounts(ctx context.Context) ([]*mount, error) {
26
var (
27
res []*mount
28
errs []error
29
)
30
for _, f := range a.instConfig.Mounts {
31
m, err := a.setupMount(ctx, f)
32
if err != nil {
33
errs = append(errs, err)
34
continue
35
}
36
res = append(res, m)
37
}
38
return res, errors.Join(errs...)
39
}
40
41
func (a *HostAgent) setupMount(ctx context.Context, m limatype.Mount) (*mount, error) {
42
if err := os.MkdirAll(m.Location, 0o755); err != nil {
43
return nil, err
44
}
45
// NOTE: allow_other requires "user_allow_other" in /etc/fuse.conf
46
sshfsOptions := "allow_other"
47
if !*m.SSHFS.Cache {
48
sshfsOptions += ",cache=no"
49
}
50
if *m.SSHFS.FollowSymlinks {
51
sshfsOptions += ",follow_symlinks"
52
}
53
logrus.Infof("Mounting %q on %q", m.Location, *m.MountPoint)
54
55
resolvedLocation := m.Location
56
if runtime.GOOS == "windows" {
57
var err error
58
resolvedLocation, err = ioutilx.WindowsSubsystemPath(ctx, m.Location)
59
if err != nil {
60
return nil, err
61
}
62
}
63
64
sshAddress, sshPort := a.sshAddressPort()
65
// Create a copy of sshConfig to avoid
66
// modifying HostAgent's sshConfig in case of Windows
67
sshConfig := *a.sshConfig
68
rsf := &reversesshfs.ReverseSSHFS{
69
Driver: *m.SSHFS.SFTPDriver,
70
SSHConfig: &sshConfig,
71
LocalPath: resolvedLocation,
72
Host: sshAddress,
73
Port: sshPort,
74
RemotePath: *m.MountPoint,
75
Readonly: !(*m.Writable),
76
SSHFSAdditionalArgs: []string{"-o", sshfsOptions},
77
}
78
if runtime.GOOS == "windows" {
79
// cygwin/msys2 doesn't support full feature set over mux socket, this has at least 2 side effects:
80
// 1. unnecessary pollutes output with error on errors encountered (ssh will try to tolerate them with fallbacks);
81
// 2. these errors still imply additional coms over mux socket, which resulted sftp-server to fail more often statistically during test runs.
82
// It is reasonable to disable this on Windows if required feature is not fully operational.
83
rsf.SSHConfig.Persist = false
84
85
// HostAgent's `sshConfig` already has some ControlMaster related args in `AdditionalArgs`,
86
// so it is necessary to remove them to avoid overrides above `Persist=false`.
87
rsf.SSHConfig.AdditionalArgs = sshutil.DisableControlMasterOptsFromSSHArgs(rsf.SSHConfig.AdditionalArgs)
88
}
89
if err := rsf.Prepare(); err != nil {
90
return nil, fmt.Errorf("failed to prepare reverse sshfs for %q on %q: %w", resolvedLocation, *m.MountPoint, err)
91
}
92
if err := rsf.Start(); err != nil {
93
logrus.WithError(err).Warnf("failed to mount reverse sshfs for %q on %q, retrying with `-o nonempty`", resolvedLocation, *m.MountPoint)
94
// NOTE: nonempty is not supported for libfuse3: https://github.com/canonical/multipass/issues/1381
95
rsf.SSHFSAdditionalArgs = []string{"-o", "nonempty"}
96
if err := rsf.Start(); err != nil {
97
return nil, fmt.Errorf("failed to mount reverse sshfs for %q on %q: %w", resolvedLocation, *m.MountPoint, err)
98
}
99
}
100
101
res := &mount{
102
close: func() error {
103
logrus.Infof("Unmounting %q", resolvedLocation)
104
if err := rsf.Close(); err != nil {
105
return fmt.Errorf("failed to unmount reverse sshfs for %q on %q: %w", resolvedLocation, *m.MountPoint, err)
106
}
107
return nil
108
},
109
}
110
return res, nil
111
}
112
113