Enable ipv6 on frontend (#1350)

This commit is contained in:
Boy132 2025-05-09 08:44:18 +02:00 committed by GitHub
parent 67705b14b4
commit 8406f4686c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 45 additions and 47 deletions

View File

@ -12,8 +12,7 @@ use Filament\Forms\Components\TextInput;
use Filament\Forms\Get; use Filament\Forms\Get;
use Filament\Forms\Set; use Filament\Forms\Set;
use Filament\Resources\RelationManagers\RelationManager; use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables; use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\BulkActionGroup;
use Filament\Tables\Actions\DeleteBulkAction; use Filament\Tables\Actions\DeleteBulkAction;
use Filament\Tables\Columns\SelectColumn; use Filament\Tables\Columns\SelectColumn;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
@ -32,18 +31,12 @@ class AllocationsRelationManager extends RelationManager
public function setTitle(): string public function setTitle(): string
{ {
return trans('admin/server.allocations'); return trans('admin/server.allocations');
} }
public function table(Table $table): Table public function table(Table $table): Table
{ {
return $table return $table
->recordTitleAttribute('ip') ->recordTitleAttribute('address')
// Non Primary Allocations
// ->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->id !== $allocation->server?->allocation_id)
// All assigned allocations
->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->server_id === null) ->checkIfRecordIsSelectableUsing(fn (Allocation $allocation) => $allocation->server_id === null)
->paginationPageOptions(['10', '20', '50', '100', '200', '500']) ->paginationPageOptions(['10', '20', '50', '100', '200', '500'])
->searchable() ->searchable()
@ -72,14 +65,14 @@ class AllocationsRelationManager extends RelationManager
->label(trans('admin/node.table.ip')), ->label(trans('admin/node.table.ip')),
]) ])
->headerActions([ ->headerActions([
Tables\Actions\Action::make('create new allocation') Action::make('create new allocation')
->label(trans('admin/node.create_allocation')) ->label(trans('admin/node.create_allocation'))
->form(fn () => [ ->form(fn () => [
Select::make('allocation_ip') Select::make('allocation_ip')
->options(collect($this->getOwnerRecord()->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip])) ->options(collect($this->getOwnerRecord()->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip]))
->label(trans('admin/node.ip_address')) ->label(trans('admin/node.ip_address'))
->inlineLabel() ->inlineLabel()
->ipv4() ->ip()
->helperText(trans('admin/node.ip_help')) ->helperText(trans('admin/node.ip_help'))
->afterStateUpdated(fn (Set $set) => $set('allocation_ports', [])) ->afterStateUpdated(fn (Set $set) => $set('allocation_ports', []))
->live() ->live()
@ -96,19 +89,15 @@ class AllocationsRelationManager extends RelationManager
->inlineLabel() ->inlineLabel()
->live() ->live()
->disabled(fn (Get $get) => empty($get('allocation_ip'))) ->disabled(fn (Get $get) => empty($get('allocation_ip')))
->afterStateUpdated(fn ($state, Set $set, Get $get) => $set('allocation_ports', ->afterStateUpdated(fn ($state, Set $set, Get $get) => $set('allocation_ports', CreateServer::retrieveValidPorts($this->getOwnerRecord(), $state, $get('allocation_ip'))))
CreateServer::retrieveValidPorts($this->getOwnerRecord(), $state, $get('allocation_ip')))
)
->splitKeys(['Tab', ' ', ',']) ->splitKeys(['Tab', ' ', ','])
->required(), ->required(),
]) ])
->action(fn (array $data, AssignmentService $service) => $service->handle($this->getOwnerRecord(), $data)), ->action(fn (array $data, AssignmentService $service) => $service->handle($this->getOwnerRecord(), $data)),
]) ])
->bulkActions([ ->groupedBulkActions([
BulkActionGroup::make([ DeleteBulkAction::make()
DeleteBulkAction::make() ->authorize(fn () => auth()->user()->can('update node')),
->authorize(fn () => auth()->user()->can('update node')),
]),
]); ]);
} }
} }

View File

