Skip to content

Commit

Permalink
Add virtfs/9p mounts, instead of sshocker/sshfs
Browse files Browse the repository at this point in the history
This PR allows selecting mount type, as "9p"

The default mount type is still as before, "sshfs"

Add mount option variable, for "rw" vs "ro"

Add mount type, for "sshfs" (fuse) vs "9p"

Signed-off-by: Anders F Björklund <anders.f.bjorklund@gmail.com>
  • Loading branch information
afbjorklund committed Mar 13, 2022
1 parent 8ac35c1 commit f04a0c5
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 24 deletions.
2 changes: 2 additions & 0 deletions docs/internal.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ The volume label is "cidata", as defined by [cloud-init NoCloud](https://cloudin
- `LIMA_CIDATA_UID`: the numeric UID
- `LIMA_CIDATA_MOUNTS`: the number of the Lima mounts
- `LIMA_CIDATA_MOUNTS_%d_MOUNTPOINT`: the N-th mount point of Lima mounts (N=0, 1, ...)
- `LIMA_CIDATA_MOUNTS_%d_MOUNTOPTION`: the N-th mount option of Lima mounts (N=0, 1, ...)
- `LIMA_CIDATA_MOUNTTYPE`: the type of the Lima mounts ("sshfs", "9p", ...)
- `LIMA_CIDATA_CONTAINERD_USER`: set to "1" if rootless containerd to be set up
- `LIMA_CIDATA_CONTAINERD_SYSTEM`: set to "1" if system-wide containerd to be set up
- `LIMA_CIDATA_SLIRP_GATEWAY`: set to the IP address of the host on the SLIRP network. `192.168.5.2`.
Expand Down
4 changes: 4 additions & 0 deletions examples/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ mounts:
# 🔵 This file: true (only for "/tmp/lima")
writable: true

# Mount type for above mounts, such as "sshfs" (from sshocker) or "9p" (from virtfs)
# 🟢 Builtin default: ""
mountType: null

ssh:
# A localhost port of the host. Forwarded to port 22 of the guest.
# 🟢 Builtin default: 0 (automatically assigned to a free port)
Expand Down
7 changes: 7 additions & 0 deletions pkg/cidata/cidata.TEMPLATE.d/boot/25-guestagent-base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ for f in $(seq 0 $((LIMA_CIDATA_MOUNTS - 1))); do
mkdir -p "${mountpoint}"
gid=$(id -g "${LIMA_CIDATA_USER}")
chown "${LIMA_CIDATA_UID}:${gid}" "${mountpoint}"

mountpointopt="LIMA_CIDATA_MOUNTS_${f}_MOUNTOPTION"
option="$(eval echo \$"$mountpointopt")"
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "9p" ]; then
tag="mount${f}"
mount -t 9p -o trans=virtio "${tag}" "${mountpoint}" -o version=9p2000.L,msize=131072 -o "${option}"
fi
done

# Install or update the guestagent binary
Expand Down
34 changes: 23 additions & 11 deletions pkg/cidata/cidata.TEMPLATE.d/boot/30-install-packages.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ fi
# Install minimum dependencies
if command -v apt-get >/dev/null 2>&1; then
pkgs=""
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "sshfs" ]; then
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
fi
fi
if [ "${INSTALL_IPTABLES}" = 1 ] && [ ! -e /usr/sbin/iptables ]; then
pkgs="${pkgs} iptables"
Expand All @@ -42,8 +44,10 @@ elif command -v dnf >/dev/null 2>&1; then
if ! command -v tar >/dev/null 2>&1; then
pkgs="${pkgs} tar"
fi
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} fuse-sshfs"
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "sshfs" ]; then
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} fuse-sshfs"
fi
fi
if [ "${INSTALL_IPTABLES}" = 1 ] && [ ! -e /usr/sbin/iptables ]; then
pkgs="${pkgs} iptables"
Expand Down Expand Up @@ -73,8 +77,10 @@ elif command -v dnf >/dev/null 2>&1; then
fi
elif command -v pacman >/dev/null 2>&1; then
pkgs=""
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "sshfs" ]; then
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
fi
fi
# other dependencies are preinstalled on Arch Linux
if [ -n "${pkgs}" ]; then
Expand All @@ -83,8 +89,10 @@ elif command -v pacman >/dev/null 2>&1; then
fi
elif command -v zypper >/dev/null 2>&1; then
pkgs=""
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "sshfs" ]; then
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
fi
fi
if [ "${INSTALL_IPTABLES}" = 1 ] && [ ! -e /usr/sbin/iptables ]; then
pkgs="${pkgs} iptables"
Expand All @@ -98,8 +106,10 @@ elif command -v zypper >/dev/null 2>&1; then
fi
elif command -v apk >/dev/null 2>&1; then
pkgs=""
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "sshfs" ]; then
if [ "${LIMA_CIDATA_MOUNTS}" -gt 0 ] && ! command -v sshfs >/dev/null 2>&1; then
pkgs="${pkgs} sshfs"
fi
fi
if [ "${INSTALL_IPTABLES}" = 1 ] && ! command -v iptables >/dev/null 2>&1; then
pkgs="${pkgs} iptables"
Expand All @@ -125,4 +135,6 @@ fi

