Skip to content

Commit 75b69b8

Browse files
authored
feat: make Virtualization Framework default (runfinch#956)
1 parent 7b68216 commit 75b69b8

14 files changed

+378
-96
lines changed

Diff for: README.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,24 @@ creds_helpers:
150150
additional_directories:
151151
# the path of each additional directory.
152152
- path: /Volumes
153-
# vmType (Experimental): sets which Hypervisor to use to launch the VM. (optional)
153+
# vmType: sets which Hypervisor to use to launch the VM. (optional)
154154
# Only takes effect when a new VM is launched (only on vm init).
155155
# One of: "qemu", "vz".
156-
# - "qemu" (default): Uses QEMU as the Hypervisor.
157-
# - "vz": Uses Virtualization.framework as the Hypervisor.
158-
vmType: "qemu"
159-
# rosetta (Experimental): sets whether to enable Rosetta as the binfmt_misc handler inside the VM. (optional)
156+
# - "qemu": Uses QEMU as the Hypervisor.
157+
# - "vz" (default): Uses Virtualization.framework as the Hypervisor.
158+
#
159+
# NOTE: prior to version 1.2.0, "qemu" was the default, and it will still be the default for
160+
# macOS versions that do not support Virtualization.framework (pre-13.0.0).
161+
vmType: "vz"
162+
# rosetta: sets whether to enable Rosetta as the binfmt_misc handler for x86_64
163+
# binaries inside the VM, as an alternative to qemu user mode emulation. (optional)
160164
# Only takes effect when a new VM is launched (only on vm init).
161165
# Only available when using vmType "vz" on Apple Silicon running macOS 13+.
162166
# If true, also sets vmType to "vz".
167+
#
168+
# NOTE: while Rosetta is generally faster than qemu user mode emulation, it causes
169+
# some performance regressions, as noted in this issue:
170+
# https://github.com/lima-vm/lima/issues/1269
163171
rosetta: false
164172
```
165173

Diff for: cmd/finch/main.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,29 @@ func xmain(logger flog.Logger,
5656
if err != nil {
5757
return fmt.Errorf("failed to get finch root path: %w", err)
5858
}
59-
fc, err := config.Load(fs, fp.ConfigFilePath(finchRootPath), logger, loadCfgDeps, mem)
59+
ecc := command.NewExecCmdCreator()
60+
fc, err := config.Load(
61+
fs,
62+
fp.ConfigFilePath(finchRootPath),
63+
logger,
64+
loadCfgDeps,
65+
mem,
66+
ecc,
67+
)
6068
if err != nil {
6169
return fmt.Errorf("failed to load config: %w", err)
6270
}
6371

64-
return newApp(logger, fp, fs, fc, stdOut, home, finchRootPath).Execute()
72+
return newApp(
73+
logger,
74+
fp,
75+
fs,
76+
fc,
77+
stdOut,
78+
home,
79+
finchRootPath,
80+
ecc,
81+
).Execute()
6582
}
6683

6784
var newApp = func(
@@ -72,6 +89,7 @@ var newApp = func(
7289
stdOut io.Writer,
7390
home,
7491
finchRootPath string,
92+
ecc command.Creator,
7593
) *cobra.Command {
7694
usage := fmt.Sprintf("%v <command>", finchRootCmd)
7795
rootCmd := &cobra.Command{
@@ -93,7 +111,6 @@ var newApp = func(
93111
return nil
94112
}
95113

96-
ecc := command.NewExecCmdCreator()
97114
lcc := command.NewLimaCmdCreator(ecc,
98115
logger,
99116
fp.LimaHomePath(),
@@ -129,7 +146,7 @@ var newApp = func(
129146

130147
func initializeNerdctlCommands(
131148
lcc command.LimaCmdCreator,
132-
ecc *command.ExecCmdCreator,
149+
ecc command.Creator,
133150
logger flog.Logger,
134151
fs afero.Fs,
135152
fc *config.Finch,

Diff for: cmd/finch/main_darwin.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
)
2020

2121
func dependencies(
22-
ecc *command.ExecCmdCreator,
22+
ecc command.Creator,
2323
fc *config.Finch,
2424
fp path.Finch,
2525
fs afero.Fs,

Diff for: cmd/finch/main_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,11 @@ func TestNewApp(t *testing.T) {
193193
fp := path.Finch("")
194194
fs := afero.NewMemMapFs()
195195
stdOut := os.Stdout
196+
ecc := mocks.NewCommandCreator(ctrl)
196197

197198
require.NoError(t, afero.WriteFile(fs, "/real/config.yaml", []byte(configStr), 0o600))
198199

199-
cmd := newApp(l, fp, fs, &config.Finch{}, stdOut, "", "")
200+
cmd := newApp(l, fp, fs, &config.Finch{}, stdOut, "", "", ecc)
200201

201202
assert.Equal(t, cmd.Name(), finchRootCmd)
202203
assert.Equal(t, cmd.Version, version.Version)

Diff for: cmd/finch/main_windows.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import (
2020
)
2121

2222
func dependencies(
23-
ecc *command.ExecCmdCreator,
23+
ecc command.Creator,
2424
fc *config.Finch,
2525
fp path.Finch,
2626
fs afero.Fs,

Diff for: cmd/finch/virtual_machine.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func virtualMachineCommands(
100100
logger flog.Logger,
101101
fp path.Finch,
102102
lcc command.LimaCmdCreator,
103-
ecc *command.ExecCmdCreator,
103+
ecc command.Creator,
104104
fs afero.Fs,
105105
fc *config.Finch,
106106
home string,

Diff for: e2e/vm/virtualization_framework_rosetta_darwin_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@ import (
1818
"github.com/runfinch/finch/pkg/config"
1919
)
2020

21-
var testVirtualizationFrameworkAndRosetta = func(o *option.Option, installed bool) {
22-
ginkgo.Describe("Virtualization framework", ginkgo.Ordered, func() {
21+
var testNonDefaultOptions = func(o *option.Option, installed bool) {
22+
ginkgo.Describe("Non-default options", ginkgo.Ordered, func() {
2323
supportsVz, supportsVzErr := config.SupportsVirtualizationFramework(finch_cmd.NewExecCmdCreator())
2424
gomega.Expect(supportsVzErr).ShouldNot(gomega.HaveOccurred())
2525

26-
ginkgo.Describe("Virtualization framework", ginkgo.Ordered, func() {
26+
ginkgo.Describe("QEMU", ginkgo.Ordered, func() {
2727
ginkgo.BeforeAll(func() {
2828
if !supportsVz {
29-
ginkgo.Skip("Skipping because system does not support Virtualization.framework")
29+
ginkgo.Skip("Skipping because default for this system is already QEMU")
3030
}
3131

3232
resetVM(o)
3333
resetDisks(o, installed)
34-
writeFile(finchConfigFilePath, []byte("memory: 4GiB\ncpus: 6\nvmType: vz\nrosetta: false"))
34+
writeFile(finchConfigFilePath, []byte("memory: 4GiB\ncpus: 6\nvmType: qemu\nrosetta: false"))
3535
// vm init with VZ set sometimes takes 2 minutes just to convert the disk to raw
3636
command.New(o, virtualMachineRootCmd, "init").WithoutCheckingExitCode().WithTimeoutInSeconds(240).Run()
3737
tests.SetupLocalRegistry(o)
@@ -46,7 +46,7 @@ var testVirtualizationFrameworkAndRosetta = func(o *option.Option, installed boo
4646
tests.Port(o)
4747
})
4848

49-
ginkgo.Describe("Virtualization framework and Rosetta", ginkgo.Ordered, func() {
49+
ginkgo.Describe("Virtualization framework with Rosetta", ginkgo.Ordered, func() {
5050
ginkgo.BeforeAll(func() {
5151
if !supportsVz || runtime.GOOS != "darwin" || runtime.GOARCH != "arm64" {
5252
ginkgo.Skip("Skipping because system does not support Rosetta")

Diff for: e2e/vm/vm_darwin_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestVM(t *testing.T) {
6666
testConfig(o, *e2e.Installed)
6767
testFinchConfigFile(o)
6868
testVersion(o)
69-
testVirtualizationFrameworkAndRosetta(o, *e2e.Installed)
69+
testNonDefaultOptions(o, *e2e.Installed)
7070
testSupportBundle(o)
7171
testCredHelper(o, *e2e.Installed, *e2e.Registry)
7272
testSoci(o, *e2e.Installed)

Diff for: pkg/config/config.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/spf13/afero"
1919
"gopkg.in/yaml.v3"
2020

21+
"github.com/runfinch/finch/pkg/command"
2122
"github.com/runfinch/finch/pkg/flog"
2223
"github.com/runfinch/finch/pkg/fmemory"
2324
"github.com/runfinch/finch/pkg/system"
@@ -135,12 +136,19 @@ func ensureConfigDir(fs afero.Fs, path string, log flog.Logger) error {
135136
}
136137

137138
// Load loads Finch's configuration from a YAML file and initializes default values.
138-
func Load(fs afero.Fs, cfgPath string, log flog.Logger, systemDeps LoadSystemDeps, mem fmemory.Memory) (*Finch, error) {
139+
func Load(
140+
fs afero.Fs,
141+
cfgPath string,
142+
log flog.Logger,
143+
systemDeps LoadSystemDeps,
144+
mem fmemory.Memory,
145+
ecc command.Creator,
146+
) (*Finch, error) {
139147
b, err := afero.ReadFile(fs, cfgPath)
140148
if err != nil {
141149
if errors.Is(err, afero.ErrFileNotFound) {
142150
log.Infof("Using default values due to missing config file at %q", cfgPath)
143-
defCfg := applyDefaults(&Finch{}, systemDeps, mem)
151+
defCfg := applyDefaults(&Finch{}, systemDeps, mem, ecc)
144152
if err := ensureConfigDir(fs, filepath.Dir(cfgPath), log); err != nil {
145153
return nil, fmt.Errorf("failed to ensure %q directory: %w", cfgPath, err)
146154
}
@@ -157,7 +165,7 @@ func Load(fs afero.Fs, cfgPath string, log flog.Logger, systemDeps LoadSystemDep
157165
return nil, fmt.Errorf("failed to unmarshal config file: %w", err)
158166
}
159167

160-
defCfg := applyDefaults(&cfg, systemDeps, mem)
168+
defCfg := applyDefaults(&cfg, systemDeps, mem, ecc)
161169
if err := writeConfig(defCfg, fs, cfgPath); err != nil {
162170
return nil, err
163171
}

0 commit comments

Comments
 (0)