Add basic support for creating a server on wings

This commit is contained in:
Dane Everitt 2019-11-16 15:48:50 -08:00
parent 22e6ce2f7e
commit f0da1eeb48
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
4 changed files with 93 additions and 15 deletions

12
http.go
View File

@ -399,9 +399,19 @@ func (rt *Router) routeCreateServer(w http.ResponseWriter, r *http.Request, ps h
if err != nil { if err != nil {
zap.S().Warnw("failed to validate the received data", zap.Error(err)) zap.S().Warnw("failed to validate the received data", zap.Error(err))
http.Error(w, "failed to validate data", http.StatusUnprocessableEntity)
return
} }
inst.Execute() // Plop that server instance onto the request so that it can be referenced in
// requests from here-on out.
rt.Servers = append(rt.Servers, inst.Server())
// 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
// to the Panel where a reinstall may take place.
go inst.Execute()
w.WriteHeader(http.StatusAccepted) w.WriteHeader(http.StatusAccepted)
} }

View File

@ -5,8 +5,11 @@ import (
"errors" "errors"
"github.com/asaskevich/govalidator" "github.com/asaskevich/govalidator"
"github.com/buger/jsonparser" "github.com/buger/jsonparser"
"github.com/pterodactyl/wings/config"
"github.com/pterodactyl/wings/server" "github.com/pterodactyl/wings/server"
"go.uber.org/zap" "go.uber.org/zap"
"gopkg.in/yaml.v2"
"os"
) )
type Installer struct { type Installer struct {
@ -26,17 +29,17 @@ func New(data []byte) (error, *Installer) {
} }
s := &server.Server{ s := &server.Server{
Uuid: getString(data, "uuid"), Uuid: getString(data, "uuid"),
Suspended: false, Suspended: false,
State: server.ProcessOfflineState, State: server.ProcessOfflineState,
Invocation: "", Invocation: "",
EnvVars: make(map[string]string), EnvVars: make(map[string]string),
Build: &server.BuildSettings{ Build: &server.BuildSettings{
MemoryLimit: getInt(data, "build", "memory"), MemoryLimit: getInt(data, "build", "memory"),
Swap: getInt(data, "build", "swap"), Swap: getInt(data, "build", "swap"),
IoWeight: uint16(getInt(data, "build", "io")), IoWeight: uint16(getInt(data, "build", "io")),
CpuLimit: getInt(data, "build", "cpu"), CpuLimit: getInt(data, "build", "cpu"),
DiskSpace: getInt(data, "build", "disk"), DiskSpace: getInt(data, "build", "disk"),
}, },
Allocations: &server.Allocations{ Allocations: &server.Allocations{
Mappings: make(map[string][]int), Mappings: make(map[string][]int),
@ -65,8 +68,20 @@ func New(data []byte) (error, *Installer) {
s.Container.Image = getString(data, "container", "image") s.Container.Image = getString(data, "container", "image")
b, err := WriteConfigurationToDisk(s)
if err != nil {
return err, nil
}
// Destroy the temporary server instance.
s = nil
// Create a new server instance using the configuration we wrote to the disk
// so that everything gets instantiated correctly on the struct.
s2, err := server.FromConfiguration(b, config.Get().System)
return nil, &Installer{ return nil, &Installer{
server: s, server: s2,
} }
} }
@ -75,13 +90,44 @@ func (i *Installer) Uuid() string {
return i.server.Uuid return i.server.Uuid
} }
// Return the server instance.
func (i *Installer) Server() *server.Server {
return i.server
}
// Executes the installer process, creating the server and running through the // Executes the installer process, creating the server and running through the
// associated installation process based on the parameters passed through for // associated installation process based on the parameters passed through for
// the server instance. // the server instance.
func (i *Installer) Execute() error { func (i *Installer) Execute() {
zap.S().Debugw("beginning installation process for server", zap.String("server", i.server.Uuid)) zap.S().Debugw("beginning installation process for server", zap.String("server", i.server.Uuid))
return nil zap.S().Debugw("creating required environment for server instance", zap.String("server", i.server.Uuid))
if err := i.server.Environment.Create(); err != nil {
zap.S().Errorw("failed to create environment for server", zap.String("server", i.server.Uuid), zap.Error(err))
return
}
}
// Writes the server configuration to the disk and return the byte representation
// of the configuration object. This allows us to pass it directly into the
// servers.FromConfiguration() function.
func WriteConfigurationToDisk(s *server.Server) ([]byte, error) {
f, err := os.Create("data/servers/" + s.Uuid + ".yml")
if err != nil {
return nil, err
}
defer f.Close()
b, err := yaml.Marshal(&s)
if err != nil {
return nil, err
}
if _, err := f.Write(b); err != nil {
return nil, err
}
return b, nil
} }
// Returns a string value from the JSON data provided. // Returns a string value from the JSON data provided.

View File

@ -3,6 +3,7 @@ package server
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -14,7 +15,6 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/pterodactyl/wings/api" "github.com/pterodactyl/wings/api"
"go.uber.org/zap" "go.uber.org/zap"
"golang.org/x/net/context"
"io" "io"
"os" "os"
"strconv" "strconv"
@ -385,6 +385,8 @@ func (d *DockerEnvironment) DisableResourcePolling() 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)
@ -394,6 +396,11 @@ func (d *DockerEnvironment) Create() error {
var oomDisabled = true var oomDisabled = true
// Ensure the data directory exists before getting too far through this process.
if err := d.Server.Filesystem.EnsureDataDirectory(); err != nil {
return err
}
// If the container already exists don't hit the user with an error, just return // If the container already exists don't hit the user with an error, just return
// the current information about it which is what we would do when creating the // the current information about it which is what we would do when creating the
// container anyways. // container anyways.

View File

@ -553,3 +553,18 @@ func (fs *Filesystem) ListDirectory(p string) ([]*Stat, error) {
return out, nil return out, nil
} }
// Ensures that the data directory for the server instance exists.
func (fs *Filesystem) EnsureDataDirectory() error {
if _, err := os.Stat(fs.Path()); err != nil && !os.IsNotExist(err) {
return err
} else if err != nil {
// Create the server data directory because it does not currently exist
// on the system.
if err := os.MkdirAll(fs.Path(), 0600); err != nil {
return err
}
}
return nil
}