Skip to content

Commit d381c69

Browse files
committed
Add support for node creation
1 parent b5821ff commit d381c69

File tree

8 files changed

+431
-0
lines changed

8 files changed

+431
-0
lines changed
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Admin;
4+
5+
use Alert;
6+
use Debugbar;
7+
use Log;
8+
use DB;
9+
10+
use Pterodactyl\Models;
11+
use Pterodactyl\Repositories\NodeRepository;
12+
13+
use Pterodactyl\Http\Controllers\Controller;
14+
use Illuminate\Http\Request;
15+
16+
class NodesController extends Controller
17+
{
18+
19+
/**
20+
* Controller Constructor
21+
*/
22+
public function __construct()
23+
{
24+
//
25+
}
26+
27+
public function getIndex(Request $request)
28+
{
29+
return view('admin.nodes.index', [
30+
'nodes' => Models\Node::select(
31+
'nodes.*',
32+
'locations.long as a_locationName',
33+
DB::raw('(SELECT COUNT(*) FROM servers WHERE servers.node = nodes.id) as a_serverCount')
34+
)->join('locations', 'nodes.location', '=', 'locations.id')->paginate(20),
35+
]);
36+
}
37+
38+
public function getNew(Request $request)
39+
{
40+
return view('admin.nodes.new', [
41+
'locations' => Models\Location::all()
42+
]);
43+
}
44+
45+
public function postNew(Request $request)
46+
{
47+
try {
48+
$node = new NodeRepository;
49+
$new = $node->create($request->except([
50+
'_token'
51+
]));
52+
Alert::success('Successfully created new node. You should allocate some IP addresses to it now.')->flash();
53+
return redirect()->route('admin.nodes.view', [
54+
'id' => $new
55+
]);
56+
} catch (\Pterodactyl\Exceptions\DisplayValidationException $e) {
57+
return redirect()->route('admin.nodes.new')->withErrors(json_decode($e->getMessage()))->withInput();
58+
} catch (\Pterodactyl\Exceptions\DisplayException $e) {
59+
Alert::danger($e->getMessage())->flash();
60+
} catch (\Exception $e) {
61+
Log::error($e);
62+
Alert::danger('An unhandled exception occured while attempting to add this node. Please try again.')->flash();
63+
}
64+
return redirect()->route('admin.nodes.new')->withInput();
65+
}
66+
67+
public function getView(Request $request, $id)
68+
{
69+
$node = Models\Node::findOrFail($id);
70+
return view('admin.nodes.view', [
71+
'node' => $node
72+
]);
73+
}
74+
75+
}

app/Http/Routes/AdminRoutes.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,39 @@ public function map(Router $router) {
137137

138138
});
139139

140+
// Node Routes
141+
$router->group([
142+
'prefix' => 'admin/nodes',
143+
'middleware' => [
144+
'auth',
145+
'admin'
146+
]
147+
], function () use ($router) {
148+
149+
// View All Nodes
150+
$router->get('/', [
151+
'as' => 'admin.nodes',
152+
'uses' => 'Admin\NodesController@getIndex'
153+
]);
154+
155+
// Add New Node
156+
$router->get('/new', [
157+
'as' => 'admin.nodes.new',
158+
'uses' => 'Admin\NodesController@getNew'
159+
]);
160+
161+
$router->post('/new', [
162+
'uses' => 'Admin\NodesController@postNew'
163+
]);
164+
165+
// View Node
166+
$router->get('/view/{id}', [
167+
'as' => 'admin.nodes.view',
168+
'uses' => 'Admin\NodesController@getView'
169+
]);
170+
171+
});
172+
140173
}
141174

142175
}

app/Models/Node.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ class Node extends Model
2222
*/
2323
protected $hidden = ['daemonSecret'];
2424

