Skip to content

Commit fccb4f3

Browse files
authored
feat: saves containerd user data to a persistent disk (#133)
this allows users to retain downloaded images, containers, etc. across new installations of finch Signed-off-by: Sam Berning <[email protected]> Issue #, if available: #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]>
1 parent 70b8e55 commit fccb4f3

18 files changed

+779
-33
lines changed

Diff for: cmd/finch/main.go

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ package main
77
import (
88
"fmt"
99

10+
"github.com/runfinch/finch/pkg/disk"
11+
1012
"github.com/runfinch/finch/pkg/command"
1113
"github.com/runfinch/finch/pkg/config"
1214
"github.com/runfinch/finch/pkg/dependency"
@@ -108,6 +110,7 @@ func virtualMachineCommands(
108110
config.NewNerdctlApplier(fssh.NewDialer(), fs, fp.LimaSSHPrivateKeyPath(), system.NewStdLib()),
109111
fp,
110112
fs,
113+
disk.NewUserDataDiskManager(lcc, &afero.OsFs{}, fp, system.NewStdLib().Env("HOME")),
111114
)
112115
}
113116

Diff for: cmd/finch/virtual_machine.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"fmt"
88
"strings"
99

10+
"github.com/runfinch/finch/pkg/disk"
11+
1012
"github.com/runfinch/finch/pkg/command"
1113
"github.com/runfinch/finch/pkg/config"
1214
"github.com/runfinch/finch/pkg/dependency"
@@ -30,17 +32,19 @@ func newVirtualMachineCommand(
3032
nca config.NerdctlConfigApplier,
3133
fp path.Finch,
3234
fs afero.Fs,
35+
diskManager disk.UserDataDiskManager,
3336
) *cobra.Command {
3437
virtualMachineCommand := &cobra.Command{
3538
Use: virtualMachineRootCmd,
3639
Short: "Manage the virtual machine lifecycle",
3740
}
3841

3942
virtualMachineCommand.AddCommand(
40-
newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath()),
43+
newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath(), diskManager),
4144
newStopVMCommand(limaCmdCreator, logger),
4245
newRemoveVMCommand(limaCmdCreator, logger),
43-
newInitVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fp.BaseYamlFilePath(), fs, fp.LimaSSHPrivateKeyPath()),
46+
newInitVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fp.BaseYamlFilePath(), fs,
47+
fp.LimaSSHPrivateKeyPath(), diskManager),
4448
)
4549

4650
return virtualMachineCommand

