Merge branch 'next' into docker-network-aliases
This commit is contained in:
@@ -329,13 +329,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
} else {
|
||||
$this->write_deployment_configurations();
|
||||
}
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"docker rm -f {$this->deployment_uuid} >/dev/null 2>&1",
|
||||
'hidden' => true,
|
||||
'ignore_errors' => true,
|
||||
]
|
||||
);
|
||||
$this->application_deployment_queue->addLogEntry("Starting graceful shutdown container: {$this->deployment_uuid}");
|
||||
$this->graceful_shutdown_container($this->deployment_uuid);
|
||||
|
||||
ApplicationStatusChanged::dispatch(data_get($this->application, 'environment.project.team.id'));
|
||||
}
|
||||
@@ -1211,7 +1206,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if ($this->container_name) {
|
||||
$counter = 1;
|
||||
$this->application_deployment_queue->addLogEntry('Waiting for healthcheck to pass on the new container.');
|
||||
if ($this->full_healthcheck_url) {
|
||||
if ($this->full_healthcheck_url && ! $this->application->custom_healthcheck_found) {
|
||||
$this->application_deployment_queue->addLogEntry("Healthcheck URL (inside the container): {$this->full_healthcheck_url}");
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry("Waiting for the start period ({$this->application->health_check_start_period} seconds) before starting healthcheck.");
|
||||
@@ -1366,13 +1361,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
}
|
||||
$this->application_deployment_queue->addLogEntry("Preparing container with helper image: $helperImage.");
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
'command' => "docker rm -f {$this->deployment_uuid}",
|
||||
'ignore_errors' => true,
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
$this->application_deployment_queue->addLogEntry("Starting graceful shutdown container: {$this->deployment_uuid}");
|
||||
$this->graceful_shutdown_container($this->deployment_uuid);
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
$runCommand,
|
||||
@@ -1718,8 +1708,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
'save' => 'dockerfile_from_repo',
|
||||
'ignore_errors' => true,
|
||||
]);
|
||||
$dockerfile = collect(str($this->saved_outputs->get('dockerfile_from_repo'))->trim()->explode("\n"));
|
||||
$this->application->parseHealthcheckFromDockerfile($dockerfile);
|
||||
$this->application->parseHealthcheckFromDockerfile($this->saved_outputs->get('dockerfile_from_repo'));
|
||||
}
|
||||
$docker_compose = [
|
||||
'services' => [
|
||||
@@ -2029,7 +2018,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
|
||||
$nginx_config = base64_encode($this->application->custom_nginx_configuration);
|
||||
} else {
|
||||
$nginx_config = base64_encode(defaultNginxConfiguration());
|
||||
if ($this->application->settings->is_spa) {
|
||||
$nginx_config = base64_encode(defaultNginxConfiguration('spa'));
|
||||
} else {
|
||||
$nginx_config = base64_encode(defaultNginxConfiguration());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($this->application->build_pack === 'nixpacks') {
|
||||
@@ -2096,7 +2089,11 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||
if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
|
||||
$nginx_config = base64_encode($this->application->custom_nginx_configuration);
|
||||
} else {
|
||||
$nginx_config = base64_encode(defaultNginxConfiguration());
|
||||
if ($this->application->settings->is_spa) {
|
||||
$nginx_config = base64_encode(defaultNginxConfiguration('spa'));
|
||||
} else {
|
||||
$nginx_config = base64_encode(defaultNginxConfiguration());
|
||||
}
|
||||
}
|
||||
}
|
||||
$build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}";
|
||||
|
||||
@@ -20,7 +20,7 @@ class CleanupHelperContainersJob implements ShouldBeEncrypted, ShouldBeUnique, S
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$containers = instant_remote_process_with_timeout(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("ghcr.io/coollabsio/coolify-helper")))\''], $this->server, false);
|
||||
$containers = instant_remote_process_with_timeout(['docker container ps --format \'{{json .}}\' | jq -s \'map(select(.Image | contains("'.config('constants.coolify.registry_url').'/coollabsio/coolify-helper")))\''], $this->server, false);
|
||||
$containerIds = collect(json_decode($containers))->pluck('ID');
|
||||
if ($containerIds->count() > 0) {
|
||||
foreach ($containerIds as $containerId) {
|
||||
|
||||
@@ -484,6 +484,11 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
$fullImageName = $this->getFullImageName();
|
||||
|
||||
$containerExists = instant_remote_process(["docker ps -a -q -f name=backup-of-{$this->backup->uuid}"], $this->server, false);
|
||||
if (filled($containerExists)) {
|
||||
instant_remote_process(["docker rm -f backup-of-{$this->backup->uuid}"], $this->server, false);
|
||||
}
|
||||
|
||||
if (isDev()) {
|
||||
if ($this->database->name === 'coolify-db') {
|
||||
$backup_location_from = '/var/lib/docker/volumes/coolify_dev_backups_data/_data/coolify/coolify-db-'.$this->server->ip.$this->backup_file;
|
||||
|
||||
@@ -66,12 +66,9 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
|
||||
if ($this->deleteVolumes && $this->resource->type() !== 'service') {
|
||||
$this->resource?->delete_volumes($persistentStorages);
|
||||
$this->resource->delete_volumes($persistentStorages);
|
||||
$this->resource->persistentStorages()->delete();
|
||||
}
|
||||
if ($this->deleteConfigurations) {
|
||||
$this->resource?->delete_configurations();
|
||||
}
|
||||
|
||||
$isDatabase = $this->resource instanceof StandalonePostgresql
|
||||
|| $this->resource instanceof StandaloneRedis
|
||||
|| $this->resource instanceof StandaloneMongodb
|
||||
@@ -80,6 +77,18 @@ class DeleteResourceJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|| $this->resource instanceof StandaloneKeydb
|
||||
|| $this->resource instanceof StandaloneDragonfly
|
||||
|| $this->resource instanceof StandaloneClickhouse;
|
||||
|
||||
if ($this->deleteConfigurations) {
|
||||
$this->resource->delete_configurations(); // rename to FileStorages
|
||||
$this->resource->fileStorages()->delete();
|
||||
}
|
||||
if ($isDatabase) {
|
||||
$this->resource->sslCertificates()->delete();
|
||||
$this->resource->scheduledBackups()->delete();
|
||||
$this->resource->environment_variables()->delete();
|
||||
$this->resource->tags()->detach();
|
||||
}
|
||||
|
||||
$server = data_get($this->resource, 'server') ?? data_get($this->resource, 'destination.server');
|
||||
if (($this->dockerCleanup || $isDatabase) && $server) {
|
||||
CleanupDocker::dispatch($server, true);
|
||||
|
||||
78
app/Jobs/RegenerateSslCertJob.php
Normal file
78
app/Jobs/RegenerateSslCertJob.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Helpers\SSLHelper;
|
||||
use App\Models\SslCertificate;
|
||||
use App\Models\Team;
|
||||
use App\Notifications\SslExpirationNotification;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RegenerateSslCertJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $tries = 3;
|
||||
|
||||
public $backoff = 60;
|
||||
|
||||
public function __construct(
|
||||
protected ?Team $team = null,
|
||||
protected ?int $server_id = null,
|
||||
protected bool $force_regeneration = false,
|
||||
) {}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$query = SslCertificate::query();
|
||||
|
||||
if ($this->server_id) {
|
||||
$query->where('server_id', $this->server_id);
|
||||
}
|
||||
|
||||
if (! $this->force_regeneration) {
|
||||
$query->where('valid_until', '<=', now()->addDays(14));
|
||||
}
|
||||
|
||||
$query->where('is_ca_certificate', false);
|
||||
|
||||
$regenerated = collect();
|
||||
|
||||
$query->cursor()->each(function ($certificate) use ($regenerated) {
|
||||
try {
|
||||
$caCert = SslCertificate::where('server_id', $certificate->server_id)
|
||||
->where('is_ca_certificate', true)
|
||||
->first();
|
||||
|
||||
if (! $caCert) {
|
||||
Log::error("No CA certificate found for server_id: {$certificate->server_id}");
|
||||
|
||||
return;
|
||||
}
|
||||
SSLHelper::generateSslCertificate(
|
||||
commonName: $certificate->common_name,
|
||||
subjectAlternativeNames: $certificate->subject_alternative_names,
|
||||
resourceType: $certificate->resource_type,
|
||||
resourceId: $certificate->resource_id,
|
||||
serverId: $certificate->server_id,
|
||||
configurationDir: $certificate->configuration_dir,
|
||||
mountPath: $certificate->mount_path,
|
||||
caCert: $caCert->ssl_certificate,
|
||||
caKey: $caCert->ssl_private_key,
|
||||
);
|
||||
$regenerated->push($certificate);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Failed to regenerate SSL certificate: '.$e->getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
if ($regenerated->isNotEmpty()) {
|
||||
$this->team?->notify(new SslExpirationNotification($regenerated));
|
||||
}
|
||||
}
|
||||
}
|
||||
46
app/Jobs/RestartProxyJob.php
Normal file
46
app/Jobs/RestartProxyJob.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Actions\Proxy\CheckProxy;
|
||||
use App\Actions\Proxy\StartProxy;
|
||||
use App\Actions\Proxy\StopProxy;
|
||||
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\Middleware\WithoutOverlapping;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class RestartProxyJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $tries = 1;
|
||||
|
||||
public $timeout = 60;
|
||||
|
||||
public function middleware(): array
|
||||
{
|
||||
return [(new WithoutOverlapping($this->server->uuid))->dontRelease()];
|
||||
}
|
||||
|
||||
public function __construct(public Server $server) {}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
StopProxy::run($this->server);
|
||||
|
||||
$this->server->proxy->force_stop = false;
|
||||
$this->server->save();
|
||||
StartProxy::run($this->server, force: true);
|
||||
|
||||
CheckProxy::run($this->server, true);
|
||||
} catch (\Throwable $e) {
|
||||
return handleError($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user