open-nomad/client/driver/executor/executor_windows.go
Nick Ethier 5dee1141d1 executor v2 (#4656)
* client/executor: refactor client to remove interpolation

* executor: POC libcontainer based executor

* vendor: use hashicorp libcontainer fork

* vendor: add libcontainer/nsenter dep

* executor: updated executor interface to simplify operations

* executor: implement logging pipe

* logmon: new logmon plugin to manage task logs

* driver/executor: use logmon for log management

* executor: fix tests and windows build

* executor: fix logging key names

* executor: fix test failures

* executor: add config field to toggle between using libcontainer and standard executors

* logmon: use discover utility to discover nomad executable

* executor: only call libcontainer-shim on main in linux

* logmon: use seperate path configs for stdout/stderr fifos

* executor: windows fixes

* executor: created reusable pid stats collection utility that can be used in an executor

* executor: update fifo.Open calls

* executor: fix build

* remove executor from docker driver

* executor: Shutdown func to kill and cleanup executor and its children

* executor: move linux specific universal executor funcs to seperate file

* move logmon initialization to a task runner hook

* client: doc fixes and renaming from code review


* taskrunner: use shared config struct for logmon fifo fields

* taskrunner: logmon only needs to be started once per task
2018-10-16 16:53:31 -07:00

70 lines
2.1 KiB
Go

package executor
import (
"fmt"
"os"
"syscall"
)
// configure new process group for child process
func (e *UniversalExecutor) setNewProcessGroup() error {
// We need to check that as build flags includes windows for this file
if e.cmd.SysProcAttr == nil {
e.cmd.SysProcAttr = &syscall.SysProcAttr{}
}
e.cmd.SysProcAttr.CreationFlags = syscall.CREATE_NEW_PROCESS_GROUP
return nil
}
// Cleanup any still hanging user processes
func (e *UniversalExecutor) cleanupChildProcesses(proc *os.Process) error {
// We must first verify if the process is still running.
// (Windows process often lingered around after being reported as killed).
handle, err := syscall.OpenProcess(syscall.PROCESS_TERMINATE|syscall.SYNCHRONIZE|syscall.PROCESS_QUERY_INFORMATION, false, uint32(proc.Pid))
if err != nil {
return os.NewSyscallError("OpenProcess", err)
}
defer syscall.CloseHandle(handle)
result, err := syscall.WaitForSingleObject(syscall.Handle(handle), 0)
switch result {
case syscall.WAIT_OBJECT_0:
return nil
case syscall.WAIT_TIMEOUT:
// Process still running. Just kill it.
return proc.Kill()
default:
return os.NewSyscallError("WaitForSingleObject", err)
}
}
// Send a Ctrl-Break signal for shutting down the process,
// like in https://golang.org/src/os/signal/signal_windows_test.go
func sendCtrlBreak(pid int) error {
dll, err := syscall.LoadDLL("kernel32.dll")
if err != nil {
return fmt.Errorf("Error loading kernel32.dll: %v", err)
}
proc, err := dll.FindProc("GenerateConsoleCtrlEvent")
if err != nil {
return fmt.Errorf("Cannot find procedure GenerateConsoleCtrlEvent: %v", err)
}
result, _, err := proc.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
if result == 0 {
return fmt.Errorf("Error sending ctrl-break event: %v", err)
}
return nil
}
// Send the process a Ctrl-Break event, allowing it to shutdown by itself
// before being Terminate.
func (e *UniversalExecutor) shutdownProcess(_ os.Signal, proc *os.Process) error {
if err := sendCtrlBreak(proc.Pid); err != nil {
return fmt.Errorf("executor shutdown error: %v", err)
}
e.logger.Info("sent Ctrl-Break to process", "pid", proc.Pid)
return nil
}