server creation wip
This commit is contained in:
22
app/Actions/GenerateRandomSlug.php
Normal file
22
app/Actions/GenerateRandomSlug.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
class GenerateRandomSlug
|
||||
{
|
||||
public function execute($adjectiveCount = 1): string
|
||||
{
|
||||
$adjectives = explode("\n", file_get_contents(resource_path('text/english-adjectives.txt')));
|
||||
$nouns = explode("\n", file_get_contents(resource_path('text/english-nouns.txt')));
|
||||
|
||||
$slug = '';
|
||||
|
||||
for ($i = 0; $i < $adjectiveCount; $i++) {
|
||||
$slug .= $adjectives[array_rand($adjectives)] . '-';
|
||||
}
|
||||
|
||||
$slug .= $nouns[array_rand($nouns)];
|
||||
|
||||
return $slug;
|
||||
}
|
||||
}
|
||||
17
app/Actions/GetProviderService.php
Normal file
17
app/Actions/GetProviderService.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Services\ServerProviders\HetznerService;
|
||||
use App\Services\ServerProviders\ServerProviderService;
|
||||
|
||||
class GetProviderService
|
||||
{
|
||||
public function execute(string $provider): ServerProviderService|null
|
||||
{
|
||||
return match ($provider) {
|
||||
'hetzner' => new HetznerService(),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
15
app/Data/ServerProviders/CreatedServer.php
Normal file
15
app/Data/ServerProviders/CreatedServer.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Data\ServerProviders;
|
||||
|
||||
class CreatedServer
|
||||
{
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public string $rootPassword,
|
||||
public string $id,
|
||||
public string $status,
|
||||
public string $ipv4,
|
||||
public string $ipv6,
|
||||
) {}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ class ServerType
|
||||
/**
|
||||
* @param string $name The name of the server type
|
||||
* @param int $cores The number of cores
|
||||
* @param int $memory The amount of memory in MB
|
||||
* @param int $memory The amount of memory in GB
|
||||
* @param int $disk The amount of disk space in GB
|
||||
*/
|
||||
public function __construct(
|
||||
|
||||
@@ -2,16 +2,100 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\GenerateRandomSlug;
|
||||
use App\Actions\GetProviderService;
|
||||
use App\Enums\ServerProvider;
|
||||
use App\Enums\ServerStatus;
|
||||
use App\Models\Organisation;
|
||||
use App\Services\ServerProviders\HetznerService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Str;
|
||||
use NunoMaduro\Collision\Provider;
|
||||
|
||||
class ServerController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$organisation = Organisation::findOrFail($request->route('organisation'));
|
||||
|
||||
return inertia('servers/Index', [
|
||||
'servers' => $organisation->servers()->paginate(30),
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(Request $request)
|
||||
{
|
||||
$locations = null;
|
||||
$serverTypes = null;
|
||||
$images = null;
|
||||
|
||||
if ($request->has('provider')) {
|
||||
$providerService = app(GetProviderService::class)->execute($request->provider);
|
||||
|
||||
if ($providerService) {
|
||||
$locations = Cache::remember($request->provider . '.locations', now()->addHour(), function () use ($providerService) {
|
||||
return $providerService->getLocations();
|
||||
});
|
||||
$serverTypes = Cache::remember($request->provider . '.serverTypes', now()->addHour(), function () use ($providerService) {
|
||||
return $providerService->getServerTypes();
|
||||
});
|
||||
$images = Cache::remember($request->provider . '.images', now()->addHour(), function () use ($providerService) {
|
||||
return $providerService->getImages();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return inertia('servers/Create', [
|
||||
'locations' => $locations,
|
||||
'serverTypes' => $serverTypes,
|
||||
'images' => $images,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$rootPassword = Str::random(32);
|
||||
$providerService = app(GetProviderService::class)->execute($request->provider);
|
||||
|
||||
if (!$providerService) {
|
||||
return back()->with('error', 'Invalid provider');
|
||||
}
|
||||
|
||||
$createdServer = $providerService->createServer(
|
||||
name: app(GenerateRandomSlug::class)->execute(), // @todo allow custom name
|
||||
serverType: $request->server_type,
|
||||
location: $request->location,
|
||||
image: $request->image,
|
||||
rootPassword: $rootPassword,
|
||||
);
|
||||
|
||||
$organisation = Organisation::findOrFail($request->route('organisation'));
|
||||
|
||||
$server = $organisation->servers()->create([
|
||||
'name' => $createdServer->name,
|
||||
'provider' => ServerProvider::tryFrom($request->provider),
|
||||
'provider_id' => $createdServer->id,
|
||||
'ipv4' => $createdServer->ipv4,
|
||||
'ipv6' => $createdServer->ipv6,
|
||||
'provider_status' => $createdServer->status,
|
||||
'status' => ServerStatus::PENDING,
|
||||
'region' => $request->location,
|
||||
'os' => $request->image,
|
||||
'plan' => $request->server_type,
|
||||
'user' => '',
|
||||
]);
|
||||
|
||||
return redirect()->route('servers.show', ['organisation' => $organisation->id, 'server' => $server->id]);
|
||||
}
|
||||
|
||||
public function show(Request $request)
|
||||
{
|
||||
$organisation = Organisation::findOrFail($request->route('organisation'));
|
||||
$server = $organisation->servers()->findOrFail($request->route('server'));
|
||||
|
||||
return inertia('servers/Show', [
|
||||
'server' => $server,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use Saloon\Enums\Method;
|
||||
use Saloon\Http\Request;
|
||||
use Saloon\Traits\Body\HasJsonBody;
|
||||
|
||||
class ListImagesRequest extends Request
|
||||
class GetImagesRequest extends Request
|
||||
{
|
||||
protected Method $method = Method::GET;
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\Http\Integrations\Requests\Hetzner\Locations;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Http\Request;
|
||||
|
||||
class ListLocationsRequest extends Request
|
||||
class GetLocationsRequest extends Request
|
||||
{
|
||||
protected Method $method = Method::GET;
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\Http\Integrations\Requests\Hetzner\ServerTypes;
|
||||
use Saloon\Enums\Method;
|
||||
use Saloon\Http\Request;
|
||||
|
||||
class ListServerTypesRequest extends Request
|
||||
class GetServerTypesRequest extends Request
|
||||
{
|
||||
protected Method $method = Method::GET;
|
||||
|
||||
@@ -18,6 +18,7 @@ class CreateServerRequest extends Request implements HasBody
|
||||
protected ?string $name = null,
|
||||
protected ?string $serverType = null,
|
||||
protected ?string $location = null,
|
||||
protected ?string $rootPassword = null,
|
||||
) {}
|
||||
|
||||
protected function defaultBody(): array
|
||||
@@ -27,6 +28,7 @@ class CreateServerRequest extends Request implements HasBody
|
||||
'name' => $this->name,
|
||||
'server_type' => $this->serverType,
|
||||
'location' => $this->location,
|
||||
'root_password' => $this->rootPassword,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -2,17 +2,19 @@
|
||||
|
||||
namespace App\Services\ServerProviders;
|
||||
|
||||
use App\Data\ServerProviders\CreatedServer;
|
||||
use App\Data\ServerProviders\Image;
|
||||
use App\Data\ServerProviders\Location;
|
||||
use App\Data\ServerProviders\ServerType;
|
||||
use App\Http\Integrations\Connectors\HetznerConnector;
|
||||
use App\Http\Integrations\Requests\Hetzner\Images\ListImagesRequest;
|
||||
use App\Http\Integrations\Requests\Hetzner\Locations\ListLocationsRequest;
|
||||
use App\Http\Integrations\Requests\Hetzner\ServerTypes\ListServerTypesRequest;
|
||||
use App\Http\Integrations\Requests\Hetzner\Images\GetImagesRequest;
|
||||
use App\Http\Integrations\Requests\Hetzner\Locations\GetLocationsRequest;
|
||||
use App\Http\Integrations\Requests\Hetzner\Servers\CreateServerRequest;
|
||||
use App\Http\Integrations\Requests\Hetzner\ServerTypes\GetServerTypesRequest;
|
||||
use Exception;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class HetznerService implements ServerProviderService
|
||||
class HetznerService extends ServerProviderService
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
@@ -24,13 +26,33 @@ class HetznerService implements ServerProviderService
|
||||
string $serverType,
|
||||
string $location,
|
||||
string $image,
|
||||
): bool {
|
||||
return false;
|
||||
string $rootPassword,
|
||||
): CreatedServer {
|
||||
$response = $this->connector->send(new CreateServerRequest(
|
||||
image: $image,
|
||||
name: $name,
|
||||
serverType: $serverType,
|
||||
location: $location,
|
||||
rootPassword: $rootPassword,
|
||||
));
|
||||
|
||||
if ($response->status() !== 201) {
|
||||
throw new Exception('Failed to create server on Hetzner');
|
||||
}
|
||||
|
||||
return new CreatedServer(
|
||||
id: $response->json('server.id'),
|
||||
name: $name,
|
||||
rootPassword: $rootPassword,
|
||||
status: $response->json('server.status')['status'],
|
||||
ipv4: $response->json('server.public_net.ipv4.ip'),
|
||||
ipv6: $response->json('server.public_net.ipv6.ip'),
|
||||
);
|
||||
}
|
||||
|
||||
public function listServerTypes(): Collection
|
||||
public function getServerTypes(): Collection
|
||||
{
|
||||
$response = $this->connector->send(new ListServerTypesRequest);
|
||||
$response = $this->connector->send(new GetServerTypesRequest);
|
||||
|
||||
if ($response->status() !== 200) {
|
||||
throw new Exception('Failed to fetch server types from Hetzner');
|
||||
@@ -41,17 +63,17 @@ class HetznerService implements ServerProviderService
|
||||
id: $serverType['id'],
|
||||
name: $serverType['name'],
|
||||
cores: $serverType['cores'],
|
||||
memory: $serverType['memory'] * 1024,
|
||||
memory: $serverType['memory'],
|
||||
disk: $serverType['disk'],
|
||||
priceMonthly: $serverType['prices'][0]['monthly']['gross'] ?? 0,
|
||||
priceHourly: $serverType['prices'][0]['hourly']['gross'] ?? 0,
|
||||
);
|
||||
});
|
||||
})->values();
|
||||
}
|
||||
|
||||
public function listLocations(): Collection
|
||||
public function getLocations(): Collection
|
||||
{
|
||||
$response = $this->connector->send(new ListLocationsRequest);
|
||||
$response = $this->connector->send(new GetLocationsRequest);
|
||||
|
||||
if ($response->status() !== 200) {
|
||||
throw new Exception('Failed to fetch locations from Hetzner');
|
||||
@@ -64,12 +86,12 @@ class HetznerService implements ServerProviderService
|
||||
country: $location['country'],
|
||||
city: $location['city'],
|
||||
);
|
||||
});
|
||||
})->values();
|
||||
}
|
||||
|
||||
public function listImages(): Collection
|
||||
public function getImages(): Collection
|
||||
{
|
||||
$response = $this->connector->send(new ListImagesRequest(
|
||||
$response = $this->connector->send(new GetImagesRequest(
|
||||
architecture: 'x86',
|
||||
));
|
||||
|
||||
@@ -84,6 +106,6 @@ class HetznerService implements ServerProviderService
|
||||
osFlavor: $image['os_flavor'],
|
||||
osVersion: $image['os_version'],
|
||||
);
|
||||
});
|
||||
})->values();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,25 @@
|
||||
|
||||
namespace App\Services\ServerProviders;
|
||||
|
||||
use App\Data\ServerProviders\CreatedServer;
|
||||
use Illuminate\Support\Collection;
|
||||
use Saloon\Http\Connector;
|
||||
|
||||
interface ServerProviderService
|
||||
abstract class ServerProviderService
|
||||
{
|
||||
protected Connector $connector;
|
||||
|
||||
public function createServer(
|
||||
abstract public function createServer(
|
||||
string $name,
|
||||
string $serverType,
|
||||
string $location,
|
||||
string $image,
|
||||
): bool;
|
||||
string $rootPassword,
|
||||
): CreatedServer;
|
||||
|
||||
public function listServerTypes(): Collection;
|
||||
abstract public function getServerTypes(): Collection;
|
||||
|
||||
public function listLocations(): Collection;
|
||||
abstract public function getLocations(): Collection;
|
||||
|
||||
public function listImages(): Collection;
|
||||
abstract public function getImages(): Collection;
|
||||
}
|
||||
Reference in New Issue
Block a user