server(install): update installation status request
The new request includes a `reinstall` option to denote whether the installation failed for the first time, or during a reinstall. ref https://github.com/pterodactyl/panel/issues/1994
This commit is contained in:
parent
51cb6dfa42
commit
da94f750ad
|
@ -29,7 +29,7 @@ type Client interface {
|
||||||
SetArchiveStatus(ctx context.Context, uuid string, successful bool) error
|
SetArchiveStatus(ctx context.Context, uuid string, successful bool) error
|
||||||
SetBackupStatus(ctx context.Context, backup string, data BackupRequest) error
|
SetBackupStatus(ctx context.Context, backup string, data BackupRequest) error
|
||||||
SendRestorationStatus(ctx context.Context, backup string, successful bool) error
|
SendRestorationStatus(ctx context.Context, backup string, successful bool) error
|
||||||
SetInstallationStatus(ctx context.Context, uuid string, successful bool) error
|
SetInstallationStatus(ctx context.Context, uuid string, data InstallStatusRequest) error
|
||||||
SetTransferStatus(ctx context.Context, uuid string, successful bool) error
|
SetTransferStatus(ctx context.Context, uuid string, successful bool) error
|
||||||
ValidateSftpCredentials(ctx context.Context, request SftpAuthRequest) (SftpAuthResponse, error)
|
ValidateSftpCredentials(ctx context.Context, request SftpAuthRequest) (SftpAuthResponse, error)
|
||||||
SendActivityLogs(ctx context.Context, activity []models.Activity) error
|
SendActivityLogs(ctx context.Context, activity []models.Activity) error
|
||||||
|
|
|
@ -19,7 +19,7 @@ const (
|
||||||
ProcessStopNativeStop = "stop"
|
ProcessStopNativeStop = "stop"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetServers returns all of the servers that are present on the Panel making
|
// GetServers returns all the servers that are present on the Panel making
|
||||||
// parallel API calls to the endpoint if more than one page of servers is
|
// parallel API calls to the endpoint if more than one page of servers is
|
||||||
// returned.
|
// returned.
|
||||||
func (c *client) GetServers(ctx context.Context, limit int) ([]RawServerData, error) {
|
func (c *client) GetServers(ctx context.Context, limit int) ([]RawServerData, error) {
|
||||||
|
@ -58,7 +58,7 @@ func (c *client) GetServers(ctx context.Context, limit int) ([]RawServerData, er
|
||||||
//
|
//
|
||||||
// This handles Wings exiting during either of these processes which will leave
|
// This handles Wings exiting during either of these processes which will leave
|
||||||
// things in a bad state within the Panel. This API call is executed once Wings
|
// things in a bad state within the Panel. This API call is executed once Wings
|
||||||
// has fully booted all of the servers.
|
// has fully booted all the servers.
|
||||||
func (c *client) ResetServersState(ctx context.Context) error {
|
func (c *client) ResetServersState(ctx context.Context) error {
|
||||||
res, err := c.Post(ctx, "/servers/reset", nil)
|
res, err := c.Post(ctx, "/servers/reset", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,8 +92,8 @@ func (c *client) GetInstallationScript(ctx context.Context, uuid string) (Instal
|
||||||
return config, err
|
return config, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) SetInstallationStatus(ctx context.Context, uuid string, successful bool) error {
|
func (c *client) SetInstallationStatus(ctx context.Context, uuid string, data InstallStatusRequest) error {
|
||||||
resp, err := c.Post(ctx, fmt.Sprintf("/servers/%s/install", uuid), d{"successful": successful})
|
resp, err := c.Post(ctx, fmt.Sprintf("/servers/%s/install", uuid), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ func (c *client) SetTransferStatus(ctx context.Context, uuid string, successful
|
||||||
// password combination provided is associated with a valid server on the instance
|
// password combination provided is associated with a valid server on the instance
|
||||||
// using the Panel's authentication control mechanisms. This will get itself
|
// using the Panel's authentication control mechanisms. This will get itself
|
||||||
// throttled if too many requests are made, allowing us to completely offload
|
// throttled if too many requests are made, allowing us to completely offload
|
||||||
// all of the authorization security logic to the Panel.
|
// all the authorization security logic to the Panel.
|
||||||
func (c *client) ValidateSftpCredentials(ctx context.Context, request SftpAuthRequest) (SftpAuthResponse, error) {
|
func (c *client) ValidateSftpCredentials(ctx context.Context, request SftpAuthRequest) (SftpAuthResponse, error) {
|
||||||
var auth SftpAuthResponse
|
var auth SftpAuthResponse
|
||||||
res, err := c.Post(ctx, "/sftp/auth", request)
|
res, err := c.Post(ctx, "/sftp/auth", request)
|
||||||
|
|
|
@ -92,8 +92,8 @@ type SftpAuthResponse struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutputLineMatcher struct {
|
type OutputLineMatcher struct {
|
||||||
// The raw string to match against. This may or may not be prefixed with
|
// raw string to match against. This may or may not be prefixed with
|
||||||
// regex: which indicates we want to match against the regex expression.
|
// `regex:` which indicates we want to match against the regex expression.
|
||||||
raw []byte
|
raw []byte
|
||||||
reg *regexp.Regexp
|
reg *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
@ -139,9 +139,9 @@ type ProcessStopConfiguration struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessConfiguration defines the process configuration for a given server
|
// ProcessConfiguration defines the process configuration for a given server
|
||||||
// instance. This sets what Wings is looking for to mark a server as done starting
|
// instance. This sets what Wings is looking for to mark a server as done
|
||||||
// what to do when stopping, and what changes to make to the configuration file
|
// starting what to do when stopping, and what changes to make to the
|
||||||
// for a server.
|
// configuration file for a server.
|
||||||
type ProcessConfiguration struct {
|
type ProcessConfiguration struct {
|
||||||
Startup struct {
|
Startup struct {
|
||||||
Done []*OutputLineMatcher `json:"done"`
|
Done []*OutputLineMatcher `json:"done"`
|
||||||
|
@ -169,3 +169,8 @@ type BackupRequest struct {
|
||||||
Successful bool `json:"successful"`
|
Successful bool `json:"successful"`
|
||||||
Parts []BackupPart `json:"parts"`
|
Parts []BackupPart `json:"parts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InstallStatusRequest struct {
|
||||||
|
Successful bool `json:"successful"`
|
||||||
|
Reinstall bool `json:"reinstall"`
|
||||||
|
}
|
||||||
|
|
|
@ -153,9 +153,15 @@ func postServerSync(c *gin.Context) {
|
||||||
func postServerInstall(c *gin.Context) {
|
func postServerInstall(c *gin.Context) {
|
||||||
s := ExtractServer(c)
|
s := ExtractServer(c)
|
||||||
|
|
||||||
go func(serv *server.Server) {
|
go func(s *server.Server) {
|
||||||
if err := serv.Install(true); err != nil {
|
s.Log().Info("syncing server state with remote source before executing installation process")
|
||||||
serv.Log().WithField("error", err).Error("failed to execute server installation process")
|
if err := s.Sync(); err != nil {
|
||||||
|
s.Log().WithField("error", err).Error("failed to sync server state with Panel")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.Install(); err != nil {
|
||||||
|
s.Log().WithField("error", err).Error("failed to execute server installation process")
|
||||||
}
|
}
|
||||||
}(s)
|
}(s)
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ func postCreateServer(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := i.Server().Install(false); err != nil {
|
if err := i.Server().Install(); err != nil {
|
||||||
log.WithFields(log.Fields{"server": i.Server().ID(), "error": err}).Error("failed to run install process for server")
|
log.WithFields(log.Fields{"server": i.Server().ID(), "error": err}).Error("failed to run install process for server")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,19 +32,17 @@ import (
|
||||||
//
|
//
|
||||||
// Pass true as the first argument in order to execute a server sync before the
|
// Pass true as the first argument in order to execute a server sync before the
|
||||||
// process to ensure the latest information is used.
|
// process to ensure the latest information is used.
|
||||||
func (s *Server) Install(sync bool) error {
|
func (s *Server) Install() error {
|
||||||
if sync {
|
return s.install(false)
|
||||||
s.Log().Info("syncing server state with remote source before executing installation process")
|
|
||||||
if err := s.Sync(); err != nil {
|
|
||||||
return errors.WrapIf(err, "install: failed to sync server state with Panel")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) install(reinstall bool) error {
|
||||||
var err error
|
var err error
|
||||||
if !s.Config().SkipEggScripts {
|
if !s.Config().SkipEggScripts {
|
||||||
// Send the start event so the Panel can automatically update. We don't send this unless the process
|
// Send the start event so the Panel can automatically update. We don't
|
||||||
// is actually going to run, otherwise all sorts of weird rapid UI behavior happens since there isn't
|
// send this unless the process is actually going to run, otherwise all
|
||||||
// an actual install process being executed.
|
// sorts of weird rapid UI behavior happens since there isn't an actual
|
||||||
|
// install process being executed.
|
||||||
s.Events().Publish(InstallStartedEvent, "")
|
s.Events().Publish(InstallStartedEvent, "")
|
||||||
|
|
||||||
err = s.internalInstall()
|
err = s.internalInstall()
|
||||||
|
@ -53,12 +51,13 @@ func (s *Server) Install(sync bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Log().WithField("was_successful", err == nil).Debug("notifying panel of server install state")
|
s.Log().WithField("was_successful", err == nil).Debug("notifying panel of server install state")
|
||||||
if serr := s.SyncInstallState(err == nil); serr != nil {
|
if serr := s.SyncInstallState(err == nil, reinstall); serr != nil {
|
||||||
l := s.Log().WithField("was_successful", err == nil)
|
l := s.Log().WithField("was_successful", err == nil)
|
||||||
|
|
||||||
// If the request was successful but there was an error with this request, attach the
|
// If the request was successful but there was an error with this request,
|
||||||
// error to this log entry. Otherwise ignore it in this log since whatever is calling
|
// attach the error to this log entry. Otherwise, ignore it in this log
|
||||||
// this function should handle the error and will end up logging the same one.
|
// since whatever is calling this function should handle the error and
|
||||||
|
// will end up logging the same one.
|
||||||
if err == nil {
|
if err == nil {
|
||||||
l.WithField("error", err)
|
l.WithField("error", err)
|
||||||
}
|
}
|
||||||
|
@ -66,19 +65,20 @@ func (s *Server) Install(sync bool) error {
|
||||||
l.Warn("failed to notify panel of server install state")
|
l.Warn("failed to notify panel of server install state")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the server is marked as offline at this point, otherwise you end up
|
// Ensure that the server is marked as offline at this point, otherwise you
|
||||||
// with a blank value which is a bit confusing.
|
// end up with a blank value which is a bit confusing.
|
||||||
s.Environment.SetState(environment.ProcessOfflineState)
|
s.Environment.SetState(environment.ProcessOfflineState)
|
||||||
|
|
||||||
// Push an event to the websocket so we can auto-refresh the information in the panel once
|
// Push an event to the websocket, so we can auto-refresh the information in
|
||||||
// the install is completed.
|
// the panel once the installation is completed.
|
||||||
s.Events().Publish(InstallCompletedEvent, "")
|
s.Events().Publish(InstallCompletedEvent, "")
|
||||||
|
|
||||||
return errors.WithStackIf(err)
|
return errors.WithStackIf(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinstalls a server's software by utilizing the install script for the server egg. This
|
// Reinstall reinstalls a server's software by utilizing the installation script
|
||||||
// does not touch any existing files for the server, other than what the script modifies.
|
// for the server egg. This does not touch any existing files for the server,
|
||||||
|
// other than what the script modifies.
|
||||||
func (s *Server) Reinstall() error {
|
func (s *Server) Reinstall() error {
|
||||||
if s.Environment.State() != environment.ProcessOfflineState {
|
if s.Environment.State() != environment.ProcessOfflineState {
|
||||||
s.Log().Debug("waiting for server instance to enter a stopped state")
|
s.Log().Debug("waiting for server instance to enter a stopped state")
|
||||||
|
@ -87,7 +87,12 @@ func (s *Server) Reinstall() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.Install(true)
|
s.Log().Info("syncing server state with remote source before executing re-installation process")
|
||||||
|
if err := s.Sync(); err != nil {
|
||||||
|
return errors.WrapIf(err, "install: failed to sync server state with Panel")
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.install(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal installation function used to simplify reporting back to the Panel.
|
// Internal installation function used to simplify reporting back to the Panel.
|
||||||
|
@ -116,8 +121,9 @@ type InstallationProcess struct {
|
||||||
client *client.Client
|
client *client.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a new installation process struct that will be used to create containers,
|
// NewInstallationProcess returns a new installation process struct that will be
|
||||||
// and otherwise perform installation commands for a server.
|
// used to create containers and otherwise perform installation commands for a
|
||||||
|
// server.
|
||||||
func NewInstallationProcess(s *Server, script *remote.InstallationScript) (*InstallationProcess, error) {
|
func NewInstallationProcess(s *Server, script *remote.InstallationScript) (*InstallationProcess, error) {
|
||||||
proc := &InstallationProcess{
|
proc := &InstallationProcess{
|
||||||
Script: script,
|
Script: script,
|
||||||
|
@ -133,8 +139,8 @@ func NewInstallationProcess(s *Server, script *remote.InstallationScript) (*Inst
|
||||||
return proc, nil
|
return proc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if the server is actively running the installation process by checking the status
|
// IsInstalling returns if the server is actively running the installation
|
||||||
// of the installer lock.
|
// process by checking the status of the installer lock.
|
||||||
func (s *Server) IsInstalling() bool {
|
func (s *Server) IsInstalling() bool {
|
||||||
return s.installing.Load()
|
return s.installing.Load()
|
||||||
}
|
}
|
||||||
|
@ -155,7 +161,7 @@ func (s *Server) SetRestoring(state bool) {
|
||||||
s.restoring.Store(state)
|
s.restoring.Store(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes the installer container for the server.
|
// RemoveContainer removes the installation container for the server.
|
||||||
func (ip *InstallationProcess) RemoveContainer() error {
|
func (ip *InstallationProcess) RemoveContainer() error {
|
||||||
err := ip.client.ContainerRemove(ip.Server.Context(), ip.Server.ID()+"_installer", types.ContainerRemoveOptions{
|
err := ip.client.ContainerRemove(ip.Server.Context(), ip.Server.ID()+"_installer", types.ContainerRemoveOptions{
|
||||||
RemoveVolumes: true,
|
RemoveVolumes: true,
|
||||||
|
@ -328,14 +334,14 @@ func (ip *InstallationProcess) BeforeExecute() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the log path for the installation process.
|
// GetLogPath returns the log path for the installation process.
|
||||||
func (ip *InstallationProcess) GetLogPath() string {
|
func (ip *InstallationProcess) GetLogPath() string {
|
||||||
return filepath.Join(config.Get().System.LogDirectory, "/install", ip.Server.ID()+".log")
|
return filepath.Join(config.Get().System.LogDirectory, "/install", ip.Server.ID()+".log")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleans up after the execution of the installation process. This grabs the logs from the
|
// AfterExecute cleans up after the execution of the installation process.
|
||||||
// process to store in the server configuration directory, and then destroys the associated
|
// This grabs the logs from the process to store in the server configuration
|
||||||
// installation container.
|
// directory, and then destroys the associated installation container.
|
||||||
func (ip *InstallationProcess) AfterExecute(containerId string) error {
|
func (ip *InstallationProcess) AfterExecute(containerId string) error {
|
||||||
defer ip.RemoveContainer()
|
defer ip.RemoveContainer()
|
||||||
|
|
||||||
|
@ -525,7 +531,7 @@ func (ip *InstallationProcess) StreamOutput(ctx context.Context, id string) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resourceLimits returns the install container specific resource limits. This
|
// resourceLimits returns resource limits for the installation container. This
|
||||||
// looks at the globally defined install container limits and attempts to use
|
// looks at the globally defined install container limits and attempts to use
|
||||||
// the higher of the two (defined limits & server limits). This allows for servers
|
// the higher of the two (defined limits & server limits). This allows for servers
|
||||||
// with super low limits (e.g. Discord bots with 128Mb of memory) to perform more
|
// with super low limits (e.g. Discord bots with 128Mb of memory) to perform more
|
||||||
|
@ -537,8 +543,8 @@ func (ip *InstallationProcess) StreamOutput(ctx context.Context, id string) erro
|
||||||
func (ip *InstallationProcess) resourceLimits() container.Resources {
|
func (ip *InstallationProcess) resourceLimits() container.Resources {
|
||||||
limits := config.Get().Docker.InstallerLimits
|
limits := config.Get().Docker.InstallerLimits
|
||||||
|
|
||||||
// Create a copy of the configuration so we're not accidentally making changes
|
// Create a copy of the configuration, so we're not accidentally making
|
||||||
// to the underlying server build data.
|
// changes to the underlying server build data.
|
||||||
c := *ip.Server.Config()
|
c := *ip.Server.Config()
|
||||||
cfg := c.Build
|
cfg := c.Build
|
||||||
if cfg.MemoryLimit < limits.Memory {
|
if cfg.MemoryLimit < limits.Memory {
|
||||||
|
@ -562,10 +568,12 @@ func (ip *InstallationProcess) resourceLimits() container.Resources {
|
||||||
return resources
|
return resources
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncInstallState makes a HTTP request to the Panel instance notifying it that
|
// SyncInstallState makes an HTTP request to the Panel instance notifying it that
|
||||||
// the server has completed the installation process, and what the state of the
|
// the server has completed the installation process, and what the state of the
|
||||||
// server is. A boolean value of "true" means everything was successful, "false"
|
// server is.
|
||||||
// means something went wrong and the server must be deleted and re-created.
|
func (s *Server) SyncInstallState(successful, reinstall bool) error {
|
||||||
func (s *Server) SyncInstallState(successful bool) error {
|
return s.client.SetInstallationStatus(s.Context(), s.ID(), remote.InstallStatusRequest{
|
||||||
return s.client.SetInstallationStatus(s.Context(), s.ID(), successful)
|
Successful: successful,
|
||||||
|
Reinstall: reinstall,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user