Skip to content

Commit 214aa88

Browse files
author
Noah Meyerhans
committed
Add machine.Shutdown method
machine.Shutdown wraps the SendCtrlAltDel firecracker API, allowing the caller to request a clean shutdown of the guest by sending CtrlAltDel on the virtual keyboard. Signed-off-by: Noah Meyerhans <[email protected]>
1 parent 21b7278 commit 214aa88

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

machine.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ func (m *Machine) Start(ctx context.Context) error {
260260
return m.startInstance(ctx)
261261
}
262262

263+
// Shutdown requests a clean shutdown of the VM by sending CtrlAltDelete on the virtual keyboard
264+
func (m *Machine) Shutdown(ctx context.Context) error {
265+
m.logger.Debug("Called machine.Shutdown()")
266+
return m.sendCtrlAltDel(ctx)
267+
}
268+
263269
// Wait will wait until the firecracker process has finished. Wait is safe to
264270
// call concurrently, and will deliver the same error to all callers, subject to
265271
// each caller's context cancellation.
@@ -571,6 +577,20 @@ func (m *Machine) startInstance(ctx context.Context) error {
571577
return err
572578
}
573579

580+
func (m *Machine) sendCtrlAltDel(ctx context.Context) error {
581+
info := models.InstanceActionInfo{
582+
ActionType: models.InstanceActionInfoActionTypeSendCtrlAltDel,
583+
}
584+
585+
resp, err := m.client.CreateSyncAction(ctx, &info)
586+
if err == nil {
587+
m.logger.Printf("Sent instance shutdown request: %s", resp.Error())
588+
} else {
589+
m.logger.Errorf("Unable to send CtrlAltDel: %s", err)
590+
}
591+
return err
592+
}
593+
574594
// EnableMetadata will append or replace the metadata handler.
575595
func (m *Machine) EnableMetadata(metadata interface{}) {
576596
m.Handlers.FcInit = m.Handlers.FcInit.Swappend(NewSetMetadataHandler(metadata))

machine_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ func TestMicroVMExecution(t *testing.T) {
330330
timer := time.NewTimer(5 * time.Second)
331331
select {
332332
case <-timer.C:
333-
t.Run("TestStopVMM", func(t *testing.T) { testStopVMM(ctx, t, m) })
333+
t.Run("TestShutdown", func(t *testing.T) { testShutdown(vmmCtx, t, m) })
334334
case <-exitchannel:
335335
// if we've already exited, there's no use waiting for the timer
336336
}
@@ -370,7 +370,6 @@ func TestStartVMM(t *testing.T) {
370370
t.Errorf("startVMM returned %s", m.Wait(ctx))
371371
}
372372
}
373-
374373
}
375374

376375
func TestStartVMMOnce(t *testing.T) {
@@ -410,6 +409,7 @@ func TestStartVMMOnce(t *testing.T) {
410409
case <-timeout.Done():
411410
if timeout.Err() == context.DeadlineExceeded {
412411
t.Log("firecracker ran for 250ms")
412+
t.Run("TestStopVMM", func(t *testing.T) { testStopVMM(ctx, t, m) })
413413
} else {
414414
t.Errorf("startVMM returned %s", m.Wait(ctx))
415415
}
@@ -565,6 +565,13 @@ func testStopVMM(ctx context.Context, t *testing.T, m *Machine) {
565565
}
566566
}
567567

568+
func testShutdown(ctx context.Context, t *testing.T, m *Machine) {
569+
err := m.Shutdown(ctx)
570+
if err != nil {
571+
t.Errorf("machine.Shutdown() failed: %s", err)
572+
}
573+
}
574+
568575
func TestWaitForSocket(t *testing.T) {
569576
okClient := fctesting.MockClient{}
570577
errClient := fctesting.MockClient{

0 commit comments

Comments
 (0)