Skip to content

Commit

Permalink
feat: saves containerd user data to a persistent disk
Browse files Browse the repository at this point in the history
this allows users to retain downloaded images, containers,
etc. across new installations of finch

Signed-off-by: Sam Berning <[email protected]>
  • Loading branch information
sam-berning committed Dec 27, 2022
1 parent 26b7b09 commit da824ba
Show file tree
Hide file tree
Showing 13 changed files with 638 additions and 19 deletions.
2 changes: 2 additions & 0 deletions cmd/finch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"fmt"
"github.com/runfinch/finch/pkg/disk"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
Expand Down Expand Up @@ -108,6 +109,7 @@ func virtualMachineCommands(
config.NewNerdctlApplier(fssh.NewDialer(), fs, fp.LimaSSHPrivateKeyPath(), system.NewStdLib()),
fp,
fs,
disk.NewUserDataDiskManager(lcc, &afero.OsFs{}, fp, system.NewStdLib().Env("HOME")),
)
}

Expand Down
4 changes: 3 additions & 1 deletion cmd/finch/virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main

import (
"fmt"
"github.com/runfinch/finch/pkg/disk"
"strings"

"github.com/runfinch/finch/pkg/command"
Expand All @@ -30,6 +31,7 @@ func newVirtualMachineCommand(
nca config.NerdctlConfigApplier,
fp path.Finch,
fs afero.Fs,
diskManager disk.UserDataDiskManager,
) *cobra.Command {
virtualMachineCommand := &cobra.Command{
Use: virtualMachineRootCmd,
Expand All @@ -40,7 +42,7 @@ func newVirtualMachineCommand(
newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath()),
newStopVMCommand(limaCmdCreator, logger),
newRemoveVMCommand(limaCmdCreator, logger),
newInitVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fp.BaseYamlFilePath(), fs, fp.LimaSSHPrivateKeyPath()),
newInitVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fp.BaseYamlFilePath(), fs, fp.LimaSSHPrivateKeyPath(), diskManager),
)

return virtualMachineCommand
Expand Down
19 changes: 14 additions & 5 deletions cmd/finch/virtual_machine_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package main

