Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qemu: use 9p by default #1953

Merged
merged 3 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,15 @@ jobs:
if: matrix.template == '../hack/test-templates/test-misc.yaml'
- name: "Show cache"
run: ./hack/debug-cache.sh
- name: "Adjust LIMACTL_CREATE_ARGS"
# Change the mount type from 9p to reverse-sshfs, as a workaround for:
#
# > level=fatal msg="failed to get unprivileged mount flags for \"/home/runner/lima-container-engine-test-tmp/random\": stat /home/runner/lima-container-engine-test-tmp/random: no such file or directory"
AkihiroSuda marked this conversation as resolved.
Show resolved Hide resolved
#
# The issue is not reproducible on a local MacBook.
# https://github.com/lima-vm/lima/issues/2701
run: echo "LIMACTL_CREATE_ARGS=${LIMACTL_CREATE_ARGS} --mount-type=reverse-sshfs" >>$GITHUB_ENV
if: matrix.template == 'archlinux.yaml'
- name: "Test"
uses: nick-fields/retry@v3
with:
Expand Down
1 change: 1 addition & 0 deletions examples/almalinux-8.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ images:
arch: "x86_64"
- location: "https://repo.almalinux.org/almalinux/8/cloud/aarch64/images/AlmaLinux-8-GenericCloud-latest.aarch64.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/almalinux-9.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ images:
arch: "x86_64"
- location: "https://repo.almalinux.org/almalinux/9/cloud/aarch64/images/AlmaLinux-9-GenericCloud-latest.aarch64.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/centos-stream-9.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ images:
arch: "x86_64"
- location: "https://cloud.centos.org/centos/9-stream/aarch64/images/CentOS-Stream-GenericCloud-9-latest.aarch64.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
2 changes: 1 addition & 1 deletion examples/debian-11.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ images:
arch: "x86_64"
- location: "https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2"
arch: "aarch64"

mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
2 changes: 1 addition & 1 deletion examples/debian-12.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ images:
arch: "x86_64"
- location: "https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-arm64.qcow2"
arch: "aarch64"

mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
12 changes: 8 additions & 4 deletions examples/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ mounts:
# Configure the mountPoint inside the guest.
# 🟢 Builtin default: value of location
mountPoint: null
# CAUTION: `writable` SHOULD be false for the home directory.
# Setting `writable` to true is possible, but untested and dangerous.
# Setting `writable` to true is discouraged when mountType is set to "reverse-sshfs".
AkihiroSuda marked this conversation as resolved.
Show resolved Hide resolved
# 🟢 Builtin default: false
writable: null
sshfs:
Expand Down Expand Up @@ -112,9 +111,14 @@ mounts:
# 🔵 This file: true (only for "/tmp/lima")
writable: true

# Mount type for above mounts, such as "reverse-sshfs" (from sshocker), "9p" (EXPERIMENTAL, from QEMU’s virtio-9p-pci, aka virtfs),
# List of mount types not supported by the kernel of this distro.
# Also used to resolve the default mount type when not explicitly specified.
# 🟢 Builtin default: null
mountTypesUnsupported: null

# Mount type for above mounts, such as "reverse-sshfs" (from sshocker), "9p" (EXPERIMENTAL until Lima v1.0, from QEMU’s virtio-9p-pci, aka virtfs),
AkihiroSuda marked this conversation as resolved.
Show resolved Hide resolved
# or "virtiofs" (EXPERIMENTAL, needs `vmType: vz`; will graduate from experimental in Lima v1.0)
# 🟢 Builtin default: "reverse-sshfs" (for QEMU), "virtiofs" (for vz)
# 🟢 Builtin default: "default" (resolved to be "9p" for QEMU since Lima v1.0, "virtiofs" for vz)
mountType: null

# Enable inotify support for mounted directories (EXPERIMENTAL)
Expand Down
8 changes: 8 additions & 0 deletions examples/experimental/9p.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# ⚠️ ⚠️ ⚠️ `template://experimental/9p` will be removed in Lima v1.0,
# as 9p will graduate from experimental and will be the default mount type for QEMU.
#
# For Lima v1.0 and later, use the following command instead:
# ```
# limactl create --vm-type=qemu template://default
# ```

