Skip to content

Commit

Permalink
feat: windows persistent disk and other misc fixes/refactors (#594)
Browse files Browse the repository at this point in the history
Issue #, if available:

*Description of changes:*
- Adds persistent disk support to Windows
- This took more work than anticipated, in order to deal with non-Admin
users
- `pkg/disk/dpgo/` is brand new code, and should be a focus of the
review
- `pkg/winutil/run_windows.go` is also new and requires careful review.
This is what allows Finch to run as the regular user, except for when it
needs Admin access to call `diskpart` (to create the persistent disk)
- Fix paths in `nerdctl_config_applier` to make the post-boot/init
shelling work
- Added winres to allow the finch.exe to have metadata attached to it.
This is WIP, need final icons and descriptions etc.
- Large (in terms of lines changed) refactor of `pkg/path/finch.go`, but
it should have no impact on functionality (needs careful review)
- Fixed the Makefile's `clean` target for Windows
- Most of the other changes are just noise from refactoring (like,
literally renaming things). Nothing major, but take a look if possible.
Sorry the diff is so large

*Testing done:*

- [x] I've reviewed the guidance in CONTRIBUTING.md

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 license.

---------

Signed-off-by: Vishwas Siravara <[email protected]>
Signed-off-by: Justin Alvarez <[email protected]>
Signed-off-by: Vishwas Siravara <[email protected]>
Co-authored-by: Vishwas Siravara <[email protected]>
Co-authored-by: Vishwas Siravara <[email protected]>
Signed-off-by: Vishwas Siravara <[email protected]>
  • Loading branch information
3 people committed Oct 17, 2023
1 parent 614e3b4 commit 005f400
Show file tree
Hide file tree
Showing 53 changed files with 1,665 additions and 331 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ tmp/
.vscode/
tools_bin/
test-coverage.*
*.syso
34 changes: 30 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ arch-test:

.PHONY: all
ifeq ($(GOOS),windows)
all: arch-test finch finch-core-local finch.windows.yaml networks.yaml config.yaml
all: arch-test finch finch-core-local finch.windows.yaml networks.yaml config.yaml dpgo
else
all: arch-test finch finch-core finch.yaml networks.yaml config.yaml lima-and-qemu
endif
Expand All @@ -81,7 +81,6 @@ all-local: arch-test networks.yaml config.yaml lima-and-qemu local-core finch.ya
.PHONY: finch-core
finch-core:
cd deps/finch-core && \
FINCH_OS_x86_URL="$(FINCH_OS_x86_URL)" \
FINCH_OS_AARCH64_URL="$(FINCH_OS_AARCH64_URL)" \
VDE_TEMP_PREFIX=$(CORE_VDE_PREFIX) \
"$(MAKE)"
Expand Down Expand Up @@ -112,6 +111,8 @@ local-core:

mkdir -p _output
cd deps/finch-core/_output && tar -cf - * | tar -xvf - -C $(OUTDIR)
cd deps/finch-core/src/lima/_output && tar -cf - * | tar -xvf - -C $(OUTDIR)/lima
cd deps/finch-core/_output && tar -cf - * | tar -xvf - -C $(OUTDIR)
cd deps/finch-core/src/lima/_output && tar -cf - * | tar -xvf - -C $(OUTDIR)/lima
rm -rf $(OUTDIR)/lima-template

Expand Down Expand Up @@ -195,9 +196,25 @@ uninstall.vde:
uninstall: uninstall.finch

.PHONY: finch
finch:
ifeq ($(GOOS),windows)
finch: finch-windows finch-general
else
finch: finch-unix
endif

finch-windows:
GOBIN=$(GOBIN) go install github.com/tc-hib/go-winres
$(GO) generate cmd/finch/main_windows.go

finch-unix: finch-general

finch-general:
$(GO) build -ldflags $(LDFLAGS) -o $(OUTDIR)/bin/$(BINARYNAME) $(PACKAGE)/cmd/finch

.PHONY: dpgo
dpgo:
$(GO) build -o $(OUTDIR)/bin/dpgo.exe $(PACKAGE)/pkg/disk/dpgo

.PHONY: release
release: check-licenses all download-licenses

Expand Down Expand Up @@ -370,6 +387,14 @@ mdlint-ctr:
$(BINARYNAME) run --rm -v "$(shell pwd):/repo:ro" -w /repo avtodev/markdown-lint:v1 --ignore CHANGELOG.md '**/*.md'

.PHONY: clean
ifeq ($(GOOS),windows)
clean:
-@rm -rf $(OUTDIR) 2>/dev/null || true
-@rm -rf ./deps/finch-core/_output || true
-@rm ./*.tar.gz 2>/dev/null || true
-@rm ./*.qcow2 2>/dev/null || true
-@rm ./test-coverage.* 2>/dev/null || true
else
clean:
-sudo pkill '^socket_vmnet'
-sudo pkill '^qemu-system-'
Expand All @@ -381,4 +406,5 @@ clean:
-@rm -rf ./deps/finch-core/_output || true
-@rm ./*.tar.gz 2>/dev/null || true
-@rm ./*.qcow2 2>/dev/null || true
-@rm ./test-coverage.* 2>/dev/null || true
-@rm ./test-coverage.* 2>/dev/null || true
endif
20 changes: 16 additions & 4 deletions cmd/finch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,27 @@ func xmain(logger flog.Logger,
if err != nil {
return fmt.Errorf("failed to get user home directory: %w", err)
}
fc, err := config.Load(fs, fp.ConfigFilePath(home), logger, loadCfgDeps, mem)
finchRootPath, err := fp.FinchRootDir(ffd)
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)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}

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

var newApp = func(logger flog.Logger, fp path.Finch, fs afero.Fs, fc *config.Finch, stdOut io.Writer) *cobra.Command {
var newApp = func(
logger flog.Logger,
fp path.Finch,
fs afero.Fs,
fc *config.Finch,
stdOut io.Writer,
home,
finchRootPath string,
) *cobra.Command {
usage := fmt.Sprintf("%v <command>", finchRootCmd)
rootCmd := &cobra.Command{
Use: usage,
Expand Down Expand Up @@ -105,7 +117,7 @@ var newApp = func(logger flog.Logger, fp path.Finch, fs afero.Fs, fc *config.Fin
// append finch specific commands
allCommands = append(allCommands,
newVersionCommand(lcc, logger, stdOut),
virtualMachineCommands(logger, fp, lcc, ecc, fs, fc),
virtualMachineCommands(logger, fp, lcc, ecc, fs, fc, home, finchRootPath),
newSupportBundleCommand(logger, supportBundleBuilder, lcc),
)

Expand Down
41 changes: 17 additions & 24 deletions cmd/finch/main_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,35 @@ package main

import (
"github.com/spf13/afero"
"github.com/spf13/cobra"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
"github.com/runfinch/finch/pkg/dependency"
"github.com/runfinch/finch/pkg/dependency/credhelper"
"github.com/runfinch/finch/pkg/dependency/vmnet"
"github.com/runfinch/finch/pkg/disk"
"github.com/runfinch/finch/pkg/flog"
"github.com/runfinch/finch/pkg/fssh"
"github.com/runfinch/finch/pkg/path"
"github.com/runfinch/finch/pkg/system"
)

func virtualMachineCommands(
logger flog.Logger,
fp path.Finch,
lcc command.LimaCmdCreator,
func dependencies(
ecc *command.ExecCmdCreator,
fs afero.Fs,
fc *config.Finch,
) *cobra.Command {
optionalDepGroups := []*dependency.Group{
credhelper.NewDependencyGroup(ecc, fs, fp, logger, fc, system.NewStdLib().Env("USER"),
system.NewStdLib().Arch()),
fp path.Finch,
fs afero.Fs,
lcc command.LimaCmdCreator,
logger flog.Logger,
) []*dependency.Group {
return []*dependency.Group{
credhelper.NewDependencyGroup(
ecc,
fs,
fp,
logger,
fc,
system.NewStdLib().Env("USER"),
system.NewStdLib().Arch(),
),
vmnet.NewDependencyGroup(ecc, lcc, fs, fp, logger),
}

optionalDepGroups = append(optionalDepGroups, vmnet.NewDependencyGroup(ecc, lcc, fs, fp, logger))
return newVirtualMachineCommand(
lcc,
logger,
optionalDepGroups,
config.NewLimaApplier(fc, ecc, fs, fp.LimaOverrideConfigPath(), system.NewStdLib()),
config.NewNerdctlApplier(fssh.NewDialer(), fs, fp.LimaSSHPrivateKeyPath(), system.NewStdLib().Env("USER")),
fp,
fs,
disk.NewUserDataDiskManager(lcc, ecc, &afero.OsFs{}, fp, system.NewStdLib().Env("HOME"), fc),
)
}
66 changes: 45 additions & 21 deletions cmd/finch/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,34 @@ func TestXmain(t *testing.T) {
ffd.EXPECT().Executable().Return("", errors.New("failed to find executable path"))
},
},
}

darwinTestCases := []struct {
name string
mockSvc func(*mocks.Logger, *mocks.FinchFinderDeps, afero.Fs, *mocks.LoadSystemDeps, *mocks.Memory)
wantErr error
}{
{
name: "happy path",
wantErr: nil,
mockSvc: func(
logger *mocks.Logger,
ffd *mocks.FinchFinderDeps,
fs afero.Fs,
loadCfgDeps *mocks.LoadSystemDeps,
mem *mocks.Memory,
) {
require.NoError(t, afero.WriteFile(fs, "/home/.finch/finch.yaml", []byte(configStr), 0o600))

ffd.EXPECT().GetUserHome().Return("/home", nil)
ffd.EXPECT().Executable().Return("/bin/path", nil)
ffd.EXPECT().EvalSymlinks("/bin/path").Return("/real/bin/path", nil)
ffd.EXPECT().FilePathJoin("/real/bin/path", "..", "..").Return("/real")
loadCfgDeps.EXPECT().NumCPU().Return(16)
// 12_884_901_888 == 12GiB
mem.EXPECT().TotalMemory().Return(uint64(12_884_901_888))
},
},
{
name: "failed to load finch config because of invalid YAML",
wantErr: fmt.Errorf("failed to load config: %w",
Expand All @@ -77,12 +105,12 @@ func TestXmain(t *testing.T) {
ffd.EXPECT().GetUserHome().Return("/home", nil)
ffd.EXPECT().Executable().Return("/bin/path", nil)
ffd.EXPECT().EvalSymlinks("/bin/path").Return("/real/bin/path", nil)
ffd.EXPECT().FilePathJoin("/real/bin/path", "../../").Return("/real")
ffd.EXPECT().FilePathJoin("/real/bin/path", "..", "..").Return("/real")
},
},
}

darwinTestCases := []struct {
windowsTestCases := []struct {
name string
mockSvc func(*mocks.Logger, *mocks.FinchFinderDeps, afero.Fs, *mocks.LoadSystemDeps, *mocks.Memory)
wantErr error
Expand All @@ -100,37 +128,33 @@ func TestXmain(t *testing.T) {
require.NoError(t, afero.WriteFile(fs, "/home/.finch/finch.yaml", []byte(configStr), 0o600))

ffd.EXPECT().GetUserHome().Return("/home", nil)
ffd.EXPECT().Env("LOCALAPPDATA").Return("/home/")
ffd.EXPECT().Executable().Return("/bin/path", nil)
ffd.EXPECT().EvalSymlinks("/bin/path").Return("/real/bin/path", nil)
ffd.EXPECT().FilePathJoin("/real/bin/path", "../../").Return("/real")
loadCfgDeps.EXPECT().NumCPU().Return(16)
// 12_884_901_888 == 12GiB
mem.EXPECT().TotalMemory().Return(uint64(12_884_901_888))
ffd.EXPECT().FilePathJoin("/real/bin/path", "..", "..").Return("/real")
},
},
}

windowsTestCases := []struct {
name string
mockSvc func(*mocks.Logger, *mocks.FinchFinderDeps, afero.Fs, *mocks.LoadSystemDeps, *mocks.Memory)
wantErr error
}{
{
name: "happy path",
wantErr: nil,
name: "failed to load finch config because of invalid YAML",
wantErr: fmt.Errorf("failed to load config: %w",
fmt.Errorf("failed to unmarshal config file: %w",
&yaml.TypeError{Errors: []string{"line 1: cannot unmarshal !!str `this is...` into config.Finch"}},
),
),
mockSvc: func(
logger *mocks.Logger,
_ *mocks.Logger,
ffd *mocks.FinchFinderDeps,
fs afero.Fs,
loadCfgDeps *mocks.LoadSystemDeps,
mem *mocks.Memory,
_ *mocks.LoadSystemDeps,
_ *mocks.Memory,
) {
require.NoError(t, afero.WriteFile(fs, "/home/.finch/finch.yaml", []byte(configStr), 0o600))
require.NoError(t, afero.WriteFile(fs, "/home/.finch/finch.yaml", []byte("this isn't YAML"), 0o600))

ffd.EXPECT().GetUserHome().Return("/home", nil)
ffd.EXPECT().Env("LOCALAPPDATA").Return("/home/")
ffd.EXPECT().Executable().Return("/bin/path", nil)
ffd.EXPECT().EvalSymlinks("/bin/path").Return("/real/bin/path", nil)
ffd.EXPECT().FilePathJoin("/real/bin/path", "../../").Return("/real")
ffd.EXPECT().FilePathJoin("/real/bin/path", "..", "..").Return("/real")
},
},
}
Expand Down Expand Up @@ -170,7 +194,7 @@ func TestNewApp(t *testing.T) {

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, "", "")

assert.Equal(t, cmd.Name(), finchRootCmd)
assert.Equal(t, cmd.Version, version.Version)
Expand Down
40 changes: 18 additions & 22 deletions cmd/finch/main_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,39 @@

//go:build windows

//go:generate go-winres make --file-version=git-tag --product-version=git-tag --arch amd64 --in ../../winres/winres.json

package main

import (
"github.com/spf13/afero"
"github.com/spf13/cobra"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
"github.com/runfinch/finch/pkg/dependency"
"github.com/runfinch/finch/pkg/dependency/credhelper"
"github.com/runfinch/finch/pkg/disk"
"github.com/runfinch/finch/pkg/flog"
"github.com/runfinch/finch/pkg/fssh"
"github.com/runfinch/finch/pkg/path"
"github.com/runfinch/finch/pkg/system"
)

func virtualMachineCommands(
logger flog.Logger,
fp path.Finch,
lcc command.LimaCmdCreator,
func dependencies(
ecc *command.ExecCmdCreator,
fs afero.Fs,
fc *config.Finch,
) *cobra.Command {
optionalDepGroups := []*dependency.Group{
credhelper.NewDependencyGroup(ecc, fs, fp, logger, fc, system.NewStdLib().Env("USER"),
system.NewStdLib().Arch()),
fp path.Finch,
fs afero.Fs,
_ command.LimaCmdCreator,
logger flog.Logger,
) []*dependency.Group {
return []*dependency.Group{
credhelper.NewDependencyGroup(
ecc,
fs,
fp,
logger,
fc,
system.NewStdLib().Env("USER"),
system.NewStdLib().Arch(),
),
}
return newVirtualMachineCommand(
lcc,
logger,
optionalDepGroups,
config.NewLimaApplier(fc, ecc, fs, fp.LimaOverrideConfigPath(), system.NewStdLib()),
config.NewNerdctlApplier(fssh.NewDialer(), fs, fp.LimaSSHPrivateKeyPath(), system.NewStdLib().Env("USER")),
fp,
fs,
disk.NewUserDataDiskManager(lcc, ecc, &afero.OsFs{}, fp, system.NewStdLib().Env("HOME"), fc),
)
}
Loading

0 comments on commit 005f400

Please sign in to comment.