commit
72fe5f4cd2
|
@ -27,7 +27,7 @@ const (
|
|||
)
|
||||
|
||||
// LockCommand is a Command implementation that is used to setup
|
||||
// a "lock" which manages lock acquasition and invokes a sub-process
|
||||
// a "lock" which manages lock acquisition and invokes a sub-process
|
||||
type LockCommand struct {
|
||||
ShutdownCh <-chan struct{}
|
||||
Ui cli.Ui
|
||||
|
@ -47,6 +47,8 @@ Usage: consul lock [options] prefix child...
|
|||
the child process will be sent a SIGTERM signal and given time to
|
||||
gracefully exit. After the grace period expires the process will
|
||||
be hard terminated.
|
||||
On Windows agents, the process is always hard terminated, even on
|
||||
the first attempt.
|
||||
|
||||
When -n=1, only a single lock holder or leader exists providing
|
||||
mutual exclusion. Setting a higher value switches to a semaphore
|
||||
|
@ -286,6 +288,8 @@ func (c *LockCommand) startChild(script string, doneCh chan struct{}) error {
|
|||
// killChild is used to forcefully kill the child, first using SIGTERM
|
||||
// to allow for a graceful cleanup and then using SIGKILL for a hard
|
||||
// termination.
|
||||
// On Windows, the child is always hard terminated with SIGKILL, even
|
||||
// on the first attempt.
|
||||
func (c *LockCommand) killChild(childDone chan struct{}) error {
|
||||
// Get the child process
|
||||
c.childLock.Lock()
|
||||
|
@ -300,11 +304,11 @@ func (c *LockCommand) killChild(childDone chan struct{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Attempt a SIGTERM first
|
||||
// Attempt termination first
|
||||
if c.verbose {
|
||||
c.Ui.Info(fmt.Sprintf("Sending SIGTERM to child pid %d", child.Pid))
|
||||
c.Ui.Info(fmt.Sprintf("Terminating child pid %d", child.Pid))
|
||||
}
|
||||
if err := syscall.Kill(child.Pid, syscall.SIGTERM); err != nil {
|
||||
if err := signalPid(child.Pid, syscall.SIGTERM); err != nil {
|
||||
return fmt.Errorf("Failed to terminate %d: %v", child.Pid, err)
|
||||
}
|
||||
|
||||
|
@ -312,7 +316,7 @@ func (c *LockCommand) killChild(childDone chan struct{}) error {
|
|||
select {
|
||||
case <-childDone:
|
||||
if c.verbose {
|
||||
c.Ui.Info("Child exited after SIGTERM")
|
||||
c.Ui.Info("Child terminated")
|
||||
}
|
||||
return nil
|
||||
case <-time.After(lockKillGracePeriod):
|
||||
|
@ -322,11 +326,11 @@ func (c *LockCommand) killChild(childDone chan struct{}) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Send a final SIGKILL first
|
||||
// Send a final SIGKILL
|
||||
if c.verbose {
|
||||
c.Ui.Info(fmt.Sprintf("Sending SIGKILL to child pid %d", child.Pid))
|
||||
c.Ui.Info(fmt.Sprintf("Killing child pid %d", child.Pid))
|
||||
}
|
||||
if err := syscall.Kill(child.Pid, syscall.SIGKILL); err != nil {
|
||||
if err := signalPid(child.Pid, syscall.SIGKILL); err != nil {
|
||||
return fmt.Errorf("Failed to kill %d: %v", child.Pid, err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// +build !windows
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// signalPid sends a sig signal to the process with process id pid.
|
||||
func signalPid(pid int, sig syscall.Signal) error {
|
||||
return syscall.Kill(pid, sig)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// +build windows
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// signalPid sends a sig signal to the process with process id pid.
|
||||
// Interrupts et al is not implemented on Windows. Always send a SIGKILL.
|
||||
func signalPid(pid int, sig syscall.Signal) error {
|
||||
p, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = sig
|
||||
return p.Signal(syscall.SIGKILL)
|
||||
}
|
Loading…
Reference in New Issue