import (
"fmt"
"github.com/runfinch/finch/pkg/disk"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
Expand All @@ -25,11 +26,12 @@ func newInitVMCommand(
baseYamlFilePath string,
fs afero.Fs,
privateKeyPath string,
diskManager disk.UserDataDiskManager,
) *cobra.Command {
initVMCommand := &cobra.Command{
Use: "init",
Short: "Initialize the virtual machine",
RunE: newInitVMAction(lcc, logger, optionalDepGroups, lca, baseYamlFilePath).runAdapter,
RunE: newInitVMAction(lcc, logger, optionalDepGroups, lca, baseYamlFilePath, diskManager).runAdapter,
PostRunE: newPostVMStartInitAction(logger, lcc, fs, privateKeyPath, nca).runAdapter,
}

Expand All @@ -42,6 +44,7 @@ type initVMAction struct {
logger flog.Logger
optionalDepGroups []*dependency.Group
limaConfigApplier config.LimaConfigApplier
diskManager disk.UserDataDiskManager
}

func newInitVMAction(
Expand All @@ -50,9 +53,10 @@ func newInitVMAction(
optionalDepGroups []*dependency.Group,
lca config.LimaConfigApplier,
baseYamlFilePath string,
diskManager disk.UserDataDiskManager,
) *initVMAction {
return &initVMAction{
creator: creator, logger: logger, optionalDepGroups: optionalDepGroups, limaConfigApplier: lca, baseYamlFilePath: baseYamlFilePath,
creator: creator, logger: logger, optionalDepGroups: optionalDepGroups, limaConfigApplier: lca, baseYamlFilePath: baseYamlFilePath, diskManager: diskManager,
}
}

Expand All @@ -61,7 +65,7 @@ func (iva *initVMAction) runAdapter(cmd *cobra.Command, args []string) error {
}

func (iva *initVMAction) run() error {
err := iva.assertVMIsNonexistent(iva.creator, iva.logger)
err := iva.assertVMIsNonexistent()
if err != nil {
return err
}
Expand All @@ -76,6 +80,11 @@ func (iva *initVMAction) run() error {
return err
}

err = iva.diskManager.InitializeUserDataDisk();
if err != nil {
return err
}

instanceName := fmt.Sprintf("--name=%v", limaInstanceName)
limaCmd := iva.creator.CreateWithoutStdio("start", instanceName, iva.baseYamlFilePath, "--tty=false")
iva.logger.Info("Initializing and starting Finch virtual machine...")
Expand All @@ -88,8 +97,8 @@ func (iva *initVMAction) run() error {
return nil
}

func (iva *initVMAction) assertVMIsNonexistent(creator command.LimaCmdCreator, logger flog.Logger) error {
status, err := lima.GetVMStatus(creator, logger, limaInstanceName)
func (iva *initVMAction) assertVMIsNonexistent() error {
status, err := lima.GetVMStatus(iva.creator, iva.logger, limaInstanceName)
if err != nil {
return err
}
Expand Down
25 changes: 20 additions & 5 deletions cmd/finch/virtual_machine_init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const mockBaseYamlFilePath = "/os/os.yaml"
func TestNewInitVMCommand(t *testing.T) {
t.Parallel()

cmd := newInitVMCommand(nil, nil, nil, nil, nil, "", nil, "")
cmd := newInitVMCommand(nil, nil, nil, nil, nil, "", nil, "", nil)
assert.Equal(t, cmd.Name(), "init")
}

Expand All @@ -37,6 +37,7 @@ func TestInitVMAction_runAdapter(t *testing.T) {
*mocks.LimaCmdCreator,
*mocks.Logger,
*mocks.LimaConfigApplier,
*mocks.MockUserDataDiskManager,
*gomock.Controller,
)
}{
Expand All @@ -61,6 +62,7 @@ func TestInitVMAction_runAdapter(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -70,6 +72,7 @@ func TestInitVMAction_runAdapter(t *testing.T) {

command := mocks.NewCommand(ctrl)
lca.EXPECT().Apply().Return(nil)
dm.EXPECT().InitializeUserDataDisk().Return(nil)
lcc.EXPECT().CreateWithoutStdio("start", fmt.Sprintf("--name=%s", limaInstanceName),
mockBaseYamlFilePath, "--tty=false").Return(command)
command.EXPECT().CombinedOutput()
Expand All @@ -89,11 +92,12 @@ func TestInitVMAction_runAdapter(t *testing.T) {
logger := mocks.NewLogger(ctrl)
lcc := mocks.NewLimaCmdCreator(ctrl)
lca := mocks.NewLimaConfigApplier(ctrl)
dm := mocks.NewMockUserDataDiskManager(ctrl)

groups := tc.groups(ctrl)
tc.mockSvc(lcc, logger, lca, ctrl)
tc.mockSvc(lcc, logger, lca, dm, ctrl)

assert.NoError(t, newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath).runAdapter(tc.command, tc.args))
assert.NoError(t, newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath, dm).runAdapter(tc.command, tc.args))
})
}
}
Expand All @@ -109,6 +113,7 @@ func TestInitVMAction_run(t *testing.T) {
*mocks.LimaCmdCreator,
*mocks.Logger,
*mocks.LimaConfigApplier,
*mocks.MockUserDataDiskManager,
*gomock.Controller,
)
}{
Expand All @@ -122,6 +127,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -130,6 +136,7 @@ func TestInitVMAction_run(t *testing.T) {
logger.EXPECT().Debugf("Status of virtual machine: %s", "")

lca.EXPECT().Apply().Return(nil)
dm.EXPECT().InitializeUserDataDisk().Return(nil)

command := mocks.NewCommand(ctrl)
lcc.EXPECT().CreateWithoutStdio("start", fmt.Sprintf("--name=%s", limaInstanceName),
Expand All @@ -150,6 +157,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -170,6 +178,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -188,6 +197,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -206,6 +216,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand Down Expand Up @@ -234,6 +245,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -257,6 +269,7 @@ func TestInitVMAction_run(t *testing.T) {
lcc *mocks.LimaCmdCreator,
logger *mocks.Logger,
lca *mocks.LimaConfigApplier,
dm *mocks.MockUserDataDiskManager,
ctrl *gomock.Controller,
) {
getVMStatusC := mocks.NewCommand(ctrl)
Expand All @@ -265,6 +278,7 @@ func TestInitVMAction_run(t *testing.T) {
logger.EXPECT().Debugf("Status of virtual machine: %s", "")

lca.EXPECT().Apply().Return(nil)
dm.EXPECT().InitializeUserDataDisk().Return(nil)

logs := []byte("stdout + stderr")
command := mocks.NewCommand(ctrl)
Expand All @@ -287,11 +301,12 @@ func TestInitVMAction_run(t *testing.T) {
logger := mocks.NewLogger(ctrl)
lcc := mocks.NewLimaCmdCreator(ctrl)
lca := mocks.NewLimaConfigApplier(ctrl)
dm := mocks.NewMockUserDataDiskManager(ctrl)

groups := tc.groups(ctrl)
tc.mockSvc(lcc, logger, lca, ctrl)
tc.mockSvc(lcc, logger, lca, dm, ctrl)

err := newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath).run()
err := newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath, dm).run()
assert.Equal(t, err, tc.wantErr)
})
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/finch/virtual_machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
func TestVirtualMachineCommand(t *testing.T) {
t.Parallel()

cmd := newVirtualMachineCommand(nil, nil, nil, nil, nil, "", nil)
cmd := newVirtualMachineCommand(nil, nil, nil, nil, nil, "", nil, nil)
assert.Equal(t, cmd.Use, virtualMachineRootCmd)

// check the number of subcommand for vm
Expand Down
21 changes: 14 additions & 7 deletions finch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ mounts:
# 🟢 Builtin default: "reverse-sshfs"
mountType: reverse-sshfs

# Lima disks to attach to the instance. The disks will be accessible from inside the
# instance, labeled by name. (e.g. if the disk is named "data", it will be labeled
# "lima-data" inside the instance). The disk will be mounted inside the instance at
# `/mnt/lima-${VOLUME}`.
# 🟢 Builtin default: null
additionalDisks:
- "finch"

ssh:
# A localhost port of the host. Forwarded to port 22 of the guest.
# 🟢 Builtin default: 0 (automatically assigned to a free port)
Expand Down Expand Up @@ -136,13 +144,12 @@ provision:
systemctl reset-failed NetworkManager-wait-online.service
systemctl mask NetworkManager-wait-online.service
# # `user` is executed without the root privilege
# - mode: user
# script: |
# #!/bin/bash
# set -eux -o pipefail
# cat <<EOF > ~/.vimrc
# set number
# EOF
- mode: user
script: |
#!/bin/bash
sudo chown $USER /mnt/lima-finch
sudo mount --bind /mnt/lima-finch ~/.local/share/containerd
systemctl --user restart containerd.service
# Probe scripts to check readiness.
# 🟢 Builtin default: null
Expand Down
16 changes: 16 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ require (
inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 // indirect
)

require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/apparentlymart/go-cidr v1.1.0 // indirect
github.com/containers/gvisor-tap-vsock v0.4.1-0.20220920072955-5b1aff8ba743 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f // indirect
github.com/miekg/dns v1.1.50 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
gvisor.dev/gvisor v0.0.0-20220908032458-edc830a43ba6 // indirect
inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 // indirect
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/go-units v0.5.0
Expand Down
Loading

0 comments on commit da824ba

Please sign in to comment.