Skip to content

Commit 66cf250

Browse files
authored
Merge pull request #3899 from afbjorklund/vmopts-qemu
Convert limatype.VMOpts to an abstract map
2 parents e49932f + f505499 commit 66cf250

File tree

11 files changed

+256
-34
lines changed

11 files changed

+256
-34
lines changed

pkg/driver/qemu/qemu.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,11 @@ func defaultCPUType() limatype.CPUType {
449449
func resolveCPUType(y *limatype.LimaYAML) string {
450450
cpuType := defaultCPUType()
451451
var overrideCPUType bool
452-
for k, v := range y.VMOpts.QEMU.CPUType {
452+
var qemuOpts limatype.QEMUOpts
453+
if err := limayaml.Convert(y.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
454+
logrus.WithError(err).Warnf("Couldn't convert %q", y.VMOpts[limatype.QEMU])
455+
}
456+
for k, v := range qemuOpts.CPUType {
453457
if !slices.Contains(limatype.ArchTypes, *y.Arch) {
454458
logrus.Warnf("field `vmOpts.qemu.cpuType` uses unsupported arch %q", k)
455459
continue
@@ -460,7 +464,11 @@ func resolveCPUType(y *limatype.LimaYAML) string {
460464
}
461465
}
462466
if overrideCPUType {
463-
y.VMOpts.QEMU.CPUType = cpuType
467+
qemuOpts.CPUType = cpuType
468+
if y.VMOpts == nil {
469+
y.VMOpts = limatype.VMOpts{}
470+
}
471+
y.VMOpts[limatype.QEMU] = qemuOpts
464472
}
465473

466474
return cpuType[*y.Arch]
@@ -490,8 +498,12 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
490498
if version.LessThan(softMin) {
491499
logrus.Warnf("QEMU %v is too old, %v or later is recommended", version, softMin)
492500
}
493-
if y.VMOpts.QEMU.MinimumVersion != nil && version.LessThan(*semver.New(*y.VMOpts.QEMU.MinimumVersion)) {
494-
logrus.Fatalf("QEMU %v is too old, template requires %q or later", version, *y.VMOpts.QEMU.MinimumVersion)
501+
var qemuOpts limatype.QEMUOpts
502+
if err := limayaml.Convert(y.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
503+
logrus.WithError(err).Warnf("Couldn't convert %q", y.VMOpts[limatype.QEMU])
504+
}
505+
if qemuOpts.MinimumVersion != nil && version.LessThan(*semver.New(*qemuOpts.MinimumVersion)) {
506+
logrus.Fatalf("QEMU %v is too old, template requires %q or later", version, *qemuOpts.MinimumVersion)
495507
}
496508
}
497509

pkg/driver/qemu/qemu_driver.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,13 @@ func validateConfig(cfg *limatype.LimaYAML) error {
104104
}
105105
}
106106

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

@@ -154,8 +158,12 @@ func (l *LimaQemuDriver) FillConfig(_ context.Context, cfg *limatype.LimaYAML, f
154158
cfg.Video.VNC.Display = ptr.Of("127.0.0.1:0,to=9")
155159
}
156160

157-
if cfg.VMOpts.QEMU.CPUType == nil {
158-
cfg.VMOpts.QEMU.CPUType = limatype.CPUType{}
161+
var qemuOpts limatype.QEMUOpts
162+
if err := limayaml.Convert(cfg.VMOpts[limatype.QEMU], &qemuOpts, "vmOpts.qemu"); err != nil {
163+
logrus.WithError(err).Warnf("Couldn't convert %q", cfg.VMOpts[limatype.QEMU])
164+
}
165+
if qemuOpts.CPUType == nil {
166+
qemuOpts.CPUType = limatype.CPUType{}
159167
}
160168

161169
//nolint:staticcheck // Migration of top-level CPUTYPE if specified
@@ -165,13 +173,22 @@ func (l *LimaQemuDriver) FillConfig(_ context.Context, cfg *limatype.LimaYAML, f
165173
if v == "" {
166174
continue
167175
}
168-
if existing, ok := cfg.VMOpts.QEMU.CPUType[arch]; ok && existing != "" && existing != v {
176+
if existing, ok := qemuOpts.CPUType[arch]; ok && existing != "" && existing != v {
169177
logrus.Warnf("Conflicting cpuType for arch %q: top-level=%q, vmOpts.qemu=%q; using vmOpts.qemu value", arch, v, existing)
170178
continue
171179
}
172-
cfg.VMOpts.QEMU.CPUType[arch] = v
180+
qemuOpts.CPUType[arch] = v
173181
}
174182
cfg.CPUType = nil
183+
184+
var opts any
185+
if err := limayaml.Convert(qemuOpts, &opts, ""); err != nil {
186+
logrus.WithError(err).Warnf("Couldn't convert %+v", qemuOpts)
187+
}
188+
if cfg.VMOpts == nil {
189+
cfg.VMOpts = limatype.VMOpts{}
190+
}
191+
cfg.VMOpts[limatype.QEMU] = opts
175192
}
176193

177194
mountTypesUnsupported := make(map[string]struct{})

pkg/driver/vz/vm_darwin.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,12 @@ func attachFolderMounts(inst *limatype.Instance, vmConfig *vz.VirtualMachineConf
602602
}
603603
}
604604

605-
if *inst.Config.VMOpts.VZ.Rosetta.Enabled {
605+
var vzOpts limatype.VZOpts
606+
if err := limayaml.Convert(inst.Config.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
607+
logrus.WithError(err).Warnf("Couldn't convert %q", inst.Config.VMOpts[limatype.VZ])
608+
}
609+
610+
if vzOpts.Rosetta.Enabled != nil && *vzOpts.Rosetta.Enabled {
606611
logrus.Info("Setting up Rosetta share")
607612
directorySharingDeviceConfig, err := createRosettaDirectoryShareConfiguration()
608613
if err != nil {

pkg/driver/vz/vz_driver_darwin.go

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,20 @@ func (l *LimaVzDriver) Configure(inst *limatype.Instance) *driver.ConfiguredDriv
108108
}
109109
}
110110

111+
var vzOpts limatype.VZOpts
112+
if l.Instance.Config.VMOpts[limatype.VZ] != nil {
113+
if err := limayaml.Convert(l.Instance.Config.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
114+
logrus.WithError(err).Warnf("Couldn't convert %q", l.Instance.Config.VMOpts[limatype.VZ])
115+
}
116+
}
117+
111118
if runtime.GOOS == "darwin" && limayaml.IsNativeArch(limatype.AARCH64) {
112-
if l.Instance.Config.VMOpts.VZ.Rosetta.Enabled != nil {
113-
l.rosettaEnabled = *l.Instance.Config.VMOpts.VZ.Rosetta.Enabled
119+
if vzOpts.Rosetta.Enabled != nil {
120+
l.rosettaEnabled = *vzOpts.Rosetta.Enabled
114121
}
115122
}
116-
if l.Instance.Config.VMOpts.VZ.Rosetta.BinFmt != nil {
117-
l.rosettaBinFmt = *l.Instance.Config.VMOpts.VZ.Rosetta.BinFmt
123+
if vzOpts.Rosetta.BinFmt != nil {
124+
l.rosettaBinFmt = *vzOpts.Rosetta.BinFmt
118125
}
119126

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

141+
var vzOpts limatype.VZOpts
142+
if err := limayaml.Convert(cfg.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
143+
logrus.WithError(err).Warnf("Couldn't convert %q", cfg.VMOpts[limatype.VZ])
144+
}
145+
134146
//nolint:staticcheck // Migration of top-level Rosetta if specified
135-
if (cfg.VMOpts.VZ.Rosetta.Enabled == nil && cfg.VMOpts.VZ.Rosetta.BinFmt == nil) && (!isEmpty(cfg.Rosetta)) {
147+
if (vzOpts.Rosetta.Enabled == nil && vzOpts.Rosetta.BinFmt == nil) && (!isEmpty(cfg.Rosetta)) {
136148
logrus.Debug("Migrating top-level Rosetta configuration to vmOpts.vz.rosetta")
137-
cfg.VMOpts.VZ.Rosetta = cfg.Rosetta
149+
vzOpts.Rosetta = cfg.Rosetta
138150
}
139151
//nolint:staticcheck // Warning about both top-level and vmOpts.vz.Rosetta being set
140-
if (cfg.VMOpts.VZ.Rosetta.Enabled != nil && cfg.VMOpts.VZ.Rosetta.BinFmt != nil) && (!isEmpty(cfg.Rosetta)) {
152+
if (vzOpts.Rosetta.Enabled != nil && vzOpts.Rosetta.BinFmt != nil) && (!isEmpty(cfg.Rosetta)) {
141153
logrus.Warn("Both top-level 'rosetta' and 'vmOpts.vz.rosetta' are configured. Using vmOpts.vz.rosetta. Top-level 'rosetta' is deprecated.")
142154
}
143155

144-
if cfg.VMOpts.VZ.Rosetta.Enabled == nil {
145-
cfg.VMOpts.VZ.Rosetta.Enabled = ptr.Of(false)
156+
if vzOpts.Rosetta.Enabled == nil {
157+
vzOpts.Rosetta.Enabled = ptr.Of(false)
158+
}
159+
if vzOpts.Rosetta.BinFmt == nil {
160+
vzOpts.Rosetta.BinFmt = ptr.Of(false)
161+
}
162+
163+
var opts any
164+
if err := limayaml.Convert(vzOpts, &opts, ""); err != nil {
165+
logrus.WithError(err).Warnf("Couldn't convert %+v", vzOpts)
146166
}
147-
if cfg.VMOpts.VZ.Rosetta.BinFmt == nil {
148-
cfg.VMOpts.VZ.Rosetta.BinFmt = ptr.Of(false)
167+
if cfg.VMOpts == nil {
168+
cfg.VMOpts = limatype.VMOpts{}
149169
}
170+
cfg.VMOpts[limatype.VZ] = opts
150171

151172
return validateConfig(ctx, cfg)
152173
}

pkg/limatmpl/embed.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/lima-vm/lima/v2/pkg/limatype"
2222
"github.com/lima-vm/lima/v2/pkg/limatype/dirnames"
2323
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
24+
"github.com/lima-vm/lima/v2/pkg/limayaml"
2425
"github.com/lima-vm/lima/v2/pkg/version/versionutil"
2526
"github.com/lima-vm/lima/v2/pkg/yqutil"
2627
)
@@ -179,9 +180,17 @@ func (tmpl *Template) mergeBase(base *Template) error {
179180
tmpl.copyField(minimumLimaVersion, minimumLimaVersion)
180181
}
181182
}
182-
if tmpl.Config.VMOpts.QEMU.MinimumVersion != nil && base.Config.VMOpts.QEMU.MinimumVersion != nil {
183-
tmplVersion := *semver.New(*tmpl.Config.VMOpts.QEMU.MinimumVersion)
184-
baseVersion := *semver.New(*base.Config.VMOpts.QEMU.MinimumVersion)
183+
var tmplOpts limatype.QEMUOpts
184+
if err := limayaml.Convert(tmpl.Config.VMOpts[limatype.QEMU], &tmplOpts, "vmOpts.qemu"); err != nil {
185+
return err
186+
}
187+
var baseOpts limatype.QEMUOpts
188+
if err := limayaml.Convert(base.Config.VMOpts[limatype.QEMU], &baseOpts, "vmOpts.qemu"); err != nil {
189+
return err
190+
}
191+
if tmplOpts.MinimumVersion != nil && baseOpts.MinimumVersion != nil {
192+
tmplVersion := *semver.New(*tmplOpts.MinimumVersion)
193+
baseVersion := *semver.New(*baseOpts.MinimumVersion)
185194
if tmplVersion.LessThan(baseVersion) {
186195
const minimumQEMUVersion = "vmOpts.qemu.minimumVersion"
187196
tmpl.copyField(minimumQEMUVersion, minimumQEMUVersion)

pkg/limatype/lima_yaml.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type LimaYAML struct {
2020
OS *OS `yaml:"os,omitempty" json:"os,omitempty" jsonschema:"nullable"`
2121
Arch *Arch `yaml:"arch,omitempty" json:"arch,omitempty" jsonschema:"nullable"`
2222
Images []Image `yaml:"images,omitempty" json:"images,omitempty" jsonschema:"nullable"`
23-
// Deprecated: Use VMOpts.Qemu.CPUType instead.
23+
// Deprecated: Use vmOpts.qemu.cpuType instead.
2424
CPUType CPUType `yaml:"cpuType,omitempty" json:"cpuType,omitempty" jsonschema:"nullable"`
2525
CPUs *int `yaml:"cpus,omitempty" json:"cpus,omitempty" jsonschema:"nullable"`
2626
Memory *string `yaml:"memory,omitempty" json:"memory,omitempty" jsonschema:"nullable"` // go-units.RAMInBytes
@@ -51,7 +51,7 @@ type LimaYAML struct {
5151
// `useHostResolver` was deprecated in Lima v0.8.1, removed in Lima v0.14.0. Use `hostResolver.enabled` instead.
5252
PropagateProxyEnv *bool `yaml:"propagateProxyEnv,omitempty" json:"propagateProxyEnv,omitempty" jsonschema:"nullable"`
5353
CACertificates CACertificates `yaml:"caCerts,omitempty" json:"caCerts,omitempty"`
54-
// Deprecated: Use VMOpts.VZ.Rosetta instead.
54+
// Deprecated: Use vmOpts.vz.rosetta instead.
5555
Rosetta Rosetta `yaml:"rosetta,omitempty" json:"rosetta,omitempty"`
5656
Plain *bool `yaml:"plain,omitempty" json:"plain,omitempty" jsonschema:"nullable"`
5757
TimeZone *string `yaml:"timezone,omitempty" json:"timezone,omitempty" jsonschema:"nullable"`
@@ -110,10 +110,7 @@ type User struct {
110110
UID *uint32 `yaml:"uid,omitempty" json:"uid,omitempty" jsonschema:"nullable"`
111111
}
112112

113-
type VMOpts struct {
114-
QEMU QEMUOpts `yaml:"qemu,omitempty" json:"qemu,omitempty"`
115-
VZ VZOpts `yaml:"vz,omitempty" json:"vz,omitempty"`
116-
}
113+
type VMOpts map[VMType]any
117114

118115
type QEMUOpts struct {
119116
MinimumVersion *string `yaml:"minimumVersion,omitempty" json:"minimumVersion,omitempty" jsonschema:"nullable"`

pkg/limayaml/limayaml_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func TestDefaultYAML(t *testing.T) {
5151
y.Images = nil // remove default images
5252
y.Mounts = nil // remove default mounts
5353
y.Base = nil // remove default base templates
54+
y.VMOpts = nil // remove default vmopts mapping
5455
y.MinimumLimaVersion = nil // remove minimum Lima version
5556
y.MountTypesUnsupported = nil // remove default workaround for kernel 6.9-6.11
5657
t.Log(dumpJSON(t, y))

pkg/limayaml/marshal.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,20 @@ func Unmarshal(data []byte, y *limatype.LimaYAML, comment string) error {
8282
}
8383
return nil
8484
}
85+
86+
// Convert converts from x to y, using YAML.
87+
// If x is nil, then y is left unmodified.
88+
func Convert(x, y any, comment string) error {
89+
if x == nil {
90+
return nil
91+
}
92+
b, err := yaml.Marshal(x)
93+
if err != nil {
94+
return err
95+
}
96+
err = yaml.Unmarshal(b, y)
97+
if err != nil {
98+
return fmt.Errorf("failed to unmarshal YAML (%s): %w", comment, err)
99+
}
100+
return nil
101+
}

0 commit comments

Comments
 (0)