Compare commits

..

1 Commits

Author SHA1 Message Date
Dane Everitt
9ea991d86b Bump for release 2020-05-03 21:38:22 -07:00
22 changed files with 186 additions and 446 deletions

View File

@@ -1,10 +1,28 @@
build: BINARY = "build/wings"
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -gcflags "all=-trimpath=/Users/dane/Sites/development/code" -o build/wings_linux_amd64 -v wings.go OSARCHLIST = "darwin/386 darwin/amd64 linux/386 linux/amd64 linux/arm linux/arm64 windows/386 windows/amd64"
compress: all: $(BINARY)
upx --brute build/wings_*
cross-build: clean build compress $(BINARY):
go build -o $(BINARY)
clean: cross-build:
rm -rf build/wings_* gox -osarch $(OSARCHLIST) -output "build/{{.Dir}}_{{.OS}}_{{.Arch}}"
.PHONY: install
install:
go install
test:
go test `go list ./... | grep -v "/vendor/"`
coverage:
goverage -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
dependencies:
glide install
install-tools:
go get -u github.com/mitchellh/gox
go get -u github.com/haya14busa/goverage

View File

@@ -45,28 +45,6 @@ func (r *PanelRequest) GetEndpoint(endpoint string) string {
) )
} }
// Logs the request into the debug log with all of the important request bits.
// The authorization key will be cleaned up before being output.
func (r *PanelRequest) logDebug(req *http.Request) {
headers := make(map[string][]string)
for k, v := range req.Header {
if k != "Authorization" || len(v) == 0 {
headers[k] = v
continue
}
headers[k] = []string{v[0][0:15] + "(redacted)"}
}
zap.S().Debugw(
"making request to external HTTP endpoint",
zap.String("method", req.Method),
zap.String("endpoint", req.URL.String()),
zap.Any("headers", headers),
)
}
func (r *PanelRequest) Get(url string) (*http.Response, error) { func (r *PanelRequest) Get(url string) (*http.Response, error) {
c := r.GetClient() c := r.GetClient()
@@ -77,7 +55,7 @@ func (r *PanelRequest) Get(url string) (*http.Response, error) {
return nil, err return nil, err
} }
r.logDebug(req) zap.S().Debugw("GET request to endpoint", zap.String("endpoint", r.GetEndpoint(url)), zap.Any("headers", req.Header))
return c.Do(req) return c.Do(req)
} }
@@ -92,7 +70,7 @@ func (r *PanelRequest) Post(url string, data []byte) (*http.Response, error) {
return nil, err return nil, err
} }
r.logDebug(req) zap.S().Debugw("POST request to endpoint", zap.String("endpoint", r.GetEndpoint(url)), zap.Any("headers", req.Header))
return c.Do(req) return c.Do(req)
} }

View File

@@ -1,60 +0,0 @@
package cmd
import (
"github.com/pterodactyl/wings/config"
"os"
"path/filepath"
)
// We've gone through a couple of iterations of where the configuration is stored. This
// helpful little function will look through the three areas it might have ended up, and
// return it.
//
// We only run this if the configuration flag for the instance is not actually passed in
// via the command line. Once found, the configuration is moved into the expected default
// location. Only errors are returned from this function, you can safely assume that after
// running this the configuration can be found in the correct default location.
func RelocateConfiguration() error {
var match string
check := []string{
config.DefaultLocation,
"/var/lib/pterodactyl/config.yml",
"/etc/wings/config.yml",
}
// Loop over all of the configuration paths, and return which one we found, if
// any.
for _, p := range check {
if s, err := os.Stat(p); err != nil {
if !os.IsNotExist(err) {
return err
}
} else if !s.IsDir() {
match = p
break
}
}
// Just return a generic not exist error at this point if we didn't have a match, this
// will allow the caller to handle displaying a more friendly error to the user. If we
// did match in the default location, go ahead and return successfully.
if match == "" {
return os.ErrNotExist
} else if match == config.DefaultLocation {
return nil
}
// The rest of this function simply creates the new default location and moves the
// old configuration file over to the new location, then sets the permissions on the
// file correctly so that only the user running this process can read it.
p, _ := filepath.Split(config.DefaultLocation)
if err := os.MkdirAll(p, 0755); err != nil {
return err
}
if err := os.Rename(match, config.DefaultLocation); err != nil {
return err
}
return os.Chmod(config.DefaultLocation, 0600)
}

View File

