Stop servers when exceeding their disk limits; closes pterodactyl/panel#2638

This commit is contained in:
Dane Everitt 2020-11-01 17:20:42 -08:00
parent 384b9a3c28
commit fe572beada
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53

View File

@ -10,6 +10,7 @@ import (
"github.com/pterodactyl/wings/events" "github.com/pterodactyl/wings/events"
"regexp" "regexp"
"strconv" "strconv"
"sync"
) )
var dockerEvents = []string{ var dockerEvents = []string{
@ -18,6 +19,37 @@ var dockerEvents = []string{
environment.DockerImagePullCompleted, environment.DockerImagePullCompleted,
} }
type diskSpaceLimiter struct {
o sync.Once
mu sync.Mutex
server *Server
}
func newDiskLimiter(s *Server) *diskSpaceLimiter {
return &diskSpaceLimiter{server: s}
}
// Reset the disk space limiter status.
func (dsl *diskSpaceLimiter) Reset() {
dsl.mu.Lock()
dsl.o = sync.Once{}
dsl.mu.Unlock()
}
// Trigger the disk space limiter which will attempt to stop a running server instance within
// 15 seconds, and terminate it forcefully if it does not stop.
//
// This function is only executed one time, so whenever a server is marked as booting the limiter
// should be reset so it can properly be triggered as needed.
func (dsl *diskSpaceLimiter) Trigger() {
dsl.o.Do(func() {
dsl.server.PublishConsoleOutputFromDaemon("Server is exceeding the assigned disk space limit, stopping process now.")
if err := dsl.server.Environment.WaitForStop(15, true); err != nil {
dsl.server.Log().WithField("error", err).Error("failed to stop server after exceeding space limit!")
}
})
}
// Adds all of the internal event listeners we want to use for a server. These listeners can only be // Adds all of the internal event listeners we want to use for a server. These listeners can only be
// removed by deleting the server as they should last for the duration of the process' lifetime. // removed by deleting the server as they should last for the duration of the process' lifetime.
func (s *Server) StartEventListeners() { func (s *Server) StartEventListeners() {
@ -60,9 +92,11 @@ func (s *Server) StartEventListeners() {
s.onConsoleOutput(e.Data) s.onConsoleOutput(e.Data)
} }
l := newDiskLimiter(s)
state := func(e events.Event) { state := func(e events.Event) {
// Reset the throttler when the process is started. // Reset the throttler when the process is started.
if e.Data == environment.ProcessStartingState { if e.Data == environment.ProcessStartingState {
l.Reset()
s.Throttler().Reset() s.Throttler().Reset()
} }
@ -81,7 +115,11 @@ func (s *Server) StartEventListeners() {
s.resources.Stats = *st s.resources.Stats = *st
s.resources.mu.Unlock() s.resources.mu.Unlock()
s.Filesystem().HasSpaceAvailable(true) // If there is no disk space available at this point, trigger the server disk limiter logic
// which will start to stop the running instance.
if !s.Filesystem().HasSpaceAvailable(true) {
l.Trigger()
}
s.emitProcUsage() s.emitProcUsage()
} }