Diff for: cmd/finch/virtual_machine_init.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package main
66
import (
77
"fmt"
88

9+
"github.com/runfinch/finch/pkg/disk"
10+
911
"github.com/runfinch/finch/pkg/command"
1012
"github.com/runfinch/finch/pkg/config"
1113
"github.com/runfinch/finch/pkg/dependency"
@@ -25,11 +27,12 @@ func newInitVMCommand(
2527
baseYamlFilePath string,
2628
fs afero.Fs,
2729
privateKeyPath string,
30+
diskManager disk.UserDataDiskManager,
2831
) *cobra.Command {
2932
initVMCommand := &cobra.Command{
3033
Use: "init",
3134
Short: "Initialize the virtual machine",
32-
RunE: newInitVMAction(lcc, logger, optionalDepGroups, lca, baseYamlFilePath).runAdapter,
35+
RunE: newInitVMAction(lcc, logger, optionalDepGroups, lca, baseYamlFilePath, diskManager).runAdapter,
3336
PostRunE: newPostVMStartInitAction(logger, lcc, fs, privateKeyPath, nca).runAdapter,
3437
}
3538

@@ -42,6 +45,7 @@ type initVMAction struct {
4245
logger flog.Logger
4346
optionalDepGroups []*dependency.Group
4447
limaConfigApplier config.LimaConfigApplier
48+
diskManager disk.UserDataDiskManager
4549
}
4650

4751
func newInitVMAction(
@@ -50,9 +54,15 @@ func newInitVMAction(
5054
optionalDepGroups []*dependency.Group,
5155
lca config.LimaConfigApplier,
5256
baseYamlFilePath string,
57+
diskManager disk.UserDataDiskManager,
5358
) *initVMAction {
5459
return &initVMAction{
55-
creator: creator, logger: logger, optionalDepGroups: optionalDepGroups, limaConfigApplier: lca, baseYamlFilePath: baseYamlFilePath,
60+
creator: creator,
61+
logger: logger,
62+
optionalDepGroups: optionalDepGroups,
63+
limaConfigApplier: lca,
64+
baseYamlFilePath: baseYamlFilePath,
65+
diskManager: diskManager,
5666
}
5767
}
5868

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

6373
func (iva *initVMAction) run() error {
64-
err := iva.assertVMIsNonexistent(iva.creator, iva.logger)
74+
err := iva.assertVMIsNonexistent()
6575
if err != nil {
6676
return err
6777
}
@@ -76,6 +86,11 @@ func (iva *initVMAction) run() error {
7686
return err
7787
}
7888

89+
err = iva.diskManager.EnsureUserDataDisk()
90+
if err != nil {
91+
return err
92+
}
93+
7994
instanceName := fmt.Sprintf("--name=%v", limaInstanceName)
8095
limaCmd := iva.creator.CreateWithoutStdio("start", instanceName, iva.baseYamlFilePath, "--tty=false")
8196
iva.logger.Info("Initializing and starting Finch virtual machine...")
@@ -88,8 +103,8 @@ func (iva *initVMAction) run() error {
88103
return nil
89104
}
90105

91-
func (iva *initVMAction) assertVMIsNonexistent(creator command.LimaCmdCreator, logger flog.Logger) error {
92-
status, err := lima.GetVMStatus(creator, logger, limaInstanceName)
106+
func (iva *initVMAction) assertVMIsNonexistent() error {
107+
status, err := lima.GetVMStatus(iva.creator, iva.logger, limaInstanceName)
93108
if err != nil {
94109
return err
95110
}

Diff for: cmd/finch/virtual_machine_init_test.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const mockBaseYamlFilePath = "/os/os.yaml"
2121
func TestNewInitVMCommand(t *testing.T) {
2222
t.Parallel()
2323

24-
cmd := newInitVMCommand(nil, nil, nil, nil, nil, "", nil, "")
24+
cmd := newInitVMCommand(nil, nil, nil, nil, nil, "", nil, "", nil)
2525
assert.Equal(t, cmd.Name(), "init")
2626
}
2727

@@ -37,6 +37,7 @@ func TestInitVMAction_runAdapter(t *testing.T) {
3737
*mocks.LimaCmdCreator,
3838
*mocks.Logger,
3939
*mocks.LimaConfigApplier,
40+
*mocks.MockUserDataDiskManager,
4041
*gomock.Controller,
4142
)
4243
}{
@@ -61,6 +62,7 @@ func TestInitVMAction_runAdapter(t *testing.T) {
6162
lcc *mocks.LimaCmdCreator,
6263
logger *mocks.Logger,
6364
lca *mocks.LimaConfigApplier,
65+
dm *mocks.MockUserDataDiskManager,
6466
ctrl *gomock.Controller,
6567
) {
6668
getVMStatusC := mocks.NewCommand(ctrl)
@@ -70,6 +72,7 @@ func TestInitVMAction_runAdapter(t *testing.T) {
7072

7173
command := mocks.NewCommand(ctrl)
7274
lca.EXPECT().Apply().Return(nil)
75+
dm.EXPECT().EnsureUserDataDisk().Return(nil)
7376
lcc.EXPECT().CreateWithoutStdio("start", fmt.Sprintf("--name=%s", limaInstanceName),
7477
mockBaseYamlFilePath, "--tty=false").Return(command)
7578
command.EXPECT().CombinedOutput()
@@ -89,11 +92,12 @@ func TestInitVMAction_runAdapter(t *testing.T) {
8992
logger := mocks.NewLogger(ctrl)
9093
lcc := mocks.NewLimaCmdCreator(ctrl)
9194
lca := mocks.NewLimaConfigApplier(ctrl)
95+
dm := mocks.NewMockUserDataDiskManager(ctrl)
9296

9397
groups := tc.groups(ctrl)
94-
tc.mockSvc(lcc, logger, lca, ctrl)
98+
tc.mockSvc(lcc, logger, lca, dm, ctrl)
9599

96-
assert.NoError(t, newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath).runAdapter(tc.command, tc.args))
100+
assert.NoError(t, newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath, dm).runAdapter(tc.command, tc.args))
97101
})
98102
}
99103
}
@@ -109,6 +113,7 @@ func TestInitVMAction_run(t *testing.T) {
109113
*mocks.LimaCmdCreator,
110114
*mocks.Logger,
111115
*mocks.LimaConfigApplier,
116+
*mocks.MockUserDataDiskManager,
112117
*gomock.Controller,
113118
)
114119
}{
@@ -122,6 +127,7 @@ func TestInitVMAction_run(t *testing.T) {
122127
lcc *mocks.LimaCmdCreator,
123128
logger *mocks.Logger,
124129
lca *mocks.LimaConfigApplier,
130+
dm *mocks.MockUserDataDiskManager,
125131
ctrl *gomock.Controller,
126132
) {
127133
getVMStatusC := mocks.NewCommand(ctrl)
@@ -130,6 +136,7 @@ func TestInitVMAction_run(t *testing.T) {
130136
logger.EXPECT().Debugf("Status of virtual machine: %s", "")
131137

132138
lca.EXPECT().Apply().Return(nil)
139+
dm.EXPECT().EnsureUserDataDisk().Return(nil)
133140

134141
command := mocks.NewCommand(ctrl)
135142
lcc.EXPECT().CreateWithoutStdio("start", fmt.Sprintf("--name=%s", limaInstanceName),
@@ -150,6 +157,7 @@ func TestInitVMAction_run(t *testing.T) {
150157
lcc *mocks.LimaCmdCreator,
151158
logger *mocks.Logger,
152159
lca *mocks.LimaConfigApplier,
160+
dm *mocks.MockUserDataDiskManager,
153161
ctrl *gomock.Controller,
154162
) {
155163
getVMStatusC := mocks.NewCommand(ctrl)
@@ -170,6 +178,7 @@ func TestInitVMAction_run(t *testing.T) {
170178
lcc *mocks.LimaCmdCreator,
171179
logger *mocks.Logger,
172180
lca *mocks.LimaConfigApplier,
181+
dm *mocks.MockUserDataDiskManager,
173182
ctrl *gomock.Controller,
174183
) {
175184
getVMStatusC := mocks.NewCommand(ctrl)
@@ -188,6 +197,7 @@ func TestInitVMAction_run(t *testing.T) {
188197
lcc *mocks.LimaCmdCreator,
189198
logger *mocks.Logger,
190199
lca *mocks.LimaConfigApplier,
200+
dm *mocks.MockUserDataDiskManager,
191201
ctrl *gomock.Controller,
192202
) {
193203
getVMStatusC := mocks.NewCommand(ctrl)
@@ -206,6 +216,7 @@ func TestInitVMAction_run(t *testing.T) {
206216
lcc *mocks.LimaCmdCreator,
207217
logger *mocks.Logger,
208218
lca *mocks.LimaConfigApplier,
219+
dm *mocks.MockUserDataDiskManager,
209220
ctrl *gomock.Controller,
210221
) {
211222
getVMStatusC := mocks.NewCommand(ctrl)
@@ -234,6 +245,7 @@ func TestInitVMAction_run(t *testing.T) {
234245
lcc *mocks.LimaCmdCreator,
235246
logger *mocks.Logger,
236247
lca *mocks.LimaConfigApplier,
248+
dm *mocks.MockUserDataDiskManager,
237249
ctrl *gomock.Controller,
238250
) {
239251
getVMStatusC := mocks.NewCommand(ctrl)
@@ -257,6 +269,7 @@ func TestInitVMAction_run(t *testing.T) {
257269
lcc *mocks.LimaCmdCreator,
258270
logger *mocks.Logger,
259271
lca *mocks.LimaConfigApplier,
272+
dm *mocks.MockUserDataDiskManager,
260273
ctrl *gomock.Controller,
261274
) {
262275
getVMStatusC := mocks.NewCommand(ctrl)
@@ -265,6 +278,7 @@ func TestInitVMAction_run(t *testing.T) {
265278
logger.EXPECT().Debugf("Status of virtual machine: %s", "")
266279

267280
lca.EXPECT().Apply().Return(nil)
281+
dm.EXPECT().EnsureUserDataDisk().Return(nil)
268282

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

291306
groups := tc.groups(ctrl)
292-
tc.mockSvc(lcc, logger, lca, ctrl)
307+
tc.mockSvc(lcc, logger, lca, dm, ctrl)
293308

294-
err := newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath).run()
309+
err := newInitVMAction(lcc, logger, groups, lca, mockBaseYamlFilePath, dm).run()
295310
assert.Equal(t, err, tc.wantErr)
296311
})
297312
}

Diff for: cmd/finch/virtual_machine_start.go

+22-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package main
66
import (
77
"fmt"
88

9+
"github.com/runfinch/finch/pkg/disk"
10+
911
"github.com/runfinch/finch/pkg/command"
1012
"github.com/runfinch/finch/pkg/config"
1113
"github.com/runfinch/finch/pkg/dependency"
@@ -24,29 +26,38 @@ func newStartVMCommand(
2426
nca config.NerdctlConfigApplier,
2527
fs afero.Fs,
2628
privateKeyPath string,
29+
dm disk.UserDataDiskManager,
2730
) *cobra.Command {
2831
return &cobra.Command{
2932
Use: "start",
3033
Short: "Start the virtual machine",
31-
RunE: newStartVMAction(lcc, logger, optionalDepGroups, lca).runAdapter,
34+
RunE: newStartVMAction(lcc, logger, optionalDepGroups, lca, dm).runAdapter,
3235
PostRunE: newPostVMStartInitAction(logger, lcc, fs, privateKeyPath, nca).runAdapter,
3336
}
3437
}
3538

3639
type startVMAction struct {
37-
creator command.LimaCmdCreator
38-
logger flog.Logger
39-
optionalDepGroups []*dependency.Group
40-
limaConfigApplier config.LimaConfigApplier
40+
creator command.LimaCmdCreator
41+
logger flog.Logger
42+
optionalDepGroups []*dependency.Group
43+
limaConfigApplier config.LimaConfigApplier
44+
userDataDiskManager disk.UserDataDiskManager
4145
}
4246

4347
func newStartVMAction(
4448
creator command.LimaCmdCreator,
4549
logger flog.Logger,
4650
optionalDepGroups []*dependency.Group,
4751
lca config.LimaConfigApplier,
52+
dm disk.UserDataDiskManager,
4853
) *startVMAction {
49-
return &startVMAction{creator: creator, logger: logger, optionalDepGroups: optionalDepGroups, limaConfigApplier: lca}
54+
return &startVMAction{
55+
creator: creator,
56+
logger: logger,
57+
optionalDepGroups: optionalDepGroups,
58+
limaConfigApplier: lca,
59+
userDataDiskManager: dm,
60+
}
5061
}
5162

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

82+
err = sva.userDataDiskManager.EnsureUserDataDisk()
83+
if err != nil {
84+
return err
85+
}
86+
7187
limaCmd := sva.creator.CreateWithoutStdio("start", limaInstanceName)
7288
sva.logger.Info("Starting existing Finch virtual machine...")
7389
logs, err := limaCmd.CombinedOutput()

0 commit comments

Comments
 (0)