@ -189,10 +189,7 @@ class CreateServer extends CreateRecord
$set('allocation_additional', null); $set('allocation_additional', null);
$set('allocation_additional.needstobeastringhere.extra_allocations', null); $set('allocation_additional.needstobeastringhere.extra_allocations', null);
}) })
->getOptionLabelFromRecordUsing( ->getOptionLabelFromRecordUsing(fn (Allocation $allocation) => $allocation->address)
fn (Allocation $allocation) => "$allocation->ip:$allocation->port" .
($allocation->ip_alias ? " ($allocation->ip_alias)" : '')
)
->placeholder(function (Get $get) { ->placeholder(function (Get $get) {
$node = Node::find($get('node_id')); $node = Node::find($get('node_id'));
@ -218,7 +215,7 @@ class CreateServer extends CreateRecord
->label(trans('admin/server.ip_address'))->inlineLabel() ->label(trans('admin/server.ip_address'))->inlineLabel()
->helperText(trans('admin/server.ip_address_helper')) ->helperText(trans('admin/server.ip_address_helper'))
->afterStateUpdated(fn (Set $set) => $set('allocation_ports', [])) ->afterStateUpdated(fn (Set $set) => $set('allocation_ports', []))
->ipv4() ->ip()
->live() ->live()
->required(), ->required(),
TextInput::make('allocation_alias') TextInput::make('allocation_alias')
@ -269,10 +266,7 @@ class CreateServer extends CreateRecord
->columnSpan(2) ->columnSpan(2)
->disabled(fn (Get $get) => $get('../../node_id') === null) ->disabled(fn (Get $get) => $get('../../node_id') === null)
->searchable(['ip', 'port', 'ip_alias']) ->searchable(['ip', 'port', 'ip_alias'])
->getOptionLabelFromRecordUsing( ->getOptionLabelFromRecordUsing(fn (Allocation $allocation) => $allocation->address)
fn (Allocation $allocation) => "$allocation->ip:$allocation->port" .
($allocation->ip_alias ? " ($allocation->ip_alias)" : '')
)
->placeholder(trans('admin/server.select_additional')) ->placeholder(trans('admin/server.select_additional'))
->disableOptionsWhenSelectedInSiblingRepeaterItems() ->disableOptionsWhenSelectedInSiblingRepeaterItems()
->relationship( ->relationship(

View File

@ -16,6 +16,7 @@ use Filament\Support\Exceptions\Halt;
use Filament\Tables\Actions\Action; use Filament\Tables\Actions\Action;
use Filament\Tables\Actions\AssociateAction; use Filament\Tables\Actions\AssociateAction;
use Filament\Tables\Actions\CreateAction; use Filament\Tables\Actions\CreateAction;
use Filament\Tables\Actions\DissociateAction;
use Filament\Tables\Actions\DissociateBulkAction; use Filament\Tables\Actions\DissociateBulkAction;
use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn; use Filament\Tables\Columns\TextColumn;
@ -34,15 +35,18 @@ class AllocationsRelationManager extends RelationManager
{ {
return $table return $table
->selectCurrentPageOnly() ->selectCurrentPageOnly()
->recordTitleAttribute('ip') ->recordTitleAttribute('address')
->recordTitle(fn (Allocation $allocation) => "$allocation->ip:$allocation->port") ->recordTitle(fn (Allocation $allocation) => $allocation->address)
->checkIfRecordIsSelectableUsing(fn (Allocation $record) => $record->id !== $this->getOwnerRecord()->allocation_id) ->checkIfRecordIsSelectableUsing(fn (Allocation $record) => $record->id !== $this->getOwnerRecord()->allocation_id)
->inverseRelationship('server') ->inverseRelationship('server')
->heading(trans('admin/server.allocations')) ->heading(trans('admin/server.allocations'))
->columns([ ->columns([
TextColumn::make('ip')->label(trans('admin/server.ip_address')), TextColumn::make('ip')
TextColumn::make('port')->label(trans('admin/server.port')), ->label(trans('admin/server.ip_address')),
TextInputColumn::make('ip_alias')->label(trans('admin/server.alias')), TextColumn::make('port')
->label(trans('admin/server.port')),
TextInputColumn::make('ip_alias')
->label(trans('admin/server.alias')),
IconColumn::make('primary') IconColumn::make('primary')
->icon(fn ($state) => match ($state) { ->icon(fn ($state) => match ($state) {
true => 'tabler-star-filled', true => 'tabler-star-filled',
@ -58,8 +62,11 @@ class AllocationsRelationManager extends RelationManager
]) ])
->actions([ ->actions([
Action::make('make-primary') Action::make('make-primary')
->label(trans('admin/server.make_primary'))
->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id]) && $this->deselectAllTableRecords()) ->action(fn (Allocation $allocation) => $this->getOwnerRecord()->update(['allocation_id' => $allocation->id]) && $this->deselectAllTableRecords())
->label(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id ? '' : trans('admin/server.make_primary')), ->hidden(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id),
DissociateAction::make()
->hidden(fn (Allocation $allocation) => $allocation->id === $this->getOwnerRecord()->allocation_id),
]) ])
->headerActions([ ->headerActions([
CreateAction::make()->label(trans('admin/server.create_allocation')) CreateAction::make()->label(trans('admin/server.create_allocation'))
@ -69,7 +76,7 @@ class AllocationsRelationManager extends RelationManager
->options(collect($this->getOwnerRecord()->node->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip])) ->options(collect($this->getOwnerRecord()->node->ipAddresses())->mapWithKeys(fn (string $ip) => [$ip => $ip]))
->label(trans('admin/server.ip_address')) ->label(trans('admin/server.ip_address'))
->inlineLabel() ->inlineLabel()
->ipv4() ->ip()
->live() ->live()
->afterStateUpdated(fn (Set $set) => $set('allocation_ports', [])) ->afterStateUpdated(fn (Set $set) => $set('allocation_ports', []))
->required(), ->required(),
@ -85,9 +92,7 @@ class AllocationsRelationManager extends RelationManager
->inlineLabel() ->inlineLabel()
->live() ->live()
->disabled(fn (Get $get) => empty($get('allocation_ip'))) ->disabled(fn (Get $get) => empty($get('allocation_ip')))
->afterStateUpdated(fn ($state, Set $set, Get $get) => $set('allocation_ports', ->afterStateUpdated(fn ($state, Set $set, Get $get) => $set('allocation_ports', CreateServer::retrieveValidPorts($this->getOwnerRecord()->node, $state, $get('allocation_ip'))))
CreateServer::retrieveValidPorts($this->getOwnerRecord()->node, $state, $get('allocation_ip')))
)
->splitKeys(['Tab', ' ', ',']) ->splitKeys(['Tab', ' ', ','])
->required(), ->required(),
]) ])

View File

@ -117,7 +117,7 @@ class Allocation extends Model
protected function address(): Attribute protected function address(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => "$this->alias:$this->port", get: fn () => (is_ipv6($this->alias) ? "[$this->alias]" : $this->alias) . ":$this->port",
); );
} }

View File

@ -403,10 +403,11 @@ class Node extends Model implements Validatable
} }
} }
// Only IPV4 $ips = $ips->filter(fn (string $ip) => is_ip($ip));
$ips = $ips->filter(fn (string $ip) => filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false);
// TODO: remove later
$ips->push('0.0.0.0'); $ips->push('0.0.0.0');
$ips->push('::');
return $ips->unique()->all(); return $ips->unique()->all();
}); });

