mirror of
https://github.com/kemko/nomad.git
synced 2026-01-03 17:05:43 +03:00
On Windows, if the `raw_exec` driver's executor exits, the child processes are not also killed. Create a Windows "job object" (not to be confused with a Nomad job) and add the executor to it. Child processes of the executor will inherit the job automatically. When the handle to the job object is freed (on executor exit), the job itself is destroyed and this causes all processes in that job to exit. Fixes: https://github.com/hashicorp/nomad/issues/23668 Ref: https://learn.microsoft.com/en-us/windows/win32/procthread/job-objects
97 lines
2.3 KiB
Go
97 lines
2.3 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
//go:build windows
|
|
|
|
package rawexec
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/helper/uuid"
|
|
"github.com/hashicorp/nomad/plugins/base"
|
|
"github.com/hashicorp/nomad/plugins/drivers"
|
|
dtestutil "github.com/hashicorp/nomad/plugins/drivers/testutils"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
// TestRawExecDriver_ExecutorKill verifies that killing the executor will stop
|
|
// its child processes
|
|
func TestRawExecDriver_ExecutorKill(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
d := newEnabledRawExecDriver(t)
|
|
harness := dtestutil.NewDriverHarness(t, d)
|
|
t.Cleanup(harness.Kill)
|
|
|
|
config := &Config{Enabled: true}
|
|
var data []byte
|
|
must.NoError(t, base.MsgPackEncode(&data, config))
|
|
bconfig := &base.Config{
|
|
PluginConfig: data,
|
|
AgentConfig: &base.AgentConfig{
|
|
Driver: &base.ClientDriverConfig{
|
|
Topology: d.nomadConfig.Topology,
|
|
},
|
|
},
|
|
}
|
|
must.NoError(t, harness.SetConfig(bconfig))
|
|
|
|
allocID := uuid.Generate()
|
|
taskName := "test"
|
|
task := &drivers.TaskConfig{
|
|
AllocID: allocID,
|
|
ID: uuid.Generate(),
|
|
Name: taskName,
|
|
Resources: testResources(allocID, taskName),
|
|
}
|
|
|
|
taskConfig := map[string]interface{}{}
|
|
taskConfig["command"] = "Powershell.exe"
|
|
taskConfig["args"] = []string{"sleep", "100s"}
|
|
|
|
must.NoError(t, task.EncodeConcreteDriverConfig(&taskConfig))
|
|
|
|
cleanup := harness.MkAllocDir(task, false)
|
|
t.Cleanup(cleanup)
|
|
|
|
handle, _, err := harness.StartTask(task)
|
|
must.NoError(t, err)
|
|
|
|
var taskState TaskState
|
|
must.NoError(t, handle.GetDriverState(&taskState))
|
|
must.NoError(t, harness.WaitUntilStarted(task.ID, 1*time.Second))
|
|
|
|
// forcibly kill the executor, not the workload
|
|
must.NotEq(t, taskState.ReattachConfig.Pid, taskState.Pid)
|
|
proc, err := os.FindProcess(taskState.ReattachConfig.Pid)
|
|
must.NoError(t, err)
|
|
|
|
taskProc, err := os.FindProcess(taskState.Pid)
|
|
must.NoError(t, err)
|
|
|
|
must.NoError(t, proc.Kill())
|
|
t.Logf("killed %d, waiting on %d to stop", taskState.ReattachConfig.Pid, taskState.Pid)
|
|
|
|
t.Cleanup(func() {
|
|
if taskProc != nil {
|
|
taskProc.Kill()
|
|
}
|
|
})
|
|
|
|
done := make(chan struct{})
|
|
go func() {
|
|
taskProc.Wait()
|
|
close(done)
|
|
}()
|
|
|
|
select {
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("expected child process to exit")
|
|
case <-done:
|
|
}
|
|
}
|