# update_fuse_conf has to be called after installing all the packages,
# otherwise apt-get fails with conflict
update_fuse_conf
if [ "${LIMA_CIDATA_MOUNTTYPE}" = "sshfs" ]; then
update_fuse_conf
fi
4 changes: 4 additions & 0 deletions pkg/cidata/cidata.TEMPLATE.d/lima.env
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ LIMA_CIDATA_MOUNTS={{ len .Mounts }}
{{- range $i, $val := .Mounts}}
LIMA_CIDATA_MOUNTS_{{$i}}_MOUNTPOINT={{$val}}
{{- end}}
{{- range $i, $opt := .MountOptions}}
LIMA_CIDATA_MOUNTS_{{$i}}_MOUNTOPTION={{$opt}}
{{- end}}
LIMA_CIDATA_MOUNTTYPE={{ .MountType }}
{{- if .Containerd.User}}
LIMA_CIDATA_CONTAINERD_USER=1
{{- else}}
Expand Down
7 changes: 7 additions & 0 deletions pkg/cidata/cidata.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,15 @@ func GenerateISO9660(instDir, name string, y *limayaml.LimaYAML, udpDNSLocalPort
return err
}
args.Mounts = append(args.Mounts, expanded)
option := "ro"
if *f.Writable {
option = "rw"
}
args.MountOptions = append(args.MountOptions, option)
}

args.MountType = y.MountType

slirpMACAddress := limayaml.MACAddress(instDir)
args.Networks = append(args.Networks, Network{MACAddress: slirpMACAddress, Interface: qemu.SlirpNICName})
for _, nw := range y.Networks {
Expand Down
10 changes: 10 additions & 0 deletions pkg/cidata/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ type TemplateArgs struct {
UID int
SSHPubKeys []string
Mounts []string // abs path, accessible by the User
MountOptions []string // mount option, usually "rw" or "ro"
MountType string
Containerd Containerd
Networks []Network
SlirpNICName string
Expand Down Expand Up @@ -67,6 +69,14 @@ func ValidateTemplateArgs(args TemplateArgs) error {
return fmt.Errorf("field mounts[%d] must be absolute, got %q", i, f)
}
}
for i, o := range args.MountOptions {
if o != "ro" && o != "rw" {
return fmt.Errorf("field options[%d] is not rw or ro, got %q", i, o)
}
}
if args.MountType != "sshfs" && args.MountType != "9p" {
return fmt.Errorf("field MountType is not sshfs or 9p, got %q", args.MountType)
}
return nil
}