View File

@ -51,12 +51,7 @@ class AssignmentService
} }
try { try {
// TODO: how should we approach supporting IPv6 with this? $parsed = Network::parse($data['allocation_ip']);
// gethostbyname only supports IPv4, but the alternative (dns_get_record) returns
// an array of records, which is not ideal for this use case, we need a SINGLE
// IP to use, not multiple.
$underlying = gethostbyname($data['allocation_ip']);
$parsed = Network::parse($underlying);
} catch (\Exception $exception) { } catch (\Exception $exception) {
throw new DisplayException("Could not parse provided allocation IP address ({$data['allocation_ip']}): {$exception->getMessage()}", $exception); throw new DisplayException("Could not parse provided allocation IP address ({$data['allocation_ip']}): {$exception->getMessage()}", $exception);
} }

View File

@ -18,6 +18,20 @@ if (!function_exists('is_ip')) {
} }
} }
if (!function_exists('is_ipv4')) {
function is_ipv4(?string $address): bool
{
return $address !== null && filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
}
}
if (!function_exists('is_ipv6')) {
function is_ipv6(?string $address): bool
{
return $address !== null && filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false;
}
}
if (!function_exists('convert_bytes_to_readable')) { if (!function_exists('convert_bytes_to_readable')) {
function convert_bytes_to_readable(int $bytes, int $decimals = 2, ?int $base = null): string function convert_bytes_to_readable(int $bytes, int $decimals = 2, ?int $base = null): string
{ {