Update configuration struct to support defaults

This commit is contained in:
Dane Everitt 2019-12-22 13:20:34 -08:00
parent 0866b84d8e
commit 834f0122e3
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
3 changed files with 53 additions and 82 deletions

View File

@ -3,7 +3,6 @@ package config
import ( import (
"fmt" "fmt"
"github.com/creasty/defaults" "github.com/creasty/defaults"
"github.com/pkg/errors"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"io/ioutil" "io/ioutil"
@ -22,9 +21,9 @@ type Configuration struct {
// if the debug flag is passed through the command line arguments. // if the debug flag is passed through the command line arguments.
Debug bool Debug bool
Api *ApiConfiguration Api ApiConfiguration
System *SystemConfiguration System SystemConfiguration
Docker *DockerConfiguration Docker DockerConfiguration
// The amount of time in seconds that should elapse between disk usage checks // The amount of time in seconds that should elapse between disk usage checks
// run by the daemon. Setting a higher number can result in better IO performance // run by the daemon. Setting a higher number can result in better IO performance
@ -37,20 +36,20 @@ type Configuration struct {
Throttles struct { Throttles struct {
// The number of data overage warnings (inclusive) that can accumulate // The number of data overage warnings (inclusive) that can accumulate
// before a process is terminated. // before a process is terminated.
KillAtCount int `yaml:"kill_at_count"` KillAtCount int `default:"5" yaml:"kill_at_count"`
// The number of seconds that must elapse before the internal counter // The number of seconds that must elapse before the internal counter
// begins decrementing warnings assigned to a process that is outputting // begins decrementing warnings assigned to a process that is outputting
// too much data. // too much data.
DecaySeconds int `yaml:"decay"` DecaySeconds int `default:"10" yaml:"decay"`
// The total number of bytes allowed to be output by a server process // The total number of bytes allowed to be output by a server process
// per interval. // per interval.
BytesPerInterval int `yaml:"bytes"` BytesPerInterval int `default:"4096" yaml:"bytes"`
// The amount of time that should lapse between data output throttle // The amount of time that should lapse between data output throttle
// checks. This should be defined in milliseconds. // checks. This should be defined in milliseconds.
CheckInterval int `yaml:"check_interval"` CheckInterval int `defauly:"100" yaml:"check_interval"`
} }
// The location where the panel is running that this daemon should connect to // The location where the panel is running that this daemon should connect to
@ -65,10 +64,10 @@ type Configuration struct {
// Defines basic system configuration settings. // Defines basic system configuration settings.
type SystemConfiguration struct { type SystemConfiguration struct {
// Directory where the server data is stored at. // Directory where the server data is stored at.
Data string Data string `default:"/srv/daemon-data" yaml:"data"`
// The user that should own all of the server files, and be used for containers. // The user that should own all of the server files, and be used for containers.
Username string Username string `default:"pterodactyl" yaml:"username"`
// Definitions for the user that gets created to ensure that we can quickly access // Definitions for the user that gets created to ensure that we can quickly access
// this information without constantly having to do a system lookup. // this information without constantly having to do a system lookup.
@ -77,20 +76,33 @@ type SystemConfiguration struct {
Gid int Gid int
} }
// Determines wether or not server data should be synced when the Daemon is started.
// If set to false, data will only be synced when a server process is started, or
// detected as started when booting.
SyncServersOnBoot bool `default:"true" yaml:"sync_servers_on_boot"`
// The path to the system's timezone file that will be mounted into running Docker containers. // The path to the system's timezone file that will be mounted into running Docker containers.
TimezonePath string `yaml:"timezone_path"` TimezonePath string `yaml:"timezone_path"`
// Determines if permissions for a server should be set automatically on // Determines if permissions for a server should be set automatically on
// daemon boot. This can take a long time on systems with many servers, or on // daemon boot. This can take a long time on systems with many servers, or on
// systems with servers containing thousands of files. // systems with servers containing thousands of files.
SetPermissionsOnBoot bool `yaml:"set_permissions_on_boot"` //
// Setting this to true by default helps us avoid a lot of support requests
// from people that keep trying to move files around as a root user leading
// to server permission issues.
//
// In production and heavy use environments where boot speed is essential,
// this should be set to false as servers will self-correct permissions on
// boot anyways.
SetPermissionsOnBoot bool `default:"true" yaml:"set_permissions_on_boot"`
// Determines if Wings should detect a server that stops with a normal exit code of // Determines if Wings should detect a server that stops with a normal exit code of
// "0" as being crashed if the process stopped without any Wings interaction. E.g. // "0" as being crashed if the process stopped without any Wings interaction. E.g.
// the user did not press the stop button, but the process stopped cleanly. // the user did not press the stop button, but the process stopped cleanly.
DetectCleanExitAsCrash bool `default:"true" yaml:"detect_clean_exit_as_crash"` DetectCleanExitAsCrash bool `default:"true" yaml:"detect_clean_exit_as_crash"`
Sftp *SftpConfiguration `default:"SftpConfiguration" yaml:"sftp"` Sftp *SftpConfiguration `yaml:"sftp"`
} }
// Defines the configuration of the internal SFTP server. // Defines the configuration of the internal SFTP server.
@ -134,7 +146,7 @@ type DockerNetworkConfiguration struct {
Driver string `default:"bridge"` Driver string `default:"bridge"`
IsInternal bool `default:"false" yaml:"is_internal"` IsInternal bool `default:"false" yaml:"is_internal"`
EnableICC bool `default:"true" yaml:"enable_icc"` EnableICC bool `default:"true" yaml:"enable_icc"`
Interfaces *dockerNetworkInterfaces `yaml:"interfaces"` Interfaces dockerNetworkInterfaces `yaml:"interfaces"`
} }
// Defines the docker configuration used by the daemon when interacting with // Defines the docker configuration used by the daemon when interacting with
@ -142,7 +154,7 @@ type DockerNetworkConfiguration struct {
type DockerConfiguration struct { type DockerConfiguration struct {
// Network configuration that should be used when creating a new network // Network configuration that should be used when creating a new network
// for containers run through the daemon. // for containers run through the daemon.
Network *DockerNetworkConfiguration `yaml:"network"` Network DockerNetworkConfiguration `yaml:"network"`
// If true, container images will be updated when a server starts if there // If true, container images will be updated when a server starts if there
// is an update available. If false the daemon will not attempt updates and will // is an update available. If false the daemon will not attempt updates and will
@ -161,70 +173,20 @@ type DockerConfiguration struct {
// daemon webserver. // daemon webserver.
type ApiConfiguration struct { type ApiConfiguration struct {
// The interface that the internal webserver should bind to. // The interface that the internal webserver should bind to.
Host string Host string `default:"0.0.0.0" yaml:"host"`
// The port that the internal webserver should bind to. // The port that the internal webserver should bind to.
Port int Port int `default:"8080" yaml:"port"`
// SSL configuration for the daemon. // SSL configuration for the daemon.
Ssl struct { Ssl struct {
Enabled bool Enabled bool `default:"false"`
CertificateFile string `yaml:"cert"` CertificateFile string `yaml:"cert"`
KeyFile string `yaml:"key"` KeyFile string `yaml:"key"`
} }
// The maximum size for files uploaded through the Panel in bytes. // The maximum size for files uploaded through the Panel in bytes.
UploadLimit int `yaml:"upload_limit"` UploadLimit int `default:"100" yaml:"upload_limit"`
}
// Configures the default values for many of the configuration options present
// in the structs. If these values are set in the configuration file they will
// be overridden. However, if they don't exist and we don't set these here, all
// of the places in the code using them will need to be doing checks, which is
// a tedious thing to have to do.
func (c *Configuration) SetDefaults() {
c.System = &SystemConfiguration{
Username: "pterodactyl",
Data: "/srv/daemon-data",
TimezonePath: "/etc/timezone",
Sftp: &SftpConfiguration{},
}
// By default the internal webserver should bind to all interfaces and
// be served on port 8080.
c.Api = &ApiConfiguration{
Host: "0.0.0.0",
Port: 8080,
}
// Setting this to true by default helps us avoid a lot of support requests
// from people that keep trying to move files around as a root user leading
// to server permission issues.
//
// In production and heavy use environments where boot speed is essential,
// this should be set to false as servers will self-correct permissions on
// boot anyways.
c.System.SetPermissionsOnBoot = true
// Configure the default throttler implementation. This should work fine
// for 99% of people running servers on the platform. The occasional host
// might need to tweak them to be less restrictive depending on their hardware
// and target audience.
c.Throttles.KillAtCount = 5
c.Throttles.DecaySeconds = 10
c.Throttles.BytesPerInterval = 4096
c.Throttles.CheckInterval = 100
// Configure the defaults for Docker connection and networks.
c.Docker = &DockerConfiguration{
Network: &DockerNetworkConfiguration{
Interfaces: &dockerNetworkInterfaces{},
},
}
if err := defaults.Set(c); err != nil {
zap.S().Warnw("error setting defaults for configuration", zap.Error(errors.WithStack(err)))
}
} }
// Reads the configuration from the provided file and returns the configuration // Reads the configuration from the provided file and returns the configuration
@ -236,7 +198,12 @@ func ReadConfiguration(path string) (*Configuration, error) {
} }
c := new(Configuration) c := new(Configuration)
c.SetDefaults() // Configures the default values for many of the configuration options present
// in the structs. Valkues set in the configuration file take priority over the
// default values.
if err := defaults.Set(c); err != nil {
return nil, err
}
// Replace environment variables within the configuration file with their // Replace environment variables within the configuration file with their
// values from the host system. // values from the host system.

View File

@ -81,7 +81,7 @@ func New(data []byte) (*Installer, error) {
// Create a new server instance using the configuration we wrote to the disk // Create a new server instance using the configuration we wrote to the disk
// so that everything gets instantiated correctly on the struct. // so that everything gets instantiated correctly on the struct.
s2, err := server.FromConfiguration(b, config.Get().System) s2, err := server.FromConfiguration(b, &config.Get().System)
return &Installer{ return &Installer{
server: s2, server: s2,

View File

@ -69,12 +69,12 @@ func main() {
zap.S().Infow("finished ensuring file permissions") zap.S().Infow("finished ensuring file permissions")
} }
if err := server.LoadDirectory("data/servers", c.System); err != nil { if err := server.LoadDirectory("data/servers",&c.System); err != nil {
zap.S().Fatalw("failed to load server configurations", zap.Error(err)) zap.S().Fatalw("failed to load server configurations", zap.Error(err))
return return
} }
if err := ConfigureDockerEnvironment(c.Docker); err != nil { if err := ConfigureDockerEnvironment(&c.Docker); err != nil {
zap.S().Fatalw("failed to configure docker environment", zap.Error(errors.WithStack(err))) zap.S().Fatalw("failed to configure docker environment", zap.Error(errors.WithStack(err)))
os.Exit(1) os.Exit(1)
} }
@ -113,6 +113,9 @@ func main() {
// We never want to stop an instance that is currently running external from Wings since // We never want to stop an instance that is currently running external from Wings since
// that is a good way of keeping things running even if Wings gets in a very corrupted state. // that is a good way of keeping things running even if Wings gets in a very corrupted state.
zap.S().Infow("detected server is running, re-attaching to process", zap.String("server", s.Uuid)) zap.S().Infow("detected server is running, re-attaching to process", zap.String("server", s.Uuid))
if err := s.Sync(); err != nil {
zap.S().Errorw("failed to sync server state, cannot mark as running", zap.String("server", s.Uuid), zap.Error(errors.WithStack(err)))
} else {
s.SetState(server.ProcessRunningState) s.SetState(server.ProcessRunningState)
// If we cannot attach to the environment go ahead and mark the processs as being offline. // If we cannot attach to the environment go ahead and mark the processs as being offline.
@ -120,6 +123,7 @@ func main() {
zap.S().Warnw("error attaching to server environment", zap.String("server", s.Uuid), zap.Error(err)) zap.S().Warnw("error attaching to server environment", zap.String("server", s.Uuid), zap.Error(err))
s.SetState(server.ProcessOfflineState) s.SetState(server.ProcessOfflineState)
} }
}
} else if !r { } else if !r {
// If the server is not in a running state right now but according to the configuration it // If the server is not in a running state right now but according to the configuration it
// should be, we want to go ahead and restart the instance. // should be, we want to go ahead and restart the instance.