# This template requires Lima v0.10.0 or later.
# On macOS hosts, QEMU needs to be v7.0.0 or later. Homebrew's QEMU v6.2.0_1 can be used too.
# This template is planned to be merged to default.yaml in Lima v1.0 (ETA: 2022 Q2).
Expand Down
1 change: 1 addition & 0 deletions examples/experimental/opensuse-tumbleweed.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ images:
arch: "x86_64"
- location: "https://download.opensuse.org/ports/aarch64/tumbleweed/appliances/openSUSE-Tumbleweed-Minimal-VM.aarch64-Cloud.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/opensuse-leap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ images:
arch: "x86_64"
- location: "https://download.opensuse.org/distribution/leap/15.6/appliances/openSUSE-Leap-15.6-Minimal-VM.aarch64-Cloud.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/oraclelinux-8.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ images:
- location: "https://yum.oracle.com/templates/OracleLinux/OL8/u10/aarch64/OL8U10_aarch64-kvm-cloud-b100.qcow2"
arch: "aarch64"
digest: "sha256:def7b8055e275507a593f07dc6076a2adc5967af046c003072b479e69f25f407"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/oraclelinux-9.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ images:
- location: "https://yum.oracle.com/templates/OracleLinux/OL9/u4/aarch64/OL9U4_aarch64-kvm-cloud-b90.qcow2"
arch: "aarch64"
digest: "sha256:1f4e20190e87c76e8c3b4a9e15e660972386cbfa4f128e5cdcd8faa43a713d44"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/rocky-8.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ images:
arch: "x86_64"
- location: "https://dl.rockylinux.org/pub/rocky/8/images/aarch64/Rocky-8-GenericCloud.latest.aarch64.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
1 change: 1 addition & 0 deletions examples/rocky-9.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ images:
arch: "x86_64"
- location: "https://dl.rockylinux.org/pub/rocky/9/images/aarch64/Rocky-9-GenericCloud.latest.aarch64.qcow2"
arch: "aarch64"
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
- location: "/tmp/lima"
Expand Down
3 changes: 3 additions & 0 deletions hack/test-templates/test-misc.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# The test template for testing misc configurations:
# - disk
# - snapshots
AkihiroSuda marked this conversation as resolved.
Show resolved Hide resolved
# - (More to come)
#
# This template requires Lima v1.0.0-alpha.0 or later.
Expand All @@ -18,6 +19,8 @@ images:
- location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-arm64.img"
arch: "aarch64"

# 9p is not compatible with `limactl snapshot`
mountTypesUnsupported: ["9p"]
mounts:
- location: "~"
writable: true
Expand Down
38 changes: 35 additions & 3 deletions pkg/limayaml/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/lima-vm/lima/pkg/ptr"
"github.com/lima-vm/lima/pkg/store/dirnames"
"github.com/lima-vm/lima/pkg/store/filenames"
"github.com/lima-vm/lima/pkg/version/versionutil"
)

