Add IP Aliasing (#72)

* complete support for IP Alias's throughout panel

Includes a database change and probably better allocation handling
anyways

closes #37
This commit is contained in:
Dane Everitt 2016-08-31 16:03:37 -04:00 committed by GitHub
parent f1a3008a50
commit e8c175f385
14 changed files with 206 additions and 76 deletions

View file

@ -52,10 +52,17 @@ class ServersController extends Controller
public function getIndex(Request $request) public function getIndex(Request $request)
{ {
return view('admin.servers.index', [ return view('admin.servers.index', [
'servers' => Models\Server::select('servers.*', 'nodes.name as a_nodeName', 'users.email as a_ownerEmail') 'servers' => Models\Server::select(
->join('nodes', 'servers.node', '=', 'nodes.id') 'servers.*',
->join('users', 'servers.owner', '=', 'users.id') 'nodes.name as a_nodeName',
->paginate(20), 'users.email as a_ownerEmail',
'allocations.ip',
'allocations.port',
'allocations.ip_alias'
)->join('nodes', 'servers.node', '=', 'nodes.id')
->join('users', 'servers.owner', '=', 'users.id')
->join('allocations', 'servers.allocation', '=', 'allocations.id')
->paginate(20),
]); ]);
} }
@ -76,12 +83,16 @@ class ServersController extends Controller
'locations.long as a_locationName', 'locations.long as a_locationName',
'services.name as a_serviceName', 'services.name as a_serviceName',
'services.executable as a_serviceExecutable', 'services.executable as a_serviceExecutable',
'service_options.name as a_servceOptionName' 'service_options.name as a_servceOptionName',
'allocations.ip',
'allocations.port',
'allocations.ip_alias'
)->join('nodes', 'servers.node', '=', 'nodes.id') )->join('nodes', 'servers.node', '=', 'nodes.id')
->join('users', 'servers.owner', '=', 'users.id') ->join('users', 'servers.owner', '=', 'users.id')
->join('locations', 'nodes.location', '=', 'locations.id') ->join('locations', 'nodes.location', '=', 'locations.id')
->join('services', 'servers.service', '=', 'services.id') ->join('services', 'servers.service', '=', 'services.id')
->join('service_options', 'servers.option', '=', 'service_options.id') ->join('service_options', 'servers.option', '=', 'service_options.id')
->join('allocations', 'servers.allocation', '=', 'allocations.id')
->where('servers.id', $id) ->where('servers.id', $id)
->first(); ->first();
@ -91,8 +102,8 @@ class ServersController extends Controller
return view('admin.servers.view', [ return view('admin.servers.view', [
'server' => $server, 'server' => $server,
'assigned' => Models\Allocation::select('id', 'ip', 'port')->where('assigned_to', $id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), 'assigned' => Models\Allocation::where('assigned_to', $id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(),
'unassigned' => Models\Allocation::select('id', 'ip', 'port')->where('node', $server->node)->whereNull('assigned_to')->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(), 'unassigned' => Models\Allocation::where('node', $server->node)->whereNull('assigned_to')->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(),
'startup' => Models\ServiceVariables::select('service_variables.*', 'server_variables.variable_value as a_serverValue') 'startup' => Models\ServiceVariables::select('service_variables.*', 'server_variables.variable_value as a_serverValue')
->join('server_variables', 'server_variables.variable_id', '=', 'service_variables.id') ->join('server_variables', 'server_variables.variable_id', '=', 'service_variables.id')
->where('service_variables.option_id', $server->option) ->where('service_variables.option_id', $server->option)

View file

@ -194,9 +194,11 @@ class AjaxController extends Controller
{ {
$server = Server::getByUUID($uuid); $server = Server::getByUUID($uuid);
$allocation = Models\Allocation::findOrFail($server->allocation);
$this->authorize('set-connection', $server); $this->authorize('set-connection', $server);
if ($request->input('connection') === $server->ip . ':' . $server->port) { if ($request->input('connection') === $allocation->ip . ':' . $allocation->port) {
return response()->json([ return response()->json([
'error' => 'You are already using this as your default connection.' 'error' => 'You are already using this as your default connection.'
], 409); ], 409);

View file

@ -195,11 +195,8 @@ class ServerController extends Controller
public function getSettings(Request $request, $uuid) public function getSettings(Request $request, $uuid)
{ {
$server = Models\Server::getByUUID($uuid); $server = Models\Server::getByUUID($uuid);
// $variables = Models\ServiceVariables::select('service_variables.*', 'server_variables.variable_value as a_serverValue') $allocation = Models\Allocation::findOrFail($server->allocation);
// ->join('server_variables', 'server_variables.variable_id', '=', 'service_variables.id')
// ->where('service_variables.option_id', $server->option)
// ->where('server_variables.server_id', $server->id)
// ->get();
$variables = Models\ServiceVariables::select( $variables = Models\ServiceVariables::select(
'service_variables.*', 'service_variables.*',
DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_serverValue') DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_serverValue')
@ -217,8 +214,8 @@ class ServerController extends Controller
$serverVariables = [ $serverVariables = [
'{{SERVER_MEMORY}}' => $server->memory, '{{SERVER_MEMORY}}' => $server->memory,
'{{SERVER_IP}}' => $server->ip, '{{SERVER_IP}}' => $allocation->ip,
'{{SERVER_PORT}}' => $server->port, '{{SERVER_PORT}}' => $allocation->port,
]; ];
$processed = str_replace(array_keys($serverVariables), array_values($serverVariables), $server->startup); $processed = str_replace(array_keys($serverVariables), array_values($serverVariables), $server->startup);

View file

@ -124,10 +124,16 @@ class Server extends Model
public static function getUserServers($paginate = null) public static function getUserServers($paginate = null)
{ {
$query = self::select('servers.*', 'nodes.name as nodeName', 'locations.short as a_locationShort') $query = self::select(
->join('nodes', 'servers.node', '=', 'nodes.id') 'servers.*',
->join('locations', 'nodes.location', '=', 'locations.id') 'nodes.name as nodeName',
->where('active', 1); 'locations.short as a_locationShort',
'allocations.ip_alias',
'allocations.port'
)->join('nodes', 'servers.node', '=', 'nodes.id')
->join('locations', 'nodes.location', '=', 'locations.id')
->join('allocations', 'servers.allocation', '=', 'allocations.id')
->where('active', 1);
if (self::$user->root_admin !== 1) { if (self::$user->root_admin !== 1) {
$query->whereIn('servers.id', Subuser::accessServers()); $query->whereIn('servers.id', Subuser::accessServers());

View file

@ -213,8 +213,7 @@ class ServerRepository
'io' => $data['io'], 'io' => $data['io'],
'cpu' => $data['cpu'], 'cpu' => $data['cpu'],
'oom_disabled' => (isset($data['oom_disabled'])) ? true : false, 'oom_disabled' => (isset($data['oom_disabled'])) ? true : false,
'ip' => $data['ip'], 'allocation' => $allocation->id,
'port' => $data['port'],
'service' => $data['service'], 'service' => $data['service'],
'option' => $data['option'], 'option' => $data['option'],
'startup' => $data['startup'], 'startup' => $data['startup'],
@ -253,11 +252,11 @@ class ServerRepository
'user' => $server->username, 'user' => $server->username,
'build' => [ 'build' => [
'default' => [ 'default' => [
'ip' => $server->ip, 'ip' => $allocation->ip,
'port' => (int) $server->port 'port' => (int) $allocation->port
], ],
'ports' => [ 'ports' => [
(string) $server->ip => [ (int) $server->port ] (string) $allocation->ip => [ (int) $allocation->port ]
], ],
'env' => $environmentVariables, 'env' => $environmentVariables,
'memory' => (int) $server->memory, 'memory' => (int) $server->memory,
@ -413,17 +412,20 @@ class ServerRepository
try { try {
$server = Models\Server::findOrFail($id); $server = Models\Server::findOrFail($id);
$allocation = Models\Allocation::findOrFail($server->allocation);
if (isset($data['default'])) { if (isset($data['default'])) {
list($ip, $port) = explode(':', $data['default']); list($ip, $port) = explode(':', $data['default']);
if ($ip !== $server->ip || $port !== $server->port) { if ($ip !== $allocation->ip || $port !== $allocation->port) {
$allocation = Models\Allocation::where('ip', $ip)->where('port', $port)->where('assigned_to', $server->id)->first(); $selection = Models\Allocation::where('ip', $ip)->where('port', $port)->where('assigned_to', $server->id)->first();
if (!$allocation) { if (!$selection) {
throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.'); throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.');
} }
$server->ip = $ip; $server->allocation = $selection->id;
$server->port = $port;
// Re-Run to keep updated for rest of function
$allocation = Models\Allocation::findOrFail($server->allocation);
} }
} }
@ -437,7 +439,7 @@ class ServerRepository
} }
// Can't remove the assigned IP/Port combo // Can't remove the assigned IP/Port combo
if ($ip === $server->ip && $port === $server->port) { if ($ip === $allocation->ip && $port === $allocation->port) {
continue; continue;
} }
@ -513,8 +515,8 @@ class ServerRepository
'json' => [ 'json' => [
'build' => [ 'build' => [
'default' => [ 'default' => [
'ip' => $server->ip, 'ip' => $allocation->ip,
'port' => (int) $server->port 'port' => (int) $allocation->port
], ],
'ports|overwrite' => $additionalAssignments, 'ports|overwrite' => $additionalAssignments,
'memory' => (int) $server->memory, 'memory' => (int) $server->memory,

View file

@ -1,31 +0,0 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class FixColumnNameForDatabases extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('databases', function (Blueprint $table) {
$table->renameColumn('server', 'server_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('databases', function (Blueprint $table) {
$table->renameColumn('server_id', 'server');
});
}
}

View file

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddIpAlias extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('allocations', function (Blueprint $table) {
$table->text('ip_alias')->nullable()->after('ip');
});
$allocations = DB::select('SELECT id, ip FROM allocations');
foreach($allocations as $allocation) {
DB::update(
'UPDATE allocations SET ip_alias = :ip WHERE id = :id',
[
'ip' => $allocation->ip,
'id' => $allocation->id
]
);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('allocations', function (Blueprint $table) {
$table->dropColumn('ip_alias');
});
}
}

View file

@ -0,0 +1,84 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class ModifyIpStorageMethod extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('servers', function (Blueprint $table) {
$table->mediumInteger('allocation')->unsigned()->after('oom_disabled');
});
// Parse All Servers
$servers = DB::select('SELECT id, ip, port, node FROM servers');
foreach($servers as $server) {
$allocation = DB::select(
'SELECT id FROM allocations WHERE ip = :ip AND port = :port AND node = :node',
[
'ip' => $server->ip,
'port' => $server->port,
'node' => $server->node
]
);
if (isset($allocation[0])) {
DB::update(
'UPDATE servers SET allocation = :alocid WHERE id = :id',
[
'alocid' => $allocation[0]->id,
'id' => $server->id
]
);
}
}
// Updated the server allocations, remove old fields
Schema::table('servers', function (Blueprint $table) {
$table->dropColumn('ip');
$table->dropColumn('port');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('servers', function (Blueprint $table) {
$table->text('ip')->after('allocation');
$table->integer('port')->unsigned()->after('ip');
});
// Find the allocations and reset the servers...
$servers = DB::select('SELECT id, allocation FROM servers');
foreach($servers as $server) {
$allocation = DB::select('SELECT * FROM allocations WHERE id = :alocid', [ 'alocid' => $server->allocation ]);
if (isset($allocation[0])) {
DB::update(
'UPDATE servers SET ip = :ip, port = :port WHERE id = :id',
[
'ip' => $allocation[0]->ip,
'port' => $allocation[0]->port,
'id' => $server->id
]
);
}
}
Schema::table('servers', function (Blueprint $table) {
$table->dropColumn('allocation');
});
}
}

View file

@ -46,7 +46,7 @@
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</td> <td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</td>
<td><a href="/admin/users/view/{{ $server->owner }}">{{ $server->a_ownerEmail }}</a></td> <td><a href="/admin/users/view/{{ $server->owner }}">{{ $server->a_ownerEmail }}</a></td>
<td class="hidden-xs"><a href="/admin/nodes/view/{{ $server->node }}">{{ $server->a_nodeName }}</a></td> <td class="hidden-xs"><a href="/admin/nodes/view/{{ $server->node }}">{{ $server->a_nodeName }}</a></td>
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td> <td><code>{{ $server->ip_alias }}:{{ $server->port }}</code> @if($server->ip !== $server->ip_alias)<span class="label label-default">alias</span>@endif</td>
<td class="hidden-xs"><code>{{ $server->username }}</code></td> <td class="hidden-xs"><code>{{ $server->username }}</code></td>
</tr> </tr>
@endforeach @endforeach

View file

@ -85,11 +85,15 @@
</tr> </tr>
<tr> <tr>
<td>Memory</td> <td>Memory</td>
<td><code>{{ $server->memory }}MB</code> (Swap: {{ $server->swap }}MB) (OOM Killer: <strong>{{ ($server->oom_disabled === 0) ? 'enabled' : 'disabled' }}</strong>)</td> <td><code>{{ $server->memory }}MB</code> / <code data-toggle="tooltip" data-placement="top" title="Swap Space">{{ $server->swap }}MB</code></td>
</tr>
<tr>
<td><abbr title="Out of Memory">OOM</abbr> Killer</td>
<td>{!! ($server->oom_disabled === 0) ? '<span class="label label-success">enabled</span>' : '<span class="label label-default">disabled</span>' !!}</td>
</tr> </tr>
<tr> <tr>
<td>Disk Space</td> <td>Disk Space</td>
<td><code>{{ $server->disk }}MB</code> (Enforced: <strong>no</strong>)</td> <td><code>{{ $server->disk }}MB</code></td>
</tr> </tr>
<tr> <tr>
<td>Block IO Weight</td> <td>Block IO Weight</td>
@ -103,9 +107,19 @@
<td>Default Connection</td> <td>Default Connection</td>
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td> <td><code>{{ $server->ip }}:{{ $server->port }}</code></td>
</tr> </tr>
<tr>
<td>Connection Alias</td>
<td>
@if($server->ip !== $server->ip_alias)
<code>{{ $server->ip_alias }}:{{ $server->port }}</code>
@else
<span class="label label-default">No Alias Assigned</span>
@endif
</td>
</tr>
<tr> <tr>
<td>Installed</td> <td>Installed</td>
<td>{{ ($server->installed === 1) ? 'Yes' : 'No' }}</td> <td>{!! ($server->installed === 1) ? '<span class="label label-success">Yes</span>' : '<span class="label label-danger">No</span>' !!}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -213,7 +227,7 @@
<span class="input-group-addon"> <span class="input-group-addon">
<input type="radio" @if($assignment->ip == $server->ip && $assignment->port == $server->port) checked="checked" @endif name="default" value="{{ $assignment->ip }}:{{ $assignment->port }}"/> <input type="radio" @if($assignment->ip == $server->ip && $assignment->port == $server->port) checked="checked" @endif name="default" value="{{ $assignment->ip }}:{{ $assignment->port }}"/>
</span> </span>
<input type="text" class="form-control" value="{{ $assignment->ip }}:{{ $assignment->port }}" readonly /> <input type="text" class="form-control" value="{{ $assignment->ip_alias }}:{{ $assignment->port }}@if($assignment->ip !== $assignment->ip_alias) (alias of {{ $assignment->ip }})@endif" readonly />
</div> </div>
@endforeach @endforeach
</div> </div>
@ -224,7 +238,7 @@
<div> <div>
<select name="add_additional[]" class="form-control" multiple> <select name="add_additional[]" class="form-control" multiple>
@foreach ($unassigned as $assignment) @foreach ($unassigned as $assignment)
<option value="{{ $assignment->ip }}:{{ $assignment->port }}">{{ $assignment->ip }}:{{ $assignment->port }}</option> <option value="{{ $assignment->ip }}:{{ $assignment->port }}">{{ $assignment->ip_alias }}:{{ $assignment->port }}@if($assignment->ip !== $assignment->ip_alias) (alias of {{ $assignment->ip }})@endif</option>
@endforeach @endforeach
</select> </select>
</div> </div>
@ -237,7 +251,7 @@
<div> <div>
<select name="remove_additional[]" class="form-control" multiple> <select name="remove_additional[]" class="form-control" multiple>
@foreach ($assigned as $assignment) @foreach ($assigned as $assignment)
<option value="{{ $assignment->ip }}:{{ $assignment->port }}" @if($assignment->ip == $server->ip && $assignment->port == $server->port) disabled @endif>{{ $assignment->ip }}:{{ $assignment->port }}</option> <option value="{{ $assignment->ip }}:{{ $assignment->port }}" @if($assignment->ip == $server->ip && $assignment->port == $server->port) disabled @endif>{{ $assignment->ip_alias }}:{{ $assignment->port }}@if($assignment->ip !== $assignment->ip_alias) (alias of {{ $assignment->ip }})@endif</option>
@endforeach @endforeach
</select> </select>
</div> </div>

View file

@ -171,7 +171,6 @@
<tr> <tr>
<th>Name</th> <th>Name</th>
<th>Owner</th> <th>Owner</th>
<th>Connection</th>
<th>Updated</th> <th>Updated</th>
</tr> </tr>
</thead> </thead>
@ -180,7 +179,6 @@
<tr> <tr>
<td><a href="{{ route('admin.servers.view', $server->id) }}">{{ $server->name }}</a></td> <td><a href="{{ route('admin.servers.view', $server->id) }}">{{ $server->name }}</a></td>
<td><a href="{{ route('admin.users.view', $server->owner) }}">{{ $server->a_ownerEmail }}</a></td> <td><a href="{{ route('admin.users.view', $server->owner) }}">{{ $server->a_ownerEmail }}</a></td>
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td>
<td>{{ $server->updated_at }}</td> <td>{{ $server->updated_at }}</td>
</tr> </tr>
@endforeach @endforeach

View file

@ -95,9 +95,9 @@
<thead> <thead>
<tr> <tr>
<th style="width:2%;"></th> <th style="width:2%;"></th>
<th>Identifier</th>
<th>Server Name</th> <th>Server Name</th>
<th>Node</th> <th>Node</th>
<th>Connection</th>
<th style="width:10%;"></th> <th style="width:10%;"></th>
</tr> </tr>
</thead> </thead>
@ -105,9 +105,9 @@
@foreach($servers as $server) @foreach($servers as $server)
<tr> <tr>
<td><a href="/server/{{ $server->uuidShort }}/"><i class="fa fa-tachometer"></i></a></td> <td><a href="/server/{{ $server->uuidShort }}/"><i class="fa fa-tachometer"></i></a></td>
<td><code>{{ $server->uuidShort }}</code></td>
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a></td> <td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a></td>
<td>{{ $server->nodeName }}</td> <td>{{ $server->nodeName }}</td>
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td>
<td>@if($server->active)<span class="label label-success">Enabled</span>@else<span class="label label-danger">Disabled</span>@endif</td> <td>@if($server->active)<span class="label label-success">Enabled</span>@else<span class="label label-danger">Disabled</span>@endif</td>
</td> </td>
@endforeach @endforeach

View file

@ -59,7 +59,7 @@
@endif @endif
<td><a href="/server/{{ $server->uuidShort }}">{{ $server->name }}</a></td> <td><a href="/server/{{ $server->uuidShort }}">{{ $server->name }}</a></td>
<td>{{ $server->nodeName }} ({{ $server->a_locationShort }})</td> <td>{{ $server->nodeName }} ({{ $server->a_locationShort }})</td>
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td> <td><code>{{ $server->ip_alias }}:{{ $server->port }}</code></td>
<td class="text-center" data-action="players">--</td> <td class="text-center" data-action="players">--</td>
<td class="text-center"><span data-action="memory">--</span> / {{ $server->memory === 0 ? '&infin;' : $server->memory }} MB</td> <td class="text-center"><span data-action="memory">--</span> / {{ $server->memory === 0 ? '&infin;' : $server->memory }} MB</td>
<td class="text-center"><span data-action="cpu" data-cpumax="{{ $server->cpu }}">--</span> %</td> <td class="text-center"><span data-action="cpu" data-cpumax="{{ $server->cpu }}">--</span> %</td>

View file

@ -94,7 +94,12 @@
<div class="alert alert-info">Below is a listing of all avaliable IPs and Ports for your service. To change the default connection address for your server, simply click on the one you would like to make default below.</div> <div class="alert alert-info">Below is a listing of all avaliable IPs and Ports for your service. To change the default connection address for your server, simply click on the one you would like to make default below.</div>
<ul class="nav nav-pills nav-stacked" id="conn_options"> <ul class="nav nav-pills nav-stacked" id="conn_options">
@foreach ($allocations as $allocation) @foreach ($allocations as $allocation)
<li role="presentation" @if($allocation->ip === $server->ip && $allocation->port === $server->port) class="active" @endif><a href="#/set-connnection/{{ $allocation->ip }}:{{ $allocation->port }}" data-action="set-connection" data-connection="{{ $allocation->ip }}:{{ $allocation->port }}">{{ $allocation->ip }} <span class="badge">{{ $allocation->port }}</span></a></li> <li role="presentation" @if($allocation->id === $server->allocation) class="active" @endif>
<a href="#/set-connnection/{{ $allocation->ip }}:{{ $allocation->port }}" data-action="set-connection" data-connection="{{ $allocation->ip }}:{{ $allocation->port }}">{{ $allocation->ip_alias }}
<span class="badge">{{ $allocation->port }}</span>
@if($allocation->ip !== $allocation->ip_alias)<small><span class="pull-right">Alias for {{ $allocation->ip }}</span></small>@endif
</a>
</li>
@endforeach @endforeach
</ul> </ul>
</div> </div>