Skip to content

Commit

Permalink
Add virtfs/9p mounts, instead of sshocker/sshfs
Browse files Browse the repository at this point in the history
Add mount option variable, for "rw" vs "ro"

Add mount type, for "sshfs" (fuse) vs "9p"
  • Loading branch information
afbjorklund committed Mar 13, 2022
1 parent 8ac35c1 commit 9ee911b
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 9ee911b

Please sign in to comment.