Move server tracking in program into global memory state

This commit is contained in:
Dane Everitt 2019-12-07 16:43:00 -08:00
parent e2c04cc6f5
commit c9bff0fa31
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
6 changed files with 83 additions and 38 deletions

46
http.go
View File

@ -18,22 +18,14 @@ import (
"strings" "strings"
) )
type ServerCollection []*server.Server
// Retrieves a server out of the collection by UUID. // Retrieves a server out of the collection by UUID.
func (sc *ServerCollection) Get(uuid string) *server.Server { func (rt *Router) GetServer(uuid string) *server.Server {
for _, s := range *sc { return server.GetServers().Find(func(i *server.Server) bool {
if s.Uuid == uuid { return i.Uuid == uuid
return s })
}
}
return nil
} }
type Router struct { type Router struct {
Servers ServerCollection
upgrader websocket.Upgrader upgrader websocket.Upgrader
// The authentication token defined in the config.yml file that allows // The authentication token defined in the config.yml file that allows
@ -49,7 +41,7 @@ func (rt *Router) AuthenticateRequest(h httprouter.Handle) httprouter.Handle {
// is in a state that allows it to be exposed to the API. // is in a state that allows it to be exposed to the API.
func (rt *Router) AuthenticateServer(h httprouter.Handle) httprouter.Handle { func (rt *Router) AuthenticateServer(h httprouter.Handle) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
if rt.Servers.Get(ps.ByName("server")) != nil { if rt.GetServer(ps.ByName("server")) != nil {
h(w, r, ps) h(w, r, ps)
return return
} }
@ -98,12 +90,12 @@ func (rt *Router) routeIndex(w http.ResponseWriter, _ *http.Request, _ httproute
// requests that include an administrative control key, otherwise a 404 is returned. This // requests that include an administrative control key, otherwise a 404 is returned. This
// authentication is handled by a middleware. // authentication is handled by a middleware.
func (rt *Router) routeAllServers(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { func (rt *Router) routeAllServers(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) {
json.NewEncoder(w).Encode(rt.Servers) json.NewEncoder(w).Encode(server.GetServers().All())
} }
// Returns basic information about a single server found on the Daemon. // Returns basic information about a single server found on the Daemon.
func (rt *Router) routeServer(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) { func (rt *Router) routeServer(w http.ResponseWriter, _ *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
json.NewEncoder(w).Encode(s) json.NewEncoder(w).Encode(s)
} }
@ -130,7 +122,7 @@ func (pr *PowerActionRequest) IsValid() bool {
// things are happening, so theres no reason to sit and wait for a request to finish. We'll // things are happening, so theres no reason to sit and wait for a request to finish. We'll
// just see over the socket if something isn't working correctly. // just see over the socket if something isn't working correctly.
func (rt *Router) routeServerPower(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerPower(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
dec := json.NewDecoder(r.Body) dec := json.NewDecoder(r.Body)
@ -206,7 +198,7 @@ func (rt *Router) routeServerPower(w http.ResponseWriter, r *http.Request, ps ht
// Return the last 1Kb of the server log file. // Return the last 1Kb of the server log file.
func (rt *Router) routeServerLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerLogs(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
l, _ := strconv.ParseInt(r.URL.Query().Get("size"), 10, 64) l, _ := strconv.ParseInt(r.URL.Query().Get("size"), 10, 64)
if l <= 0 { if l <= 0 {
@ -225,7 +217,7 @@ func (rt *Router) routeServerLogs(w http.ResponseWriter, r *http.Request, ps htt
// Handle a request to get the contents of a file on the server. // Handle a request to get the contents of a file on the server.
func (rt *Router) routeServerFileRead(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerFileRead(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
cleaned, err := s.Filesystem.SafePath(r.URL.Query().Get("file")) cleaned, err := s.Filesystem.SafePath(r.URL.Query().Get("file"))
if err != nil { if err != nil {
@ -272,7 +264,7 @@ func (rt *Router) routeServerFileRead(w http.ResponseWriter, r *http.Request, ps
// Lists the contents of a directory. // Lists the contents of a directory.
func (rt *Router) routeServerListDirectory(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerListDirectory(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
stats, err := s.Filesystem.ListDirectory(r.URL.Query().Get("directory")) stats, err := s.Filesystem.ListDirectory(r.URL.Query().Get("directory"))
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -290,7 +282,7 @@ func (rt *Router) routeServerListDirectory(w http.ResponseWriter, r *http.Reques
// Writes a file to the system for the server. // Writes a file to the system for the server.
func (rt *Router) routeServerWriteFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerWriteFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
p := r.URL.Query().Get("file") p := r.URL.Query().Get("file")
defer r.Body.Close() defer r.Body.Close()
@ -308,7 +300,7 @@ func (rt *Router) routeServerWriteFile(w http.ResponseWriter, r *http.Request, p
// Creates a new directory for the server. // Creates a new directory for the server.
func (rt *Router) routeServerCreateDirectory(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerCreateDirectory(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
dec := json.NewDecoder(r.Body) dec := json.NewDecoder(r.Body)
@ -336,7 +328,7 @@ func (rt *Router) routeServerCreateDirectory(w http.ResponseWriter, r *http.Requ
} }
func (rt *Router) routeServerRenameFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerRenameFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
data := rt.ReaderToBytes(r.Body) data := rt.ReaderToBytes(r.Body)
@ -359,7 +351,7 @@ func (rt *Router) routeServerRenameFile(w http.ResponseWriter, r *http.Request,
} }
func (rt *Router) routeServerCopyFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerCopyFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
data := rt.ReaderToBytes(r.Body) data := rt.ReaderToBytes(r.Body)
@ -376,7 +368,7 @@ func (rt *Router) routeServerCopyFile(w http.ResponseWriter, r *http.Request, ps
} }
func (rt *Router) routeServerDeleteFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerDeleteFile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
data := rt.ReaderToBytes(r.Body) data := rt.ReaderToBytes(r.Body)
@ -393,7 +385,7 @@ func (rt *Router) routeServerDeleteFile(w http.ResponseWriter, r *http.Request,
} }
func (rt *Router) routeServerSendCommand(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerSendCommand(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
if running, err := s.Environment.IsRunning(); !running || err != nil { if running, err := s.Environment.IsRunning(); !running || err != nil {
@ -419,7 +411,7 @@ func (rt *Router) routeServerSendCommand(w http.ResponseWriter, r *http.Request,
} }
func (rt *Router) routeServerUpdate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { func (rt *Router) routeServerUpdate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
defer r.Body.Close() defer r.Body.Close()
data := rt.ReaderToBytes(r.Body) data := rt.ReaderToBytes(r.Body)
@ -447,7 +439,7 @@ func (rt *Router) routeCreateServer(w http.ResponseWriter, r *http.Request, ps h
// Plop that server instance onto the request so that it can be referenced in // Plop that server instance onto the request so that it can be referenced in
// requests from here-on out. // requests from here-on out.
rt.Servers = append(rt.Servers, inst.Server()) server.GetServers().Add(inst.Server())
// Begin the installation process in the background to not block the request // Begin the installation process in the background to not block the request
// cycle. If there are any errors they will be logged and communicated back // cycle. If there are any errors they will be logged and communicated back

39
server/collection.go Normal file
View File

@ -0,0 +1,39 @@
package server
type Collection struct {
items []*Server
}
// Return all of the items in the collection.
func (c *Collection) All() []*Server {
return c.items
}
// Adds an item to the collection store.
func (c *Collection) Add(s *Server) {
c.items = append(c.items, s)
}
// Returns only those items matching the filter criteria.
func (c *Collection) Filter(filter func (*Server) bool) []*Server {
r := make([]*Server, 0)
for _, v := range c.items {
if filter(v) {
r = append(r, v)
}
}
return r
}
// Returns a single element from the collection matching the filter. If nothing is
// found a nil result is returned.
func (c *Collection) Find(filter func (*Server) bool) *Server {
for _, v := range c.items {
if filter(v) {
return v
}
}
return nil
}

View File

@ -18,6 +18,12 @@ import (
"time" "time"
) )
var servers *Collection
func GetServers() *Collection {
return servers
}
// High level definition for a server instance being controlled by Wings. // High level definition for a server instance being controlled by Wings.
type Server struct { type Server struct {
// The unique identifier for the server that should be used when referencing // The unique identifier for the server that should be used when referencing
@ -136,7 +142,7 @@ type Allocations struct {
// Iterates over a given directory and loads all of the servers listed before returning // Iterates over a given directory and loads all of the servers listed before returning
// them to the calling function. // them to the calling function.
func LoadDirectory(dir string, cfg *config.SystemConfiguration) ([]*Server, error) { func LoadDirectory(dir string, cfg *config.SystemConfiguration) error {
// We could theoretically use a standard wait group here, however doing // We could theoretically use a standard wait group here, however doing
// that introduces the potential to crash the program due to too many // that introduces the potential to crash the program due to too many
// open files. This wouldn't happen on a small setup, but once the daemon is // open files. This wouldn't happen on a small setup, but once the daemon is
@ -149,10 +155,10 @@ func LoadDirectory(dir string, cfg *config.SystemConfiguration) ([]*Server, erro
f, err := ioutil.ReadDir(dir) f, err := ioutil.ReadDir(dir)
if err != nil { if err != nil {
return nil, err return err
} }
var servers []*Server servers = new(Collection)
for _, file := range f { for _, file := range f {
if !strings.HasSuffix(file.Name(), ".yml") || file.IsDir() { if !strings.HasSuffix(file.Name(), ".yml") || file.IsDir() {
@ -177,7 +183,7 @@ func LoadDirectory(dir string, cfg *config.SystemConfiguration) ([]*Server, erro
return return
} }
servers = append(servers, s) servers.Add(s)
}(file) }(file)
} }
@ -185,7 +191,7 @@ func LoadDirectory(dir string, cfg *config.SystemConfiguration) ([]*Server, erro
// before continuing. // before continuing.
wg.Wait() wg.Wait()
return servers, nil return nil
} }
// Initializes the default required internal struct components for a Server. // Initializes the default required internal struct components for a Server.

View File

@ -24,6 +24,8 @@ func Initialize(config *config.Configuration) error {
DisableDiskCheck: config.System.Sftp.DisableDiskChecking, DisableDiskCheck: config.System.Sftp.DisableDiskChecking,
}, },
CredentialValidator: validateCredentials, CredentialValidator: validateCredentials,
PathValidator: validatePath,
DiskSpaceValidator: validateDiskSpace,
} }
if err := sftp_server.New(c); err != nil { if err := sftp_server.New(c); err != nil {
@ -45,6 +47,14 @@ func Initialize(config *config.Configuration) error {
return nil return nil
} }
func validatePath(fs sftp_server.FileSystem, p string) (string, error) {
return p, nil
}
func validateDiskSpace(fs sftp_server.FileSystem) bool {
return true
}
// Validates a set of credentials for a SFTP login aganist Pterodactyl Panel and returns // Validates a set of credentials for a SFTP login aganist Pterodactyl Panel and returns
// 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) {

View File

@ -164,7 +164,7 @@ func (rt *Router) routeWebsocket(w http.ResponseWriter, r *http.Request, ps http
c.Close() c.Close()
}() }()
s := rt.Servers.Get(ps.ByName("server")) s := rt.GetServer(ps.ByName("server"))
handler := WebsocketHandler{ handler := WebsocketHandler{
Server: s, Server: s,
Mutex: sync.Mutex{}, Mutex: sync.Mutex{},

View File

@ -65,14 +65,13 @@ func main() {
zap.S().Infow("finished ensuring file permissions") zap.S().Infow("finished ensuring file permissions")
} }
servers, err := server.LoadDirectory("data/servers", c.System) if err := server.LoadDirectory("data/servers", c.System); err != nil {
if 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
} }
// Just for some nice log output. // Just for some nice log output.
for _, s := range servers { for _, s := range server.GetServers().All() {
zap.S().Infow("loaded configuration for server", zap.String("server", s.Uuid)) zap.S().Infow("loaded configuration for server", zap.String("server", s.Uuid))
} }
@ -81,7 +80,7 @@ func main() {
// and reboot processes without causing a slow-down due to sequential booting. // and reboot processes without causing a slow-down due to sequential booting.
wg := sizedwaitgroup.New(4) wg := sizedwaitgroup.New(4)
for _, serv := range servers { for _, serv := range server.GetServers().All() {
wg.Add() wg.Add()
go func(s *server.Server) { go func(s *server.Server) {
@ -144,7 +143,6 @@ func main() {
} }
r := &Router{ r := &Router{
Servers: servers,
token: c.AuthenticationToken, token: c.AuthenticationToken,
upgrader: websocket.Upgrader{ upgrader: websocket.Upgrader{
// Ensure that the websocket request is originating from the Panel itself, // Ensure that the websocket request is originating from the Panel itself,