25+
/**
26+
* Fields that are not mass assignable.
27+
*
28+
* @var array
29+
*/
30+
protected $guarded = ['id', 'created_at', 'updated_at'];
31+
2532
/**
2633
* @var array
2734
*/
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace Pterodactyl\Repositories;
4+
5+
use Validator;
6+
7+
use Pterodactyl\Models;
8+
use Pterodactyl\Services\UuidService;
9+
10+
use Pterodactyl\Exceptions\DisplayException;
11+
use Pterodactyl\Exceptions\DisplayValidationException;
12+
13+
class NodeRepository {
14+
15+
public function __construct()
16+
{
17+
//
18+
}
19+
20+
public function create(array $data)
21+
{
22+
// Validate Fields
23+
$validator = Validator::make($data, [
24+
'name' => 'required|regex:/^([\w .-]{1,100})$/',
25+
'location' => 'required|numeric|min:1|exists:locations,id',
26+
'public' => 'required|numeric|between:0,1',
27+
'fqdn' => 'required|string|unique:nodes,fqdn',
28+
'scheme' => 'required|regex:/^(http(s)?)$/',
29+
'memory' => 'required|numeric|min:1',
30+
'memory_overallocate' => 'required|numeric|min:-1',
31+
'disk' => 'required|numeric|min:1',
32+
'disk_overallocate' => 'required|numeric|min:-1',
33+
'daemonBase' => 'required|regex:/^([\/][\d\w.\-\/]+)$/',
34+
'daemonSFTP' => 'required|numeric|between:1,65535',
35+
'daemonListen' => 'required|numeric|between:1,65535'
36+
]);
37+
38+
// Run validator, throw catchable and displayable exception if it fails.
39+
// Exception includes a JSON result of failed validation rules.
40+
if ($validator->fails()) {
41+
throw new DisplayValidationException($validator->errors());
42+
}
43+
44+
// Verify the FQDN
45+
if (!filter_var(gethostbyname($data['fqdn']), FILTER_VALIDATE_IP)) {
46+
throw new DisplayException('The FQDN provided does not resolve to a valid IP address.');
47+
}
48+
49+
// Should we be nulling the overallocations?
50+
$data['memory_overallocate'] = ($data['memory_overallocate'] < 0) ? null : $data['memory_overallocate'];
51+
$data['disk_overallocate'] = ($data['disk_overallocate'] < 0) ? null : $data['disk_overallocate'];
52+
53+
// Set the Secret
54+
$uuid = new UuidService;
55+
$data['daemonSecret'] = (string) $uuid->generate('nodes', 'daemonSecret');
56+
57+
// Store the Data
58+
$node = new Models\Node;
59+
$node->fill($data);
60+
$node->save();
61+
62+
return $node->id;
63+
64+
}
65+
66+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
use Illuminate\Database\Schema\Blueprint;
4+
use Illuminate\Database\Migrations\Migration;
5+
6+
class RemoveNodeIp extends Migration
7+
{
8+
/**
9+
* Run the migrations.
10+
*
11+
* @return void
12+
*/
13+
public function up()
14+
{
15+
Schema::table('nodes', function (Blueprint $table) {
16+
$table->dropColumn('ip');
17+
});
18+
}
19+
20+
/**
21+
* Reverse the migrations.
22+
*
23+
* @return void
24+
*/
25+
public function down()
26+
{
27+
Schema::table('nodes', function (Blueprint $table) {
28+
$table->string('ip')->after('fqdn');
29+
});
30+
}
31+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
@extends('layouts.admin')
2+
3+
@section('title')
4+
Node List
5+
@endsection
6+
7+
@section('content')
8+
<div class="col-md-12">
9+
<ul class="breadcrumb">
10+
<li><a href="/admin">Admin Control</a></li>
11+
<li class="active">Nodes</li>
12+
</ul>
13+
<h3>All Nodes</h3><hr />
14+
<table class="table table-bordered table-hover">
15+
<thead>
16+
<tr>
17+
<th>Name</th>
18+
<th>Location</th>
19+
<th>FQDN</th>
20+
<th>Memory</th>
21+
<th>Disk</th>
22+
<th class="text-center">Servers</th>
23+
<th class="text-center">HTTPS</th>
24+
<th class="text-center">Public</th>
25+
</tr>
26+
</thead>
27+
<tbody>
28+
@foreach ($nodes as $node)
29+
<tr>
30+
<td><a href="/admin/nodes/view/{{ $node->id }}">{{ $node->name }}</td>
31+
<td>{{ $node->a_locationName }}</td>
32+
<td><code>{{ $node->fqdn }}</code></td>
33+
<td>{{ $node->memory }} MB</td>
34+
<td>{{ $node->disk }} MB</td>
35+
<td class="text-center">{{ $node->a_serverCount }}</td>
36+
<td class="text-center" style="color:{{ ($node->scheme === 'https') ? '#50af51' : '#d9534f' }}"><i class="fa fa-{{ ($node->scheme === 'https') ? 'lock' : 'unlock' }}"></i></td>
37+
<td class="text-center"><i class="fa fa-{{ ($node->public === 1) ? 'check' : 'times' }}"></i></td>
38+
</tr>
39+
@endforeach
40+
</tbody>
41+
</table>
42+
<div class="row">
43+
<div class="col-md-12 text-center">{!! $nodes->render() !!}</div>
44+
</div>
45+
</div>
46+
<script>
47+
$(document).ready(function () {
48+
$('#sidebar_links').find("a[href='/admin/nodes']").addClass('active');
49+
});
50+
</script>
51+
@endsection

0 commit comments

Comments
 (0)