@@ -3,7 +3,6 @@ package cmd
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/mitchellh/colorstring"
"net/http" "net/http"
"os" "os"
"path" "path"
@@ -63,22 +62,11 @@ func readConfiguration() (*config.Configuration, error) {
} }
func rootCmdRun(*cobra.Command, []string) { func rootCmdRun(*cobra.Command, []string) {
// Profile wings in production!!!!
if shouldRunProfiler { if shouldRunProfiler {
defer profile.Start().Stop() defer profile.Start().Stop()
} }
// Only attempt configuration file relocation if a custom location has not
// been specified in the command startup.
if configPath == config.DefaultLocation {
if err := RelocateConfiguration(); err != nil {
if os.IsNotExist(err) {
exitWithConfigurationNotice()
}
panic(err)
}
}
c, err := readConfiguration() c, err := readConfiguration()
if err != nil { if err != nil {
panic(err) panic(err)
@@ -271,23 +259,3 @@ func printLogo() {
fmt.Println(`Copyright © 2018 - 2020 Dane Everitt & Contributors`) fmt.Println(`Copyright © 2018 - 2020 Dane Everitt & Contributors`)
fmt.Println() fmt.Println()
} }
func exitWithConfigurationNotice() {
fmt.Print(colorstring.Color(`
[_red_][white][bold]Error: Configuration File Not Found[reset]
Wings was not able to locate your configuration file, and therefore is not
able to complete its boot process.
Please ensure you have copied your instance configuration file into
the default location, or have provided the --config flag to use a
custom location.
Default Location: /etc/pterodactyl/config.yml
[yellow]This is not a bug with this software. Please do not make a bug report
for this issue, it will be closed.[reset]
`))
os.Exit(1)
}

View File

@@ -19,7 +19,7 @@ import (
"sync" "sync"
) )
const DefaultLocation = "/etc/pterodactyl/config.yml" const DefaultLocation = "/var/lib/pterodactyl/config.yml"
type Configuration struct { type Configuration struct {
sync.RWMutex `json:"-" yaml:"-"` sync.RWMutex `json:"-" yaml:"-"`
@@ -46,9 +46,9 @@ type Configuration struct {
// validate against it. // validate against it.
AuthenticationToken string `json:"token" yaml:"token"` AuthenticationToken string `json:"token" yaml:"token"`
Api ApiConfiguration `json:"api" yaml:"api"` Api ApiConfiguration
System SystemConfiguration `json:"system" yaml:"system"` System SystemConfiguration
Docker DockerConfiguration `json:"docker" yaml:"docker"` 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

View File

@@ -15,7 +15,7 @@ type dockerNetworkInterfaces struct {
type DockerNetworkConfiguration struct { type DockerNetworkConfiguration struct {
// The interface that should be used to create the network. Must not conflict // The interface that should be used to create the network. Must not conflict
// with any other interfaces in use by Docker or on the system. // with any other interfaces in use by Docker or on the system.
Interface string `default:"172.18.0.1" json:"interface" yaml:"interface"` Interface string `default:"172.18.0.1"`
// The DNS settings for containers. // The DNS settings for containers.
Dns []string `default:"[\"1.1.1.1\", \"1.0.0.1\"]"` Dns []string `default:"[\"1.1.1.1\", \"1.0.0.1\"]"`
@@ -26,7 +26,6 @@ type DockerNetworkConfiguration struct {
Name string `default:"pterodactyl_nw"` Name string `default:"pterodactyl_nw"`
ISPN bool `default:"false" yaml:"ispn"` ISPN bool `default:"false" yaml:"ispn"`
Driver string `default:"bridge"` Driver string `default:"bridge"`
Mode string `default:"pterodactyl_nw" yaml:"network_mode"`
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"`
@@ -45,7 +44,7 @@ type DockerConfiguration struct {
UpdateImages bool `default:"true" json:"update_images" yaml:"update_images"` UpdateImages bool `default:"true" json:"update_images" yaml:"update_images"`
// The location of the Docker socket. // The location of the Docker socket.
Socket string `default:"/var/run/docker.sock" json:"socket" yaml:"socket"` Socket string `default:"/var/run/docker.sock"`
// Defines the location of the timezone file on the host system that should // Defines the location of the timezone file on the host system that should
// be mounted into the created containers so that they all use the same time. // be mounted into the created containers so that they all use the same time.

20
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/pterodactyl/wings module github.com/pterodactyl/wings
go 1.13 go 1.12
// Uncomment this in development environments to make changes to the core SFTP // Uncomment this in development environments to make changes to the core SFTP
// server software. This assumes you're using the official Pterodactyl Environment // server software. This assumes you're using the official Pterodactyl Environment
@@ -36,7 +36,6 @@ require (
github.com/gorilla/websocket v1.4.0 github.com/gorilla/websocket v1.4.0
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334
github.com/icza/dyno v0.0.0-20200205103839-49cb13720835
github.com/imdario/mergo v0.3.8 github.com/imdario/mergo v0.3.8
github.com/klauspost/pgzip v1.2.3 github.com/klauspost/pgzip v1.2.3
github.com/magiconair/properties v1.8.1 github.com/magiconair/properties v1.8.1
@@ -51,24 +50,25 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.4.0 github.com/pkg/profile v1.4.0
github.com/pkg/sftp v1.11.0 // indirect github.com/pkg/sftp v1.10.1 // indirect
github.com/pterodactyl/sftp-server v1.1.2 github.com/pterodactyl/sftp-server v1.1.1
github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94
github.com/smartystreets/goconvey v1.6.4 // indirect github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/spf13/cobra v0.0.7 github.com/spf13/cobra v0.0.7
github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/objx v0.2.0 // indirect
github.com/yuin/goldmark v1.1.30 // indirect github.com/yuin/goldmark v1.1.30 // indirect
go.uber.org/zap v1.15.0 go.uber.org/atomic v1.5.1 // indirect
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 // indirect go.uber.org/multierr v1.4.0 // indirect
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect go.uber.org/zap v1.13.0
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5 // indirect
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f // indirect
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0 // indirect
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f // indirect golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f // indirect
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5 // indirect golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/ini.v1 v1.51.0 gopkg.in/ini.v1 v1.51.0
gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 v2.2.8
gotest.tools v2.2.0+incompatible // indirect gotest.tools v2.2.0+incompatible // indirect
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
) )

23
go.sum
View File

@@ -123,8 +123,6 @@ github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDG
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/icza/dyno v0.0.0-20200205103839-49cb13720835 h1:f1irK5f03uGGj+FjgQfZ5VhdKNVQVJ4skHsedzVohQ4=
github.com/icza/dyno v0.0.0-20200205103839-49cb13720835/go.mod h1:c1tRKs5Tx7E2+uHGSyyncziFjvGpgv4H2HrqXeUQ/Uk=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
@@ -218,8 +216,6 @@ github.com/pkg/sftp v1.8.3 h1:9jSe2SxTM8/3bXZjtqnkgTBW+lA8db0knZJyns7gpBA=
github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk= github.com/pkg/sftp v1.8.3/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk=
github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc= github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.11.0 h1:4Zv0OGbpkg4yNuUtH0s8rvoYxRCNyT29NVUo6pgPmxI=
github.com/pkg/sftp v1.11.0/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -233,8 +229,6 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/pterodactyl/sftp-server v1.1.1 h1:IjuOy21BNZxfejKnXG1RgLxXAYylDqBVpbKZ6+fG5FQ= github.com/pterodactyl/sftp-server v1.1.1 h1:IjuOy21BNZxfejKnXG1RgLxXAYylDqBVpbKZ6+fG5FQ=
github.com/pterodactyl/sftp-server v1.1.1/go.mod h1:b1VVWYv0RF9rxSZQqaD/rYXriiRMNPsbV//CKMXR4ag= github.com/pterodactyl/sftp-server v1.1.1/go.mod h1:b1VVWYv0RF9rxSZQqaD/rYXriiRMNPsbV//CKMXR4ag=
github.com/pterodactyl/sftp-server v1.1.2 h1:5bI9upe0kBRn9ALDabn9S2GVU5gkYvSErYgs32dAKjk=
github.com/pterodactyl/sftp-server v1.1.2/go.mod h1:KjSONrenRr1oCh94QIVAU6yEzMe+Hd7r/JHrh5/oQHs=
github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce h1:aP+C+YbHZfOQlutA4p4soHi7rVUqHQdWEVMSkHfDTqY= github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce h1:aP+C+YbHZfOQlutA4p4soHi7rVUqHQdWEVMSkHfDTqY=
github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/remeh/sizedwaitgroup v0.0.0-20180822144253-5e7302b12cce/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@@ -291,15 +285,11 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM= go.uber.org/atomic v1.5.1 h1:rsqfU5vBkVknbhUGbAUwQKR2H4ItV8tjJ+6kJX4cxHM=
go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
@@ -307,8 +297,6 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -321,8 +309,6 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEB
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5 h1:Q7tZBpemrlsc2I7IyODzhtallWRSm4Q0d09pL6XbQtU= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5 h1:Q7tZBpemrlsc2I7IyODzhtallWRSm4Q0d09pL6XbQtU=
golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -330,9 +316,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -372,8 +356,6 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HX
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
@@ -392,13 +374,9 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290 h1:NXNmtp0ToD36cui5IqWy95LC4Y6vT/4y3RnPxlQPinU= golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290 h1:NXNmtp0ToD36cui5IqWy95LC4Y6vT/4y3RnPxlQPinU=
golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200417140056-c07e33ef3290/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b h1:zSzQJAznWxAh9fZxiPy2FZo+ZZEYoYFYYDYdOrU7AaM=
golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools/gopls v0.1.3/go.mod h1:vrCQzOKxvuiZLjCKSmbbov04oeBQQOb4VQqwYK2PWIY= golang.org/x/tools/gopls v0.1.3/go.mod h1:vrCQzOKxvuiZLjCKSmbbov04oeBQQOb4VQqwYK2PWIY=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -430,4 +408,3 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=

View File

@@ -9,6 +9,7 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
"io/ioutil" "io/ioutil"
"os" "os"
"reflect"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
@@ -47,14 +48,13 @@ func readFileBytes(path string) ([]byte, error) {
} }
// Gets the value of a key based on the value type defined. // Gets the value of a key based on the value type defined.
func (cfr *ConfigurationFileReplacement) getKeyValue(value []byte) interface{} { func getKeyValue(value []byte) interface{} {
if cfr.ReplaceWith.Type() == jsonparser.Boolean { if reflect.ValueOf(value).Kind() == reflect.Bool {
v, _ := strconv.ParseBool(string(value)) v, _ := strconv.ParseBool(string(value))
return v return v
} }
// Try to parse into an int, if this fails just ignore the error and continue // Try to parse into an int, if this fails just ignore the error and
// through, returning the string.
if v, err := strconv.Atoi(string(value)); err == nil { if v, err := strconv.Atoi(string(value)); err == nil {
return v return v
} }
@@ -70,9 +70,7 @@ func (cfr *ConfigurationFileReplacement) getKeyValue(value []byte) interface{} {
// configurations per-world (such as Spigot and Bungeecord) where we'll need to make // configurations per-world (such as Spigot and Bungeecord) where we'll need to make
// adjustments to the bind address for the user. // adjustments to the bind address for the user.
// //
// This does not currently support nested wildcard matches. For example, foo.*.bar // This does not currently support nested matches. container.*.foo.*.bar will not work.
// will work, however foo.*.bar.*.baz will not, since we'll only be splitting at the
// first wildcard, and not subsequent ones.
func (f *ConfigurationFile) IterateOverJson(data []byte) (*gabs.Container, error) { func (f *ConfigurationFile) IterateOverJson(data []byte) (*gabs.Container, error) {
parsed, err := gabs.ParseJSON(data) parsed, err := gabs.ParseJSON(data)
if err != nil { if err != nil {
@@ -145,7 +143,7 @@ func (cfr *ConfigurationFileReplacement) SetAtPathway(c *gabs.Container, path st
} }
} }
_, err := c.SetP(cfr.getKeyValue(value), path) _, err := c.SetP(getKeyValue(value), path)
return err return err
} }
@@ -167,8 +165,11 @@ func (f *ConfigurationFile) LookupConfigurationValue(cfr ConfigurationFileReplac
) )
var path []string var path []string
// The camel casing is important here, the configuration for the Daemon does not use
// JSON, and as such all of the keys will be generated in CamelCase format, rather than
// the expected snake_case from the old Daemon.
for _, value := range strings.Split(huntPath, ".") { for _, value := range strings.Split(huntPath, ".") {
path = append(path, strcase.ToSnake(value)) path = append(path, strcase.ToCamel(value))
} }
// Look for the key in the configuration file, and if found return that value to the // Look for the key in the configuration file, and if found return that value to the

View File

@@ -5,16 +5,14 @@ import (
"encoding/json" "encoding/json"
"github.com/beevik/etree" "github.com/beevik/etree"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
"github.com/icza/dyno" "github.com/ghodss/yaml"
"github.com/magiconair/properties" "github.com/magiconair/properties"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"gopkg.in/yaml.v2"
"io/ioutil" "io/ioutil"
"os" "os"
"regexp"
"strings" "strings"
) )
@@ -42,44 +40,6 @@ type ConfigurationFile struct {
configuration []byte configuration []byte
} }
// Custom unmarshaler for configuration files. If there is an error while parsing out the
// replacements, don't fail the entire operation, just log a global warning so someone can
// find the issue, and return an empty array of replacements.
//
// I imagine people will notice configuration replacement isn't working correctly and then
// the logs should help better expose that issue.
func (f *ConfigurationFile) UnmarshalJSON(data []byte) error {
var m map[string]*json.RawMessage
if err := json.Unmarshal(data, &m); err != nil {
return err
}
if err := json.Unmarshal(*m["file"], &f.FileName); err != nil {
return err
}
if err := json.Unmarshal(*m["parser"], &f.Parser); err != nil {
return err
}
if err := json.Unmarshal(*m["replace"], &f.Replace); err != nil {
zap.S().Warnw(
"failed to unmarshal configuration file replacement",
zap.String("file", f.FileName),
zap.Error(err),
)
f.Replace = []ConfigurationFileReplacement{}
}
return nil
}
// Regex to match paths such as foo[1].bar[2] and convert them into a format that
// gabs can work with, such as foo.1.bar.2 in this case. This is applied when creating
// the struct for the configuration file replacements.
var cfrMatchReplacement = regexp.MustCompile(`\[(\d+)]`)
// Defines a single find/replace instance for a given server configuration file. // Defines a single find/replace instance for a given server configuration file.
type ConfigurationFileReplacement struct { type ConfigurationFileReplacement struct {
Match string `json:"match"` Match string `json:"match"`
@@ -92,34 +52,22 @@ type ConfigurationFileReplacement struct {
func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error { func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error {
m, err := jsonparser.GetString(data, "match") m, err := jsonparser.GetString(data, "match")
if err != nil { if err != nil {
return err return errors.WithStack(err)
} }
cfr.Match = m
// See comment on the replacement regex to understand what exactly this is doing.
cfr.Match = cfrMatchReplacement.ReplaceAllString(m, ".$1")
iv, err := jsonparser.GetString(data, "if_value") iv, err := jsonparser.GetString(data, "if_value")
// We only check keypath here since match & replace_with should be present on all of // We only check keypath here since match & replace_with should be present on all of
// them, however if_value is optional. // them, however if_value is optional.
if err != nil && err != jsonparser.KeyPathNotFoundError { if err != nil && err != jsonparser.KeyPathNotFoundError {
return err return errors.WithStack(err)
} }
cfr.IfValue = iv cfr.IfValue = iv
rw, dt, _, err := jsonparser.Get(data, "replace_with") rw, dt, _, err := jsonparser.Get(data, "replace_with")
if err != nil { if err != nil {
if err != jsonparser.KeyPathNotFoundError { return errors.WithStack(err)
return err
}
// Okay, likely dealing with someone who forgot to upgrade their eggs, so in
// that case, fallback to using the old key which was "value".
rw, dt, _, err = jsonparser.Get(data, "value")
if err != nil {
return err
}
} }
cfr.ReplaceWith = ReplaceValue{ cfr.ReplaceWith = ReplaceValue{
value: rw, value: rw,
valueType: dt, valueType: dt,
@@ -133,11 +81,8 @@ func (cfr *ConfigurationFileReplacement) UnmarshalJSON(data []byte) error {
func (f *ConfigurationFile) Parse(path string, internal bool) error { func (f *ConfigurationFile) Parse(path string, internal bool) error {
zap.S().Debugw("parsing configuration file", zap.String("path", path), zap.String("parser", string(f.Parser))) zap.S().Debugw("parsing configuration file", zap.String("path", path), zap.String("parser", string(f.Parser)))
if mb, err := json.Marshal(config.Get()); err != nil { mb, _ := json.Marshal(config.Get())
return err f.configuration = mb
} else {
f.configuration = mb
}
var err error var err error
@@ -359,15 +304,10 @@ func (f *ConfigurationFile) parseYamlFile(path string) error {
return err return err
} }
i := make(map[string]interface{})
if err := yaml.Unmarshal(b, &i); err != nil {
return err
}
// Unmarshal the yaml data into a JSON interface such that we can work with // Unmarshal the yaml data into a JSON interface such that we can work with
// any arbitrary data structure. If we don't do this, I can't use gabs which // any arbitrary data structure. If we don't do this, I can't use gabs which
// makes working with unknown JSON signficiantly easier. // makes working with unknown JSON signficiantly easier.
jsonBytes, err := json.Marshal(dyno.ConvertMapI2MapS(i)) jsonBytes, err := yaml.YAMLToJSON(b)
if err != nil { if err != nil {
return err return err
} }
@@ -380,7 +320,7 @@ func (f *ConfigurationFile) parseYamlFile(path string) error {
} }
// Remarshal the JSON into YAML format before saving it back to the disk. // Remarshal the JSON into YAML format before saving it back to the disk.
marshaled, err := yaml.Marshal(data.Data()) marshaled, err := yaml.JSONToYAML(data.Bytes())
if err != nil { if err != nil {
return err return err
} }

View File

@@ -4,24 +4,14 @@ import (
"bufio" "bufio"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http" "net/http"
"net/url"
"os" "os"
"strconv" "strconv"
"strings"
) )
// Returns the contents of a file on the server. // Returns the contents of a file on the server.
func getServerFileContents(c *gin.Context) { func getServerFileContents(c *gin.Context) {
s := GetServer(c.Param("server")) s := GetServer(c.Param("server"))
cleaned, err := s.Filesystem.SafePath(c.Query("file"))
p, err := url.QueryUnescape(c.Query("file"))
if err != nil {
TrackedServerError(err, s).AbortWithServerError(c)
return
}
p = "/" + strings.TrimLeft(p, "/")
cleaned, err := s.Filesystem.SafePath(p)
if err != nil { if err != nil {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{ c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
"error": "The file requested could not be found.", "error": "The file requested could not be found.",
@@ -66,13 +56,7 @@ func getServerFileContents(c *gin.Context) {
func getServerListDirectory(c *gin.Context) { func getServerListDirectory(c *gin.Context) {
s := GetServer(c.Param("server")) s := GetServer(c.Param("server"))
d, err := url.QueryUnescape(c.Query("directory")) stats, err := s.Filesystem.ListDirectory(c.Query("directory"))
if err != nil {
TrackedServerError(err, s).AbortWithServerError(c)
return
}
stats, err := s.Filesystem.ListDirectory(d)
if err != nil { if err != nil {
TrackedServerError(err, s).AbortWithServerError(c) TrackedServerError(err, s).AbortWithServerError(c)
return return
@@ -85,9 +69,9 @@ func getServerListDirectory(c *gin.Context) {
func putServerRenameFile(c *gin.Context) { func putServerRenameFile(c *gin.Context) {
s := GetServer(c.Param("server")) s := GetServer(c.Param("server"))
var data struct { var data struct{
RenameFrom string `json:"rename_from"` RenameFrom string `json:"rename_from"`
RenameTo string `json:"rename_to"` RenameTo string `json:"rename_to"`
} }
c.BindJSON(&data) c.BindJSON(&data)
@@ -144,14 +128,7 @@ func postServerDeleteFile(c *gin.Context) {
func postServerWriteFile(c *gin.Context) { func postServerWriteFile(c *gin.Context) {
s := GetServer(c.Param("server")) s := GetServer(c.Param("server"))
f, err := url.QueryUnescape(c.Query("file")) if err := s.Filesystem.Writefile(c.Query("file"), c.Request.Body); err != nil {
if err != nil {
TrackedServerError(err, s).AbortWithServerError(c)
return
}
f = "/" + strings.TrimLeft(f, "/")
if err := s.Filesystem.Writefile(f, c.Request.Body); err != nil {
TrackedServerError(err, s).AbortWithServerError(c) TrackedServerError(err, s).AbortWithServerError(c)
return return
} }
@@ -175,4 +152,4 @@ func postServerCreateDirectory(c *gin.Context) {
} }
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
} }

View File

@@ -86,8 +86,7 @@ func (s *Server) Backup(b backup.BackupInterface) error {
return errors.WithStack(err) return errors.WithStack(err)
} }
ad, err := b.Generate(inc, s.Filesystem.Path()) if err := b.Generate(inc, s.Filesystem.Path()); err != nil {
if err != nil {
if notifyError := s.notifyPanelOfBackup(b.Identifier(), &backup.ArchiveDetails{}, false); notifyError != nil { if notifyError := s.notifyPanelOfBackup(b.Identifier(), &backup.ArchiveDetails{}, false); notifyError != nil {
zap.S().Warnw("failed to notify panel of failed backup state", zap.String("backup", b.Identifier()), zap.Error(err)) zap.S().Warnw("failed to notify panel of failed backup state", zap.String("backup", b.Identifier()), zap.Error(err))
} }
@@ -97,6 +96,7 @@ func (s *Server) Backup(b backup.BackupInterface) error {
// Try to notify the panel about the status of this backup. If for some reason this request // Try to notify the panel about the status of this backup. If for some reason this request
// fails, delete the archive from the daemon and return that error up the chain to the caller. // fails, delete the archive from the daemon and return that error up the chain to the caller.
ad := b.Details()
if notifyError := s.notifyPanelOfBackup(b.Identifier(), ad, true); notifyError != nil { if notifyError := s.notifyPanelOfBackup(b.Identifier(), ad, true); notifyError != nil {
b.Remove() b.Remove()

View File

@@ -49,7 +49,7 @@ type BackupInterface interface {
// Generates a backup in whatever the configured source for the specific // Generates a backup in whatever the configured source for the specific
// implementation is. // implementation is.
Generate(*IncludedFiles, string) (*ArchiveDetails, error) Generate(*IncludedFiles, string) error
// Returns the ignored files for this backup instance. // Returns the ignored files for this backup instance.
Ignored() []string Ignored() []string

View File

@@ -41,15 +41,13 @@ func (b *LocalBackup) Remove() error {
// Generates a backup of the selected files and pushes it to the defined location // Generates a backup of the selected files and pushes it to the defined location
// for this instance. // for this instance.
func (b *LocalBackup) Generate(included *IncludedFiles, prefix string) (*ArchiveDetails, error) { func (b *LocalBackup) Generate(included *IncludedFiles, prefix string) error {
a := &Archive{ a := &Archive{
TrimPrefix: prefix, TrimPrefix: prefix,
Files: included, Files: included,
} }
if err := a.Create(b.Path(), context.Background()); err != nil { err := a.Create(b.Path(), context.Background())
return nil, err
}
return b.Details(), nil return err
} }

View File

@@ -3,7 +3,6 @@ package backup
import ( import (
"context" "context"
"fmt" "fmt"
"go.uber.org/zap"
"io" "io"
"net/http" "net/http"
"os" "os"
@@ -22,9 +21,7 @@ type S3Backup struct {
var _ BackupInterface = (*S3Backup)(nil) var _ BackupInterface = (*S3Backup)(nil)
// Generates a new backup on the disk, moves it into the S3 bucket via the provided func (s *S3Backup) Generate(included *IncludedFiles, prefix string) error {
// presigned URL, and then deletes the backup from the disk.
func (s *S3Backup) Generate(included *IncludedFiles, prefix string) (*ArchiveDetails, error) {
defer s.Remove() defer s.Remove()
a := &Archive{ a := &Archive{
@@ -33,26 +30,45 @@ func (s *S3Backup) Generate(included *IncludedFiles, prefix string) (*ArchiveDet
} }
if err := a.Create(s.Path(), context.Background()); err != nil { if err := a.Create(s.Path(), context.Background()); err != nil {
return nil, err return err
} }
rc, err := os.Open(s.Path()) fmt.Println(s.PresignedUrl)
r, err := http.NewRequest(http.MethodPut, s.PresignedUrl, nil)
if err != nil { if err != nil {
return nil, err return err
}
if sz, err := s.Size(); err != nil {
return err
} else {
r.ContentLength = sz
r.Header.Add("Content-Length", strconv.Itoa(int(sz)))
r.Header.Add("Content-Type", "application/x-gzip")
}
var rc io.ReadCloser
if f, err := os.Open(s.Path()); err != nil {
return err
} else {
rc = f
} }
defer rc.Close() defer rc.Close()
if resp, err := s.generateRemoteRequest(rc); err != nil { r.Body = rc
return nil, err resp, err := http.DefaultClient.Do(r)
} else { if err != nil {
resp.Body.Close() return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("failed to put S3 object, %d:%s", resp.StatusCode, resp.Status) io.Copy(os.Stdout, resp.Body)
} return fmt.Errorf("failed to put S3 object, %d:%s", resp.StatusCode, resp.Status)
} }
return s.Details(), err return nil
} }
// Removes a backup from the system. // Removes a backup from the system.
@@ -60,24 +76,9 @@ func (s *S3Backup) Remove() error {
return os.Remove(s.Path()) return os.Remove(s.Path())
} }
// Generates the remote S3 request and begins the upload. func (s *S3Backup) Details() *ArchiveDetails {
func (s *S3Backup) generateRemoteRequest(rc io.ReadCloser) (*http.Response, error) { return &ArchiveDetails{
r, err := http.NewRequest(http.MethodPut, s.PresignedUrl, nil) Checksum: "checksum",
if err != nil { Size: 1024,
return nil, err
} }
if sz, err := s.Size(); err != nil {
return nil, err
} else {
r.ContentLength = sz
r.Header.Add("Content-Length", strconv.Itoa(int(sz)))
r.Header.Add("Content-Type", "application/x-gzip")
}
r.Body = rc
zap.S().Debugw("uploading backup to remote S3 endpoint", zap.String("endpoint", s.PresignedUrl), zap.Any("headers", r.Header))
return http.DefaultClient.Do(r)
} }

View File

@@ -17,6 +17,7 @@ import (
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"go.uber.org/zap" "go.uber.org/zap"
"io" "io"
"math"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@@ -196,31 +197,16 @@ func (d *DockerEnvironment) Start() error {
return &suspendedError{} return &suspendedError{}
} }
if c, err := d.Client.ContainerInspect(context.Background(), d.Server.Uuid); err != nil { c, err := d.Client.ContainerInspect(context.Background(), d.Server.Uuid)
// Do nothing if the container is not found, we just don't want to continue if err != nil && !client.IsErrNotFound(err) {
// to the next block of code here. This check was inlined here to guard againt return errors.WithStack(err)
// a nil-pointer when checking c.State below. }
//
// @see https://github.com/pterodactyl/panel/issues/2000
if !client.IsErrNotFound(err) {
return errors.WithStack(err)
}
} else {
// If the server is running update our internal state and continue on with the attach.
if c.State.Running {
d.Server.SetState(ProcessRunningState)
return d.Attach() // No reason to try starting a container that is already running.
} if c.State.Running {
d.Server.SetState(ProcessRunningState)
// Truncate the log file so we don't end up outputting a bunch of useless log information return d.Attach()
// to the websocket and whatnot. Check first that the path and file exist before trying
// to truncate them.
if _, err := os.Stat(c.LogPath); err == nil {
if err := os.Truncate(c.LogPath, 0); err != nil {
return errors.WithStack(err)
}
}
} }
d.Server.SetState(ProcessStartingState) d.Server.SetState(ProcessStartingState)
@@ -235,6 +221,15 @@ func (d *DockerEnvironment) Start() error {
return errors.WithStack(err) return errors.WithStack(err)
} }
// Truncate the log file so we don't end up outputting a bunch of useless log information
// to the websocket and whatnot. Check first that the path and file exist before trying
// to truncate them.
if _, err := os.Stat(c.LogPath); err == nil {
if err := os.Truncate(c.LogPath, 0); err != nil {
return errors.WithStack(err)
}
}
// Update the configuration files defined for the server before beginning the boot process. // Update the configuration files defined for the server before beginning the boot process.
// This process executes a bunch of parallel updates, so we just block until that process // This process executes a bunch of parallel updates, so we just block until that process
// is completed. Any errors as a result of this will just be bubbled out in the logger, // is completed. Any errors as a result of this will just be bubbled out in the logger,
@@ -343,21 +338,11 @@ func (d *DockerEnvironment) Destroy() error {
// Avoid crash detection firing off. // Avoid crash detection firing off.
d.Server.SetState(ProcessStoppingState) d.Server.SetState(ProcessStoppingState)
err := d.Client.ContainerRemove(ctx, d.Server.Uuid, types.ContainerRemoveOptions{ return d.Client.ContainerRemove(ctx, d.Server.Uuid, types.ContainerRemoveOptions{
RemoveVolumes: true, RemoveVolumes: true,
RemoveLinks: false, RemoveLinks: false,
Force: true, Force: true,
}) })
// Don't trigger a destroy failure if we try to delete a container that does not
// exist on the system. We're just a step ahead of ourselves in that case.
//
// @see https://github.com/pterodactyl/panel/issues/2001
if err != nil && client.IsErrNotFound(err) {
return nil
}
return err
} }
// Determine the container exit state and return the exit code and wether or not // Determine the container exit state and return the exit code and wether or not
@@ -365,19 +350,6 @@ func (d *DockerEnvironment) Destroy() error {
func (d *DockerEnvironment) ExitState() (uint32, bool, error) { func (d *DockerEnvironment) ExitState() (uint32, bool, error) {
c, err := d.Client.ContainerInspect(context.Background(), d.Server.Uuid) c, err := d.Client.ContainerInspect(context.Background(), d.Server.Uuid)
if err != nil { if err != nil {
// I'm not entirely sure how this can happen to be honest. I tried deleting a
// container _while_ a server was running and wings gracefully saw the crash and
// created a new container for it.
//
// However, someone reported an error in Discord about this scenario happening,
// so I guess this should prevent it? They didn't tell me how they caused it though
// so thats a mystery that will have to go unsolved.
//
// @see https://github.com/pterodactyl/panel/issues/2003
if client.IsErrNotFound(err) {
return 1, false, nil
}
return 0, false, errors.WithStack(err) return 0, false, errors.WithStack(err)
} }
@@ -511,7 +483,7 @@ func (d *DockerEnvironment) EnableResourcePolling() error {
} }
s.Resources.CpuAbsolute = s.Resources.CalculateAbsoluteCpu(&v.PreCPUStats, &v.CPUStats) s.Resources.CpuAbsolute = s.Resources.CalculateAbsoluteCpu(&v.PreCPUStats, &v.CPUStats)
s.Resources.Memory = s.Resources.CalculateDockerMemory(v.MemoryStats) s.Resources.Memory = v.MemoryStats.Usage
s.Resources.MemoryLimit = v.MemoryStats.Limit s.Resources.MemoryLimit = v.MemoryStats.Limit
// Why you ask? This already has the logic for caching disk space in use and then // Why you ask? This already has the logic for caching disk space in use and then
@@ -575,6 +547,8 @@ func (d *DockerEnvironment) ensureImageExists(c *client.Client) error {
// Creates a new container for the server using all of the data that is currently // Creates a new container for the server using all of the data that is currently
// available for it. If the container already exists it will be returned. // available for it. If the container already exists it will be returned.
//
// @todo pull the image being requested if it doesn't exist currently.
func (d *DockerEnvironment) Create() error { func (d *DockerEnvironment) Create() error {
ctx := context.Background() ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv) cli, err := client.NewClientWithOpts(client.FromEnv)
@@ -665,9 +639,20 @@ func (d *DockerEnvironment) Create() error {
"setpcap", "mknod", "audit_write", "net_raw", "dac_override", "setpcap", "mknod", "audit_write", "net_raw", "dac_override",
"fowner", "fsetid", "net_bind_service", "sys_chroot", "setfcap", "fowner", "fsetid", "net_bind_service", "sys_chroot", "setfcap",
}, },
NetworkMode: container.NetworkMode(config.Get().Docker.Network.Mode), NetworkMode: "pterodactyl_nw",
} }
// Pretty sure TZ=X in the environment variables negates the need for this
// to happen. Leaving it until I can confirm that works for everything.
//
// if err := mountTimezoneData(hostConf); err != nil {
// if os.IsNotExist(err) {
// zap.S().Warnw("the timezone data path configured does not exist on the system", zap.Error(errors.WithStack(err)))
// } else {
// zap.S().Warnw("failed to mount timezone data into container", zap.Error(errors.WithStack(err)))
// }
// }
if _, err := cli.ContainerCreate(ctx, conf, hostConf, nil, d.Server.Uuid); err != nil { if _, err := cli.ContainerCreate(ctx, conf, hostConf, nil, d.Server.Uuid); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@@ -784,7 +769,7 @@ eloop:
} }
} }
out = append(out, fmt.Sprintf("%s=%s", strings.ToUpper(k), v)) out = append(out, fmt.Sprintf("%s=\"%s\"", strings.ToUpper(k), v))
} }
return out return out
@@ -839,21 +824,23 @@ func (d *DockerEnvironment) exposedPorts() nat.PortSet {
// Formats the resources available to a server instance in such as way that Docker will // Formats the resources available to a server instance in such as way that Docker will
// generate a matching environment in the container. // generate a matching environment in the container.
//
// This will set the actual memory limit on the container using the multiplier which is the
// hard limit for the container (after which will result in a crash). We then set the
// reservation to be the expected memory limit based on simply multiplication.
//
// The swap value is either -1 to disable it, or set to the value of the hard memory limit
// plus the additional swap assigned to the server since Docker expects this value to be
// the same or higher than the memory limit.
func (d *DockerEnvironment) getResourcesForServer() container.Resources { func (d *DockerEnvironment) getResourcesForServer() container.Resources {
overhead := 1.05
// Set the hard limit for memory usage to be 5% more than the amount of memory assigned to
// the server. If the memory limit for the server is < 4G, use 10%, if less than 2G use
// 15%. This avoids unexpected crashes from processes like Java which run over the limit.
if d.Server.Build.MemoryLimit <= 2048 {
overhead = 1.15
} else if d.Server.Build.MemoryLimit <= 4096 {
overhead = 1.10;
}
return container.Resources{ return container.Resources{
Memory: d.Server.Build.BoundedMemoryLimit(), Memory: int64(math.Round(float64(d.Server.Build.MemoryLimit) * 1000000.0 * overhead)),
MemoryReservation: d.Server.Build.MemoryLimit * 1_000_000, MemoryReservation: d.Server.Build.MemoryLimit * 1000000,
MemorySwap: d.Server.Build.ConvertedSwap(), MemorySwap: d.Server.Build.ConvertedSwap(),
CPUQuota: d.Server.Build.ConvertedCpuLimit(), CPUQuota: d.Server.Build.ConvertedCpuLimit(),
CPUPeriod: 100_000, CPUPeriod: 100000,
CPUShares: 1024, CPUShares: 1024,
BlkioWeight: d.Server.Build.IoWeight, BlkioWeight: d.Server.Build.IoWeight,
OomKillDisable: &d.Server.Container.OomDisabled, OomKillDisable: &d.Server.Container.OomDisabled,

View File

@@ -401,12 +401,13 @@ func (fs *Filesystem) Copy(p string) error {
return errors.WithStack(err) return errors.WithStack(err)
} }
if s, err := os.Stat(cleaned); err != nil { if s, err := os.Stat(cleaned); (err != nil && os.IsNotExist(err)) || s.IsDir() || !s.Mode().IsRegular() {
return err // For now I think I am okay just returning a nil response if the thing
} else if s.IsDir() || !s.Mode().IsRegular() { // we're trying to copy doesn't exist. Probably will want to come back and
// If this is a directory or not a regular file, just throw a not-exist error // re-evaluate if this is a smart decision (I'm guessing not).
// since anything calling this function should understand what that means. return nil
return os.ErrNotExist } else if err != nil {
return errors.WithStack(err)
} }
base := filepath.Base(cleaned) base := filepath.Base(cleaned)

View File

@@ -104,18 +104,6 @@ func NewInstallationProcess(s *Server, script *api.InstallationScript) (*Install
return proc, nil return proc, nil
} }
// Removes the installer container for the server.
func (ip *InstallationProcess) RemoveContainer() {
err := ip.client.ContainerRemove(context.Background(), ip.Server.Uuid + "_installer", types.ContainerRemoveOptions{
RemoveVolumes: true,
Force: true,
})
if err != nil && !client.IsErrNotFound(err) {
zap.S().Warnw("failed to delete server installer container", zap.String("server", ip.Server.Uuid), zap.Error(errors.WithStack(err)))
}
}
// Runs the installation process, this is done as a backgrounded thread. This will configure // Runs the installation process, this is done as a backgrounded thread. This will configure
// the required environment, and then spin up the installation container. // the required environment, and then spin up the installation container.
// //
@@ -129,8 +117,6 @@ func (ip *InstallationProcess) Run() error {
cid, err := ip.Execute(installPath) cid, err := ip.Execute(installPath)
if err != nil { if err != nil {
ip.RemoveContainer()
return err return err
} }
@@ -263,7 +249,6 @@ func (ip *InstallationProcess) GetLogPath() string {
// installation container. // installation container.
func (ip *InstallationProcess) AfterExecute(containerId string) error { func (ip *InstallationProcess) AfterExecute(containerId string) error {
ctx := context.Background() ctx := context.Background()
defer ip.RemoveContainer()
zap.S().Debugw("pulling installation logs for server", zap.String("server", ip.Server.Uuid), zap.String("container_id", containerId)) zap.S().Debugw("pulling installation logs for server", zap.String("server", ip.Server.Uuid), zap.String("container_id", containerId))
reader, err := ip.client.ContainerLogs(ctx, containerId, types.ContainerLogsOptions{ reader, err := ip.client.ContainerLogs(ctx, containerId, types.ContainerLogsOptions{
@@ -288,6 +273,17 @@ func (ip *InstallationProcess) AfterExecute(containerId string) error {
return errors.WithStack(err) return errors.WithStack(err)
} }
zap.S().Debugw("removing server installation container", zap.String("server", ip.Server.Uuid), zap.String("container_id", containerId))
rErr := ip.client.ContainerRemove(ctx, containerId, types.ContainerRemoveOptions{
RemoveVolumes: true,
RemoveLinks: false,
Force: true,
})
if rErr != nil && !client.IsErrNotFound(rErr) {
return errors.WithStack(rErr)
}
return nil return nil
} }
@@ -335,7 +331,7 @@ func (ip *InstallationProcess) Execute(installPath string) (string, error) {
Tmpfs: map[string]string{ Tmpfs: map[string]string{
"/tmp": "rw,exec,nosuid,size=50M", "/tmp": "rw,exec,nosuid,size=50M",
}, },
DNS: config.Get().Docker.Network.Dns, DNS: []string{"1.1.1.1", "8.8.8.8"},
LogConfig: container.LogConfig{ LogConfig: container.LogConfig{
Type: "local", Type: "local",
Config: map[string]string{ Config: map[string]string{
@@ -345,7 +341,7 @@ func (ip *InstallationProcess) Execute(installPath string) (string, error) {
}, },
}, },
Privileged: true, Privileged: true,
NetworkMode: container.NetworkMode(config.Get().Docker.Network.Mode), NetworkMode: "pterodactyl_nw",
} }
zap.S().Infow("creating installer container for server process", zap.String("server", ip.Server.Uuid)) zap.S().Infow("creating installer container for server process", zap.String("server", ip.Server.Uuid))

View File

@@ -9,10 +9,7 @@ import (
// should obviously expect memory and CPU usage to be 0. However, disk will always be returned // should obviously expect memory and CPU usage to be 0. However, disk will always be returned
// since that is not dependent on the server being running to collect that data. // since that is not dependent on the server being running to collect that data.
type ResourceUsage struct { type ResourceUsage struct {
// The total amount of memory, in bytes, that this server instance is consuming. This is // The total amount of memory, in bytes, that this server instance is consuming.
// calculated slightly differently than just using the raw Memory field that the stats
// return from the container, so please check the code setting this value for how that
// is calculated.
Memory uint64 `json:"memory_bytes"` Memory uint64 `json:"memory_bytes"`
// The total amount of memory this container or resource can use. Inside Docker this is // The total amount of memory this container or resource can use. Inside Docker this is
// going to be higher than you'd expect because we're automatically allocating overhead // going to be higher than you'd expect because we're automatically allocating overhead
@@ -31,27 +28,6 @@ type ResourceUsage struct {
} `json:"network"` } `json:"network"`
} }
// The "docker stats" CLI call does not return the same value as the types.MemoryStats.Usage
// value which can be rather confusing to people trying to compare panel usage to
// their stats output.
//
// This math is straight up lifted from their CLI repository in order to show the same
// values to avoid people bothering me about it. It should also reflect a slightly more
// correct memory value anyways.
//
// @see https://github.com/docker/cli/blob/96e1d1d6/cli/command/container/stats_helpers.go#L227-L249
func (ru *ResourceUsage) CalculateDockerMemory(stats types.MemoryStats) uint64 {
if v, ok := stats.Stats["total_inactive_file"]; ok && v < stats.Usage {
return stats.Usage - v
}
if v := stats.Stats["inactive_file"]; v < stats.Usage {
return stats.Usage - v
}
return stats.Usage
}
// Calculates the absolute CPU usage used by the server process on the system, not constrained // Calculates the absolute CPU usage used by the server process on the system, not constrained
// by the defined CPU limits on the container. // by the defined CPU limits on the container.
// //
@@ -75,4 +51,4 @@ func (ru *ResourceUsage) CalculateAbsoluteCpu(pStats *types.CPUStats, stats *typ
} }
return math.Round(percent*1000) / 1000 return math.Round(percent*1000) / 1000
} }

View File

@@ -9,7 +9,6 @@ import (
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/remeh/sizedwaitgroup" "github.com/remeh/sizedwaitgroup"
"go.uber.org/zap" "go.uber.org/zap"
"math"
"os" "os"
"strings" "strings"
"sync" "sync"
@@ -113,23 +112,6 @@ func (b *BuildSettings) ConvertedCpuLimit() int64 {
return b.CpuLimit * 1000 return b.CpuLimit * 1000
} }
// Set the hard limit for memory usage to be 5% more than the amount of memory assigned to
// the server. If the memory limit for the server is < 4G, use 10%, if less than 2G use
// 15%. This avoids unexpected crashes from processes like Java which run over the limit.
func (b *BuildSettings) MemoryOverheadMultiplier() float64 {
if b.MemoryLimit <= 2048 {
return 1.15
} else if b.MemoryLimit <= 4096 {
return 1.10
}
return 1.05
}
func (b *BuildSettings) BoundedMemoryLimit() int64 {
return int64(math.Round(float64(b.MemoryLimit) * b.MemoryOverheadMultiplier() * 1_000_000))
}
// Returns the amount of swap available as a total in bytes. This is returned as the amount // Returns the amount of swap available as a total in bytes. This is returned as the amount
// of memory available to the server initially, PLUS the amount of additional swap to include // of memory available to the server initially, PLUS the amount of additional swap to include
// which is the format used by Docker. // which is the format used by Docker.
@@ -138,7 +120,7 @@ func (b *BuildSettings) ConvertedSwap() int64 {
return -1 return -1
} }
return (b.Swap * 1_000_000) + b.BoundedMemoryLimit() return (b.Swap * 1000000) + (b.MemoryLimit * 1000000)
} }
// Defines the allocations available for a given server. When using the Docker environment // Defines the allocations available for a given server. When using the Docker environment

View File

@@ -7,6 +7,7 @@ import (
"github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"go.uber.org/zap" "go.uber.org/zap"
"path"
) )
func Initialize(config *config.Configuration) error { func Initialize(config *config.Configuration) error {
@@ -20,6 +21,8 @@ func Initialize(config *config.Configuration) error {
ReadOnly: config.System.Sftp.ReadOnly, ReadOnly: config.System.Sftp.ReadOnly,
BindAddress: config.System.Sftp.Address, BindAddress: config.System.Sftp.Address,
BindPort: config.System.Sftp.Port, BindPort: config.System.Sftp.Port,
ServerDataFolder: path.Join(config.System.Data, "/servers"),
DisableDiskCheck: config.System.Sftp.DisableDiskChecking,
}, },
CredentialValidator: validateCredentials, CredentialValidator: validateCredentials,
PathValidator: validatePath, PathValidator: validatePath,
@@ -73,7 +76,6 @@ func validateDiskSpace(fs sftp_server.FileSystem) bool {
// the server's UUID if the credentials were valid. // the server's UUID if the credentials were valid.
func validateCredentials(c sftp_server.AuthenticationRequest) (*sftp_server.AuthenticationResponse, error) { func validateCredentials(c sftp_server.AuthenticationRequest) (*sftp_server.AuthenticationResponse, error) {
resp, err := api.NewRequester().ValidateSftpCredentials(c) resp, err := api.NewRequester().ValidateSftpCredentials(c)
zap.S().Named("sftp").Debugw("validating credentials for SFTP connection", zap.String("username", c.User))
if err != nil { if err != nil {
return resp, err return resp, err
} }
@@ -83,9 +85,8 @@ func validateCredentials(c sftp_server.AuthenticationRequest) (*sftp_server.Auth
}) })
if s == nil { if s == nil {
return resp, errors.New("no matching server with UUID found") return resp, errors.New("no server found with that UUID")
} }
zap.S().Named("sftp").Debugw("matched user to server instance, credentials successfully validated", zap.String("username", c.User), zap.String("server", s.Uuid))
return resp, err return resp, err
} }

View File

@@ -2,5 +2,5 @@ package system
const ( const (
// The current version of this software. // The current version of this software.
Version = "1.0.0-beta.5" Version = "1.0.0-beta.3"
) )