commit
72fe5f4cd2
|
@ -27,7 +27,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// LockCommand is a Command implementation that is used to setup
|
// 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 {
|
type LockCommand struct {
|
||||||
ShutdownCh <-chan struct{}
|
ShutdownCh <-chan struct{}
|
||||||
Ui cli.Ui
|
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
|
the child process will be sent a SIGTERM signal and given time to
|
||||||
gracefully exit. After the grace period expires the process will
|
gracefully exit. After the grace period expires the process will
|
||||||
be hard terminated.
|
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
|
When -n=1, only a single lock holder or leader exists providing
|
||||||
mutual exclusion. Setting a higher value switches to a semaphore
|
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
|
// killChild is used to forcefully kill the child, first using SIGTERM
|
||||||
// to allow for a graceful cleanup and then using SIGKILL for a hard
|
// to allow for a graceful cleanup and then using SIGKILL for a hard
|
||||||
// termination.
|
// termination.
|
||||||
|
// On Windows, the child is always hard terminated with SIGKILL, even
|
||||||
|
// on the first attempt.
|
||||||
func (c *LockCommand) killChild(childDone chan struct{}) error {
|
func (c *LockCommand) killChild(childDone chan struct{}) error {
|
||||||
// Get the child process
|
// Get the child process
|
||||||
c.childLock.Lock()
|
c.childLock.Lock()
|
||||||
|
@ -300,11 +304,11 @@ func (c *LockCommand) killChild(childDone chan struct{}) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt a SIGTERM first
|
// Attempt termination first
|
||||||
if c.verbose {
|
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)
|
return fmt.Errorf("Failed to terminate %d: %v", child.Pid, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +316,7 @@ func (c *LockCommand) killChild(childDone chan struct{}) error {
|
||||||
select {
|
select {
|
||||||
case <-childDone:
|
case <-childDone:
|
||||||
if c.verbose {
|
if c.verbose {
|
||||||
c.Ui.Info("Child exited after SIGTERM")
|
c.Ui.Info("Child terminated")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case <-time.After(lockKillGracePeriod):
|
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 {
|
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 fmt.Errorf("Failed to kill %d: %v", child.Pid, err)
|
||||||
}
|
}
|
||||||
return nil
|
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