const (
Expand Down Expand Up @@ -171,6 +172,17 @@ func defaultGuestInstallPrefix() string {
// - CACertificates Files and Certs are uniquely appended in d, y, o order
func FillDefault(y, d, o *LimaYAML, filePath string) {
instDir := filepath.Dir(filePath)

// existingLimaVersion can be empty if the instance was created with Lima prior to v0.20,
// or, when editing a template file without an instance (`limactl edit foo.yaml`)
var existingLimaVersion string
limaVersionFile := filepath.Join(instDir, filenames.LimaVersion)
if b, err := os.ReadFile(limaVersionFile); err == nil {
existingLimaVersion = strings.TrimSpace(string(b))
} else if !errors.Is(err, os.ErrNotExist) {
logrus.WithError(err).Warnf("Failed to read %q", limaVersionFile)
}
AkihiroSuda marked this conversation as resolved.
Show resolved Hide resolved

if y.VMType == nil {
y.VMType = d.VMType
}
Expand Down Expand Up @@ -547,21 +559,41 @@ func FillDefault(y, d, o *LimaYAML, filePath string) {
}
}

y.MountTypesUnsupported = append(append(o.MountTypesUnsupported, y.MountTypesUnsupported...), d.MountTypesUnsupported...)
mountTypesUnsupported := make(map[string]struct{})
for _, f := range y.MountTypesUnsupported {
mountTypesUnsupported[f] = struct{}{}
}
// MountType has to be resolved before resolving Mounts
if y.MountType == nil {
y.MountType = d.MountType
}
if o.MountType != nil {
y.MountType = o.MountType
}
if y.MountType == nil || *y.MountType == "" {
if *y.VMType == VZ {
if y.MountType == nil || *y.MountType == "" || *y.MountType == "default" {
switch *y.VMType {
case VZ:
y.MountType = ptr.Of(VIRTIOFS)
} else {
case QEMU:
y.MountType = ptr.Of(NINEP)
if _, ok := mountTypesUnsupported[NINEP]; ok {
// Use REVSSHFS if the instance does not support 9p
y.MountType = ptr.Of(REVSSHFS)
} else if isExistingInstanceDir(instDir) && !versionutil.GreaterEqual(existingLimaVersion, "1.0.0") {
// Use REVSSHFS if the instance was created with Lima prior to v1.0
y.MountType = ptr.Of(REVSSHFS)
}
default:
y.MountType = ptr.Of(REVSSHFS)
}
}

if _, ok := mountTypesUnsupported[*y.MountType]; ok {
// We cannot return an error here, but Validate() will return it.
logrus.Warnf("Unsupported mount type: %q", *y.MountType)
}

if y.MountInotify == nil {
y.MountInotify = d.MountInotify
}
Expand Down
55 changes: 28 additions & 27 deletions pkg/limayaml/limayaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,34 @@ import (
)

type LimaYAML struct {
MinimumLimaVersion *string `yaml:"minimumLimaVersion,omitempty" json:"minimumLimaVersion,omitempty"`
VMType *VMType `yaml:"vmType,omitempty" json:"vmType,omitempty"`
VMOpts VMOpts `yaml:"vmOpts,omitempty" json:"vmOpts,omitempty"`
OS *OS `yaml:"os,omitempty" json:"os,omitempty"`
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty"`
Images []Image `yaml:"images" json:"images"` // REQUIRED
CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty"`
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty"`
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes
Disk *string `yaml:"disk,omitempty" json:"disk,omitempty"` // go-units.RAMInBytes
AdditionalDisks []Disk `yaml:"additionalDisks,omitempty" json:"additionalDisks,omitempty"`
Mounts []Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
MountType *MountType `yaml:"mountType,omitempty" json:"mountType,omitempty"`
MountInotify *bool `yaml:"mountInotify,omitempty" json:"mountInotify,omitempty"`
SSH SSH `yaml:"ssh,omitempty" json:"ssh,omitempty"` // REQUIRED (FIXME)
Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"`
Audio Audio `yaml:"audio,omitempty" json:"audio,omitempty"`
Video Video `yaml:"video,omitempty" json:"video,omitempty"`
Provision []Provision `yaml:"provision,omitempty" json:"provision,omitempty"`
UpgradePackages *bool `yaml:"upgradePackages,omitempty" json:"upgradePackages,omitempty"`
Containerd Containerd `yaml:"containerd,omitempty" json:"containerd,omitempty"`
GuestInstallPrefix *string `yaml:"guestInstallPrefix,omitempty" json:"guestInstallPrefix,omitempty"`
Probes []Probe `yaml:"probes,omitempty" json:"probes,omitempty"`
PortForwards []PortForward `yaml:"portForwards,omitempty" json:"portForwards,omitempty"`
CopyToHost []CopyToHost `yaml:"copyToHost,omitempty" json:"copyToHost,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty"`
MinimumLimaVersion *string `yaml:"minimumLimaVersion,omitempty" json:"minimumLimaVersion,omitempty"`
VMType *VMType `yaml:"vmType,omitempty" json:"vmType,omitempty"`
VMOpts VMOpts `yaml:"vmOpts,omitempty" json:"vmOpts,omitempty"`
OS *OS `yaml:"os,omitempty" json:"os,omitempty"`
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty"`
Images []Image `yaml:"images" json:"images"` // REQUIRED
CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty"`
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty"`
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty"` // go-units.RAMInBytes
Disk *string `yaml:"disk,omitempty" json:"disk,omitempty"` // go-units.RAMInBytes
AdditionalDisks []Disk `yaml:"additionalDisks,omitempty" json:"additionalDisks,omitempty"`
Mounts []Mount `yaml:"mounts,omitempty" json:"mounts,omitempty"`
MountTypesUnsupported []string `yaml:"mountTypesUnsupported,omitempty" json:"mountTypesUnsupported,omitempty"`
MountType *MountType `yaml:"mountType,omitempty" json:"mountType,omitempty"`
MountInotify *bool `yaml:"mountInotify,omitempty" json:"mountInotify,omitempty"`
SSH SSH `yaml:"ssh,omitempty" json:"ssh,omitempty"` // REQUIRED (FIXME)
Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"`
Audio Audio `yaml:"audio,omitempty" json:"audio,omitempty"`
Video Video `yaml:"video,omitempty" json:"video,omitempty"`
Provision []Provision `yaml:"provision,omitempty" json:"provision,omitempty"`
UpgradePackages *bool `yaml:"upgradePackages,omitempty" json:"upgradePackages,omitempty"`
Containerd Containerd `yaml:"containerd,omitempty" json:"containerd,omitempty"`
GuestInstallPrefix *string `yaml:"guestInstallPrefix,omitempty" json:"guestInstallPrefix,omitempty"`
Probes []Probe `yaml:"probes,omitempty" json:"probes,omitempty"`
PortForwards []PortForward `yaml:"portForwards,omitempty" json:"portForwards,omitempty"`
CopyToHost []CopyToHost `yaml:"copyToHost,omitempty" json:"copyToHost,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
Networks []Network `yaml:"networks,omitempty" json:"networks,omitempty"`
// `network` was deprecated in Lima v0.7.0, removed in Lima v0.14.0. Use `networks` instead.
Env map[string]string `yaml:"env,omitempty" json:"env,omitempty"`
Param map[string]string `yaml:"param,omitempty" json:"param,omitempty"`
Expand Down
9 changes: 6 additions & 3 deletions pkg/limayaml/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ func Validate(y *LimaYAML, warn bool) error {
return fmt.Errorf("field `mountType` must be %q or %q or %q, or %q, got %q", REVSSHFS, NINEP, VIRTIOFS, WSLMount, *y.MountType)
}

for _, f := range y.MountTypesUnsupported {
if f == *y.MountType {
return fmt.Errorf("field `mountType` must not be one of %v (`mountTypesUnsupported`), got %q", y.MountTypesUnsupported, *y.MountType)
}
}

if warn && runtime.GOOS != "linux" {
for i, mount := range y.Mounts {
if mount.Virtiofs.QueueSize != nil {
Expand Down Expand Up @@ -508,9 +514,6 @@ func validatePort(field string, port int) error {
}

func warnExperimental(y *LimaYAML) {
if *y.MountType == NINEP {
logrus.Warn("`mountType: 9p` is experimental")
}
if *y.MountType == VIRTIOFS && runtime.GOOS == "linux" {
logrus.Warn("`mountType: virtiofs` on Linux is experimental")
}
Expand Down
40 changes: 24 additions & 16 deletions pkg/version/versionutil/versionutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,34 @@ func Parse(version string) (*semver.Version, error) {
return semver.NewVersion(version)
}

// GreaterThan returns true if the Lima version used to create an instance is greater
// than a specific older version. Always returns false if the Lima version is the empty string.
// Unparsable lima versions (like SHA1 commit ids) are treated as the latest version and return true.
// limaVersion is a `github describe` string, not a semantic version. So "0.19.1-16-gf3dc6ed.m"
// will be considered greater than "0.19.1".
func GreaterThan(limaVersion, oldVersion string) bool {
func compare(limaVersion, oldVersion string) int {
if limaVersion == "" {
return false
if oldVersion == "" {
return 0
}
return -1
}
version, err := Parse(limaVersion)
if err != nil {
return true
return 1
}
switch version.Compare(*semver.New(oldVersion)) {
case -1:
return false
case +1:
return true
case 0:
return strings.Contains(limaVersion, "-")
cmp := version.Compare(*semver.New(oldVersion))
if cmp == 0 && strings.Contains(limaVersion, "-") {
cmp = 1
}
panic("unreachable")
return cmp
}

// GreaterThan returns true if the Lima version used to create an instance is greater
// than a specific older version. Always returns false if the Lima version is the empty string.
// Unparsable lima versions (like SHA1 commit ids) are treated as the latest version and return true.
// limaVersion is a `github describe` string, not a semantic version. So "0.19.1-16-gf3dc6ed.m"
// will be considered greater than "0.19.1".
func GreaterThan(limaVersion, oldVersion string) bool {
return compare(limaVersion, oldVersion) > 0
}

// GreaterEqual return true if limaVersion >= oldVersion.
func GreaterEqual(limaVersion, oldVersion string) bool {
return compare(limaVersion, oldVersion) >= 0
}
10 changes: 10 additions & 0 deletions pkg/version/versionutil/versionutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ func TestGreaterThan(t *testing.T) {
assert.Equal(t, GreaterThan("0.2.0", "0.1.0"), true)
assert.Equal(t, GreaterThan("abacab", "0.1.0"), true)
}

func TestGreaterEqual(t *testing.T) {
assert.Equal(t, GreaterEqual("", ""), true)
assert.Equal(t, GreaterEqual("", "0.1.0"), false)
assert.Equal(t, GreaterEqual("0.0.1", "0.1.0"), false)
assert.Equal(t, GreaterEqual("0.1.0", "0.1.0"), true)
assert.Equal(t, GreaterEqual("0.1.0-2", "0.1.0"), true)
assert.Equal(t, GreaterEqual("0.2.0", "0.1.0"), true)
assert.Equal(t, GreaterEqual("abacab", "0.1.0"), true)
}
1 change: 1 addition & 0 deletions pkg/vz/vz_driver_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var knownYamlProperties = []string{
"Message",
"Mounts",
"MountType",
"MountTypesUnsupported",
"MountInotify",
"Networks",
"OS",
Expand Down
2 changes: 1 addition & 1 deletion website/content/en/docs/config/mount/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Lima prior to v0.10 had used "builtin" as the SFTP driver.

### 9p
> **Warning**
> "9p" mode is experimental
> "9p" mode is experimental (will graduate from experimental in Lima v1.0)

The "9p" mount type is implemented by using QEMU's virtio-9p-pci devices.
virtio-9p-pci is also known as "virtfs", but note that this is unrelated to [virtio-fs](https://virtio-fs.gitlab.io/).
Expand Down
Loading
Loading