Skip to content

Commit a5e27b9

Browse files
committed
allocRunner: add restore test when allocDir is gone
1 parent 8637ab6 commit a5e27b9

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

client/allocrunner/alloc_runner_unix_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"time"
1515

1616
"github.com/hashicorp/nomad/ci"
17+
"github.com/hashicorp/nomad/client/allocdir"
1718
regMock "github.com/hashicorp/nomad/client/serviceregistration/mock"
1819
"github.com/hashicorp/nomad/client/state"
1920
"github.com/hashicorp/nomad/client/taskenv"
@@ -108,6 +109,8 @@ func TestAllocRunner_Restore_RunningTerminal(t *testing.T) {
108109

109110
// Use original statedb to maintain hook state
110111
conf2.StateDB = conf.StateDB
112+
conf2.ClientConfig.AllocDir = conf.ClientConfig.AllocDir
113+
conf2.ClientConfig.AllocMountsDir = conf.ClientConfig.AllocMountsDir
111114

112115
// Restore, start, and wait for task to be killed
113116
ar2Iface, err := NewAllocRunner(conf2)
@@ -203,6 +206,8 @@ func TestAllocRunner_Restore_CompletedBatch(t *testing.T) {
203206

204207
// Use original statedb to maintain hook state
205208
conf2.StateDB = conf.StateDB
209+
conf2.ClientConfig.AllocDir = conf.ClientConfig.AllocDir
210+
conf2.ClientConfig.AllocMountsDir = conf.ClientConfig.AllocMountsDir
206211

207212
// Restore, start, and wait for task to be killed
208213
ar2Iface, err := NewAllocRunner(conf2)
@@ -307,3 +312,80 @@ func (*allocFailingPrestartHook) Name() string { return "failing_prestart" }
307312
func (*allocFailingPrestartHook) Prerun(_ *taskenv.TaskEnv) error {
308313
return fmt.Errorf("failing prestart hooks")
309314
}
315+
316+
// TestAllocRunner_Restore_MissingAllocDir asserts that restoring a running
317+
// system alloc fails if client.alloc_dir was wiped.
318+
func TestAllocRunner_Restore_MissingAllocDir(t *testing.T) {
319+
ci.Parallel(t)
320+
321+
alloc := mock.Alloc()
322+
alloc.Job.Type = structs.JobTypeSystem
323+
taskName := alloc.Job.TaskGroups[0].Tasks[0].Name
324+
alloc.Job.TaskGroups[0].Tasks[0].Driver = "mock_driver"
325+
alloc.Job.TaskGroups[0].Tasks[0].Config = map[string]interface{}{
326+
"run_for": "1h",
327+
}
328+
329+
conf, cleanup := testAllocRunnerConfig(t, alloc.Copy())
330+
defer cleanup()
331+
332+
// Persist task hook state across runner restarts to simulate data_dir.
333+
conf.StateDB = state.NewMemDB(conf.Logger)
334+
335+
arIface, err := NewAllocRunner(conf)
336+
must.NoError(t, err)
337+
ar := arIface.(*allocRunner)
338+
339+
go ar.Run()
340+
defer destroy(ar)
341+
342+
testutil.WaitForResult(func() (bool, error) {
343+
state := ar.AllocState()
344+
ts, ok := state.TaskStates[taskName]
345+
if !ok || ts == nil {
346+
return false, fmt.Errorf("expected task to be running")
347+
}
348+
if ts.State != structs.TaskStateRunning {
349+
return false, fmt.Errorf("expected task to be running")
350+
}
351+
return true, nil
352+
}, func(err error) {
353+
require.NoError(t, err)
354+
})
355+
356+
allocDirPath := ar.GetAllocDir().AllocDirPath()
357+
358+
ar.Shutdown()
359+
select {
360+
case <-ar.ShutdownCh():
361+
case <-time.After(30 * time.Second):
362+
require.Fail(t, "AR took too long to exit")
363+
}
364+
365+
// Unmount dangling mounts to allow folder deletion in this test process suite
366+
allocDirImpl, _ := ar.GetAllocDir().(*allocdir.AllocDir)
367+
if allocDirImpl != nil {
368+
require.NoError(t, allocDirImpl.UnmountAll())
369+
}
370+
require.NoError(t, os.RemoveAll(allocDirPath))
371+
372+
conf2, cleanup2 := testAllocRunnerConfig(t, alloc.Copy())
373+
defer cleanup2()
374+
375+
// Reuse persistent state and the same alloc storage path after restart.
376+
conf2.StateDB = conf.StateDB
377+
conf2.ClientConfig.AllocDir = conf.ClientConfig.AllocDir
378+
conf2.ClientConfig.AllocMountsDir = conf.ClientConfig.AllocMountsDir
379+
380+
ar2Iface, err := NewAllocRunner(conf2)
381+
must.NoError(t, err)
382+
ar2 := ar2Iface.(*allocRunner)
383+
defer destroy(ar2)
384+
385+
err = ar2.Restore()
386+
must.ErrorContains(t, err, "allocation directory is inacessible")
387+
388+
// Usually set by client.go restoreState handle code
389+
ar2.SetClientStatus(structs.AllocClientStatusFailed)
390+
must.Eq(t, structs.AllocClientStatusFailed, ar2.AllocState().ClientStatus)
391+
}

0 commit comments

Comments
 (0)