Skip to content

Commit 5615e55

Browse files
committed
Merge branch 'demo_branch2'
This commit merges #348 from Gabriel Ionescu as is. Signed-off-by: Kazuyoshi Kato <katokazu@amazon.com>
2 parents 565c88a + ff57c09 commit 5615e55

File tree

5 files changed

+123
-2
lines changed

5 files changed

+123
-2
lines changed

firecracker.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,23 @@ func (f *Client) CreateSnapshot(ctx context.Context, snapshotParams *models.Snap
265265
return f.client.Operations.CreateSnapshot(params)
266266
}
267267

268+
// LoadSnapshotOpt is a functional option to be used for the
269+
// LoadSnapshot API in setting any additional optional fields.
270+
type LoadSnapshotOpt func(*ops.LoadSnapshotParams)
271+
272+
// LoadSnapshot is a wrapper for the swagger generated client to make
273+
// calling of the API easier.
274+
func (f *Client) LoadSnapshot(ctx context.Context, snapshotParams *models.SnapshotLoadParams, opts ...LoadSnapshotOpt) (*ops.LoadSnapshotNoContent, error) {
275+
params := ops.NewLoadSnapshotParamsWithContext(ctx)
276+
params.SetBody(snapshotParams)
277+
278+
for _, opt := range opts {
279+
opt(params)
280+
}
281+
282+
return f.client.Operations.LoadSnapshot(params)
283+
}
284+
268285
// CreateSyncActionOpt is a functional option to be used for the
269286
// CreateSyncAction API in setting any additional optional fields.
270287
type CreateSyncActionOpt func(*ops.CreateSyncActionParams)

