mirror of
https://github.com/coollabsio/coolify.git
synced 2026-03-11 08:55:47 +00:00
Merge 42c386f4f9 into 201998638a
This commit is contained in:
commit
df28b09102
5 changed files with 91 additions and 27 deletions
|
|
@ -5,6 +5,7 @@ namespace App\Actions\Docker;
|
|||
use App\Actions\Database\StartDatabaseProxy;
|
||||
use App\Actions\Database\StopDatabaseProxy;
|
||||
use App\Actions\Shared\ComplexStatusCheck;
|
||||
use App\Actions\Shared\DockerInspectCache;
|
||||
use App\Events\ServiceChecked;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\Server;
|
||||
|
|
@ -47,10 +48,11 @@ class GetContainersStatus
|
|||
}
|
||||
$this->applications = $this->server->applications();
|
||||
$skip_these_applications = collect([]);
|
||||
$dockerInspectCache = new DockerInspectCache();
|
||||
foreach ($this->applications as $application) {
|
||||
if ($application->additional_servers->count() > 0) {
|
||||
$skip_these_applications->push($application);
|
||||
ComplexStatusCheck::run($application);
|
||||
ComplexStatusCheck::run($application, $dockerInspectCache);
|
||||
$this->applications = $this->applications->filter(function ($value, $key) use ($application) {
|
||||
return $value->id !== $application->id;
|
||||
});
|
||||
|
|
@ -60,7 +62,12 @@ class GetContainersStatus
|
|||
return ! $skip_these_applications->pluck('id')->contains($value->id);
|
||||
});
|
||||
if ($this->containers === null) {
|
||||
['containers' => $this->containers, 'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
|
||||
if (isset($dockerInspectCache->data[$this->server->id]) && !$this->server->isSwarm()) {
|
||||
$this->containers = collect($dockerInspectCache->data[$this->server->id]);
|
||||
$this->containerReplicates = collect([]);
|
||||
} else {
|
||||
['containers' => $this->containers, 'containerReplicates' => $this->containerReplicates] = $this->server->getContainers();
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($this->containers)) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ namespace App\Actions\Shared;
|
|||
use App\Models\Application;
|
||||
use App\Services\ContainerStatusAggregator;
|
||||
use App\Traits\CalculatesExcludedStatus;
|
||||
use App\Actions\Shared\DockerInspectCache;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class ComplexStatusCheck
|
||||
|
|
@ -12,10 +13,21 @@ class ComplexStatusCheck
|
|||
use AsAction;
|
||||
use CalculatesExcludedStatus;
|
||||
|
||||
public function handle(Application $application)
|
||||
public function handle(Application $application, DockerInspectCache $dockerInspectCache = new DockerInspectCache())
|
||||
{
|
||||
$servers = $application->additional_servers;
|
||||
$servers->push($application->destination->server);
|
||||
|
||||
$serversToInspect = $servers->filter(fn($server) => !isset($dockerInspectCache->data[$server->id]));
|
||||
|
||||
if ($serversToInspect->isNotEmpty()) {
|
||||
$results = instant_remote_process(["docker container inspect $(docker container ls -aq) --format '{{json .}}'"], $serversToInspect, false);
|
||||
|
||||
foreach ($results as $serverId => $result) {
|
||||
$dockerInspectCache->data[$serverId] = format_docker_command_output_to_json($result);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($servers as $server) {
|
||||
$is_main_server = $application->destination->server->id === $server->id;
|
||||
if (! $server->isFunctional()) {
|
||||
|
|
@ -29,8 +41,15 @@ class ComplexStatusCheck
|
|||
continue;
|
||||
}
|
||||
}
|
||||
$containers = instant_remote_process(["docker container inspect $(docker container ls -q --filter 'label=coolify.applicationId={$application->id}' --filter 'label=coolify.pullRequestId=0') --format '{{json .}}'"], $server, false);
|
||||
$containers = format_docker_command_output_to_json($containers);
|
||||
$allContainers = $dockerInspectCache->data[$server->id];
|
||||
|
||||
$containers = collect($allContainers)->filter(function ($container) use ($application) {
|
||||
$labels = data_get($container, 'Config.Labels', []);
|
||||
$appId = $labels['coolify.applicationId'] ?? null;
|
||||
$pullRequestId = $labels['coolify.pullRequestId'] ?? null;
|
||||
|
||||
return $appId !== null && intval($appId) === $application->id && $pullRequestId !== null && intval($pullRequestId) === 0;
|
||||
});
|
||||
|
||||
if ($containers->count() > 0) {
|
||||
$statusToSet = $this->aggregateContainerStatuses($application, $containers);
|
||||
|
|
|
|||
8
app/Actions/Shared/DockerInspectCache.php
Normal file
8
app/Actions/Shared/DockerInspectCache.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Actions\Shared;
|
||||
|
||||
class DockerInspectCache
|
||||
{
|
||||
public array $data = [];
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ use App\Actions\Proxy\CheckProxy;
|
|||
use App\Actions\Proxy\StartProxy;
|
||||
use App\Actions\Server\StartLogDrain;
|
||||
use App\Actions\Shared\ComplexStatusCheck;
|
||||
use App\Actions\Shared\DockerInspectCache;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\Server;
|
||||
|
|
@ -602,8 +603,9 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue, Silenced
|
|||
|
||||
private function updateAdditionalServersStatus()
|
||||
{
|
||||
$dockerInspectCache = new DockerInspectCache();
|
||||
$this->allApplicationsWithAdditionalServers->each(function ($application) {
|
||||
ComplexStatusCheck::run($application);
|
||||
ComplexStatusCheck::run($application, $dockerInspectCache);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -118,36 +118,64 @@ function instant_remote_process_with_timeout(Collection|array $command, Server $
|
|||
);
|
||||
}
|
||||
|
||||
function instant_remote_process(Collection|array $command, Server $server, bool $throwError = true, bool $no_sudo = false, ?int $timeout = null, bool $disableMultiplexing = false): ?string
|
||||
{
|
||||
function instant_remote_process(
|
||||
Collection|array $command,
|
||||
Server|Collection|array $server,
|
||||
bool $throwError = true,
|
||||
bool $no_sudo = false,
|
||||
?int $timeout = null,
|
||||
bool $disableMultiplexing = false
|
||||
): string|array|null {
|
||||
$command = $command instanceof Collection ? $command->toArray() : $command;
|
||||
|
||||
if ($server->isNonRoot() && ! $no_sudo) {
|
||||
$command = parseCommandsByLineForSudo(collect($command), $server);
|
||||
}
|
||||
$command_string = implode("\n", $command);
|
||||
$effectiveTimeout = $timeout ?? config('constants.ssh.command_timeout');
|
||||
// Use the variable server instead of servers for backward compatibility
|
||||
$servers = $server instanceof Collection ? $server : collect(is_array($server) ? $server : [$server]);
|
||||
|
||||
return \App\Helpers\SshRetryHandler::retry(
|
||||
function () use ($server, $command_string, $effectiveTimeout, $disableMultiplexing) {
|
||||
$sshCommand = SshMultiplexingHelper::generateSshCommand($server, $command_string, $disableMultiplexing);
|
||||
$process = Process::timeout($effectiveTimeout)->run($sshCommand);
|
||||
function () use ($servers, $command, $no_sudo, $timeout, $disableMultiplexing) {
|
||||
$results = Process::concurrently(function ($pool) use (
|
||||
$servers,
|
||||
$command,
|
||||
$no_sudo,
|
||||
$timeout,
|
||||
$disableMultiplexing
|
||||
) {
|
||||
foreach ($servers as $server) {
|
||||
if ($server->isNonRoot() && ! $no_sudo) {
|
||||
$command = parseCommandsByLineForSudo(collect($command), $server);
|
||||
}
|
||||
$command_string = implode("\n", $command);
|
||||
$effectiveTimeout = $timeout ?? config('constants.ssh.command_timeout');
|
||||
|
||||
$output = trim($process->output());
|
||||
$exitCode = $process->exitCode();
|
||||
$sshCommand = SshMultiplexingHelper::generateSshCommand($server, $command_string, $disableMultiplexing);
|
||||
|
||||
if ($exitCode !== 0) {
|
||||
excludeCertainErrors($process->errorOutput(), $exitCode);
|
||||
$pool->as($server->id)->timeout($effectiveTimeout)->command($sshCommand);
|
||||
}
|
||||
});
|
||||
|
||||
$outputs = [];
|
||||
|
||||
foreach ($results->collect() as $serverId => $process) {
|
||||
$output = trim($process->output());
|
||||
$exitCode = $process->exitCode();
|
||||
|
||||
if ($exitCode !== 0) {
|
||||
excludeCertainErrors($process->errorOutput(), $exitCode);
|
||||
}
|
||||
|
||||
// Sanitize output to ensure valid UTF-8 encoding
|
||||
$output = $output === 'null' ? null : sanitize_utf8_text($output);
|
||||
$outputs[$serverId] = $output;
|
||||
}
|
||||
|
||||
// Sanitize output to ensure valid UTF-8 encoding
|
||||
$output = $output === 'null' ? null : sanitize_utf8_text($output);
|
||||
|
||||
return $output;
|
||||
if ($servers->count() === 1) {
|
||||
return $outputs[$servers->first()->id];
|
||||
}
|
||||
|
||||
return $outputs;
|
||||
},
|
||||
[
|
||||
'server' => $server->ip,
|
||||
'command_preview' => substr($command_string, 0, 100),
|
||||
'server' => implode(', ', $servers->pluck('ip')->toArray()),
|
||||
'command_preview' => substr(implode("\n", $command), 0, 100),
|
||||
'function' => 'instant_remote_process',
|
||||
],
|
||||
$throwError
|
||||
|
|
|
|||
Loading…
Reference in a new issue