diff --git a/app/Actions/Proxy/CheckConfigurationSync.php b/app/Actions/Proxy/CheckConfiguration.php
similarity index 76%
rename from app/Actions/Proxy/CheckConfigurationSync.php
rename to app/Actions/Proxy/CheckConfiguration.php
index c1a261796..1526c9728 100644
--- a/app/Actions/Proxy/CheckConfigurationSync.php
+++ b/app/Actions/Proxy/CheckConfiguration.php
@@ -2,12 +2,14 @@
namespace App\Actions\Proxy;
+use Lorisleiva\Actions\Concerns\AsAction;
use App\Models\Server;
use Illuminate\Support\Str;
-class CheckConfigurationSync
+class CheckConfiguration
{
- public function __invoke(Server $server, bool $reset = false)
+ use AsAction;
+ public function handle(Server $server, bool $reset = false)
{
$proxy_path = get_proxy_path();
$proxy_configuration = instant_remote_process([
diff --git a/app/Actions/Proxy/SaveConfiguration.php b/app/Actions/Proxy/SaveConfiguration.php
new file mode 100644
index 000000000..85aebf619
--- /dev/null
+++ b/app/Actions/Proxy/SaveConfiguration.php
@@ -0,0 +1,27 @@
+proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
+ $server->save();
+
+ return instant_remote_process([
+ "mkdir -p $proxy_path",
+ "echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
+ ], $server);
+ }
+}
diff --git a/app/Actions/Proxy/SaveConfigurationSync.php b/app/Actions/Proxy/SaveConfigurationSync.php
deleted file mode 100644
index d58dad0c7..000000000
--- a/app/Actions/Proxy/SaveConfigurationSync.php
+++ /dev/null
@@ -1,29 +0,0 @@
-proxy->last_saved_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
- $server->save();
-
- instant_remote_process([
- "mkdir -p $proxy_path",
- "echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
- ], $server);
- } catch (\Throwable $e) {
- ray($e);
- }
-
- }
-}
diff --git a/app/Actions/Proxy/StartProxy.php b/app/Actions/Proxy/StartProxy.php
index 37c9c492e..fd14f49d5 100644
--- a/app/Actions/Proxy/StartProxy.php
+++ b/app/Actions/Proxy/StartProxy.php
@@ -32,8 +32,10 @@ class StartProxy
return "docker network ls --format '{{.Name}}' | grep '^$network$' >/dev/null 2>&1 || docker network create --attachable $network > /dev/null 2>&1";
});
- $configuration = resolve(CheckConfigurationSync::class)($server);
-
+ $configuration = CheckConfiguration::run($server);
+ if (!$configuration) {
+ throw new \Exception("Configuration is not synced");
+ }
$docker_compose_yml_base64 = base64_encode($configuration);
$server->proxy->last_applied_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
$server->save();
diff --git a/app/Actions/Server/InstallDocker.php b/app/Actions/Server/InstallDocker.php
index 49ea85c6b..39d0718db 100644
--- a/app/Actions/Server/InstallDocker.php
+++ b/app/Actions/Server/InstallDocker.php
@@ -4,11 +4,10 @@ namespace App\Actions\Server;
use App\Models\Server;
use App\Models\StandaloneDocker;
-use App\Models\Team;
class InstallDocker
{
- public function __invoke(Server $server, Team $team)
+ public function __invoke(Server $server, bool $instant = false)
{
$dockerVersion = '24.0';
$config = base64_encode('{
@@ -19,15 +18,16 @@ class InstallDocker
}
}');
$found = StandaloneDocker::where('server_id', $server->id);
- if ($found->count() == 0) {
+ if ($found->count() == 0 && $server->id) {
StandaloneDocker::create([
'name' => 'coolify',
'network' => 'coolify',
'server_id' => $server->id,
]);
}
- if (isDev()) {
- return remote_process([
+
+ if (isDev() && $server->id === 0) {
+ $command = [
"echo '####### Installing Prerequisites...'",
"sleep 1",
"echo '####### Installing/updating Docker Engine...'",
@@ -35,9 +35,9 @@ class InstallDocker
"sleep 4",
"echo '####### Restarting Docker Engine...'",
"ls -l /tmp"
- ], $server);
+ ];
} else {
- return remote_process([
+ $command = [
"echo '####### Installing Prerequisites...'",
"command -v jq >/dev/null || apt-get update",
"command -v jq >/dev/null || apt install -y jq",
@@ -53,7 +53,11 @@ class InstallDocker
"echo '####### Creating default Docker network (coolify)...'",
"docker network create --attachable coolify >/dev/null 2>&1 || true",
"echo '####### Done!'"
- ], $server);
+ ];
}
+ if ($instant) {
+ return instant_remote_process($command, $server);
+ }
+ return remote_process($command, $server);
}
}
diff --git a/app/Http/Livewire/Boarding/Index.php b/app/Http/Livewire/Boarding/Index.php
index dace2eb94..bc15c5579 100644
--- a/app/Http/Livewire/Boarding/Index.php
+++ b/app/Http/Livewire/Boarding/Index.php
@@ -15,6 +15,7 @@ class Index extends Component
{
public string $currentState = 'welcome';
+ public ?string $selectedServerType = null;
public ?Collection $privateKeys = null;
public ?int $selectedExistingPrivateKey = null;
public ?string $privateKeyType = null;
@@ -37,6 +38,7 @@ class Index extends Component
public ?int $selectedExistingProject = null;
public ?Project $createdProject = null;
+ public bool $dockerInstallationStarted = false;
public function mount()
{
$this->privateKeyName = generate_random_name();
@@ -64,12 +66,14 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
public function restartBoarding()
{
- if ($this->createdServer) {
- $this->createdServer->delete();
- }
- if ($this->createdPrivateKey) {
- $this->createdPrivateKey->delete();
- }
+ // if ($this->selectedServerType !== 'localhost') {
+ // if ($this->createdServer) {
+ // $this->createdServer->delete();
+ // }
+ // if ($this->createdPrivateKey) {
+ // $this->createdPrivateKey->delete();
+ // }
+ // }
return redirect()->route('boarding');
}
public function skipBoarding()
@@ -84,13 +88,14 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
public function setServerType(string $type)
{
- if ($type === 'localhost') {
+ $this->selectedServerType = $type;
+ if ($this->selectedServerType === 'localhost') {
$this->createdServer = Server::find(0);
if (!$this->createdServer) {
return $this->emit('error', 'Localhost server is not found. Something went wrong during installation. Please try to reinstall or contact support.');
}
return $this->validateServer('localhost');
- } elseif ($type === 'remote') {
+ } elseif ($this->selectedServerType === 'remote') {
$this->privateKeys = PrivateKey::ownedByCurrentTeam(['name'])->where('id', '!=', 0)->get();
if ($this->privateKeys->count() > 0) {
$this->selectedExistingPrivateKey = $this->privateKeys->first()->id;
@@ -114,8 +119,6 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
}
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
$this->validateServer();
- $this->getProxyType();
- $this->getProjects();
}
public function getProxyType()
{
@@ -128,6 +131,7 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
}
public function selectExistingPrivateKey()
{
+ $this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
$this->currentState = 'create-server';
}
public function createNewServer()
@@ -150,39 +154,38 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
'privateKeyName' => 'required',
'privateKey' => 'required',
]);
+ $this->createdPrivateKey = PrivateKey::create([
+ 'name' => $this->privateKeyName,
+ 'description' => $this->privateKeyDescription,
+ 'private_key' => $this->privateKey,
+ 'team_id' => currentTeam()->id
+ ]);
+ $this->createdPrivateKey->save();
$this->currentState = 'create-server';
}
public function saveServer()
{
$this->validate([
'remoteServerName' => 'required',
- 'remoteServerHost' => 'required|ip',
+ 'remoteServerHost' => 'required',
'remoteServerPort' => 'required|integer',
'remoteServerUser' => 'required',
]);
$this->privateKey = formatPrivateKey($this->privateKey);
- $this->createdPrivateKey = new PrivateKey();
- $this->createdPrivateKey->private_key = $this->privateKey;
- $this->createdPrivateKey->name = $this->privateKeyName;
- $this->createdPrivateKey->description = $this->privateKeyDescription;
- $this->createdPrivateKey->team_id = currentTeam()->id;
$foundServer = Server::whereIp($this->remoteServerHost)->first();
if ($foundServer) {
return $this->emit('error', 'IP address is already in use by another team.');
}
- $this->createdServer = new Server();
- $this->createdServer->uuid = (string)new Cuid2(7);
- $this->createdServer->name = $this->remoteServerName;
- $this->createdServer->ip = $this->remoteServerHost;
- $this->createdServer->port = $this->remoteServerPort;
- $this->createdServer->user = $this->remoteServerUser;
- $this->createdServer->description = $this->remoteServerDescription;
- $this->createdServer->privateKey = $this->createdPrivateKey;
- $this->createdServer->team_id = currentTeam()->id;
-
- ray($this->createdServer);
-
-
+ $this->createdServer = Server::create([
+ 'name' => $this->remoteServerName,
+ 'ip' => $this->remoteServerHost,
+ 'port' => $this->remoteServerPort,
+ 'user' => $this->remoteServerUser,
+ 'description' => $this->remoteServerDescription,
+ 'private_key_id' => $this->createdPrivateKey->id,
+ 'team_id' => currentTeam()->id,
+ ]);
+ $this->createdServer->save();
$this->validateServer();
}
public function validateServer(?string $type = null)
@@ -190,47 +193,36 @@ uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
try {
$customErrorMessage = "Server is not reachable:";
config()->set('coolify.mux_enabled', false);
+
instant_remote_process(['uptime'], $this->createdServer, true);
+
+ $this->createdServer->settings->update([
+ 'is_reachable' => true,
+ ]);
+
$dockerVersion = instant_remote_process(["docker version|head -2|grep -i version| awk '{print $2}'"], $this->createdServer, true);
$dockerVersion = checkMinimumDockerEngineVersion($dockerVersion);
if (is_null($dockerVersion)) {
- throw new \Exception('No Docker Engine or older than 23 version installed.');
+ $this->currentState = 'install-docker';
+ throw new \Exception('Docker version is not supported or not installed.');
}
- $customErrorMessage = "Cannot create Server or Private Key. Please try again.";
- if ($type !== 'localhost') {
- $createdPrivateKey = PrivateKey::create([
- 'name' => $this->privateKeyName,
- 'description' => $this->privateKeyDescription,
- 'private_key' => $this->privateKey,
- 'team_id' => currentTeam()->id
- ]);
- $server = Server::create([
- 'name' => $this->remoteServerName,
- 'ip' => $this->remoteServerHost,
- 'port' => $this->remoteServerPort,
- 'user' => $this->remoteServerUser,
- 'description' => $this->remoteServerDescription,
- 'private_key_id' => $createdPrivateKey->id,
- 'team_id' => currentTeam()->id,
- ]);
- $server->settings->is_reachable = true;
- $server->settings->is_usable = true;
- $server->settings->save();
- } else {
- $this->createdServer->settings->update([
- 'is_reachable' => true,
- ]);
- }
- $this->getProxyType();
+ $this->dockerInstalledOrSkipped();
} catch (\Throwable $e) {
return handleError(error: $e, customErrorMessage: $customErrorMessage, livewire: $this);
}
}
public function installDocker()
{
- $activity = resolve(InstallDocker::class)($this->createdServer, currentTeam());
+ $this->dockerInstallationStarted = true;
+ $activity = resolve(InstallDocker::class)($this->createdServer);
$this->emit('newMonitorActivity', $activity->id);
- $this->currentState = 'select-proxy';
+ }
+ public function dockerInstalledOrSkipped()
+ {
+ $this->createdServer->settings->update([
+ 'is_usable' => true,
+ ]);
+ $this->getProxyType();
}
public function selectProxy(string|null $proxyType = null)
{
diff --git a/app/Http/Livewire/Server/Form.php b/app/Http/Livewire/Server/Form.php
index 56cec63da..9794610fe 100644
--- a/app/Http/Livewire/Server/Form.php
+++ b/app/Http/Livewire/Server/Form.php
@@ -15,6 +15,7 @@ class Form extends Component
public $dockerVersion;
public string|null $wildcard_domain = null;
public int $cleanup_after_percentage;
+ public bool $dockerInstallationStarted = false;
protected $rules = [
'server.name' => 'required|min:6',
@@ -44,7 +45,8 @@ class Form extends Component
public function installDocker()
{
- $activity = resolve(InstallDocker::class)($this->server, currentTeam());
+ $this->dockerInstallationStarted = true;
+ $activity = resolve(InstallDocker::class)($this->server);
$this->emit('newMonitorActivity', $activity->id);
}
@@ -56,7 +58,10 @@ class Form extends Component
$this->uptime = $uptime;
$this->emit('success', 'Server is reachable.');
} else {
+ ray($this->uptime);
+
$this->emit('error', 'Server is not reachable.');
+
return;
}
if ($dockerVersion) {
diff --git a/app/Http/Livewire/Server/New/ByIp.php b/app/Http/Livewire/Server/New/ByIp.php
index f08b2ddb8..7814aef8f 100644
--- a/app/Http/Livewire/Server/New/ByIp.php
+++ b/app/Http/Livewire/Server/New/ByIp.php
@@ -26,7 +26,7 @@ class ByIp extends Component
protected $rules = [
'name' => 'required|string',
'description' => 'nullable|string',
- 'ip' => 'required|ip',
+ 'ip' => 'required',
'user' => 'required|string',
'port' => 'required|integer',
];
diff --git a/app/Http/Livewire/Server/Proxy.php b/app/Http/Livewire/Server/Proxy.php
index d65518975..560bdd784 100644
--- a/app/Http/Livewire/Server/Proxy.php
+++ b/app/Http/Livewire/Server/Proxy.php
@@ -2,9 +2,8 @@
namespace App\Http\Livewire\Server;
-use App\Actions\Proxy\CheckConfigurationSync;
-use App\Actions\Proxy\SaveConfigurationSync;
-use App\Enums\ProxyTypes;
+use App\Actions\Proxy\CheckConfiguration;
+use App\Actions\Proxy\SaveConfiguration;
use App\Models\Server;
use Livewire\Component;
@@ -48,8 +47,7 @@ class Proxy extends Component
public function submit()
{
try {
- resolve(SaveConfigurationSync::class)($this->server);
-
+ SaveConfiguration::run($this->server);
$this->server->proxy->redirect_url = $this->redirect_url;
$this->server->save();
@@ -63,7 +61,7 @@ class Proxy extends Component
public function reset_proxy_configuration()
{
try {
- $this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server, true);
+ $this->proxy_settings = CheckConfiguration::run($this->server, true);
} catch (\Throwable $e) {
return handleError($e);
}
@@ -72,8 +70,7 @@ class Proxy extends Component
public function loadProxyConfiguration()
{
try {
- ray('loadProxyConfiguration');
- $this->proxy_settings = resolve(CheckConfigurationSync::class)($this->server);
+ $this->proxy_settings = CheckConfiguration::run($this->server);
} catch (\Throwable $e) {
return handleError($e);
}
diff --git a/app/Http/Livewire/Server/Proxy/Deploy.php b/app/Http/Livewire/Server/Proxy/Deploy.php
index df369c49a..ad60ca53a 100644
--- a/app/Http/Livewire/Server/Proxy/Deploy.php
+++ b/app/Http/Livewire/Server/Proxy/Deploy.php
@@ -2,7 +2,7 @@
namespace App\Http\Livewire\Server\Proxy;
-use App\Actions\Proxy\SaveConfigurationSync;
+use App\Actions\Proxy\SaveConfiguration;
use App\Actions\Proxy\StartProxy;
use App\Models\Server;
use Livewire\Component;
@@ -13,20 +13,25 @@ class Deploy extends Component
public $proxy_settings = null;
protected $listeners = ['proxyStatusUpdated'];
- public function proxyStatusUpdated() {
+ public function proxyStatusUpdated()
+ {
$this->server->refresh();
}
public function startProxy()
{
- if (
- $this->server->proxy->last_applied_settings &&
- $this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
- ) {
- resolve(SaveConfigurationSync::class)($this->server);
- }
+ try {
+ if (
+ $this->server->proxy->last_applied_settings &&
+ $this->server->proxy->last_saved_settings !== $this->server->proxy->last_applied_settings
+ ) {
+ SaveConfiguration::run($this->server);
+ }
- $activity = resolve(StartProxy::class)($this->server);
- $this->emit('newMonitorActivity', $activity->id);
+ $activity = resolve(StartProxy::class)($this->server);
+ $this->emit('newMonitorActivity', $activity->id);
+ } catch (\Throwable $e) {
+ return handleError($e);
+ }
}
public function stop()
diff --git a/app/Http/Livewire/Server/Proxy/Status.php b/app/Http/Livewire/Server/Proxy/Status.php
index f808fdb81..061728049 100644
--- a/app/Http/Livewire/Server/Proxy/Status.php
+++ b/app/Http/Livewire/Server/Proxy/Status.php
@@ -2,6 +2,7 @@
namespace App\Http\Livewire\Server\Proxy;
+use App\Jobs\ContainerStatusJob;
use App\Models\Server;
use Livewire\Component;
@@ -18,9 +19,7 @@ class Status extends Component
{
try {
if ($this->server->isFunctional()) {
- $container = getContainerStatus(server: $this->server, container_id: 'coolify-proxy');
- $this->server->proxy->status = $container;
- $this->server->save();
+ dispatch_sync(new ContainerStatusJob($this->server));
$this->emit('proxyStatusUpdated');
}
} catch (\Throwable $e) {
diff --git a/app/Http/Livewire/Server/ShowPrivateKey.php b/app/Http/Livewire/Server/ShowPrivateKey.php
index c9054f7df..a0aa6e1e2 100644
--- a/app/Http/Livewire/Server/ShowPrivateKey.php
+++ b/app/Http/Livewire/Server/ShowPrivateKey.php
@@ -37,14 +37,27 @@ class ShowPrivateKey extends Component
try {
['uptime' => $uptime, 'dockerVersion' => $dockerVersion] = validateServer($this->server, true);
if ($uptime) {
+ $this->server->settings->update([
+ 'is_reachable' => true
+ ]);
$this->emit('success', 'Server is reachable with this private key.');
} else {
+ $this->server->settings->update([
+ 'is_reachable' => false,
+ 'is_usable' => false
+ ]);
$this->emit('error', 'Server is not reachable with this private key.');
return;
}
if ($dockerVersion) {
+ $this->server->settings->update([
+ 'is_usable' => true
+ ]);
$this->emit('success', 'Server is usable for Coolify.');
} else {
+ $this->server->settings->update([
+ 'is_usable' => false
+ ]);
$this->emit('error', 'Old (lower than 23) or no Docker version detected. Install Docker Engine on the General tab.');
}
} catch (\Throwable $e) {
diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php
index 6d5feb5ce..20d6640bd 100644
--- a/app/Jobs/ContainerStatusJob.php
+++ b/app/Jobs/ContainerStatusJob.php
@@ -40,7 +40,8 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
return $this->server->uuid;
}
- private function checkServerConnection() {
+ private function checkServerConnection()
+ {
$uptime = instant_remote_process(['uptime'], $this->server, false);
if (!is_null($uptime)) {
return true;
@@ -51,7 +52,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
try {
// ray()->clearAll();
$serverUptimeCheckNumber = 0;
- $serverUptimeCheckNumberMax = 5;
+ $serverUptimeCheckNumberMax = 3;
while (true) {
if ($serverUptimeCheckNumber >= $serverUptimeCheckNumberMax) {
$this->server->settings()->update(['is_reachable' => false]);
@@ -65,19 +66,29 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
$serverUptimeCheckNumber++;
sleep(5);
}
+ $containers = instant_remote_process(["docker container ls -q"], $this->server);
+ if (!$containers) {
+ return;
+ }
$containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server);
$containers = format_docker_command_output_to_json($containers);
$applications = $this->server->applications();
$databases = $this->server->databases();
$previews = $this->server->previews();
- if ($this->server->isProxyShouldRun()) {
- $foundProxyContainer = $containers->filter(function ($value, $key) {
- return data_get($value, 'Name') === '/coolify-proxy';
- })->first();
- if (!$foundProxyContainer) {
+
+ /// Check if proxy is running
+ $foundProxyContainer = $containers->filter(function ($value, $key) {
+ return data_get($value, 'Name') === '/coolify-proxy';
+ })->first();
+ if (!$foundProxyContainer) {
+ if ($this->server->isProxyShouldRun()) {
resolve(StartProxy::class)($this->server, false);
$this->server->team->notify(new ContainerRestarted('coolify-proxy', $this->server));
}
+ } else {
+ ray($foundProxyContainer);
+ $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status');
+ $this->server->save();
}
$foundApplications = [];
$foundApplicationPreviews = [];
@@ -88,10 +99,10 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
$labels = Arr::undot(format_docker_labels_to_json($labels));
$labelId = data_get($labels, 'coolify.applicationId');
if ($labelId) {
- if (str_contains($labelId,'-pr-')) {
+ if (str_contains($labelId, '-pr-')) {
$previewId = (int) Str::after($labelId, '-pr-');
$applicationId = (int) Str::before($labelId, '-pr-');
- $preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id',$previewId)->first();
+ $preview = ApplicationPreview::where('application_id', $applicationId)->where('pull_request_id', $previewId)->first();
if ($preview) {
$foundApplicationPreviews[] = $preview->id;
$statusFromDb = $preview->status;
@@ -128,10 +139,9 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
}
}
}
-
}
$notRunningApplications = $applications->pluck('id')->diff($foundApplications);
- foreach($notRunningApplications as $applicationId) {
+ foreach ($notRunningApplications as $applicationId) {
$application = $applications->where('id', $applicationId)->first();
if ($application->status === 'exited') {
continue;
@@ -170,14 +180,14 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
$this->server->team->notify(new ContainerStopped($containerName, $this->server, $url));
}
$notRunningDatabases = $databases->pluck('id')->diff($foundDatabases);
- foreach($notRunningDatabases as $database) {
+ foreach ($notRunningDatabases as $database) {
$database = $databases->where('id', $database)->first();
if ($database->status === 'exited') {
continue;
}
$database->update(['status' => 'exited']);
- $name = data_get($database, 'name');
+ $name = data_get($database, 'name');
$fqdn = data_get($database, 'fqdn');
$containerName = $name;
@@ -249,7 +259,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
return Str::startsWith(data_get($value, 'Name'), "/$uuid-pr-{$preview->id}");
})->first();
}
-
}
foreach ($databases as $database) {
$uuid = data_get($database, 'uuid');
@@ -276,7 +285,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
}
}
}
- // TODO Monitor other containers not managed by Coolify
+ // TODO Monitor other containers not managed by Coolify
} catch (\Throwable $e) {
send_internal_notification('ContainerStatusJob failed with: ' . $e->getMessage());
ray($e->getMessage());
diff --git a/bootstrap/helpers/proxy.php b/bootstrap/helpers/proxy.php
index c78a560c7..e3db2be36 100644
--- a/bootstrap/helpers/proxy.php
+++ b/bootstrap/helpers/proxy.php
@@ -96,7 +96,7 @@ function setup_default_redirect_404(string|null $redirect_url, Server $server)
$traefik_default_redirect_file = "$traefik_dynamic_conf_path/default_redirect_404.yaml";
ray($redirect_url);
if (empty($redirect_url)) {
- remote_process([
+ instant_remote_process([
"rm -f $traefik_default_redirect_file",
], $server);
} else {
@@ -157,7 +157,7 @@ function setup_default_redirect_404(string|null $redirect_url, Server $server)
$base64 = base64_encode($yaml);
ray("mkdir -p $traefik_dynamic_conf_path");
- remote_process([
+ instant_remote_process([
"mkdir -p $traefik_dynamic_conf_path",
"echo '$base64' | base64 -d > $traefik_default_redirect_file",
], $server);
diff --git a/bootstrap/helpers/remoteProcess.php b/bootstrap/helpers/remoteProcess.php
index ae16c7bc0..7017ead10 100644
--- a/bootstrap/helpers/remoteProcess.php
+++ b/bootstrap/helpers/remoteProcess.php
@@ -7,15 +7,13 @@ use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\PrivateKey;
use App\Models\Server;
-use App\Notifications\Server\NotReachable;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;
-use Illuminate\Support\Sleep;
-use Spatie\Activitylog\Models\Activity;
use Illuminate\Support\Str;
+use Spatie\Activitylog\Contracts\Activity;
function remote_process(
array $command,
@@ -110,11 +108,28 @@ function instant_remote_process(array $command, Server $server, $throwError = tr
if (!$throwError) {
return null;
}
- throw new \RuntimeException($process->errorOutput(), $exitCode);
+ return excludeCertainErrors($process->errorOutput(), $exitCode);
}
return $output;
}
-
+function excludeCertainErrors(string $errorOutput, ?int $exitCode = null) {
+ $ignoredErrors = collect([
+ 'Permission denied (publickey',
+ 'Could not resolve hostname',
+ ]);
+ $ignored = false;
+ foreach ($ignoredErrors as $ignoredError) {
+ if (Str::contains($errorOutput, $ignoredError)) {
+ $ignored = true;
+ break;
+ }
+ }
+ if ($ignored) {
+ // TODO: Create new exception and disable in sentry
+ throw new \RuntimeException($errorOutput, $exitCode);
+ }
+ throw new \RuntimeException($errorOutput, $exitCode);
+}
function decode_remote_command_output(?ApplicationDeploymentQueue $application_deployment_queue = null): Collection
{
$application = Application::find(data_get($application_deployment_queue, 'application_id'));
diff --git a/composer.json b/composer.json
index 79f3793dd..217560b57 100644
--- a/composer.json
+++ b/composer.json
@@ -22,6 +22,7 @@
"lcobucci/jwt": "^5.0.0",
"league/flysystem-aws-s3-v3": "^3.0",
"livewire/livewire": "^v2.12.3",
+ "lorisleiva/laravel-actions": "^2.7",
"masmerise/livewire-toaster": "^1.2",
"nubs/random-name-generator": "^2.2",
"phpseclib/phpseclib": "~3.0",
diff --git a/composer.lock b/composer.lock
index 63d0c626d..551d78229 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "cf138424c896f30b035bc8cdff63e8d1",
+ "content-hash": "de2c45be3f03d43430549d963778dc4a",
"packages": [
{
"name": "aws/aws-crt-php",
@@ -3059,6 +3059,153 @@
],
"time": "2023-08-11T04:02:34+00:00"
},
+ {
+ "name": "lorisleiva/laravel-actions",
+ "version": "v2.7.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/lorisleiva/laravel-actions.git",
+ "reference": "5250614fd6b77e8e2780be0206174e069e94661d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/lorisleiva/laravel-actions/zipball/5250614fd6b77e8e2780be0206174e069e94661d",
+ "reference": "5250614fd6b77e8e2780be0206174e069e94661d",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/contracts": "9.0 - 9.34 || ^9.36 || ^10.0",
+ "lorisleiva/lody": "^0.4",
+ "php": "^8.0"
+ },
+ "require-dev": {
+ "orchestra/testbench": "^8.5",
+ "pestphp/pest": "^1.23",
+ "phpunit/phpunit": "^9.6"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Lorisleiva\\Actions\\ActionServiceProvider"
+ ],
+ "aliases": {
+ "Action": "Lorisleiva\\Actions\\Facades\\Actions"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Lorisleiva\\Actions\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Loris Leiva",
+ "email": "loris.leiva@gmail.com",
+ "homepage": "https://lorisleiva.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "Laravel components that take care of one specific task",
+ "homepage": "https://github.com/lorisleiva/laravel-actions",
+ "keywords": [
+ "action",
+ "command",
+ "component",
+ "controller",
+ "job",
+ "laravel",
+ "object"
+ ],
+ "support": {
+ "issues": "https://github.com/lorisleiva/laravel-actions/issues",
+ "source": "https://github.com/lorisleiva/laravel-actions/tree/v2.7.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/lorisleiva",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-24T10:20:57+00:00"
+ },
+ {
+ "name": "lorisleiva/lody",
+ "version": "v0.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/lorisleiva/lody.git",
+ "reference": "1a43e8e423f3b2b64119542bc44a2071208fae16"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/lorisleiva/lody/zipball/1a43e8e423f3b2b64119542bc44a2071208fae16",
+ "reference": "1a43e8e423f3b2b64119542bc44a2071208fae16",
+ "shasum": ""
+ },
+ "require": {
+ "illuminate/contracts": "^8.0|^9.0|^10.0",
+ "php": "^8.0"
+ },
+ "require-dev": {
+ "orchestra/testbench": "^8.0",
+ "pestphp/pest": "^1.20.0",
+ "phpunit/phpunit": "^9.5.10"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Lorisleiva\\Lody\\LodyServiceProvider"
+ ],
+ "aliases": {
+ "Lody": "Lorisleiva\\Lody\\Lody"
+ }
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Lorisleiva\\Lody\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Loris Leiva",
+ "email": "loris.leiva@gmail.com",
+ "homepage": "https://lorisleiva.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "Load files and classes as lazy collections in Laravel.",
+ "homepage": "https://github.com/lorisleiva/lody",
+ "keywords": [
+ "classes",
+ "collection",
+ "files",
+ "laravel",
+ "load"
+ ],
+ "support": {
+ "issues": "https://github.com/lorisleiva/lody/issues",
+ "source": "https://github.com/lorisleiva/lody/tree/v0.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sponsors/lorisleiva",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-05T15:03:45+00:00"
+ },
{
"name": "masmerise/livewire-toaster",
"version": "1.3.0",
@@ -13089,5 +13236,5 @@
"php": "^8.2"
},
"platform-dev": [],
- "plugin-api-version": "2.3.0"
+ "plugin-api-version": "2.6.0"
}
diff --git a/config/sentry.php b/config/sentry.php
index bc82840f5..ad788a56e 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.40',
+ 'release' => '4.0.0-beta.41',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index 5e04a22e3..9d505bcb9 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
-
This will install the latest Docker Engine on your server, configure a few things to be able
diff --git a/resources/views/livewire/server/form.blade.php b/resources/views/livewire/server/form.blade.php
index ebb40f78f..4f3df85c2 100644
--- a/resources/views/livewire/server/form.blade.php
+++ b/resources/views/livewire/server/form.blade.php
@@ -48,10 +48,16 @@
@endif
@if ($server->settings->is_reachable && !$server->settings->is_usable && $server->id !== 0)
-