Skip to content

Commit

Permalink
feat: make Virtualization Framework default (#956)
Browse files Browse the repository at this point in the history
  • Loading branch information
pendo324 committed May 23, 2024
1 parent 7b68216 commit 75b69b8
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 96 deletions.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,16 +150,24 @@ creds_helpers:
additional_directories:
# the path of each additional directory.
- path: /Volumes
# vmType (Experimental): sets which Hypervisor to use to launch the VM. (optional)
# vmType: sets which Hypervisor to use to launch the VM. (optional)
# Only takes effect when a new VM is launched (only on vm init).
# One of: "qemu", "vz".
# - "qemu" (default): Uses QEMU as the Hypervisor.
# - "vz": Uses Virtualization.framework as the Hypervisor.
vmType: "qemu"
# rosetta (Experimental): sets whether to enable Rosetta as the binfmt_misc handler inside the VM. (optional)
# - "qemu": Uses QEMU as the Hypervisor.
# - "vz" (default): Uses Virtualization.framework as the Hypervisor.
#
# NOTE: prior to version 1.2.0, "qemu" was the default, and it will still be the default for
# macOS versions that do not support Virtualization.framework (pre-13.0.0).
vmType: "vz"
# rosetta: sets whether to enable Rosetta as the binfmt_misc handler for x86_64
# binaries inside the VM, as an alternative to qemu user mode emulation. (optional)
# Only takes effect when a new VM is launched (only on vm init).
# Only available when using vmType "vz" on Apple Silicon running macOS 13+.
# If true, also sets vmType to "vz".
#
# NOTE: while Rosetta is generally faster than qemu user mode emulation, it causes
# some performance regressions, as noted in this issue:
# https://github.com/lima-vm/lima/issues/1269
rosetta: false
```

Expand Down
25 changes: 21 additions & 4 deletions cmd/finch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,29 @@ func xmain(logger flog.Logger,
if err != nil {
return fmt.Errorf("failed to get finch root path: %w", err)
}
fc, err := config.Load(fs, fp.ConfigFilePath(finchRootPath), logger, loadCfgDeps, mem)
ecc := command.NewExecCmdCreator()
fc, err := config.Load(
fs,
fp.ConfigFilePath(finchRootPath),
logger,
loadCfgDeps,
mem,
ecc,
)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}

return newApp(logger, fp, fs, fc, stdOut, home, finchRootPath).Execute()
return newApp(
logger,
fp,
fs,
fc,
stdOut,
home,
finchRootPath,
ecc,
).Execute()
}

var newApp = func(
Expand All @@ -72,6 +89,7 @@ var newApp = func(
stdOut io.Writer,
home,
finchRootPath string,
ecc command.Creator,
) *cobra.Command {
usage := fmt.Sprintf("%v <command>", finchRootCmd)
rootCmd := &cobra.Command{
Expand All @@ -93,7 +111,6 @@ var newApp = func(
return nil
}

ecc := command.NewExecCmdCreator()
lcc := command.NewLimaCmdCreator(ecc,
logger,
fp.LimaHomePath(),
Expand Down Expand Up @@ -129,7 +146,7 @@ var newApp = func(

func initializeNerdctlCommands(
lcc command.LimaCmdCreator,
ecc *command.ExecCmdCreator,
ecc command.Creator,
logger flog.Logger,
fs afero.Fs,
fc *config.Finch,
Expand Down
2 changes: 1 addition & 1 deletion cmd/finch/main_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
)

func dependencies(
ecc *command.ExecCmdCreator,
ecc command.Creator,
fc *config.Finch,
fp path.Finch,
fs afero.Fs,
Expand Down
3 changes: 2 additions & 1 deletion cmd/finch/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,11 @@ func TestNewApp(t *testing.T) {
fp := path.Finch("")
fs := afero.NewMemMapFs()
stdOut := os.Stdout
ecc := mocks.NewCommandCreator(ctrl)

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

cmd := newApp(l, fp, fs, &config.Finch{}, stdOut, "", "")
cmd := newApp(l, fp, fs, &config.Finch{}, stdOut, "", "", ecc)

assert.Equal(t, cmd.Name(), finchRootCmd)
assert.Equal(t, cmd.Version, version.Version)
Expand Down
2 changes: 1 addition & 1 deletion cmd/finch/main_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
)

func dependencies(
ecc *command.ExecCmdCreator,
ecc command.Creator,
fc *config.Finch,
fp path.Finch,
fs afero.Fs,
Expand Down
2 changes: 1 addition & 1 deletion cmd/finch/virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func virtualMachineCommands(
logger flog.Logger,
fp path.Finch,
lcc command.LimaCmdCreator,
ecc *command.ExecCmdCreator,
ecc command.Creator,
fs afero.Fs,
fc *config.Finch,
home string,
Expand Down
12 changes: 6 additions & 6 deletions e2e/vm/virtualization_framework_rosetta_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ import (
"github.com/runfinch/finch/pkg/config"
)

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

ginkgo.Describe("Virtualization framework", ginkgo.Ordered, func() {
ginkgo.Describe("QEMU", ginkgo.Ordered, func() {
ginkgo.BeforeAll(func() {
if !supportsVz {
ginkgo.Skip("Skipping because system does not support Virtualization.framework")
ginkgo.Skip("Skipping because default for this system is already QEMU")
}

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

ginkgo.Describe("Virtualization framework and Rosetta", ginkgo.Ordered, func() {
ginkgo.Describe("Virtualization framework with Rosetta", ginkgo.Ordered, func() {
ginkgo.BeforeAll(func() {
if !supportsVz || runtime.GOOS != "darwin" || runtime.GOARCH != "arm64" {
ginkgo.Skip("Skipping because system does not support Rosetta")
Expand Down
2 changes: 1 addition & 1 deletion e2e/vm/vm_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestVM(t *testing.T) {
testConfig(o, *e2e.Installed)
testFinchConfigFile(o)
testVersion(o)
testVirtualizationFrameworkAndRosetta(o, *e2e.Installed)
testNonDefaultOptions(o, *e2e.Installed)
testSupportBundle(o)
testCredHelper(o, *e2e.Installed, *e2e.Registry)
testSoci(o, *e2e.Installed)
Expand Down
14 changes: 11 additions & 3 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/spf13/afero"
"gopkg.in/yaml.v3"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/flog"
"github.com/runfinch/finch/pkg/fmemory"
"github.com/runfinch/finch/pkg/system"
Expand Down Expand Up @@ -135,12 +136,19 @@ func ensureConfigDir(fs afero.Fs, path string, log flog.Logger) error {
}

// Load loads Finch's configuration from a YAML file and initializes default values.
func Load(fs afero.Fs, cfgPath string, log flog.Logger, systemDeps LoadSystemDeps, mem fmemory.Memory) (*Finch, error) {
func Load(
fs afero.Fs,
cfgPath string,
log flog.Logger,
systemDeps LoadSystemDeps,
mem fmemory.Memory,
ecc command.Creator,
) (*Finch, error) {
b, err := afero.ReadFile(fs, cfgPath)
if err != nil {
if errors.Is(err, afero.ErrFileNotFound) {
log.Infof("Using default values due to missing config file at %q", cfgPath)
defCfg := applyDefaults(&Finch{}, systemDeps, mem)
defCfg := applyDefaults(&Finch{}, systemDeps, mem, ecc)
if err := ensureConfigDir(fs, filepath.Dir(cfgPath), log); err != nil {
return nil, fmt.Errorf("failed to ensure %q directory: %w", cfgPath, err)
}
Expand All @@ -157,7 +165,7 @@ func Load(fs afero.Fs, cfgPath string, log flog.Logger, systemDeps LoadSystemDep
return nil, fmt.Errorf("failed to unmarshal config file: %w", err)
}

defCfg := applyDefaults(&cfg, systemDeps, mem)
defCfg := applyDefaults(&cfg, systemDeps, mem, ecc)
if err := writeConfig(defCfg, fs, cfgPath); err != nil {
return nil, err
}
Expand Down

0 comments on commit 75b69b8

Please sign in to comment.