mirror of
https://github.com/ershisan99/coolify.git
synced 2025-12-29 12:33:59 +00:00
Compare commits
40 Commits
v4.0.0-bet
...
v4.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10b9c4bcfa | ||
|
|
38d914076e | ||
|
|
102dd6bfb1 | ||
|
|
04379b76f2 | ||
|
|
d6fb54f3c3 | ||
|
|
1d419c6ab8 | ||
|
|
8a4e958663 | ||
|
|
b04f7686fd | ||
|
|
5aabdefaa7 | ||
|
|
f76d45b826 | ||
|
|
6cc86a3c82 | ||
|
|
f1e5b61970 | ||
|
|
65380646f7 | ||
|
|
189a8347ed | ||
|
|
e96e8f6fec | ||
|
|
38299ab507 | ||
|
|
f134171855 | ||
|
|
320204d854 | ||
|
|
b68199a482 | ||
|
|
6f4436fd5e | ||
|
|
0d8cc19698 | ||
|
|
a3a1ff69e1 | ||
|
|
5df7e23aa4 | ||
|
|
35d9691b3f | ||
|
|
465f649641 | ||
|
|
d909e7d802 | ||
|
|
06db6b8502 | ||
|
|
12261b9082 | ||
|
|
583ec432e8 | ||
|
|
8ffbccf7db | ||
|
|
439fe43a04 | ||
|
|
7fd9a799b5 | ||
|
|
7459ab22d1 | ||
|
|
133a68f3eb | ||
|
|
3224110583 | ||
|
|
810488b115 | ||
|
|
b2276147ad | ||
|
|
6c1293c63e | ||
|
|
526d675272 | ||
|
|
14b2442d40 |
4
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
4
.github/ISSUE_TEMPLATE/BUG_REPORT.yml
vendored
@@ -40,7 +40,7 @@ body:
|
|||||||
label: Cloud?
|
label: Cloud?
|
||||||
description: "Are you using the cloud version of Coolify?"
|
description: "Are you using the cloud version of Coolify?"
|
||||||
options:
|
options:
|
||||||
- label: Yes
|
- label: 'Yes'
|
||||||
required: false
|
required: false
|
||||||
- label: No
|
- label: 'No'
|
||||||
required: false
|
required: false
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ Special thanks to our biggest sponsors!
|
|||||||
<a href="https://trieve.ai/?ref=coolify.io" target="_blank"><img src="./other/logos/trieve_bg.png" alt="trieve logo" width="180"/></a>
|
<a href="https://trieve.ai/?ref=coolify.io" target="_blank"><img src="./other/logos/trieve_bg.png" alt="trieve logo" width="180"/></a>
|
||||||
<a href="https://blacksmith.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/blacksmith.svg" alt="blacksmith logo" width="200"/></a>
|
<a href="https://blacksmith.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/blacksmith.svg" alt="blacksmith logo" width="200"/></a>
|
||||||
<a href="https://latitude.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/latitude.svg" alt="latitude logo" width="200"/></a>
|
<a href="https://latitude.sh/?ref=coolify.io" target="_blank"><img src="./other/logos/latitude.svg" alt="latitude logo" width="200"/></a>
|
||||||
|
<a href="https://brand.dev/?ref=coolify.io" target="_blank"><img src="./other/logos/branddev.png" alt="branddev logo" width="200"/></a>
|
||||||
|
|
||||||
## Github Sponsors ($40+)
|
## Github Sponsors ($40+)
|
||||||
<a href="https://serpapi.com/?ref=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
|
<a href="https://serpapi.com/?ref=coolify.io"><img width="60px" alt="SerpAPI" src="https://github.com/serpapi.png"/></a>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class StopApplication
|
|||||||
{
|
{
|
||||||
use AsAction;
|
use AsAction;
|
||||||
|
|
||||||
public function handle(Application $application)
|
public function handle(Application $application, bool $previewDeployments = false)
|
||||||
{
|
{
|
||||||
if ($application->destination->server->isSwarm()) {
|
if ($application->destination->server->isSwarm()) {
|
||||||
instant_remote_process(["docker stack rm {$application->uuid}"], $application->destination->server);
|
instant_remote_process(["docker stack rm {$application->uuid}"], $application->destination->server);
|
||||||
@@ -26,7 +26,12 @@ class StopApplication
|
|||||||
if (! $server->isFunctional()) {
|
if (! $server->isFunctional()) {
|
||||||
return 'Server is not functional';
|
return 'Server is not functional';
|
||||||
}
|
}
|
||||||
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
|
if ($previewDeployments) {
|
||||||
|
$containers = getCurrentApplicationContainerStatus($server, $application->id, includePullrequests: true);
|
||||||
|
} else {
|
||||||
|
$containers = getCurrentApplicationContainerStatus($server, $application->id, 0);
|
||||||
|
}
|
||||||
|
ray($containers);
|
||||||
if ($containers->count() > 0) {
|
if ($containers->count() > 0) {
|
||||||
foreach ($containers as $container) {
|
foreach ($containers as $container) {
|
||||||
$containerName = data_get($container, 'Names');
|
$containerName = data_get($container, 'Names');
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ class CheckConfiguration
|
|||||||
"cat $proxy_path/docker-compose.yml",
|
"cat $proxy_path/docker-compose.yml",
|
||||||
];
|
];
|
||||||
$proxy_configuration = instant_remote_process($payload, $server, false);
|
$proxy_configuration = instant_remote_process($payload, $server, false);
|
||||||
|
|
||||||
if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
|
if ($reset || ! $proxy_configuration || is_null($proxy_configuration)) {
|
||||||
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value;
|
$proxy_configuration = str(generate_default_proxy_configuration($server))->trim()->value;
|
||||||
}
|
}
|
||||||
|
|||||||
67
app/Actions/Server/ValidateServer.php
Normal file
67
app/Actions/Server/ValidateServer.php
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
|
||||||
|
class ValidateServer
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
|
||||||
|
public ?string $uptime = null;
|
||||||
|
|
||||||
|
public ?string $error = null;
|
||||||
|
|
||||||
|
public ?string $supported_os_type = null;
|
||||||
|
|
||||||
|
public ?string $docker_installed = null;
|
||||||
|
|
||||||
|
public ?string $docker_compose_installed = null;
|
||||||
|
|
||||||
|
public ?string $docker_version = null;
|
||||||
|
|
||||||
|
public function handle(Server $server)
|
||||||
|
{
|
||||||
|
$server->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.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$error.'</div>';
|
||||||
|
$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: <a target="_blank" class="text-black underline dark:text-white" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$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: <a target="_blank" class="text-black underline dark:text-white" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$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: <a target="_blank" class="text-black underline dark:text-white" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$server->update([
|
||||||
|
'validation_logs' => $this->error,
|
||||||
|
]);
|
||||||
|
throw new \Exception($this->error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ class CleanupUnreachableServers extends Command
|
|||||||
if ($servers->count() > 0) {
|
if ($servers->count() > 0) {
|
||||||
foreach ($servers as $server) {
|
foreach ($servers as $server) {
|
||||||
echo "Cleanup unreachable server ($server->id) with name $server->name";
|
echo "Cleanup unreachable server ($server->id) with name $server->name";
|
||||||
send_internal_notification("Server $server->name is unreachable for 7 days. Cleaning up...");
|
// send_internal_notification("Server $server->name is unreachable for 7 days. Cleaning up...");
|
||||||
$server->update([
|
$server->update([
|
||||||
'ip' => '1.2.3.4',
|
'ip' => '1.2.3.4',
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ class Emails extends Command
|
|||||||
}
|
}
|
||||||
set_transanctional_email_settings();
|
set_transanctional_email_settings();
|
||||||
|
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage;
|
||||||
$this->mail->subject('Test Email');
|
$this->mail->subject('Test Email');
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'updates':
|
case 'updates':
|
||||||
@@ -107,7 +107,7 @@ class Emails extends Command
|
|||||||
$confirmed = confirm('Are you sure?');
|
$confirmed = confirm('Are you sure?');
|
||||||
if ($confirmed) {
|
if ($confirmed) {
|
||||||
foreach ($emails as $email) {
|
foreach ($emails as $email) {
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage;
|
||||||
$this->mail->subject('One-click Services, Docker Compose support');
|
$this->mail->subject('One-click Services, Docker Compose support');
|
||||||
$unsubscribeUrl = route('unsubscribe.marketing.emails', [
|
$unsubscribeUrl = route('unsubscribe.marketing.emails', [
|
||||||
'token' => encrypt($email),
|
'token' => encrypt($email),
|
||||||
@@ -118,7 +118,7 @@ class Emails extends Command
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'emails-test':
|
case 'emails-test':
|
||||||
$this->mail = (new Test())->toMail();
|
$this->mail = (new Test)->toMail();
|
||||||
$this->sendEmail();
|
$this->sendEmail();
|
||||||
break;
|
break;
|
||||||
case 'database-backup-statuses-daily':
|
case 'database-backup-statuses-daily':
|
||||||
@@ -224,7 +224,7 @@ class Emails extends Command
|
|||||||
// $this->sendEmail();
|
// $this->sendEmail();
|
||||||
// break;
|
// break;
|
||||||
case 'waitlist-invitation-link':
|
case 'waitlist-invitation-link':
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage;
|
||||||
$this->mail->view('emails.waitlist-invitation', [
|
$this->mail->view('emails.waitlist-invitation', [
|
||||||
'loginLink' => 'https://coolify.io',
|
'loginLink' => 'https://coolify.io',
|
||||||
]);
|
]);
|
||||||
@@ -241,7 +241,7 @@ class Emails extends Command
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'realusers-before-trial':
|
case 'realusers-before-trial':
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage;
|
||||||
$this->mail->view('emails.before-trial-conversion');
|
$this->mail->view('emails.before-trial-conversion');
|
||||||
$this->mail->subject('Trial period has been added for all subscription plans.');
|
$this->mail->subject('Trial period has been added for all subscription plans.');
|
||||||
$teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get();
|
$teams = Team::doesntHave('subscription')->where('id', '!=', 0)->get();
|
||||||
@@ -287,7 +287,7 @@ class Emails extends Command
|
|||||||
foreach ($admins as $admin) {
|
foreach ($admins as $admin) {
|
||||||
$this->info($admin);
|
$this->info($admin);
|
||||||
}
|
}
|
||||||
$this->mail = new MailMessage();
|
$this->mail = new MailMessage;
|
||||||
$this->mail->view('emails.server-lost-connection', [
|
$this->mail->view('emails.server-lost-connection', [
|
||||||
'name' => $server->name,
|
'name' => $server->name,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class WaitlistInvite extends Command
|
|||||||
{
|
{
|
||||||
$token = Crypt::encryptString("{$this->next_patient->email}@@@$this->password");
|
$token = Crypt::encryptString("{$this->next_patient->email}@@@$this->password");
|
||||||
$loginLink = route('auth.link', ['token' => $token]);
|
$loginLink = route('auth.link', ['token' => $token]);
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->view('emails.waitlist-invitation', [
|
$mail->view('emails.waitlist-invitation', [
|
||||||
'loginLink' => $loginLink,
|
'loginLink' => $loginLink,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -708,7 +708,7 @@ class ApplicationsController extends Controller
|
|||||||
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
if ($return instanceof \Illuminate\Http\JsonResponse) {
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
$application = new Application();
|
$application = new Application;
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
|
|
||||||
$application->fill($request->all());
|
$application->fill($request->all());
|
||||||
@@ -796,7 +796,7 @@ class ApplicationsController extends Controller
|
|||||||
if (str($gitRepository)->startsWith('http') || str($gitRepository)->contains('github.com')) {
|
if (str($gitRepository)->startsWith('http') || str($gitRepository)->contains('github.com')) {
|
||||||
$gitRepository = str($gitRepository)->replace('https://', '')->replace('http://', '')->replace('github.com/', '');
|
$gitRepository = str($gitRepository)->replace('https://', '')->replace('http://', '')->replace('github.com/', '');
|
||||||
}
|
}
|
||||||
$application = new Application();
|
$application = new Application;
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
|
|
||||||
$application->fill($request->all());
|
$application->fill($request->all());
|
||||||
@@ -890,7 +890,7 @@ class ApplicationsController extends Controller
|
|||||||
return response()->json(['message' => 'Private Key not found.'], 404);
|
return response()->json(['message' => 'Private Key not found.'], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$application = new Application();
|
$application = new Application;
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
|
|
||||||
$application->fill($request->all());
|
$application->fill($request->all());
|
||||||
@@ -988,7 +988,7 @@ class ApplicationsController extends Controller
|
|||||||
$port = 80;
|
$port = 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
$application = new Application();
|
$application = new Application;
|
||||||
$application->fill($request->all());
|
$application->fill($request->all());
|
||||||
$application->fqdn = $fqdn;
|
$application->fqdn = $fqdn;
|
||||||
$application->ports_exposes = $port;
|
$application->ports_exposes = $port;
|
||||||
@@ -1046,7 +1046,7 @@ class ApplicationsController extends Controller
|
|||||||
if (! $request->docker_registry_image_tag) {
|
if (! $request->docker_registry_image_tag) {
|
||||||
$request->offsetSet('docker_registry_image_tag', 'latest');
|
$request->offsetSet('docker_registry_image_tag', 'latest');
|
||||||
}
|
}
|
||||||
$application = new Application();
|
$application = new Application;
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
|
|
||||||
$application->fill($request->all());
|
$application->fill($request->all());
|
||||||
@@ -1140,7 +1140,7 @@ class ApplicationsController extends Controller
|
|||||||
// return $this->dispatch('error', "Invalid docker-compose file.\n$isValid");
|
// return $this->dispatch('error', "Invalid docker-compose file.\n$isValid");
|
||||||
// }
|
// }
|
||||||
|
|
||||||
$service = new Service();
|
$service = new Service;
|
||||||
removeUnnecessaryFieldsFromRequest($request);
|
removeUnnecessaryFieldsFromRequest($request);
|
||||||
$service->fill($request->all());
|
$service->fill($request->all());
|
||||||
|
|
||||||
|
|||||||
@@ -135,8 +135,14 @@ class ProjectController extends Controller
|
|||||||
if (is_null($teamId)) {
|
if (is_null($teamId)) {
|
||||||
return invalidTokenResponse();
|
return invalidTokenResponse();
|
||||||
}
|
}
|
||||||
$project = Project::whereTeamId($teamId)->whereUuid(request()->uuid)->first();
|
if (! $request->uuid) {
|
||||||
$environment = $project->environments()->whereName(request()->environment_name)->first();
|
return response()->json(['message' => 'Uuid is required.'], 422);
|
||||||
|
}
|
||||||
|
if (! $request->environment_name) {
|
||||||
|
return response()->json(['message' => 'Environment name is required.'], 422);
|
||||||
|
}
|
||||||
|
$project = Project::whereTeamId($teamId)->whereUuid($request->uuid)->first();
|
||||||
|
$environment = $project->environments()->whereName($request->environment_name)->first();
|
||||||
if (! $environment) {
|
if (! $environment) {
|
||||||
return response()->json(['message' => 'Environment not found.'], 404);
|
return response()->json(['message' => 'Environment not found.'], 404);
|
||||||
}
|
}
|
||||||
@@ -144,4 +150,276 @@ class ProjectController extends Controller
|
|||||||
|
|
||||||
return response()->json(serializeApiResponse($environment));
|
return response()->json(serializeApiResponse($environment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[OA\Post(
|
||||||
|
summary: 'Create',
|
||||||
|
description: 'Create Project.',
|
||||||
|
path: '/projects',
|
||||||
|
security: [
|
||||||
|
['bearerAuth' => []],
|
||||||
|
],
|
||||||
|
tags: ['Projects'],
|
||||||
|
requestBody: new OA\RequestBody(
|
||||||
|
required: true,
|
||||||
|
description: 'Project created.',
|
||||||
|
content: new OA\MediaType(
|
||||||
|
mediaType: 'application/json',
|
||||||
|
schema: new OA\Schema(
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
'uuid' => ['type' => 'string', 'description' => 'The name of the project.'],
|
||||||
|
'description' => ['type' => 'string', 'description' => 'The description of the project.'],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
responses: [
|
||||||
|
new OA\Response(
|
||||||
|
response: 201,
|
||||||
|
description: 'Project 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 project.'],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
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_project(Request $request)
|
||||||
|
{
|
||||||
|
$allowedFields = ['name', 'description'];
|
||||||
|
|
||||||
|
$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|required',
|
||||||
|
'description' => 'string|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);
|
||||||
|
}
|
||||||
|
|
||||||
|
$project = Project::create([
|
||||||
|
'name' => $request->name,
|
||||||
|
'description' => $request->description,
|
||||||
|
'team_id' => $teamId,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'uuid' => $project->uuid,
|
||||||
|
])->setStatusCode(201);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[OA\Patch(
|
||||||
|
summary: 'Update',
|
||||||
|
description: 'Update Project.',
|
||||||
|
path: '/projects/{uuid}',
|
||||||
|
security: [
|
||||||
|
['bearerAuth' => []],
|
||||||
|
],
|
||||||
|
tags: ['Projects'],
|
||||||
|
requestBody: new OA\RequestBody(
|
||||||
|
required: true,
|
||||||
|
description: 'Project updated.',
|
||||||
|
content: new OA\MediaType(
|
||||||
|
mediaType: 'application/json',
|
||||||
|
schema: new OA\Schema(
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
'name' => ['type' => 'string', 'description' => 'The name of the project.'],
|
||||||
|
'description' => ['type' => 'string', 'description' => 'The description of the project.'],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
responses: [
|
||||||
|
new OA\Response(
|
||||||
|
response: 201,
|
||||||
|
description: 'Project updated.',
|
||||||
|
content: [
|
||||||
|
new OA\MediaType(
|
||||||
|
mediaType: 'application/json',
|
||||||
|
schema: new OA\Schema(
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
'uuid' => ['type' => 'string', 'example' => 'og888os'],
|
||||||
|
'name' => ['type' => 'string', 'example' => 'Project Name'],
|
||||||
|
'description' => ['type' => 'string', 'example' => 'Project Description'],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
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_project(Request $request)
|
||||||
|
{
|
||||||
|
$allowedFields = ['name', 'description'];
|
||||||
|
|
||||||
|
$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',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
$uuid = $request->uuid;
|
||||||
|
if (! $uuid) {
|
||||||
|
return response()->json(['message' => 'Uuid is required.'], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$project = Project::whereTeamId($teamId)->whereUuid($uuid)->first();
|
||||||
|
if (! $project) {
|
||||||
|
return response()->json(['message' => 'Project not found.'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$project->update($request->only($allowedFields));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'uuid' => $project->uuid,
|
||||||
|
'name' => $project->name,
|
||||||
|
'description' => $project->description,
|
||||||
|
])->setStatusCode(201);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[OA\Delete(
|
||||||
|
summary: 'Delete',
|
||||||
|
description: 'Delete project by UUID.',
|
||||||
|
path: '/projects/{uuid}',
|
||||||
|
security: [
|
||||||
|
['bearerAuth' => []],
|
||||||
|
],
|
||||||
|
tags: ['Projects'],
|
||||||
|
parameters: [
|
||||||
|
new OA\Parameter(
|
||||||
|
name: 'uuid',
|
||||||
|
in: 'path',
|
||||||
|
description: 'UUID of the application.',
|
||||||
|
required: true,
|
||||||
|
schema: new OA\Schema(
|
||||||
|
type: 'string',
|
||||||
|
format: 'uuid',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
responses: [
|
||||||
|
new OA\Response(
|
||||||
|
response: 200,
|
||||||
|
description: 'Project deleted.',
|
||||||
|
content: [
|
||||||
|
new OA\MediaType(
|
||||||
|
mediaType: 'application/json',
|
||||||
|
schema: new OA\Schema(
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
'message' => ['type' => 'string', 'example' => 'Project 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_project(Request $request)
|
||||||
|
{
|
||||||
|
$teamId = getTeamIdFromToken();
|
||||||
|
if (is_null($teamId)) {
|
||||||
|
return invalidTokenResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $request->uuid) {
|
||||||
|
return response()->json(['message' => 'Uuid is required.'], 422);
|
||||||
|
}
|
||||||
|
$project = Project::whereTeamId($teamId)->whereUuid($request->uuid)->first();
|
||||||
|
if (! $project) {
|
||||||
|
return response()->json(['message' => 'Project not found.'], 404);
|
||||||
|
}
|
||||||
|
if ($project->resource_count() > 0) {
|
||||||
|
return response()->json(['message' => 'Project has resources, so it cannot be deleted.'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$project->delete();
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Project deleted.']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
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\Http\Controllers\Controller;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
|
use App\Models\PrivateKey;
|
||||||
use App\Models\Project;
|
use App\Models\Project;
|
||||||
use App\Models\Server as ModelsServer;
|
use App\Models\Server as ModelsServer;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -75,7 +79,7 @@ class ServersController extends Controller
|
|||||||
if (is_null($teamId)) {
|
if (is_null($teamId)) {
|
||||||
return invalidTokenResponse();
|
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_reachable'] = $server->settings->is_reachable;
|
||||||
$server['is_usable'] = $server->settings->is_usable;
|
$server['is_usable'] = $server->settings->is_usable;
|
||||||
|
|
||||||
@@ -392,4 +396,390 @@ class ServersController extends Controller
|
|||||||
|
|
||||||
return response()->json(serializeApiResponse($domains));
|
return response()->json(serializeApiResponse($domains));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[OA\Post(
|
||||||
|
summary: 'Create',
|
||||||
|
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',
|
||||||
|
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.']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class UploadController extends BaseController
|
|||||||
$receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
|
$receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
|
||||||
|
|
||||||
if ($receiver->isUploaded() === false) {
|
if ($receiver->isUploaded() === false) {
|
||||||
throw new UploadMissingFileException();
|
throw new UploadMissingFileException;
|
||||||
}
|
}
|
||||||
|
|
||||||
$save = $receiver->receive();
|
$save = $receiver->receive();
|
||||||
|
|||||||
@@ -340,7 +340,6 @@ class Github extends Controller
|
|||||||
return response("Nothing to do. No applications found with branch '$base_branch'.");
|
return response("Nothing to do. No applications found with branch '$base_branch'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($applications as $application) {
|
foreach ($applications as $application) {
|
||||||
$isFunctional = $application->destination->server->isFunctional();
|
$isFunctional = $application->destination->server->isFunctional();
|
||||||
if (! $isFunctional) {
|
if (! $isFunctional) {
|
||||||
@@ -432,8 +431,13 @@ class Github extends Controller
|
|||||||
if ($action === 'closed' || $action === 'close') {
|
if ($action === 'closed' || $action === 'close') {
|
||||||
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
$found = ApplicationPreview::where('application_id', $application->id)->where('pull_request_id', $pull_request_id)->first();
|
||||||
if ($found) {
|
if ($found) {
|
||||||
$container_name = generateApplicationContainerName($application, $pull_request_id);
|
$containers = getCurrentApplicationContainerStatus($application->destination->server, $application->id, $pull_request_id);
|
||||||
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
if ($containers->isNotEmpty()) {
|
||||||
|
$containers->each(function ($container) use ($application) {
|
||||||
|
$container_name = data_get($container, 'Names');
|
||||||
|
instant_remote_process(["docker rm -f $container_name"], $application->destination->server);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ApplicationPullRequestUpdateJob::dispatchSync(application: $application, preview: $found, status: ProcessStatus::CLOSED);
|
ApplicationPullRequestUpdateJob::dispatchSync(application: $application, preview: $found, status: ProcessStatus::CLOSED);
|
||||||
$found->delete();
|
$found->delete();
|
||||||
|
|||||||
@@ -490,10 +490,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
// Start compose file
|
// Start compose file
|
||||||
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
if ($this->application->settings->is_raw_compose_deployment_enabled) {
|
||||||
if ($this->docker_compose_custom_start_command) {
|
if ($this->docker_compose_custom_start_command) {
|
||||||
|
$this->write_deployment_configurations();
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
|
[executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
|
||||||
);
|
);
|
||||||
$this->write_deployment_configurations();
|
|
||||||
} else {
|
} else {
|
||||||
$this->write_deployment_configurations();
|
$this->write_deployment_configurations();
|
||||||
$server_workdir = $this->application->workdir();
|
$server_workdir = $this->application->workdir();
|
||||||
@@ -510,22 +510,21 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($this->docker_compose_custom_start_command) {
|
if ($this->docker_compose_custom_start_command) {
|
||||||
|
$this->write_deployment_configurations();
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
|
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
|
||||||
);
|
);
|
||||||
$this->write_deployment_configurations();
|
|
||||||
} else {
|
} else {
|
||||||
$command = "{$this->coolify_variables} docker compose";
|
$command = "{$this->coolify_variables} docker compose";
|
||||||
if ($this->env_filename) {
|
if ($this->env_filename) {
|
||||||
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
$command .= " --env-file {$this->workdir}/{$this->env_filename}";
|
||||||
}
|
}
|
||||||
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
|
||||||
ray($command);
|
|
||||||
|
|
||||||
|
$this->write_deployment_configurations();
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
[executeInDocker($this->deployment_uuid, $command), 'hidden' => true],
|
||||||
);
|
);
|
||||||
$this->write_deployment_configurations();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,14 +614,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$this->server = $this->original_server;
|
$this->server = $this->original_server;
|
||||||
}
|
}
|
||||||
if (str($this->configuration_dir)->isNotEmpty()) {
|
if (str($this->configuration_dir)->isNotEmpty()) {
|
||||||
ray("docker cp {$this->deployment_uuid}:{$this->workdir} {$this->configuration_dir}");
|
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"mkdir -p $this->configuration_dir",
|
"mkdir -p $this->configuration_dir",
|
||||||
],
|
],
|
||||||
[
|
// removing this now as we are using docker cp
|
||||||
"rm -rf $this->configuration_dir/{*,.*}",
|
// [
|
||||||
],
|
// "rm -rf $this->configuration_dir/{*,.*}",
|
||||||
|
// ],
|
||||||
[
|
[
|
||||||
"docker cp {$this->deployment_uuid}:{$this->workdir}/. {$this->configuration_dir}",
|
"docker cp {$this->deployment_uuid}:{$this->workdir}/. {$this->configuration_dir}",
|
||||||
],
|
],
|
||||||
@@ -992,7 +991,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
|
$nixpacks_php_root_dir = $this->application->environment_variables_preview->where('key', 'NIXPACKS_PHP_ROOT_DIR')->first();
|
||||||
}
|
}
|
||||||
if (! $nixpacks_php_fallback_path) {
|
if (! $nixpacks_php_fallback_path) {
|
||||||
$nixpacks_php_fallback_path = new EnvironmentVariable();
|
$nixpacks_php_fallback_path = new EnvironmentVariable;
|
||||||
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
$nixpacks_php_fallback_path->key = 'NIXPACKS_PHP_FALLBACK_PATH';
|
||||||
$nixpacks_php_fallback_path->value = '/index.php';
|
$nixpacks_php_fallback_path->value = '/index.php';
|
||||||
$nixpacks_php_fallback_path->is_build_time = false;
|
$nixpacks_php_fallback_path->is_build_time = false;
|
||||||
@@ -1000,7 +999,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
$nixpacks_php_fallback_path->save();
|
$nixpacks_php_fallback_path->save();
|
||||||
}
|
}
|
||||||
if (! $nixpacks_php_root_dir) {
|
if (! $nixpacks_php_root_dir) {
|
||||||
$nixpacks_php_root_dir = new EnvironmentVariable();
|
$nixpacks_php_root_dir = new EnvironmentVariable;
|
||||||
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
$nixpacks_php_root_dir->key = 'NIXPACKS_PHP_ROOT_DIR';
|
||||||
$nixpacks_php_root_dir->value = '/app/public';
|
$nixpacks_php_root_dir->value = '/app/public';
|
||||||
$nixpacks_php_root_dir->is_build_time = false;
|
$nixpacks_php_root_dir->is_build_time = false;
|
||||||
@@ -1274,7 +1273,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// ray('Deploying to additional destination: ', $server->name);
|
// ray('Deploying to additional destination: ', $server->name);
|
||||||
$deployment_uuid = new Cuid2();
|
$deployment_uuid = new Cuid2;
|
||||||
queue_application_deployment(
|
queue_application_deployment(
|
||||||
deployment_uuid: $deployment_uuid,
|
deployment_uuid: $deployment_uuid,
|
||||||
application: $this->application,
|
application: $this->application,
|
||||||
@@ -1448,6 +1447,11 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
}
|
}
|
||||||
$this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
|
$this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
|
||||||
$this->application_deployment_queue->addLogEntry("Final Nixpacks plan: {$this->nixpacks_plan}", hidden: true);
|
$this->application_deployment_queue->addLogEntry("Final Nixpacks plan: {$this->nixpacks_plan}", hidden: true);
|
||||||
|
if ($this->nixpacks_type === 'rust') {
|
||||||
|
// temporary: disable healthcheck for rust because the start phase does not have curl/wget
|
||||||
|
$this->application->health_check_enabled = false;
|
||||||
|
$this->application->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
switch ($this->resource->type()) {
|
switch ($this->resource->type()) {
|
||||||
case 'application':
|
case 'application':
|
||||||
$persistentStorages = $this->resource?->persistentStorages()?->get();
|
$persistentStorages = $this->resource?->persistentStorages()?->get();
|
||||||
StopApplication::run($this->resource);
|
StopApplication::run($this->resource, previewDeployments: true);
|
||||||
break;
|
break;
|
||||||
case 'standalone-postgresql':
|
case 'standalone-postgresql':
|
||||||
case 'standalone-redis':
|
case 'standalone-redis':
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SendConfirmationForWaitlistJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$confirmation_url = base_url().'/webhooks/waitlist/confirm?email='.$this->email.'&confirmation_code='.$this->uuid;
|
$confirmation_url = base_url().'/webhooks/waitlist/confirm?email='.$this->email.'&confirmation_code='.$this->uuid;
|
||||||
$cancel_url = base_url().'/webhooks/waitlist/cancel?email='.$this->email.'&confirmation_code='.$this->uuid;
|
$cancel_url = base_url().'/webhooks/waitlist/cancel?email='.$this->email.'&confirmation_code='.$this->uuid;
|
||||||
$mail->view('emails.waitlist-confirmation',
|
$mail->view('emails.waitlist-confirmation',
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SubscriptionInvoiceFailedJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$session = getStripeCustomerPortalSession($this->team);
|
$session = getStripeCustomerPortalSession($this->team);
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->view('emails.subscription-invoice-failed', [
|
$mail->view('emails.subscription-invoice-failed', [
|
||||||
'stripeCustomerPortal' => $session->url,
|
'stripeCustomerPortal' => $session->url,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class SubscriptionTrialEndedJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$session = getStripeCustomerPortalSession($this->team);
|
$session = getStripeCustomerPortalSession($this->team);
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Action required: You trial in Coolify Cloud ended.');
|
$mail->subject('Action required: You trial in Coolify Cloud ended.');
|
||||||
$mail->view('emails.trial-ended', [
|
$mail->view('emails.trial-ended', [
|
||||||
'stripeCustomerPortal' => $session->url,
|
'stripeCustomerPortal' => $session->url,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class SubscriptionTrialEndsSoonJob implements ShouldBeEncrypted, ShouldQueue
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$session = getStripeCustomerPortalSession($this->team);
|
$session = getStripeCustomerPortalSession($this->team);
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('You trial in Coolify Cloud ends soon.');
|
$mail->subject('You trial in Coolify Cloud ends soon.');
|
||||||
$mail->view('emails.trial-ends-soon', [
|
$mail->view('emails.trial-ends-soon', [
|
||||||
'stripeCustomerPortal' => $session->url,
|
'stripeCustomerPortal' => $session->url,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class MaintenanceModeDisabledNotification
|
|||||||
$class = "App\Http\Controllers\Webhook\\".ucfirst(str($endpoint)->before('::')->value());
|
$class = "App\Http\Controllers\Webhook\\".ucfirst(str($endpoint)->before('::')->value());
|
||||||
$method = str($endpoint)->after('::')->value();
|
$method = str($endpoint)->after('::')->value();
|
||||||
try {
|
try {
|
||||||
$instance = new $class();
|
$instance = new $class;
|
||||||
$instance->$method($request);
|
$instance->$method($request);
|
||||||
} catch (\Throwable $th) {
|
} catch (\Throwable $th) {
|
||||||
ray($th);
|
ray($th);
|
||||||
|
|||||||
@@ -257,7 +257,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
$this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
|
$this->createdServer->settings->is_swarm_manager = $this->isSwarmManager;
|
||||||
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
$this->createdServer->settings->is_cloudflare_tunnel = $this->isCloudflareTunnel;
|
||||||
$this->createdServer->settings->save();
|
$this->createdServer->settings->save();
|
||||||
$this->createdServer->addInitialNetwork();
|
|
||||||
$this->selectedExistingServer = $this->createdServer->id;
|
$this->selectedExistingServer = $this->createdServer->id;
|
||||||
$this->currentState = 'validate-server';
|
$this->currentState = 'validate-server';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class Help extends Component
|
|||||||
$this->rateLimit(3, 30);
|
$this->rateLimit(3, 30);
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$debug = "Route: {$this->path}";
|
$debug = "Route: {$this->path}";
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->view(
|
$mail->view(
|
||||||
'emails.help',
|
'emails.help',
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class Discord extends Component
|
|||||||
|
|
||||||
public function sendTestNotification()
|
public function sendTestNotification()
|
||||||
{
|
{
|
||||||
$this->team?->notify(new Test());
|
$this->team?->notify(new Test);
|
||||||
$this->dispatch('success', 'Test notification sent.');
|
$this->dispatch('success', 'Test notification sent.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class Telegram extends Component
|
|||||||
|
|
||||||
public function sendTestNotification()
|
public function sendTestNotification()
|
||||||
{
|
{
|
||||||
$this->team?->notify(new Test());
|
$this->team?->notify(new Test);
|
||||||
$this->dispatch('success', 'Test notification sent.');
|
$this->dispatch('success', 'Test notification sent.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,11 +62,15 @@ class Navbar extends Component
|
|||||||
|
|
||||||
public function checkDeployments()
|
public function checkDeployments()
|
||||||
{
|
{
|
||||||
$activity = Activity::where('properties->type_uuid', $this->service->uuid)->latest()->first();
|
try {
|
||||||
$status = data_get($activity, 'properties.status');
|
$activity = Activity::where('properties->type_uuid', $this->service->uuid)->latest()->first();
|
||||||
if ($status === 'queued' || $status === 'in_progress') {
|
$status = data_get($activity, 'properties.status');
|
||||||
$this->isDeploymentProgress = true;
|
if ($status === 'queued' || $status === 'in_progress') {
|
||||||
} else {
|
$this->isDeploymentProgress = true;
|
||||||
|
} else {
|
||||||
|
$this->isDeploymentProgress = false;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
$this->isDeploymentProgress = false;
|
$this->isDeploymentProgress = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class All extends Component
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
$environment = new EnvironmentVariable();
|
$environment = new EnvironmentVariable;
|
||||||
$environment->key = $key;
|
$environment->key = $key;
|
||||||
$environment->value = $variable;
|
$environment->value = $variable;
|
||||||
if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
|
if (str($environment->value)->startsWith('{{') && str($environment->value)->endsWith('}}')) {
|
||||||
@@ -209,7 +209,7 @@ class All extends Component
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$environment = new EnvironmentVariable();
|
$environment = new EnvironmentVariable;
|
||||||
$environment->key = $data['key'];
|
$environment->key = $data['key'];
|
||||||
$environment->value = $data['value'];
|
$environment->value = $data['value'];
|
||||||
$environment->is_build_time = $data['is_build_time'];
|
$environment->is_build_time = $data['is_build_time'];
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class Show extends Component
|
|||||||
public string $type;
|
public string $type;
|
||||||
|
|
||||||
protected $listeners = [
|
protected $listeners = [
|
||||||
|
'refresh' => 'refresh',
|
||||||
'compose_loaded' => '$refresh',
|
'compose_loaded' => '$refresh',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -46,6 +47,12 @@ class Show extends Component
|
|||||||
'env.is_shown_once' => 'Shown Once',
|
'env.is_shown_once' => 'Shown Once',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function refresh()
|
||||||
|
{
|
||||||
|
$this->env->refresh();
|
||||||
|
$this->checkEnvs();
|
||||||
|
}
|
||||||
|
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') {
|
if ($this->env->getMorphClass() === 'App\Models\SharedEnvironmentVariable') {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class All extends Component
|
|||||||
public function submit($data)
|
public function submit($data)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$task = new ScheduledTask();
|
$task = new ScheduledTask;
|
||||||
$task->name = $data['name'];
|
$task->name = $data['name'];
|
||||||
$task->command = $data['command'];
|
$task->command = $data['command'];
|
||||||
$task->frequency = $data['frequency'];
|
$task->frequency = $data['frequency'];
|
||||||
|
|||||||
@@ -164,6 +164,9 @@ class Form extends Component
|
|||||||
|
|
||||||
public function validateServer($install = true)
|
public function validateServer($install = true)
|
||||||
{
|
{
|
||||||
|
$this->server->update([
|
||||||
|
'validation_logs' => null,
|
||||||
|
]);
|
||||||
$this->dispatch('init', $install);
|
$this->dispatch('init', $install);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ class ByIp extends Component
|
|||||||
}
|
}
|
||||||
$server->settings->is_build_server = $this->is_build_server;
|
$server->settings->is_build_server = $this->is_build_server;
|
||||||
$server->settings->save();
|
$server->settings->save();
|
||||||
$server->addInitialNetwork();
|
|
||||||
|
|
||||||
return redirect()->route('server.show', $server->uuid);
|
return redirect()->route('server.show', $server->uuid);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class Deploy extends Component
|
|||||||
public function proxyStarted()
|
public function proxyStarted()
|
||||||
{
|
{
|
||||||
CheckProxy::run($this->server, true);
|
CheckProxy::run($this->server, true);
|
||||||
$this->dispatch('success', 'Proxy started.');
|
$this->dispatch('proxyStatusUpdated');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function proxyStatusUpdated()
|
public function proxyStatusUpdated()
|
||||||
@@ -61,7 +61,7 @@ class Deploy extends Component
|
|||||||
public function restart()
|
public function restart()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->stop();
|
$this->stop(forceStop: false);
|
||||||
$this->dispatch('checkProxy');
|
$this->dispatch('checkProxy');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return handleError($e, $this);
|
return handleError($e, $this);
|
||||||
@@ -91,7 +91,7 @@ class Deploy extends Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function stop()
|
public function stop(bool $forceStop = true)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ($this->server->isSwarm()) {
|
if ($this->server->isSwarm()) {
|
||||||
@@ -104,7 +104,7 @@ class Deploy extends Component
|
|||||||
], $this->server);
|
], $this->server);
|
||||||
}
|
}
|
||||||
$this->server->proxy->status = 'exited';
|
$this->server->proxy->status = 'exited';
|
||||||
$this->server->proxy->force_stop = true;
|
$this->server->proxy->force_stop = $forceStop;
|
||||||
$this->server->save();
|
$this->server->save();
|
||||||
$this->dispatch('proxyStatusUpdated');
|
$this->dispatch('proxyStatusUpdated');
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ class Status extends Component
|
|||||||
|
|
||||||
public int $numberOfPolls = 0;
|
public int $numberOfPolls = 0;
|
||||||
|
|
||||||
protected $listeners = ['proxyStatusUpdated' => '$refresh', 'startProxyPolling'];
|
protected $listeners = [
|
||||||
|
'proxyStatusUpdated',
|
||||||
|
'startProxyPolling',
|
||||||
|
];
|
||||||
|
|
||||||
public function startProxyPolling()
|
public function startProxyPolling()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -87,7 +87,10 @@ class ValidateAndInstall extends Component
|
|||||||
{
|
{
|
||||||
['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
|
['uptime' => $this->uptime, 'error' => $error] = $this->server->validateConnection();
|
||||||
if (! $this->uptime) {
|
if (! $this->uptime) {
|
||||||
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error;
|
$this->error = 'Server is not reachable. Please validate your configuration and connection.<br>Check this <a target="_blank" class="text-black underline dark:text-white" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br><div class="text-error">Error: '.$error.'</div>';
|
||||||
|
$this->server->update([
|
||||||
|
'validation_logs' => $this->error,
|
||||||
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -99,6 +102,9 @@ class ValidateAndInstall extends Component
|
|||||||
$this->supported_os_type = $this->server->validateOS();
|
$this->supported_os_type = $this->server->validateOS();
|
||||||
if (! $this->supported_os_type) {
|
if (! $this->supported_os_type) {
|
||||||
$this->error = 'Server OS type is not supported. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
$this->error = 'Server OS type is not supported. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$this->server->update([
|
||||||
|
'validation_logs' => $this->error,
|
||||||
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -113,6 +119,9 @@ class ValidateAndInstall extends Component
|
|||||||
if ($this->install) {
|
if ($this->install) {
|
||||||
if ($this->number_of_tries == $this->max_tries) {
|
if ($this->number_of_tries == $this->max_tries) {
|
||||||
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
$this->error = 'Docker Engine could not be installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$this->server->update([
|
||||||
|
'validation_logs' => $this->error,
|
||||||
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@@ -126,6 +135,9 @@ class ValidateAndInstall extends Component
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
$this->error = 'Docker Engine is not installed. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$this->server->update([
|
||||||
|
'validation_logs' => $this->error,
|
||||||
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -148,6 +160,9 @@ class ValidateAndInstall extends Component
|
|||||||
$this->dispatch('success', 'Server validated.');
|
$this->dispatch('success', 'Server validated.');
|
||||||
} else {
|
} else {
|
||||||
$this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
$this->error = 'Docker Engine version is not 22+. Please install Docker manually before continuing: <a target="_blank" class="underline" href="https://docs.docker.com/engine/install/#server">documentation</a>.';
|
||||||
|
$this->server->update([
|
||||||
|
'validation_logs' => $this->error,
|
||||||
|
]);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class Create extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->validate();
|
$this->validate();
|
||||||
$this->storage = new S3Storage();
|
$this->storage = new S3Storage;
|
||||||
$this->storage->name = $this->name;
|
$this->storage->name = $this->name;
|
||||||
$this->storage->description = $this->description ?? null;
|
$this->storage->description = $this->description ?? null;
|
||||||
$this->storage->region = $this->region;
|
$this->storage->region = $this->region;
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ class Index extends Component
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->applications->each(function ($resource) {
|
$this->applications->each(function ($resource) {
|
||||||
$deploy = new DeployController();
|
$deploy = new DeployController;
|
||||||
$deploy->deploy_resource($resource);
|
$deploy->deploy_resource($resource);
|
||||||
});
|
});
|
||||||
$this->services->each(function ($resource) {
|
$this->services->each(function ($resource) {
|
||||||
$deploy = new DeployController();
|
$deploy = new DeployController;
|
||||||
$deploy->deploy_resource($resource);
|
$deploy->deploy_resource($resource);
|
||||||
});
|
});
|
||||||
$this->dispatch('success', 'Mass deployment started.');
|
$this->dispatch('success', 'Mass deployment started.');
|
||||||
|
|||||||
@@ -59,11 +59,11 @@ class Show extends Component
|
|||||||
try {
|
try {
|
||||||
$message = collect([]);
|
$message = collect([]);
|
||||||
$this->applications->each(function ($resource) use ($message) {
|
$this->applications->each(function ($resource) use ($message) {
|
||||||
$deploy = new DeployController();
|
$deploy = new DeployController;
|
||||||
$message->push($deploy->deploy_resource($resource));
|
$message->push($deploy->deploy_resource($resource));
|
||||||
});
|
});
|
||||||
$this->services->each(function ($resource) use ($message) {
|
$this->services->each(function ($resource) use ($message) {
|
||||||
$deploy = new DeployController();
|
$deploy = new DeployController;
|
||||||
$message->push($deploy->deploy_resource($resource));
|
$message->push($deploy->deploy_resource($resource));
|
||||||
});
|
});
|
||||||
$this->dispatch('success', 'Mass deployment started.');
|
$this->dispatch('success', 'Mass deployment started.');
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class InviteLink extends Component
|
|||||||
'via' => $sendEmail ? 'email' : 'link',
|
'via' => $sendEmail ? 'email' : 'link',
|
||||||
]);
|
]);
|
||||||
if ($sendEmail) {
|
if ($sendEmail) {
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->view('emails.invitation-link', [
|
$mail->view('emails.invitation-link', [
|
||||||
'team' => currentTeam()->name,
|
'team' => currentTeam()->name,
|
||||||
'invitation_link' => $link,
|
'invitation_link' => $link,
|
||||||
|
|||||||
@@ -1066,7 +1066,7 @@ class Application extends BaseModel
|
|||||||
if ($isInit && $this->docker_compose_raw) {
|
if ($isInit && $this->docker_compose_raw) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$uuid = new Cuid2();
|
$uuid = new Cuid2;
|
||||||
['commands' => $cloneCommand] = $this->generateGitImportCommands(deployment_uuid: $uuid, only_checkout: true, exec_in_docker: false, custom_base_dir: '.');
|
['commands' => $cloneCommand] = $this->generateGitImportCommands(deployment_uuid: $uuid, only_checkout: true, exec_in_docker: false, custom_base_dir: '.');
|
||||||
$workdir = rtrim($this->base_directory, '/');
|
$workdir = rtrim($this->base_directory, '/');
|
||||||
$composeFile = $this->docker_compose_location;
|
$composeFile = $this->docker_compose_location;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class EnvironmentVariable extends Model
|
|||||||
{
|
{
|
||||||
static::creating(function (Model $model) {
|
static::creating(function (Model $model) {
|
||||||
if (! $model->uuid) {
|
if (! $model->uuid) {
|
||||||
$model->uuid = (string) new Cuid2();
|
$model->uuid = (string) new Cuid2;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
static::created(function (EnvironmentVariable $environment_variable) {
|
static::created(function (EnvironmentVariable $environment_variable) {
|
||||||
|
|||||||
@@ -79,23 +79,29 @@ class LocalFileVolume extends BaseModel
|
|||||||
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
$isFile = instant_remote_process(["test -f $path && echo OK || echo NOK"], $server);
|
||||||
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
$isDir = instant_remote_process(["test -d $path && echo OK || echo NOK"], $server);
|
||||||
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
if ($isFile == 'OK' && $fileVolume->is_directory) {
|
||||||
|
$fileVolume->is_directory = false;
|
||||||
|
$fileVolume->save();
|
||||||
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
throw new \Exception('The following file is a file on the server, but you are trying to mark it as a directory. Please delete the file on the server or mark it as directory.');
|
||||||
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
} elseif ($isDir == 'OK' && ! $fileVolume->is_directory) {
|
||||||
|
$fileVolume->is_directory = true;
|
||||||
|
$fileVolume->save();
|
||||||
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
throw new \Exception('The following file is a directory on the server, but you are trying to mark it as a file. <br><br>Please delete the directory on the server or mark it as directory.');
|
||||||
}
|
}
|
||||||
if (! $fileVolume->is_directory && $isDir == 'NOK') {
|
if ($isDir == 'NOK' && ! $fileVolume->is_directory) {
|
||||||
|
$chmod = data_get($fileVolume, 'chmod');
|
||||||
|
$chown = data_get($fileVolume, 'chown');
|
||||||
if ($content) {
|
if ($content) {
|
||||||
$content = base64_encode($content);
|
$content = base64_encode($content);
|
||||||
$chmod = $fileVolume->chmod;
|
|
||||||
$chown = $fileVolume->chown;
|
|
||||||
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
$commands->push("echo '$content' | base64 -d | tee $path > /dev/null");
|
||||||
$commands->push("chmod +x $path");
|
} else {
|
||||||
if ($chown) {
|
$commands->push("touch $path");
|
||||||
$commands->push("chown $chown $path");
|
}
|
||||||
}
|
$commands->push("chmod +x $path");
|
||||||
if ($chmod) {
|
if ($chown) {
|
||||||
$commands->push("chmod $chmod $path");
|
$commands->push("chown $chown $path");
|
||||||
}
|
}
|
||||||
|
if ($chmod) {
|
||||||
|
$commands->push("chmod $chmod $path");
|
||||||
}
|
}
|
||||||
} elseif ($isDir == 'NOK' && $fileVolume->is_directory) {
|
} elseif ($isDir == 'NOK' && $fileVolume->is_directory) {
|
||||||
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
$commands->push("mkdir -p $path > /dev/null 2>&1 || true");
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class Project extends BaseModel
|
|||||||
|
|
||||||
public function resource_count()
|
public function resource_count()
|
||||||
{
|
{
|
||||||
return $this->applications()->count() + $this->postgresqls()->count() + $this->redis()->count() + $this->mongodbs()->count() + $this->mysqls()->count() + $this->mariadbs()->count() + $this->keydbs()->count() + $this->dragonflies()->count() + $this->services()->count() + $this->clickhouses()->count();
|
return $this->applications()->count() + $this->postgresqls()->count() + $this->redis()->count() + $this->mongodbs()->count() + $this->mysqls()->count() + $this->mariadbs()->count() + $this->keydbs()->count() + $this->dragonflies()->count() + $this->clickhouses()->count() + $this->services()->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function databases()
|
public function databases()
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class S3Storage extends BaseModel
|
|||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
$this->is_usable = false;
|
$this->is_usable = false;
|
||||||
if ($this->unusable_email_sent === false && is_transactional_emails_active()) {
|
if ($this->unusable_email_sent === false && is_transactional_emails_active()) {
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Coolify: S3 Storage Connection Error');
|
$mail->subject('Coolify: S3 Storage Connection Error');
|
||||||
$mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('storage.show', ['storage_uuid' => $this->uuid])]);
|
$mail->view('emails.s3-connection-error', ['name' => $this->name, 'reason' => $e->getMessage(), 'url' => route('storage.show', ['storage_uuid' => $this->uuid])]);
|
||||||
$users = collect([]);
|
$users = collect([]);
|
||||||
|
|||||||
@@ -19,85 +19,23 @@ use Spatie\Url\Url;
|
|||||||
use Symfony\Component\Yaml\Yaml;
|
use Symfony\Component\Yaml\Yaml;
|
||||||
|
|
||||||
#[OA\Schema(
|
#[OA\Schema(
|
||||||
description: 'Application model',
|
description: 'Server model',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: [
|
properties: [
|
||||||
'id' => ['type' => 'integer'],
|
'id' => ['type' => 'integer'],
|
||||||
'repository_project_id' => ['type' => 'integer', 'nullable' => true],
|
|
||||||
'uuid' => ['type' => 'string'],
|
'uuid' => ['type' => 'string'],
|
||||||
'name' => ['type' => 'string'],
|
'name' => ['type' => 'string'],
|
||||||
'fqdn' => ['type' => 'string'],
|
'description' => ['type' => 'string'],
|
||||||
'config_hash' => ['type' => 'string'],
|
'ip' => ['type' => 'string'],
|
||||||
'git_repository' => ['type' => 'string'],
|
'user' => ['type' => 'string'],
|
||||||
'git_branch' => ['type' => 'string'],
|
'port' => ['type' => 'integer'],
|
||||||
'git_commit_sha' => ['type' => 'string'],
|
'proxy' => ['type' => 'object'],
|
||||||
'git_full_url' => ['type' => 'string', 'nullable' => true],
|
'high_disk_usage_notification_sent' => ['type' => 'boolean'],
|
||||||
'docker_registry_image_name' => ['type' => 'string', 'nullable' => true],
|
'unreachable_notification_sent' => ['type' => 'boolean'],
|
||||||
'docker_registry_image_tag' => ['type' => 'string', 'nullable' => true],
|
'unreachable_count' => ['type' => 'integer'],
|
||||||
'build_pack' => ['type' => 'string'],
|
'validation_logs' => ['type' => 'string'],
|
||||||
'static_image' => ['type' => 'string'],
|
'log_drain_notification_sent' => ['type' => 'boolean'],
|
||||||
'install_command' => ['type' => 'string'],
|
'swarm_cluster' => ['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'],
|
|
||||||
]
|
]
|
||||||
)]
|
)]
|
||||||
|
|
||||||
@@ -123,6 +61,37 @@ class Server extends BaseModel
|
|||||||
ServerSetting::create([
|
ServerSetting::create([
|
||||||
'server_id' => $server->id,
|
'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) {
|
static::deleting(function ($server) {
|
||||||
$server->destinations()->each(function ($destination) {
|
$server->destinations()->each(function ($destination) {
|
||||||
@@ -176,41 +145,6 @@ class Server extends BaseModel
|
|||||||
return $this->hasOne(ServerSetting::class);
|
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()
|
public function setupDefault404Redirect()
|
||||||
{
|
{
|
||||||
$dynamic_conf_path = $this->proxyPath().'/dynamic';
|
$dynamic_conf_path = $this->proxyPath().'/dynamic';
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class User extends Authenticatable implements SendsEmail
|
|||||||
|
|
||||||
public function sendVerificationEmail()
|
public function sendVerificationEmail()
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$url = Url::temporarySignedRoute(
|
$url = Url::temporarySignedRoute(
|
||||||
'verify.verify',
|
'verify.verify',
|
||||||
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
|
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class DeploymentFailed extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
||||||
$fqdn = $this->fqdn;
|
$fqdn = $this->fqdn;
|
||||||
if ($pull_request_id === 0) {
|
if ($pull_request_id === 0) {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class DeploymentSuccess extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
$pull_request_id = data_get($this->preview, 'pull_request_id', 0);
|
||||||
$fqdn = $this->fqdn;
|
$fqdn = $this->fqdn;
|
||||||
if ($pull_request_id === 0) {
|
if ($pull_request_id === 0) {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class StatusChanged extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$fqdn = $this->fqdn;
|
$fqdn = $this->fqdn;
|
||||||
$mail->subject("Coolify: {$this->resource_name} has been stopped");
|
$mail->subject("Coolify: {$this->resource_name} has been stopped");
|
||||||
$mail->view('emails.application-status-changes', [
|
$mail->view('emails.application-status-changes', [
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ContainerRestarted extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}");
|
$mail->subject("Coolify: A resource ({$this->name}) has been restarted automatically on {$this->server->name}");
|
||||||
$mail->view('emails.container-restarted', [
|
$mail->view('emails.container-restarted', [
|
||||||
'containerName' => $this->name,
|
'containerName' => $this->name,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ContainerStopped extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: A resource has been stopped unexpectedly on {$this->server->name}");
|
$mail->subject("Coolify: A resource has been stopped unexpectedly on {$this->server->name}");
|
||||||
$mail->view('emails.container-stopped', [
|
$mail->view('emails.container-stopped', [
|
||||||
'containerName' => $this->name,
|
'containerName' => $this->name,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class BackupFailed extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: [ACTION REQUIRED] Backup FAILED for {$this->database->name}");
|
$mail->subject("Coolify: [ACTION REQUIRED] Backup FAILED for {$this->database->name}");
|
||||||
$mail->view('emails.backup-failed', [
|
$mail->view('emails.backup-failed', [
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class BackupSuccess extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: Backup successfully done for {$this->database->name}");
|
$mail->subject("Coolify: Backup successfully done for {$this->database->name}");
|
||||||
$mail->view('emails.backup-success', [
|
$mail->view('emails.backup-success', [
|
||||||
'name' => $this->name,
|
'name' => $this->name,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class DailyBackup extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Coolify: Daily backup statuses');
|
$mail->subject('Coolify: Daily backup statuses');
|
||||||
$mail->view('emails.daily-backup', [
|
$mail->view('emails.daily-backup', [
|
||||||
'databases' => $this->databases,
|
'databases' => $this->databases,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class TaskFailed extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: [ACTION REQUIRED] Scheduled task ({$this->task->name}) failed.");
|
$mail->subject("Coolify: [ACTION REQUIRED] Scheduled task ({$this->task->name}) failed.");
|
||||||
$mail->view('emails.scheduled-task-failed', [
|
$mail->view('emails.scheduled-task-failed', [
|
||||||
'task' => $this->task,
|
'task' => $this->task,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class ForceDisabled extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: Server ({$this->server->name}) disabled because it is not paid!");
|
$mail->subject("Coolify: Server ({$this->server->name}) disabled because it is not paid!");
|
||||||
$mail->view('emails.server-force-disabled', [
|
$mail->view('emails.server-force-disabled', [
|
||||||
'name' => $this->server->name,
|
'name' => $this->server->name,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class ForceEnabled extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: Server ({$this->server->name}) enabled again!");
|
$mail->subject("Coolify: Server ({$this->server->name}) enabled again!");
|
||||||
$mail->view('emails.server-force-enabled', [
|
$mail->view('emails.server-force-enabled', [
|
||||||
'name' => $this->server->name,
|
'name' => $this->server->name,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class HighDiskUsage extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: Server ({$this->server->name}) high disk usage detected!");
|
$mail->subject("Coolify: Server ({$this->server->name}) high disk usage detected!");
|
||||||
$mail->view('emails.high-disk-usage', [
|
$mail->view('emails.high-disk-usage', [
|
||||||
'name' => $this->server->name,
|
'name' => $this->server->name,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class Revived extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: Server ({$this->server->name}) revived.");
|
$mail->subject("Coolify: Server ({$this->server->name}) revived.");
|
||||||
$mail->view('emails.server-revived', [
|
$mail->view('emails.server-revived', [
|
||||||
'name' => $this->server->name,
|
'name' => $this->server->name,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class Unreachable extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject("Coolify: Your server ({$this->server->name}) is unreachable.");
|
$mail->subject("Coolify: Your server ({$this->server->name}) is unreachable.");
|
||||||
$mail->view('emails.server-lost-connection', [
|
$mail->view('emails.server-lost-connection', [
|
||||||
'name' => $this->server->name,
|
'name' => $this->server->name,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Test extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Coolify: Test Email');
|
$mail->subject('Coolify: Test Email');
|
||||||
$mail->view('emails.test');
|
$mail->view('emails.test');
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class InvitationLink extends Notification implements ShouldQueue
|
|||||||
$invitation = TeamInvitation::whereEmail($this->user->email)->first();
|
$invitation = TeamInvitation::whereEmail($this->user->email)->first();
|
||||||
$invitation_team = Team::find($invitation->team->id);
|
$invitation_team = Team::find($invitation->team->id);
|
||||||
|
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Coolify: Invitation for '.$invitation_team->name);
|
$mail->subject('Coolify: Invitation for '.$invitation_team->name);
|
||||||
$mail->view('emails.invitation-link', [
|
$mail->view('emails.invitation-link', [
|
||||||
'team' => $invitation_team->name,
|
'team' => $invitation_team->name,
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class ResetPassword extends Notification
|
|||||||
|
|
||||||
protected function buildMailMessage($url)
|
protected function buildMailMessage($url)
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Coolify: Reset Password');
|
$mail->subject('Coolify: Reset Password');
|
||||||
$mail->view('emails.reset-password', ['url' => $url, 'count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]);
|
$mail->view('emails.reset-password', ['url' => $url, 'count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class Test extends Notification implements ShouldQueue
|
|||||||
|
|
||||||
public function toMail(): MailMessage
|
public function toMail(): MailMessage
|
||||||
{
|
{
|
||||||
$mail = new MailMessage();
|
$mail = new MailMessage;
|
||||||
$mail->subject('Coolify: Test Email');
|
$mail->subject('Coolify: Test Email');
|
||||||
$mail->view('emails.test');
|
$mail->view('emails.test');
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function create_standalone_postgresql($environmentId, $destinationUuid, ?array $
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandalonePostgresql();
|
$database = new StandalonePostgresql;
|
||||||
$database->name = generate_database_name('postgresql');
|
$database->name = generate_database_name('postgresql');
|
||||||
$database->postgres_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->postgres_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environmentId;
|
$database->environment_id = $environmentId;
|
||||||
@@ -45,7 +45,7 @@ function create_standalone_redis($environment_id, $destination_uuid, ?array $oth
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneRedis();
|
$database = new StandaloneRedis;
|
||||||
$database->name = generate_database_name('redis');
|
$database->name = generate_database_name('redis');
|
||||||
$database->redis_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->redis_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environment_id;
|
$database->environment_id = $environment_id;
|
||||||
@@ -65,7 +65,7 @@ function create_standalone_mongodb($environment_id, $destination_uuid, ?array $o
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneMongodb();
|
$database = new StandaloneMongodb;
|
||||||
$database->name = generate_database_name('mongodb');
|
$database->name = generate_database_name('mongodb');
|
||||||
$database->mongo_initdb_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->mongo_initdb_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environment_id;
|
$database->environment_id = $environment_id;
|
||||||
@@ -84,7 +84,7 @@ function create_standalone_mysql($environment_id, $destination_uuid, ?array $oth
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneMysql();
|
$database = new StandaloneMysql;
|
||||||
$database->name = generate_database_name('mysql');
|
$database->name = generate_database_name('mysql');
|
||||||
$database->mysql_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->mysql_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->mysql_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->mysql_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
@@ -104,7 +104,7 @@ function create_standalone_mariadb($environment_id, $destination_uuid, ?array $o
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneMariadb();
|
$database = new StandaloneMariadb;
|
||||||
$database->name = generate_database_name('mariadb');
|
$database->name = generate_database_name('mariadb');
|
||||||
$database->mariadb_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->mariadb_root_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->mariadb_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->mariadb_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
@@ -125,7 +125,7 @@ function create_standalone_keydb($environment_id, $destination_uuid, ?array $oth
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneKeydb();
|
$database = new StandaloneKeydb;
|
||||||
$database->name = generate_database_name('keydb');
|
$database->name = generate_database_name('keydb');
|
||||||
$database->keydb_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->keydb_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environment_id;
|
$database->environment_id = $environment_id;
|
||||||
@@ -145,7 +145,7 @@ function create_standalone_dragonfly($environment_id, $destination_uuid, ?array
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneDragonfly();
|
$database = new StandaloneDragonfly;
|
||||||
$database->name = generate_database_name('dragonfly');
|
$database->name = generate_database_name('dragonfly');
|
||||||
$database->dragonfly_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->dragonfly_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environment_id;
|
$database->environment_id = $environment_id;
|
||||||
@@ -164,7 +164,7 @@ function create_standalone_clickhouse($environment_id, $destination_uuid, ?array
|
|||||||
if (! $destination) {
|
if (! $destination) {
|
||||||
throw new Exception('Destination not found');
|
throw new Exception('Destination not found');
|
||||||
}
|
}
|
||||||
$database = new StandaloneClickhouse();
|
$database = new StandaloneClickhouse;
|
||||||
$database->name = generate_database_name('clickhouse');
|
$database->name = generate_database_name('clickhouse');
|
||||||
$database->clickhouse_admin_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
$database->clickhouse_admin_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
|
||||||
$database->environment_id = $environment_id;
|
$database->environment_id = $environment_id;
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ use Lcobucci\JWT\Token\Builder;
|
|||||||
function generate_github_installation_token(GithubApp $source)
|
function generate_github_installation_token(GithubApp $source)
|
||||||
{
|
{
|
||||||
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
||||||
$algorithm = new Sha256();
|
$algorithm = new Sha256;
|
||||||
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
$tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable;
|
||||||
$now = $now->setTime($now->format('H'), $now->format('i'));
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
||||||
$issuedToken = $tokenBuilder
|
$issuedToken = $tokenBuilder
|
||||||
->issuedBy($source->app_id)
|
->issuedBy($source->app_id)
|
||||||
@@ -38,9 +38,9 @@ function generate_github_installation_token(GithubApp $source)
|
|||||||
function generate_github_jwt_token(GithubApp $source)
|
function generate_github_jwt_token(GithubApp $source)
|
||||||
{
|
{
|
||||||
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
$signingKey = InMemory::plainText($source->privateKey->private_key);
|
||||||
$algorithm = new Sha256();
|
$algorithm = new Sha256;
|
||||||
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
$tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable;
|
||||||
$now = $now->setTime($now->format('H'), $now->format('i'));
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
||||||
$issuedToken = $tokenBuilder
|
$issuedToken = $tokenBuilder
|
||||||
->issuedBy($source->app_id)
|
->issuedBy($source->app_id)
|
||||||
|
|||||||
@@ -73,6 +73,13 @@ function getFilesystemVolumesFromServer(ServiceApplication|ServiceDatabase|Appli
|
|||||||
"echo '$content' | base64 -d | tee $fileLocation",
|
"echo '$content' | base64 -d | tee $fileLocation",
|
||||||
], $server);
|
], $server);
|
||||||
} elseif ($isFile == 'NOK' && $isDir == 'NOK' && $fileVolume->is_directory && $isInit) {
|
} elseif ($isFile == 'NOK' && $isDir == 'NOK' && $fileVolume->is_directory && $isInit) {
|
||||||
|
// Does not exists (no dir or file), flagged as directory, is init
|
||||||
|
$fileVolume->content = null;
|
||||||
|
$fileVolume->is_directory = true;
|
||||||
|
$fileVolume->save();
|
||||||
|
instant_remote_process(["mkdir -p $fileLocation"], $server);
|
||||||
|
} elseif ($isFile == 'NOK' && $isDir == 'NOK' && ! $fileVolume->is_directory && $isInit && ! $content) {
|
||||||
|
// Does not exists (no dir or file), not flagged as directory, is init, has no content => create directory
|
||||||
$fileVolume->content = null;
|
$fileVolume->content = null;
|
||||||
$fileVolume->is_directory = true;
|
$fileVolume->is_directory = true;
|
||||||
$fileVolume->save();
|
$fileVolume->save();
|
||||||
@@ -109,7 +116,7 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
if ($resourceFqdns->count() === 1) {
|
if ($resourceFqdns->count() === 1) {
|
||||||
$resourceFqdns = $resourceFqdns->first();
|
$resourceFqdns = $resourceFqdns->first();
|
||||||
$variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
|
$variableName = 'SERVICE_FQDN_'.str($resource->name)->upper()->replace('-', '');
|
||||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', 'LIKE', "{$variableName}_%")->first();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
$fqdn = Url::fromString($resourceFqdns);
|
$fqdn = Url::fromString($resourceFqdns);
|
||||||
$port = $fqdn->getPort();
|
$port = $fqdn->getPort();
|
||||||
$path = $fqdn->getPath();
|
$path = $fqdn->getPath();
|
||||||
@@ -121,14 +128,13 @@ function updateCompose(ServiceApplication|ServiceDatabase $resource)
|
|||||||
if ($port) {
|
if ($port) {
|
||||||
$variableName = $variableName."_$port";
|
$variableName = $variableName."_$port";
|
||||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
// ray($generatedEnv);
|
|
||||||
if ($generatedEnv) {
|
if ($generatedEnv) {
|
||||||
$generatedEnv->value = $fqdn.$path;
|
$generatedEnv->value = $fqdn.$path;
|
||||||
$generatedEnv->save();
|
$generatedEnv->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
|
$variableName = 'SERVICE_URL_'.str($resource->name)->upper()->replace('-', '');
|
||||||
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', 'LIKE', "{$variableName}_%")->first();
|
$generatedEnv = EnvironmentVariable::where('service_id', $resource->service_id)->where('key', $variableName)->first();
|
||||||
$url = Url::fromString($fqdn);
|
$url = Url::fromString($fqdn);
|
||||||
$port = $url->getPort();
|
$port = $url->getPort();
|
||||||
$path = $url->getPath();
|
$path = $url->getPath();
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ function generate_random_name(?string $cuid = null): string
|
|||||||
{
|
{
|
||||||
$generator = new \Nubs\RandomNameGenerator\All(
|
$generator = new \Nubs\RandomNameGenerator\All(
|
||||||
[
|
[
|
||||||
new \Nubs\RandomNameGenerator\Alliteration(),
|
new \Nubs\RandomNameGenerator\Alliteration,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
if (is_null($cuid)) {
|
if (is_null($cuid)) {
|
||||||
@@ -977,6 +977,8 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$target = str($volume)->after(':')->beforeLast(':');
|
$target = str($volume)->after(':')->beforeLast(':');
|
||||||
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
if ($source->startsWith('./') || $source->startsWith('/') || $source->startsWith('~')) {
|
||||||
$type = str('bind');
|
$type = str('bind');
|
||||||
|
// By default, we cannot determine if the bind is a directory or not, so we set it to directory
|
||||||
|
$isDirectory = true;
|
||||||
} else {
|
} else {
|
||||||
$type = str('volume');
|
$type = str('volume');
|
||||||
}
|
}
|
||||||
@@ -985,14 +987,19 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
$source = data_get_str($volume, 'source');
|
$source = data_get_str($volume, 'source');
|
||||||
$target = data_get_str($volume, 'target');
|
$target = data_get_str($volume, 'target');
|
||||||
$content = data_get($volume, 'content');
|
$content = data_get($volume, 'content');
|
||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', false) || (bool) data_get($volume, 'is_directory', false);
|
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
||||||
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
$foundConfig = $savedService->fileStorages()->whereMountPath($target)->first();
|
||||||
if ($foundConfig) {
|
if ($foundConfig) {
|
||||||
$contentNotNull = data_get($foundConfig, 'content');
|
$contentNotNull = data_get($foundConfig, 'content');
|
||||||
if ($contentNotNull) {
|
if ($contentNotNull) {
|
||||||
$content = $contentNotNull;
|
$content = $contentNotNull;
|
||||||
}
|
}
|
||||||
$isDirectory = (bool) data_get($volume, 'isDirectory', false) || (bool) data_get($volume, 'is_directory', false);
|
$isDirectory = (bool) data_get($volume, 'isDirectory', null) || (bool) data_get($volume, 'is_directory', null);
|
||||||
|
}
|
||||||
|
if (is_null($isDirectory) && is_null($content)) {
|
||||||
|
// if isDirectory is not set & content is also not set, we assume it is a directory
|
||||||
|
ray('setting isDirectory to true');
|
||||||
|
$isDirectory = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($type?->value() === 'bind') {
|
if ($type?->value() === 'bind') {
|
||||||
@@ -1058,30 +1065,26 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
data_set($service, 'volumes', $serviceVolumes->toArray());
|
data_set($service, 'volumes', $serviceVolumes->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add env_file with at least .env to the service
|
|
||||||
// $envFile = collect(data_get($service, 'env_file', []));
|
|
||||||
// if ($envFile->count() > 0) {
|
|
||||||
// if (!$envFile->contains('.env')) {
|
|
||||||
// $envFile->push('.env');
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// $envFile = collect(['.env']);
|
|
||||||
// }
|
|
||||||
// data_set($service, 'env_file', $envFile->toArray());
|
|
||||||
|
|
||||||
// Get variables from the service
|
// Get variables from the service
|
||||||
foreach ($serviceVariables as $variableName => $variable) {
|
foreach ($serviceVariables as $variableName => $variable) {
|
||||||
if (is_numeric($variableName)) {
|
if (is_numeric($variableName)) {
|
||||||
$variable = str($variable);
|
if (is_array($variable)) {
|
||||||
if ($variable->contains('=')) {
|
// - SESSION_SECRET: 123
|
||||||
// - SESSION_SECRET=123
|
// - SESSION_SECRET:
|
||||||
// - SESSION_SECRET=
|
$key = str(collect($variable)->keys()->first());
|
||||||
$key = $variable->before('=');
|
$value = str(collect($variable)->values()->first());
|
||||||
$value = $variable->after('=');
|
|
||||||
} else {
|
} else {
|
||||||
// - SESSION_SECRET
|
$variable = str($variable);
|
||||||
$key = $variable;
|
if ($variable->contains('=')) {
|
||||||
$value = null;
|
// - SESSION_SECRET=123
|
||||||
|
// - SESSION_SECRET=
|
||||||
|
$key = $variable->before('=');
|
||||||
|
$value = $variable->after('=');
|
||||||
|
} else {
|
||||||
|
// - SESSION_SECRET
|
||||||
|
$key = $variable;
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// SESSION_SECRET: 123
|
// SESSION_SECRET: 123
|
||||||
@@ -1735,6 +1738,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
if (is_array($volume)) {
|
if (is_array($volume)) {
|
||||||
return data_get($volume, 'source');
|
return data_get($volume, 'source');
|
||||||
}
|
}
|
||||||
|
dispatch(new ServerFilesFromServerJob($resource));
|
||||||
|
|
||||||
return $volume->value();
|
return $volume->value();
|
||||||
});
|
});
|
||||||
@@ -1836,16 +1840,23 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
|
|||||||
// Get variables from the service
|
// Get variables from the service
|
||||||
foreach ($serviceVariables as $variableName => $variable) {
|
foreach ($serviceVariables as $variableName => $variable) {
|
||||||
if (is_numeric($variableName)) {
|
if (is_numeric($variableName)) {
|
||||||
$variable = str($variable);
|
if (is_array($variable)) {
|
||||||
if ($variable->contains('=')) {
|
// - SESSION_SECRET: 123
|
||||||
// - SESSION_SECRET=123
|
// - SESSION_SECRET:
|
||||||
// - SESSION_SECRET=
|
$key = str(collect($variable)->keys()->first());
|
||||||
$key = $variable->before('=');
|
$value = str(collect($variable)->values()->first());
|
||||||
$value = $variable->after('=');
|
|
||||||
} else {
|
} else {
|
||||||
// - SESSION_SECRET
|
$variable = str($variable);
|
||||||
$key = $variable;
|
if ($variable->contains('=')) {
|
||||||
$value = null;
|
// - SESSION_SECRET=123
|
||||||
|
// - SESSION_SECRET=
|
||||||
|
$key = $variable->before('=');
|
||||||
|
$value = $variable->after('=');
|
||||||
|
} else {
|
||||||
|
// - SESSION_SECRET
|
||||||
|
$key = $variable;
|
||||||
|
$value = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// SESSION_SECRET: 123
|
// SESSION_SECRET: 123
|
||||||
@@ -2187,9 +2198,9 @@ function generateEnvValue(string $command, ?Service $service = null)
|
|||||||
$signingKey = $signingKey->value;
|
$signingKey = $signingKey->value;
|
||||||
}
|
}
|
||||||
$key = InMemory::plainText($signingKey);
|
$key = InMemory::plainText($signingKey);
|
||||||
$algorithm = new Sha256();
|
$algorithm = new Sha256;
|
||||||
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
$tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable;
|
||||||
$now = $now->setTime($now->format('H'), $now->format('i'));
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
||||||
$token = $tokenBuilder
|
$token = $tokenBuilder
|
||||||
->issuedBy('supabase')
|
->issuedBy('supabase')
|
||||||
@@ -2207,9 +2218,9 @@ function generateEnvValue(string $command, ?Service $service = null)
|
|||||||
$signingKey = $signingKey->value;
|
$signingKey = $signingKey->value;
|
||||||
}
|
}
|
||||||
$key = InMemory::plainText($signingKey);
|
$key = InMemory::plainText($signingKey);
|
||||||
$algorithm = new Sha256();
|
$algorithm = new Sha256;
|
||||||
$tokenBuilder = (new Builder(new JoseEncoder(), ChainedFormatter::default()));
|
$tokenBuilder = (new Builder(new JoseEncoder, ChainedFormatter::default()));
|
||||||
$now = new DateTimeImmutable();
|
$now = new DateTimeImmutable;
|
||||||
$now = $now->setTime($now->format('H'), $now->format('i'));
|
$now = $now->setTime($now->format('H'), $now->format('i'));
|
||||||
$token = $tokenBuilder
|
$token = $tokenBuilder
|
||||||
->issuedBy('supabase')
|
->issuedBy('supabase')
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ return [
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.317',
|
'release' => '4.0.0-beta.319',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.317';
|
return '4.0.0-beta.319';
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ return new class extends Migration
|
|||||||
|
|
||||||
EnvironmentVariable::all()->each(function (EnvironmentVariable $environmentVariable) {
|
EnvironmentVariable::all()->each(function (EnvironmentVariable $environmentVariable) {
|
||||||
$environmentVariable->update([
|
$environmentVariable->update([
|
||||||
'uuid' => (string) new Cuid2(),
|
'uuid' => (string) new Cuid2,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
Schema::table('environment_variables', function (Blueprint $table) {
|
Schema::table('environment_variables', function (Blueprint $table) {
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->boolean('health_check_enabled')->default(false)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('applications', function (Blueprint $table) {
|
||||||
|
$table->boolean('health_check_enabled')->default(true)->change();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->text('validation_logs')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('servers', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('validation_logs');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -178,7 +178,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
|
|||||||
|
|
||||||
get_public_ips();
|
get_public_ips();
|
||||||
|
|
||||||
$oauth_settings_seeder = new OauthSettingSeeder();
|
$oauth_settings_seeder = new OauthSettingSeeder;
|
||||||
$oauth_settings_seeder->run();
|
$oauth_settings_seeder->run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::table('services', function (Blueprint $table) {
|
|
||||||
$table->string('git_repository')->nullable();
|
|
||||||
$table->string('git_branch')->nullable();
|
|
||||||
$table->nullableMorphs('source');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::table('services', function (Blueprint $table) {
|
|
||||||
$table->dropColumn('git_repository');
|
|
||||||
$table->dropColumn('git_branch');
|
|
||||||
$table->dropMorphs('source');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
486
openapi.yaml
486
openapi.yaml
@@ -3010,6 +3010,44 @@ paths:
|
|||||||
security:
|
security:
|
||||||
-
|
-
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Projects
|
||||||
|
summary: Create
|
||||||
|
description: 'Create Project.'
|
||||||
|
operationId: cf067eb7cf18216cda3239329a2eeadb
|
||||||
|
requestBody:
|
||||||
|
description: 'Project created.'
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
uuid:
|
||||||
|
type: string
|
||||||
|
description: 'The name of the project.'
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: 'The description of the project.'
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: 'Project created.'
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
uuid: { type: string, example: og888os, description: 'The UUID of the project.' }
|
||||||
|
type: object
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/400'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/404'
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
'/projects/{uuid}':
|
'/projects/{uuid}':
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -3041,6 +3079,79 @@ paths:
|
|||||||
security:
|
security:
|
||||||
-
|
-
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- Projects
|
||||||
|
summary: Delete
|
||||||
|
description: 'Delete project by UUID.'
|
||||||
|
operationId: f668a936f505b4401948c74b6a663029
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
name: uuid
|
||||||
|
in: path
|
||||||
|
description: 'UUID of the application.'
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 'Project deleted.'
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
message: { type: string, example: 'Project deleted.' }
|
||||||
|
type: object
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/400'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/404'
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- Projects
|
||||||
|
summary: Update
|
||||||
|
description: 'Update Project.'
|
||||||
|
operationId: 2db343bd6fc14c658cb51a2b73b2f842
|
||||||
|
requestBody:
|
||||||
|
description: 'Project updated.'
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: 'The name of the project.'
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
description: 'The description of the project.'
|
||||||
|
type: object
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
description: 'Project updated.'
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
uuid: { type: string, example: og888os }
|
||||||
|
name: { type: string, example: 'Project Name' }
|
||||||
|
description: { type: string, example: 'Project Description' }
|
||||||
|
type: object
|
||||||
|
'401':
|
||||||
|
$ref: '#/components/responses/401'
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/responses/400'
|
||||||
|
'404':
|
||||||
|
$ref: '#/components/responses/404'
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
'/projects/{uuid}/{environment_name}':
|
'/projects/{uuid}/{environment_name}':
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -3288,6 +3399,70 @@ paths:
|
|||||||
security:
|
security:
|
||||||
-
|
-
|
||||||
bearerAuth: []
|
bearerAuth: []
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Servers
|
||||||
|
summary: Create
|
||||||
|
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}':
|
'/servers/{uuid}':
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -3319,6 +3494,95 @@ paths:
|
|||||||
security:
|
security:
|
||||||
-
|
-
|
||||||
bearerAuth: []
|
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
|
||||||
|
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':
|
'/servers/{uuid}/resources':
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -3383,6 +3647,39 @@ paths:
|
|||||||
security:
|
security:
|
||||||
-
|
-
|
||||||
bearerAuth: []
|
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:
|
/services:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@@ -4189,191 +4486,35 @@ components:
|
|||||||
$ref: '#/components/schemas/Environment'
|
$ref: '#/components/schemas/Environment'
|
||||||
type: object
|
type: object
|
||||||
Server:
|
Server:
|
||||||
description: 'Application model'
|
description: 'Server model'
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
repository_project_id:
|
|
||||||
type: integer
|
|
||||||
nullable: true
|
|
||||||
uuid:
|
uuid:
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
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:
|
description:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
ip:
|
||||||
dockerfile:
|
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
user:
|
||||||
health_check_enabled:
|
|
||||||
type: boolean
|
|
||||||
dockerfile_location:
|
|
||||||
type: string
|
type: string
|
||||||
custom_labels:
|
port:
|
||||||
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
|
type: integer
|
||||||
swarm_placement_constraints:
|
proxy:
|
||||||
type: string
|
type: object
|
||||||
nullable: true
|
high_disk_usage_notification_sent:
|
||||||
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
|
type: boolean
|
||||||
manual_webhook_secret_gitea:
|
unreachable_notification_sent:
|
||||||
|
type: boolean
|
||||||
|
unreachable_count:
|
||||||
|
type: integer
|
||||||
|
validation_logs:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
log_drain_notification_sent:
|
||||||
redirect:
|
type: boolean
|
||||||
|
swarm_cluster:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
ServerSetting:
|
ServerSetting:
|
||||||
@@ -4480,6 +4621,9 @@ components:
|
|||||||
is_container_label_escape_enabled:
|
is_container_label_escape_enabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 'The flag to enable the container label escape.'
|
description: 'The flag to enable the container label escape.'
|
||||||
|
is_container_label_readonly_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: 'The flag to enable the container label readonly.'
|
||||||
config_hash:
|
config_hash:
|
||||||
type: string
|
type: string
|
||||||
description: 'The hash of the service configuration.'
|
description: 'The hash of the service configuration.'
|
||||||
|
|||||||
BIN
other/logos/branddev.png
Normal file
BIN
other/logos/branddev.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
@@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@if (!str($status)->startsWith('Proxy') && !str($status)->contains('('))
|
@if (!str($status)->startsWith('Proxy') && !str($status)->contains('('))
|
||||||
@if (str($status)->contains('unhealthy'))
|
@if (str($status)->contains('unhealthy'))
|
||||||
<x-helper helper="Unhealthy state. <span class='dark:text-warning text-coollabs'>This doesn't mean that the resource is malfunctioning.</span><br><br>- If the resource is accessible, it indicates that no health check is configured - it is not mandatory.<br>- If the resource is not accessible (returning 404 or 503), it may indicate that a health check is needed and has not passed. <span class='dark:text-warning text-coollabs'>Your action is required.</span>" >
|
<x-helper helper="Unhealthy state. <span class='dark:text-warning text-coollabs'>This doesn't mean that the resource is malfunctioning.</span><br><br>- If the resource is accessible, it indicates that no health check is configured - it is not mandatory.<br>- If the resource is not accessible (returning 404 or 503), it may indicate that a health check is needed and has not passed. <span class='dark:text-warning text-coollabs'>Your action is required.</span><br><br>More details in the <a href='https://coolify.io/docs/knowledge-base/healthchecks' class='underline dark:text-warning text-coollabs' target='_blank'>documentation</a>." >
|
||||||
<x-slot:icon>
|
<x-slot:icon>
|
||||||
<svg class="hidden w-4 h-4 dark:text-warning lg:block" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
<svg class="hidden w-4 h-4 dark:text-warning lg:block" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill="currentColor" d="M240.26 186.1L152.81 34.23a28.74 28.74 0 0 0-49.62 0L15.74 186.1a27.45 27.45 0 0 0 0 27.71A28.31 28.31 0 0 0 40.55 228h174.9a28.31 28.31 0 0 0 24.79-14.19a27.45 27.45 0 0 0 .02-27.71m-20.8 15.7a4.46 4.46 0 0 1-4 2.2H40.55a4.46 4.46 0 0 1-4-2.2a3.56 3.56 0 0 1 0-3.73L124 46.2a4.77 4.77 0 0 1 8 0l87.44 151.87a3.56 3.56 0 0 1 .02 3.73M116 136v-32a12 12 0 0 1 24 0v32a12 12 0 0 1-24 0m28 40a16 16 0 1 1-16-16a16 16 0 0 1 16 16"></path>
|
<path fill="currentColor" d="M240.26 186.1L152.81 34.23a28.74 28.74 0 0 0-49.62 0L15.74 186.1a27.45 27.45 0 0 0 0 27.71A28.31 28.31 0 0 0 40.55 228h174.9a28.31 28.31 0 0 0 24.79-14.19a27.45 27.45 0 0 0 .02-27.71m-20.8 15.7a4.46 4.46 0 0 1-4 2.2H40.55a4.46 4.46 0 0 1-4-2.2a3.56 3.56 0 0 1 0-3.73L124 46.2a4.77 4.77 0 0 1 8 0l87.44 151.87a3.56 3.56 0 0 1 .02 3.73M116 136v-32a12 12 0 0 1 24 0v32a12 12 0 0 1-24 0m28 40a16 16 0 1 1-16-16a16 16 0 0 1 16 16"></path>
|
||||||
|
|||||||
@@ -106,7 +106,7 @@
|
|||||||
<livewire:project.shared.destination :resource="$application" :servers="$servers" />
|
<livewire:project.shared.destination :resource="$application" :servers="$servers" />
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'storages'">
|
<div x-cloak x-show="activeTab === 'storages'">
|
||||||
<livewire:project.service.storage :resource="$application" />
|
<livewire:project.service.storage :resource="$application" lazy />
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'webhooks'">
|
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||||
<livewire:project.shared.webhooks :resource="$application" lazy />
|
<livewire:project.shared.webhooks :resource="$application" lazy />
|
||||||
|
|||||||
@@ -175,15 +175,15 @@
|
|||||||
<div class="pb-4 dark:text-warning text-coollabs">If you would like to add a volume, you must add it to
|
<div class="pb-4 dark:text-warning text-coollabs">If you would like to add a volume, you must add it to
|
||||||
your compose file (General tab).</div>
|
your compose file (General tab).</div>
|
||||||
@foreach ($applications as $application)
|
@foreach ($applications as $application)
|
||||||
<livewire:project.service.storage wire:key="application-{{ $application->id }}"
|
<livewire:project.service.storage wire:key="application-{{ $application->id }}" :resource="$application"
|
||||||
:resource="$application" />
|
lazy />
|
||||||
@endforeach
|
@endforeach
|
||||||
@foreach ($databases as $database)
|
@foreach ($databases as $database)
|
||||||
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" />
|
<livewire:project.service.storage wire:key="database-{{ $database->id }}" :resource="$database" lazy />
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'scheduled-tasks'">
|
<div x-cloak x-show="activeTab === 'scheduled-tasks'">
|
||||||
<livewire:project.shared.scheduled-task.all :resource="$service" />
|
<livewire:project.shared.scheduled-task.all :resource="$service" lazy />
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'webhooks'">
|
<div x-cloak x-show="activeTab === 'webhooks'">
|
||||||
<livewire:project.shared.webhooks :resource="$service" />
|
<livewire:project.shared.webhooks :resource="$service" />
|
||||||
|
|||||||
@@ -8,25 +8,35 @@
|
|||||||
<h3 class="pt-4">Limit CPUs</h3>
|
<h3 class="pt-4">Limit CPUs</h3>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input placeholder="1.5"
|
<x-forms.input placeholder="1.5"
|
||||||
helper="0 means use all CPUs. Floating point number, like 0.002 or 1.5. More info <a class='dark:text-white underline' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
helper="0 means use all CPUs. Floating point number, like 0.002 or 1.5. More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
||||||
label="Number of CPUs" id="resource.limits_cpus" />
|
label="Number of CPUs" id="resource.limits_cpus" />
|
||||||
<x-forms.input placeholder="0-2"
|
<x-forms.input placeholder="0-2"
|
||||||
helper="Empty means, use all CPU sets. 0-2 will use CPU 0, CPU 1 and CPU 2. More info <a class='dark:text-white underline' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
helper="Empty means, use all CPU sets. 0-2 will use CPU 0, CPU 1 and CPU 2. More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
||||||
label="CPU sets to use" id="resource.limits_cpuset" />
|
label="CPU sets to use" id="resource.limits_cpuset" />
|
||||||
<x-forms.input placeholder="1024"
|
<x-forms.input placeholder="1024"
|
||||||
helper="More info <a class='dark:text-white underline' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
helper="More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/engine/reference/run/#cpu-share-constraint'>here</a>."
|
||||||
label="CPU Weight" id="resource.limits_cpu_shares" />
|
label="CPU Weight" id="resource.limits_cpu_shares" />
|
||||||
</div>
|
</div>
|
||||||
<h3 class="pt-4">Limit Memory</h3>
|
<h3 class="pt-4">Limit Memory</h3>
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<x-forms.input placeholder="69b or 420k or 1337m or 1g" label="Soft Memory Limit"
|
<div class="flex gap-2">
|
||||||
id="resource.limits_memory_reservation" />
|
<x-forms.input
|
||||||
<x-forms.input placeholder="69b or 420k or 1337m or 1g" label="Maximum Memory Limit"
|
helper="Examples: 69b (byte) or 420k (kilobyte) or 1337m (megabyte) or 1g (gigabyte).<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#mem_reservation'>here</a>."
|
||||||
id="resource.limits_memory" />
|
label="Soft Memory Limit" id="resource.limits_memory_reservation" />
|
||||||
<x-forms.input placeholder="69b or 420k or 1337m or 1g" label="Maximum Swap Limit"
|
<x-forms.input
|
||||||
id="resource.limits_memory_swap" />
|
helper="0-100.<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#mem_swappiness'>here</a>."
|
||||||
<x-forms.input placeholder="0-100" type="number" min="0" max="100" label="Swappiness"
|
type="number" min="0" max="100" label="Swappiness"
|
||||||
id="resource.limits_memory_swappiness" />
|
id="resource.limits_memory_swappiness" />
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<x-forms.input
|
||||||
|
helper="Examples: 69b (byte) or 420k (kilobyte) or 1337m (megabyte) or 1g (gigabyte).<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#mem_limit'>here</a>."
|
||||||
|
label="Maximum Memory Limit" id="resource.limits_memory" />
|
||||||
|
<x-forms.input
|
||||||
|
helper="Examples:69b (byte) or 420k (kilobyte) or 1337m (megabyte) or 1g (gigabyte).<br>More info <a class='underline dark:text-white' target='_blank' href='https://docs.docker.com/compose/compose-file/05-services/#memswap_limit'>here</a>."
|
||||||
|
label="Maximum Swap Limit" id="resource.limits_memory_swap" />
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,6 +40,12 @@
|
|||||||
Validate Server & Install Docker Engine
|
Validate Server & Install Docker Engine
|
||||||
</x-forms.button>
|
</x-forms.button>
|
||||||
</x-slide-over>
|
</x-slide-over>
|
||||||
|
@if ($server->validation_logs)
|
||||||
|
<h4>Previous Validation Logs</h4>
|
||||||
|
<div class="pb-8">
|
||||||
|
{!! $server->validation_logs !!}
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
@endif
|
@endif
|
||||||
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id === 0)
|
@if ((!$server->settings->is_reachable || !$server->settings->is_usable) && $server->id === 0)
|
||||||
<x-forms.button class="mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100"
|
<x-forms.button class="mt-8 mb-4 font-bold box-without-bg bg-coollabs hover:bg-coollabs-100"
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ Route::group([
|
|||||||
Route::get('/projects/{uuid}', [ProjectController::class, 'project_by_uuid']);
|
Route::get('/projects/{uuid}', [ProjectController::class, 'project_by_uuid']);
|
||||||
Route::get('/projects/{uuid}/{environment_name}', [ProjectController::class, 'environment_details']);
|
Route::get('/projects/{uuid}/{environment_name}', [ProjectController::class, 'environment_details']);
|
||||||
|
|
||||||
|
Route::post('/projects', [ProjectController::class, 'create_project']);
|
||||||
|
Route::patch('/projects/{uuid}', [ProjectController::class, 'update_project']);
|
||||||
|
Route::delete('/projects/{uuid}', [ProjectController::class, 'delete_project']);
|
||||||
|
|
||||||
Route::get('/security/keys', [SecurityController::class, 'keys']);
|
Route::get('/security/keys', [SecurityController::class, 'keys']);
|
||||||
Route::post('/security/keys', [SecurityController::class, 'create_key'])->middleware([IgnoreReadOnlyApiToken::class]);
|
Route::post('/security/keys', [SecurityController::class, 'create_key'])->middleware([IgnoreReadOnlyApiToken::class]);
|
||||||
|
|
||||||
@@ -57,6 +61,12 @@ Route::group([
|
|||||||
Route::get('/servers/{uuid}/domains', [ServersController::class, 'domains_by_server']);
|
Route::get('/servers/{uuid}/domains', [ServersController::class, 'domains_by_server']);
|
||||||
Route::get('/servers/{uuid}/resources', [ServersController::class, 'resources_by_server']);
|
Route::get('/servers/{uuid}/resources', [ServersController::class, 'resources_by_server']);
|
||||||
|
|
||||||
|
Route::get('/servers/{uuid}/validate', [ServersController::class, 'validate_server']);
|
||||||
|
|
||||||
|
Route::post('/servers', [ServersController::class, 'create_server']);
|
||||||
|
Route::patch('/servers/{uuid}', [ServersController::class, 'update_server']);
|
||||||
|
Route::delete('/servers/{uuid}', [ServersController::class, 'delete_server']);
|
||||||
|
|
||||||
Route::get('/resources', [ResourcesController::class, 'resources']);
|
Route::get('/resources', [ResourcesController::class, 'resources']);
|
||||||
|
|
||||||
Route::get('/applications', [ApplicationsController::class, 'applications']);
|
Route::get('/applications', [ApplicationsController::class, 'applications']);
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
|
|
||||||
x-app-env: &app-env
|
x-app-env: &app-env
|
||||||
environment:
|
environment:
|
||||||
- WEB_URL=http://localhost
|
- WEB_URL=${SERVICE_FQDN_PLANE}
|
||||||
- DEBUG=${DEBUG:-0}
|
- DEBUG=${DEBUG:-0}
|
||||||
- CORS_ALLOWED_ORIGINS=http://localhost
|
- CORS_ALLOWED_ORIGINS=${CORS_ALLOWED_ORIGIN:-http://localhost}
|
||||||
# Gunicorn Workers
|
# Gunicorn Workers
|
||||||
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
|
- GUNICORN_WORKERS=${GUNICORN_WORKERS:-1}
|
||||||
#DB SETTINGS
|
#DB SETTINGS
|
||||||
@@ -28,8 +28,8 @@ x-app-env: &app-env
|
|||||||
# DATA STORE SETTINGS
|
# DATA STORE SETTINGS
|
||||||
- USE_MINIO=${USE_MINIO:-1}
|
- USE_MINIO=${USE_MINIO:-1}
|
||||||
- AWS_REGION=${AWS_REGION}
|
- AWS_REGION=${AWS_REGION}
|
||||||
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
|
- AWS_ACCESS_KEY_ID=$SERVICE_USER_MINIO
|
||||||
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
|
- AWS_SECRET_ACCESS_KEY=$SERVICE_PASSWORD_MINIO
|
||||||
- AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
|
- AWS_S3_ENDPOINT_URL=${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000}
|
||||||
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads}
|
- AWS_S3_BUCKET_NAME=${AWS_S3_BUCKET_NAME:-uploads}
|
||||||
- MINIO_ROOT_USER=$SERVICE_USER_MINIO
|
- MINIO_ROOT_USER=$SERVICE_USER_MINIO
|
||||||
@@ -39,13 +39,14 @@ x-app-env: &app-env
|
|||||||
# Admin and Space URLs
|
# Admin and Space URLs
|
||||||
- ADMIN_BASE_URL=${ADMIN_BASE_URL}
|
- ADMIN_BASE_URL=${ADMIN_BASE_URL}
|
||||||
- SPACE_BASE_URL=${SPACE_BASE_URL}
|
- SPACE_BASE_URL=${SPACE_BASE_URL}
|
||||||
- APP_BASE_URL=${APP_BASE_URL}
|
- APP_BASE_URL=${SERVICE_FQDN_PLANE}
|
||||||
|
|
||||||
services:
|
services:
|
||||||
proxy:
|
proxy:
|
||||||
environment:
|
environment:
|
||||||
- SERVICE_FQDN_PLANE
|
- SERVICE_FQDN_PLANE
|
||||||
- FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
|
- FILE_SIZE_LIMIT=${FILE_SIZE_LIMIT:-5242880}
|
||||||
|
- BUCKET_NAME=${BUCKET_NAME:-uploads}
|
||||||
image: makeplane/plane-proxy:stable
|
image: makeplane/plane-proxy:stable
|
||||||
depends_on:
|
depends_on:
|
||||||
- web
|
- web
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ services:
|
|||||||
- DEFAULT_ORGANIZATION_NAME=${STUDIO_DEFAULT_ORGANIZATION:-Default Organization}
|
- DEFAULT_ORGANIZATION_NAME=${STUDIO_DEFAULT_ORGANIZATION:-Default Organization}
|
||||||
- DEFAULT_PROJECT_NAME=${STUDIO_DEFAULT_PROJECT:-Default Project}
|
- DEFAULT_PROJECT_NAME=${STUDIO_DEFAULT_PROJECT:-Default Project}
|
||||||
|
|
||||||
- SUPABASE_URL=${SERVICE_FQDN_SUPABASEKONG:-http://supabase-kong:8000}
|
- SUPABASE_URL=${SERVICE_FQDN_SUPABASEKONG}
|
||||||
- SUPABASE_PUBLIC_URL=${SERVICE_FQDN_SUPABASEKONG}
|
- SUPABASE_PUBLIC_URL=${SERVICE_FQDN_SUPABASEKONG}
|
||||||
- SUPABASE_ANON_KEY=${SERVICE_SUPABASEANON_KEY}
|
- SUPABASE_ANON_KEY=${SERVICE_SUPABASEANON_KEY}
|
||||||
- SUPABASE_SERVICE_KEY=${SERVICE_SUPABASESERVICE_KEY}
|
- SUPABASE_SERVICE_KEY=${SERVICE_SUPABASESERVICE_KEY}
|
||||||
@@ -1013,7 +1013,7 @@ services:
|
|||||||
"/dev/null",
|
"/dev/null",
|
||||||
"-H",
|
"-H",
|
||||||
"Authorization: Bearer ${SERVICE_SUPABASEANON_KEY}",
|
"Authorization: Bearer ${SERVICE_SUPABASEANON_KEY}",
|
||||||
"http://127.0.0.1:4000/api/tenants/realtime-dev/health"
|
"http://127.0.0.1:4000/api/tenants/realtime-dev/health",
|
||||||
]
|
]
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
interval: 5s
|
interval: 5s
|
||||||
@@ -1182,7 +1182,7 @@ services:
|
|||||||
retries: 3
|
retries: 3
|
||||||
environment:
|
environment:
|
||||||
- JWT_SECRET=${SERVICE_PASSWORD_JWT}
|
- JWT_SECRET=${SERVICE_PASSWORD_JWT}
|
||||||
- SUPABASE_URL=${SERVICE_FQDN_SUPABASEKONG:-http://supabase-kong:8000}
|
- SUPABASE_URL=${SERVICE_FQDN_SUPABASEKONG}
|
||||||
- SUPABASE_ANON_KEY=${SERVICE_SUPABASEANON_KEY}
|
- SUPABASE_ANON_KEY=${SERVICE_SUPABASEANON_KEY}
|
||||||
- SUPABASE_SERVICE_ROLE_KEY=${SERVICE_SUPABASESERVICE_KEY}
|
- SUPABASE_SERVICE_ROLE_KEY=${SERVICE_SUPABASESERVICE_KEY}
|
||||||
- SUPABASE_DB_URL=postgresql://postgres:${SERVICE_PASSWORD_POSTGRES}@${POSTGRES_HOSTNAME:-supabase-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}
|
- SUPABASE_DB_URL=postgresql://postgres:${SERVICE_PASSWORD_POSTGRES}@${POSTGRES_HOSTNAME:-supabase-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-postgres}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"coolify": {
|
"coolify": {
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.317"
|
"version": "4.0.0-beta.319"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user