Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make Virtualization Framework default #956

Merged
merged 5 commits into from
May 23, 2024
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
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.
pendo324 marked this conversation as resolved.
Show resolved Hide resolved
#
# 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
Loading
Loading