Sync all server details when booting daemon or server process
This commit is contained in:
parent
834f0122e3
commit
fabaf21a0d
|
@ -3,6 +3,7 @@ package api
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"github.com/pterodactyl/wings/parser"
|
"github.com/pterodactyl/wings/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,10 +13,23 @@ const (
|
||||||
ProcessStopNativeStop = "stop"
|
ProcessStopNativeStop = "stop"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Holds the server configuration data returned from the Panel. When a server process
|
||||||
|
// is started, Wings communicates with the Panel to fetch the latest build information
|
||||||
|
// as well as get all of the details needed to parse the given Egg.
|
||||||
|
//
|
||||||
|
// This means we do not need to hit Wings each time part of the server is updated, and
|
||||||
|
// the Panel serves as the source of truth at all times. This also means if a configuration
|
||||||
|
// is accidentally wiped on Wings we can self-recover without too much hassle, so long
|
||||||
|
// as Wings is aware of what servers should exist on it.
|
||||||
|
type ServerConfigurationResponse struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
ProcessConfiguration *ProcessConfiguration `json:"process_configuration"`
|
||||||
|
}
|
||||||
|
|
||||||
// Defines the process configuration for a given server instance. This sets what the
|
// Defines the process configuration for a given server instance. This sets what the
|
||||||
// daemon is looking for to mark a server as done starting, what to do when stopping,
|
// daemon is looking for to mark a server as done starting, what to do when stopping,
|
||||||
// and what changes to make to the configuration file for a server.
|
// and what changes to make to the configuration file for a server.
|
||||||
type ServerConfiguration struct {
|
type ProcessConfiguration struct {
|
||||||
Startup struct {
|
Startup struct {
|
||||||
Done string `json:"done"`
|
Done string `json:"done"`
|
||||||
UserInteraction []string `json:"userInteraction"`
|
UserInteraction []string `json:"userInteraction"`
|
||||||
|
@ -28,10 +42,10 @@ type ServerConfiguration struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetches the server configuration and returns the struct for it.
|
// Fetches the server configuration and returns the struct for it.
|
||||||
func (r *PanelRequest) GetServerConfiguration(uuid string) (*ServerConfiguration, *RequestError, error) {
|
func (r *PanelRequest) GetServerConfiguration(uuid string) (*ServerConfigurationResponse, *RequestError, error) {
|
||||||
resp, err := r.Get(fmt.Sprintf("/servers/%s/configuration", uuid))
|
resp, err := r.Get(fmt.Sprintf("/servers/%s", uuid))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
@ -41,11 +55,11 @@ func (r *PanelRequest) GetServerConfiguration(uuid string) (*ServerConfiguration
|
||||||
return nil, r.Error(), nil
|
return nil, r.Error(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
res := &ServerConfiguration{}
|
res := &ServerConfigurationResponse{}
|
||||||
b, _ := r.ReadBody()
|
b, _ := r.ReadBody()
|
||||||
|
|
||||||
if err := json.Unmarshal(b, res); err != nil {
|
if err := json.Unmarshal(b, res); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil, nil
|
return res, nil, nil
|
||||||
|
|
2
http.go
2
http.go
|
@ -425,7 +425,7 @@ func (rt *Router) routeServerUpdate(w http.ResponseWriter, r *http.Request, ps h
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
data := rt.ReaderToBytes(r.Body)
|
data := rt.ReaderToBytes(r.Body)
|
||||||
if err := s.UpdateDataStructure(data); err != nil {
|
if err := s.UpdateDataStructure(data, true); err != nil {
|
||||||
zap.S().Errorw("failed to update a server's data structure", zap.String("server", s.Uuid), zap.Error(err))
|
zap.S().Errorw("failed to update a server's data structure", zap.String("server", s.Uuid), zap.Error(err))
|
||||||
|
|
||||||
http.Error(w, "failed to update data structure", http.StatusInternalServerError)
|
http.Error(w, "failed to update data structure", http.StatusInternalServerError)
|
||||||
|
|
|
@ -151,15 +151,11 @@ func (d *DockerEnvironment) InSituUpdate() error {
|
||||||
// state. This ensures that unexpected container deletion while Wings is running does
|
// state. This ensures that unexpected container deletion while Wings is running does
|
||||||
// not result in the server becoming unbootable.
|
// not result in the server becoming unbootable.
|
||||||
func (d *DockerEnvironment) OnBeforeStart() error {
|
func (d *DockerEnvironment) OnBeforeStart() error {
|
||||||
c, rerr, err := d.Server.GetProcessConfiguration()
|
zap.S().Infow("syncing server configuration with Panel", zap.String("server", d.Server.Uuid))
|
||||||
if err != nil {
|
if err := d.Server.Sync(); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if rerr != nil {
|
|
||||||
return errors.New(rerr.String())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d.Server.processConfiguration = c
|
|
||||||
|
|
||||||
// If the server requires a rebuild, go ahead and delete the container from the system which
|
// If the server requires a rebuild, go ahead and delete the container from the system which
|
||||||
// will allow the subsequent Create() call to create a new container instance for the server
|
// will allow the subsequent Create() call to create a new container instance for the server
|
||||||
// to run in.
|
// to run in.
|
||||||
|
|
|
@ -72,7 +72,7 @@ type Server struct {
|
||||||
// Defines the process configuration for the server instance. This is dynamically
|
// Defines the process configuration for the server instance. This is dynamically
|
||||||
// fetched from the Pterodactyl Server instance each time the server process is
|
// fetched from the Pterodactyl Server instance each time the server process is
|
||||||
// started, and then cached here.
|
// started, and then cached here.
|
||||||
processConfiguration *api.ServerConfiguration
|
processConfiguration *api.ProcessConfiguration
|
||||||
|
|
||||||
// Internal mutex used to block actions that need to occur sequentially, such as
|
// Internal mutex used to block actions that need to occur sequentially, such as
|
||||||
// writing the configuration to the disk.
|
// writing the configuration to the disk.
|
||||||
|
@ -250,23 +250,45 @@ func FromConfiguration(data []byte, cfg *config.SystemConfiguration) (*Server, e
|
||||||
// This is also done when the server is booted, however we need to account for instances
|
// This is also done when the server is booted, however we need to account for instances
|
||||||
// where the server is already running and the Daemon reboots. In those cases this will
|
// where the server is already running and the Daemon reboots. In those cases this will
|
||||||
// allow us to you know, stop servers.
|
// allow us to you know, stop servers.
|
||||||
if cfg, rerr, err := s.GetProcessConfiguration(); err != nil {
|
if cfg.SyncServersOnBoot {
|
||||||
|
if err := s.Sync(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if rerr != nil {
|
|
||||||
// If the response error is because a server does not exist on the Panel return
|
|
||||||
// that so that we can handle that in the future.
|
|
||||||
if rerr.Status == "404" {
|
|
||||||
return nil, &serverDoesNotExist{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(rerr.String())
|
|
||||||
} else {
|
|
||||||
s.processConfiguration = cfg
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Syncs the state of the server on the Panel with Wings. This ensures that we're always
|
||||||
|
// using the state of the server from the Panel and allows us to not require successful
|
||||||
|
// API calls to Wings to do things.
|
||||||
|
//
|
||||||
|
// This also means mass actions can be performed against servers on the Panel and they
|
||||||
|
// will automatically sync with Wings when the server is started.
|
||||||
|
func (s *Server) Sync() error {
|
||||||
|
cfg, rerr, err := s.GetProcessConfiguration()
|
||||||
|
if err != nil || rerr != nil {
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rerr.Status == "404" {
|
||||||
|
return &serverDoesNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New(rerr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the data structure and persist it to the disk.
|
||||||
|
if err:= s.UpdateDataStructure(cfg.Settings, false); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.processConfiguration = cfg.ProcessConfiguration
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Reads the log file for a server up to a specified number of bytes.
|
// Reads the log file for a server up to a specified number of bytes.
|
||||||
func (s *Server) ReadLogfile(len int64) ([]string, error) {
|
func (s *Server) ReadLogfile(len int64) ([]string, error) {
|
||||||
return s.Environment.Readlog(len)
|
return s.Environment.Readlog(len)
|
||||||
|
@ -348,6 +370,6 @@ func (s *Server) SetState(state string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the process configuration data for the server.
|
// Gets the process configuration data for the server.
|
||||||
func (s *Server) GetProcessConfiguration() (*api.ServerConfiguration, *api.RequestError, error) {
|
func (s *Server) GetProcessConfiguration() (*api.ServerConfigurationResponse, *api.RequestError, error) {
|
||||||
return api.NewRequester().GetServerConfiguration(s.Uuid)
|
return api.NewRequester().GetServerConfiguration(s.Uuid)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@ import (
|
||||||
// The server will be marked as requiring a rebuild on the next boot sequence,
|
// The server will be marked as requiring a rebuild on the next boot sequence,
|
||||||
// it is up to the specific environment to determine what needs to happen when
|
// it is up to the specific environment to determine what needs to happen when
|
||||||
// that is the case.
|
// that is the case.
|
||||||
func (s *Server) UpdateDataStructure(data []byte) error {
|
func (s *Server) UpdateDataStructure(data []byte, background bool) error {
|
||||||
src := Server{}
|
src := new(Server)
|
||||||
if err := json.Unmarshal(data, &src); err != nil {
|
if err := json.Unmarshal(data, src); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,8 +31,8 @@ func (s *Server) UpdateDataStructure(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the default values in the interface that we unmarshaled into.
|
// Set the default values in the interface that we unmarshaled into.
|
||||||
if err := defaults.Set(&src); err != nil {
|
if err := defaults.Set(src); err != nil {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge the new data object that we have received with the existing server data object
|
// Merge the new data object that we have received with the existing server data object
|
||||||
|
@ -76,7 +76,9 @@ func (s *Server) UpdateDataStructure(data []byte) error {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if background {
|
||||||
s.runBackgroundActions()
|
s.runBackgroundActions()
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user