diff --git a/app/Actions/Proxy/CheckProxy.php b/app/Actions/Proxy/CheckProxy.php
index 279fac20e..32673abc9 100644
--- a/app/Actions/Proxy/CheckProxy.php
+++ b/app/Actions/Proxy/CheckProxy.php
@@ -17,35 +17,42 @@ class CheckProxy
return false;
}
}
- $status = getContainerStatus($server, 'coolify-proxy');
- if ($status === 'running') {
- $server->proxy->set('status', 'running');
+ if ($server->isSwarm()) {
+ $status = getContainerStatus($server, 'coolify-proxy_traefik');
+ $server->proxy->set('status', $status);
$server->save();
return false;
- }
- $ip = $server->ip;
- if ($server->id === 0) {
- $ip = 'host.docker.internal';
- }
+ } else {
+ $status = getContainerStatus($server, 'coolify-proxy');
+ if ($status === 'running') {
+ $server->proxy->set('status', 'running');
+ $server->save();
+ return false;
+ }
+ $ip = $server->ip;
+ if ($server->id === 0) {
+ $ip = 'host.docker.internal';
+ }
- $connection80 = @fsockopen($ip, '80');
- $connection443 = @fsockopen($ip, '443');
- $port80 = is_resource($connection80) && fclose($connection80);
- $port443 = is_resource($connection443) && fclose($connection443);
- if ($port80) {
- if ($fromUI) {
- throw new \Exception("Port 80 is in use.
You must stop the process using this port.
Docs: https://coolify.io/docs
Discord: https://coollabs.io/discord");
- } else {
- return false;
+ $connection80 = @fsockopen($ip, '80');
+ $connection443 = @fsockopen($ip, '443');
+ $port80 = is_resource($connection80) && fclose($connection80);
+ $port443 = is_resource($connection443) && fclose($connection443);
+ if ($port80) {
+ if ($fromUI) {
+ throw new \Exception("Port 80 is in use.
You must stop the process using this port.
Docs: https://coolify.io/docs
Discord: https://coollabs.io/discord");
+ } else {
+ return false;
+ }
}
- }
- if ($port443) {
- if ($fromUI) {
- throw new \Exception("Port 443 is in use.
You must stop the process using this port.
Docs: https://coolify.io/docs
Discord: https://coollabs.io/discord");
- } else {
- return false;
+ if ($port443) {
+ if ($fromUI) {
+ throw new \Exception("Port 443 is in use.
You must stop the process using this port.
Docs: https://coolify.io/docs
Discord: https://coollabs.io/discord");
+ } else {
+ return false;
+ }
}
+ return true;
}
- return true;
}
}
diff --git a/app/Http/Livewire/Server/Proxy/Deploy.php b/app/Http/Livewire/Server/Proxy/Deploy.php
index 7e828b092..9612eccc7 100644
--- a/app/Http/Livewire/Server/Proxy/Deploy.php
+++ b/app/Http/Livewire/Server/Proxy/Deploy.php
@@ -58,11 +58,25 @@ class Deploy extends Component
public function stop()
{
- instant_remote_process([
- "docker rm -f coolify-proxy",
- ], $this->server);
- $this->server->proxy->status = 'exited';
- $this->server->save();
- $this->emit('proxyStatusUpdated');
+ try {
+ if ($this->server->isSwarm()) {
+ instant_remote_process([
+ "docker service rm coolify-proxy_traefik",
+ ], $this->server);
+ $this->server->proxy->status = 'exited';
+ $this->server->save();
+ $this->emit('proxyStatusUpdated');
+ } else {
+ instant_remote_process([
+ "docker rm -f coolify-proxy",
+ ], $this->server);
+ $this->server->proxy->status = 'exited';
+ $this->server->save();
+ $this->emit('proxyStatusUpdated');
+ }
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ }
+
}
}
diff --git a/app/Http/Livewire/Server/Proxy/Status.php b/app/Http/Livewire/Server/Proxy/Status.php
index 8df8f10cd..0c5f274b5 100644
--- a/app/Http/Livewire/Server/Proxy/Status.php
+++ b/app/Http/Livewire/Server/Proxy/Status.php
@@ -16,7 +16,7 @@ class Status extends Component
protected $listeners = ['proxyStatusUpdated', 'startProxyPolling'];
public function startProxyPolling()
{
- $this->polling = true;
+ $this->checkProxy();
}
public function proxyStatusUpdated()
{
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index bd6d7436a..d0f18d00c 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -220,8 +220,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->application_deployment_queue->addLogEntry("Creating / updating stack.");
$this->execute_remote_command(
[
- "docker stack deploy --with-registry-auth --prune --compose-file {$this->configuration_dir}/docker-compose.yml {$this->application->uuid}"
+ executeInDocker($this->deployment_uuid, "cd {$this->workdir} && docker stack deploy --with-registry-auth -c docker-compose.yml {$this->application->uuid}")
],
+ [
+ "echo 'Stack deployed. It may take a few minutes to fully available in your swarm.'"
+ ]
);
}
}
@@ -376,7 +379,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$envs->push($env->key . '=' . $env->value);
}
}
- ray($envs);
$envs_base64 = base64_encode($envs->implode("\n"));
$this->execute_remote_command(
[
@@ -442,17 +444,21 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->cleanup_git();
$composeFile = $this->application->parseCompose(pull_request_id: $this->pull_request_id);
$yaml = Yaml::dump($composeFile->toArray(), 10);
+ ray($composeFile);
+ ray($this->container_name);
$this->docker_compose_base64 = base64_encode($yaml);
$this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yaml"), "hidden" => true
+ executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}{$this->docker_compose_location}"), "hidden" => true
]);
$this->save_environment_variables();
$this->stop_running_container(force: true);
+ ray($this->pull_request_id);
$networkId = $this->application->uuid;
if ($this->pull_request_id !== 0) {
$networkId = "{$this->application->uuid}-{$this->pull_request_id}";
}
+ ray($networkId);
if ($this->server->isSwarm()) {
// TODO
} else {
@@ -832,26 +838,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->env_args = $this->env_args->implode(' ');
}
- private function modify_compose_file()
- {
- // ray("{$this->workdir}{$this->docker_compose_location}");
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->docker_compose_location}"), "hidden" => true, "save" => 'compose_file']);
- if ($this->saved_outputs->get('compose_file')) {
- $compose = $this->saved_outputs->get('compose_file');
- }
- try {
- $yaml = Yaml::parse($compose);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
- }
- $services = data_get($yaml, 'services');
- $topLevelNetworks = collect(data_get($yaml, 'networks', []));
- $definedNetwork = collect([$this->application->uuid]);
-
- $services = collect($services)->map(function ($service, $serviceName) use ($topLevelNetworks, $definedNetwork) {
- $serviceNetworks = collect(data_get($service, 'networks', []));
- });
- }
private function generate_compose_file()
{
$ports = $this->application->settings->is_static ? [80] : $this->application->ports_exposes_array;
@@ -952,10 +938,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
]
]
];
-
} else {
$docker_compose['services'][$this->container_name]['labels'] = $labels;
-
}
if ($this->server->isLogDrainEnabled() && $this->application->isLogDrainEnabled()) {
$docker_compose['services'][$this->container_name]['logging'] = [
diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php
index 30324baab..7063e01cd 100644
--- a/app/Jobs/ContainerStatusJob.php
+++ b/app/Jobs/ContainerStatusJob.php
@@ -43,15 +43,37 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
return;
};
if ($this->server->isSwarm()) {
-
+ $containers = instant_remote_process(["docker service inspect $(docker service ls -q) --format '{{json .}}'"], $this->server, false);
+ $containerReplicase = instant_remote_process(["docker service ls --format '{{json .}}'"], $this->server, false);
} else {
-
+ $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false);
+ $containerReplicase = null;
}
- $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server, false);
if (is_null($containers)) {
return;
}
$containers = format_docker_command_output_to_json($containers);
+ if ($containerReplicase) {
+ $containerReplicase = format_docker_command_output_to_json($containerReplicase);
+ foreach ($containerReplicase as $containerReplica) {
+ $name = data_get($containerReplica, 'Name');
+ $containers = $containers->map(function ($container) use ($name, $containerReplica) {
+ if (data_get($container, 'Spec.Name') === $name) {
+ $replicas = data_get($containerReplica, 'Replicas');
+ $running = str($replicas)->explode('/')[0];
+ $total = str($replicas)->explode('/')[1];
+ if ($running === $total) {
+ data_set($container, 'State.Status', 'running');
+ data_set($container, 'State.Health.Status', 'healthy');
+ } else {
+ data_set($container, 'State.Status', 'starting');
+ data_set($container, 'State.Health.Status', 'unhealthy');
+ }
+ }
+ return $container;
+ });
+ }
+ }
$applications = $this->server->applications();
$databases = $this->server->databases();
$services = $this->server->services()->get();
@@ -63,10 +85,16 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
$foundServices = [];
foreach ($containers as $container) {
+ if ($this->server->isSwarm()) {
+ $labels = data_get($container, 'Spec.Labels');
+ $uuid = data_get($labels, 'coolify.name');
+ } else {
+ $labels = data_get($container, 'Config.Labels');
+ $uuid = data_get($labels, 'com.docker.compose.service');
+ }
$containerStatus = data_get($container, 'State.Status');
$containerHealth = data_get($container, 'State.Health.Status', 'unhealthy');
$containerStatus = "$containerStatus ($containerHealth)";
- $labels = data_get($container, 'Config.Labels');
$labels = Arr::undot(format_docker_labels_to_json($labels));
$applicationId = data_get($labels, 'coolify.applicationId');
if ($applicationId) {
@@ -98,7 +126,6 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
}
}
} else {
- $uuid = data_get($labels, 'com.docker.compose.service');
if ($uuid) {
$database = $databases->where('uuid', $uuid)->first();
if ($database) {
@@ -253,7 +280,11 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted
// Check if proxy is running
$this->server->proxyType();
$foundProxyContainer = $containers->filter(function ($value, $key) {
- return data_get($value, 'Name') === '/coolify-proxy';
+ if ($this->server->isSwarm()) {
+ return data_get($value, 'Spec.Name') === 'coolify-proxy_traefik';
+ } else {
+ return data_get($value, 'Name') === '/coolify-proxy';
+ }
})->first();
if (!$foundProxyContainer) {
try {
diff --git a/app/Models/Application.php b/app/Models/Application.php
index ea7e0a930..e2d93c7a1 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -603,6 +603,7 @@ class Application extends BaseModel
{
if ($this->docker_compose_raw) {
$mainCompose = parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id);
+ ray($this->docker_compose_pr_raw);
if ($this->getMorphClass() === 'App\Models\Application' && $this->docker_compose_pr_raw) {
parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id, is_pr: true);
}
@@ -614,7 +615,7 @@ class Application extends BaseModel
function loadComposeFile($isInit = false)
{
$initialDockerComposeLocation = $this->docker_compose_location;
- $initialDockerComposePrLocation = $this->docker_compose_pr_location;
+ // $initialDockerComposePrLocation = $this->docker_compose_pr_location;
if ($this->build_pack === 'dockercompose') {
if ($isInit && $this->docker_compose_raw) {
return;
@@ -623,11 +624,11 @@ class Application extends BaseModel
['commands' => $cloneCommand] = $this->generateGitImportCommands(deployment_uuid: $uuid, only_checkout: true, exec_in_docker: false, custom_base_dir: '.');
$workdir = rtrim($this->base_directory, '/');
$composeFile = $this->docker_compose_location;
- $prComposeFile = $this->docker_compose_pr_location;
- $fileList = collect([".$composeFile"]);
- if ($composeFile !== $prComposeFile) {
- $fileList->push(".$prComposeFile");
- }
+ // $prComposeFile = $this->docker_compose_pr_location;
+ $fileList = collect([".$workdir$composeFile"]);
+ // if ($composeFile !== $prComposeFile) {
+ // $fileList->push(".$prComposeFile");
+ // }
$commands = collect([
"mkdir -p /tmp/{$uuid} && cd /tmp/{$uuid}",
$cloneCommand,
@@ -645,24 +646,24 @@ class Application extends BaseModel
$this->docker_compose_raw = $composeFileContent;
$this->save();
}
- if ($composeFile === $prComposeFile) {
- $this->docker_compose_pr_raw = $composeFileContent;
- $this->save();
- } else {
- $commands = collect([
- "cd /tmp/{$uuid}",
- "cat .$workdir$prComposeFile",
- ]);
- $composePrFileContent = instant_remote_process($commands, $this->destination->server, false);
- if (!$composePrFileContent) {
- $this->docker_compose_pr_location = $initialDockerComposePrLocation;
- $this->save();
- throw new \Exception("Could not load compose file from $workdir$prComposeFile");
- } else {
- $this->docker_compose_pr_raw = $composePrFileContent;
- $this->save();
- }
- }
+ // if ($composeFile === $prComposeFile) {
+ // $this->docker_compose_pr_raw = $composeFileContent;
+ // $this->save();
+ // } else {
+ // $commands = collect([
+ // "cd /tmp/{$uuid}",
+ // "cat .$workdir$prComposeFile",
+ // ]);
+ // $composePrFileContent = instant_remote_process($commands, $this->destination->server, false);
+ // if (!$composePrFileContent) {
+ // $this->docker_compose_pr_location = $initialDockerComposePrLocation;
+ // $this->save();
+ // throw new \Exception("Could not load compose file from $workdir$prComposeFile");
+ // } else {
+ // $this->docker_compose_pr_raw = $composePrFileContent;
+ // $this->save();
+ // }
+ // }
$commands = collect([
"rm -rf /tmp/{$uuid}",
diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php
index d643cce6b..c46c4d558 100644
--- a/bootstrap/helpers/docker.php
+++ b/bootstrap/helpers/docker.php
@@ -93,7 +93,11 @@ function executeInDocker(string $containerId, string $command)
function getContainerStatus(Server $server, string $container_id, bool $all_data = false, bool $throwError = false)
{
- $container = instant_remote_process(["docker inspect --format '{{json .}}' {$container_id}"], $server, $throwError);
+ if ($server->isSwarm()) {
+ $container = instant_remote_process(["docker service ls --filter 'name={$container_id}' --format '{{json .}}' "], $server, $throwError);
+ } else {
+ $container = instant_remote_process(["docker inspect --format '{{json .}}' {$container_id}"], $server, $throwError);
+ }
if (!$container) {
return 'exited';
}
@@ -101,7 +105,19 @@ function getContainerStatus(Server $server, string $container_id, bool $all_data
if ($all_data) {
return $container[0];
}
- return data_get($container[0], 'State.Status', 'exited');
+ if ($server->isSwarm()) {
+ $replicas = data_get($container[0], 'Replicas');
+ $replicas = explode('/', $replicas);
+ $active = (int)$replicas[0];
+ $total = (int)$replicas[1];
+ if ($active === $total) {
+ return 'running';
+ } else {
+ return 'starting';
+ }
+ } else {
+ return data_get($container[0], 'State.Status', 'exited');
+ }
}
function generateApplicationContainerName(Application $application, $pull_request_id = 0)
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index 8eb1fd443..3681a6c0c 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -863,7 +863,6 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
$key = Str::of($variableName);
$value = Str::of($variable);
}
- // TODO: here is the problem
if ($key->startsWith('SERVICE_FQDN')) {
if ($isNew || $savedService->fqdn === null) {
$name = $key->after('SERVICE_FQDN_')->beforeLast('_')->lower();
@@ -1145,6 +1144,7 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
data_set($service, 'volumes', $serviceVolumes->toArray());
}
} else {
+ // TODO
}
// Decide if the service is a database
$isDatabase = isDatabaseImage(data_get_str($service, 'image'));
diff --git a/resources/views/livewire/boarding/index.blade.php b/resources/views/livewire/boarding/index.blade.php
index fb102c7c5..98a2c772a 100644
--- a/resources/views/livewire/boarding/index.blade.php
+++ b/resources/views/livewire/boarding/index.blade.php
@@ -207,10 +207,10 @@
placeholder="Username to connect to your server. Default is root." label="Username"
id="remoteServerUser" />
-