2016-01-05 04:59:45 +00:00
< ? php
2016-01-20 00:10:39 +00:00
/**
2016-01-20 21:05:16 +00:00
* Pterodactyl - Panel
2017-01-24 22:57:08 +00:00
* Copyright ( c ) 2015 - 2017 Dane Everitt < dane @ daneeveritt . com >.
2016-01-20 00:10:39 +00:00
*
2016-01-20 20:56:40 +00:00
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ), to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
2016-01-20 00:10:39 +00:00
*
2016-01-20 20:56:40 +00:00
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
2016-01-20 00:10:39 +00:00
*
2016-01-20 20:56:40 +00:00
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
2016-01-20 00:10:39 +00:00
*/
2016-12-07 22:46:38 +00:00
2016-01-05 04:59:45 +00:00
namespace Pterodactyl\Http\Controllers\Admin ;
use DB ;
2016-12-07 22:46:38 +00:00
use Log ;
use Alert ;
2017-03-03 22:30:39 +00:00
use Javascript ;
2016-01-05 04:59:45 +00:00
use Pterodactyl\Models ;
2016-12-07 22:46:38 +00:00
use Illuminate\Http\Request ;
2016-09-07 20:12:06 +00:00
use Pterodactyl\Exceptions\DisplayException ;
2016-01-05 04:59:45 +00:00
use Pterodactyl\Http\Controllers\Controller ;
2016-12-07 22:46:38 +00:00
use Pterodactyl\Repositories\NodeRepository ;
use Pterodactyl\Exceptions\DisplayValidationException ;
2016-01-05 04:59:45 +00:00
class NodesController extends Controller
{
/**
2017-03-04 04:37:41 +00:00
* Displays the index page listing all nodes on the panel .
*
* @ param Request $request
* @ return \Illuminate\View\View
2016-01-05 04:59:45 +00:00
*/
2017-03-04 04:37:41 +00:00
public function index ( Request $request )
2016-01-05 04:59:45 +00:00
{
2017-03-03 22:30:39 +00:00
$nodes = Models\Node :: with ( 'location' ) -> withCount ( 'servers' );
if ( ! is_null ( $request -> input ( 'query' ))) {
$nodes -> search ( $request -> input ( 'query' ));
}
return view ( 'admin.nodes.index' , [ 'nodes' => $nodes -> paginate ( 25 )]);
2016-01-05 04:59:45 +00:00
}
2017-03-04 04:37:41 +00:00
/**
* Displays create new node page .
*
* @ param Request $request
* @ return \Illuminate\View\View | \Illuminate\Response\RedirectResponse
*/
public function new ( Request $request )
2016-01-05 04:59:45 +00:00
{
2017-03-04 04:37:41 +00:00
$locations = Models\Location :: all ();
if ( ! $locations -> count ()) {
2016-09-30 20:05:39 +00:00
Alert :: warning ( 'You must add a location before you can add a new node.' ) -> flash ();
2016-12-07 22:46:38 +00:00
2016-09-30 20:05:39 +00:00
return redirect () -> route ( 'admin.locations' );
}
2017-03-04 04:37:41 +00:00
return view ( 'admin.nodes.new' , [ 'locations' => $locations ]);
2016-01-05 04:59:45 +00:00
}
2017-03-04 04:37:41 +00:00
/**
* Post controller to create a new node on the system .
*
* @ param Request $request
* @ return \Illuminate\Response\RedirectResponse
*/
public function create ( Request $request )
2016-01-05 04:59:45 +00:00
{
try {
2017-02-03 21:50:28 +00:00
$repo = new NodeRepository ;
2017-03-04 04:37:41 +00:00
$node = $repo -> create ( $request -> intersect ([
'name' , 'location_id' , 'public' , 'fqdn' , 'scheme' , 'memory' ,
'memory_overallocate' , 'disk' , 'disk_overallocate' ,
'daemonBase' , 'daemonSFTP' , 'daemonListen' ,
2016-01-05 04:59:45 +00:00
]));
2017-02-03 21:50:28 +00:00
Alert :: success ( 'Successfully created new node that can be configured automatically on your remote machine by visiting the configuration tab. <strong>Before you can add any servers you need to first assign some IP addresses and ports.</strong>' ) -> flash ();
2016-12-07 22:46:38 +00:00
2017-03-04 04:37:41 +00:00
return redirect () -> route ( 'admin.nodes.view' , $node -> id );
2016-09-07 20:12:06 +00:00
} catch ( DisplayValidationException $e ) {
2016-01-05 04:59:45 +00:00
return redirect () -> route ( 'admin.nodes.new' ) -> withErrors ( json_decode ( $e -> getMessage ())) -> withInput ();
2016-09-07 20:12:06 +00:00
} catch ( DisplayException $e ) {
2016-01-05 04:59:45 +00:00
Alert :: danger ( $e -> getMessage ()) -> flash ();
} catch ( \Exception $e ) {
Log :: error ( $e );
Alert :: danger ( 'An unhandled exception occured while attempting to add this node. Please try again.' ) -> flash ();
}
2016-12-07 22:46:38 +00:00
2016-01-05 04:59:45 +00:00
return redirect () -> route ( 'admin.nodes.new' ) -> withInput ();
}
2017-03-03 22:30:39 +00:00
/**
* Shows the index overview page for a specific node .
*
* @ param Request $request
* @ param int $id The ID of the node to display information for .
*
* @ return \Illuminate\View\View
*/
public function viewIndex ( Request $request , $id )
{
$node = Models\Node :: with ( 'location' ) -> withCount ( 'servers' ) -> findOrFail ( $id );
$stats = collect (
Models\Server :: select (
DB :: raw ( 'SUM(memory) as memory, SUM(disk) as disk' )
) -> where ( 'node_id' , $node -> id ) -> first ()
) -> mapWithKeys ( function ( $item , $key ) use ( $node ) {
$percent = ( $item / $node -> { $key }) * 100 ;
return [ $key => [
'value' => $item ,
'percent' => $percent ,
'css' => ( $percent <= 75 ) ? 'green' : (( $percent > 90 ) ? 'red' : 'yellow' ),
]];
}) -> toArray ();
return view ( 'admin.nodes.view.index' , [ 'node' => $node , 'stats' => $stats ]);
}
/**
* Shows the settings page for a specific node .
*
* @ param Request $request
* @ param int $id The ID of the node to display information for .
*
* @ return \Illuminate\View\View
*/
public function viewSettings ( Request $request , $id )
{
return view ( 'admin.nodes.view.settings' , [
'node' => Models\Node :: findOrFail ( $id ),
'locations' => Models\Location :: all (),
]);
}
/**
* Shows the configuration page for a specific node .
*
* @ param Request $request
* @ param int $id The ID of the node to display information for .
*
* @ return \Illuminate\View\View
*/
public function viewConfiguration ( Request $request , $id )
{
return view ( 'admin.nodes.view.configuration' , [
'node' => Models\Node :: findOrFail ( $id ),
]);
}
/**
* Shows the allocation page for a specific node .
*
* @ param Request $request
* @ param int $id The ID of the node to display information for .
*
* @ return \Illuminate\View\View
*/
public function viewAllocation ( Request $request , $id )
{
$node = Models\Node :: findOrFail ( $id );
$node -> setRelation ( 'allocations' , $node -> allocations () -> orderBy ( 'ip' , 'asc' ) -> orderBy ( 'port' , 'asc' ) -> with ( 'server' ) -> paginate ( 50 ));
Javascript :: put ([
'node' => collect ( $node ) -> only ([ 'id' ]),
]);
return view ( 'admin.nodes.view.allocation' , [ 'node' => $node ]);
}
/**
* Shows the server listing page for a specific node .
*
* @ param Request $request
* @ param int $id The ID of the node to display information for .
*
* @ return \Illuminate\View\View
*/
public function viewServers ( Request $request , $id )
{
2017-03-03 22:53:35 +00:00
$node = Models\Node :: with ( 'servers.user' , 'servers.service' , 'servers.option' ) -> findOrFail ( $id );
2017-03-03 22:30:39 +00:00
Javascript :: put ([
'node' => collect ( $node -> makeVisible ( 'daemonSecret' )) -> only ([ 'scheme' , 'fqdn' , 'daemonListen' , 'daemonSecret' ]),
]);
return view ( 'admin.nodes.view.servers' , [
'node' => $node ,
]);
}
2017-03-04 04:14:23 +00:00
/**
* Updates settings for a node .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $node
2017-03-04 04:14:23 +00:00
* @ return \Illuminate\Http\RedirectResponse
*/
public function updateSettings ( Request $request , $id )
2016-01-05 23:31:25 +00:00
{
2017-03-04 04:14:23 +00:00
$repo = new NodeRepository ;
2016-01-05 23:31:25 +00:00
try {
2017-03-04 04:14:23 +00:00
$repo -> update ( $id , $request -> intersect ([
'name' , 'location_id' , 'public' , 'fqdn' , 'scheme' , 'memory' ,
'memory_overallocate' , 'disk' , 'disk_overallocate' , 'upload_size' ,
2017-02-16 20:57:02 +00:00
'daemonSFTP' , 'daemonListen' , 'reset_secret' ,
2016-01-05 23:31:25 +00:00
]));
2016-12-07 22:46:38 +00:00
2017-03-04 04:14:23 +00:00
Alert :: success ( 'Successfully updated this node\'s information. If you changed any daemon settings you will need to restart it now.' ) -> flash ();
} catch ( DisplayValidationException $ex ) {
return redirect () -> route ( 'admin.nodes.view.settings' , $id ) -> withErrors ( json_decode ( $ex -> getMessage ())) -> withInput ();
} catch ( DisplayException $ex ) {
Alert :: danger ( $ex -> getMessage ()) -> flash ();
} catch ( \Exception $ex ) {
Log :: error ( $ex );
2016-01-05 23:31:25 +00:00
Alert :: danger ( 'An unhandled exception occured while attempting to edit this node. Please try again.' ) -> flash ();
}
2016-12-07 22:46:38 +00:00
2017-03-04 04:14:23 +00:00
return redirect () -> route ( 'admin.nodes.view.settings' , $id ) -> withInput ();
2016-01-05 23:31:25 +00:00
}
2017-03-03 22:30:39 +00:00
/**
* Removes a single allocation from a node .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $node
* @ param int $allocation [ description ]
2017-03-04 04:14:23 +00:00
* @ return \Illuminate\Http\Response | \Illuminate\Http\JsonResponse
2017-03-03 22:30:39 +00:00
*/
public function allocationRemoveSingle ( Request $request , $node , $allocation )
2016-01-09 01:01:18 +00:00
{
2017-02-18 00:59:40 +00:00
$query = Models\Allocation :: where ( 'node_id' , $node ) -> whereNull ( 'server_id' ) -> where ( 'id' , $allocation ) -> delete ();
2017-03-03 22:30:39 +00:00
if ( $query < 1 ) {
2016-01-09 01:01:18 +00:00
return response () -> json ([
2016-12-07 22:46:38 +00:00
'error' => 'Unable to find an allocation matching those details to delete.' ,
2016-01-09 01:01:18 +00:00
], 400 );
}
2016-12-07 22:46:38 +00:00
2016-01-09 01:01:18 +00:00
return response ( '' , 204 );
}
2017-03-03 22:30:39 +00:00
/**
* Remove all allocations for a specific IP at once on a node .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $node
2017-03-04 04:14:23 +00:00
* @ return \Illuminate\Http\RedirectResponse
2017-03-03 22:30:39 +00:00
*/
public function allocationRemoveBlock ( Request $request , $node )
2016-09-30 01:34:20 +00:00
{
2017-02-19 03:32:16 +00:00
$query = Models\Allocation :: where ( 'node_id' , $node ) -> whereNull ( 'server_id' ) -> where ( 'ip' , $request -> input ( 'ip' )) -> delete ();
2017-03-03 22:30:39 +00:00
if ( $query < 1 ) {
2016-09-30 01:34:20 +00:00
Alert :: danger ( 'There was an error while attempting to delete allocations on that IP.' ) -> flash ();
2017-03-03 22:30:39 +00:00
} else {
Alert :: success ( 'Deleted all unallocated ports for <code>' . $request -> input ( 'ip' ) . '</code>.' ) -> flash ();
2016-09-30 01:34:20 +00:00
}
2016-12-07 22:46:38 +00:00
2017-03-03 22:30:39 +00:00
return redirect () -> route ( 'admin.nodes.view.allocation' , $node );
2016-09-30 01:34:20 +00:00
}
2017-03-03 22:30:39 +00:00
/**
* Sets an alias for a specific allocation on a node .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $node
2017-03-04 04:14:23 +00:00
* @ return \Illuminate\Http\Response
* @ throws \Exception
2017-03-03 22:30:39 +00:00
*/
public function allocationSetAlias ( Request $request , $node )
2016-09-30 01:34:20 +00:00
{
2017-03-03 22:30:39 +00:00
if ( ! $request -> input ( 'allocation_id' )) {
2016-09-30 01:34:20 +00:00
return response ( 'Missing required parameters.' , 422 );
}
try {
2017-03-03 22:30:39 +00:00
$update = Models\Allocation :: findOrFail ( $request -> input ( 'allocation_id' ));
2016-09-30 20:01:36 +00:00
$update -> ip_alias = ( empty ( $request -> input ( 'alias' ))) ? null : $request -> input ( 'alias' );
2016-09-30 01:34:20 +00:00
$update -> save ();
return response ( '' , 204 );
} catch ( \Exception $ex ) {
throw $ex ;
}
}
2017-03-03 22:30:39 +00:00
/**
* Creates new allocations on a node .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $node
2017-03-03 22:30:39 +00:00
* @ return \Illuminate\Http\RedirectResponse
*/
public function createAllocation ( Request $request , $node )
2016-01-10 05:38:16 +00:00
{
2017-03-03 22:30:39 +00:00
$repo = new NodeRepository ;
2016-09-30 21:12:36 +00:00
2017-03-03 22:30:39 +00:00
try {
$repo -> addAllocations ( $node , $request -> intersect ([ 'allocation_ip' , 'allocation_alias' , 'allocation_ports' ]));
Alert :: success ( 'Successfully added new allocations!' ) -> flash ();
} catch ( DisplayValidationException $ex ) {
return redirect () -> route ( 'admin.nodes.view.allocation' , $node ) -> withErrors ( json_decode ( $ex -> getMessage ())) -> withInput ();
} catch ( DisplayException $ex ) {
Alert :: danger ( $ex -> getMessage ()) -> flash ();
} catch ( \Exception $ex ) {
Log :: error ( $ex );
Alert :: danger ( 'An unhandled exception occured while attempting to add allocations this node. This error has been logged.' ) -> flash ();
2016-09-30 21:12:36 +00:00
}
2017-03-03 22:30:39 +00:00
return redirect () -> route ( 'admin.nodes.view.allocation' , $node );
}
2016-01-10 05:38:16 +00:00
2017-03-04 04:14:23 +00:00
/**
* Deletes a node from the system .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $id
2017-03-04 04:14:23 +00:00
* @ return \Illuminate\Http\RedirectResponse
*/
public function delete ( Request $request , $id )
2017-03-03 22:30:39 +00:00
{
2017-03-04 04:14:23 +00:00
$repo = new NodeRepository ;
2016-01-10 05:38:16 +00:00
2016-11-26 21:29:13 +00:00
try {
$repo -> delete ( $id );
Alert :: success ( 'Successfully deleted the requested node from the panel.' ) -> flash ();
2016-12-07 22:46:38 +00:00
2016-11-26 21:29:13 +00:00
return redirect () -> route ( 'admin.nodes' );
2017-03-04 04:14:23 +00:00
} catch ( DisplayException $ex ) {
Alert :: danger ( $ex -> getMessage ()) -> flash ();
} catch ( \Exception $ex ) {
Log :: error ( $ex );
2016-11-26 21:29:13 +00:00
Alert :: danger ( 'An unhandled exception occured while attempting to delete this node. Please try again.' ) -> flash ();
2016-01-10 21:59:19 +00:00
}
2017-03-04 04:14:23 +00:00
return redirect () -> route ( 'admin.nodes.view' , $id );
2016-01-10 21:59:19 +00:00
}
2017-01-07 17:10:11 +00:00
2017-03-04 04:14:23 +00:00
/**
* Returns the configuration token to auto - deploy a node .
*
* @ param Request $request
2017-03-04 04:38:21 +00:00
* @ param int $id
2017-03-04 04:14:23 +00:00
* @ return \Illuminate\Http\JsonResponse
*/
public function setToken ( Request $request , $id )
2017-01-07 17:39:41 +00:00
{
2017-03-04 04:14:23 +00:00
$node = Models\Node :: findOrFail ( $id );
$t = Models\NodeConfigurationToken :: create ([
'node_id' => $id ,
'token' => str_random ( 32 ),
]);
return response () -> json ([ 'token' => $t -> token ]);
2017-01-07 17:10:11 +00:00
}
2016-01-05 04:59:45 +00:00
}