NetworkZone

This commit is contained in:
2025-05-22 14:51:54 +01:00
parent 7d03b81723
commit bfe0f8eabf
8 changed files with 48 additions and 13 deletions

View File

@@ -9,5 +9,6 @@ class Location
public string $name, public string $name,
public string $country, public string $country,
public string $city, public string $city,
public ?string $networkZone = null,
) {} ) {}
} }

View File

@@ -8,5 +8,6 @@ class Network
public string $id, public string $id,
public string $name, public string $name,
public string $ipRange, public string $ipRange,
public ?string $networkZone = 'global',
) {} ) {}
} }

View File

@@ -63,6 +63,7 @@ class ServerController extends Controller
'server_type' => ['required', 'string'], 'server_type' => ['required', 'string'],
'location' => ['required', 'string'], 'location' => ['required', 'string'],
'image' => ['required', 'string'], 'image' => ['required', 'string'],
'network_zone' => ['nullable', 'string'],
]); ]);
$sudoPassword = Str::random(32); $sudoPassword = Str::random(32);
@@ -74,10 +75,19 @@ class ServerController extends Controller
return back()->with('error', 'Invalid provider'); return back()->with('error', 'Invalid provider');
} }
if (! $network = $provider->networks()->first()) { $networkZone = $request->network_zone ?? 'global';
// we need a keystone network to create this server
// Look for an existing network with the same network_zone
$network = $provider->networks()
->where('network_zone', $networkZone)
->first();
if (! $network) {
// We need to create a network with the correct network zone
$networkName = "keystone-{$networkZone}";
$createdNetwork = $providerService->createNetwork( $createdNetwork = $providerService->createNetwork(
name: 'keystone', name: $networkName,
networkZone: $networkZone
); );
$network = $provider->networks()->create([ $network = $provider->networks()->create([
@@ -86,6 +96,7 @@ class ServerController extends Controller
'type' => NetworkType::EXTERNAL, 'type' => NetworkType::EXTERNAL,
'name' => $createdNetwork->name, 'name' => $createdNetwork->name,
'ip_range' => $createdNetwork->ipRange, 'ip_range' => $createdNetwork->ipRange,
'network_zone' => $networkZone,
]); ]);
} }

View File

@@ -15,14 +15,27 @@ class CreateNetworkRequest extends Request implements HasBody
public function __construct( public function __construct(
protected ?string $name = null, protected ?string $name = null,
protected ?string $networkZone = null,
) {} ) {}
protected function defaultBody(): array protected function defaultBody(): array
{ {
return [ $body = [
'name' => $this->name, 'name' => $this->name,
'ip_range' => '10.0.0.0/16', 'ip_range' => '10.0.0.0/16',
]; ];
if ($this->networkZone) {
$body['subnets'] = [
[
'type' => 'cloud',
'ip_range' => '10.0.1.0/24',
'network_zone' => $this->networkZone
]
];
}
return $body;
} }
public function resolveEndpoint(): string public function resolveEndpoint(): string

View File

@@ -111,6 +111,7 @@ class HetznerService extends ServerProviderService
name: $location['name'], name: $location['name'],
country: $location['country'], country: $location['country'],
city: $location['city'], city: $location['city'],
networkZone: $location['network_zone'] ?? null,
); );
})->values(); })->values();
} }
@@ -135,7 +136,7 @@ class HetznerService extends ServerProviderService
})->where('osVersion', '!=', 'unknown')->values(); })->where('osVersion', '!=', 'unknown')->values();
} }
public function findNetwork(string $name): ?Network public function findNetwork(string $name, ?string $networkZone = null): ?Network
{ {
$response = $this->connector->send(new GetNetworksRequest( $response = $this->connector->send(new GetNetworksRequest(
name: $name, name: $name,
@@ -152,16 +153,18 @@ class HetznerService extends ServerProviderService
id: $network['id'], id: $network['id'],
name: $network['name'], name: $network['name'],
ipRange: $network['ip_range'], ipRange: $network['ip_range'],
networkZone: $networkZone ?? 'global',
); );
} }
return null; return null;
} }
public function createNetwork(string $name): Network public function createNetwork(string $name, ?string $networkZone = null): Network
{ {
$response = $this->connector->send(new CreateNetworkRequest( $response = $this->connector->send(new CreateNetworkRequest(
name: $name, name: $name,
networkZone: $networkZone,
)); ));
if ($response->status() !== 201) { if ($response->status() !== 201) {
@@ -169,6 +172,7 @@ class HetznerService extends ServerProviderService
'response' => $response->json(), 'response' => $response->json(),
'status' => $response->status(), 'status' => $response->status(),
'name' => $name, 'name' => $name,
'networkZone' => $networkZone,
]); ]);
throw new Exception('Failed to create network on Hetzner'); throw new Exception('Failed to create network on Hetzner');
} }
@@ -177,6 +181,7 @@ class HetznerService extends ServerProviderService
id: $response->json('network.id'), id: $response->json('network.id'),
name: $response->json('network.name'), name: $response->json('network.name'),
ipRange: $response->json('network.ip_range'), ipRange: $response->json('network.ip_range'),
networkZone: $response->json('network.network_zone') ?? $networkZone ?? 'global',
); );
} }
} }

View File

@@ -28,7 +28,7 @@ abstract class ServerProviderService
abstract public function getImages(): Collection; abstract public function getImages(): Collection;
abstract public function findNetwork(string $name): ?Network; abstract public function findNetwork(string $name, ?string $networkZone = null): ?Network;
abstract public function createNetwork(string $name): Network; abstract public function createNetwork(string $name, ?string $networkZone = null): Network;
} }

View File

@@ -15,6 +15,7 @@ return new class extends Migration
$table->foreignIdFor(Organisation::class); $table->foreignIdFor(Organisation::class);
$table->foreignIdFor(Provider::class); $table->foreignIdFor(Provider::class);
$table->string('external_id')->nullable(); $table->string('external_id')->nullable();
$table->string('network_zone')->default('global');
$table->string('type'); $table->string('type');
$table->string('name'); $table->string('name');
$table->string('ip_range'); $table->string('ip_range');

View File

@@ -15,23 +15,26 @@ const props = defineProps({
const form = useForm({ const form = useForm({
provider: null, provider: null,
location: null, location: null,
network_zone: null,
server_type: null, server_type: null,
image: null, image: null,
}); });
watch( watch(
() => form.provider, () => form.provider,
(provider) => { () => {
loadLocations(); loadLocations();
}, },
); );
watch ( watch(
() => form.location, () => form.location,
(location) => { (location) => {
const selectedLoc = props.locations.find((loc) => loc.id === location)?.networkZone;
form.network_zone = selectedLoc;
loadServerTypes(); loadServerTypes();
} },
) );
loadLocations(); loadLocations();
loadServerTypes(); loadServerTypes();
@@ -75,7 +78,7 @@ function loadServerTypes() {
}, },
{ {
title: 'Create', title: 'Create',
} },
]" ]"
> >
<div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4"> <div class="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">