diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php
index 546f9b8f7..62a8d5dc4 100644
--- a/app/Exceptions/Handler.php
+++ b/app/Exceptions/Handler.php
@@ -4,7 +4,9 @@ namespace Pterodactyl\Exceptions;
use Exception;
use DisplayException;
-use Debugbar;
+use DisplayValidationException;
+use AccountNotFoundException;
+
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
diff --git a/app/Http/Controllers/Admin/ServersController.php b/app/Http/Controllers/Admin/ServersController.php
index c307f0f3d..299721abb 100644
--- a/app/Http/Controllers/Admin/ServersController.php
+++ b/app/Http/Controllers/Admin/ServersController.php
@@ -2,15 +2,14 @@
namespace Pterodactyl\Http\Controllers\Admin;
+use Alert;
use Debugbar;
+
+use Pterodactyl\Models;
use Pterodactyl\Repositories\ServerRepository;
-use Pterodactyl\Models\Server;
-use Pterodactyl\Models\Node;
-use Pterodactyl\Models\Location;
-use Pterodactyl\Models\Allocation;
-use Pterodactyl\Models\Service;
-use Pterodactyl\Models\ServiceOptions;
-use Pterodactyl\Models\ServiceVariables;
+
+use Pterodactly\Exceptions\DisplayException;
+use Pterodactly\Exceptions\DisplayValidationException;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Http\Request;
@@ -33,7 +32,7 @@ class ServersController extends Controller
public function getIndex(Request $request)
{
return view('admin.servers.index', [
- 'servers' => Server::select('servers.*', 'nodes.name as a_nodeName', 'users.email as a_ownerEmail')
+ 'servers' => Models\Server::select('servers.*', 'nodes.name as a_nodeName', 'users.email as a_ownerEmail')
->join('nodes', 'servers.node', '=', 'nodes.id')
->join('users', 'servers.owner', '=', 'users.id')
->paginate(20),
@@ -43,8 +42,8 @@ class ServersController extends Controller
public function getNew(Request $request)
{
return view('admin.servers.new', [
- 'locations' => Location::all(),
- 'services' => Service::all()
+ 'locations' => Models\Location::all(),
+ 'services' => Models\Service::all()
]);
}
@@ -57,14 +56,26 @@ class ServersController extends Controller
{
try {
- $server = new ServerRepository;
- $resp = $server->create($request->all());
- echo $resp . '
';
- } catch (\Exception $e) {
- Debugbar::addException($e);
- }
- return json_encode($request->all());
+ $server = new ServerRepository;
+ $response = $server->create($request->all());
+
+ return redirect()->route('admin.servers.view', [ 'id' => $response ]);
+
+ } catch (\Exception $e) {
+
+ if ($e instanceof \Pterodactyl\Exceptions\DisplayValidationException) {
+ return redirect()->route('admin.servers.new')->withErrors(json_decode($e->getMessage()))->withInput();
+ } else if ($e instanceof \Pterodactyl\Exceptions\DisplayException) {
+ Alert::danger($e->getMessage())->flash();
+ } else {
+ Debugbar::addException($e);
+ Alert::danger('An unhandled exception occured while attemping to add this server. Please try again.')->flash();
+ }
+
+ return redirect()->route('admin.servers.new')->withInput();
+
+ }
}
@@ -83,7 +94,7 @@ class ServersController extends Controller
], 500);
}
- return response()->json(Node::select('id', 'name', 'public')->where('location', $request->input('location'))->get());
+ return response()->json(Models\Node::select('id', 'name', 'public')->where('location', $request->input('location'))->get());
}
@@ -102,7 +113,7 @@ class ServersController extends Controller
], 500);
}
- $ips = Allocation::where('node', $request->input('node'))->whereNull('assigned_to')->get();
+ $ips = Models\Allocation::where('node', $request->input('node'))->whereNull('assigned_to')->get();
$listing = [];
foreach($ips as &$ip) {
@@ -131,7 +142,7 @@ class ServersController extends Controller
], 500);
}
- return response()->json(ServiceOptions::select('id', 'name', 'docker_image')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get());
+ return response()->json(Models\ServiceOptions::select('id', 'name', 'docker_image')->where('parent_service', $request->input('service'))->orderBy('name', 'asc')->get());
}
@@ -150,7 +161,7 @@ class ServersController extends Controller
], 500);
}
- return response()->json(ServiceVariables::where('option_id', $request->input('option'))->get());
+ return response()->json(Models\ServiceVariables::where('option_id', $request->input('option'))->get());
}
diff --git a/app/Models/Server.php b/app/Models/Server.php
index 2fa7bb735..838564010 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -24,6 +24,13 @@ class Server extends Model
*/
protected $hidden = ['daemonSecret'];
+ /**
+ * Fields that are not mass assignable.
+ *
+ * @var array
+ */
+ protected $guarded = ['id', 'installed', 'created_at', 'updated_at'];
+
/**
* @var array
*/
diff --git a/app/Models/ServerVariables.php b/app/Models/ServerVariables.php
index 611d57931..23e0d1b11 100644
--- a/app/Models/ServerVariables.php
+++ b/app/Models/ServerVariables.php
@@ -14,4 +14,11 @@ class ServerVariables extends Model
*/
protected $table = 'server_variables';
+ /**
+ * Fields that are not mass assignable.
+ *
+ * @var array
+ */
+ protected $guarded = ['id', 'created_at', 'updated_at'];
+
}
diff --git a/app/Repositories/ServerRepository.php b/app/Repositories/ServerRepository.php
index d0a00f793..131a8ac5e 100644
--- a/app/Repositories/ServerRepository.php
+++ b/app/Repositories/ServerRepository.php
@@ -3,6 +3,7 @@
namespace Pterodactyl\Repositories;
use DB;
+use Debugbar;
use Validator;
use Pterodactyl\Models;
@@ -64,7 +65,7 @@ class ServerRepository
// Run validator, throw catchable and displayable exception if it fails.
// Exception includes a JSON result of failed validation rules.
if ($validator->fails()) {
- throw new DisplayValidationException(json_encode($validator->errors()->all()));
+ throw new DisplayValidationException($validator->errors());
}
// Get the User ID; user exists since we passed the 'exists:users,email' part of the validation
@@ -91,6 +92,7 @@ class ServerRepository
// Check those Variables
$variables = Models\ServiceVariables::where('option_id', $data['option'])->get();
+ $variableList = [];
if ($variables) {
foreach($variables as $variable) {
@@ -100,7 +102,11 @@ class ServerRepository
throw new DisplayException('A required service option variable field (env_' . $variable->env_variable . ') was missing from the request.');
}
- $data['env_' . $variable->env_variable] = $variable->default_value;
+ $variableList = array_merge($variableList, [[
+ 'var_id' => $variable->id,
+ 'var_val' => $variable->default_value
+ ]]);
+
continue;
}
@@ -109,13 +115,91 @@ class ServerRepository
throw new DisplayException('Failed to validate service option variable field (env_' . $variable->env_variable . ') aganist regex (' . $variable->regex . ').');
}
- continue;
+ $variableList = array_merge($variableList, [[
+ 'var_id' => $variable->id,
+ 'var_val' => $data['env_' . $variable->env_variable]
+ ]]);
+ continue;
}
}
- return (new UuidService)->generateShort();
- //return $this->generateSFTPUsername($data['name']);
+ // Check Overallocation
+ if (is_numeric($node->memory_overallocate) || is_numeric($node->disk_overallocate)) {
+
+ $totals = Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node', $node->id)->first();
+
+ // Check memory limits
+ if (is_numeric($node->memory_overallocate)) {
+ $newMemory = $totals->memory + $data['memory'];
+ $memoryLimit = ($node->memory * (1 + ($node->memory_overallocate / 100)));
+ if($newMemory > $memoryLimit) {
+ throw new DisplayException('The amount of memory allocated to this server would put the node over its allocation limits. This node is allowed ' . ($node->memory_overallocate + 100) . '% of its assigned ' . $node->memory . 'Mb of memory (' . $memoryLimit . 'Mb) of which ' . (($totals->memory / $node->memory) * 100) . '% (' . $totals->memory . 'Mb) is in use already. By allocating this server the node would be at ' . (($newMemory / $node->memory) * 100) . '% (' . $newMemory . 'Mb) usage.');
+ }
+ }
+
+ // Check Disk Limits
+ if (is_numeric($node->disk_overallocate)) {
+ $newDisk = $totals->disk + $data['disk'];
+ $diskLimit = ($node->disk * (1 + ($node->disk_overallocate / 100)));
+ if($newDisk > $diskLimit) {
+ throw new DisplayException('The amount of disk allocated to this server would put the node over its allocation limits. This node is allowed ' . ($node->disk_overallocate + 100) . '% of its assigned ' . $node->disk . 'Mb of disk (' . $diskLimit . 'Mb) of which ' . (($totals->disk / $node->disk) * 100) . '% (' . $totals->disk . 'Mb) is in use already. By allocating this server the node would be at ' . (($newDisk / $node->disk) * 100) . '% (' . $newDisk . 'Mb) usage.');
+ }
+ }
+
+ }
+
+ DB::beginTransaction();
+
+ $uuid = new UuidService;
+
+ // Add Server to the Database
+ $server = new Models\Server;
+ $server->fill([
+ 'uuid' => $uuid->generate('servers', 'uuid'),
+ 'uuidShort' => $uuid->generateShort(),
+ 'node' => $data['node'],
+ 'name' => $data['name'],
+ 'active' => 1,
+ 'owner' => $user->id,
+ 'memory' => $data['memory'],
+ 'disk' => $data['disk'],
+ 'io' => $data['io'],
+ 'cpu' => $data['cpu'],
+ 'ip' => $data['ip'],
+ 'port' => $data['port'],
+ 'service' => $data['service'],
+ 'option' => $data['option'],
+ 'daemonSecret' => $uuid->generate('servers', 'daemonSecret'),
+ 'username' => $this->generateSFTPUsername($data['name'])
+ ]);
+ $server->save();
+
+ // Mark Allocation in Use
+ $allocation->assigned_to = $server->id;
+ $allocation->save();
+
+ // Add Variables
+ foreach($variableList as $item) {
+ Models\ServerVariables::create([
+ 'server_id' => $server->id,
+ 'variable_id' => $item['var_id'],
+ 'variable_value' => $item['var_val']
+ ]);
+ }
+
+ try {
+
+ // Add logic for communicating with Wings to make the server in here.
+ // We should add the server regardless of the Wings response, but
+ // handle the error and then allow the server to be re-deployed.
+
+ DB::commit();
+ return $server->id;
+ } catch (\Exception $e) {
+ DB::rollBack();
+ throw $e;
+ }
}
diff --git a/app/Repositories/UserRepository.php b/app/Repositories/UserRepository.php
index bd3d48ce9..cf60b7b9a 100644
--- a/app/Repositories/UserRepository.php
+++ b/app/Repositories/UserRepository.php
@@ -17,7 +17,7 @@ class UserRepository
/**
* Creates a user on the panel. Returns the created user's ID.
- *
+ *
* @param string $username
* @param string $email
* @param string $password An unhashed version of the user's password.
@@ -29,7 +29,7 @@ class UserRepository
$user = new User;
$uuid = new UuidService;
- $user->uuid = $uuid->table('users')->generate();
+ $user->uuid = $uuid->generate('users', 'uuid');
$user->username = $username;
$user->email = $email;
diff --git a/app/Services/UuidService.php b/app/Services/UuidService.php
index e9ecf7f76..9217cd084 100644
--- a/app/Services/UuidService.php
+++ b/app/Services/UuidService.php
@@ -8,16 +8,6 @@ use Uuid;
class UuidService
{
- /**
- * @var string
- */
- protected $table = 'users';
-
- /**
- * @var string
- */
- protected $field = 'uuid';
-
/**
* Constructor
*/
@@ -26,45 +16,23 @@ class UuidService
//
}
- /**
- * Set the table that we need to be checking in the database.
- *
- * @param string $table
- * @return void
- */
- public function table($table)
- {
- $this->table = $table;
- return $this;
- }
-
- /**
- * Set the field in the given table that we want to check for a unique UUID.
- *
- * @param string $field
- * @return void
- */
- public function field($field)
- {
- $this->field = $field;
- return $this;
- }
-
/**
* Generate a unique UUID validating against specified table and column.
* Defaults to `users.uuid`
*
+ * @param string $table
+ * @param string $field
* @param integer $type The type of UUID to generate.
* @return string
*/
- public function generate($type = 4)
+ public function generate($table = 'users', $field = 'uuid', $type = 4)
{
$return = false;
do {
- $uuid = LaravelUUID::generate($type);
- if (!DB::table($this->table)->where($this->field, $uuid)->exists()) {
+ $uuid = Uuid::generate($type);
+ if (!DB::table($table)->where($field, $uuid)->exists()) {
$return = $uuid;
}
@@ -81,13 +49,15 @@ class UuidService
* @param string $field
* @return string
*/
- public function generateShort($table = 'servers', $field = 'uuidShort')
+ public function generateShort($table = 'servers', $field = 'uuidShort', $attachedUuid = null)
{
$return = false;
do {
- $short = substr(Uuid::generate(4), 0, 8);
+ $short = (is_null($attachedUuid)) ? substr(Uuid::generate(4), 0, 8) : substr($attachedUuid, 0, 8);
+ $attachedUuid = null;
+
if (!DB::table($table)->where($field, $short)->exists()) {
$return = $short;
}
diff --git a/database/migrations/2015_12_15_175100_remove_daemon_table.php b/database/migrations/2015_12_15_175100_remove_daemon_table.php
new file mode 100644
index 000000000..b6fb8b20d
--- /dev/null
+++ b/database/migrations/2015_12_15_175100_remove_daemon_table.php
@@ -0,0 +1,36 @@
+increments('id')->unsigned();
+ $table->mediumInteger('server')->unsigned();
+ $table->string('parameter');
+ $table->text('value');
+ $table->tinyInteger('editable')->unsigned()->default(0);
+ $table->tinyInteger('visible')->unsigned()->default(0);
+ $table->text('regex')->nullable();
+ $table->timestamps();
+ });
+ }
+}
diff --git a/resources/lang/en/base.php b/resources/lang/en/base.php
index d92c41fa6..852b6e16b 100644
--- a/resources/lang/en/base.php
+++ b/resources/lang/en/base.php
@@ -12,6 +12,8 @@ return [
|
*/
+ 'validation_error' => 'An error occured while validating the data you submitted:',
+
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
'view_as_admin' => 'You are viewing this server listing as an admin. As such, all servers installed on the system are displayed. Any servers that you are set as the owner of are marked with a blue dot to the left of their name.',
diff --git a/resources/views/admin/servers/new.blade.php b/resources/views/admin/servers/new.blade.php
index 2e48a838d..272f506e0 100644
--- a/resources/views/admin/servers/new.blade.php
+++ b/resources/views/admin/servers/new.blade.php
@@ -11,11 +11,21 @@
Character limits: a-zA-Z0-9_-
and [Space]
(max 35 characters)