diff --git a/app/Http/Controllers/Admin/LocationsController.php b/app/Http/Controllers/Admin/LocationsController.php index 9ef004be..93a45fb6 100644 --- a/app/Http/Controllers/Admin/LocationsController.php +++ b/app/Http/Controllers/Admin/LocationsController.php @@ -45,8 +45,8 @@ class LocationsController extends Controller return view('admin.locations.index', [ 'locations' => Models\Location::select( 'locations.*', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') )->paginate(20), ]); } @@ -55,8 +55,8 @@ class LocationsController extends Controller { $model = Models\Location::select( 'locations.id', - DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location = locations.id) as a_nodeCount'), - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location = locations.id)) as a_serverCount') + DB::raw('(SELECT COUNT(*) FROM nodes WHERE nodes.location_id = locations.id) as a_nodeCount'), + DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id IN (SELECT nodes.id FROM nodes WHERE nodes.location_id = locations.id)) as a_serverCount') )->where('id', $id)->first(); if (! $model) { @@ -80,12 +80,12 @@ class LocationsController extends Controller { try { $location = new LocationRepository; - $location->edit($id, $request->all()); + $location->edit($id, $request->only(['long', 'short'])); return response('', 204); } catch (DisplayValidationException $ex) { return response()->json([ - 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 10 characters with no spaces or special characters.', + 'error' => 'There was a validation error while processing this request. Location descriptions must be between 1 and 255 characters, and the location code must be between 1 and 20 characters with no spaces or special characters.', ], 422); } catch (\Exception $ex) { // This gets caught and processed into JSON anyways. @@ -97,9 +97,7 @@ class LocationsController extends Controller { try { $location = new LocationRepository; - $id = $location->create($request->except([ - '_token', - ])); + $id = $location->create($request->only(['long', 'short'])); Alert::success('New location successfully added.')->flash(); return redirect()->route('admin.locations'); diff --git a/app/Http/Controllers/Admin/NodesController.php b/app/Http/Controllers/Admin/NodesController.php index 600ecb93..9cfac1fd 100644 --- a/app/Http/Controllers/Admin/NodesController.php +++ b/app/Http/Controllers/Admin/NodesController.php @@ -48,17 +48,15 @@ class NodesController extends Controller public function getScript(Request $request, $id) { - return response()->view('admin.nodes.remote.deploy', ['node' => Models\Node::findOrFail($id)])->header('Content-Type', 'text/plain'); + return response()->view('admin.nodes.remote.deploy', [ + 'node' => Models\Node::findOrFail($id), + ])->header('Content-Type', 'text/plain'); } public function getIndex(Request $request) { return view('admin.nodes.index', [ - 'nodes' => Models\Node::select( - 'nodes.*', - 'locations.long as a_locationName', - DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node_id = nodes.id) as a_serverCount') - )->join('locations', 'nodes.location', '=', 'locations.id')->paginate(20), + 'nodes' => Models\Node::with('location')->withCount('servers')->paginate(20), ]); } @@ -78,15 +76,25 @@ class NodesController extends Controller public function postNew(Request $request) { try { - $node = new NodeRepository; - $new = $node->create($request->except([ - '_token', + $repo = new NodeRepository; + $node = $repo->create($request->only([ + 'name', + 'location', + 'public', + 'fqdn', + 'scheme', + 'memory', + 'memory_overallocate', + 'disk', + 'disk_overallocate', + 'daemonBase', + 'daemonSFTP', + 'daemonListen', ])); - Alert::success('Successfully created new node. Before you can add any servers you need to first assign some IP addresses and ports.')->flash(); - Alert::info('To simplify the node setup you can generate a token on the configuration tab.')->flash(); + Alert::success('Successfully created new node that can be configured automatically on your remote machine by visiting the configuration tab. Before you can add any servers you need to first assign some IP addresses and ports.')->flash(); return redirect()->route('admin.nodes.view', [ - 'id' => $new, + 'id' => $node->id, 'tab' => 'tab_allocation', ]); } catch (DisplayValidationException $e) { @@ -103,26 +111,18 @@ class NodesController extends Controller public function getView(Request $request, $id) { - $node = Models\Node::findOrFail($id); + $node = Models\Node::with( + 'servers.user', + 'servers.service', + 'servers.allocations', + 'location' + )->findOrFail($id); + $node->setRelation('allocations', $node->allocations()->paginate(40)); return view('admin.nodes.view', [ 'node' => $node, - 'servers' => Models\Server::select('servers.*', 'users.email as a_ownerEmail', 'services.name as a_serviceName') - ->join('users', 'users.id', '=', 'servers.owner_id') - ->join('services', 'services.id', '=', 'servers.service_id') - ->where('node_id', $id)->paginate(10, ['*'], 'servers'), 'stats' => Models\Server::select(DB::raw('SUM(memory) as memory, SUM(disk) as disk'))->where('node_id', $node->id)->first(), 'locations' => Models\Location::all(), - 'allocations' => Models\Allocation::select('allocations.*', 'servers.name as assigned_to_name') - ->where('allocations.node', $node->id) - ->leftJoin('servers', 'servers.id', '=', 'allocations.assigned_to') - ->orderBy('allocations.ip', 'asc') - ->orderBy('allocations.port', 'asc') - ->paginate(20, ['*'], 'allocations'), - 'allocation_ips' => Models\Allocation::select('id', 'ip') - ->where('node', $node->id) - ->groupBy('ip') - ->get(), ]); } @@ -130,8 +130,21 @@ class NodesController extends Controller { try { $node = new NodeRepository; - $node->update($id, $request->except([ - '_token', + $node->update($id, $request->only([ + 'name', + 'location', + 'public', + 'fqdn', + 'scheme', + 'memory', + 'memory_overallocate', + 'disk', + 'disk_overallocate', + 'upload_size', + 'daemonBase', + 'daemonSFTP', + 'daemonListen', + 'reset_secret', ])); Alert::success('Successfully update this node\'s information. If you changed any daemon settings you will need to restart it now.')->flash(); diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 10308ebd..34b6baec 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -48,8 +48,8 @@ class Allocation extends Model * @var array */ protected $casts = [ - 'node' => 'integer', + 'node_id' => 'integer', 'port' => 'integer', - 'assigned_to' => 'integer', + 'server_id' => 'integer', ]; } diff --git a/app/Models/Node.php b/app/Models/Node.php index 0c4d8fb3..2be35568 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -226,4 +226,24 @@ class Node extends Model { return $this->hasOne(Location::class, 'id', 'location_id'); } + + /** + * Gets the servers associated with a node. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function servers() + { + return $this->hasMany(Server::class); + } + + /** + * Gets the allocations associated with a node. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function allocations() + { + return $this->hasMany(Allocation::class); + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index db8ba638..f7e8bdbe 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -121,7 +121,7 @@ class Server extends Model 'services.name as a_serviceName', 'service_options.name as a_serviceOptionName' )->join('nodes', 'servers.node_id', '=', 'nodes.id') - ->join('locations', 'nodes.location', '=', 'locations.id') + ->join('locations', 'nodes.location_id', '=', 'locations.id') ->join('services', 'servers.service_id', '=', 'services.id') ->join('service_options', 'servers.option_id', '=', 'service_options.id') ->join('allocations', 'servers.allocation_id', '=', 'allocations.id'); @@ -218,6 +218,16 @@ class Server extends Model return Javascript::put($response); } + /** + * Gets the user who owns the server. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function user() + { + return $this->hasOne(User::class, 'id', 'owner_id'); + } + /** * Gets all allocations associated with this server. * @@ -225,7 +235,7 @@ class Server extends Model */ public function allocations() { - return $this->hasMany(Allocation::class, 'assigned_to'); + return $this->hasMany(Allocation::class, 'server_id'); } /** diff --git a/app/Repositories/LocationRepository.php b/app/Repositories/LocationRepository.php index 79196ff3..e25446d3 100644 --- a/app/Repositories/LocationRepository.php +++ b/app/Repositories/LocationRepository.php @@ -44,7 +44,7 @@ class LocationRepository public function create(array $data) { $validator = Validator::make($data, [ - 'short' => 'required|regex:/^[a-z0-9_.-]{1,10}$/i|unique:locations,short', + 'short' => 'required|regex:/^[\w.-]{1,20}$/i|unique:locations,short', 'long' => 'required|string|min:1|max:255', ]); @@ -73,9 +73,11 @@ class LocationRepository */ public function edit($id, array $data) { + $location = Models\Location::findOrFail($id); + $validator = Validator::make($data, [ - 'short' => 'regex:/^[a-z0-9_.-]{1,10}$/i', - 'long' => 'string|min:1|max:255', + 'short' => 'required|regex:/^[\w.-]{1,20}$/i|unique:locations,short,' . $location->id, + 'long' => 'required|string|min:1|max:255', ]); // Run validator, throw catchable and displayable exception if it fails. @@ -84,15 +86,7 @@ class LocationRepository throw new DisplayValidationException($validator->errors()); } - $location = Models\Location::findOrFail($id); - - if (isset($data['short'])) { - $location->short = $data['short']; - } - - if (isset($data['long'])) { - $location->long = $data['long']; - } + $location->fill($data); return $location->save(); } diff --git a/app/Repositories/NodeRepository.php b/app/Repositories/NodeRepository.php index d5544619..b9ba82e4 100644 --- a/app/Repositories/NodeRepository.php +++ b/app/Repositories/NodeRepository.php @@ -65,7 +65,7 @@ class NodeRepository // Verify the FQDN if using SSL if (filter_var($data['fqdn'], FILTER_VALIDATE_IP) && $data['scheme'] === 'https') { - throw new DisplayException('A fully qualified domain name is required to use secure comunication on this node.'); + throw new DisplayException('A fully qualified domain name is required to use a secure comunication method on this node.'); } // Verify FQDN is resolvable, or if not using SSL that the IP is valid. @@ -86,7 +86,7 @@ class NodeRepository $node->fill($data); $node->save(); - return $node->id; + return $node; } public function update($id, array $data) @@ -152,18 +152,12 @@ class NodeRepository $oldDaemonKey = $node->daemonSecret; $node->update($data); try { - $client = Models\Node::guzzleRequest($node->id); - $client->request('PATCH', '/config', [ - 'headers' => [ - 'X-Access-Token' => $oldDaemonKey, - ], + $node->guzzleClient(['X-Access-Token' => $oldDaemonKey])->request('PATCH', '/config', [ 'json' => [ 'web' => [ 'listen' => $node->daemonListen, 'ssl' => [ 'enabled' => ($node->scheme === 'https'), - 'certificate' => '/etc/letsencrypt/live/' . $node->fqdn . '/fullchain.pem', - 'key' => '/etc/letsencrypt/live/' . $node->fqdn . '/privkey.pem', ], ], 'sftp' => [ diff --git a/database/migrations/2017_02_03_155554_RenameColumns.php b/database/migrations/2017_02_03_155554_RenameColumns.php new file mode 100644 index 00000000..519ccc82 --- /dev/null +++ b/database/migrations/2017_02_03_155554_RenameColumns.php @@ -0,0 +1,48 @@ +dropForeign('allocations_node_foreign'); + $table->dropForeign('allocations_assigned_to_foreign'); + $table->dropIndex('allocations_node_foreign'); + $table->dropIndex('allocations_assigned_to_foreign'); + + $table->renameColumn('node', 'node_id'); + $table->renameColumn('assigned_to', 'server_id'); + $table->foreign('node_id')->references('id')->on('nodes'); + $table->foreign('server_id')->references('id')->on('servers'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('allocations', function (Blueprint $table) { + $table->dropForeign('allocations_node_id_foreign'); + $table->dropForeign('allocations_server_id_foreign'); + $table->dropIndex('allocations_node_id_foreign'); + $table->dropIndex('allocations_server_id_foreign'); + + $table->renameColumn('node_id', 'node'); + $table->renameColumn('server_id', 'assigned_to'); + $table->foreign('node')->references('id')->on('nodes'); + $table->foreign('assigned_to')->references('id')->on('servers'); + }); + } +} diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 29546d4e..de168708 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -53,10 +53,10 @@ {{ $node->name }} - {{ $node->a_locationName }} + {{ $node->location->short }} {{ $node->memory }} MB {{ $node->disk }} MB - {{ $node->a_serverCount }} + {{ $node->servers_count }} diff --git a/resources/views/admin/nodes/view.blade.php b/resources/views/admin/nodes/view.blade.php index 8485c9a5..5fa05470 100644 --- a/resources/views/admin/nodes/view.blade.php +++ b/resources/views/admin/nodes/view.blade.php @@ -60,7 +60,7 @@
  • Configuration
  • Allocation
  • Servers
  • - @if(count($servers) === 0)
  • Delete
  • @endif + @if(count($node->servers) === 0)
  • Delete
  • @endif
    @@ -83,7 +83,7 @@ Total Servers - {{ count($servers) }} + {{ count($node->servers) }} Memory Allocated @@ -309,7 +309,7 @@
    @@ -355,7 +355,7 @@ - @foreach($allocations as $allocation) + @foreach($node->allocations as $allocation) {{ $allocation->ip }} @@ -376,7 +376,7 @@
    - {{ $allocations->appends(['tab' => 'tab_allocation'])->links() }} + {{ $node->allocations->appends(['tab' => 'tab_allocation'])->render() }}
    @@ -402,11 +402,11 @@ - @foreach($servers as $server) + @foreach($node->servers as $server) {{ $server->name }} - {{ $server->a_ownerEmail }} - {{ $server->a_serviceName }} + {{ $server->user->email }} + {{ $server->service->name }} -- / {{ $server->memory === 0 ? '∞' : $server->memory }} MB {{ $server->disk }} MB -- % @@ -415,13 +415,10 @@ @endforeach -
    -
    {!! $servers->appends(['tab' => 'tab_servers'])->render() !!}
    -
    - @if(count($servers) === 0) + @if(count($node->servers) === 0)
    @@ -459,7 +456,7 @@