[#3896cn] Add support for suspending a server and blocking boot when suspended
This commit is contained in:
parent
fa42ed92fb
commit
0ce95aa2e3
11
http.go
11
http.go
|
@ -152,6 +152,17 @@ func (rt *Router) routeServerPower(w http.ResponseWriter, r *http.Request, ps ht
|
|||
return
|
||||
}
|
||||
|
||||
// Because we route all of the actual bootup process to a seperate thread we need to
|
||||
// check the suspension status here, otherwise the user will hit the endpoint and then
|
||||
// just sit there wondering why it returns a success but nothing actually happens.
|
||||
//
|
||||
// We don't really care about any of the other actions at this point, they'll all result
|
||||
// in the process being stopped, which should have happened anyways if the server is suspended.
|
||||
if action.Action == "start" && s.Suspended {
|
||||
http.Error(w, "server is suspended", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Pass the actual heavy processing off to a seperate thread to handle so that
|
||||
// we can immediately return a response from the server.
|
||||
go func(a string, s *server.Server) {
|
||||
|
|
|
@ -215,6 +215,16 @@ func (d *DockerEnvironment) Start() error {
|
|||
}
|
||||
}()
|
||||
|
||||
// If the server is suspended the user shouldn't be able to boot it, in those cases
|
||||
// return a suspension error and let the calling area handle the issue.
|
||||
//
|
||||
// Theoretically you'd have the Panel handle all of this logic, but we cannot do that
|
||||
// because we allow the websocket to control the server power state as well, so we'll
|
||||
// need to handle that action in here.
|
||||
if d.Server.Suspended {
|
||||
return &suspendedError{}
|
||||
}
|
||||
|
||||
c, err := d.Client.ContainerInspect(context.Background(), d.Server.Uuid)
|
||||
if err != nil && !client.IsErrNotFound(err) {
|
||||
return errors.WithStack(err)
|
||||
|
|
14
server/errors.go
Normal file
14
server/errors.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package server
|
||||
|
||||
type suspendedError struct {
|
||||
}
|
||||
|
||||
func (e *suspendedError) Error() string {
|
||||
return "server is currently in a suspended state"
|
||||
}
|
||||
|
||||
func IsSuspendedError(err error) bool {
|
||||
_, ok := err.(*suspendedError)
|
||||
|
||||
return ok
|
||||
}
|
|
@ -5,6 +5,8 @@ import (
|
|||
"github.com/buger/jsonparser"
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/pkg/errors"
|
||||
"go.uber.org/zap"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Merges data passed through in JSON form into the existing server object.
|
||||
|
@ -59,5 +61,41 @@ func (s *Server) UpdateDataStructure(data []byte) error {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return s.Environment.InSituUpdate()
|
||||
s.runBackgroundActions()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Runs through different actions once a server's configuration has been persisted
|
||||
// to the disk. This function does not return anything as any failures should be logged
|
||||
// but have no effect on actually updating the server itself.
|
||||
//
|
||||
// These tasks run in independent threads where relevant to speed up any updates
|
||||
// that need to happen.
|
||||
func (s *Server) runBackgroundActions() {
|
||||
// Update the environment in place, allowing memory and CPU usage to be adjusted
|
||||
// on the fly without the user needing to reboot (theoretically).
|
||||
go func(server *Server) {
|
||||
if err := server.Environment.InSituUpdate(); err != nil {
|
||||
zap.S().Warnw(
|
||||
"failed to perform in-situ update of server environment",
|
||||
zap.String("server", server.Uuid),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}(s)
|
||||
|
||||
// Check if the server is now suspended, and if so and the process is not terminated
|
||||
// yet, do it immediately.
|
||||
go func(server *Server) {
|
||||
if server.Suspended && server.State != ProcessOfflineState {
|
||||
if err := server.Environment.Terminate(os.Kill); err != nil {
|
||||
zap.S().Warnw(
|
||||
"failed to terminate server environment after seeing suspension",
|
||||
zap.String("server", server.Uuid),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
}
|
||||
}(s)
|
||||
}
|
||||
|
|
|
@ -276,8 +276,10 @@ func (wsh *WebsocketHandler) SendErrorJson(err error) error {
|
|||
defer wsh.Mutex.Unlock()
|
||||
|
||||
message := "an unexpected error was encountered while handling this request"
|
||||
if wsh.JWT != nil && wsh.JWT.HasPermission(PermissionReceiveErrors) {
|
||||
message = err.Error()
|
||||
if wsh.JWT != nil {
|
||||
if server.IsSuspendedError(err) || wsh.JWT.HasPermission(PermissionReceiveErrors) {
|
||||
message = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
m, u := wsh.GetErrorMessage(message)
|
||||
|
|
Loading…
Reference in New Issue
Block a user