diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php index 024ef35fa..cbee00642 100644 --- a/app/Http/Controllers/Api/ServersController.php +++ b/app/Http/Controllers/Api/ServersController.php @@ -426,6 +426,7 @@ class ServersController extends Controller 'private_key_uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the private key.'], 'is_build_server' => ['type' => 'boolean', 'example' => false, 'description' => 'Is build server.'], 'instant_validate' => ['type' => 'boolean', 'example' => false, 'description' => 'Instant validate.'], + 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'example' => 'traefik', 'description' => 'The proxy type.'], ], ), ), @@ -461,7 +462,7 @@ class ServersController extends Controller )] public function create_server(Request $request) { - $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate']; + $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate', 'proxy_type']; $teamId = getTeamIdFromToken(); if (is_null($teamId)) { @@ -481,6 +482,7 @@ class ServersController extends Controller 'user' => 'string|nullable', 'is_build_server' => 'boolean|nullable', 'instant_validate' => 'boolean|nullable', + 'proxy_type' => 'string|nullable', ]); $extraFields = array_diff(array_keys($request->all()), $allowedFields); @@ -512,6 +514,14 @@ class ServersController extends Controller if (is_null($request->instant_validate)) { $request->offsetSet('instant_validate', false); } + if ($request->proxy_type) { + $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) { + return str($proxyType->value)->lower(); + }); + if (! $validProxyTypes->contains(str($request->proxy_type)->lower())) { + return response()->json(['message' => 'Invalid proxy type.'], 422); + } + } $privateKey = PrivateKey::whereTeamId($teamId)->whereUuid($request->private_key_uuid)->first(); if (! $privateKey) { return response()->json(['message' => 'Private key not found.'], 404); @@ -521,6 +531,8 @@ class ServersController extends Controller return response()->json(['message' => 'Server with this IP already exists.'], 400); } + $proxyType = $request->proxy_type ? str($request->proxy_type)->upper() : ProxyTypes::TRAEFIK->value; + $server = ModelsServer::create([ 'name' => $request->name, 'description' => $request->description, @@ -530,7 +542,7 @@ class ServersController extends Controller 'private_key_id' => $privateKey->id, 'team_id' => $teamId, 'proxy' => [ - 'type' => ProxyTypes::TRAEFIK->value, + 'type' => $proxyType, 'status' => ProxyStatus::EXITED->value, ], ]); @@ -571,6 +583,7 @@ class ServersController extends Controller 'private_key_uuid' => ['type' => 'string', 'description' => 'The UUID of the private key.'], 'is_build_server' => ['type' => 'boolean', 'description' => 'Is build server.'], 'instant_validate' => ['type' => 'boolean', 'description' => 'Instant validate.'], + 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'description' => 'The proxy type.'], ], ), ), @@ -604,7 +617,7 @@ class ServersController extends Controller )] public function update_server(Request $request) { - $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate']; + $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate', 'proxy_type']; $teamId = getTeamIdFromToken(); if (is_null($teamId)) { @@ -624,6 +637,7 @@ class ServersController extends Controller 'user' => 'string|nullable', 'is_build_server' => 'boolean|nullable', 'instant_validate' => 'boolean|nullable', + 'proxy_type' => 'string|nullable', ]); $extraFields = array_diff(array_keys($request->all()), $allowedFields); @@ -644,6 +658,16 @@ class ServersController extends Controller if (! $server) { return response()->json(['message' => 'Server not found.'], 404); } + if ($request->proxy_type) { + $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) { + return str($proxyType->value)->lower(); + }); + if ($validProxyTypes->contains(str($request->proxy_type)->lower())) { + $server->changeProxy($request->proxy_type, async: true); + } else { + return response()->json(['message' => 'Invalid proxy type.'], 422); + } + } $server->update($request->only(['name', 'description', 'ip', 'port', 'user'])); if ($request->is_build_server) { $server->settings()->update([ @@ -654,7 +678,9 @@ class ServersController extends Controller ValidateServer::dispatch($server)->onQueue('high'); } - return response()->json(serializeApiResponse($server))->setStatusCode(201); + return response()->json([ + + ])->setStatusCode(201); } #[OA\Delete( diff --git a/app/Livewire/Server/Proxy.php b/app/Livewire/Server/Proxy.php index 94ea3509a..0b069ddb9 100644 --- a/app/Livewire/Server/Proxy.php +++ b/app/Livewire/Server/Proxy.php @@ -4,7 +4,6 @@ namespace App\Livewire\Server; use App\Actions\Proxy\CheckConfiguration; use App\Actions\Proxy\SaveConfiguration; -use App\Actions\Proxy\StartProxy; use App\Models\Server; use Livewire\Component; @@ -44,14 +43,13 @@ class Proxy extends Component public function selectProxy($proxy_type) { - $this->server->proxy->set('status', 'exited'); - $this->server->proxy->set('type', $proxy_type); - $this->server->save(); - $this->selectedProxy = $this->server->proxy->type; - if ($this->server->proxySet()) { - StartProxy::run($this->server, false); + try { + $this->server->changeProxy($proxy_type, async: false); + $this->selectedProxy = $this->server->proxy->type; + $this->dispatch('proxyStatusUpdated'); + } catch (\Throwable $e) { + return handleError($e, $this); } - $this->dispatch('proxyStatusUpdated'); } public function instantSave() diff --git a/app/Models/Server.php b/app/Models/Server.php index 515e5b9c7..3df156a78 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Actions\Proxy\StartProxy; use App\Actions\Server\InstallDocker; use App\Actions\Server\StartSentinel; use App\Enums\ProxyTypes; @@ -26,22 +27,23 @@ use Symfony\Component\Yaml\Yaml; description: 'Server model', type: 'object', properties: [ - 'id' => ['type' => 'integer'], - 'uuid' => ['type' => 'string'], - 'name' => ['type' => 'string'], - 'description' => ['type' => 'string'], - 'ip' => ['type' => 'string'], - 'user' => ['type' => 'string'], - 'port' => ['type' => 'integer'], - 'proxy' => ['type' => 'object'], - 'high_disk_usage_notification_sent' => ['type' => 'boolean'], - 'unreachable_notification_sent' => ['type' => 'boolean'], - 'unreachable_count' => ['type' => 'integer'], - 'validation_logs' => ['type' => 'string'], - 'log_drain_notification_sent' => ['type' => 'boolean'], - 'swarm_cluster' => ['type' => 'string'], - 'delete_unused_volumes' => ['type' => 'boolean'], - 'delete_unused_networks' => ['type' => 'boolean'], + 'id' => ['type' => 'integer', 'description' => 'The server ID.'], + 'uuid' => ['type' => 'string', 'description' => 'The server UUID.'], + 'name' => ['type' => 'string', 'description' => 'The server name.'], + 'description' => ['type' => 'string', 'description' => 'The server description.'], + 'ip' => ['type' => 'string', 'description' => 'The IP address.'], + 'user' => ['type' => 'string', 'description' => 'The user.'], + 'port' => ['type' => 'integer', 'description' => 'The port number.'], + 'proxy' => ['type' => 'object', 'description' => 'The proxy configuration.'], + 'proxy_type' => ['type' => 'string', 'enum' => ['traefik', 'caddy', 'none'], 'description' => 'The proxy type.'], + 'high_disk_usage_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the high disk usage notification has been sent.'], + 'unreachable_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unreachable notification has been sent.'], + 'unreachable_count' => ['type' => 'integer', 'description' => 'The unreachable count for your server.'], + 'validation_logs' => ['type' => 'string', 'description' => 'The validation logs.'], + 'log_drain_notification_sent' => ['type' => 'boolean', 'description' => 'The flag to indicate if the log drain notification has been sent.'], + 'swarm_cluster' => ['type' => 'string', 'description' => 'The swarm cluster configuration.'], + 'delete_unused_volumes' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused volumes should be deleted.'], + 'delete_unused_networks' => ['type' => 'boolean', 'description' => 'The flag to indicate if the unused networks should be deleted.'], ] )] @@ -1251,4 +1253,25 @@ $schema://$host { { return instant_remote_process(['docker restart '.$containerName], $this, false); } + + public function changeProxy(string $proxyType, bool $async = true) + { + $validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) { + return str($proxyType->value)->lower(); + }); + if ($validProxyTypes->contains(str($proxyType)->lower())) { + $this->proxy->set('type', str($proxyType)->upper()); + $this->proxy->set('status', 'exited'); + $this->save(); + if ($this->proxySet()) { + if ($async) { + StartProxy::dispatch($this); + } else { + StartProxy::run($this); + } + } + } else { + throw new \Exception('Invalid proxy type.'); + } + } } diff --git a/openapi.json b/openapi.json index 72ef66393..cdcd47f40 100644 --- a/openapi.json +++ b/openapi.json @@ -5234,6 +5234,16 @@ "type": "boolean", "example": false, "description": "Instant validate." + }, + "proxy_type": { + "type": "string", + "enum": [ + "traefik", + "caddy", + "none" + ], + "example": "traefik", + "description": "The proxy type." } }, "type": "object" @@ -5419,6 +5429,15 @@ "instant_validate": { "type": "boolean", "description": "Instant validate." + }, + "proxy_type": { + "type": "string", + "enum": [ + "traefik", + "caddy", + "none" + ], + "description": "The proxy type." } }, "type": "object" @@ -7358,52 +7377,77 @@ "description": "Server model", "properties": { "id": { - "type": "integer" + "type": "integer", + "description": "The server ID." }, "uuid": { - "type": "string" + "type": "string", + "description": "The server UUID." }, "name": { - "type": "string" + "type": "string", + "description": "The server name." }, "description": { - "type": "string" + "type": "string", + "description": "The server description." }, "ip": { - "type": "string" + "type": "string", + "description": "The IP address." }, "user": { - "type": "string" + "type": "string", + "description": "The user." }, "port": { - "type": "integer" + "type": "integer", + "description": "The port number." }, "proxy": { - "type": "object" + "type": "object", + "description": "The proxy configuration." + }, + "proxy_type": { + "type": "string", + "enum": [ + "traefik", + "caddy", + "none" + ], + "description": "The proxy type." }, "high_disk_usage_notification_sent": { - "type": "boolean" + "type": "boolean", + "description": "The flag to indicate if the high disk usage notification has been sent." }, "unreachable_notification_sent": { - "type": "boolean" + "type": "boolean", + "description": "The flag to indicate if the unreachable notification has been sent." }, "unreachable_count": { - "type": "integer" + "type": "integer", + "description": "The unreachable count for your server." }, "validation_logs": { - "type": "string" + "type": "string", + "description": "The validation logs." }, "log_drain_notification_sent": { - "type": "boolean" + "type": "boolean", + "description": "The flag to indicate if the log drain notification has been sent." }, "swarm_cluster": { - "type": "string" + "type": "string", + "description": "The swarm cluster configuration." }, "delete_unused_volumes": { - "type": "boolean" + "type": "boolean", + "description": "The flag to indicate if the unused volumes should be deleted." }, "delete_unused_networks": { - "type": "boolean" + "type": "boolean", + "description": "The flag to indicate if the unused networks should be deleted." } }, "type": "object" diff --git a/openapi.yaml b/openapi.yaml index 6794b2652..2b1ece41c 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -3577,6 +3577,11 @@ paths: type: boolean example: false description: 'Instant validate.' + proxy_type: + type: string + enum: [traefik, caddy, none] + example: traefik + description: 'The proxy type.' type: object responses: '201': @@ -3697,6 +3702,10 @@ paths: instant_validate: type: boolean description: 'Instant validate.' + proxy_type: + type: string + enum: [traefik, caddy, none] + description: 'The proxy type.' type: object responses: '201': @@ -4911,36 +4920,59 @@ components: properties: id: type: integer + description: 'The server ID.' uuid: type: string + description: 'The server UUID.' name: type: string + description: 'The server name.' description: type: string + description: 'The server description.' ip: type: string + description: 'The IP address.' user: type: string + description: 'The user.' port: type: integer + description: 'The port number.' proxy: type: object + description: 'The proxy configuration.' + proxy_type: + type: string + enum: + - traefik + - caddy + - none + description: 'The proxy type.' high_disk_usage_notification_sent: type: boolean + description: 'The flag to indicate if the high disk usage notification has been sent.' unreachable_notification_sent: type: boolean + description: 'The flag to indicate if the unreachable notification has been sent.' unreachable_count: type: integer + description: 'The unreachable count for your server.' validation_logs: type: string + description: 'The validation logs.' log_drain_notification_sent: type: boolean + description: 'The flag to indicate if the log drain notification has been sent.' swarm_cluster: type: string + description: 'The swarm cluster configuration.' delete_unused_volumes: type: boolean + description: 'The flag to indicate if the unused volumes should be deleted.' delete_unused_networks: type: boolean + description: 'The flag to indicate if the unused networks should be deleted.' type: object ServerSetting: description: 'Server Settings model'