Merge branch 'coollabsio:main' into main

This commit is contained in:
Jakubko
2024-10-01 22:08:32 +02:00
committed by GitHub
94 changed files with 1261 additions and 238 deletions

View File

@@ -46,9 +46,6 @@ class StartDragonfly
'networks' => [
$this->database->destination->network,
],
'ulimits' => [
'memlock' => '-1',
],
'labels' => [
'coolify.managed' => 'true',
],

View File

@@ -2,7 +2,6 @@
namespace App\Actions\Fortify;
use App\Models\InstanceSettings;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
@@ -20,7 +19,7 @@ class CreateNewUser implements CreatesNewUsers
*/
public function create(array $input): User
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->is_registration_enabled) {
abort(403);
}
@@ -48,7 +47,7 @@ class CreateNewUser implements CreatesNewUsers
$team = $user->teams()->first();
// Disable registration after first user is created
$settings = InstanceSettings::get();
$settings = instanceSettings();
$settings->is_registration_enabled = false;
$settings->save();
} else {

View File

@@ -2,7 +2,6 @@
namespace App\Actions\License;
use App\Models\InstanceSettings;
use Illuminate\Support\Facades\Http;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -13,7 +12,7 @@ class CheckResaleLicense
public function handle()
{
try {
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (isDev()) {
$settings->update([
'is_resale_license_active' => true,

View File

@@ -2,7 +2,6 @@
namespace App\Actions\Server;
use App\Models\InstanceSettings;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -12,7 +11,7 @@ class CleanupDocker
public function handle(Server $server)
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$helperImageVersion = data_get($settings, 'helper_version');
$helperImage = config('coolify.helper_image');
$helperImageWithVersion = "$helperImage:$helperImageVersion";

View File

@@ -3,7 +3,6 @@
namespace App\Actions\Server;
use App\Jobs\PullHelperImageJob;
use App\Models\InstanceSettings;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
@@ -20,7 +19,7 @@ class UpdateCoolify
public function handle($manual_update = false)
{
try {
$settings = InstanceSettings::get();
$settings = instanceSettings();
$this->server = Server::find(0);
if (! $this->server) {
return;

View File

@@ -48,6 +48,13 @@ class Dev extends Command
echo "Generating APP_KEY.\n";
Artisan::call('key:generate');
}
// Generate STORAGE link if not exists
if (! file_exists(public_path('storage'))) {
echo "Generating STORAGE link.\n";
Artisan::call('storage:link');
}
// Seed database if it's empty
$settings = InstanceSettings::find(0);
if (! $settings) {

View File

@@ -7,7 +7,6 @@ use App\Enums\ActivityTypes;
use App\Enums\ApplicationDeploymentStatus;
use App\Models\ApplicationDeploymentQueue;
use App\Models\Environment;
use App\Models\InstanceSettings;
use App\Models\ScheduledDatabaseBackup;
use App\Models\Server;
use App\Models\StandalonePostgresql;
@@ -69,7 +68,7 @@ class Init extends Command
} catch (\Throwable $e) {
echo "Could not setup dynamic configuration: {$e->getMessage()}\n";
}
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! is_null(env('AUTOUPDATE', null))) {
if (env('AUTOUPDATE') == true) {
$settings->update(['is_auto_update_enabled' => true]);
@@ -196,7 +195,7 @@ class Init extends Command
{
$id = config('app.id');
$version = config('version');
$settings = InstanceSettings::get();
$settings = instanceSettings();
$do_not_track = data_get($settings, 'do_not_track');
if ($do_not_track == true) {
echo "Skipping alive as do_not_track is enabled\n";

View File

@@ -12,8 +12,8 @@ use App\Jobs\PullSentinelImageJob;
use App\Jobs\PullTemplatesFromCDN;
use App\Jobs\ScheduledTaskJob;
use App\Jobs\ServerCheckJob;
use App\Jobs\ServerStorageCheckJob;
use App\Jobs\UpdateCoolifyJob;
use App\Models\InstanceSettings;
use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledTask;
use App\Models\Server;
@@ -28,7 +28,7 @@ class Kernel extends ConsoleKernel
protected function schedule(Schedule $schedule): void
{
$this->all_servers = Server::all();
$settings = InstanceSettings::get();
$settings = instanceSettings();
$schedule->job(new CleanupStaleMultiplexedConnections)->hourly();
@@ -66,7 +66,7 @@ class Kernel extends ConsoleKernel
private function pull_images($schedule)
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
foreach ($servers as $server) {
if ($server->isSentinelEnabled()) {
@@ -88,7 +88,7 @@ class Kernel extends ConsoleKernel
private function schedule_updates($schedule)
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$updateCheckFrequency = $settings->update_check_frequency;
$schedule->job(new CheckForUpdatesJob)
@@ -116,6 +116,7 @@ class Kernel extends ConsoleKernel
}
foreach ($servers as $server) {
$schedule->job(new ServerCheckJob($server))->everyMinute()->onOneServer();
// $schedule->job(new ServerStorageCheckJob($server))->everyMinute()->onOneServer();
$serverTimezone = $server->settings->server_timezone;
if ($server->settings->force_docker_cleanup) {
$schedule->job(new DockerCleanupJob($server))->cron($server->settings->docker_cleanup_frequency)->timezone($serverTimezone)->onOneServer();

View File

@@ -65,7 +65,7 @@ class Handler extends ExceptionHandler
if ($e instanceof RuntimeException) {
return;
}
$this->settings = \App\Models\InstanceSettings::get();
$this->settings = instanceSettings();
if ($this->settings->do_not_track) {
return;
}

View File

@@ -177,6 +177,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -279,6 +280,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -381,6 +383,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -468,6 +471,7 @@ class ApplicationsController extends Controller
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -552,6 +556,7 @@ class ApplicationsController extends Controller
'manual_webhook_secret_gitea' => ['type' => 'string', 'description' => 'Manual webhook secret for Gitea.'],
'redirect' => ['type' => 'string', 'nullable' => true, 'description' => 'How to set redirect with Traefik / Caddy. www<->non-www.', 'enum' => ['www', 'non-www', 'both']],
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -602,6 +607,7 @@ class ApplicationsController extends Controller
'name' => ['type' => 'string', 'description' => 'The application name.'],
'description' => ['type' => 'string', 'description' => 'The application description.'],
'instant_deploy' => ['type' => 'boolean', 'description' => 'The flag to indicate if the application should be deployed instantly.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -627,7 +633,7 @@ class ApplicationsController extends Controller
private function create_application(Request $request, $type)
{
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths'];
$allowedFields = ['project_uuid', 'environment_name', 'server_uuid', 'destination_uuid', 'type', 'name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'private_key_uuid', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'redirect', 'github_app_uuid', 'instant_deploy', 'dockerfile', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'watch_paths', 'use_build_server'];
$teamId = getTeamIdFromToken();
if (is_null($teamId)) {
return invalidTokenResponse();
@@ -665,6 +671,7 @@ class ApplicationsController extends Controller
$fqdn = $request->domains;
$instantDeploy = $request->instant_deploy;
$githubAppUuid = $request->github_app_uuid;
$useBuildServer = $request->use_build_server;
$project = Project::whereTeamId($teamId)->whereUuid($request->project_uuid)->first();
if (! $project) {
@@ -737,6 +744,8 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
@@ -833,6 +842,8 @@ class ApplicationsController extends Controller
$application->environment_id = $environment->id;
$application->source_type = $githubApp->getMorphClass();
$application->source_id = $githubApp->id;
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
@@ -925,6 +936,8 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
$application->save();
$application->refresh();
if (! $application->settings->is_container_label_readonly_enabled) {
@@ -1004,6 +1017,8 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
$application->git_repository = 'coollabsio/coolify';
$application->git_branch = 'main';
@@ -1062,6 +1077,8 @@ class ApplicationsController extends Controller
$application->destination_id = $destination->id;
$application->destination_type = $destination->getMorphClass();
$application->environment_id = $environment->id;
$application->settings->is_build_server_enabled = $useBuildServer;
$application->settings->save();
$application->git_repository = 'coollabsio/coolify';
$application->git_branch = 'main';
@@ -1259,16 +1276,10 @@ class ApplicationsController extends Controller
format: 'uuid',
)
),
new OA\Parameter(
name: 'cleanup',
in: 'query',
description: 'Delete configurations and volumes.',
required: false,
schema: new OA\Schema(
type: 'boolean',
default: true,
)
),
new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
],
responses: [
new OA\Response(
@@ -1316,10 +1327,14 @@ class ApplicationsController extends Controller
'message' => 'Application not found',
], 404);
}
DeleteResourceJob::dispatch(
resource: $application,
deleteConfigurations: $cleanup,
deleteVolumes: $cleanup);
deleteConfigurations: $request->query->get('delete_configurations', true),
deleteVolumes: $request->query->get('delete_volumes', true),
dockerCleanup: $request->query->get('docker_cleanup', true),
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
);
return response()->json([
'message' => 'Application deletion request queued.',
@@ -1404,6 +1419,7 @@ class ApplicationsController extends Controller
'docker_compose_custom_build_command' => ['type' => 'string', 'description' => 'The Docker Compose custom build command.'],
'docker_compose_domains' => ['type' => 'array', 'description' => 'The Docker Compose domains.'],
'watch_paths' => ['type' => 'string', 'description' => 'The watch paths.'],
'use_build_server' => ['type' => 'boolean', 'nullable' => true, 'description' => 'Use build server.'],
],
)),
]),
@@ -1460,7 +1476,7 @@ class ApplicationsController extends Controller
], 404);
}
$server = $application->destination->server;
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy'];
$allowedFields = ['name', 'description', 'is_static', 'domains', 'git_repository', 'git_branch', 'git_commit_sha', 'docker_registry_image_name', 'docker_registry_image_tag', 'build_pack', 'static_image', 'install_command', 'build_command', 'start_command', 'ports_exposes', 'ports_mappings', 'base_directory', 'publish_directory', 'health_check_enabled', 'health_check_path', 'health_check_port', 'health_check_host', 'health_check_method', 'health_check_return_code', 'health_check_scheme', 'health_check_response_text', 'health_check_interval', 'health_check_timeout', 'health_check_retries', 'health_check_start_period', 'limits_memory', 'limits_memory_swap', 'limits_memory_swappiness', 'limits_memory_reservation', 'limits_cpus', 'limits_cpuset', 'limits_cpu_shares', 'custom_labels', 'custom_docker_run_options', 'post_deployment_command', 'post_deployment_command_container', 'pre_deployment_command', 'pre_deployment_command_container', 'watch_paths', 'manual_webhook_secret_github', 'manual_webhook_secret_gitlab', 'manual_webhook_secret_bitbucket', 'manual_webhook_secret_gitea', 'docker_compose_location', 'docker_compose_raw', 'docker_compose_custom_start_command', 'docker_compose_custom_build_command', 'docker_compose_domains', 'redirect', 'instant_deploy', 'use_build_server'];
$validator = customApiValidator($request->all(), [
sharedDataApplications(),
@@ -1538,6 +1554,10 @@ class ApplicationsController extends Controller
}
$instantDeploy = $request->instant_deploy;
$use_build_server = $request->use_build_server;
$application->settings->is_build_server_enabled = $use_build_server;
$application->settings->save();
removeUnnecessaryFieldsFromRequest($request);
$data = $request->all();

View File

@@ -1541,16 +1541,10 @@ class DatabasesController extends Controller
format: 'uuid',
)
),
new OA\Parameter(
name: 'cleanup',
in: 'query',
description: 'Delete configurations and volumes.',
required: false,
schema: new OA\Schema(
type: 'boolean',
default: true,
)
),
new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
],
responses: [
new OA\Response(
@@ -1595,10 +1589,14 @@ class DatabasesController extends Controller
if (! $database) {
return response()->json(['message' => 'Database not found.'], 404);
}
DeleteResourceJob::dispatch(
resource: $database,
deleteConfigurations: $cleanup,
deleteVolumes: $cleanup);
deleteConfigurations: $request->query->get('delete_configurations', true),
deleteVolumes: $request->query->get('delete_volumes', true),
dockerCleanup: $request->query->get('docker_cleanup', true),
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
);
return response()->json([
'message' => 'Database deletion request queued.',

View File

@@ -86,7 +86,7 @@ class OtherController extends Controller
if ($teamId !== '0') {
return response()->json(['message' => 'You are not allowed to enable the API.'], 403);
}
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$settings->update(['is_api_enabled' => true]);
return response()->json(['message' => 'API enabled.'], 200);
@@ -138,7 +138,7 @@ class OtherController extends Controller
if ($teamId !== '0') {
return response()->json(['message' => 'You are not allowed to disable the API.'], 403);
}
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$settings->update(['is_api_enabled' => false]);
return response()->json(['message' => 'API disabled.'], 200);

View File

@@ -308,7 +308,7 @@ class ServersController extends Controller
$projects = Project::where('team_id', $teamId)->get();
$domains = collect();
$applications = $projects->pluck('applications')->flatten();
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if ($applications->count() > 0) {
foreach ($applications as $application) {
$ip = $application->destination->server->ip;

View File

@@ -432,6 +432,10 @@ class ServicesController extends Controller
tags: ['Services'],
parameters: [
new OA\Parameter(name: 'uuid', in: 'path', required: true, description: 'Service UUID', schema: new OA\Schema(type: 'string')),
new OA\Parameter(name: 'delete_configurations', in: 'query', required: false, description: 'Delete configurations.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_volumes', in: 'query', required: false, description: 'Delete volumes.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'docker_cleanup', in: 'query', required: false, description: 'Run docker cleanup.', schema: new OA\Schema(type: 'boolean', default: true)),
new OA\Parameter(name: 'delete_connected_networks', in: 'query', required: false, description: 'Delete connected networks.', schema: new OA\Schema(type: 'boolean', default: true)),
],
responses: [
new OA\Response(
@@ -476,7 +480,14 @@ class ServicesController extends Controller
if (! $service) {
return response()->json(['message' => 'Service not found.'], 404);
}
DeleteResourceJob::dispatch($service);
DeleteResourceJob::dispatch(
resource: $service,
deleteConfigurations: $request->query->get('delete_configurations', true),
deleteVolumes: $request->query->get('delete_volumes', true),
dockerCleanup: $request->query->get('docker_cleanup', true),
deleteConnectedNetworks: $request->query->get('delete_connected_networks', true)
);
return response()->json([
'message' => 'Service deletion request queued.',
@@ -516,7 +527,8 @@ class ServicesController extends Controller
items: new OA\Items(ref: '#/components/schemas/EnvironmentVariable')
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -619,7 +631,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -738,7 +751,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -853,7 +867,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -953,7 +968,8 @@ class ServicesController extends Controller
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -1025,9 +1041,11 @@ class ServicesController extends Controller
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Service starting request queued.'],
])
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -1101,9 +1119,11 @@ class ServicesController extends Controller
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Service stopping request queued.'],
])
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',
@@ -1177,9 +1197,11 @@ class ServicesController extends Controller
type: 'object',
properties: [
'message' => ['type' => 'string', 'example' => 'Service restaring request queued.'],
])
]
)
),
]),
]
),
new OA\Response(
response: 401,
ref: '#/components/responses/401',

View File

@@ -2,7 +2,6 @@
namespace App\Http\Controllers;
use App\Models\InstanceSettings;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpKernel\Exception\HttpException;
@@ -22,7 +21,7 @@ class OauthController extends Controller
$oauthUser = get_socialite_provider($provider)->user();
$user = User::whereEmail($oauthUser->email)->first();
if (! $user) {
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->is_registration_enabled) {
abort(403, 'Registration is disabled');
}

View File

@@ -14,7 +14,7 @@ class ApiAllowed
if (isCloud()) {
return $next($request);
}
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if ($settings->is_api_enabled === false) {
return response()->json(['success' => true, 'message' => 'API is disabled.'], 403);
}

View File

@@ -12,7 +12,6 @@ use App\Models\ApplicationPreview;
use App\Models\EnvironmentVariable;
use App\Models\GithubApp;
use App\Models\GitlabApp;
use App\Models\InstanceSettings;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\SwarmDocker;
@@ -962,7 +961,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
}
if ($this->application->environment_variables->where('key', 'COOLIFY_FQDN')->isEmpty()) {
if ($this->application->compose_parsing_version === '3') {
if ((int) $this->application->compose_parsing_version >= 3) {
$envs->push("COOLIFY_URL={$this->application->fqdn}");
} else {
$envs->push("COOLIFY_FQDN={$this->application->fqdn}");
@@ -970,7 +969,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
if ($this->application->environment_variables->where('key', 'COOLIFY_URL')->isEmpty()) {
$url = str($this->application->fqdn)->replace('http://', '')->replace('https://', '');
if ($this->application->compose_parsing_version === '3') {
if ((int) $this->application->compose_parsing_version >= 3) {
$envs->push("COOLIFY_FQDN={$url}");
} else {
$envs->push("COOLIFY_URL={$url}");
@@ -1334,7 +1333,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
private function prepare_builder_image()
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$helperImage = config('coolify.helper_image');
$helperImage = "{$helperImage}:{$settings->helper_version}";
// Get user home directory

View File

@@ -2,7 +2,6 @@
namespace App\Jobs;
use App\Models\InstanceSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
@@ -22,7 +21,7 @@ class CheckForUpdatesJob implements ShouldBeEncrypted, ShouldQueue
if (isDev() || isCloud()) {
return;
}
$settings = InstanceSettings::get();
$settings = instanceSettings();
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
if ($response->successful()) {
$versions = $response->json();

View File

@@ -4,7 +4,6 @@ namespace App\Jobs;
use App\Actions\Database\StopDatabase;
use App\Events\BackupCreated;
use App\Models\InstanceSettings;
use App\Models\S3Storage;
use App\Models\ScheduledDatabaseBackup;
use App\Models\ScheduledDatabaseBackupExecution;
@@ -84,7 +83,6 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
try {
// Check if team is exists
if (is_null($this->team)) {
$this->backup->update(['status' => 'failed']);
StopDatabase::run($this->database);
$this->database->delete();
@@ -562,7 +560,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
private function getFullImageName(): string
{
$settings = InstanceSettings::get();
$settings = instanceSettings();
$helperImage = config('coolify.helper_image');
$latestVersion = $settings->helper_version;

View File

@@ -31,10 +31,10 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
public function __construct(
public Application|Service|StandalonePostgresql|StandaloneRedis|StandaloneMongodb|StandaloneMysql|StandaloneMariadb|StandaloneKeydb|StandaloneDragonfly|StandaloneClickhouse $resource,
public bool $deleteConfigurations,
public bool $deleteVolumes,
public bool $dockerCleanup,
public bool $deleteConnectedNetworks
public bool $deleteConfigurations = true,
public bool $deleteVolumes = true,
public bool $dockerCleanup = true,
public bool $deleteConnectedNetworks = true
) {}
public function handle()

View File

@@ -2,7 +2,6 @@
namespace App\Jobs;
use App\Models\InstanceSettings;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
@@ -26,7 +25,7 @@ class PullHelperImageJob implements ShouldBeEncrypted, ShouldQueue
$response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
if ($response->successful()) {
$versions = $response->json();
$settings = InstanceSettings::get();
$settings = instanceSettings();
$latest_version = data_get($versions, 'coolify.helper.version');
$current_version = $settings->helper_version;
if (version_compare($latest_version, $current_version, '>')) {

View File

@@ -0,0 +1,59 @@
<?php
namespace App\Jobs;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class ServerStorageCheckJob implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 1;
public $timeout = 60;
public $containers;
public $applications;
public $databases;
public $services;
public $previews;
public function backoff(): int
{
return isDev() ? 1 : 3;
}
public function __construct(public Server $server) {}
public function handle()
{
try {
if (! $this->server->isFunctional()) {
ray('Server is not ready.');
return 'Server is not ready.';
}
$team = $this->server->team;
$percentage = $this->server->storageCheck();
if ($percentage > 1) {
ray('Server storage is at '.$percentage.'%');
}
} catch (\Throwable $e) {
ray($e->getMessage());
return handleError($e);
}
}
}

View File

@@ -3,7 +3,6 @@
namespace App\Jobs;
use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings;
use App\Models\Server;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
@@ -23,7 +22,7 @@ class UpdateCoolifyJob implements ShouldBeEncrypted, ShouldQueue
{
try {
CheckForUpdatesJob::dispatchSync();
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->new_version_available) {
Log::info('No new version available. Skipping update.');

View File

@@ -47,7 +47,7 @@ class Help extends Component
]
);
$mail->subject("[HELP]: {$this->subject}");
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$type = set_transanctional_email_settings($settings);
if (! $type) {
$url = 'https://app.coolify.io/api/feedback';

View File

@@ -172,7 +172,7 @@ class Email extends Component
public function copyFromInstanceSettings()
{
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if ($settings->smtp_enabled) {
$team = currentTeam();
$team->update([

View File

@@ -109,7 +109,7 @@ class Navbar extends Component
return;
}
PullImage::run($this->service);
StopService::run($this->service);
StopService::run(service: $this->service, dockerCleanup: false);
$this->service->parse();
$this->dispatch('imagePulled');
$activity = StartService::run($this->service);

View File

@@ -91,10 +91,12 @@ class Danger extends Component
public function delete($password)
{
if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
if (isProduction()) {
if (! Hash::check($password, Auth::user()->password)) {
$this->addError('password', 'The provided password is incorrect.');
return;
return;
}
}
if (! $this->resource) {

View File

@@ -11,6 +11,8 @@ use Livewire\Component;
class ExecuteContainerCommand extends Component
{
public $selected_container = 'default';
public $container;
public Collection $containers;
@@ -83,11 +85,14 @@ class ExecuteContainerCommand extends Component
$containers = getCurrentApplicationContainerStatus($server, $this->resource->id, includePullrequests: true);
}
foreach ($containers as $container) {
$payload = [
'server' => $server,
'container' => $container,
];
$this->containers = $this->containers->push($payload);
// if container state is running
if (data_get($container, 'State') === 'running') {
$payload = [
'server' => $server,
'container' => $container,
];
$this->containers = $this->containers->push($payload);
}
}
} elseif (data_get($this->parameters, 'database_uuid')) {
if ($this->resource->isRunning()) {
@@ -100,7 +105,6 @@ class ExecuteContainerCommand extends Component
}
} elseif (data_get($this->parameters, 'service_uuid')) {
$this->resource->applications()->get()->each(function ($application) {
ray($application);
if ($application->isRunning()) {
$this->containers->push([
'server' => $this->resource->server,
@@ -131,9 +135,14 @@ class ExecuteContainerCommand extends Component
#[On('connectToContainer')]
public function connectToContainer()
{
if ($this->selected_container === 'default') {
$this->dispatch('error', 'Please select a container.');
return;
}
try {
$container_name = data_get($this->container, 'container.Names');
if (is_null($container_name)) {
$container = collect($this->containers)->firstWhere('container.Names', $this->selected_container);
if (is_null($container)) {
throw new \RuntimeException('Container not found.');
}
$server = data_get($this->container, 'server');
@@ -141,11 +150,11 @@ class ExecuteContainerCommand extends Component
if ($server->isForceDisabled()) {
throw new \RuntimeException('Server is disabled.');
}
$this->dispatch('send-terminal-command',
true,
$container_name,
$server->uuid,
$this->dispatch(
'send-terminal-command',
isset($container),
data_get($container, 'container.Names'),
data_get($container, 'server.uuid')
);
} catch (\Throwable $e) {

View File

@@ -60,7 +60,7 @@ class Index extends Component
public function mount()
{
if (isInstanceAdmin()) {
$this->settings = InstanceSettings::get();
$this->settings = instanceSettings();
$this->do_not_track = $this->settings->do_not_track;
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
$this->is_registration_enabled = $this->settings->is_registration_enabled;
@@ -162,7 +162,7 @@ class Index extends Component
{
CheckForUpdatesJob::dispatchSync();
$this->dispatch('updateAvailable');
$settings = InstanceSettings::get();
$settings = instanceSettings();
if ($settings->new_version_available) {
$this->dispatch('success', 'New version available!');
} else {

View File

@@ -29,7 +29,7 @@ class License extends Component
abort(404);
}
$this->instance_id = config('app.id');
$this->settings = \App\Models\InstanceSettings::get();
$this->settings = instanceSettings();
}
public function render()

View File

@@ -42,7 +42,7 @@ class SettingsBackup extends Component
public function mount()
{
if (isInstanceAdmin()) {
$settings = InstanceSettings::get();
$settings = instanceSettings();
$this->database = StandalonePostgresql::whereName('coolify-db')->first();
$s3s = S3Storage::whereTeamId(0)->get() ?? [];
if ($this->database) {

View File

@@ -43,7 +43,7 @@ class SettingsEmail extends Component
public function mount()
{
if (isInstanceAdmin()) {
$this->settings = InstanceSettings::get();
$this->settings = instanceSettings();
$this->emails = auth()->user()->email;
} else {
return redirect()->route('dashboard');

View File

@@ -99,7 +99,7 @@ class Change extends Component
return redirect()->route('source.all');
}
$this->applications = $this->github_app->applications;
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$this->github_app->makeVisible('client_secret')->makeVisible('webhook_secret');
$this->name = str($this->github_app->name)->kebab();

View File

@@ -23,7 +23,7 @@ class Index extends Component
if (data_get(currentTeam(), 'subscription') && isSubscriptionActive()) {
return redirect()->route('subscription.show');
}
$this->settings = \App\Models\InstanceSettings::get();
$this->settings = instanceSettings();
$this->alreadySubscribed = currentTeam()->subscription()->exists();
}

View File

@@ -104,7 +104,7 @@ class Application extends BaseModel
{
use SoftDeletes;
private static $parserVersion = '3';
private static $parserVersion = '4';
protected $guarded = [];
@@ -304,7 +304,7 @@ class Application extends BaseModel
'application_uuid' => data_get($this, 'uuid'),
'task_uuid' => $task_uuid,
]);
$settings = InstanceSettings::get();
$settings = instanceSettings();
if (data_get($settings, 'fqdn')) {
$url = Url::fromString($route);
$url = $url->withPort(null);
@@ -1150,7 +1150,7 @@ class Application extends BaseModel
public function parse(int $pull_request_id = 0, ?int $preview_id = null)
{
if ($this->compose_parsing_version === '3') {
if ((int) $this->compose_parsing_version >= 3) {
return newParser($this, $pull_request_id, $preview_id);
} elseif ($this->docker_compose_raw) {
return parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id, preview_id: $preview_id);

View File

@@ -126,11 +126,6 @@ class EnvironmentVariable extends Model
$env = $this->get_real_environment_variables($this->value, $resource);
return data_get($env, 'value', $env);
if (is_string($env)) {
return $env;
}
return $env->value;
}
);
}

View File

@@ -85,4 +85,17 @@ class InstanceSettings extends Model implements SendsEmail
return "[{$instanceName}]";
}
public function helperVersion(): Attribute
{
return Attribute::make(
get: function ($value) {
if (isDev()) {
return 'latest';
}
return $value;
}
);
}
}

View File

@@ -268,7 +268,7 @@ respond 404
public function setupDynamicProxyConfiguration()
{
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$dynamic_config_path = $this->proxyPath().'/dynamic';
if ($this->proxyType() === ProxyTypes::TRAEFIK->value) {
$file = "$dynamic_config_path/coolify.yaml";
@@ -1212,4 +1212,13 @@ $schema://$host {
return $this;
}
public function storageCheck(): ?string
{
$commands = [
'df / --output=pcent | tr -cd 0-9',
];
return instant_remote_process($commands, $this, false);
}
}

View File

@@ -42,7 +42,7 @@ class Service extends BaseModel
{
use HasFactory, SoftDeletes;
private static $parserVersion = '3';
private static $parserVersion = '4';
protected $guarded = [];
@@ -1095,7 +1095,22 @@ class Service extends BaseModel
return 3;
});
foreach ($sorted as $env) {
$commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
if (version_compare($env->version, '4.0.0-beta.347', '<=')) {
$commands[] = "echo '{$env->key}={$env->real_value}' >> .env";
} else {
$real_value = $env->real_value;
if ($env->version === '4.0.0-beta.239') {
$real_value = $env->real_value;
} else {
if ($env->is_literal || $env->is_multiline) {
$real_value = '\''.$real_value.'\'';
} else {
$real_value = escapeEnvVariables($env->real_value);
}
}
ray("echo \"{$env->key}={$real_value}\" >> .env");
$commands[] = "echo \"{$env->key}={$real_value}\" >> .env";
}
}
if ($sorted->count() === 0) {
$commands[] = 'touch .env';
@@ -1105,7 +1120,7 @@ class Service extends BaseModel
public function parse(bool $isNew = false): Collection
{
if ($this->compose_parsing_version === '3') {
if ((int) $this->compose_parsing_version >= 3) {
return newParser($this);
} elseif ($this->docker_compose_raw) {
return parseDockerComposeFile($this, $isNew);

View File

@@ -13,7 +13,7 @@ class TransactionalEmailChannel
{
public function send(User $notifiable, Notification $notification): void
{
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if (! data_get($settings, 'smtp_enabled') && ! data_get($settings, 'resend_enabled')) {
Log::info('SMTP/Resend not enabled');

View File

@@ -18,7 +18,7 @@ class ResetPassword extends Notification
public function __construct($token)
{
$this->settings = \App\Models\InstanceSettings::get();
$this->settings = instanceSettings();
$this->token = $token;
}

View File

@@ -2,10 +2,8 @@
namespace App\Providers;
use App\Models\InstanceSettings;
use App\Models\PersonalAccessToken;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Laravel\Sanctum\Sanctum;
@@ -30,9 +28,5 @@ class AppServiceProvider extends ServiceProvider
])->baseUrl($api_url);
}
});
// if (! env('CI')) {
// View::share('instanceSettings', InstanceSettings::get());
// }
}
}

View File

@@ -46,7 +46,7 @@ class FortifyServiceProvider extends ServiceProvider
Fortify::registerView(function () {
$isFirstUser = User::count() === 0;
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
if (! $settings->is_registration_enabled) {
return redirect()->route('login');
}
@@ -60,7 +60,7 @@ class FortifyServiceProvider extends ServiceProvider
});
Fortify::loginView(function () {
$settings = \App\Models\InstanceSettings::get();
$settings = instanceSettings();
$enabled_oauth_providers = OauthSetting::where('enabled', true)->get();
$users = User::count();
if ($users == 0) {