Nuke more API code and begin consolidation process
This commit is contained in:
parent
aa287d21cf
commit
6775c17324
|
@ -11,9 +11,9 @@ import (
|
||||||
|
|
||||||
type Client interface {
|
type Client interface {
|
||||||
GetBackupRemoteUploadURLs(ctx context.Context, backup string, size int64) (api.BackupRemoteUploadResponse, error)
|
GetBackupRemoteUploadURLs(ctx context.Context, backup string, size int64) (api.BackupRemoteUploadResponse, error)
|
||||||
GetInstallationScript(ctx context.Context, uuid string) (api.InstallationScript, error)
|
GetInstallationScript(ctx context.Context, uuid string) (InstallationScript, error)
|
||||||
GetServerConfiguration(ctx context.Context, uuid string) (api.ServerConfigurationResponse, error)
|
GetServerConfiguration(ctx context.Context, uuid string) (ServerConfigurationResponse, error)
|
||||||
GetServers(context context.Context, perPage int) ([]api.RawServerData, error)
|
GetServers(context context.Context, perPage int) ([]RawServerData, error)
|
||||||
SetArchiveStatus(ctx context.Context, uuid string, successful bool) error
|
SetArchiveStatus(ctx context.Context, uuid string, successful bool) error
|
||||||
SetBackupStatus(ctx context.Context, backup string, data api.BackupRequest) error
|
SetBackupStatus(ctx context.Context, backup string, data api.BackupRequest) error
|
||||||
SetInstallationStatus(ctx context.Context, uuid string, successful bool) error
|
SetInstallationStatus(ctx context.Context, uuid string, successful bool) error
|
||||||
|
|
|
@ -13,13 +13,6 @@ import (
|
||||||
"github.com/pterodactyl/wings/system"
|
"github.com/pterodactyl/wings/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Response is a custom response type that allows for commonly used error
|
|
||||||
// handling and response parsing from the Panel API. This just embeds the normal
|
|
||||||
// HTTP response from Go and we attach a few helper functions to it.
|
|
||||||
type Response struct {
|
|
||||||
*http.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// A generic type allowing for easy binding use when making requests to API
|
// A generic type allowing for easy binding use when making requests to API
|
||||||
// endpoints that only expect a singular argument or something that would not
|
// endpoints that only expect a singular argument or something that would not
|
||||||
// benefit from being a typed struct.
|
// benefit from being a typed struct.
|
||||||
|
@ -30,6 +23,22 @@ type d map[string]interface{}
|
||||||
// Same concept as d, but a map of strings, used for querying GET requests.
|
// Same concept as d, but a map of strings, used for querying GET requests.
|
||||||
type q map[string]string
|
type q map[string]string
|
||||||
|
|
||||||
|
// Response is a custom response type that allows for commonly used error
|
||||||
|
// handling and response parsing from the Panel API. This just embeds the normal
|
||||||
|
// HTTP response from Go and we attach a few helper functions to it.
|
||||||
|
type Response struct {
|
||||||
|
*http.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pagination struct {
|
||||||
|
CurrentPage uint `json:"current_page"`
|
||||||
|
From uint `json:"from"`
|
||||||
|
LastPage uint `json:"last_page"`
|
||||||
|
PerPage uint `json:"per_page"`
|
||||||
|
To uint `json:"to"`
|
||||||
|
Total uint `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
// requestOnce creates a http request and executes it once. Prefer request()
|
// requestOnce creates a http request and executes it once. Prefer request()
|
||||||
// over this method when possible. It appends the path to the endpoint of the
|
// over this method when possible. It appends the path to the endpoint of the
|
||||||
// client and adds the authentication token to the request.
|
// client and adds the authentication token to the request.
|
||||||
|
|
|
@ -51,7 +51,7 @@ type RawServerData struct {
|
||||||
// GetServers returns all of the servers that are present on the Panel making
|
// GetServers returns all of the servers that are present on the Panel making
|
||||||
// parallel API calls to the endpoint if more than one page of servers is
|
// parallel API calls to the endpoint if more than one page of servers is
|
||||||
// returned.
|
// returned.
|
||||||
func (c *client) GetServers(ctx context.Context, limit int) ([]api.RawServerData, error) {
|
func (c *client) GetServers(ctx context.Context, limit int) ([]RawServerData, error) {
|
||||||
servers, meta, err := c.getServersPaged(ctx, 0, limit)
|
servers, meta, err := c.getServersPaged(ctx, 0, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -81,34 +81,34 @@ func (c *client) GetServers(ctx context.Context, limit int) ([]api.RawServerData
|
||||||
return servers, nil
|
return servers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) GetServerConfiguration(ctx context.Context, uuid string) (api.ServerConfigurationResponse, error) {
|
func (c *client) GetServerConfiguration(ctx context.Context, uuid string) (ServerConfigurationResponse, error) {
|
||||||
|
var config ServerConfigurationResponse
|
||||||
res, err := c.get(ctx, fmt.Sprintf("/servers/%s", uuid), nil)
|
res, err := c.get(ctx, fmt.Sprintf("/servers/%s", uuid), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.ServerConfigurationResponse{}, err
|
return config, err
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if res.HasError() {
|
if res.HasError() {
|
||||||
return api.ServerConfigurationResponse{}, err
|
return config, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := api.ServerConfigurationResponse{}
|
|
||||||
err = res.BindJSON(&config)
|
err = res.BindJSON(&config)
|
||||||
return config, err
|
return config, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) GetInstallationScript(ctx context.Context, uuid string) (api.InstallationScript, error) {
|
func (c *client) GetInstallationScript(ctx context.Context, uuid string) (InstallationScript, error) {
|
||||||
res, err := c.get(ctx, fmt.Sprintf("/servers/%s/install", uuid), nil)
|
res, err := c.get(ctx, fmt.Sprintf("/servers/%s/install", uuid), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return api.InstallationScript{}, err
|
return InstallationScript{}, err
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if res.HasError() {
|
if res.HasError() {
|
||||||
return api.InstallationScript{}, err
|
return InstallationScript{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := api.InstallationScript{}
|
var config InstallationScript
|
||||||
err = res.BindJSON(&config)
|
err = res.BindJSON(&config)
|
||||||
return config, err
|
return config, err
|
||||||
}
|
}
|
||||||
|
@ -146,7 +146,7 @@ func (c *client) SetTransferStatus(ctx context.Context, uuid string, successful
|
||||||
|
|
||||||
// getServersPaged returns a subset of servers from the Panel API using the
|
// getServersPaged returns a subset of servers from the Panel API using the
|
||||||
// pagination query parameters.
|
// pagination query parameters.
|
||||||
func (c *client) getServersPaged(ctx context.Context, page, limit int) ([]api.RawServerData, api.Pagination, error) {
|
func (c *client) getServersPaged(ctx context.Context, page, limit int) ([]RawServerData, api.Pagination, error) {
|
||||||
res, err := c.get(ctx, "/servers", q{
|
res, err := c.get(ctx, "/servers", q{
|
||||||
"page": strconv.Itoa(page),
|
"page": strconv.Itoa(page),
|
||||||
"per_page": strconv.Itoa(limit),
|
"per_page": strconv.Itoa(limit),
|
||||||
|
@ -161,7 +161,7 @@ func (c *client) getServersPaged(ctx context.Context, page, limit int) ([]api.Ra
|
||||||
}
|
}
|
||||||
|
|
||||||
var r struct {
|
var r struct {
|
||||||
Data []api.RawServerData `json:"data"`
|
Data []RawServerData `json:"data"`
|
||||||
Meta api.Pagination `json:"meta"`
|
Meta api.Pagination `json:"meta"`
|
||||||
}
|
}
|
||||||
if err := res.BindJSON(&r); err != nil {
|
if err := res.BindJSON(&r); err != nil {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,13 +15,16 @@ import (
|
||||||
"emperror.dev/errors"
|
"emperror.dev/errors"
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/gammazero/workerpool"
|
"github.com/gammazero/workerpool"
|
||||||
"github.com/pterodactyl/wings/api"
|
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
|
"github.com/pterodactyl/wings/environment"
|
||||||
|
"github.com/pterodactyl/wings/environment/docker"
|
||||||
"github.com/pterodactyl/wings/remote"
|
"github.com/pterodactyl/wings/remote"
|
||||||
|
"github.com/pterodactyl/wings/server/filesystem"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
client remote.Client
|
||||||
servers []*Server
|
servers []*Server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +32,8 @@ type Manager struct {
|
||||||
// the servers that are currently present on the filesystem and set them into
|
// the servers that are currently present on the filesystem and set them into
|
||||||
// the manager.
|
// the manager.
|
||||||
func NewManager(ctx context.Context, client remote.Client) (*Manager, error) {
|
func NewManager(ctx context.Context, client remote.Client) (*Manager, error) {
|
||||||
m := NewEmptyManager()
|
m := NewEmptyManager(client)
|
||||||
if err := m.init(ctx, client); err != nil {
|
if err := m.init(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
|
@ -38,15 +42,15 @@ func NewManager(ctx context.Context, client remote.Client) (*Manager, error) {
|
||||||
// NewEmptyManager returns a new empty manager collection without actually
|
// NewEmptyManager returns a new empty manager collection without actually
|
||||||
// loading any of the servers from the disk. This allows the caller to set their
|
// loading any of the servers from the disk. This allows the caller to set their
|
||||||
// own servers into the collection as needed.
|
// own servers into the collection as needed.
|
||||||
func NewEmptyManager() *Manager {
|
func NewEmptyManager(client remote.Client) *Manager {
|
||||||
return &Manager{}
|
return &Manager{client: client}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeFromRemoteSource iterates over a given directory and loads all of
|
// initializeFromRemoteSource iterates over a given directory and loads all of
|
||||||
// the servers listed before returning them to the calling function.
|
// the servers listed before returning them to the calling function.
|
||||||
func (m *Manager) init(ctx context.Context, client remote.Client) error {
|
func (m *Manager) init(ctx context.Context) error {
|
||||||
log.Info("fetching list of servers from API")
|
log.Info("fetching list of servers from API")
|
||||||
servers, err := client.GetServers(ctx, config.Get().RemoteQuery.BootServersPerPage)
|
servers, err := m.client.GetServers(ctx, config.Get().RemoteQuery.BootServersPerPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !remote.IsRequestError(err) {
|
if !remote.IsRequestError(err) {
|
||||||
return errors.WithStackIf(err)
|
return errors.WithStackIf(err)
|
||||||
|
@ -65,7 +69,7 @@ func (m *Manager) init(ctx context.Context, client remote.Client) error {
|
||||||
// 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
|
||||||
// messaging in the output.
|
// messaging in the output.
|
||||||
d := api.ServerConfigurationResponse{
|
d := remote.ServerConfigurationResponse{
|
||||||
Settings: data.Settings,
|
Settings: data.Settings,
|
||||||
}
|
}
|
||||||
log.WithField("server", data.Uuid).Info("creating new server object from API response")
|
log.WithField("server", data.Uuid).Info("creating new server object from API response")
|
||||||
|
@ -73,7 +77,7 @@ func (m *Manager) init(ctx context.Context, client remote.Client) error {
|
||||||
log.WithField("server", data.Uuid).WithField("error", err).Error("failed to parse server configuration from API response, skipping...")
|
log.WithField("server", data.Uuid).WithField("error", err).Error("failed to parse server configuration from API response, skipping...")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s, err := FromConfiguration(d)
|
s, err := m.InitServer(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithField("server", data.Uuid).WithField("error", err).Error("failed to load server, skipping...")
|
log.WithField("server", data.Uuid).WithField("error", err).Error("failed to load server, skipping...")
|
||||||
return
|
return
|
||||||
|
@ -202,3 +206,53 @@ func (m *Manager) ReadStates() (map[string]string, error) {
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitServer initializes a server using a data byte array. This will be
|
||||||
|
// marshaled into the given struct using a YAML marshaler. This will also
|
||||||
|
// configure the given environment for a server.
|
||||||
|
func (m *Manager) InitServer(data remote.ServerConfigurationResponse) (*Server, error) {
|
||||||
|
s, err := New(m.client)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithMessage(err, "loader: failed to instantiate empty server struct")
|
||||||
|
}
|
||||||
|
if err := s.UpdateDataStructure(data.Settings); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Archiver = Archiver{Server: s}
|
||||||
|
s.fs = filesystem.New(filepath.Join(config.Get().System.Data, s.Id()), s.DiskSpace(), s.Config().Egg.FileDenylist)
|
||||||
|
|
||||||
|
// Right now we only support a Docker based environment, so I'm going to hard code
|
||||||
|
// this logic in. When we're ready to support other environment we'll need to make
|
||||||
|
// some modifications here obviously.
|
||||||
|
settings := environment.Settings{
|
||||||
|
Mounts: s.Mounts(),
|
||||||
|
Allocations: s.cfg.Allocations,
|
||||||
|
Limits: s.cfg.Build,
|
||||||
|
}
|
||||||
|
|
||||||
|
envCfg := environment.NewConfiguration(settings, s.GetEnvironmentVariables())
|
||||||
|
meta := docker.Metadata{
|
||||||
|
Image: s.Config().Container.Image,
|
||||||
|
}
|
||||||
|
|
||||||
|
if env, err := docker.New(s.Id(), &meta, envCfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
s.Environment = env
|
||||||
|
s.StartEventListeners()
|
||||||
|
s.Throttler().StartTimer(s.Context())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forces the configuration to be synced with the panel.
|
||||||
|
if err := s.SyncWithConfiguration(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the server's data directory exists, force disk usage calculation.
|
||||||
|
if _, err := os.Stat(s.Filesystem().Path()); err == nil {
|
||||||
|
s.Filesystem().HasSpaceAvailable(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
@ -16,6 +15,7 @@ import (
|
||||||
"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/events"
|
"github.com/pterodactyl/wings/events"
|
||||||
|
"github.com/pterodactyl/wings/remote"
|
||||||
"github.com/pterodactyl/wings/server/filesystem"
|
"github.com/pterodactyl/wings/server/filesystem"
|
||||||
"github.com/pterodactyl/wings/system"
|
"github.com/pterodactyl/wings/system"
|
||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
|
@ -37,6 +37,7 @@ type Server struct {
|
||||||
// Maintains the configuration for the server. This is the data that gets returned by the Panel
|
// Maintains the configuration for the server. This is the data that gets returned by the Panel
|
||||||
// such as build settings and container images.
|
// such as build settings and container images.
|
||||||
cfg Configuration
|
cfg Configuration
|
||||||
|
client remote.Client
|
||||||
|
|
||||||
// The crash handler for this server instance.
|
// The crash handler for this server instance.
|
||||||
crasher CrashHandler
|
crasher CrashHandler
|
||||||
|
@ -72,11 +73,12 @@ type Server struct {
|
||||||
|
|
||||||
// Returns a new server instance with a context and all of the default values set on
|
// Returns a new server instance with a context and all of the default values set on
|
||||||
// the instance.
|
// the instance.
|
||||||
func New() (*Server, error) {
|
func New(client remote.Client) (*Server, error) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
s := Server{
|
s := Server{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
ctxCancel: &cancel,
|
ctxCancel: &cancel,
|
||||||
|
client: client,
|
||||||
installing: system.NewAtomicBool(false),
|
installing: system.NewAtomicBool(false),
|
||||||
transferring: system.NewAtomicBool(false),
|
transferring: system.NewAtomicBool(false),
|
||||||
}
|
}
|
||||||
|
@ -148,7 +150,7 @@ func (s *Server) Log() *log.Entry {
|
||||||
// This also means mass actions can be performed against servers on the Panel and they
|
// This also means mass actions can be performed against servers on the Panel and they
|
||||||
// will automatically sync with Wings when the server is started.
|
// will automatically sync with Wings when the server is started.
|
||||||
func (s *Server) Sync() error {
|
func (s *Server) Sync() error {
|
||||||
cfg, err := api.New().GetServerConfiguration(s.Id())
|
cfg, err := s.client.GetServerConfiguration(s.Context(), s.Id())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !api.IsRequestError(err) {
|
if !api.IsRequestError(err) {
|
||||||
return err
|
return err
|
||||||
|
@ -164,7 +166,7 @@ func (s *Server) Sync() error {
|
||||||
return s.SyncWithConfiguration(cfg)
|
return s.SyncWithConfiguration(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SyncWithConfiguration(cfg api.ServerConfigurationResponse) error {
|
func (s *Server) SyncWithConfiguration(cfg remote.ServerConfigurationResponse) error {
|
||||||
// Update the data structure and persist it to the disk.
|
// Update the data structure and persist it to the disk.
|
||||||
if err := s.UpdateDataStructure(cfg.Settings); err != nil {
|
if err := s.UpdateDataStructure(cfg.Settings); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -295,61 +297,11 @@ func (s *Server) OnStateChange() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if the server state is running or not. This is different than the
|
// IsRunning determines if the server state is running or not. This is different
|
||||||
// environment state, it is simply the tracked state from this daemon instance, and
|
// than the environment state, it is simply the tracked state from this daemon
|
||||||
// not the response from Docker.
|
// instance, and not the response from Docker.
|
||||||
func (s *Server) IsRunning() bool {
|
func (s *Server) IsRunning() bool {
|
||||||
st := s.Environment.State()
|
st := s.Environment.State()
|
||||||
|
|
||||||
return st == environment.ProcessRunningState || st == environment.ProcessStartingState
|
return st == environment.ProcessRunningState || st == environment.ProcessStartingState
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromConfiguration initializes a server using a data byte array. This will be
|
|
||||||
// marshaled into the given struct using a YAML marshaler. This will also
|
|
||||||
// configure the given environment for a server.
|
|
||||||
func FromConfiguration(data api.ServerConfigurationResponse) (*Server, error) {
|
|
||||||
s, err := New()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithMessage(err, "loader: failed to instantiate empty server struct")
|
|
||||||
}
|
|
||||||
if err := s.UpdateDataStructure(data.Settings); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Archiver = Archiver{Server: s}
|
|
||||||
s.fs = filesystem.New(filepath.Join(config.Get().System.Data, s.Id()), s.DiskSpace(), s.Config().Egg.FileDenylist)
|
|
||||||
|
|
||||||
// Right now we only support a Docker based environment, so I'm going to hard code
|
|
||||||
// this logic in. When we're ready to support other environment we'll need to make
|
|
||||||
// some modifications here obviously.
|
|
||||||
settings := environment.Settings{
|
|
||||||
Mounts: s.Mounts(),
|
|
||||||
Allocations: s.cfg.Allocations,
|
|
||||||
Limits: s.cfg.Build,
|
|
||||||
}
|
|
||||||
|
|
||||||
envCfg := environment.NewConfiguration(settings, s.GetEnvironmentVariables())
|
|
||||||
meta := docker.Metadata{
|
|
||||||
Image: s.Config().Container.Image,
|
|
||||||
}
|
|
||||||
|
|
||||||
if env, err := docker.New(s.Id(), &meta, envCfg); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
s.Environment = env
|
|
||||||
s.StartEventListeners()
|
|
||||||
s.Throttler().StartTimer(s.Context())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forces the configuration to be synced with the panel.
|
|
||||||
if err := s.SyncWithConfiguration(data); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the server's data directory exists, force disk usage calculation.
|
|
||||||
if _, err := os.Stat(s.Filesystem().Path()); err == nil {
|
|
||||||
s.Filesystem().HasSpaceAvailable(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user