commit
6bb6de188c
@ -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([
|
27
app/Actions/Proxy/SaveConfiguration.php
Normal file
27
app/Actions/Proxy/SaveConfiguration.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
use Lorisleiva\Actions\Concerns\AsAction;
|
||||
|
||||
class SaveConfiguration
|
||||
{
|
||||
use AsAction;
|
||||
|
||||
public function handle(Server $server)
|
||||
{
|
||||
$proxy_settings = CheckConfiguration::run($server, true);
|
||||
$proxy_path = get_proxy_path();
|
||||
$docker_compose_yml_base64 = base64_encode($proxy_settings);
|
||||
|
||||
$server->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);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions\Proxy;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class SaveConfigurationSync
|
||||
{
|
||||
public function __invoke(Server $server)
|
||||
{
|
||||
try {
|
||||
$proxy_settings = resolve(CheckConfigurationSync::class)($server, true);
|
||||
$proxy_path = get_proxy_path();
|
||||
$docker_compose_yml_base64 = base64_encode($proxy_settings);
|
||||
|
||||
$server->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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -32,8 +32,10 @@ public function __invoke(Server $server, bool $async = true): Activity|string
|
||||
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();
|
||||
|
@ -4,11 +4,10 @@
|
||||
|
||||
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 @@ public function __invoke(Server $server, Team $team)
|
||||
}
|
||||
}');
|
||||
$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 @@ public function __invoke(Server $server, Team $team)
|
||||
"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 @@ public function __invoke(Server $server, Team $team)
|
||||
"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);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ public function explanation()
|
||||
|
||||
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 @@ public function skipBoarding()
|
||||
|
||||
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 @@ public function selectExistingServer()
|
||||
}
|
||||
$this->selectedExistingPrivateKey = $this->createdServer->privateKey->id;
|
||||
$this->validateServer();
|
||||
$this->getProxyType();
|
||||
$this->getProjects();
|
||||
}
|
||||
public function getProxyType()
|
||||
{
|
||||
@ -128,6 +131,7 @@ public function getProxyType()
|
||||
}
|
||||
public function selectExistingPrivateKey()
|
||||
{
|
||||
$this->createdPrivateKey = PrivateKey::find($this->selectedExistingPrivateKey);
|
||||
$this->currentState = 'create-server';
|
||||
}
|
||||
public function createNewServer()
|
||||
@ -150,39 +154,38 @@ public function savePrivateKey()
|
||||
'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 @@ public function validateServer(?string $type = null)
|
||||
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)
|
||||
{
|
||||
|
@ -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 @@ public function mount()
|
||||
|
||||
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 @@ public function validateServer()
|
||||
$this->uptime = $uptime;
|
||||
$this->emit('success', 'Server is reachable.');
|
||||
} else {
|
||||
ray($this->uptime);
|
||||
|
||||
$this->emit('error', 'Server is not reachable.');
|
||||
|
||||
return;
|
||||
}
|
||||
if ($dockerVersion) {
|
||||
|
@ -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',
|
||||
];
|
||||
|
@ -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 @@ public function select_proxy($proxy_type)
|
||||
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 @@ public function submit()
|
||||
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 @@ public function reset_proxy_configuration()
|
||||
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);
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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 @@ public function getProxyStatus()
|
||||
{
|
||||
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) {
|
||||
|
@ -37,14 +37,27 @@ public function checkConnection()
|
||||
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) {
|
||||
|
@ -40,7 +40,8 @@ public function uniqueId(): string
|
||||
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 @@ public function handle(): void
|
||||
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 @@ public function handle(): void
|
||||
$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 @@ public function handle(): void
|
||||
$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 @@ public function handle(): void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$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 @@ public function handle(): void
|
||||
$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 @@ public function handle(): void
|
||||
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 @@ public function handle(): void
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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());
|
||||
|
@ -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);
|
||||
|
@ -7,15 +7,13 @@
|
||||
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'));
|
||||
|
@ -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",
|
||||
|
151
composer.lock
generated
151
composer.lock
generated
@ -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"
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
// 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'),
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
<?php
|
||||
|
||||
return '4.0.0-beta.40';
|
||||
return '4.0.0-beta.41';
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="pb-6">
|
||||
<livewire:server.proxy.modal :server="$server" />
|
||||
<livewire:server.proxy.modal :server="$server" />
|
||||
<div class="flex items-center gap-2">
|
||||
<h1>Server</h1>
|
||||
@if ($server->settings->is_reachable)
|
||||
|
@ -1,9 +1,19 @@
|
||||
@extends('layouts.base')
|
||||
@section('body')
|
||||
<main class="min-h-screen hero">
|
||||
<div class="hero-content">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</main>
|
||||
@parent
|
||||
<main class="min-h-screen hero">
|
||||
<div class="hero-content">
|
||||
<x-modal modalId="installDocker">
|
||||
<x-slot:modalBody>
|
||||
<livewire:activity-monitor header="Docker Installation Logs" />
|
||||
</x-slot:modalBody>
|
||||
<x-slot:modalSubmit>
|
||||
<x-forms.button onclick="installDocker.close()" type="submit">
|
||||
Close
|
||||
</x-forms.button>
|
||||
</x-slot:modalSubmit>
|
||||
</x-modal>
|
||||
{{ $slot }}
|
||||
</div>
|
||||
</main>
|
||||
@parent
|
||||
@endsection
|
||||
|
@ -23,9 +23,12 @@
|
||||
<x-highlighted text="Self-hosting with superpowers!" /></span>
|
||||
</x-slot:question>
|
||||
<x-slot:explanation>
|
||||
<p><x-highlighted text="Task automation:" /> You do not to manage your servers too much. Coolify do it for you.</p>
|
||||
<p><x-highlighted text="No vendor lock-in:" /> All configurations are stored on your server, so everything works without Coolify (except integrations and automations).</p>
|
||||
<p><x-highlighted text="Monitoring:" />You will get notified on your favourite platform (Discord, Telegram, Email, etc.) when something goes wrong, or an action needed from your side.</p>
|
||||
<p><x-highlighted text="Task automation:" /> You do not to manage your servers too much. Coolify do
|
||||
it for you.</p>
|
||||
<p><x-highlighted text="No vendor lock-in:" /> All configurations are stored on your server, so
|
||||
everything works without Coolify (except integrations and automations).</p>
|
||||
<p><x-highlighted text="Monitoring:" />You will get notified on your favourite platform (Discord,
|
||||
Telegram, Email, etc.) when something goes wrong, or an action needed from your side.</p>
|
||||
</x-slot:explanation>
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center box" wire:click="explanation">Next
|
||||
@ -194,16 +197,6 @@
|
||||
</div>
|
||||
<div>
|
||||
@if ($currentState === 'install-docker')
|
||||
<x-modal modalId="installDocker">
|
||||
<x-slot:modalBody>
|
||||
<livewire:activity-monitor header="Docker Installation Logs" />
|
||||
</x-slot:modalBody>
|
||||
<x-slot:modalSubmit>
|
||||
<x-forms.button onclick="installDocker.close()" type="submit">
|
||||
Close
|
||||
</x-forms.button>
|
||||
</x-slot:modalSubmit>
|
||||
</x-modal>
|
||||
<x-boarding-step title="Install Docker">
|
||||
<x-slot:question>
|
||||
Could not find Docker Engine on your server. Do you want me to install it for you?
|
||||
@ -211,8 +204,11 @@
|
||||
<x-slot:actions>
|
||||
<x-forms.button class="justify-center box" wire:click="installDocker"
|
||||
onclick="installDocker.showModal()">
|
||||
Let's do
|
||||
it!</x-forms.button>
|
||||
Let's do it!</x-forms.button>
|
||||
@if ($dockerInstallationStarted)
|
||||
<x-forms.button class="justify-center box" wire:click="dockerInstalledOrSkipped">
|
||||
Next</x-forms.button>
|
||||
@endif
|
||||
</x-slot:actions>
|
||||
<x-slot:explanation>
|
||||
<p>This will install the latest Docker Engine on your server, configure a few things to be able
|
||||
|
@ -48,10 +48,16 @@
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@if ($server->settings->is_reachable && !$server->settings->is_usable && $server->id !== 0)
|
||||
<x-forms.button class="mt-8 mb-4 box" onclick="installDocker.showModal()" wire:click.prevent='installDocker'
|
||||
isHighlighted>
|
||||
Install Docker Engine 24.0
|
||||
</x-forms.button>
|
||||
@if ($dockerInstallationStarted)
|
||||
<x-forms.button class="mt-8 mb-4 box" wire:click.prevent='validateServer'>
|
||||
Validate Server
|
||||
</x-forms.button>
|
||||
@else
|
||||
<x-forms.button class="mt-8 mb-4 box" onclick="installDocker.showModal()"
|
||||
wire:click.prevent='installDocker' isHighlighted>
|
||||
Install Docker Engine 24.0
|
||||
</x-forms.button>
|
||||
@endif
|
||||
@endif
|
||||
@if ($server->isFunctional())
|
||||
<h3 class="py-4">Settings</h3>
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
<div class="flex gap-2" x-init="$wire.getProxyStatus">
|
||||
@if ($server->proxy->status === 'running')
|
||||
<x-status.running text="Proxy Running" />
|
||||
@ -7,7 +6,8 @@
|
||||
@else
|
||||
<x-status.stopped text="Proxy Stopped" />
|
||||
@endif
|
||||
<button wire:click.prevent='getProxyStatusWithNoti'><svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<button wire:loading.remove.delay.longer wire:click.prevent='getProxyStatusWithNoti'>
|
||||
<svg class="icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#FCD44F">
|
||||
<path
|
||||
d="M12.079 3v-.75V3Zm-8.4 8.333h-.75h.75Zm0 1.667l-.527.532a.75.75 0 0 0 1.056 0L3.68 13Zm2.209-1.134A.75.75 0 1 0 4.83 10.8l1.057 1.065ZM2.528 10.8a.75.75 0 0 0-1.056 1.065L2.528 10.8Zm16.088-3.408a.75.75 0 1 0 1.277-.786l-1.277.786ZM12.079 2.25c-5.047 0-9.15 4.061-9.15 9.083h1.5c0-4.182 3.42-7.583 7.65-7.583v-1.5Zm-9.15 9.083V13h1.5v-1.667h-1.5Zm1.28 2.2l1.679-1.667L4.83 10.8l-1.68 1.667l1.057 1.064Zm0-1.065L2.528 10.8l-1.057 1.065l1.68 1.666l1.056-1.064Zm15.684-5.86A9.158 9.158 0 0 0 12.08 2.25v1.5a7.658 7.658 0 0 1 6.537 3.643l1.277-.786Z" />
|
||||
|
@ -4,7 +4,7 @@
|
||||
"version": "3.12.36"
|
||||
},
|
||||
"v4": {
|
||||
"version": "4.0.0-beta.40"
|
||||
"version": "4.0.0-beta.41"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user