Skip to content

Commit 6579aae

Browse files
committed
LoadSnapshot
Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
1 parent 565c88a commit 6579aae

File tree

4 files changed

+116
-0
lines changed

4 files changed

+116
-0
lines changed

firecracker.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,18 @@ func (f *Client) PatchBalloonStatsInterval(ctx context.Context, balloonStatsUpda
474474

475475
return f.client.Operations.PatchBalloonStatsInterval(params)
476476
}
477+
478+
type LoadSnapshotOpt func(*ops.LoadSnapshotParams)
479+
480+
func (f *Client) LoadSnapshot(ctx context.Context, cfg *models.SnapshotLoadParams, opts ...LoadSnapshotOpt) (*ops.LoadSnapshotNoContent, error) {
481+
timeout, cancel := context.WithTimeout(ctx, time.Duration(f.firecrackerRequestTimeout)*time.Millisecond)
482+
defer cancel()
483+
484+
params := ops.NewLoadSnapshotParamsWithContext(timeout)
485+
params.SetBody(cfg)
486+
for _, opt := range opts {
487+
opt(params)
488+
}
489+
490+
return f.client.Operations.LoadSnapshot(params)
491+
}

handlers.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,10 @@ var defaultFcInitHandlerList = HandlerList{}.Append(
286286
StartVMMHandler,
287287
CreateLogFilesHandler,
288288
BootstrapLoggingHandler,
289+
289290
CreateMachineHandler,
290291
CreateBootSourceHandler,
292+
291293
AttachDrivesHandler,
292294
CreateNetworkInterfacesHandler,
293295
AddVsocksHandler,

machine.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,22 @@ type Config struct {
150150
// It is possible to use a valid IPv4 link-local address (169.254.0.0/16).
151151
// If not provided, the default address (169.254.169.254) will be used.
152152
MmdsAddress net.IP
153+
154+
Snapshot SnapshotConfig
155+
}
156+
157+
func (cfg *Config) validateSnapshot() error {
158+
ss := cfg.Snapshot
159+
160+
if _, err := os.Stat(ss.MemFilePath); err != nil {
161+
return fmt.Errorf("failed to stat snapshot memory file path, %q: %v", cfg.KernelImagePath, err)
162+
}
163+
164+
if _, err := os.Stat(ss.SnapshotPath); err != nil {
165+
return fmt.Errorf("failed to stat snapshot file path, %q: %v", cfg.InitrdPath, err)
166+
}
167+
168+
return nil
153169
}
154170

155171
// Validate will ensure that the required fields are set and that
@@ -159,6 +175,11 @@ func (cfg *Config) Validate() error {
159175
return nil
160176
}
161177

178+
ss := cfg.Snapshot
179+
if ss.SnapshotPath != "" || ss.MemFilePath != "" {
180+
return cfg.validateSnapshot()
181+
}
182+
162183
if _, err := os.Stat(cfg.KernelImagePath); err != nil {
163184
return fmt.Errorf("failed to stat kernel image path, %q: %v", cfg.KernelImagePath, err)
164185
}
@@ -718,6 +739,17 @@ func (m *Machine) captureFifoToFileWithChannel(ctx context.Context, logger *log.
718739
}
719740

720741
func (m *Machine) createMachine(ctx context.Context) error {
742+
ss := m.Cfg.Snapshot
743+
if ss.SnapshotPath != "" || ss.MemFilePath != "" {
744+
_, err := m.client.LoadSnapshot(ctx, &models.SnapshotLoadParams{
745+
SnapshotPath: String(ss.SnapshotPath),
746+
MemFilePath: String(ss.MemFilePath),
747+
EnableDiffSnapshots: ss.EnableDiffSnapshots,
748+
ResumeVM: ss.ResumeVM,
749+
})
750+
return err
751+
}
752+
721753
resp, err := m.client.PutMachineConfiguration(ctx, &m.Cfg.MachineCfg)
722754
if err != nil {
723755
m.logger.Errorf("PutMachineConfiguration returned %s", resp.Error())
@@ -734,6 +766,11 @@ func (m *Machine) createMachine(ctx context.Context) error {
734766
}
735767

736768
func (m *Machine) createBootSource(ctx context.Context, imagePath, initrdPath, kernelArgs string) error {
769+
ss := m.Cfg.Snapshot
770+
if ss.SnapshotPath != "" || ss.MemFilePath != "" {
771+
return nil
772+
}
773+
737774
bsrc := models.BootSource{
738775
KernelImagePath: &imagePath,
739776
InitrdPath: initrdPath,
@@ -841,6 +878,10 @@ func (m *Machine) addVsock(ctx context.Context, dev VsockDevice) error {
841878
}
842879

843880
func (m *Machine) startInstance(ctx context.Context) error {
881+
if m.Cfg.Snapshot.SnapshotPath != "" || m.Cfg.Snapshot.MemFilePath != "" {
882+
return nil
883+
}
884+
844885
action := models.InstanceActionInfoActionTypeInstanceStart
845886
info := models.InstanceActionInfo{
846887
ActionType: &action,

machine_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,6 +1728,64 @@ func TestCreateSnapshot(t *testing.T) {
17281728
}
17291729
}
17301730

1731+
func TestSnapshot(t *testing.T) {
1732+
fctesting.RequiresKVM(t)
1733+
fctesting.RequiresRoot(t)
1734+
1735+
ctx, cancel := context.WithCancel(context.Background())
1736+
defer cancel()
1737+
1738+
snapshotDir := t.TempDir()
1739+
snapPath := filepath.Join(snapshotDir, "snap.out")
1740+
memPath := filepath.Join(snapshotDir, "mem.out")
1741+
1742+
t.Run("create", func(t *testing.T) {
1743+
cfg := createValidConfig(t, filepath.Join(snapshotDir, "fc.sock"))
1744+
m, err := NewMachine(ctx, cfg, func(m *Machine) {
1745+
args := m.cmd.Args[1:]
1746+
m.cmd = exec.Command(getFirecrackerBinaryPath(), args...)
1747+
})
1748+
require.NoError(t, err)
1749+
1750+
err = m.Start(ctx)
1751+
require.NoError(t, err)
1752+
1753+
err = m.PauseVM(ctx)
1754+
require.NoError(t, err)
1755+
1756+
err = m.CreateSnapshot(ctx, memPath, snapPath)
1757+
require.NoError(t, err)
1758+
1759+
err = m.StopVMM()
1760+
require.NoError(t, err)
1761+
})
1762+
1763+
t.Run("load", func(t *testing.T) {
1764+
dir := t.TempDir()
1765+
cfg := Config{
1766+
SocketPath: filepath.Join(dir, "fc.sock"),
1767+
Snapshot: SnapshotConfig{
1768+
SnapshotPath: snapPath,
1769+
MemFilePath: memPath,
1770+
},
1771+
}
1772+
m, err := NewMachine(ctx, cfg, func(m *Machine) {
1773+
args := m.cmd.Args[1:]
1774+
m.cmd = exec.Command(getFirecrackerBinaryPath(), args...)
1775+
})
1776+
require.NoError(t, err)
1777+
1778+
err = m.Start(ctx)
1779+
require.NoError(t, err)
1780+
1781+
err = m.ResumeVM(ctx)
1782+
require.NoError(t, err)
1783+
1784+
err = m.StopVMM()
1785+
require.NoError(t, err)
1786+
})
1787+
}
1788+
17311789
func testCreateBalloon(ctx context.Context, t *testing.T, m *Machine) {
17321790
if err := m.CreateBalloon(ctx, testBalloonMemory, testBalloonDeflateOnOom, testStatsPollingIntervals); err != nil {
17331791
t.Errorf("Create balloon device failed from testAttachBalloon: %s", err)

0 commit comments

Comments
 (0)