Add initial support for fetching egg configuration from panel for servers

This commit is contained in:
Dane Everitt
2019-09-22 20:47:38 -07:00
parent 2a745c5da1
commit d7753d9c7f
7 changed files with 308 additions and 8 deletions

View File

@@ -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

View File

@@ -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")
}

View File

@@ -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)
}

View 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
}