Add initial support for fetching egg configuration from panel for servers
This commit is contained in:
@@ -14,6 +14,10 @@ type Environment interface {
|
||||
// for this specific server instance.
|
||||
IsRunning() (bool, error)
|
||||
|
||||
// Runs before the environment is started. If an error is returned starting will
|
||||
// not occur, otherwise proceeds as normal.
|
||||
OnBeforeStart() error
|
||||
|
||||
// Starts a server instance. If the server instance is not in a state where it
|
||||
// can be started an error should be returned.
|
||||
Start() error
|
||||
|
||||
@@ -113,12 +113,35 @@ func (d *DockerEnvironment) IsRunning() (bool, error) {
|
||||
return c.State.Running, nil
|
||||
}
|
||||
|
||||
// Run before the container starts and get the process configuration from the Panel.
|
||||
// This is important since we use this to check configuration files as well as ensure
|
||||
// we always have the latest version of an egg available for server processes.
|
||||
func (d *DockerEnvironment) OnBeforeStart() error {
|
||||
c, err := d.Server.GetProcessConfiguration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Server.processConfiguration = c
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Checks if there is a container that already exists for the server. If so that
|
||||
// container is started. If there is no container, one is created and then started.
|
||||
func (d *DockerEnvironment) Start() error {
|
||||
sawError := false
|
||||
// If sawError is set to true there was an error somewhere in the pipeline that
|
||||
// got passed up, but we also want to ensure we set the server to be offline at
|
||||
// that point.
|
||||
defer func () {
|
||||
if sawError {
|
||||
d.Server.SetState(ProcessOfflineState)
|
||||
}
|
||||
}()
|
||||
|
||||
c, err := d.Client.ContainerInspect(context.Background(), d.Server.Uuid)
|
||||
if err != nil {
|
||||
// @todo what?
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -132,27 +155,36 @@ func (d *DockerEnvironment) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
d.Server.SetState(ProcessStartingState)
|
||||
// Set this to true for now, we will set it to false once we reach the
|
||||
// end of this chain.
|
||||
sawError = true
|
||||
|
||||
// Run the before start function and wait for it to finish.
|
||||
if err := d.OnBeforeStart(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Truncate the log file so we don't end up outputting a bunch of useless log information
|
||||
// to the websocket and whatnot.
|
||||
if err := os.Truncate(c.LogPath, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d.Server.SetState(ProcessStartingState)
|
||||
|
||||
// Reset the permissions on files for the server before actually trying
|
||||
// to start it.
|
||||
if err := d.Server.Filesystem.Chown("/"); err != nil {
|
||||
d.Server.SetState(ProcessOfflineState)
|
||||
return err
|
||||
}
|
||||
|
||||
opts := types.ContainerStartOptions{}
|
||||
if err := d.Client.ContainerStart(context.Background(), d.Server.Uuid, opts); err != nil {
|
||||
d.Server.SetState(ProcessOfflineState)
|
||||
return err
|
||||
}
|
||||
|
||||
// No errors, good to continue through.
|
||||
sawError = false
|
||||
|
||||
return d.Attach()
|
||||
}
|
||||
|
||||
@@ -246,6 +278,7 @@ func (d *DockerEnvironment) FollowConsoleOutput() error {
|
||||
ShowStderr: true,
|
||||
ShowStdout: true,
|
||||
Follow: true,
|
||||
Since: time.Now().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
reader, err := d.Client.ContainerLogs(ctx, d.Server.Uuid, opts)
|
||||
@@ -270,9 +303,7 @@ func (d *DockerEnvironment) FollowConsoleOutput() error {
|
||||
// information, instead just sit there with an async process that lets Docker stream all of this data
|
||||
// to us automatically.
|
||||
func (d *DockerEnvironment) EnableResourcePolling() error {
|
||||
fmt.Println("called")
|
||||
if d.Server.State == ProcessOfflineState {
|
||||
fmt.Println("not running")
|
||||
return errors.New("cannot enable resource polling on a server that is not running")
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/patrickmn/go-cache"
|
||||
"github.com/pterodactyl/wings/api"
|
||||
"github.com/pterodactyl/wings/config"
|
||||
"github.com/remeh/sizedwaitgroup"
|
||||
"go.uber.org/zap"
|
||||
@@ -56,6 +57,11 @@ type Server struct {
|
||||
|
||||
// All of the registered event listeners for this server instance.
|
||||
listeners EventListeners
|
||||
|
||||
// Defines the process configuration for the server instance. This is dynamically
|
||||
// fetched from the Pterodactyl Server instance each time the server process is
|
||||
// started, and then cached here.
|
||||
processConfiguration *api.ServerConfiguration
|
||||
}
|
||||
|
||||
// The build settings for a given server that impact docker container creation and
|
||||
@@ -183,6 +189,8 @@ func FromConfiguration(data []byte, cfg *config.SystemConfiguration) (*Server, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.AddEventListeners()
|
||||
|
||||
withConfiguration := func(e *DockerEnvironment) {
|
||||
e.User = cfg.User.Uid
|
||||
e.TimezonePath = cfg.TimezonePath
|
||||
@@ -207,6 +215,11 @@ func FromConfiguration(data []byte, cfg *config.SystemConfiguration) (*Server, e
|
||||
}
|
||||
s.Resources = &ResourceUsage{}
|
||||
|
||||
// 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
|
||||
// allow us to you know, stop servers.
|
||||
s.GetProcessConfiguration()
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -245,6 +258,8 @@ func (s *Server) SetState(state string) error {
|
||||
|
||||
s.State = state
|
||||
|
||||
zap.S().Debugw("saw server status change event", zap.String("server", s.Uuid), zap.String("status", state))
|
||||
|
||||
// Emit the event to any listeners that are currently registered.
|
||||
s.Emit(StatusEvent, s.State)
|
||||
|
||||
@@ -254,3 +269,8 @@ func (s *Server) SetState(state string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Gets the process configuration data for the server.
|
||||
func (s *Server) GetProcessConfiguration() (*api.ServerConfiguration, error) {
|
||||
return api.NewRequester().GetServerConfiguration(s.Uuid)
|
||||
}
|
||||
35
server/server_listeners.go
Normal file
35
server/server_listeners.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
||||
// Adds all of the internal event listeners we want to use for a server.
|
||||
func (s *Server) AddEventListeners() {
|
||||
s.AddListener(ConsoleOutputEvent, s.onConsoleOutput())
|
||||
}
|
||||
|
||||
var onConsoleOutputListener func(string)
|
||||
|
||||
// Custom listener for console output events that will check if the given line
|
||||
// of output matches one that should mark the server as started or not.
|
||||
func (s *Server) onConsoleOutput() *func(string) {
|
||||
if onConsoleOutputListener == nil {
|
||||
onConsoleOutputListener = func (data string) {
|
||||
// If the specific line of output is one that would mark the server as started,
|
||||
// set the server to that state. Only do this if the server is not currently stopped
|
||||
// or stopping.
|
||||
if s.State == ProcessStartingState && strings.Contains(data, s.processConfiguration.Startup.Done) {
|
||||
zap.S().Debugw(
|
||||
"detected server in running state based on line output", zap.String("match", s.processConfiguration.Startup.Done), zap.String("against", data),
|
||||
)
|
||||
|
||||
s.SetState(ProcessRunningState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &onConsoleOutputListener
|
||||
}
|
||||
Reference in New Issue
Block a user