Support some additional signal types for stopping a server; ref pterodactyl/panel#3042
This commit is contained in:
parent
df721f45f8
commit
225f8aa904
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/pterodactyl/wings/environment"
|
"github.com/pterodactyl/wings/environment"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -115,23 +116,40 @@ func (e *Environment) Start() error {
|
||||||
return e.Attach()
|
return e.Attach()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stops the container that the server is running in. This will allow up to 30 seconds to pass
|
// Stop stops the container that the server is running in. This will allow up to
|
||||||
// before the container is forcefully terminated if we are trying to stop it without using a command
|
// 30 seconds to pass before the container is forcefully terminated if we are
|
||||||
// sent into the instance.
|
// trying to stop it without using a command sent into the instance.
|
||||||
//
|
//
|
||||||
// You most likely want to be using WaitForStop() rather than this function, since this will return
|
// You most likely want to be using WaitForStop() rather than this function,
|
||||||
// as soon as the command is sent, rather than waiting for the process to be completed stopped.
|
// since this will return as soon as the command is sent, rather than waiting
|
||||||
|
// for the process to be completed stopped.
|
||||||
|
//
|
||||||
|
// TODO: pass context through from the server instance.
|
||||||
func (e *Environment) Stop() error {
|
func (e *Environment) Stop() error {
|
||||||
e.mu.RLock()
|
e.mu.RLock()
|
||||||
s := e.meta.Stop
|
s := e.meta.Stop
|
||||||
e.mu.RUnlock()
|
e.mu.RUnlock()
|
||||||
|
|
||||||
|
// A native "stop" as the Type field value will just skip over all of this
|
||||||
|
// logic and end up only executing the container stop command (which may or
|
||||||
|
// may not work as expected).
|
||||||
if s.Type == "" || s.Type == api.ProcessStopSignal {
|
if s.Type == "" || s.Type == api.ProcessStopSignal {
|
||||||
if s.Type == "" {
|
if s.Type == "" {
|
||||||
log.WithField("container_id", e.Id).Warn("no stop configuration detected for environment, using termination procedure")
|
log.WithField("container_id", e.Id).Warn("no stop configuration detected for environment, using termination procedure")
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.Terminate(os.Kill)
|
signal := os.Kill
|
||||||
|
// Handle a few common cases, otherwise just fall through and just pass along
|
||||||
|
// the os.Kill signal to the process.
|
||||||
|
switch strings.ToUpper(s.Value) {
|
||||||
|
case "SIGABRT":
|
||||||
|
signal = syscall.SIGABRT
|
||||||
|
case "SIGINT":
|
||||||
|
signal = syscall.SIGINT
|
||||||
|
case "SIGTERM":
|
||||||
|
signal = syscall.SIGTERM
|
||||||
|
}
|
||||||
|
return e.Terminate(signal)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the process is already offline don't switch it back to stopping. Just leave it how
|
// If the process is already offline don't switch it back to stopping. Just leave it how
|
||||||
|
@ -147,26 +165,24 @@ func (e *Environment) Stop() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
t := time.Second * 30
|
t := time.Second * 30
|
||||||
|
|
||||||
if err := e.client.ContainerStop(context.Background(), e.Id, &t); err != nil {
|
if err := e.client.ContainerStop(context.Background(), e.Id, &t); err != nil {
|
||||||
// If the container does not exist just mark the process as stopped and return without
|
// If the container does not exist just mark the process as stopped and return without
|
||||||
// an error.
|
// an error.
|
||||||
if client.IsErrNotFound(err) {
|
if client.IsErrNotFound(err) {
|
||||||
e.SetStream(nil)
|
e.SetStream(nil)
|
||||||
e.SetState(environment.ProcessOfflineState)
|
e.SetState(environment.ProcessOfflineState)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to gracefully stop a server using the defined stop command. If the server
|
// WaitForStop attempts to gracefully stop a server using the defined stop
|
||||||
// does not stop after seconds have passed, an error will be returned, or the instance
|
// command. If the server does not stop after seconds have passed, an error will
|
||||||
// will be terminated forcefully depending on the value of the second argument.
|
// be returned, or the instance will be terminated forcefully depending on the
|
||||||
|
// value of the second argument.
|
||||||
func (e *Environment) WaitForStop(seconds uint, terminate bool) error {
|
func (e *Environment) WaitForStop(seconds uint, terminate bool) error {
|
||||||
if err := e.Stop(); err != nil {
|
if err := e.Stop(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -211,7 +227,7 @@ func (e *Environment) WaitForStop(seconds uint, terminate bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forcefully terminates the container using the signal passed through.
|
// Terminate forcefully terminates the container using the signal provided.
|
||||||
func (e *Environment) Terminate(signal os.Signal) error {
|
func (e *Environment) Terminate(signal os.Signal) error {
|
||||||
c, err := e.client.ContainerInspect(context.Background(), e.Id)
|
c, err := e.client.ContainerInspect(context.Background(), e.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user