diff --git a/app/Actions/Proxy/CheckConfiguration.php b/app/Actions/Proxy/CheckConfiguration.php
index 3cbd5669d..f4fe650c5 100644
--- a/app/Actions/Proxy/CheckConfiguration.php
+++ b/app/Actions/Proxy/CheckConfiguration.php
@@ -21,7 +21,6 @@ public function handle(Server $server, bool $reset = false)
"cat $proxy_path/docker-compose.yml",
];
$proxy_configuration = instant_remote_process($payload, $server, false);
-
if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value;
}
diff --git a/app/Actions/Server/ValidateServer.php b/app/Actions/Server/ValidateServer.php
new file mode 100644
index 000000000..d0a4cd6be
--- /dev/null
+++ b/app/Actions/Server/ValidateServer.php
@@ -0,0 +1,67 @@
+update([
+ 'validation_logs' => null,
+ ]);
+ ['uptime' => $this->uptime, 'error' => $error] = $server->validateConnection();
+ if (! $this->uptime) {
+ $this->error = 'Server is not reachable. Please validate your configuration and connection.
Check this documentation for further help.
Error: '.$error.'
';
+ $server->update([
+ 'validation_logs' => $this->error,
+ ]);
+ throw new \Exception($this->error);
+ }
+ $this->supported_os_type = $server->validateOS();
+ if (! $this->supported_os_type) {
+ $this->error = 'Server OS type is not supported. Please install Docker manually before continuing: documentation.';
+ $server->update([
+ 'validation_logs' => $this->error,
+ ]);
+ throw new \Exception($this->error);
+ }
+
+ $this->docker_installed = $server->validateDockerEngine();
+ $this->docker_compose_installed = $server->validateDockerCompose();
+ if (! $this->docker_installed || ! $this->docker_compose_installed) {
+ $this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: documentation.';
+ $server->update([
+ 'validation_logs' => $this->error,
+ ]);
+ throw new \Exception($this->error);
+ }
+ $this->docker_version = $server->validateDockerEngineVersion();
+
+ if ($this->docker_version) {
+ return 'OK';
+ } else {
+ $this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: documentation.';
+ $server->update([
+ 'validation_logs' => $this->error,
+ ]);
+ throw new \Exception($this->error);
+ }
+ }
+}
diff --git a/app/Http/Controllers/Api/ProjectController.php b/app/Http/Controllers/Api/ProjectController.php
index 6ae1825e9..1de8126d9 100644
--- a/app/Http/Controllers/Api/ProjectController.php
+++ b/app/Http/Controllers/Api/ProjectController.php
@@ -167,7 +167,7 @@ public function environment_details(Request $request)
schema: new OA\Schema(
type: 'object',
properties: [
- 'name' => ['type' => 'string', 'description' => 'The name of the project.'],
+ 'uuid' => ['type' => 'string', 'description' => 'The name of the project.'],
'description' => ['type' => 'string', 'description' => 'The description of the project.'],
],
),
@@ -183,9 +183,7 @@ public function environment_details(Request $request)
schema: new OA\Schema(
type: 'object',
properties: [
- 'uuid' => ['type' => 'string', 'example' => 'og888os'],
- 'name' => ['type' => 'string', 'example' => 'Project Name'],
- 'description' => ['type' => 'string', 'example' => 'Project Description'],
+ 'uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the project.'],
]
)
),
@@ -218,7 +216,7 @@ public function create_project(Request $request)
return $return;
}
$validator = customApiValidator($request->all(), [
- 'name' => 'string|max:255',
+ 'name' => 'string|max:255|required',
'description' => 'string|nullable',
]);
@@ -245,8 +243,6 @@ public function create_project(Request $request)
return response()->json([
'uuid' => $project->uuid,
- 'name' => $project->name,
- 'description' => $project->description,
])->setStatusCode(201);
}
diff --git a/app/Http/Controllers/Api/ServersController.php b/app/Http/Controllers/Api/ServersController.php
index da9c3b2d8..b3c429270 100644
--- a/app/Http/Controllers/Api/ServersController.php
+++ b/app/Http/Controllers/Api/ServersController.php
@@ -2,8 +2,12 @@
namespace App\Http\Controllers\Api;
+use App\Actions\Server\ValidateServer;
+use App\Enums\ProxyStatus;
+use App\Enums\ProxyTypes;
use App\Http\Controllers\Controller;
use App\Models\Application;
+use App\Models\PrivateKey;
use App\Models\Project;
use App\Models\Server as ModelsServer;
use Illuminate\Http\Request;
@@ -75,7 +79,7 @@ public function servers(Request $request)
if (is_null($teamId)) {
return invalidTokenResponse();
}
- $servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port')->get()->load(['settings'])->map(function ($server) {
+ $servers = ModelsServer::whereTeamId($teamId)->select('id', 'name', 'uuid', 'ip', 'user', 'port', 'description')->get()->load(['settings'])->map(function ($server) {
$server['is_reachable'] = $server->settings->is_reachable;
$server['is_usable'] = $server->settings->is_usable;
@@ -392,4 +396,390 @@ public function domains_by_server(Request $request)
return response()->json(serializeApiResponse($domains));
}
+
+ #[OA\Post(
+ summary: 'Create Server',
+ description: 'Create Server.',
+ path: '/servers',
+ security: [
+ ['bearerAuth' => []],
+ ],
+ tags: ['Servers'],
+ requestBody: new OA\RequestBody(
+ required: true,
+ description: 'Server created.',
+ content: new OA\MediaType(
+ mediaType: 'application/json',
+ schema: new OA\Schema(
+ type: 'object',
+ properties: [
+ 'name' => ['type' => 'string', 'example' => 'My Server', 'description' => 'The name of the server.'],
+ 'description' => ['type' => 'string', 'example' => 'My Server Description', 'description' => 'The description of the server.'],
+ 'ip' => ['type' => 'string', 'example' => '127.0.0.1', 'description' => 'The IP of the server.'],
+ 'port' => ['type' => 'integer', 'example' => 22, 'description' => 'The port of the server.'],
+ 'user' => ['type' => 'string', 'example' => 'root', 'description' => 'The user of the server.'],
+ '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.'],
+ ],
+ ),
+ ),
+ ),
+ responses: [
+ new OA\Response(
+ response: 201,
+ description: 'Server created.',
+ content: [
+ new OA\MediaType(
+ mediaType: 'application/json',
+ schema: new OA\Schema(
+ type: 'object',
+ properties: [
+ 'uuid' => ['type' => 'string', 'example' => 'og888os', 'description' => 'The UUID of the server.'],
+ ]
+ )
+ ),
+ ]),
+ new OA\Response(
+ response: 401,
+ ref: '#/components/responses/401',
+ ),
+ new OA\Response(
+ response: 400,
+ ref: '#/components/responses/400',
+ ),
+ new OA\Response(
+ response: 404,
+ ref: '#/components/responses/404',
+ ),
+ ]
+ )]
+ public function create_server(Request $request)
+ {
+ $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate'];
+
+ $teamId = getTeamIdFromToken();
+ if (is_null($teamId)) {
+ return invalidTokenResponse();
+ }
+
+ $return = validateIncomingRequest($request);
+ if ($return instanceof \Illuminate\Http\JsonResponse) {
+ return $return;
+ }
+ $validator = customApiValidator($request->all(), [
+ 'name' => 'string|max:255',
+ 'description' => 'string|nullable',
+ 'ip' => 'string|required',
+ 'port' => 'integer|nullable',
+ 'private_key_uuid' => 'string|required',
+ 'user' => 'string|nullable',
+ 'is_build_server' => 'boolean|nullable',
+ 'instant_validate' => 'boolean|nullable',
+ ]);
+
+ $extraFields = array_diff(array_keys($request->all()), $allowedFields);
+ if ($validator->fails() || ! empty($extraFields)) {
+ $errors = $validator->errors();
+ if (! empty($extraFields)) {
+ foreach ($extraFields as $field) {
+ $errors->add($field, 'This field is not allowed.');
+ }
+ }
+
+ return response()->json([
+ 'message' => 'Validation failed.',
+ 'errors' => $errors,
+ ], 422);
+ }
+ if (! $request->name) {
+ $request->offsetSet('name', generate_random_name());
+ }
+ if (! $request->user) {
+ $request->offsetSet('user', 'root');
+ }
+ if (is_null($request->port)) {
+ $request->offsetSet('port', 22);
+ }
+ if (is_null($request->is_build_server)) {
+ $request->offsetSet('is_build_server', false);
+ }
+ if (is_null($request->instant_validate)) {
+ $request->offsetSet('instant_validate', false);
+ }
+ $privateKey = PrivateKey::whereTeamId($teamId)->whereUuid($request->private_key_uuid)->first();
+ if (! $privateKey) {
+ return response()->json(['message' => 'Private key not found.'], 404);
+ }
+ $allServers = ModelsServer::whereIp($request->ip)->get();
+ if ($allServers->count() > 0) {
+ return response()->json(['message' => 'Server with this IP already exists.'], 400);
+ }
+
+ $server = ModelsServer::create([
+ 'name' => $request->name,
+ 'description' => $request->description,
+ 'ip' => $request->ip,
+ 'port' => $request->port,
+ 'user' => $request->user,
+ 'private_key_id' => $privateKey->id,
+ 'team_id' => $teamId,
+ 'proxy' => [
+ 'type' => ProxyTypes::TRAEFIK_V2->value,
+ 'status' => ProxyStatus::EXITED->value,
+ ],
+ ]);
+ $server->settings()->update([
+ 'is_build_server' => $request->is_build_server,
+ ]);
+ if ($request->instant_validate) {
+ ValidateServer::dispatch($server);
+ }
+
+ return response()->json([
+ 'uuid' => $server->uuid,
+ ])->setStatusCode(201);
+ }
+
+ #[OA\Patch(
+ summary: 'Update Server',
+ description: 'Update Server.',
+ path: '/servers/{uuid}',
+ security: [
+ ['bearerAuth' => []],
+ ],
+ tags: ['Servers'],
+ requestBody: new OA\RequestBody(
+ required: true,
+ description: 'Server updated.',
+ content: new OA\MediaType(
+ mediaType: 'application/json',
+ schema: new OA\Schema(
+ type: 'object',
+ properties: [
+ 'name' => ['type' => 'string', 'description' => 'The name of the server.'],
+ 'description' => ['type' => 'string', 'description' => 'The description of the server.'],
+ 'ip' => ['type' => 'string', 'description' => 'The IP of the server.'],
+ 'port' => ['type' => 'integer', 'description' => 'The port of the server.'],
+ 'user' => ['type' => 'string', 'description' => 'The user of the server.'],
+ '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.'],
+ ],
+ ),
+ ),
+ ),
+ responses: [
+ new OA\Response(
+ response: 201,
+ description: 'Server updated.',
+ content: [
+ new OA\MediaType(
+ mediaType: 'application/json',
+ schema: new OA\Schema(
+ type: 'array',
+ items: new OA\Items(ref: '#/components/schemas/Server')
+ )
+ ),
+ ]),
+ new OA\Response(
+ response: 401,
+ ref: '#/components/responses/401',
+ ),
+ new OA\Response(
+ response: 400,
+ ref: '#/components/responses/400',
+ ),
+ new OA\Response(
+ response: 404,
+ ref: '#/components/responses/404',
+ ),
+ ]
+ )]
+ public function update_server(Request $request)
+ {
+ $allowedFields = ['name', 'description', 'ip', 'port', 'user', 'private_key_uuid', 'is_build_server', 'instant_validate'];
+
+ $teamId = getTeamIdFromToken();
+ if (is_null($teamId)) {
+ return invalidTokenResponse();
+ }
+
+ $return = validateIncomingRequest($request);
+ if ($return instanceof \Illuminate\Http\JsonResponse) {
+ return $return;
+ }
+ $validator = customApiValidator($request->all(), [
+ 'name' => 'string|max:255|nullable',
+ 'description' => 'string|nullable',
+ 'ip' => 'string|nullable',
+ 'port' => 'integer|nullable',
+ 'private_key_uuid' => 'string|nullable',
+ 'user' => 'string|nullable',
+ 'is_build_server' => 'boolean|nullable',
+ 'instant_validate' => 'boolean|nullable',
+ ]);
+
+ $extraFields = array_diff(array_keys($request->all()), $allowedFields);
+ if ($validator->fails() || ! empty($extraFields)) {
+ $errors = $validator->errors();
+ if (! empty($extraFields)) {
+ foreach ($extraFields as $field) {
+ $errors->add($field, 'This field is not allowed.');
+ }
+ }
+
+ return response()->json([
+ 'message' => 'Validation failed.',
+ 'errors' => $errors,
+ ], 422);
+ }
+ $server = ModelsServer::whereTeamId($teamId)->whereUuid($request->uuid)->first();
+ if (! $server) {
+ return response()->json(['message' => 'Server not found.'], 404);
+ }
+ $server->update($request->only(['name', 'description', 'ip', 'port', 'user']));
+ if ($request->is_build_server) {
+ $server->settings()->update([
+ 'is_build_server' => $request->is_build_server,
+ ]);
+ }
+ if ($request->instant_validate) {
+ ValidateServer::dispatch($server);
+ }
+
+ return response()->json(serializeApiResponse($server))->setStatusCode(201);
+ }
+
+ #[OA\Delete(
+ summary: 'Delete',
+ description: 'Delete server by UUID.',
+ path: '/servers/{uuid}',
+ security: [
+ ['bearerAuth' => []],
+ ],
+ tags: ['Servers'],
+ parameters: [
+ new OA\Parameter(
+ name: 'uuid',
+ in: 'path',
+ description: 'UUID of the server.',
+ required: true,
+ schema: new OA\Schema(
+ type: 'string',
+ format: 'uuid',
+ )
+ ),
+ ],
+ responses: [
+ new OA\Response(
+ response: 200,
+ description: 'Server deleted.',
+ content: [
+ new OA\MediaType(
+ mediaType: 'application/json',
+ schema: new OA\Schema(
+ type: 'object',
+ properties: [
+ 'message' => ['type' => 'string', 'example' => 'Server deleted.'],
+ ]
+ )
+ ),
+ ]),
+ new OA\Response(
+ response: 401,
+ ref: '#/components/responses/401',
+ ),
+ new OA\Response(
+ response: 400,
+ ref: '#/components/responses/400',
+ ),
+ new OA\Response(
+ response: 404,
+ ref: '#/components/responses/404',
+ ),
+ ]
+ )]
+ public function delete_server(Request $request)
+ {
+ $teamId = getTeamIdFromToken();
+ if (is_null($teamId)) {
+ return invalidTokenResponse();
+ }
+
+ if (! $request->uuid) {
+ return response()->json(['message' => 'Uuid is required.'], 422);
+ }
+ $server = ModelsServer::whereTeamId($teamId)->whereUuid($request->uuid)->first();
+
+ if (! $server) {
+ return response()->json(['message' => 'Server not found.'], 404);
+ }
+ if ($server->definedResources()->count() > 0) {
+ return response()->json(['message' => 'Server has resources, so you need to delete them before.'], 400);
+ }
+ $server->delete();
+
+ return response()->json(['message' => 'Server deleted.']);
+ }
+
+ #[OA\Get(
+ summary: 'Validate',
+ description: 'Validate server by UUID.',
+ path: '/servers/{uuid}/validate',
+ security: [
+ ['bearerAuth' => []],
+ ],
+ tags: ['Servers'],
+ parameters: [
+ new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Server UUID', schema: new OA\Schema(type: 'integer')),
+ ],
+ responses: [
+ new OA\Response(
+ response: 201,
+ description: 'Server validation started.',
+ content: [
+ new OA\MediaType(
+ mediaType: 'application/json',
+ schema: new OA\Schema(
+ type: 'object',
+ properties: [
+ 'message' => ['type' => 'string', 'example' => 'Validation started.'],
+ ]
+ )
+ ),
+ ]),
+ new OA\Response(
+ response: 401,
+ ref: '#/components/responses/401',
+ ),
+ new OA\Response(
+ response: 400,
+ ref: '#/components/responses/400',
+ ),
+ new OA\Response(
+ response: 404,
+ ref: '#/components/responses/404',
+ ),
+ ]
+ )]
+ public function validate_server(Request $request)
+ {
+ $teamId = getTeamIdFromToken();
+ if (is_null($teamId)) {
+ return invalidTokenResponse();
+ }
+
+ if (! $request->uuid) {
+ return response()->json(['message' => 'Uuid is required.'], 422);
+ }
+ $server = ModelsServer::whereTeamId($teamId)->whereUuid($request->uuid)->first();
+
+ if (! $server) {
+ return response()->json(['message' => 'Server not found.'], 404);
+ }
+ ValidateServer::dispatch($server);
+
+ return response()->json(['message' => 'Validation started.']);
+ }
}
diff --git a/app/Livewire/Boarding/Index.php b/app/Livewire/Boarding/Index.php
index 7acf5ed87..8127ca009 100644
--- a/app/Livewire/Boarding/Index.php
+++ b/app/Livewire/Boarding/Index.php
@@ -257,7 +257,6 @@ public function saveServer()
$this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
$this->createdServer->settings->save();
- $this->createdServer->addInitialNetwork();
$this->selectedExistingServer = $this->createdServer->id;
$this->currentState = 'validate-server';
}
diff --git a/app/Livewire/Server/Form.php b/app/Livewire/Server/Form.php
index c2a55afcb..9934ea345 100644
--- a/app/Livewire/Server/Form.php
+++ b/app/Livewire/Server/Form.php
@@ -164,6 +164,9 @@ public function checkLocalhostConnection()
public function validateServer($install = true)
{
+ $this->server->update([
+ 'validation_logs' => null,
+ ]);
$this->dispatch('init', $install);
}
diff --git a/app/Livewire/Server/New/ByIp.php b/app/Livewire/Server/New/ByIp.php
index 0aad33b1c..0f4c1afea 100644
--- a/app/Livewire/Server/New/ByIp.php
+++ b/app/Livewire/Server/New/ByIp.php
@@ -124,7 +124,6 @@ public function submit()
}
$server->settings->is_build_server = $this->is_build_server;
$server->settings->save();
- $server->addInitialNetwork();
return redirect()->route('server.show', $server->uuid);
} catch (\Throwable $e) {
diff --git a/app/Livewire/Server/ValidateAndInstall.php b/app/Livewire/Server/ValidateAndInstall.php
index 422cae779..8c5bc23ed 100644
--- a/app/Livewire/Server/ValidateAndInstall.php
+++ b/app/Livewire/Server/ValidateAndInstall.php
@@ -87,7 +87,10 @@ public function validateConnection()
{
['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
if (! $this->uptime) {
- $this->error = 'Server is not reachable. Please validate your configuration and connection.
Check this documentation for further help.
Error: '.$error;
+ $this->error = 'Server is not reachable. Please validate your configuration and connection.
Check this documentation for further help.
Error: '.$error.'
';
+ $this->server->update([
+ 'validation_logs' => $this->error,
+ ]);
return;
}
@@ -99,6 +102,9 @@ public function validateOS()
$this->supported_os_type = $this->server->validateOS();
if (! $this->supported_os_type) {
$this->error = 'Server OS type is not supported. Please install Docker manually before continuing: documentation.';
+ $this->server->update([
+ 'validation_logs' => $this->error,
+ ]);
return;
}
@@ -113,6 +119,9 @@ public function validateDockerEngine()
if ($this->install) {
if ($this->number_of_tries == $this->max_tries) {
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: documentation.';
+ $this->server->update([
+ 'validation_logs' => $this->error,
+ ]);
return;
} else {
@@ -126,6 +135,9 @@ public function validateDockerEngine()
}
} else {
$this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: documentation.';
+ $this->server->update([
+ 'validation_logs' => $this->error,
+ ]);
return;
}
@@ -148,6 +160,9 @@ public function validateDockerVersion()
$this->dispatch('success', 'Server validated.');
} else {
$this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: documentation.';
+ $this->server->update([
+ 'validation_logs' => $this->error,
+ ]);
return;
}
diff --git a/app/Models/Server.php b/app/Models/Server.php
index e164f2e27..9166f5a0f 100644
--- a/app/Models/Server.php
+++ b/app/Models/Server.php
@@ -19,85 +19,23 @@
use Symfony\Component\Yaml\Yaml;
#[OA\Schema(
- description: 'Application model',
+ description: 'Server model',
type: 'object',
properties: [
'id' => ['type' => 'integer'],
- 'repository_project_id' => ['type' => 'integer', 'nullable' => true],
'uuid' => ['type' => 'string'],
'name' => ['type' => 'string'],
- 'fqdn' => ['type' => 'string'],
- 'config_hash' => ['type' => 'string'],
- 'git_repository' => ['type' => 'string'],
- 'git_branch' => ['type' => 'string'],
- 'git_commit_sha' => ['type' => 'string'],
- 'git_full_url' => ['type' => 'string', 'nullable' => true],
- 'docker_registry_image_name' => ['type' => 'string', 'nullable' => true],
- 'docker_registry_image_tag' => ['type' => 'string', 'nullable' => true],
- 'build_pack' => ['type' => 'string'],
- 'static_image' => ['type' => 'string'],
- 'install_command' => ['type' => 'string'],
- 'build_command' => ['type' => 'string'],
- 'start_command' => ['type' => 'string'],
- 'ports_exposes' => ['type' => 'string'],
- 'ports_mappings' => ['type' => 'string', 'nullable' => true],
- 'base_directory' => ['type' => 'string'],
- 'publish_directory' => ['type' => 'string'],
- 'health_check_path' => ['type' => 'string'],
- 'health_check_port' => ['type' => 'string', 'nullable' => true],
- 'health_check_host' => ['type' => 'string'],
- 'health_check_method' => ['type' => 'string'],
- 'health_check_return_code' => ['type' => 'integer'],
- 'health_check_scheme' => ['type' => 'string'],
- 'health_check_response_text' => ['type' => 'string', 'nullable' => true],
- 'health_check_interval' => ['type' => 'integer'],
- 'health_check_timeout' => ['type' => 'integer'],
- 'health_check_retries' => ['type' => 'integer'],
- 'health_check_start_period' => ['type' => 'integer'],
- 'limits_memory' => ['type' => 'string'],
- 'limits_memory_swap' => ['type' => 'string'],
- 'limits_memory_swappiness' => ['type' => 'integer'],
- 'limits_memory_reservation' => ['type' => 'string'],
- 'limits_cpus' => ['type' => 'string'],
- 'limits_cpuset' => ['type' => 'string', 'nullable' => true],
- 'limits_cpu_shares' => ['type' => 'integer'],
- 'status' => ['type' => 'string'],
- 'preview_url_template' => ['type' => 'string'],
- 'destination_type' => ['type' => 'string'],
- 'destination_id' => ['type' => 'integer'],
- 'source_type' => ['type' => 'string'],
- 'source_id' => ['type' => 'integer'],
- 'private_key_id' => ['type' => 'integer', 'nullable' => true],
- 'environment_id' => ['type' => 'integer'],
- 'created_at' => ['type' => 'string', 'format' => 'date-time'],
- 'updated_at' => ['type' => 'string', 'format' => 'date-time'],
- 'description' => ['type' => 'string', 'nullable' => true],
- 'dockerfile' => ['type' => 'string', 'nullable' => true],
- 'health_check_enabled' => ['type' => 'boolean'],
- 'dockerfile_location' => ['type' => 'string'],
- 'custom_labels' => ['type' => 'string'],
- 'dockerfile_target_build' => ['type' => 'string', 'nullable' => true],
- 'manual_webhook_secret_github' => ['type' => 'string', 'nullable' => true],
- 'manual_webhook_secret_gitlab' => ['type' => 'string', 'nullable' => true],
- 'docker_compose_location' => ['type' => 'string'],
- 'docker_compose' => ['type' => 'string', 'nullable' => true],
- 'docker_compose_raw' => ['type' => 'string', 'nullable' => true],
- 'docker_compose_domains' => ['type' => 'string', 'nullable' => true],
- 'deleted_at' => ['type' => 'string', 'format' => 'date-time', 'nullable' => true],
- 'docker_compose_custom_start_command' => ['type' => 'string', 'nullable' => true],
- 'docker_compose_custom_build_command' => ['type' => 'string', 'nullable' => true],
- 'swarm_replicas' => ['type' => 'integer'],
- 'swarm_placement_constraints' => ['type' => 'string', 'nullable' => true],
- 'manual_webhook_secret_bitbucket' => ['type' => 'string', 'nullable' => true],
- 'custom_docker_run_options' => ['type' => 'string', 'nullable' => true],
- 'post_deployment_command' => ['type' => 'string', 'nullable' => true],
- 'post_deployment_command_container' => ['type' => 'string', 'nullable' => true],
- 'pre_deployment_command' => ['type' => 'string', 'nullable' => true],
- 'pre_deployment_command_container' => ['type' => 'string', 'nullable' => true],
- 'watch_paths' => ['type' => 'string', 'nullable' => true],
- 'custom_healthcheck_found' => ['type' => 'boolean'],
- 'manual_webhook_secret_gitea' => ['type' => 'string', 'nullable' => true],
- 'redirect' => ['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'],
]
)]
@@ -123,6 +61,37 @@ protected static function booted()
ServerSetting::create([
'server_id' => $server->id,
]);
+ if ($server->id === 0) {
+ if ($server->isSwarm()) {
+ SwarmDocker::create([
+ 'id' => 0,
+ 'name' => 'coolify',
+ 'network' => 'coolify-overlay',
+ 'server_id' => $server->id,
+ ]);
+ } else {
+ StandaloneDocker::create([
+ 'id' => 0,
+ 'name' => 'coolify',
+ 'network' => 'coolify',
+ 'server_id' => $server->id,
+ ]);
+ }
+ } else {
+ if ($server->isSwarm()) {
+ SwarmDocker::create([
+ 'name' => 'coolify-overlay',
+ 'network' => 'coolify-overlay',
+ 'server_id' => $server->id,
+ ]);
+ } else {
+ StandaloneDocker::create([
+ 'name' => 'coolify',
+ 'network' => 'coolify',
+ 'server_id' => $server->id,
+ ]);
+ }
+ }
});
static::deleting(function ($server) {
$server->destinations()->each(function ($destination) {
@@ -176,41 +145,6 @@ public function settings()
return $this->hasOne(ServerSetting::class);
}
- public function addInitialNetwork()
- {
- if ($this->id === 0) {
- if ($this->isSwarm()) {
- SwarmDocker::create([
- 'id' => 0,
- 'name' => 'coolify',
- 'network' => 'coolify-overlay',
- 'server_id' => $this->id,
- ]);
- } else {
- StandaloneDocker::create([
- 'id' => 0,
- 'name' => 'coolify',
- 'network' => 'coolify',
- 'server_id' => $this->id,
- ]);
- }
- } else {
- if ($this->isSwarm()) {
- SwarmDocker::create([
- 'name' => 'coolify-overlay',
- 'network' => 'coolify-overlay',
- 'server_id' => $this->id,
- ]);
- } else {
- StandaloneDocker::create([
- 'name' => 'coolify',
- 'network' => 'coolify',
- 'server_id' => $this->id,
- ]);
- }
- }
- }
-
public function setupDefault404Redirect()
{
$dynamic_conf_path = $this->proxyPath().'/dynamic';
diff --git a/database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php b/database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php
new file mode 100644
index 000000000..d3293620b
--- /dev/null
+++ b/database/migrations/2024_07_23_112710_add_validation_logs_to_servers.php
@@ -0,0 +1,28 @@
+text('validation_logs')->nullable();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('servers', function (Blueprint $table) {
+ $table->dropColumn('validation_logs');
+ });
+ }
+};
diff --git a/openapi.yaml b/openapi.yaml
index 23c00e3e4..92d6147cb 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -3023,7 +3023,7 @@ paths:
application/json:
schema:
properties:
- name:
+ uuid:
type: string
description: 'The name of the project.'
description:
@@ -3037,9 +3037,7 @@ paths:
application/json:
schema:
properties:
- uuid: { type: string, example: og888os }
- name: { type: string, example: 'Project Name' }
- description: { type: string, example: 'Project Description' }
+ uuid: { type: string, example: og888os, description: 'The UUID of the project.' }
type: object
'401':
$ref: '#/components/responses/401'
@@ -3401,6 +3399,70 @@ paths:
security:
-
bearerAuth: []
+ post:
+ tags:
+ - Servers
+ summary: 'Create Server'
+ description: 'Create Server.'
+ operationId: fa44b42490379e428ba5b8747716a8d9
+ requestBody:
+ description: 'Server created.'
+ required: true
+ content:
+ application/json:
+ schema:
+ properties:
+ name:
+ type: string
+ example: 'My Server'
+ description: 'The name of the server.'
+ description:
+ type: string
+ example: 'My Server Description'
+ description: 'The description of the server.'
+ ip:
+ type: string
+ example: 127.0.0.1
+ description: 'The IP of the server.'
+ port:
+ type: integer
+ example: 22
+ description: 'The port of the server.'
+ user:
+ type: string
+ example: root
+ description: 'The user of the server.'
+ 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.'
+ type: object
+ responses:
+ '201':
+ description: 'Server created.'
+ content:
+ application/json:
+ schema:
+ properties:
+ uuid: { type: string, example: og888os, description: 'The UUID of the server.' }
+ type: object
+ '401':
+ $ref: '#/components/responses/401'
+ '400':
+ $ref: '#/components/responses/400'
+ '404':
+ $ref: '#/components/responses/404'
+ security:
+ -
+ bearerAuth: []
'/servers/{uuid}':
get:
tags:
@@ -3432,6 +3494,95 @@ paths:
security:
-
bearerAuth: []
+ delete:
+ tags:
+ - Servers
+ summary: Delete
+ description: 'Delete server by UUID.'
+ operationId: 0231fe0134f0306b21f006ce51b0a3dc
+ parameters:
+ -
+ name: uuid
+ in: path
+ description: 'UUID of the server.'
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ '200':
+ description: 'Server deleted.'
+ content:
+ application/json:
+ schema:
+ properties:
+ message: { type: string, example: 'Server deleted.' }
+ type: object
+ '401':
+ $ref: '#/components/responses/401'
+ '400':
+ $ref: '#/components/responses/400'
+ '404':
+ $ref: '#/components/responses/404'
+ security:
+ -
+ bearerAuth: []
+ patch:
+ tags:
+ - Servers
+ summary: 'Update Server'
+ description: 'Update Server.'
+ operationId: 41bbdaf79eb1938592494fc5494442a0
+ requestBody:
+ description: 'Server updated.'
+ required: true
+ content:
+ application/json:
+ schema:
+ properties:
+ name:
+ type: string
+ description: 'The name of the server.'
+ description:
+ type: string
+ description: 'The description of the server.'
+ ip:
+ type: string
+ description: 'The IP of the server.'
+ port:
+ type: integer
+ description: 'The port of the server.'
+ user:
+ type: string
+ description: 'The user of the server.'
+ 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.'
+ type: object
+ responses:
+ '201':
+ description: 'Server updated.'
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Server'
+ '401':
+ $ref: '#/components/responses/401'
+ '400':
+ $ref: '#/components/responses/400'
+ '404':
+ $ref: '#/components/responses/404'
+ security:
+ -
+ bearerAuth: []
'/servers/{uuid}/resources':
get:
tags:
@@ -3496,6 +3647,39 @@ paths:
security:
-
bearerAuth: []
+ '/servers/{uuid}/validate':
+ get:
+ tags:
+ - Servers
+ summary: Validate
+ description: 'Validate server by UUID.'
+ operationId: a543a12ef2cbc7a3dd22c3dbe6cbee89
+ parameters:
+ -
+ name: uuid
+ in: path
+ description: 'Server UUID'
+ required: true
+ schema:
+ type: integer
+ responses:
+ '201':
+ description: 'Server validation started.'
+ content:
+ application/json:
+ schema:
+ properties:
+ message: { type: string, example: 'Validation started.' }
+ type: object
+ '401':
+ $ref: '#/components/responses/401'
+ '400':
+ $ref: '#/components/responses/400'
+ '404':
+ $ref: '#/components/responses/404'
+ security:
+ -
+ bearerAuth: []
/services:
get:
tags:
@@ -4302,191 +4486,35 @@ components:
$ref: '#/components/schemas/Environment'
type: object
Server:
- description: 'Application model'
+ description: 'Server model'
properties:
id:
type: integer
- repository_project_id:
- type: integer
- nullable: true
uuid:
type: string
name:
type: string
- fqdn:
- type: string
- config_hash:
- type: string
- git_repository:
- type: string
- git_branch:
- type: string
- git_commit_sha:
- type: string
- git_full_url:
- type: string
- nullable: true
- docker_registry_image_name:
- type: string
- nullable: true
- docker_registry_image_tag:
- type: string
- nullable: true
- build_pack:
- type: string
- static_image:
- type: string
- install_command:
- type: string
- build_command:
- type: string
- start_command:
- type: string
- ports_exposes:
- type: string
- ports_mappings:
- type: string
- nullable: true
- base_directory:
- type: string
- publish_directory:
- type: string
- health_check_path:
- type: string
- health_check_port:
- type: string
- nullable: true
- health_check_host:
- type: string
- health_check_method:
- type: string
- health_check_return_code:
- type: integer
- health_check_scheme:
- type: string
- health_check_response_text:
- type: string
- nullable: true
- health_check_interval:
- type: integer
- health_check_timeout:
- type: integer
- health_check_retries:
- type: integer
- health_check_start_period:
- type: integer
- limits_memory:
- type: string
- limits_memory_swap:
- type: string
- limits_memory_swappiness:
- type: integer
- limits_memory_reservation:
- type: string
- limits_cpus:
- type: string
- limits_cpuset:
- type: string
- nullable: true
- limits_cpu_shares:
- type: integer
- status:
- type: string
- preview_url_template:
- type: string
- destination_type:
- type: string
- destination_id:
- type: integer
- source_type:
- type: string
- source_id:
- type: integer
- private_key_id:
- type: integer
- nullable: true
- environment_id:
- type: integer
- created_at:
- type: string
- format: date-time
- updated_at:
- type: string
- format: date-time
description:
type: string
- nullable: true
- dockerfile:
+ ip:
type: string
- nullable: true
- health_check_enabled:
- type: boolean
- dockerfile_location:
+ user:
type: string
- custom_labels:
- type: string
- dockerfile_target_build:
- type: string
- nullable: true
- manual_webhook_secret_github:
- type: string
- nullable: true
- manual_webhook_secret_gitlab:
- type: string
- nullable: true
- docker_compose_location:
- type: string
- docker_compose:
- type: string
- nullable: true
- docker_compose_raw:
- type: string
- nullable: true
- docker_compose_domains:
- type: string
- nullable: true
- deleted_at:
- type: string
- format: date-time
- nullable: true
- docker_compose_custom_start_command:
- type: string
- nullable: true
- docker_compose_custom_build_command:
- type: string
- nullable: true
- swarm_replicas:
+ port:
type: integer
- swarm_placement_constraints:
- type: string
- nullable: true
- manual_webhook_secret_bitbucket:
- type: string
- nullable: true
- custom_docker_run_options:
- type: string
- nullable: true
- post_deployment_command:
- type: string
- nullable: true
- post_deployment_command_container:
- type: string
- nullable: true
- pre_deployment_command:
- type: string
- nullable: true
- pre_deployment_command_container:
- type: string
- nullable: true
- watch_paths:
- type: string
- nullable: true
- custom_healthcheck_found:
+ proxy:
+ type: object
+ high_disk_usage_notification_sent:
type: boolean
- manual_webhook_secret_gitea:
+ unreachable_notification_sent:
+ type: boolean
+ unreachable_count:
+ type: integer
+ validation_logs:
type: string
- nullable: true
- redirect:
+ log_drain_notification_sent:
+ type: boolean
+ swarm_cluster:
type: string
type: object
ServerSetting:
diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php
index e10dec0d4..848758063 100644
--- a/resources/views/livewire/server/form.blade.php
+++ b/resources/views/livewire/server/form.blade.php
@@ -40,6 +40,12 @@ class="w-full mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-1
Validate Server & Install Docker Engine
+ @if ($server->validation_logs)
+ Previous Validation Logs
+
+ {!! $server->validation_logs !!}
+
+ @endif
@endif
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id === 0)