replace servers.servers singleton with server.Manager
This commit is contained in:
parent
94f4207d60
commit
8192244fec
24
cmd/root.go
24
cmd/root.go
|
@ -2,6 +2,7 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
log2 "log"
|
log2 "log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -9,8 +10,8 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"emperror.dev/errors"
|
|
||||||
"github.com/NYTimes/logrotate"
|
"github.com/NYTimes/logrotate"
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/apex/log/handlers/multi"
|
"github.com/apex/log/handlers/multi"
|
||||||
|
@ -21,6 +22,7 @@ import (
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
"github.com/pterodactyl/wings/environment"
|
"github.com/pterodactyl/wings/environment"
|
||||||
"github.com/pterodactyl/wings/loggers/cli"
|
"github.com/pterodactyl/wings/loggers/cli"
|
||||||
|
"github.com/pterodactyl/wings/panelapi"
|
||||||
"github.com/pterodactyl/wings/router"
|
"github.com/pterodactyl/wings/router"
|
||||||
"github.com/pterodactyl/wings/server"
|
"github.com/pterodactyl/wings/server"
|
||||||
"github.com/pterodactyl/wings/sftp"
|
"github.com/pterodactyl/wings/sftp"
|
||||||
|
@ -188,7 +190,17 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
||||||
}).Info("configured system user successfully")
|
}).Info("configured system user successfully")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := server.LoadDirectory(); err != nil {
|
panelClient := panelapi.CreateClient(
|
||||||
|
config.Get().PanelLocation,
|
||||||
|
config.Get().AuthenticationTokenId,
|
||||||
|
config.Get().AuthenticationToken,
|
||||||
|
panelapi.WithTimeout(time.Second*time.Duration(config.Get().RemoteQuery.Timeout)),
|
||||||
|
)
|
||||||
|
_ = panelClient
|
||||||
|
|
||||||
|
serverManager := server.NewManager(panelClient)
|
||||||
|
|
||||||
|
if err := serverManager.Initialize(int(c.RemoteQuery.BootServersPerPage)); err != nil {
|
||||||
log.WithField("error", err).Fatal("failed to load server configurations")
|
log.WithField("error", err).Fatal("failed to load server configurations")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -203,7 +215,7 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just for some nice log output.
|
// Just for some nice log output.
|
||||||
for _, s := range server.GetServers().All() {
|
for _, s := range serverManager.GetAll() {
|
||||||
log.WithField("server", s.Id()).Info("loaded configuration for server")
|
log.WithField("server", s.Id()).Info("loaded configuration for server")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +229,7 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
||||||
// and reboot processes without causing a slow-down due to sequential booting.
|
// and reboot processes without causing a slow-down due to sequential booting.
|
||||||
pool := workerpool.New(4)
|
pool := workerpool.New(4)
|
||||||
|
|
||||||
for _, serv := range server.GetServers().All() {
|
for _, serv := range serverManager.GetAll() {
|
||||||
s := serv
|
s := serv
|
||||||
|
|
||||||
pool.Submit(func() {
|
pool.Submit(func() {
|
||||||
|
@ -302,7 +314,7 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
||||||
}).Info("configuring internal webserver")
|
}).Info("configuring internal webserver")
|
||||||
|
|
||||||
// Configure the router.
|
// Configure the router.
|
||||||
r := router.Configure()
|
r := router.Configure(serverManager)
|
||||||
|
|
||||||
s := &http.Server{
|
s := &http.Server{
|
||||||
Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port),
|
Addr: fmt.Sprintf("%s:%d", c.Api.Host, c.Api.Port),
|
||||||
|
@ -372,7 +384,7 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
||||||
|
|
||||||
// Cancel the context on all of the running servers at this point, even though the
|
// Cancel the context on all of the running servers at this point, even though the
|
||||||
// program is just shutting down.
|
// program is just shutting down.
|
||||||
for _, s := range server.GetServers().All() {
|
for _, s := range serverManager.GetAll() {
|
||||||
s.CtxCancel()
|
s.CtxCancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,9 @@ import (
|
||||||
"github.com/pterodactyl/wings/server"
|
"github.com/pterodactyl/wings/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Middleware struct{}
|
type Middleware struct {
|
||||||
|
serverManager server.Manager
|
||||||
|
}
|
||||||
|
|
||||||
// A custom handler function allowing for errors bubbled up by c.Error() to be returned in a
|
// A custom handler function allowing for errors bubbled up by c.Error() to be returned in a
|
||||||
// standardized format with tracking UUIDs on them for easier log searching.
|
// standardized format with tracking UUIDs on them for easier log searching.
|
||||||
|
@ -92,14 +94,19 @@ func (m *Middleware) RequireAuthorization() gin.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to fetch a server out of the servers collection stored in memory.
|
func (m *Middleware) WithServerManager() gin.HandlerFunc {
|
||||||
//
|
return func(c *gin.Context) {
|
||||||
// This function should not be used in new controllers, prefer ExtractServer where
|
c.Set("servermanager", m.serverManager)
|
||||||
// possible.
|
}
|
||||||
func GetServer(uuid string) *server.Server {
|
}
|
||||||
return server.GetServers().Find(func(s *server.Server) bool {
|
|
||||||
return uuid == s.Id()
|
func ServerManagerFromContext(c *gin.Context) server.Manager {
|
||||||
})
|
if s, ok := c.Get("servermanager"); ok {
|
||||||
|
if srvs, ok := s.(server.Manager); ok {
|
||||||
|
return srvs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the requested server exists in this setup. Returns a 404 if we cannot
|
// Ensure that the requested server exists in this setup. Returns a 404 if we cannot
|
||||||
|
@ -108,7 +115,7 @@ func (m *Middleware) ServerExists() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
u, err := uuid.Parse(c.Param("server"))
|
u, err := uuid.Parse(c.Param("server"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if s := GetServer(u.String()); s != nil {
|
if s := m.serverManager.Get(u.String()); s != nil {
|
||||||
c.Set("server", s)
|
c.Set("server", s)
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
|
|
|
@ -3,15 +3,18 @@ package router
|
||||||
import (
|
import (
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/pterodactyl/wings/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configures the routing infrastructure for this daemon instance.
|
// Configures the routing infrastructure for this daemon instance.
|
||||||
func Configure() *gin.Engine {
|
func Configure(serverManager server.Manager) *gin.Engine {
|
||||||
gin.SetMode("release")
|
gin.SetMode("release")
|
||||||
|
|
||||||
m := Middleware{}
|
m := Middleware{
|
||||||
|
serverManager,
|
||||||
|
}
|
||||||
router := gin.New()
|
router := gin.New()
|
||||||
router.Use(gin.Recovery(), m.ErrorHandler(), m.SetAccessControlHeaders())
|
router.Use(gin.Recovery(), m.ErrorHandler(), m.SetAccessControlHeaders(), m.WithServerManager())
|
||||||
// @todo log this into a different file so you can setup IP blocking for abusive requests and such.
|
// @todo log this into a different file so you can setup IP blocking for abusive requests and such.
|
||||||
// This should still dump requests in debug mode since it does help with understanding the request
|
// This should still dump requests in debug mode since it does help with understanding the request
|
||||||
// lifecycle and quickly seeing what was called leading to the logs. However, it isn't feasible to mix
|
// lifecycle and quickly seeing what was called leading to the logs. However, it isn't feasible to mix
|
||||||
|
|
|
@ -14,13 +14,15 @@ import (
|
||||||
|
|
||||||
// Handle a download request for a server backup.
|
// Handle a download request for a server backup.
|
||||||
func getDownloadBackup(c *gin.Context) {
|
func getDownloadBackup(c *gin.Context) {
|
||||||
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
|
||||||
token := tokens.BackupPayload{}
|
token := tokens.BackupPayload{}
|
||||||
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
||||||
NewTrackedError(err).Abort(c)
|
NewTrackedError(err).Abort(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s := GetServer(token.ServerUuid)
|
s := serverManager.Get(token.ServerUuid)
|
||||||
if s == nil || !token.IsUniqueRequest() {
|
if s == nil || !token.IsUniqueRequest() {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
||||||
"error": "The requested resource was not found on this server.",
|
"error": "The requested resource was not found on this server.",
|
||||||
|
@ -57,13 +59,15 @@ func getDownloadBackup(c *gin.Context) {
|
||||||
|
|
||||||
// Handles downloading a specific file for a server.
|
// Handles downloading a specific file for a server.
|
||||||
func getDownloadFile(c *gin.Context) {
|
func getDownloadFile(c *gin.Context) {
|
||||||
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
|
||||||
token := tokens.FilePayload{}
|
token := tokens.FilePayload{}
|
||||||
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
||||||
NewTrackedError(err).Abort(c)
|
NewTrackedError(err).Abort(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s := GetServer(token.ServerUuid)
|
s := serverManager.Get(token.ServerUuid)
|
||||||
if s == nil || !token.IsUniqueRequest() {
|
if s == nil || !token.IsUniqueRequest() {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
||||||
"error": "The requested resource was not found on this server.",
|
"error": "The requested resource was not found on this server.",
|
||||||
|
|
|
@ -22,7 +22,7 @@ type serverProcData struct {
|
||||||
|
|
||||||
// Returns a single server from the collection of servers.
|
// Returns a single server from the collection of servers.
|
||||||
func getServer(c *gin.Context) {
|
func getServer(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
c.JSON(http.StatusOK, serverProcData{
|
c.JSON(http.StatusOK, serverProcData{
|
||||||
ResourceUsage: s.Proc(),
|
ResourceUsage: s.Proc(),
|
||||||
|
@ -32,7 +32,7 @@ func getServer(c *gin.Context) {
|
||||||
|
|
||||||
// Returns the logs for a given server instance.
|
// Returns the logs for a given server instance.
|
||||||
func getServerLogs(c *gin.Context) {
|
func getServerLogs(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
l, _ := strconv.Atoi(c.DefaultQuery("size", "100"))
|
l, _ := strconv.Atoi(c.DefaultQuery("size", "100"))
|
||||||
if l <= 0 {
|
if l <= 0 {
|
||||||
|
@ -59,7 +59,7 @@ func getServerLogs(c *gin.Context) {
|
||||||
// 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 postServerPower(c *gin.Context) {
|
func postServerPower(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Action server.PowerAction `json:"action"`
|
Action server.PowerAction `json:"action"`
|
||||||
|
@ -109,7 +109,7 @@ func postServerPower(c *gin.Context) {
|
||||||
|
|
||||||
// Sends an array of commands to a running server instance.
|
// Sends an array of commands to a running server instance.
|
||||||
func postServerCommands(c *gin.Context) {
|
func postServerCommands(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
if running, err := s.Environment.IsRunning(); err != nil {
|
if running, err := s.Environment.IsRunning(); err != nil {
|
||||||
NewServerError(err, s).Abort(c)
|
NewServerError(err, s).Abort(c)
|
||||||
|
@ -140,7 +140,7 @@ func postServerCommands(c *gin.Context) {
|
||||||
|
|
||||||
// Updates information about a server internally.
|
// Updates information about a server internally.
|
||||||
func patchServer(c *gin.Context) {
|
func patchServer(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
buf.ReadFrom(c.Request.Body)
|
buf.ReadFrom(c.Request.Body)
|
||||||
|
@ -157,7 +157,7 @@ func patchServer(c *gin.Context) {
|
||||||
|
|
||||||
// Performs a server installation in a background thread.
|
// Performs a server installation in a background thread.
|
||||||
func postServerInstall(c *gin.Context) {
|
func postServerInstall(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
go func(serv *server.Server) {
|
go func(serv *server.Server) {
|
||||||
if err := serv.Install(true); err != nil {
|
if err := serv.Install(true); err != nil {
|
||||||
|
@ -170,7 +170,7 @@ func postServerInstall(c *gin.Context) {
|
||||||
|
|
||||||
// Reinstalls a server.
|
// Reinstalls a server.
|
||||||
func postServerReinstall(c *gin.Context) {
|
func postServerReinstall(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
if s.ExecutingPowerAction() {
|
if s.ExecutingPowerAction() {
|
||||||
c.AbortWithStatusJSON(http.StatusConflict, gin.H{
|
c.AbortWithStatusJSON(http.StatusConflict, gin.H{
|
||||||
|
@ -191,6 +191,7 @@ func postServerReinstall(c *gin.Context) {
|
||||||
// Deletes a server from the wings daemon and dissociate it's objects.
|
// Deletes a server from the wings daemon and dissociate it's objects.
|
||||||
func deleteServer(c *gin.Context) {
|
func deleteServer(c *gin.Context) {
|
||||||
s := ExtractServer(c)
|
s := ExtractServer(c)
|
||||||
|
sm := ServerManagerFromContext(c)
|
||||||
|
|
||||||
// Immediately suspend the server to prevent a user from attempting
|
// Immediately suspend the server to prevent a user from attempting
|
||||||
// to start it while this process is running.
|
// to start it while this process is running.
|
||||||
|
@ -234,10 +235,7 @@ func deleteServer(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}(s.Filesystem().Path())
|
}(s.Filesystem().Path())
|
||||||
|
|
||||||
uuid := s.Id()
|
sm.Remove(s)
|
||||||
server.GetServers().Remove(func(s2 *server.Server) bool {
|
|
||||||
return s2.Id() == uuid
|
|
||||||
})
|
|
||||||
|
|
||||||
// Deallocate the reference to this server.
|
// Deallocate the reference to this server.
|
||||||
s = nil
|
s = nil
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
// Backs up a server.
|
// Backs up a server.
|
||||||
func postServerBackup(c *gin.Context) {
|
func postServerBackup(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
data := &backup.Request{}
|
data := &backup.Request{}
|
||||||
// BindJSON sends 400 if the request fails, all we need to do is return
|
// BindJSON sends 400 if the request fails, all we need to do is return
|
||||||
|
@ -57,7 +57,7 @@ func postServerBackup(c *gin.Context) {
|
||||||
// a 404 error. The service calling this endpoint can make its own decisions as to how it wants
|
// a 404 error. The service calling this endpoint can make its own decisions as to how it wants
|
||||||
// to handle that response.
|
// to handle that response.
|
||||||
func deleteServerBackup(c *gin.Context) {
|
func deleteServerBackup(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
b, _, err := backup.LocateLocal(c.Param("backup"))
|
b, _, err := backup.LocateLocal(c.Param("backup"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -76,7 +76,7 @@ type renameFile struct {
|
||||||
|
|
||||||
// Renames (or moves) files for a server.
|
// Renames (or moves) files for a server.
|
||||||
func putServerRenameFiles(c *gin.Context) {
|
func putServerRenameFiles(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Root string `json:"root"`
|
Root string `json:"root"`
|
||||||
|
@ -138,7 +138,7 @@ func putServerRenameFiles(c *gin.Context) {
|
||||||
|
|
||||||
// Copies a server file.
|
// Copies a server file.
|
||||||
func postServerCopyFile(c *gin.Context) {
|
func postServerCopyFile(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Location string `json:"location"`
|
Location string `json:"location"`
|
||||||
|
@ -158,7 +158,7 @@ func postServerCopyFile(c *gin.Context) {
|
||||||
|
|
||||||
// Deletes files from a server.
|
// Deletes files from a server.
|
||||||
func postServerDeleteFiles(c *gin.Context) {
|
func postServerDeleteFiles(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Root string `json:"root"`
|
Root string `json:"root"`
|
||||||
|
@ -203,7 +203,7 @@ func postServerDeleteFiles(c *gin.Context) {
|
||||||
|
|
||||||
// Writes the contents of the request to a file on a server.
|
// Writes the contents of the request to a file on a server.
|
||||||
func postServerWriteFile(c *gin.Context) {
|
func postServerWriteFile(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
f := c.Query("file")
|
f := c.Query("file")
|
||||||
f = "/" + strings.TrimLeft(f, "/")
|
f = "/" + strings.TrimLeft(f, "/")
|
||||||
|
@ -300,7 +300,7 @@ func deleteServerPullRemoteFile(c *gin.Context) {
|
||||||
|
|
||||||
// Create a directory on a server.
|
// Create a directory on a server.
|
||||||
func postServerCreateDirectory(c *gin.Context) {
|
func postServerCreateDirectory(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -327,7 +327,7 @@ func postServerCreateDirectory(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func postServerCompressFiles(c *gin.Context) {
|
func postServerCompressFiles(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
RootPath string `json:"root"`
|
RootPath string `json:"root"`
|
||||||
|
@ -365,7 +365,7 @@ func postServerCompressFiles(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func postServerDecompressFiles(c *gin.Context) {
|
func postServerDecompressFiles(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
RootPath string `json:"root"`
|
RootPath string `json:"root"`
|
||||||
|
@ -433,7 +433,7 @@ type chmodFile struct {
|
||||||
var errInvalidFileMode = errors.New("invalid file mode")
|
var errInvalidFileMode = errors.New("invalid file mode")
|
||||||
|
|
||||||
func postServerChmodFile(c *gin.Context) {
|
func postServerChmodFile(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
s := ExtractServer(c)
|
||||||
|
|
||||||
var data struct {
|
var data struct {
|
||||||
Root string `json:"root"`
|
Root string `json:"root"`
|
||||||
|
@ -497,13 +497,15 @@ func postServerChmodFile(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func postServerUploadFiles(c *gin.Context) {
|
func postServerUploadFiles(c *gin.Context) {
|
||||||
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
|
||||||
token := tokens.UploadPayload{}
|
token := tokens.UploadPayload{}
|
||||||
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
if err := tokens.ParseToken([]byte(c.Query("token")), &token); err != nil {
|
||||||
NewTrackedError(err).Abort(c)
|
NewTrackedError(err).Abort(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s := GetServer(token.ServerUuid)
|
s := serverManager.Get(token.ServerUuid)
|
||||||
if s == nil || !token.IsUniqueRequest() {
|
if s == nil || !token.IsUniqueRequest() {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{
|
||||||
"error": "The requested resource was not found on this server.",
|
"error": "The requested resource was not found on this server.",
|
||||||
|
|
|
@ -12,7 +12,8 @@ import (
|
||||||
|
|
||||||
// Upgrades a connection to a websocket and passes events along between.
|
// Upgrades a connection to a websocket and passes events along between.
|
||||||
func getServerWebsocket(c *gin.Context) {
|
func getServerWebsocket(c *gin.Context) {
|
||||||
s := GetServer(c.Param("server"))
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
s := serverManager.Get(c.Param("server"))
|
||||||
handler, err := websocket.GetHandler(s, c.Writer, c.Request)
|
handler, err := websocket.GetHandler(s, c.Writer, c.Request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
NewServerError(err, s).Abort(c)
|
NewServerError(err, s).Abort(c)
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
"github.com/pterodactyl/wings/installer"
|
"github.com/pterodactyl/wings/installer"
|
||||||
"github.com/pterodactyl/wings/server"
|
|
||||||
"github.com/pterodactyl/wings/system"
|
"github.com/pterodactyl/wings/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -28,7 +27,8 @@ func getSystemInformation(c *gin.Context) {
|
||||||
// Returns all of the servers that are registered and configured correctly on
|
// Returns all of the servers that are registered and configured correctly on
|
||||||
// this wings instance.
|
// this wings instance.
|
||||||
func getAllServers(c *gin.Context) {
|
func getAllServers(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, server.GetServers().All())
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
c.JSON(http.StatusOK, serverManager.GetAll())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new server on the wings daemon and begins the installation process
|
// Creates a new server on the wings daemon and begins the installation process
|
||||||
|
@ -52,7 +52,8 @@ func postCreateServer(c *gin.Context) {
|
||||||
|
|
||||||
// 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.
|
||||||
server.GetServers().Add(install.Server())
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
serverManager.Add(install.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
|
||||||
|
|
|
@ -323,19 +323,19 @@ func postTransfer(c *gin.Context) {
|
||||||
i.Server().Events().Publish(server.TransferLogsEvent, output)
|
i.Server().Events().Publish(server.TransferLogsEvent, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverManager := ServerManagerFromContext(c)
|
||||||
|
|
||||||
// Mark the server as transferring to prevent problems later on during the process and
|
// Mark the server as transferring to prevent problems later on during the process and
|
||||||
// then push the server into the global server collection for this instance.
|
// then push the server into the global server collection for this instance.
|
||||||
i.Server().SetTransferring(true)
|
i.Server().SetTransferring(true)
|
||||||
server.GetServers().Add(i.Server())
|
serverManager.Add(i.Server())
|
||||||
defer func(s *server.Server) {
|
defer func(s *server.Server) {
|
||||||
// In the event that this transfer call fails, remove the server from the global
|
// In the event that this transfer call fails, remove the server from the global
|
||||||
// server tracking so that we don't have a dangling instance.
|
// server tracking so that we don't have a dangling instance.
|
||||||
if err := data.sendTransferStatus(!hasError); hasError || err != nil {
|
if err := data.sendTransferStatus(!hasError); hasError || err != nil {
|
||||||
sendTransferLog("Server transfer failed, check Wings logs for additional information.")
|
sendTransferLog("Server transfer failed, check Wings logs for additional information.")
|
||||||
s.Events().Publish(server.TransferStatusEvent, "failure")
|
s.Events().Publish(server.TransferStatusEvent, "failure")
|
||||||
server.GetServers().Remove(func(s2 *server.Server) bool {
|
serverManager.Remove(s)
|
||||||
return s.Id() == s2.Id()
|
|
||||||
})
|
|
||||||
|
|
||||||
// If the transfer status was successful but the request failed, act like the transfer failed.
|
// If the transfer status was successful but the request failed, act like the transfer failed.
|
||||||
if !hasError && err != nil {
|
if !hasError && err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -15,26 +16,21 @@ import (
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
"github.com/pterodactyl/wings/environment"
|
"github.com/pterodactyl/wings/environment"
|
||||||
"github.com/pterodactyl/wings/environment/docker"
|
"github.com/pterodactyl/wings/environment/docker"
|
||||||
|
"github.com/pterodactyl/wings/panelapi"
|
||||||
"github.com/pterodactyl/wings/server/filesystem"
|
"github.com/pterodactyl/wings/server/filesystem"
|
||||||
)
|
)
|
||||||
|
|
||||||
var servers = NewCollection(nil)
|
|
||||||
|
|
||||||
func GetServers() *Collection {
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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() error {
|
func (m *manager) Initialize(serversPerPage int) error {
|
||||||
if len(servers.items) != 0 {
|
if len(m.servers.items) != 0 {
|
||||||
return errors.New("cannot call LoadDirectory with a non-nil collection")
|
return errors.New("cannot call LoadDirectory with a non-nil collection")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("fetching list of servers from API")
|
log.Info("fetching list of servers from API")
|
||||||
configs, err := api.New().GetServers()
|
assignedServers, err := m.panelClient.GetServers(context.TODO(), serversPerPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !api.IsRequestError(err) {
|
if !panelapi.IsRequestError(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,13 +38,11 @@ func LoadDirectory() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
log.WithField("total_configs", len(configs)).Info("processing servers returned by the API")
|
log.WithField("total_configs", len(assignedServers)).Info("processing servers returned by the API")
|
||||||
|
|
||||||
pool := workerpool.New(runtime.NumCPU())
|
pool := workerpool.New(runtime.NumCPU())
|
||||||
log.Debugf("using %d workerpools to instantiate server instances", runtime.NumCPU())
|
log.Debugf("using %d workerpools to instantiate server instances", runtime.NumCPU())
|
||||||
for _, data := range configs {
|
for _, data := range assignedServers {
|
||||||
data := data
|
|
||||||
|
|
||||||
pool.Submit(func() {
|
pool.Submit(func() {
|
||||||
// Parse the json.RawMessage into an expected struct value. We do this here so that a single broken
|
// Parse the json.RawMessage into an expected struct value. We do this here so that a single broken
|
||||||
// server does not cause the entire boot process to hang, and allows us to show more useful error
|
// server does not cause the entire boot process to hang, and allows us to show more useful error
|
||||||
|
@ -69,7 +63,7 @@ func LoadDirectory() error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
servers.Add(s)
|
m.Add(s)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
server/manager.go
Normal file
46
server/manager.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pterodactyl/wings/panelapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Manager interface {
|
||||||
|
// Initialize fetches all servers assigned to this node from the API.
|
||||||
|
Initialize(serversPerPage int) error
|
||||||
|
GetAll() []*Server
|
||||||
|
Get(uuid string) *Server
|
||||||
|
Add(s *Server)
|
||||||
|
Remove(s *Server)
|
||||||
|
}
|
||||||
|
|
||||||
|
type manager struct {
|
||||||
|
servers Collection
|
||||||
|
|
||||||
|
panelClient panelapi.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewManager creates a new server manager.
|
||||||
|
func NewManager(panelClient panelapi.Client) Manager {
|
||||||
|
return &manager{panelClient: panelClient}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *manager) GetAll() []*Server {
|
||||||
|
return m.servers.items
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *manager) Get(uuid string) *Server {
|
||||||
|
return m.servers.Find(func(s *Server) bool {
|
||||||
|
return s.Id() == uuid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *manager) Add(s *Server) {
|
||||||
|
s.manager = m
|
||||||
|
m.servers.Add(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *manager) Remove(s *Server) {
|
||||||
|
m.servers.Remove(func(sf *Server) bool {
|
||||||
|
return sf.Id() == s.Id()
|
||||||
|
})
|
||||||
|
}
|
|
@ -27,6 +27,9 @@ type Server struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel *context.CancelFunc
|
ctxCancel *context.CancelFunc
|
||||||
|
|
||||||
|
// manager holds a reference to the manager responsible for the server
|
||||||
|
manager *manager
|
||||||
|
|
||||||
emitterLock sync.Mutex
|
emitterLock sync.Mutex
|
||||||
powerLock *semaphore.Weighted
|
powerLock *semaphore.Weighted
|
||||||
throttleOnce sync.Once
|
throttleOnce sync.Once
|
||||||
|
|
|
@ -36,10 +36,10 @@ func CachedServerStates() (map[string]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveServerStates .
|
// saveServerStates .
|
||||||
func saveServerStates() error {
|
func (m *manager) saveServerStates() error {
|
||||||
// Get the states of all servers on the daemon.
|
// Get the states of all servers on the daemon.
|
||||||
states := map[string]string{}
|
states := map[string]string{}
|
||||||
for _, s := range GetServers().All() {
|
for _, s := range m.GetAll() {
|
||||||
states[s.Id()] = s.Environment.State()
|
states[s.Id()] = s.Environment.State()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ func (s *Server) OnStateChange() {
|
||||||
// We also get the benefit of server status changes always propagating corrected configurations
|
// We also get the benefit of server status changes always propagating corrected configurations
|
||||||
// to the disk should we forget to do it elsewhere.
|
// to the disk should we forget to do it elsewhere.
|
||||||
go func() {
|
go func() {
|
||||||
if err := saveServerStates(); err != nil {
|
if err := s.manager.saveServerStates(); err != nil {
|
||||||
s.Log().WithField("error", err).Warn("failed to write server states to disk")
|
s.Log().WithField("error", err).Warn("failed to write server states to disk")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -12,12 +12,12 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/patrickmn/go-cache"
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/pkg/sftp"
|
"github.com/pkg/sftp"
|
||||||
"github.com/pterodactyl/wings/api"
|
"github.com/pterodactyl/wings/api"
|
||||||
|
"github.com/pterodactyl/wings/server"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,6 +39,8 @@ type Server struct {
|
||||||
Settings Settings
|
Settings Settings
|
||||||
User User
|
User User
|
||||||
|
|
||||||
|
serverManager server.Manager
|
||||||
|
|
||||||
PathValidator func(fs FileSystem, p string) (string, error)
|
PathValidator func(fs FileSystem, p string) (string, error)
|
||||||
DiskSpaceValidator func(fs FileSystem) bool
|
DiskSpaceValidator func(fs FileSystem) bool
|
||||||
|
|
||||||
|
@ -48,13 +50,6 @@ type Server struct {
|
||||||
CredentialValidator func(r api.SftpAuthRequest) (*api.SftpAuthResponse, error)
|
CredentialValidator func(r api.SftpAuthRequest) (*api.SftpAuthResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new server configuration instance.
|
|
||||||
func New(c *Server) error {
|
|
||||||
c.cache = cache.New(5*time.Minute, 10*time.Minute)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the SFTP server and add a persistent listener to handle inbound SFTP connections.
|
// Initialize the SFTP server and add a persistent listener to handle inbound SFTP connections.
|
||||||
func (c *Server) Initialize() error {
|
func (c *Server) Initialize() error {
|
||||||
serverConfig := &ssh.ServerConfig{
|
serverConfig := &ssh.ServerConfig{
|
||||||
|
|
50
sftp/sftp.go
50
sftp/sftp.go
|
@ -1,11 +1,13 @@
|
||||||
package sftp
|
package sftp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"emperror.dev/errors"
|
"emperror.dev/errors"
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
"github.com/pterodactyl/wings/api"
|
"github.com/pterodactyl/wings/api"
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
"github.com/pterodactyl/wings/server"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var noMatchingServerError = errors.New("no matching server with that UUID was found")
|
var noMatchingServerError = errors.New("no matching server with that UUID was found")
|
||||||
|
@ -22,14 +24,11 @@ func Initialize(config config.SystemConfiguration) error {
|
||||||
BindAddress: config.Sftp.Address,
|
BindAddress: config.Sftp.Address,
|
||||||
BindPort: config.Sftp.Port,
|
BindPort: config.Sftp.Port,
|
||||||
},
|
},
|
||||||
CredentialValidator: validateCredentials,
|
cache: cache.New(5*time.Minute, 10*time.Minute),
|
||||||
PathValidator: validatePath,
|
|
||||||
DiskSpaceValidator: validateDiskSpace,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := New(s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
s.CredentialValidator = s.validateCredentials
|
||||||
|
s.PathValidator = s.validatePath
|
||||||
|
s.DiskSpaceValidator = s.validateDiskSpace
|
||||||
|
|
||||||
// Initialize the SFTP server in a background thread since this is
|
// Initialize the SFTP server in a background thread since this is
|
||||||
// a long running operation.
|
// a long running operation.
|
||||||
|
@ -42,33 +41,25 @@ func Initialize(config config.SystemConfiguration) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePath(fs FileSystem, p string) (string, error) {
|
func (s *Server) validatePath(fs FileSystem, p string) (string, error) {
|
||||||
s := server.GetServers().Find(func(server *server.Server) bool {
|
srv := s.serverManager.Get(fs.UUID)
|
||||||
return server.Id() == fs.UUID
|
if srv == nil {
|
||||||
})
|
|
||||||
|
|
||||||
if s == nil {
|
|
||||||
return "", noMatchingServerError
|
return "", noMatchingServerError
|
||||||
}
|
}
|
||||||
|
return srv.Filesystem().SafePath(p)
|
||||||
return s.Filesystem().SafePath(p)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateDiskSpace(fs FileSystem) bool {
|
func (s *Server) validateDiskSpace(fs FileSystem) bool {
|
||||||
s := server.GetServers().Find(func(server *server.Server) bool {
|
srv := s.serverManager.Get(fs.UUID)
|
||||||
return server.Id() == fs.UUID
|
if srv == nil {
|
||||||
})
|
|
||||||
|
|
||||||
if s == nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
return srv.Filesystem().HasSpaceAvailable(true)
|
||||||
return s.Filesystem().HasSpaceAvailable(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validates a set of credentials for a SFTP login against Pterodactyl Panel and returns
|
// Validates a set of credentials for a SFTP login against 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 api.SftpAuthRequest) (*api.SftpAuthResponse, error) {
|
func (s *Server) validateCredentials(c api.SftpAuthRequest) (*api.SftpAuthResponse, error) {
|
||||||
f := log.Fields{"subsystem": "sftp", "username": c.User, "ip": c.IP}
|
f := log.Fields{"subsystem": "sftp", "username": c.User, "ip": c.IP}
|
||||||
|
|
||||||
log.WithFields(f).Debug("validating credentials for SFTP connection")
|
log.WithFields(f).Debug("validating credentials for SFTP connection")
|
||||||
|
@ -83,15 +74,12 @@ func validateCredentials(c api.SftpAuthRequest) (*api.SftpAuthResponse, error) {
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s := server.GetServers().Find(func(server *server.Server) bool {
|
srv := s.serverManager.Get(resp.Server)
|
||||||
return server.Id() == resp.Server
|
if srv == nil {
|
||||||
})
|
|
||||||
|
|
||||||
if s == nil {
|
|
||||||
return resp, noMatchingServerError
|
return resp, noMatchingServerError
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Log().WithFields(f).Debug("credentials successfully validated and matched user to server instance")
|
srv.Log().WithFields(f).Debug("credentials successfully validated and matched user to server instance")
|
||||||
|
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user