Skip to content
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
20 changes: 16 additions & 4 deletions pkg/driver/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,11 @@ 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 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 +464,11 @@ func resolveCPUType(y *limatype.LimaYAML) string {
}
}
if overrideCPUType {
y.VMOpts.QEMU.CPUType = cpuType
qemuOpts.CPUType = cpuType
if y.VMOpts == nil {
y.VMOpts = limatype.VMOpts{}
}
y.VMOpts[limatype.QEMU] = qemuOpts
}

return cpuType[*y.Arch]
Expand Down Expand Up @@ -490,8 +498,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
31 changes: 24 additions & 7 deletions pkg/driver/qemu/qemu_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,13 @@ func validateConfig(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)
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 @@ -154,8 +158,12 @@ func (l *LimaQemuDriver) FillConfig(_ context.Context, cfg *limatype.LimaYAML, f
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{}
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
Expand All @@ -165,13 +173,22 @@ func (l *LimaQemuDriver) FillConfig(_ context.Context, cfg *limatype.LimaYAML, f
if v == "" {
continue
}
if existing, ok := cfg.VMOpts.QEMU.CPUType[arch]; ok && existing != "" && existing != v {
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
}
cfg.VMOpts.QEMU.CPUType[arch] = v
qemuOpts.CPUType[arch] = v
}
cfg.CPUType = nil

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

mountTypesUnsupported := make(map[string]struct{})
Expand Down
7 changes: 6 additions & 1 deletion pkg/driver/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,12 @@ func attachFolderMounts(inst *limatype.Instance, vmConfig *vz.VirtualMachineConf
}
}

if *inst.Config.VMOpts.VZ.Rosetta.Enabled {
var vzOpts limatype.VZOpts
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
43 changes: 32 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,36 @@ func (l *LimaVzDriver) FillConfig(ctx context.Context, cfg *limatype.LimaYAML, _
cfg.MountType = ptr.Of(limatype.VIRTIOFS)
}

var vzOpts limatype.VZOpts
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 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)
}
if cfg.VMOpts.VZ.Rosetta.BinFmt == nil {
cfg.VMOpts.VZ.Rosetta.BinFmt = ptr.Of(false)
if cfg.VMOpts == nil {
cfg.VMOpts = limatype.VMOpts{}
}
cfg.VMOpts[limatype.VZ] = opts

return validateConfig(ctx, cfg)
}
Expand Down
15 changes: 12 additions & 3 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,9 +180,17 @@ 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)
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)
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
17 changes: 17 additions & 0 deletions pkg/limayaml/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,20 @@ func Unmarshal(data []byte, y *limatype.LimaYAML, comment string) error {
}
return nil
}

// Convert converts from x to y, using YAML.
// If x is nil, then y is left unmodified.
func Convert(x, y any, comment string) error {
if x == nil {
return nil
}
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