Support some additional signal types for stopping a server; ref pterodactyl/panel#3042

This commit is contained in:
Dane Everitt 2021-01-28 21:26:02 -08:00
parent df721f45f8
commit 225f8aa904
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53

View File

@ -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 {