machine.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ func NewMachine(ctx context.Context, cfg Config, opts ...Opt) (*Machine, error)
380380
// handlers succeed, then this will start the VMM instance.
381381
// Start may only be called once per Machine. Subsequent calls will return
382382
// ErrAlreadyStarted.
383-
func (m *Machine) Start(ctx context.Context) error {
383+
func (m *Machine) Start(ctx context.Context, opts ...Opt) error {
384384
m.logger.Debug("Called Machine.Start()")
385385
alreadyStarted := true
386386
m.startOnce.Do(func() {
@@ -401,6 +401,10 @@ func (m *Machine) Start(ctx context.Context) error {
401401
}
402402
}()
403403

404+
for _, opt := range opts {
405+
opt(m)
406+
}
407+
404408
err = m.Handlers.Run(ctx, m)
405409
if err != nil {
406410
return err
@@ -1092,6 +1096,22 @@ func (m *Machine) CreateSnapshot(ctx context.Context, memFilePath, snapshotPath
10921096
return nil
10931097
}
10941098

1099+
// LoadSnapshot load a snapshot
1100+
func (m *Machine) LoadSnapshot(ctx context.Context, memFilePath, snapshotPath string, opts ...LoadSnapshotOpt) error {
1101+
snapshotParams := &models.SnapshotLoadParams{
1102+
MemFilePath: String(memFilePath),
1103+
SnapshotPath: String(snapshotPath),
1104+
}
1105+
1106+
if _, err := m.client.LoadSnapshot(ctx, snapshotParams, opts...); err != nil {
1107+
m.logger.Errorf("failed to load a snapshot for VM: %v", err)
1108+
return err
1109+
}
1110+
1111+
m.logger.Debug("snapshot loaded successfully")
1112+
return nil
1113+
}
1114+
10951115
// CreateBalloon creates a balloon device if one does not exist
10961116
func (m *Machine) CreateBalloon(ctx context.Context, amountMib int64, deflateOnOom bool, statsPollingIntervals int64, opts ...PutBalloonOpt) error {
10971117
balloon := models.Balloon{

machine_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ var (
7171
testBalloonDeflateOnOom = true
7272
testStatsPollingIntervals = int64(1)
7373
testNewStatsPollingIntervals = int64(6)
74+
75+
// How long to wait for the socket to appear.
76+
firecrackerSocketWait = int64(10)
7477
)
7578

7679
func envOrDefault(k, empty string) string {
@@ -1728,6 +1731,76 @@ func TestCreateSnapshot(t *testing.T) {
17281731
}
17291732
}
17301733

1734+
func TestLoadSnapshot(t *testing.T) {
1735+
fctesting.RequiresKVM(t)
1736+
fctesting.RequiresRoot(t)
1737+
1738+
ctx := context.Background()
1739+
1740+
dir, err := ioutil.TempDir("", t.Name())
1741+
require.NoError(t, err)
1742+
defer os.RemoveAll(dir)
1743+
1744+
// Set snap and mem paths
1745+
socketPath := filepath.Join(dir, fsSafeTestName.Replace(t.Name()))
1746+
snapPath := socketPath + "SnapFile"
1747+
memPath := socketPath + "MemFile"
1748+
defer os.Remove(socketPath)
1749+
defer os.Remove(snapPath)
1750+
defer os.Remove(memPath)
1751+
1752+
// Tee logs for validation:
1753+
var logBuffer bytes.Buffer
1754+
machineLogger := logrus.New()
1755+
machineLogger.Out = io.MultiWriter(os.Stderr, &logBuffer)
1756+
1757+
// Create a snapshot
1758+
{
1759+
cfg := createValidConfig(t, socketPath+".create")
1760+
m, err := NewMachine(ctx, cfg, func(m *Machine) {
1761+
// Rewriting m.cmd partially wouldn't work since Cmd has
1762+
// some unexported members
1763+
args := m.cmd.Args[1:]
1764+
m.cmd = exec.Command(getFirecrackerBinaryPath(), args...)
1765+
}, WithLogger(logrus.NewEntry(machineLogger)))
1766+
require.NoError(t, err)
1767+
1768+
err = m.Start(ctx)
1769+
require.NoError(t, err)
1770+
1771+
err = m.PauseVM(ctx)
1772+
require.NoError(t, err)
1773+
1774+
err = m.CreateSnapshot(ctx, memPath, snapPath)
1775+
require.NoError(t, err)
1776+
1777+
err = m.StopVMM()
1778+
require.NoError(t, err)
1779+
}
1780+
1781+
// Load a snapshot
1782+
{
1783+
cfg := createValidConfig(t, socketPath+".load")
1784+
m, err := NewMachine(ctx, cfg, func(m *Machine) {
1785+
// Rewriting m.cmd partially wouldn't work since Cmd has
1786+
// some unexported members
1787+
args := m.cmd.Args[1:]
1788+
m.cmd = exec.Command(getFirecrackerBinaryPath(), args...)
1789+
}, WithLogger(logrus.NewEntry(machineLogger)))
1790+
require.NoError(t, err)
1791+
1792+
err = m.Start(ctx, WithSnapshot(ctx, memPath, snapPath))
1793+
require.NoError(t, err)
1794+
1795+
err = m.ResumeVM(ctx)
1796+
require.NoError(t, err)
1797+
1798+
err = m.StopVMM()
1799+
require.NoError(t, err)
1800+
}
1801+
1802+
}
1803+
17311804
func testCreateBalloon(ctx context.Context, t *testing.T, m *Machine) {
17321805
if err := m.CreateBalloon(ctx, testBalloonMemory, testBalloonDeflateOnOom, testStatsPollingIntervals); err != nil {
17331806
t.Errorf("Create balloon device failed from testAttachBalloon: %s", err)

machineiface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var _ MachineIface = (*Machine)(nil)
2323
// MachineIface can be used for mocking and testing of the Machine. The Machine
2424
// is subject to change, meaning this interface would change.
2525
type MachineIface interface {
26-
Start(context.Context) error
26+
Start(context.Context, ...Opt) error
2727
StopVMM() error
2828
Shutdown(context.Context) error
2929
Wait(context.Context) error

opts.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package firecracker
1515

1616
import (
17+
"context"
1718
"os/exec"
1819

1920
"github.com/sirupsen/logrus"
@@ -47,3 +48,13 @@ func WithProcessRunner(cmd *exec.Cmd) Opt {
4748
machine.cmd = cmd
4849
}
4950
}
51+
52+
// WithSnapshot will allow for the machine to start using a given snapshot.
53+
func WithSnapshot(ctx context.Context, memFilePath, snapshotPath string) Opt {
54+
return func(machine *Machine) {
55+
err := machine.LoadSnapshot(ctx, memFilePath, snapshotPath)
56+
if err != nil {
57+
machine.logger.Errorf("LoadSnapshot failed with %s", err)
58+
}
59+
}
60+
}

0 commit comments

Comments
 (0)