From 8f1517f2b9e5462c5b4a9da16743a0d7889df0c8 Mon Sep 17 00:00:00 2001 From: FlUxIuS Date: Fri, 10 Apr 2026 15:16:22 +0200 Subject: [PATCH] Re-introducing USB passthough but using YAML argument "usb" instead of twiking with "video" --- pkg/cidata/cloud-config.yaml | 190 +++++++++- pkg/driver/qemu/qemu.go | 3 + pkg/limatype/lima_yaml.go | 1 + pkg/limayaml/default.yaml | 683 ++++++++++++++++++++++++++++++++++- pkg/limayaml/defaults.go | 10 + 5 files changed, 885 insertions(+), 2 deletions(-) mode change 120000 => 100644 pkg/cidata/cloud-config.yaml mode change 120000 => 100644 pkg/limayaml/default.yaml diff --git a/pkg/cidata/cloud-config.yaml b/pkg/cidata/cloud-config.yaml deleted file mode 120000 index 4bec8830e5f..00000000000 --- a/pkg/cidata/cloud-config.yaml +++ /dev/null @@ -1 +0,0 @@ -cidata.TEMPLATE.d/user-data \ No newline at end of file diff --git a/pkg/cidata/cloud-config.yaml b/pkg/cidata/cloud-config.yaml new file mode 100644 index 00000000000..61f82da5433 --- /dev/null +++ b/pkg/cidata/cloud-config.yaml @@ -0,0 +1,189 @@ +#cloud-config +# vim:syntax=yaml + +growpart: + mode: auto + devices: ['/'] + +{{- if eq .OS "FreeBSD" }} +packages: + # boot.sh depends on sudo. + # TODO: consider replacing sudo with doas. + # FIXME: The hostagent script depends on sudo too. + # https://github.com/lima-vm/lima/issues/4594 + - sudo +{{- end }} + +{{- if .UpgradePackages }} +package_update: true +package_upgrade: true +package_reboot_if_required: true +{{- end }} + +{{- if or .RosettaEnabled (and .Mounts (or (eq .MountType "9p") (eq .MountType "virtiofs"))) }} +mounts: + {{- if .RosettaEnabled }}{{/* Mount the rosetta volume before systemd-binfmt.service(8) starts */}} +- [vz-rosetta, /mnt/lima-rosetta, virtiofs, defaults, "0", "0"] + {{- end }} + {{- if and .Mounts (or (eq .MountType "9p") (eq .MountType "virtiofs")) }} + {{- range $m := $.Mounts}} +- [{{$m.Tag}}, {{$m.MountPoint}}, {{$m.Type}}, "{{$m.Options}}", "0", "0"] + {{- end }} + {{- end }} +{{- end }} + +{{- if .TimeZone }} +timezone: {{.TimeZone}} +{{- end }} + +users: + - name: "{{.User}}" +{{- if ne .OS "FreeBSD" }} + # nuageinit does not support specifying the UID. + # The UID is fixed up in boot.essential.FreeBSD/00-freebsd-user-group.sh + uid: "{{.UID}}" +{{- end }} +{{- if .Comment }} + gecos: {{ printf "%q" .Comment }} +{{- end }} + homedir: "{{.Home}}" + shell: {{.Shell}} +{{- if eq .OS "Darwin" }} + {{/* On macOS, the password is not locked so as to allow GUI login. */}} + {{/* Since the user can run sudo with their own password, basically we don't need to set up passwordless sudo. */}} + {{/* However, it is still configured to allow `/sbin/shutdown -h now` without password, as it is invoked by `limactl stop` for graceful shutdown. */}} + {{/* (Why doesn't macOS VM support graceful shutdown?) */}} + sudo: ALL=(ALL) NOPASSWD:/sbin/shutdown -h now +{{- else }} + sudo: ALL=(ALL) NOPASSWD:ALL + {{- if eq .OS "FreeBSD" }} + groups: + - wheel + doas: permit nopass :wheel + {{- end}} + lock_passwd: true +{{- end }} +{{- if eq .OS "FreeBSD" }} + ssh_authorized_keys: +{{- else }} + ssh-authorized-keys: +{{- end }} + {{- range $val := .SSHPubKeys }} + - {{ printf "%q" $val }} + {{- end }} + +{{- if .BootScripts }} +write_files: + - content: | + #!/bin/sh + set -eux + LIMA_CIDATA_MNT="/mnt/lima-cidata" + UNAME="$(uname -s)" + if [ "${UNAME}" = "Darwin" ]; then + LIMA_CIDATA_MNT="/Volumes/cidata" + # Should have been mounted automatically + elif [ "${UNAME}" = "FreeBSD" ]; then + LIMA_CIDATA_DEV="/dev/iso9660/cidata" + if [ ! -e "${LIMA_CIDATA_DEV}" ]; then + # When the iso is created with `hdiutil` on macOS, + # apparently the volume name becomes "CIDATA" not "cidata" + LIMA_CIDATA_DEV="/dev/iso9660/CIDATA" + fi + mkdir -p -m 700 "${LIMA_CIDATA_MNT}" + mount_cd9660 -G wheel -U root -m 0700 -o ro,exec "${LIMA_CIDATA_DEV}" "${LIMA_CIDATA_MNT}" + elif [ "${UNAME}" = "Linux" ]; then + LIMA_CIDATA_DEV="/dev/disk/by-label/cidata" + mkdir -p -m 700 "${LIMA_CIDATA_MNT}" + mount -o ro,mode=0700,dmode=0700,overriderockperm,exec,uid=0 "${LIMA_CIDATA_DEV}" "${LIMA_CIDATA_MNT}" + else + echo "Unsupported OS: ${UNAME}" >&2 + exit 1 + fi + export LIMA_CIDATA_MNT + exec "${LIMA_CIDATA_MNT}"/boot.sh +{{- if or (eq .OS "Darwin") (eq .OS "FreeBSD") }} + owner: root:wheel +{{- else }} + owner: root:root +{{- end }} +{{- if eq .OS "FreeBSD" }} + # nuageinit requires the path to be under an existing directory + path: /usr/sbin/lima-freebsd-init.sh +{{- else }} + path: /var/lib/cloud/scripts/per-boot/00-lima.boot.sh +{{- end }} + permissions: '0755' +{{- if eq .OS "FreeBSD" }} + # nuageinit does not run /var/lib/cloud/scripts/per-boot/* scripts + - content: | + #!/bin/sh + + # PROVIDE: lima_freebsd_init + # REQUIRE: DAEMON + # BEFORE: LOGIN + + . /etc/rc.subr + + name="lima_freebsd_init" + rcvar="lima_freebsd_init_enable" + command="/usr/sbin/lima-freebsd-init.sh" + + load_rc_config "$name" + run_rc_command "$1" + owner: root:wheel + path: /etc/rc.d/lima_freebsd_init + permissions: '0755' + - content: | + lima_freebsd_init_enable="YES" + owner: root:wheel + path: /etc/rc.conf.d/lima_freebsd_init + permissions: '0644' +{{- end }} +{{- end }} + +{{- if .DNSAddresses }} +# This has no effect on systems using systemd-resolved, but is used +# on e.g. Alpine to set up /etc/resolv.conf on first boot. + +manage_resolv_conf: true + +resolv_conf: + nameservers: + {{- range $ns := $.DNSAddresses }} + - {{$ns}} + {{- end }} +{{- end }} + +{{- if or .CACerts.RemoveDefaults .CACerts.Trusted }} +{{ with .CACerts }} +ca_certs: + {{- if .RemoveDefaults }} + remove_defaults: {{ .RemoveDefaults }} + {{- end }} + {{- if .Trusted}} + trusted: + {{- range $cert := .Trusted }} + - | + {{- range $line := $cert.Lines }} + {{ $line }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} + +{{- if .BootCmds }} +bootcmd: + {{- range $cmd := $.BootCmds }} +- | + # We need to embed the params.env as a here-doc because /mnt/lima-cidata is not yet mounted + while read -r line; do [ -n "$line" ] && export "$line"; done <<'EOF' + {{- range $key, $val := $.Param }} + PARAM_{{ $key }}={{ $val }} + {{- end }} + EOF + {{- range $line := $cmd.Lines }} + {{ $line }} + {{- end }} + {{- end }} +{{- end }} diff --git a/pkg/driver/qemu/qemu.go b/pkg/driver/qemu/qemu.go index 36fe5fdff4f..c49330fdca3 100644 --- a/pkg/driver/qemu/qemu.go +++ b/pkg/driver/qemu/qemu.go @@ -852,6 +852,9 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er args = append(args, "-device", "virtio-keyboard-pci") args = append(args, "-device", "virtio-"+input+"-pci") args = append(args, "-device", "qemu-xhci,id=usb-bus") + } else if *y.USB { + // Add USB controller without display for USB device passthrough + args = append(args, "-device", "qemu-xhci,id=usb-bus") } // Parallel diff --git a/pkg/limatype/lima_yaml.go b/pkg/limatype/lima_yaml.go index afb012e8c10..68b508b432f 100644 --- a/pkg/limatype/lima_yaml.go +++ b/pkg/limatype/lima_yaml.go @@ -35,6 +35,7 @@ type LimaYAML struct { Firmware Firmware `yaml:"firmware,omitempty" json:"firmware,omitempty"` Audio Audio `yaml:"audio,omitempty" json:"audio,omitempty"` Video Video `yaml:"video,omitempty" json:"video,omitempty"` + USB *bool `yaml:"usb,omitempty" json:"usb,omitempty" jsonschema:"nullable"` Provision []Provision `yaml:"provision,omitempty" json:"provision,omitempty"` UpgradePackages *bool `yaml:"upgradePackages,omitempty" json:"upgradePackages,omitempty" jsonschema:"nullable"` Containerd Containerd `yaml:"containerd,omitempty" json:"containerd,omitempty"` diff --git a/pkg/limayaml/default.yaml b/pkg/limayaml/default.yaml deleted file mode 120000 index 1f729470ead..00000000000 --- a/pkg/limayaml/default.yaml +++ /dev/null @@ -1 +0,0 @@ -../../templates/default.yaml \ No newline at end of file diff --git a/pkg/limayaml/default.yaml b/pkg/limayaml/default.yaml new file mode 100644 index 00000000000..79d6c2288c8 --- /dev/null +++ b/pkg/limayaml/default.yaml @@ -0,0 +1,682 @@ +# ===================================================================== # +# BASIC CONFIGURATION +# ===================================================================== # + +# Default values in this YAML file are specified by `null` instead of Lima's "builtin default" values, +# so they can be overridden by the $LIMA_HOME/_config/default.yaml mechanism documented at the end of this file. + +# VM type: "qemu", "vz" (on macOS 13 and later), or "default". +# The vmType can be specified only on creating the instance. +# The vmType of existing instances cannot be changed. +# 🟢 Builtin default: "vz" (on macOS 13.5 and later), "qemu" (on others) +vmType: null + +# Arch: "default", "x86_64", "aarch64". +# 🟢 Builtin default: "default" (corresponds to the host architecture) +arch: null + + +# OpenStack-compatible disk image. +# Each image has a `location` URL for the disk image, an `arch` setting, and an optional `digest`. +# To specify a custom kernel and initial RAM disk, nest `kernel` and `initrd` under an image entry: +# - location: "https://example.com/image.qcow2" +# # kernel specifies a custom kernel to boot. +# kernel: +# location: "https://example.com/vmlinuz" +# digest: "sha256:..." +# cmdline: "console=ttyS0 root=/dev/sda1" +# # initrd specifies a custom initial RAM disk. +# initrd: +# location: "https://example.com/initrd.img" +# digest: "sha256:..." +# 🟢 Builtin default: none (must be specified) +# 🔵 This file: Ubuntu images (inherited via the `base` mechanism later in this file) +images: [] + +# CPUs +# 🟢 Builtin default: min(4, host CPU cores) +cpus: null + +# Memory size +# 🟢 Builtin default: min("4GiB", half of host memory) +memory: null + +# Disk size +# 🟢 Builtin default: "100GiB" +disk: null + +# Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest +# "location" can use these template variables: {{.Home}}, {{.Dir}}, {{.Name}}, {{.UID}}, {{.User}}, {{.Param.Key}}, +# {{.GlobalTempDir}}, and {{.TempDir}}. The global temp dir is always "/tmp" on Unix. +# "mountPoint" can use these template variables: {{.Home}}, {{.Name}}, {{.Hostname}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# 🟢 Builtin default: [] (Mount nothing) +# 🔵 This file: Mount the home as read-only (inherited via the `base` mechanism later in this file) +# Until Lima v1.2, /tmp/lima was mounted too as writable. +mounts: [] +# - location: "~" +# # Configure the mountPoint inside the guest. +# # 🟢 Builtin default: value of location +# mountPoint: null +# # Setting `writable` to true is discouraged when mountType is set to "reverse-sshfs". +# # 🟢 Builtin default: false +# writable: null +# sshfs: +# # Enabling the SSHFS cache will increase performance of the mounted filesystem, at +# # the cost of potentially not reflecting changes made on the host in a timely manner. +# # Warning: It looks like PHP filesystem access does not work correctly when +# # the cache is disabled. +# # 🟢 Builtin default: true +# cache: null +# # SSHFS has an optional flag called 'follow_symlinks'. This allows mounts +# # to be properly resolved in the guest os and allow for access to the +# # contents of the symlink. As a result, symlinked files & folders on the Host +# # system will look and feel like regular files directories in the Guest OS. +# # 🟢 Builtin default: false +# followSymlinks: null +# # SFTP driver, "builtin" or "openssh-sftp-server". "openssh-sftp-server" is recommended. +# # 🟢 Builtin default: "openssh-sftp-server" if OpenSSH SFTP Server binary is found, otherwise "builtin" +# sftpDriver: null +# 9p: +# # Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none". +# # "mapped-xattr" and "mapped-file" are useful for persistent chown but incompatible with symlinks. +# # 🟢 Builtin default: "none" (since Lima v0.13) +# securityModel: null +# # Select 9P protocol version. Valid options are: "9p2000" (legacy), "9p2000.u", "9p2000.L". +# # 🟢 Builtin default: "9p2000.L" +# protocolVersion: null +# # The number of bytes to use for 9p packet payload, where 4KiB is the absolute minimum. +# # 🟢 Builtin default: "128KiB" +# msize: null +# # Specifies a caching policy. Valid options are: "none", "loose", "fscache" and "mmap". +# # Try choosing "mmap" or "none" if you see a stability issue with the default "fscache". +# # See https://www.kernel.org/doc/Documentation/filesystems/9p.txt +# # 🟢 Builtin default: "fscache" for non-writable mounts, "mmap" for writable mounts +# cache: null + +# List of mount types not supported by the kernel of this distro. +# Also used to resolve the default mount type when not explicitly specified. +# +# NOTE: 9p is broken in Linux v6.9, v6.10, and v6.11. +# The issue was fixed in Linux v6.12-rc5 (https://github.com/torvalds/linux/commit/be2ca38). +# +# 🟢 Builtin default: [] +mountTypesUnsupported: null + +# Mount type for above mounts, such as "reverse-sshfs" (from sshocker), "9p" (QEMU’s virtio-9p-pci, aka virtfs), +# or "virtiofs" (experimental on Linux; needs `vmType: vz` on macOS). +# 🟢 Builtin default: "default" (resolved to be "9p" for QEMU since Lima v1.0 on non-Windows, "virtiofs" for vz) +mountType: null + +# Enable inotify support for mounted directories (EXPERIMENTAL) +# 🟢 Builtin default: Disabled by default +mountInotify: null + +# ===================================================================== # +# ADVANCED CONFIGURATION +# ===================================================================== # + +# Lima disks to attach to the instance. The disks will be accessible from inside the +# instance, labeled by name. (e.g. if the disk is named "data", it will be labeled +# "lima-data" inside the instance). The disk will be mounted inside the instance at +# `/mnt/lima-${VOLUME}`. +# 🟢 Builtin default: [] +additionalDisks: +# disks should either be a list of disk name strings, for example: +# - "data" +# or a list of disk objects with extra parameters, for example: +# - name: "data" +# format: true +# fsType: "ext4" + +ssh: + # A localhost port of the host. Forwarded to port 22 of the guest. + # 🟢 Builtin default: 0 (automatically assigned to a free port) + localPort: null + # Load ~/.ssh/*.pub in addition to $LIMA_HOME/_config/user.pub . + # This option is useful when you want to use other SSH-based + # applications such as rsync with the Lima instance. + # If you have an insecure key under ~/.ssh, do not use this option. + # 🟢 Builtin default: false (since Lima v1.0) + loadDotSSHPubKeys: null + # Forward ssh agent into the instance. + # The ssh agent socket can be mounted in a container at the path `/run/host-services/ssh-auth.sock`. + # Set the environment variable `SSH_AUTH_SOCK` value to the path above. + # The socket is accessible by the non-root user inside the Lima instance. + # 🟢 Builtin default: false + forwardAgent: null + # Forward X11 into the instance + # 🟢 Builtin default: false + forwardX11: null + # Trust forwarded X11 clients + # 🟢 Builtin default: false + forwardX11Trusted: null + # Enable SSH over vsock. + # 🟢 Builtin default: true for vz with Linux guests, false otherwise + overVsock: null + +caCerts: + # If set to `true`, this will remove all the default trusted CA certificates that + # are normally shipped with the OS. + # 🟢 Builtin default: false + removeDefaults: null + + # A list of trusted CA certificate files. The files will be read and passed to cloud-init. + files: + # - examples/hello.crt + + # A list of trusted CA certificates. These are directly passed to cloud-init. + certs: + # - | + # -----BEGIN CERTIFICATE----- + # YOUR-ORGS-TRUSTED-CA-CERT-HERE + # -----END CERTIFICATE----- + # - | + # -----BEGIN CERTIFICATE----- + # YOUR-ORGS-TRUSTED-CA-CERT-HERE + # -----END CERTIFICATE----- + +# Upgrade the instance on boot +# Reboot after upgrade if required +# 🟢 Builtin default: false +upgradePackages: null + +containerd: + # Enable system-wide (aka rootful) containerd and its dependencies (BuildKit, Stargz Snapshotter) + # Note that `nerdctl.lima` only works in rootless mode; you have to use `lima sudo nerdctl ...` + # to use rootful containerd with nerdctl. + # 🟢 Builtin default: false + system: null + # Enable user-scoped (aka rootless) containerd and its dependencies + # 🟢 Builtin default: true (for x86_64 and aarch64) + user: null +# # Override containerd archive +# # 🟢 Builtin default: hard-coded URL with hard-coded digest (see the output of `limactl info | jq .defaultTemplate.containerd.archives`) +# archives: +# - location: "~/Downloads/nerdctl-full-X.Y.Z-linux-amd64.tar.gz" +# arch: "x86_64" +# digest: "sha256:..." + +# Provisioning scripts need to be idempotent because they might be called +# multiple times, e.g. when the host VM is being restarted. +# The scripts can use the following template variables: {{.Home}}, {{.Name}}, {{.Hostname}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# +# EXPERIMENTAL Alternatively the script can be provided using the "file" property. This file is read when the instance +# is created and then stored under the "script" property. When "file" is specified "script" must be empty. +# The "file" property can either be a string (URL), or an object with a "url" and "digest" properties. +# The "digest" property is currently unused. +# Relative script files will be resolved relative to the location of the template file. +# 🟢 Builtin default: [] +# provision: +# # `system` is executed with root privileges +# - mode: system +# script: | +# #!/bin/bash +# set -eux -o pipefail +# export DEBIAN_FRONTEND=noninteractive +# apt-get install -y vim +# # `user` is executed without root privileges +# - mode: user +# file: +# url: user-provisioning.sh +# digest: deadbeef +# # `boot` is executed directly by /bin/sh as part of cloud-init-local.service's early boot process, +# # which is why there is no hash-bang specified in the example +# # See cloud-init docs for more info https://docs.cloud-init.io/en/latest/reference/examples.html#run-commands-on-first-boot +# - mode: boot +# script: | +# systemctl disable NetworkManager-wait-online.service +# # `dependency` is executed before the regular dependency resolution workflow in +# # pkg/cidata/cidata.TEMPLATE.d/boot.Linux/30-install-packages.sh +# # If skipDefaultDependencyResolution is set on at least one `dependency` mode provisioning script, the regular +# # dependency resolution workflow in pkg/cidata/cidata.TEMPLATE.d/boot.Linux/30-install-packages.sh will be skipped. +# - mode: dependency +# skipDefaultDependencyResolution: false +# script: | +# #!/bin/bash +# dnf config-manager --add-repo ... +# dnf install ... +# # `ansible` is executed after other scripts are complete +# # It requires `ansible-playbook` command to be installed. +# # Environment variables such as ANSIBLE_CONFIG can be used, to control the behavior of the playbook execution. +# # See ansible docs, and `ansible-config`, for more info https://docs.ansible.com/ansible/latest/playbook_guide/ +# # DEPRECATED The ansible mode is deprecated, and should not be used. Instead call ansible-playbook directly, +# # either from the host after the instance is started or from the instance by running ansible locally instead. +# - mode: ansible +# playbook: playbook.yaml +# # `data` is a file that is written to the guest filesystem and not executed at all. +# # The file is written after the boot scripts, but before any other provisioning scripts are run. +# # Note that reverse-sshfs mounts are not established at this time; other mount types are already mounted. +# # The `path` and `content` properties are required. The `file` property can be used the same way as with +# # other provisioning scripts, in which case `content` must be empty. The `owner` defaults to "root:root"; +# # the permissions default to 644. The `overwrite` property defaults to `true`, in which case the file will +# # be overwritten on every boot. +# # `path`, `contents`, and `owner` are evaluated as guest templates (see above). +# - mode: data +# path: /etc/conf.d/example +# content: | +# FOO=bar +# owner: "root:root" +# permissions: 644 +# overwrite: false +# # Create or edit a file in the guest filesystem by using `yq`. +# # The file specified by `path` will be updated by `expression`. +# # An empty file of the required `format` will be created if it does not yet exist. +# # `format` defaults to "auto" and will be detected by file extension of `path`. +# # If the extension is not recognized by `yq` then `format` must be set to a +# # value from this list: +# # "auto", "csv", "ini", "json", "props", "tsv", "toml", "xml", "yaml" +# # See https://github.com/mikefarah/yq for more info. +# # Any missing directories will be created as needed. +# # The file permissions will be set to the specified value. +# # The file and directory creation will be performed as the specified owner. +# # If the existing file is not writable by the specified owner, the operation will fail. +# # `path` and `expression` are required. +# # `owner` and `permissions` are optional. Defaults to "root:root" (on Linux) and 644. +# - mode: yq +# path: "{{.Home}}/.config/docker/daemon.json" +# expression: ".features.containerd-snapshotter = {{.Param.containerdSnapshotter}}" +# format: auto +# owner: "{{.User}}" +# permissions: 644 +# +# Q. In what order are provision scripts executed? +# A. All provisions are processed per boot by each module in stages of cloud-init as follows: +# 1. cloud-init 'init' stage +# bootcmd: +# - `mode: boot` scripts are executed +# +# 2. cloud-init 'config' stage +# write_files: +# - `00-lima.boot.sh` is created, but not executed +# +# 3. cloud-init 'final' stage +# scripts_per_boot: +# - `00-lima.boot.sh` is executed; remaining provisions are processed in the following order: +# - LIMA pre-defined boot scripts: +# - `boot.Linux/{00-..., ..., 25-...}` +# - `boot.Linux/30-install-packages.sh` +# - `mode: dependency` scripts are executed +# - `boot.Linux/{35-..., ...}` +# - `mode: data` files are copied +# - `mode: yq` files are processed +# - `mode: system` scripts are executed +# - `mode: user` scripts are executed + +# Probe scripts to check readiness. +# The scripts run in user mode. They must start with a '#!' line. +# The scripts can use the following template variables: {{.Home}}, {{.Name}}, {{.Hostname}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# EXPERIMENTAL Alternatively the script can be provided using the "file" property. This file is read when the instance +# is created and then stored under the "script" property. When "file" is specified "script" must be empty. +# The "file" property can either be a string (URL), or an object with a "url" and "digest" properties. +# The "digest" property is currently unused. +# Relative script files will be resolved relative to the location of the template file. +# 🟢 Builtin default: [] +# probes: +# # Only `readiness` probes are supported right now. +# - mode: readiness +# description: vim to be installed +# script: | +# #!/bin/bash +# set -eux -o pipefail +# if ! timeout 30s bash -c "until command -v vim; do sleep 3; done"; then +# echo >&2 "vim is not installed yet" +# exit 1 +# fi +# hint: | +# vim was not installed in the guest. Make sure the package system is working correctly. +# Also see "/var/log/cloud-init-output.log" in the guest. + +# ===================================================================== # +# FURTHER ADVANCED CONFIGURATION +# ===================================================================== # + +# A template should specify the minimum Lima version required to parse this template correctly. +# It should not be set if the minimum version is less than 1.0.0 +# 🟢 Builtin default: not set +# 🔵 This file: "1.1.0" to use the `base` templating mechanism +minimumLimaVersion: 2.0.0 + +# EXPERIMENTAL +# Default settings can be imported from base templates. These will be merged in when the instance +# is created, and the combined template is stored in the instance directory. +# This setting can be either a single string (URL), or a list of locators. +# A locator is again either a string (URL), or an object with "url" and "digest" properties, e.g. +# base: [{url: ./base.yaml, digest: decafbad}, …] +# The "digest" property is currently unused. +# Any relative base template name will be resolved relative to the location of the main template. +# 🟢 Builtin default: no base template +# 🔵 This file: Ubuntu images and default mount points +base: +- template:_images/ubuntu +- template:_default/mounts + +# User to be used inside the VM +user: + # User name. An explicitly specified username is not validated by Lima. + # 🟢 Builtin default: same as the host username, if it is a valid Linux username, otherwise "lima" + name: null + # Full name or display name of the user. + # 🟢 Builtin default: user information from the host + comment: null + # Numeric user id. It is not currently possible to specify a group id. + # 🟢 Builtin default: same as the host user id of the current user (NOT a lookup of the specified "username"). + uid: null + # Home directory inside the VM, NOT the mounted home directory of the host. + # It can use the following template variables: {{.Name}}, {{.Hostname}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. + # 🟢 Builtin default: "/home/{{.User}}.guest" (Also accessible as "/home/{{.User}}.linux") + home: null + # Shell. Needs to be an absolute path. + # 🟢 Builtin default: "/bin/bash" + shell: null + +vmOpts: + qemu: + # Minimum version of QEMU required to create an instance of this template. + # Will be ignored if the vmType is not "qemu" + # 🟢 Builtin default: not set + minimumVersion: null + # Specify desired QEMU CPU type for each arch. + # You can see what options are available for host emulation with: `qemu-system-$(arch) -cpu help`. + # Setting of instructions is supported like this: "qemu64,+ssse3". + # 🟢 Builtin default: hard-coded arch map with type (see the output of `limactl info | jq .defaultTemplate.cpuType`) + cpuType: + # aarch64: "max" # (or "host" when running on aarch64 host) + # armv7l: "max" # (or "host" when running on armv7l host) + # riscv64: "max" # (or "host" when running on riscv64 host) + # x86_64: "max" # (or "host" when running on x86_64 host; additional options are appended on Intel Mac) + vz: + # Specify the disk image format: "raw" or "asif". + # Currently only applies to the primary disk image. + # "asif" requires macOS 26+, and does not support converting back to "raw". + # 🟢 Builtin default: "raw" + diskImageFormat: null + rosetta: + # Enable Rosetta inside the VM; needs `vmType: vz` + # Hint: try `softwareupdate --install-rosetta` if Lima gets stuck at `Installing rosetta...` + # 🟢 Builtin default: false + enabled: null + # Register rosetta to /proc/sys/fs/binfmt_misc + # 🟢 Builtin default: false + binfmt: null + +# OS: "Linux". +# 🟢 Builtin default: "Linux" +os: null + +# DEPRECATED: Use vmOpts.qemu.cpuType instead. See the vmOpts.qemu.cpuType section above for configuration. +cpuType: + +# DEPRECATED: Use vmOpts.vz.rosetta instead. See the vmOpts.qemu.cpuType section above for configuration. +rosetta: + enabled: null + binfmt: null + +# Specify the timezone name (as used by the zoneinfo database). Specify the empty string +# to not set a timezone in the instance. +# 🟢 Builtin default: use name from /etc/timezone or deduce from symlink target of /etc/localtime +timezone: null + +firmware: + # Use legacy BIOS instead of UEFI. Ignored for aarch64 and vz. + # 🟢 Builtin default: false + legacyBIOS: null +# # Override UEFI images +# # 🟢 Builtin default: uses VM's default UEFI, except for qemu + aarch64. +# # See +# images: +# - location: "~/Downloads/edk2-aarch64-code.fd.gz" +# arch: "aarch64" +# digest: "sha256:..." +# vmType: "qemu" + +audio: + # EXPERIMENTAL + # QEMU audiodev, e.g., "none", "coreaudio", "pa", "alsa", "oss". + # VZ driver, use "vz" as device name + # Choosing "none" will mute the audio output, and not play any sound. + # Choosing "default" will pick a suitable choice of: coreaudio, pa, dsound, oss. + # As of QEMU v6.2 the default is to create a disconnected sound device + # that is still visible in the guest but not connected to the host. + # 🟢 Builtin default: "" + device: null + +video: + # QEMU display, e.g., "none", "cocoa", "sdl", "gtk", "vnc", "default". + # Choosing "none" will hide the video output, and not show any window. + # Choosing "vnc" will use a network server, and not show any window. + # Choosing "default" will pick the first available of: gtk, sdl, cocoa. + # As of QEMU v6.2, enabling anything but none or vnc is known to have negative impact + # on performance on macOS hosts: https://gitlab.com/qemu-project/qemu/-/issues/334 + # 🟢 Builtin default: "none" + display: null + # VNC (Virtual Network Computing) is a platform-independent graphical + # desktop-sharing system that uses the Remote Frame Buffer protocol (RFB) + vnc: + # VNC display, e.g.,"to=L", "host:d", "unix:path", "none" + # By convention the TCP port is 5900+d, connections from any host. + # 🟢 Builtin default: "127.0.0.1:0,to=9" + display: null + +# The instance can get routable IP addresses from the vmnet framework using +# https://github.com/lima-vm/socket_vmnet. +# 🟢 Builtin default: [] +networks: +# Lima can manage daemons for networks defined in $LIMA_HOME/_config/networks.yaml +# automatically. The socket_vmnet binary must be installed into +# secure locations only alterable by the "root" user. +# - lima: shared +# # MAC address of the instance; lima will pick one based on the instance name, +# # so DHCP assigned ip addresses should remain constant over instance restarts. +# macAddress: "" +# # Interface name, defaults to "lima0", "lima1", etc. +# interface: "" +# # Interface metric, lowest metric becomes the preferred route. +# # Defaults to 100. Builtin SLIRP network uses 200. +# metric: 100 +# +# Lima can also connect to "unmanaged" networks addressed by "socket". This +# means that the daemons will not be controlled by Lima, but must be started +# before the instance. The interface type (host, shared, or bridged) is +# configured in socket_vmnet and not in lima. +# - socket: "/var/run/socket_vmnet" + + +# The "vzNAT" IP address is accessible from the host, but not from other guests. +# Needs `vmType: vz` +# - vzNAT: true + +# Port forwarding rules. Forwarding between ports 22 and ssh.localPort cannot be overridden. +# Rules are checked sequentially until the first one matches. +# portForwards: +# - guestPort: 443 +# hostIP: "0.0.0.0" # overrides the default value "127.0.0.1"; allows privileged port forwarding +# # default: hostPort: 443 (same as guestPort) +# # default: guestIP: "127.0.0.1" (also matches bind addresses "0.0.0.0", "::", and "::1") +# # default: proto: "tcp" (other options: "udp, "any") +# +# - guestPortRange: [4000, 4999] +# hostIP: "0.0.0.0" # overrides the default value "127.0.0.1" +# # default: hostPortRange: [4000, 4999] (must specify same number of ports as guestPortRange) +# +# - guestPort: 80 +# hostPort: 8080 # overrides the default value 80 +# +# - guestIP: "127.0.0.2" # overrides the default value "127.0.0.1" +# hostIP: "127.0.0.2" # overrides the default value "127.0.0.1" +# # default: guestPortRange: [1, 65535] +# # default: hostPortRange: [1, 65535] +# +# - guestIP: 0.0.0.0 # otherwise defaults to 127.0.0.1 +# proto: any # tcp and udp +# ignore: true # don't forward these ports (guestPortRange, in this case 1-65535) +# +# - guestPort: 7443 +# guestIP: "0.0.0.0" # Will match *any* interface +# guestIPMustBeZero: false # 0.0.0.0 matches any bound interface, not just 0.0.0.0 itself +# hostIP: "0.0.0.0" # Forwards to 0.0.0.0, exposing it externally +# +# - guestSocket: "/run/user/{{.UID}}/my.sock" +# hostSocket: mysocket +# # default: reverse: false +# # "guestSocket" can include these template variables: {{.Home}}, {{.Name}}, {{.Hostname}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# # "hostSocket" can include {{.Home}}, {{.Dir}}, {{.Name}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# # "reverse" can only be used for unix sockets right now, not for tcp sockets. +# # Put sockets into "{{.Dir}}/sock" to avoid collision with Lima internal sockets! +# # Sockets can also be forwarded to ports and vice versa, but not to/from a range of ports. +# # Forwarding requires the lima user to have rw access to the "guestsocket", +# # and the local user rwx access to the directory of the "hostsocket". +# +# # Lima internally appends this fallback rule at the end: +# - guestIP: "127.0.0.1" +# proto: "any" +# guestPortRange: [1, 65535] +# hostIP: "127.0.0.1" +# hostPortRange: [1, 65535] +# # Any port still not matched by a rule will not be forwarded (ignored) + +# Copy files from the guest to the host. Copied after provisioning scripts have been completed. +# copyToHost: +# - guest: "/etc/myconfig.cfg" +# host: "{{.Dir}}/copied-from-guest/myconfig" +# # deleteOnStop: false +# # "guest" can include these template variables: {{.Home}}, {{.Name}}, {{.Hostname}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# # "host" can include {{.Home}}, {{.Dir}}, {{.Name}}, {{.UID}}, {{.User}}, and {{.Param.Key}}. +# # "deleteOnStop" will delete the file from the host when the instance is stopped. + +# Message. Information to be shown to the user, given as a Go template for the instance. +# The same template variables as for listing instances can be used, for example {{.Dir}}. +# You can view the complete list of variables using `limactl list --list-fields` command. +# It also includes {{.HostOS}} and {{.HostArch}} vars, for the runtime GOOS and GOARCH. +# 🟢 Builtin default: "" +# message: | +# This will be shown to the user. + +# Extra environment variables that will be loaded into the VM at start up. +# These variables are consumed by internal init scripts, and also added +# to /etc/environment. +# If you set any of "ftp_proxy", "http_proxy", "https_proxy", or "no_proxy", then +# Lima will automatically set an uppercase variant to the same value as well. +# 🟢 Builtin default: {} +# env: +# KEY: value + +# Defines variables used for customizing the functionality. +# Key names must start with an uppercase or lowercase letter followed by +# any number of letters, digits, and underscores. +# Values must not contain non-printable characters except for spaces and tabs. +# These variables can be referenced as {{.Param.Key}} in lima.yaml. +# In provisioning scripts and probes they are also available as predefined +# environment variables, prefixed with "PARAM_" (so `Key` → `$PARAM_Key`). +# param: +# Key: value + +# Lima will override the proxy environment variables with values from the current process +# environment (the environment in effect when you run `limactl start`). It will automatically +# replace the strings "localhost" and "127.0.0.1" with the host gateway address from inside +# the VM, so it stays routable. Use of the process environment can be disabled by setting +# propagateProxyEnv to false. +# 🟢 Builtin default: true +propagateProxyEnv: null + +# The host agent implements a DNS server that looks up host names on the host +# using the local system resolver. This means changing VPN and network settings +# are reflected automatically into the guest, including conditional forward, +# and mDNS lookup. By default, only IPv4 addresses will be returned. IPv6 addresses +# can only work when using a vmnet network interface and the host has working +# IPv6 configured as well. +hostResolver: + # 🟢 Builtin default: true + enabled: null + # 🟢 Builtin default: false + ipv6: null + # Static names can be defined here as an alternative to adding them to the hosts /etc/hosts. + # Values can be either other hostnames, or IP addresses. The host.lima.internal name is + # predefined to specify the gateway address to the host. + # 🟢 Builtin default: {} + hosts: + # guest.name: 127.1.1.1 + # host.name: host.lima.internal + +# If hostResolver.enabled is false, then the following rules apply for configuring dns: +# Explicitly set DNS addresses for qemu user-mode networking. By default, qemu picks *one* +# nameserver from the host config and forwards all queries to this server. On macOS +# Lima adds the nameservers configured for the first host interface in service order, +# that has an IPv4 address, to the list. In case this still doesn't work (e.g. VPN +# setups), the servers can be specified here explicitly. If nameservers are specified +# here, then the configuration from network preferences will be ignored. +# 🟢 Builtin default: [] +# dns: +# - 1.1.1.1 +# - 1.0.0.1 + +# Prefix to use for installing guest agent, and containerd with dependencies (if configured) +# 🟢 Builtin default: /usr/local +guestInstallPrefix: null + +# When the "plain" mode is enabled: +# - the YAML properties for mounts, port forwarding, containerd, etc. will be ignored +# - guest agent will not be running +# - dependency packages like sshfs will not be installed into the VM +# User-specified provisioning scripts will be still executed. +# 🟢 Builtin default: false +plain: null + +# When the "nestedVirtualization" feature is enabled: +# - Allows running a VM inside the guest VM. +# - The guest VM must configure QEMU with the `-cpu host` parameters to run a nested VM: +# qemu-system-aarch64 -accel kvm -cpu host -M virt +# - Without specifying `-cpu host`, nested virtualization may fail with the error: +# qemu-system-aarch64: kvm_init_vcpu: kvm_arch_init_vcpu failed (0): Invalid argument +# - Only supported on Apple M3 or later with `vmType: vz` or `vmType: krunkit`. +# 🟢 Builtin default: false +nestedVirtualization: null + +# ===================================================================== # +# GLOBAL DEFAULTS AND OVERRIDES +# ===================================================================== # + +# The builtin defaults can be changed globally by creating a $LIMA_HOME/_config/default.yaml +# file. It will be used by ALL instances under the same $LIMA_HOME, and it +# will be applied on each `limactl start`, so can affect instance restarts. + +# A similar mechanism is $LIMA_HOME/_config/override.yaml, which will take +# precedence even over the settings in an instances lima.yaml file. +# It also applies to ALL instances under the same $LIMA_HOME, and is applied +# on each restart. It can be used to globally override settings, e.g. make +# the mount of the home directory writable. + +# EXPERIMENTAL +# A third mechanism is $LIMA_HOME/_config/base.yaml. It is similar to +# `default.yaml` but will be merged during the `base` template embedding +# when the instance is created, and not on every start. It becomes part +# of the lima.yaml file. + +# On each instance start the config settings are determined: If a value is +# not set in `lima.yaml`, then the `default.yaml` is used. If that file +# doesn't exist, or the value is not defined in the file, then the builtin +# default is used. If `override.yaml` exists and defines the value, then +# it overrides whatever has been chosen so far. + +# For slices (e.g. `mounts`, `provision`) and maps (`env`) the entries are +# combined instead of replacing each other. Slices are produced from override +# settings, followed by lima.yaml, followed by default.yaml (but NOT from +# builtin defaults). Maps are produced starting with default.yaml values, +# overwriting with lima.yaml ones, overwriting with override.yaml. + +# Exceptions: +# - `dns` will use the list from the highest priority file; they are not +# combined. If override.yaml defines a list of `dns` entries, then the +# settings in default.yaml and lima.yaml are ignored. +# +# - `mounts` will update the `writable` setting when 2 entries have the +# same `location` value. For this reason they are processed in the opposite +# order: starting with default, followed by lima, and then override. +# +# -`networks` will replace lower priority entries with the same `interface` +# name with higher priority definitions. This does not apply if the +# `interface` field is empty. `networks` are therefore also processed +# in lowest to highest priority order. + +# ===================================================================== # +# END OF TEMPLATE +# ===================================================================== # diff --git a/pkg/limayaml/defaults.go b/pkg/limayaml/defaults.go index 68bd111efa3..2333fc2bf85 100644 --- a/pkg/limayaml/defaults.go +++ b/pkg/limayaml/defaults.go @@ -313,6 +313,16 @@ func FillDefault(ctx context.Context, y, d, o *limatype.LimaYAML, filePath strin y.Video.VNC.Display = o.Video.VNC.Display } + if y.USB == nil { + y.USB = d.USB + } + if o.USB != nil { + y.USB = o.USB + } + if y.USB == nil { + y.USB = ptr.Of(false) + } + if y.Firmware.LegacyBIOS == nil { y.Firmware.LegacyBIOS = d.Firmware.LegacyBIOS }