Skip to content

Commit

Permalink
feat: saves containerd user data to a persistent disk (runfinch#133)
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]>

Issue #, if available: runfinch#77

*Description of changes:*

- Adds a new package for managing the user data persistent disk
- Checks disk configuration & creates disk if necessary on `finch vm
init`
- Attaches disk whenever the VM starts

*Testing done:*
- Unit testing on `disk` and `cmd/finch`
- Manual testing

*Open questions:*
- Should we also check the configuration on `finch vm start`?



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


#### License Acceptance

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

Signed-off-by: Sam Berning <[email protected]>
  • Loading branch information
sam-berning authored and ahsan-z-khan committed Jan 11, 2023
1 parent 5bd0e95 commit 6a75f5d
Show file tree
Hide file tree
Showing 18 changed files with 779 additions and 33 deletions.
3 changes: 3 additions & 0 deletions cmd/finch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package main
import (
"fmt"

"github.com/runfinch/finch/pkg/disk"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
"github.com/runfinch/finch/pkg/dependency"
Expand Down Expand Up @@ -108,6 +110,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
8 changes: 6 additions & 2 deletions cmd/finch/virtual_machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"fmt"
"strings"

"github.com/runfinch/finch/pkg/disk"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
"github.com/runfinch/finch/pkg/dependency"
Expand All @@ -30,17 +32,19 @@ func newVirtualMachineCommand(
nca config.NerdctlConfigApplier,
fp path.Finch,
fs afero.Fs,
diskManager disk.UserDataDiskManager,
) *cobra.Command {
virtualMachineCommand := &cobra.Command{
Use: virtualMachineRootCmd,
Short: "Manage the virtual machine lifecycle",
}

virtualMachineCommand.AddCommand(
newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath()),
newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath(), diskManager),
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
25 changes: 20 additions & 5 deletions cmd/finch/virtual_machine_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package main
import (
"fmt"

"github.com/runfinch/finch/pkg/disk"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
"github.com/runfinch/finch/pkg/dependency"
Expand All @@ -25,11 +27,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 +45,7 @@ type initVMAction struct {
logger flog.Logger
optionalDepGroups []*dependency.Group
limaConfigApplier config.LimaConfigApplier
diskManager disk.UserDataDiskManager
}

func newInitVMAction(
Expand All @@ -50,9 +54,15 @@ 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 +71,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 +86,11 @@ func (iva *initVMAction) run() error {
return err
}

err = iva.diskManager.EnsureUserDataDisk()
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 +103,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().EnsureUserDataDisk().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().EnsureUserDataDisk().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().EnsureUserDataDisk().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
28 changes: 22 additions & 6 deletions cmd/finch/virtual_machine_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package main
import (
"fmt"

"github.com/runfinch/finch/pkg/disk"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/config"
"github.com/runfinch/finch/pkg/dependency"
Expand All @@ -24,29 +26,38 @@ func newStartVMCommand(
nca config.NerdctlConfigApplier,
fs afero.Fs,
privateKeyPath string,
dm disk.UserDataDiskManager,
) *cobra.Command {
return &cobra.Command{
Use: "start",
Short: "Start the virtual machine",
RunE: newStartVMAction(lcc, logger, optionalDepGroups, lca).runAdapter,
RunE: newStartVMAction(lcc, logger, optionalDepGroups, lca, dm).runAdapter,
PostRunE: newPostVMStartInitAction(logger, lcc, fs, privateKeyPath, nca).runAdapter,
}
}

type startVMAction struct {
creator command.LimaCmdCreator
logger flog.Logger
optionalDepGroups []*dependency.Group
limaConfigApplier config.LimaConfigApplier
creator command.LimaCmdCreator
logger flog.Logger
optionalDepGroups []*dependency.Group
limaConfigApplier config.LimaConfigApplier
userDataDiskManager disk.UserDataDiskManager
}

func newStartVMAction(
creator command.LimaCmdCreator,
logger flog.Logger,
optionalDepGroups []*dependency.Group,
lca config.LimaConfigApplier,
dm disk.UserDataDiskManager,
) *startVMAction {
return &startVMAction{creator: creator, logger: logger, optionalDepGroups: optionalDepGroups, limaConfigApplier: lca}
return &startVMAction{
creator: creator,
logger: logger,
optionalDepGroups: optionalDepGroups,
limaConfigApplier: lca,
userDataDiskManager: dm,
}
}

func (sva *startVMAction) runAdapter(cmd *cobra.Command, args []string) error {
Expand All @@ -68,6 +79,11 @@ func (sva *startVMAction) run() error {
return err
}

err = sva.userDataDiskManager.EnsureUserDataDisk()
if err != nil {
return err
}

limaCmd := sva.creator.CreateWithoutStdio("start", limaInstanceName)
sva.logger.Info("Starting existing Finch virtual machine...")
logs, err := limaCmd.CombinedOutput()
Expand Down
Loading

0 comments on commit 6a75f5d

Please sign in to comment.