Expand Down
1 change: 1 addition & 0 deletions pkg/cidata/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ func TestTemplate(t *testing.T) {
"/Users/dummy",
"/Users/dummy/lima",
},
MountType: "sshfs",
}
layout, err := ExecuteTemplate(args)
assert.NilError(t, err)
Expand Down
29 changes: 17 additions & 12 deletions pkg/hostagent/hostagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,19 +378,24 @@ func (a *HostAgent) startHostAgentRoutines(ctx context.Context) error {
if err := a.waitForRequirements(ctx, "essential", a.essentialRequirements()); err != nil {
mErr = multierror.Append(mErr, err)
}
mounts, err := a.setupMounts(ctx)
if err != nil {
mErr = multierror.Append(mErr, err)
}
a.onClose = append(a.onClose, func() error {
var unmountMErr error
for _, m := range mounts {
if unmountErr := m.close(); unmountErr != nil {
unmountMErr = multierror.Append(unmountMErr, unmountErr)
}

if a.y.MountType == "sshfs" {
// Set up **host** mounts, if any
mounts, err := a.setupMounts(ctx)
if err != nil {
mErr = multierror.Append(mErr, err)
}
return unmountMErr
})
a.onClose = append(a.onClose, func() error {
var unmountMErr error
for _, m := range mounts {
if unmountErr := m.close(); unmountErr != nil {
unmountMErr = multierror.Append(unmountMErr, unmountErr)
}
}
return unmountMErr
})
}

go a.watchGuestAgentEvents(ctx)
if err := a.waitForRequirements(ctx, "optional", a.optionalRequirements()); err != nil {
mErr = multierror.Append(mErr, err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/hostagent/requirements.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ it must not be created until the session reset is done.
`,
})

if len(a.y.Mounts) > 0 {
if a.y.MountType == "sshfs" && len(a.y.Mounts) > 0 {
req = append(req, requirement{
description: "sshfs binary to be installed",
script: `#!/bin/bash
Expand Down
4 changes: 4 additions & 0 deletions pkg/limayaml/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
}
}

if y.MountType == "" {
y.MountType = "sshfs"
}

// Note: DNS lists are not combined; highest priority setting is picked
if len(y.DNS) == 0 {
y.DNS = d.DNS
Expand Down
6 changes: 6 additions & 0 deletions pkg/limayaml/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func TestFillDefault(t *testing.T) {
Mounts: []Mount{
{Location: "/tmp"},
},
MountType: "9p",
Provision: []Provision{
{Script: "#!/bin/true"},
},
Expand Down Expand Up @@ -138,6 +139,8 @@ func TestFillDefault(t *testing.T) {
expect.Mounts[0].SSHFS.FollowSymlinks = pointer.Bool(false)
// Only missing Mounts field is Writable, and the default value is also the null value: false

expect.MountType = "9p"

expect.Provision = y.Provision
expect.Provision[0].Mode = ProvisionModeSystem

Expand Down Expand Up @@ -270,6 +273,7 @@ func TestFillDefault(t *testing.T) {
expect.HostResolver.Hosts = map[string]string{
"default.": d.HostResolver.Hosts["default"],
}
expect.MountType = "sshfs"

y = LimaYAML{}
FillDefault(&y, &d, &LimaYAML{}, filePath)
Expand Down Expand Up @@ -415,6 +419,8 @@ func TestFillDefault(t *testing.T) {
expect.Mounts[0].SSHFS.Cache = pointer.Bool(false)
expect.Mounts[0].SSHFS.FollowSymlinks = pointer.Bool(true)

expect.MountType = "9p"

// o.Networks[1] is overriding the d.Networks[0].Lima entry for the "def0" interface
expect.Networks = append(append(d.Networks, y.Networks...), o.Networks[0])
expect.Networks[0].Lima = o.Networks[1].Lima
Expand Down
1 change: 1 addition & 0 deletions pkg/limayaml/limayaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type LimaYAML struct {
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes
Disk *string `yaml:"disk,omitempty" json:"disk,omitempty"` // go-units.RAMInBytes
Mounts []Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
MountType string `yaml:"mountType,omitempty" json:"mountType,omitempty"`
SSH SSH `yaml:"ssh,omitempty" json:"ssh,omitempty"` // REQUIRED (FIXME)
Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"`
Video Video `yaml:"video,omitempty" json:"video,omitempty"`
Expand Down
12 changes: 12 additions & 0 deletions pkg/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/lima-vm/lima/pkg/downloader"
"github.com/lima-vm/lima/pkg/iso9660util"
"github.com/lima-vm/lima/pkg/limayaml"
"github.com/lima-vm/lima/pkg/localpathutil"
"github.com/lima-vm/lima/pkg/networks"
qemu "github.com/lima-vm/lima/pkg/qemu/const"
"github.com/lima-vm/lima/pkg/qemu/imgutil"
Expand Down Expand Up @@ -372,6 +373,17 @@ func Cmdline(cfg Config) (string, []string, error) {

// We also want to enable vsock and virtfs here, but QEMU does not support vsock and virtfs for macOS hosts

if y.MountType == "9p" {
for i, f := range y.Mounts {
expanded, err := localpathutil.Expand(f.Location)
if err != nil {
return "", nil, err
}
tag := fmt.Sprintf("mount%d", i)
args = append(args, "-virtfs", fmt.Sprintf("local,path=%s,mount_tag=%s,security_model=mapped-xattr", expanded, tag))
}
}

// QMP
qmpSock := filepath.Join(cfg.InstanceDir, filenames.QMPSock)
if err := os.RemoveAll(qmpSock); err != nil {
Expand Down

0 comments on commit f04a0c5

Please sign in to comment.