Skip to content
Draft
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
21 changes: 17 additions & 4 deletions pkg/driver/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,13 @@ func defaultCPUType() limatype.CPUType {
func resolveCPUType(y *limatype.LimaYAML) string {
cpuType := defaultCPUType()
var overrideCPUType bool
for k, v := range y.VMOpts.QEMU.CPUType {
var qemuOpts limatype.QEMUOpts
if y.VMOpts[limatype.QEMU] != nil {
if err := limayaml.Convert(y.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", y.VMOpts[limatype.QEMU])
}
}
for k, v := range qemuOpts.CPUType {
if !slices.Contains(limatype.ArchTypes, *y.Arch) {
logrus.Warnf("field `vmOpts.qemu.cpuType` uses unsupported arch %q", k)
continue
Expand All @@ -460,7 +466,10 @@ func resolveCPUType(y *limatype.LimaYAML) string {
}
}
if overrideCPUType {
y.VMOpts.QEMU.CPUType = cpuType
qemuOpts.CPUType = cpuType
}
if y.VMOpts[limatype.QEMU] != nil {
y.VMOpts[limatype.QEMU] = qemuOpts
}

return cpuType[*y.Arch]
Expand Down Expand Up @@ -490,8 +499,12 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
if version.LessThan(softMin) {
logrus.Warnf("QEMU %v is too old, %v or later is recommended", version, softMin)
}
if y.VMOpts.QEMU.MinimumVersion != nil && version.LessThan(*semver.New(*y.VMOpts.QEMU.MinimumVersion)) {
logrus.Fatalf("QEMU %v is too old, template requires %q or later", version, *y.VMOpts.QEMU.MinimumVersion)
var qemuOpts limatype.QEMUOpts
if err := limayaml.Convert(y.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", y.VMOpts[limatype.QEMU])
}
if qemuOpts.MinimumVersion != nil && version.LessThan(*semver.New(*qemuOpts.MinimumVersion)) {
logrus.Fatalf("QEMU %v is too old, template requires %q or later", version, *qemuOpts.MinimumVersion)
}
}

Expand Down
51 changes: 32 additions & 19 deletions pkg/driver/qemu/qemu_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,15 @@ func validateConfig(ctx context.Context, cfg *limatype.LimaYAML) error {
}
}

if cfg.VMOpts.QEMU.MinimumVersion != nil {
if _, err := semver.NewVersion(*cfg.VMOpts.QEMU.MinimumVersion); err != nil {
return fmt.Errorf("field `vmOpts.qemu.minimumVersion` must be a semvar value, got %q: %w", *cfg.VMOpts.QEMU.MinimumVersion, err)
if cfg.VMOpts[limatype.QEMU] != nil {
var qemuOpts limatype.QEMUOpts
if err := limayaml.Convert(cfg.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
return err
}
if qemuOpts.MinimumVersion != nil {
if _, err := semver.NewVersion(*qemuOpts.MinimumVersion); err != nil {
return fmt.Errorf("field `vmOpts.qemu.minimumVersion` must be a semvar value, got %q: %w", *qemuOpts.MinimumVersion, err)
}
}
}

Expand Down Expand Up @@ -146,25 +152,32 @@ func (l *LimaQemuDriver) FillConfig(ctx context.Context, cfg *limatype.LimaYAML,
cfg.Video.VNC.Display = ptr.Of("127.0.0.1:0,to=9")
}

if cfg.VMOpts.QEMU.CPUType == nil {
cfg.VMOpts.QEMU.CPUType = limatype.CPUType{}
if cfg.VMOpts == nil {
cfg.VMOpts = limatype.VMOpts{}
}

//nolint:staticcheck // Migration of top-level CPUTYPE if specified
if len(cfg.CPUType) > 0 {
logrus.Warn("The top-level `cpuType` field is deprecated and will be removed in a future release. Please migrate to `vmOpts.qemu.cpuType`.")
for arch, v := range cfg.CPUType {
if v == "" {
continue
}
if existing, ok := cfg.VMOpts.QEMU.CPUType[arch]; ok && existing != "" && existing != v {
logrus.Warnf("Conflicting cpuType for arch %q: top-level=%q, vmOpts.qemu=%q; using vmOpts.qemu value", arch, v, existing)
continue
}
cfg.VMOpts.QEMU.CPUType[arch] = v
var qemuOpts limatype.QEMUOpts
if err := limayaml.Convert(cfg.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", cfg.VMOpts[limatype.QEMU])
}
if qemuOpts.CPUType == nil {
qemuOpts.CPUType = limatype.CPUType{}
}
//nolint:staticcheck // Migration of top-level CPUType if specified
for arch, v := range cfg.CPUType {
if v == "" {
continue
}
cfg.CPUType = nil
if existing, ok := qemuOpts.CPUType[arch]; ok && existing != "" && existing != v {
logrus.Warnf("Conflicting cpuType for arch %q: top-level=%q, vmOpts.qemu=%q; using vmOpts.qemu value", arch, v, existing)
continue
}
qemuOpts.CPUType[arch] = v
}
var opts any
if err := limayaml.Convert(qemuOpts, &opts, ""); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %+v", qemuOpts)
}
cfg.VMOpts[limatype.QEMU] = opts

mountTypesUnsupported := make(map[string]struct{})
for _, f := range cfg.MountTypesUnsupported {
Expand Down
9 changes: 8 additions & 1 deletion pkg/driver/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,14 @@ func attachFolderMounts(inst *limatype.Instance, vmConfig *vz.VirtualMachineConf
}
}

if *inst.Config.VMOpts.VZ.Rosetta.Enabled {
var vzOpts limatype.VZOpts
if inst.Config.VMOpts[limatype.VZ] != nil {
if err := limayaml.Convert(inst.Config.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", inst.Config.VMOpts[limatype.VZ])
}
}

if vzOpts.Rosetta.Enabled != nil && *vzOpts.Rosetta.Enabled {
logrus.Info("Setting up Rosetta share")
directorySharingDeviceConfig, err := createRosettaDirectoryShareConfiguration()
if err != nil {
Expand Down
42 changes: 31 additions & 11 deletions pkg/driver/vz/vz_driver_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,20 @@ func (l *LimaVzDriver) Configure(inst *limatype.Instance) *driver.ConfiguredDriv
}
}

var vzOpts limatype.VZOpts
if l.Instance.Config.VMOpts[limatype.VZ] != nil {
if err := limayaml.Convert(l.Instance.Config.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", l.Instance.Config.VMOpts[limatype.VZ])
}
}

if runtime.GOOS == "darwin" && limayaml.IsNativeArch(limatype.AARCH64) {
if l.Instance.Config.VMOpts.VZ.Rosetta.Enabled != nil {
l.rosettaEnabled = *l.Instance.Config.VMOpts.VZ.Rosetta.Enabled
if vzOpts.Rosetta.Enabled != nil {
l.rosettaEnabled = *vzOpts.Rosetta.Enabled
}
}
if l.Instance.Config.VMOpts.VZ.Rosetta.BinFmt != nil {
l.rosettaBinFmt = *l.Instance.Config.VMOpts.VZ.Rosetta.BinFmt
if vzOpts.Rosetta.BinFmt != nil {
l.rosettaBinFmt = *vzOpts.Rosetta.BinFmt
}

return &driver.ConfiguredDriver{
Expand All @@ -131,22 +138,35 @@ func (l *LimaVzDriver) FillConfig(ctx context.Context, cfg *limatype.LimaYAML, _
cfg.MountType = ptr.Of(limatype.VIRTIOFS)
}

var vzOpts limatype.VZOpts
if cfg.VMOpts[limatype.VZ] != nil {
if err := limayaml.Convert(cfg.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", cfg.VMOpts[limatype.VZ])
}
}

//nolint:staticcheck // Migration of top-level Rosetta if specified
if (cfg.VMOpts.VZ.Rosetta.Enabled == nil && cfg.VMOpts.VZ.Rosetta.BinFmt == nil) && (!isEmpty(cfg.Rosetta)) {
if (vzOpts.Rosetta.Enabled == nil && vzOpts.Rosetta.BinFmt == nil) && (!isEmpty(cfg.Rosetta)) {
logrus.Debug("Migrating top-level Rosetta configuration to vmOpts.vz.rosetta")
cfg.VMOpts.VZ.Rosetta = cfg.Rosetta
vzOpts.Rosetta = cfg.Rosetta
}
//nolint:staticcheck // Warning about both top-level and vmOpts.vz.Rosetta being set
if (cfg.VMOpts.VZ.Rosetta.Enabled != nil && cfg.VMOpts.VZ.Rosetta.BinFmt != nil) && (!isEmpty(cfg.Rosetta)) {
if (vzOpts.Rosetta.Enabled != nil && vzOpts.Rosetta.BinFmt != nil) && (!isEmpty(cfg.Rosetta)) {
logrus.Warn("Both top-level 'rosetta' and 'vmOpts.vz.rosetta' are configured. Using vmOpts.vz.rosetta. Top-level 'rosetta' is deprecated.")
}

if cfg.VMOpts.VZ.Rosetta.Enabled == nil {
cfg.VMOpts.VZ.Rosetta.Enabled = ptr.Of(false)
if vzOpts.Rosetta.Enabled == nil {
vzOpts.Rosetta.Enabled = ptr.Of(false)
}
if cfg.VMOpts.VZ.Rosetta.BinFmt == nil {
cfg.VMOpts.VZ.Rosetta.BinFmt = ptr.Of(false)
if vzOpts.Rosetta.BinFmt == nil {
vzOpts.Rosetta.BinFmt = ptr.Of(false)
}

var opts any
if err := limayaml.Convert(vzOpts, &opts, ""); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %+v", vzOpts)
}
cfg.VMOpts[limatype.VZ] = opts

return validateConfig(ctx, cfg)
}
Expand Down
23 changes: 17 additions & 6 deletions pkg/limatmpl/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/lima-vm/lima/v2/pkg/limatype"
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
"github.com/lima-vm/lima/v2/pkg/limayaml"
"github.com/lima-vm/lima/v2/pkg/version/versionutil"
"github.com/lima-vm/lima/v2/pkg/yqutil"
)
Expand Down Expand Up @@ -179,12 +180,22 @@ func (tmpl *Template) mergeBase(base *Template) error {
tmpl.copyField(minimumLimaVersion, minimumLimaVersion)
}
}
if tmpl.Config.VMOpts.QEMU.MinimumVersion != nil && base.Config.VMOpts.QEMU.MinimumVersion != nil {
tmplVersion := *semver.New(*tmpl.Config.VMOpts.QEMU.MinimumVersion)
baseVersion := *semver.New(*base.Config.VMOpts.QEMU.MinimumVersion)
if tmplVersion.LessThan(baseVersion) {
const minimumQEMUVersion = "vmOpts.qemu.minimumVersion"
tmpl.copyField(minimumQEMUVersion, minimumQEMUVersion)
if tmpl.Config.VMOpts[limatype.QEMU] != nil && base.Config.VMOpts[limatype.QEMU] != nil {
var tmplOpts limatype.QEMUOpts
if err := limayaml.Convert(tmpl.Config.VMOpts[limatype.QEMU], &tmplOpts, "vmOpts.qemu"); err != nil {
return err
}
var baseOpts limatype.QEMUOpts
if err := limayaml.Convert(base.Config.VMOpts[limatype.QEMU], &baseOpts, "vmOpts.qemu"); err != nil {
return err
}
if tmplOpts.MinimumVersion != nil && baseOpts.MinimumVersion != nil {
tmplVersion := *semver.New(*tmplOpts.MinimumVersion)
baseVersion := *semver.New(*baseOpts.MinimumVersion)
if tmplVersion.LessThan(baseVersion) {
const minimumQEMUVersion = "vmOpts.qemu.minimumVersion"
tmpl.copyField(minimumQEMUVersion, minimumQEMUVersion)
}
}
}
return nil
Expand Down
9 changes: 3 additions & 6 deletions pkg/limatype/lima_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type LimaYAML struct {
OS *OS `yaml:"os,omitempty" json:"os,omitempty" jsonschema:"nullable"`
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"nullable"`
Images []Image `yaml:"images,omitempty" json:"images,omitempty" jsonschema:"nullable"`
// Deprecated: Use VMOpts.Qemu.CPUType instead.
// Deprecated: Use vmOpts.qemu.cpuType instead.
CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty" jsonschema:"nullable"`
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty" jsonschema:"nullable"`
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty" jsonschema:"nullable"` // go-units.RAMInBytes
Expand Down Expand Up @@ -51,7 +51,7 @@ type LimaYAML struct {
// `useHostResolver` was deprecated in Lima v0.8.1, removed in Lima v0.14.0. Use `hostResolver.enabled` instead.
PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty" jsonschema:"nullable"`
CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
// Deprecated: Use VMOpts.VZ.Rosetta instead.
// Deprecated: Use vmOpts.vz.rosetta instead.
Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"`
Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty" jsonschema:"nullable"`
TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"`
Expand Down Expand Up @@ -110,10 +110,7 @@ type User struct {
UID *uint32 `yaml:"uid,omitempty" json:"uid,omitempty" jsonschema:"nullable"`
}

type VMOpts struct {
QEMU QEMUOpts `yaml:"qemu,omitempty" json:"qemu,omitempty"`
VZ VZOpts `yaml:"vz,omitempty" json:"vz,omitempty"`
}
type VMOpts map[VMType]any

type QEMUOpts struct {
MinimumVersion *string `yaml:"minimumVersion,omitempty" json:"minimumVersion,omitempty" jsonschema:"nullable"`
Expand Down
1 change: 1 addition & 0 deletions pkg/limayaml/limayaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func TestDefaultYAML(t *testing.T) {
y.Images = nil // remove default images
y.Mounts = nil // remove default mounts
y.Base = nil // remove default base templates
y.VMOpts = nil // remove default vmopts mapping
y.MinimumLimaVersion = nil // remove minimum Lima version
y.MountTypesUnsupported = nil // remove default workaround for kernel 6.9-6.11
t.Log(dumpJSON(t, y))
Expand Down
13 changes: 13 additions & 0 deletions pkg/limayaml/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,16 @@ func Unmarshal(data []byte, y *limatype.LimaYAML, comment string) error {
}
return nil
}

// Convert converts from x to y, using YAML.
func Convert(x, y any, comment string) error {
b, err := yaml.Marshal(x)
if err != nil {
return err
}
err = yaml.Unmarshal(b, y)
if err != nil {
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
}
return nil
}
Loading
Loading