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

[Draft] feat: add Windows support #553

Closed
wants to merge 16 commits into from
Closed
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
3 changes: 2 additions & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[submodule "deps/finch-core"]
path = deps/finch-core
url = https://github.com/runfinch/finch-core.git
url = https://github.com/vsiravar/finch-core-public.git
branch = windev
89 changes: 76 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ VERSION := $(shell git describe --match 'v[0-9]*' --dirty='.modified' --always -
GITCOMMIT := $(shell git rev-parse HEAD)$(shell if ! git diff --no-ext-diff --quiet --exit-code; then echo .m; fi)
LDFLAGS := "-X $(PACKAGE)/pkg/version.Version=$(VERSION) -X $(PACKAGE)/pkg/version.GitCommit=$(GITCOMMIT)"

GOOS ?= $(shell $(GO) env GOOS)
ifeq ($(GOOS),windows)
BINARYNAME := $(addsuffix .exe, $(BINARYNAME))
sha = sha256sum
else
sha = shasum -a 256
endif

.DEFAULT_GOAL := all

INSTALLED ?= false
Expand All @@ -35,40 +43,66 @@ ifneq (,$(findstring arm64,$(ARCH)))
LIMA_ARCH = aarch64
# From https://dl.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/aarch64/images/
FINCH_OS_BASENAME ?= Fedora-Cloud-Base-38-1.6.aarch64-20230713205101.qcow2
LIMA_URL ?= https://deps.runfinch.com/aarch64/lima-and-qemu.macos-aarch64.1691201350.tar.gz
LIMA_URL ?= https://deps.runfinch.com/aarch64/lima-and-qemu.macos-aarch64.1689037160.tar.gz
FINCH_ROOTFS_URL ?= https://deps.runfinch.com/common/aarch64/finch-rootfs-production-arm64-1690920104.tar
FINCH_ROOTFS_BASENAME := $(notdir $(FINCH_ROOTFS_URL))
# TODO ROOTFS URL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can remove

else ifneq (,$(findstring x86_64,$(ARCH)))
SUPPORTED_ARCH = true
LIMA_ARCH = x86_64
# From https://dl.fedoraproject.org/pub/fedora/linux/releases/37/Cloud/x86_64/images/
FINCH_OS_BASENAME ?= Fedora-Cloud-Base-38-1.6.x86_64-20230713205042.qcow2
LIMA_URL ?= https://deps.runfinch.com/x86-64/lima-and-qemu.macos-x86_64.1691201350.tar.gz
LIMA_URL ?= https://deps.runfinch.com/x86-64/lima-and-qemu.macos-x86_64.1689037160.tar.gz
FINCH_ROOTFS_URL ?= https://deps.runfinch.com/common/x86-64/finch-rootfs-production-amd64-1694791577.tar.gz
FINCH_ROOTFS_BASENAME := $(notdir $(FINCH_ROOTFS_URL))
# TODO ROOTFS URL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can remove

endif

FINCH_OS_HASH := `shasum -a 256 $(OUTDIR)/os/$(FINCH_OS_BASENAME) | cut -d ' ' -f 1`
FINCH_OS_HASH := `$(sha) $(OUTDIR)/os/$(FINCH_OS_BASENAME) | cut -d ' ' -f 1`
FINCH_OS_DIGEST := "sha256:$(FINCH_OS_HASH)"
FINCH_OS_IMAGE_LOCATION_ROOT ?= $(DEST)
FINCH_OS_IMAGE_LOCATION ?= $(FINCH_OS_IMAGE_LOCATION_ROOT)/os/$(FINCH_OS_BASENAME)

# TODO: Windows PoC extracting rootfs...
FINCH_ROOTFS_HASH := `$(sha) $(OUTDIR)/os/$(FINCH_ROOTFS_BASENAME) | cut -d ' ' -f 1`
FINCH_ROOTFS_DIGEST := "sha256:$(FINCH_ROOTFS_HASH)"
FINCH_ROOTFS_LOCATION ?= $(DEST)/os/$(FINCH_ROOTFS_BASENAME)

.PHONY: arch-test
arch-test:
@if [ $(SUPPORTED_ARCH) != "true" ]; then echo "Unsupported architecture: $(ARCH)"; exit "1"; fi

.PHONY: all
ifeq ($(GOOS),windows)
all: arch-test finch finch-core-local finch.windows.yaml networks.yaml config.yaml
else
all: arch-test finch finch-core finch.yaml networks.yaml config.yaml lima-and-qemu
endif

.PHONY: all-local
all-local: arch-test finch networks.yaml config.yaml lima-and-qemu local-core finch.yaml
all-local: arch-test networks.yaml config.yaml lima-and-qemu local-core finch.yaml

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

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

.PHONY: finch-core-local
finch-core-local:
Comment on lines +96 to +97
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO on removing this rule. IIRC we added this to make lima.exe and the guestagent sourcing the WSL PR to lima:

But once lima is released with WSL support, we should source similar to how we do on macOS via LIMA_URL: https://github.com/vsiravar/finch-core-public/blob/b82c007d22d4d99f8a78a3db7c6252ce9c5afcc8/Makefile#L36C14-L36C14

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)" all lima

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

