Skip to content

Commit 479ac13

Browse files
author
Noah Meyerhans
committed
Merge branch 'ctrlaltdel'
2 parents 21b7278 + a1b30bf commit 479ac13

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
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: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func TestJailerMicroVMExecution(t *testing.T) {
140140
jailerFullRootPath := filepath.Join(jailerTestPath, "firecracker", id)
141141
os.MkdirAll(jailerTestPath, 0777)
142142

143-
socketPath := filepath.Join(jailerTestPath, "firecracker", "api.socket")
143+
socketPath := filepath.Join(jailerTestPath, "firecracker", "TestJailerMicroVMExecution.socket")
144144
logFifo := filepath.Join(testDataPath, "firecracker.log")
145145
metricsFifo := filepath.Join(testDataPath, "firecracker-metrics")
146146
defer func() {
@@ -257,7 +257,7 @@ func TestMicroVMExecution(t *testing.T) {
257257
var nCpus int64 = 2
258258
cpuTemplate := models.CPUTemplate(models.CPUTemplateT2)
259259
var memSz int64 = 256
260-
socketPath := filepath.Join(testDataPath, "firecracker.sock")
260+
socketPath := filepath.Join(testDataPath, "TestMicroVMExecution.sock")
261261
logFifo := filepath.Join(testDataPath, "firecracker.log")
262262
metricsFifo := filepath.Join(testDataPath, "firecracker-metrics")
263263
defer func() {
@@ -323,22 +323,25 @@ func TestMicroVMExecution(t *testing.T) {
323323
t.Run("TestAttachSecondaryDrive", func(t *testing.T) { testAttachSecondaryDrive(ctx, t, m) })
324324
t.Run("TestAttachVsock", func(t *testing.T) { testAttachVsock(ctx, t, m) })
325325
t.Run("SetMetadata", func(t *testing.T) { testSetMetadata(ctx, t, m) })
326-
t.Run("TestUpdateGuestDrive", func(t *testing.T) { testUpdateGuestDrive(vmmCtx, t, m) })
327-
t.Run("TestStartInstance", func(t *testing.T) { testStartInstance(vmmCtx, t, m) })
326+
t.Run("TestUpdateGuestDrive", func(t *testing.T) { testUpdateGuestDrive(ctx, t, m) })
327+
t.Run("TestStartInstance", func(t *testing.T) { testStartInstance(ctx, t, m) })
328328

329329
// Let the VMM start and stabilize...
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(ctx, t, m) })
334334
case <-exitchannel:
335335
// if we've already exited, there's no use waiting for the timer
336336
}
337+
// unconditionally stop the VM here. TestShutdown may have triggered a shutdown, but if it
338+
// didn't for some reason, we still need to terminate it:
339+
m.StopVMM()
337340
m.Wait(vmmCtx)
338341
}
339342

340343
func TestStartVMM(t *testing.T) {
341-
socketPath := filepath.Join("testdata", "fc-start-vmm-test.sock")
344+
socketPath := filepath.Join("testdata", "TestStartVMM.sock")
342345
defer os.Remove(socketPath)
343346
cfg := Config{
344347
SocketPath: socketPath,
@@ -370,11 +373,10 @@ func TestStartVMM(t *testing.T) {
370373
t.Errorf("startVMM returned %s", m.Wait(ctx))
371374
}
372375
}
373-
374376
}
375377

376378
func TestStartVMMOnce(t *testing.T) {
377-
socketPath := filepath.Join("testdata", "fc-start-vmm-test.sock")
379+
socketPath := filepath.Join("testdata", "TestStartVMMOnce.sock")
378380
defer os.Remove(socketPath)
379381

380382
cfg := Config{
@@ -410,6 +412,7 @@ func TestStartVMMOnce(t *testing.T) {
410412
case <-timeout.Done():
411413
if timeout.Err() == context.DeadlineExceeded {
412414
t.Log("firecracker ran for 250ms")
415+
t.Run("TestStopVMM", func(t *testing.T) { testStopVMM(ctx, t, m) })
413416
} else {
414417
t.Errorf("startVMM returned %s", m.Wait(ctx))
415418
}
@@ -565,6 +568,13 @@ func testStopVMM(ctx context.Context, t *testing.T, m *Machine) {
565568
}
566569
}
567570

571+
func testShutdown(ctx context.Context, t *testing.T, m *Machine) {
572+
err := m.Shutdown(ctx)
573+
if err != nil {
574+
t.Errorf("machine.Shutdown() failed: %s", err)
575+
}
576+
}
577+
568578
func TestWaitForSocket(t *testing.T) {
569579
okClient := fctesting.MockClient{}
570580
errClient := fctesting.MockClient{

0 commit comments

Comments
 (0)