.PHONY: local-core
Expand All @@ -80,8 +114,8 @@ local-core:
"$(MAKE)" lima lima-socket-vmnet

mkdir -p _output
cd deps/finch-core/_output && tar c * | tar Cvx $(OUTDIR)
cd deps/finch-core/src/lima/_output && tar c * | tar Cvx $(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

.PHONY: lima-and-qemu
Expand All @@ -97,16 +131,36 @@ lima-and-qemu: networks.yaml
rm -rf $(OUTDIR)/downloads


FINCH_IMAGE_LOCATION ?=
FINCH_IMAGE_DIGEST ?=
ifeq ($(GOOS),windows)
# Because the path in windows /C:/<some-path> is not an Absolute path, prefix with file:/ which is handled by lima https://github.com/lima-vm/lima/blob/da1260dc87fb30345c3ee7bfb131c29646e26d10/pkg/downloader/downloader.go#L266
FINCH_IMAGE_LOCATION := "file:/$(FINCH_ROOTFS_LOCATION)"
FINCH_IMAGE_DIGEST := $(FINCH_ROOTFS_DIGEST)
else
FINCH_IMAGE_LOCATION := $(FINCH_OS_IMAGE_LOCATION)
FINCH_IMAGE_DIGEST := $(FINCH_OS_DIGEST)
endif
.PHONY: finch.yaml
finch.yaml: finch-core
mkdir -p $(OUTDIR)/os
cp finch.yaml $(OUTDIR)/os
# using -i.bak is very intentional, it allows the following commands to succeed for both GNU / BSD sed
# this sed command uses the alternative separator of "|" because the image location uses "/"
sed -i.bak -e "s|<finch_image_location>|$(FINCH_OS_IMAGE_LOCATION)|g" $(OUTDIR)/os/finch.yaml
sed -i.bak -e "s|<finch_image_location>|$(FINCH_IMAGE_LOCATION)|g" $(OUTDIR)/os/finch.yaml
sed -i.bak -e "s/<finch_image_arch>/$(LIMA_ARCH)/g" $(OUTDIR)/os/finch.yaml
sed -i.bak -e "s/<finch_image_digest>/$(FINCH_IMAGE_DIGEST)/g" $(OUTDIR)/os/finch.yaml
Comment on lines 145 to +152
Copy link
Contributor

@ginglis13 ginglis13 Sep 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we can consolidate finch.yaml and finch.windows.yaml rules to be something like:

WINDOWS ?=
CONF_FILE ?=
ifeq ($(GOOS),windows)
    WINDOWS=.windows
    CONF_FILE=finch.windows.yaml
else
    CONF_FILE=finch.yaml
endif

finch$(WINDOWS).yaml: finch-core
	mkdir -p $(OUTDIR)/os
	cp $(CONF_FILE) $(OUTDIR)/os
	# using -i.bak is very intentional, it allows the following commands to succeed for both GNU / BSD sed
	# this sed command uses the alternative separator of "|" because the image location uses "/"
	sed -i.bak -e "s|<finch_image_location>|$(FINCH_IMAGE_LOCATION)|g" $(OUTDIR)/os/finch.yaml
	sed -i.bak -e "s/<finch_image_arch>/$(LIMA_ARCH)/g" $(OUTDIR)/os/finch.yaml
	sed -i.bak -e "s/<finch_image_digest>/$(FINCH_IMAGE_DIGEST)/g" $(OUTDIR)/os/finch.yaml


# TODO: Windows PoC - clean this up / consolidate
.PHONY: finch.yaml
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: finch.windows.yaml

finch.windows.yaml: finch-core-local
mkdir -p $(OUTDIR)/os
cp finch.windows.yaml $(OUTDIR)/os/finch.yaml
# using -i.bak is very intentional, it allows the following commands to succeed for both GNU / BSD sed
# this sed command uses the alternative separator of "|" because the image location uses "/"
sed -i.bak -e "s|<finch_image_location>|$(FINCH_IMAGE_LOCATION)|g" $(OUTDIR)/os/finch.yaml
sed -i.bak -e "s/<finch_image_arch>/$(LIMA_ARCH)/g" $(OUTDIR)/os/finch.yaml
sed -i.bak -e "s/<finch_image_digest>/$(FINCH_OS_DIGEST)/g" $(OUTDIR)/os/finch.yaml
rm $(OUTDIR)/os/*.yaml.bak
sed -i.bak -e "s/<finch_image_digest>/$(FINCH_IMAGE_DIGEST)/g" $(OUTDIR)/os/finch.yaml

.PHONY: networks.yaml
networks.yaml:
Expand Down Expand Up @@ -254,7 +308,7 @@ check-licenses:

.PHONY: test-unit
test-unit:
go test $(shell go list ./... | grep -v e2e) -shuffle on -race
go test $(shell go list ./... | grep -v e2e) -shuffle on
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove race condition checks?


# test-e2e assumes the VM instance doesn't exist, please make sure to remove it before running.
#
Expand Down Expand Up @@ -313,9 +367,17 @@ mdlint:
.PHONY: mdlint-ctr
# If markdownlint is not installed, you can run markdownlint within a container.
mdlint-ctr:
finch run --rm -v "$(shell pwd):/repo:ro" -w /repo avtodev/markdown-lint:v1 --ignore CHANGELOG.md '**/*.md'
$(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 @@ -328,3 +390,4 @@ clean:
-@rm ./*.tar.gz 2>/dev/null || true
-@rm ./*.qcow2 2>/dev/null || true
-@rm ./test-coverage.* 2>/dev/null || true
endif
10 changes: 10 additions & 0 deletions cmd/finch/lima_args_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//go:build darwin

package main

func (nc *nerdctlCommand) GetLimaArgs() []string {
return []string{"shell", limaInstanceName, "sudo", "-E"}
}
20 changes: 20 additions & 0 deletions cmd/finch/lima_args_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//go:build windows

package main

func (nc *nerdctlCommand) GetLimaArgs() []string {
wd, err := nc.systemDeps.GetWd()
if err != nil {
nc.logger.Warnln("failed to get working directory, will default to user home with error %s", err.Error())
return append([]string{"shell", limaInstanceName, "sudo", "-E"})
}
wslPath, err := convertToWSLPath(nc.systemDeps, wd)
if err != nil {
nc.logger.Warnln("failed to convert to WSL path, will default to user home with error %s", err.Error())
return append([]string{"shell", limaInstanceName, "sudo", "-E"})
}
return append([]string{"shell", "--workdir", wslPath, limaInstanceName, "sudo", "-E"})
}
55 changes: 21 additions & 34 deletions cmd/finch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@ import (

"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/fmemory"
"github.com/runfinch/finch/pkg/fssh"
"github.com/runfinch/finch/pkg/lima/wrapper"
"github.com/runfinch/finch/pkg/path"
"github.com/runfinch/finch/pkg/support"
Expand Down Expand Up @@ -53,15 +48,31 @@ func xmain(logger flog.Logger,
return fmt.Errorf("failed to find the installation path of Finch: %w", err)
}

fc, err := config.Load(fs, fp.ConfigFilePath(ffd.Env("HOME")), logger, loadCfgDeps, mem)
home, err := ffd.GetUserHome()
if err != nil {
return fmt.Errorf("failed to get user home directory: %w", err)
}
finchRootPath, err := fp.FinchRootDir(*system.NewStdLib())
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 @@ -90,6 +101,7 @@ var newApp = func(logger flog.Logger, fp path.Finch, fs afero.Fs, fc *config.Fin
fp.QEMUBinDir(),
system.NewStdLib(),
)

supportBundleBuilder := support.NewBundleBuilder(
logger,
fs,
Expand All @@ -104,7 +116,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 All @@ -113,31 +125,6 @@ var newApp = func(logger flog.Logger, fp path.Finch, fs afero.Fs, fc *config.Fin
return rootCmd
}

func virtualMachineCommands(
logger flog.Logger,
fp path.Finch,
lcc command.LimaCmdCreator,
ecc *command.ExecCmdCreator,
fs afero.Fs,
fc *config.Finch,
) *cobra.Command {
optionalDepGroups := []*dependency.Group{
vmnet.NewDependencyGroup(ecc, lcc, fs, fp, logger),
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),
)
}

func initializeNerdctlCommands(lcc command.LimaCmdCreator, logger flog.Logger, fs afero.Fs) []*cobra.Command {
nerdctlCommandCreator := newNerdctlCommandCreator(lcc, system.NewStdLib(), logger, fs)
var allNerdctlCommands []*cobra.Command
Expand Down
41 changes: 41 additions & 0 deletions cmd/finch/main_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

//go:build darwin

package main

import (
"github.com/spf13/afero"

"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/flog"
"github.com/runfinch/finch/pkg/path"
"github.com/runfinch/finch/pkg/system"
)

func dependencies(
ecc *command.ExecCmdCreator,
fc *config.Finch,
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),
}
}
6 changes: 3 additions & 3 deletions cmd/finch/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func TestXmain(t *testing.T) {
) {
require.NoError(t, afero.WriteFile(fs, "/home/.finch/finch.yaml", []byte(configStr), 0o600))

ffd.EXPECT().Env("HOME").Return("/home")
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")
Expand Down Expand Up @@ -94,7 +94,7 @@ func TestXmain(t *testing.T) {
) {
require.NoError(t, afero.WriteFile(fs, "/home/.finch/finch.yaml", []byte("this isn't YAML"), 0o600))

ffd.EXPECT().Env("HOME").Return("/home")
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")
Expand Down Expand Up @@ -132,7 +132,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
Loading