Merge pull request #2230 from coollabsio/next

v4.0.0-beta.281
This commit is contained in:
Andras Bacsai 2024-05-17 12:45:26 +02:00 committed by GitHub
commit 5de1246827
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
89 changed files with 507 additions and 324 deletions

View File

@ -27,10 +27,10 @@ public function handle(bool $force = false, bool $async = false)
CleanupDocker::run($this->server, false); CleanupDocker::run($this->server, false);
$this->latestVersion = get_latest_version_of_coolify(); $this->latestVersion = get_latest_version_of_coolify();
$this->currentVersion = config('version'); $this->currentVersion = config('version');
if ($settings->next_channel) { // if ($settings->next_channel) {
ray('next channel enabled'); // ray('next channel enabled');
$this->latestVersion = 'next'; // $this->latestVersion = 'next';
} // }
if ($force) { if ($force) {
$this->update(); $this->update();
} else { } else {

View File

@ -21,8 +21,10 @@
class Kernel extends ConsoleKernel class Kernel extends ConsoleKernel
{ {
private $all_servers;
protected function schedule(Schedule $schedule): void protected function schedule(Schedule $schedule): void
{ {
$this->all_servers = Server::all();
if (isDev()) { if (isDev()) {
// Instance Jobs // Instance Jobs
$schedule->command('horizon:snapshot')->everyMinute(); $schedule->command('horizon:snapshot')->everyMinute();
@ -56,7 +58,7 @@ protected function schedule(Schedule $schedule): void
} }
private function pull_helper_image($schedule) private function pull_helper_image($schedule)
{ {
$servers = Server::all()->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4'); $servers = $this->all_servers->where('settings.is_usable', true)->where('settings.is_reachable', true)->where('ip', '!=', '1.2.3.4');
foreach ($servers as $server) { foreach ($servers as $server) {
if (config('coolify.is_sentinel_enabled')) { if (config('coolify.is_sentinel_enabled')) {
$schedule->job(new PullSentinelImageJob($server))->everyFiveMinutes()->onOneServer(); $schedule->job(new PullSentinelImageJob($server))->everyFiveMinutes()->onOneServer();
@ -67,12 +69,12 @@ private function pull_helper_image($schedule)
private function check_resources($schedule) private function check_resources($schedule)
{ {
if (isCloud()) { if (isCloud()) {
$servers = Server::all()->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4'); $servers = $this->all_servers->whereNotNull('team.subscription')->where('team.subscription.stripe_trial_already_ended', false)->where('ip', '!=', '1.2.3.4');
$own = Team::find(0)->servers; $own = Team::find(0)->servers;
$servers = $servers->merge($own); $servers = $servers->merge($own);
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false); $containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
} else { } else {
$servers = Server::all()->where('ip', '!=', '1.2.3.4'); $servers = $this->all_servers->where('ip', '!=', '1.2.3.4');
$containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false); $containerServers = $servers->where('settings.is_swarm_worker', false)->where('settings.is_build_server', false);
} }
foreach ($containerServers as $server) { foreach ($containerServers as $server) {

View File

@ -713,10 +713,36 @@ private function check_image_locally_or_remotely()
private function save_environment_variables() private function save_environment_variables()
{ {
$envs = collect([]); $envs = collect([]);
$sort = $this->application->settings->is_env_sorting_enabled;
if ($sort) {
$sorted_environment_variables = $this->application->environment_variables->sortBy('key');
$sorted_environment_variables_preview = $this->application->environment_variables_preview->sortBy('key');
} else {
$sorted_environment_variables = $this->application->environment_variables->sortBy('id');
$sorted_environment_variables_preview = $this->application->environment_variables_preview->sortBy('id');
}
$ports = $this->application->main_port(); $ports = $this->application->main_port();
if ($this->pull_request_id !== 0) { if ($this->pull_request_id !== 0) {
$this->env_filename = ".env-pr-$this->pull_request_id"; $this->env_filename = ".env-pr-$this->pull_request_id";
foreach ($this->application->environment_variables_preview as $env) { // Add SOURCE_COMMIT if not exists
if ($this->application->environment_variables_preview->where('key', 'SOURCE_COMMIT')->isEmpty()) {
if (!is_null($this->commit)) {
$envs->push("SOURCE_COMMIT={$this->commit}");
} else {
$envs->push("SOURCE_COMMIT=unknown");
}
}
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_FQDN')->isEmpty()) {
$envs->push("COOLIFY_FQDN={$this->preview->fqdn}");
}
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_URL')->isEmpty()) {
$url = str($this->preview->fqdn)->replace('http://', '')->replace('https://', '');
$envs->push("COOLIFY_URL={$url}");
}
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
$envs->push("COOLIFY_BRANCH={$this->application->git_branch}");
}
foreach ($sorted_environment_variables_preview as $env) {
$real_value = $env->real_value; $real_value = $env->real_value;
if ($env->version === '4.0.0-beta.239') { if ($env->version === '4.0.0-beta.239') {
$real_value = $env->real_value; $real_value = $env->real_value;
@ -737,30 +763,27 @@ private function save_environment_variables()
if ($this->application->environment_variables_preview->where('key', 'HOST')->isEmpty()) { if ($this->application->environment_variables_preview->where('key', 'HOST')->isEmpty()) {
$envs->push("HOST=0.0.0.0"); $envs->push("HOST=0.0.0.0");
} }
} else {
$this->env_filename = ".env";
// Add SOURCE_COMMIT if not exists // Add SOURCE_COMMIT if not exists
if ($this->application->environment_variables_preview->where('key', 'SOURCE_COMMIT')->isEmpty()) { if ($this->application->environment_variables->where('key', 'SOURCE_COMMIT')->isEmpty()) {
if (!is_null($this->commit)) { if (!is_null($this->commit)) {
$envs->push("SOURCE_COMMIT={$this->commit}"); $envs->push("SOURCE_COMMIT={$this->commit}");
} else { } else {
$envs->push("SOURCE_COMMIT=unknown"); $envs->push("SOURCE_COMMIT=unknown");
} }
} }
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_FQDN')->isEmpty()) { if ($this->application->environment_variables->where('key', 'COOLIFY_FQDN')->isEmpty()) {
$envs->push("COOLIFY_FQDN={$this->preview->fqdn}"); $envs->push("COOLIFY_FQDN={$this->application->fqdn}");
} }
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_URL')->isEmpty()) { if ($this->application->environment_variables->where('key', 'COOLIFY_URL')->isEmpty()) {
$url = str($this->preview->fqdn)->replace('http://', '')->replace('https://', ''); $url = str($this->application->fqdn)->replace('http://', '')->replace('https://', '');
$envs->push("COOLIFY_URL={$url}"); $envs->push("COOLIFY_URL={$url}");
} }
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) { if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
$envs->push("COOLIFY_BRANCH={$this->application->git_branch}"); $envs->push("COOLIFY_BRANCH={$this->application->git_branch}");
} }
$envs = $envs->sort(function ($a, $b) { foreach ($sorted_environment_variables as $env) {
return strpos($a, '$') === false ? -1 : 1;
});
} else {
$this->env_filename = ".env";
foreach ($this->application->environment_variables as $env) {
$real_value = $env->real_value; $real_value = $env->real_value;
if ($env->version === '4.0.0-beta.239') { if ($env->version === '4.0.0-beta.239') {
$real_value = $env->real_value; $real_value = $env->real_value;
@ -781,27 +804,6 @@ private function save_environment_variables()
if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) { if ($this->application->environment_variables->where('key', 'HOST')->isEmpty()) {
$envs->push("HOST=0.0.0.0"); $envs->push("HOST=0.0.0.0");
} }
// Add SOURCE_COMMIT if not exists
if ($this->application->environment_variables->where('key', 'SOURCE_COMMIT')->isEmpty()) {
if (!is_null($this->commit)) {
$envs->push("SOURCE_COMMIT={$this->commit}");
} else {
$envs->push("SOURCE_COMMIT=unknown");
}
}
if ($this->application->environment_variables->where('key', 'COOLIFY_FQDN')->isEmpty()) {
$envs->push("COOLIFY_FQDN={$this->application->fqdn}");
}
if ($this->application->environment_variables->where('key', 'COOLIFY_URL')->isEmpty()) {
$url = str($this->application->fqdn)->replace('http://', '')->replace('https://', '');
$envs->push("COOLIFY_URL={$url}");
}
if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) {
$envs->push("COOLIFY_BRANCH={$this->application->git_branch}");
}
$envs = $envs->sort(function ($a, $b) {
return strpos($a, '$') === false ? -1 : 1;
});
} }
if ($envs->isEmpty()) { if ($envs->isEmpty()) {
@ -1272,6 +1274,7 @@ private function generate_nixpacks_env_variables()
private function generate_env_variables() private function generate_env_variables()
{ {
$this->env_args = collect([]); $this->env_args = collect([]);
$this->env_args->put('SOURCE_COMMIT', $this->commit);
if ($this->pull_request_id === 0) { if ($this->pull_request_id === 0) {
foreach ($this->application->build_environment_variables as $env) { foreach ($this->application->build_environment_variables as $env) {
if (!is_null($env->real_value)) { if (!is_null($env->real_value)) {
@ -1285,7 +1288,6 @@ private function generate_env_variables()
} }
} }
} }
$this->env_args->put('SOURCE_COMMIT', $this->commit);
} }
private function generate_compose_file() private function generate_compose_file()
@ -1603,12 +1605,12 @@ private function generate_healthcheck_commands()
if ($this->application->health_check_path) { if ($this->application->health_check_path) {
$this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path}"; $this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path}";
$generated_healthchecks_commands = [ $generated_healthchecks_commands = [
"curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} > /dev/null || wget -q -O- {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} > /dev/null || exit 1" "curl -o /dev/null -w \"%{http_code}\" -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} | grep -q \"{$this->application->health_check_return_code}\" || wget --save-headers -O - {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} 2>/dev/null |grep HTTP/ |grep -q \"{$this->application->health_check_return_code}\" || exit 1"
]; ];
} else { } else {
$this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/"; $this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/";
$generated_healthchecks_commands = [ $generated_healthchecks_commands = [
"curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/ > /dev/null || wget -q -O- {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/ > /dev/null || exit 1" "curl -o /dev/null -w \"%{http_code}\" -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/ | grep -q \"{$this->application->health_check_return_code}\" || wget --save-headers -O - {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/ 2>/dev/null |grep HTTP/ |grep -q \"{$this->application->health_check_return_code}\" || exit 1"
]; ];
} }
return implode(' ', $generated_healthchecks_commands); return implode(' ', $generated_healthchecks_commands);
@ -1967,10 +1969,7 @@ private function next(string $status)
if (!$this->only_this_server) { if (!$this->only_this_server) {
$this->deploy_to_additional_destinations(); $this->deploy_to_additional_destinations();
} }
if (!isCloud()) { $this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
// TODO: turn off until we have a better solution
$this->application->environment->project->team?->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
}
} }
} }

View File

@ -5,7 +5,7 @@
use App\Actions\Application\StopApplication; use App\Actions\Application\StopApplication;
use App\Actions\Docker\GetContainersStatus; use App\Actions\Docker\GetContainersStatus;
use App\Events\ApplicationStatusChanged; use App\Events\ApplicationStatusChanged;
use App\Jobs\ContainerStatusJob; use App\Jobs\ContainerStatusJob;
use App\Jobs\ServerStatusJob; use App\Jobs\ServerStatusJob;
use App\Models\Application; use App\Models\Application;
use Livewire\Component; use Livewire\Component;
@ -14,6 +14,8 @@
class Heading extends Component class Heading extends Component
{ {
public Application $application; public Application $application;
public ?string $lastDeploymentInfo = null;
public ?string $lastDeploymentLink = null;
public array $parameters; public array $parameters;
protected string $deploymentUuid; protected string $deploymentUuid;
@ -28,6 +30,9 @@ public function getListeners()
public function mount() public function mount()
{ {
$this->parameters = get_route_parameters(); $this->parameters = get_route_parameters();
$lastDeployment = $this->application->get_last_successful_deployment();
$this->lastDeploymentInfo = data_get_str($lastDeployment, 'commit')->limit(7) . ' ' . data_get($lastDeployment, 'commit_message');
$this->lastDeploymentLink = $this->application->gitCommitLink(data_get($lastDeployment, 'commit'));
} }
public function check_status($showNotification = false) public function check_status($showNotification = false)

View File

@ -5,11 +5,11 @@
use App\Models\EnvironmentVariable; use App\Models\EnvironmentVariable;
use Livewire\Component; use Livewire\Component;
use Visus\Cuid2\Cuid2; use Visus\Cuid2\Cuid2;
use Illuminate\Support\Str;
class All extends Component class All extends Component
{ {
public $resource; public $resource;
public string $resourceClass;
public bool $showPreview = false; public bool $showPreview = false;
public ?string $modalId = null; public ?string $modalId = null;
public ?string $variables = null; public ?string $variables = null;
@ -19,17 +19,44 @@ class All extends Component
'refreshEnvs', 'refreshEnvs',
'saveKey' => 'submit', 'saveKey' => 'submit',
]; ];
protected $rules = [
'resource.settings.is_env_sorting_enabled' => 'required|boolean',
];
public function mount() public function mount()
{ {
$resourceClass = get_class($this->resource); $this->resourceClass = get_class($this->resource);
$resourceWithPreviews = ['App\Models\Application']; $resourceWithPreviews = ['App\Models\Application'];
$simpleDockerfile = !is_null(data_get($this->resource, 'dockerfile')); $simpleDockerfile = !is_null(data_get($this->resource, 'dockerfile'));
if (Str::of($resourceClass)->contains($resourceWithPreviews) && !$simpleDockerfile) { if (str($this->resourceClass)->contains($resourceWithPreviews) && !$simpleDockerfile) {
$this->showPreview = true; $this->showPreview = true;
} }
$this->modalId = new Cuid2(7); $this->modalId = new Cuid2(7);
$this->sortMe();
$this->getDevView(); $this->getDevView();
} }
public function sortMe()
{
if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') {
if ($this->resource->settings->is_env_sorting_enabled) {
$this->resource->environment_variables = $this->resource->environment_variables->sortBy('key');
$this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('key');
} else {
$this->resource->environment_variables = $this->resource->environment_variables->sortBy('id');
$this->resource->environment_variables_preview = $this->resource->environment_variables_preview->sortBy('id');
}
}
$this->getDevView();
}
public function instantSave()
{
if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose') {
$this->resource->settings->save();
$this->dispatch('success', 'Environment variable settings updated.');
$this->sortMe();
}
}
public function getDevView() public function getDevView()
{ {
$this->variables = $this->resource->environment_variables->map(function ($item) { $this->variables = $this->resource->environment_variables->map(function ($item) {
@ -40,7 +67,7 @@ public function getDevView()
return "$item->key=(multiline, edit in normal view)"; return "$item->key=(multiline, edit in normal view)";
} }
return "$item->key=$item->value"; return "$item->key=$item->value";
})->sort()->join(' })->join('
'); ');
if ($this->showPreview) { if ($this->showPreview) {
$this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) { $this->variablesPreview = $this->resource->environment_variables_preview->map(function ($item) {
@ -51,13 +78,18 @@ public function getDevView()
return "$item->key=(multiline, edit in normal view)"; return "$item->key=(multiline, edit in normal view)";
} }
return "$item->key=$item->value"; return "$item->key=$item->value";
})->sort()->join(' })->join('
'); ');
} }
} }
public function switch() public function switch()
{ {
$this->view = $this->view === 'normal' ? 'dev' : 'normal'; if ($this->view === 'normal') {
$this->view = 'dev';
} else {
$this->view = 'normal';
}
$this->sortMe();
} }
public function saveVariables($isPreview) public function saveVariables($isPreview)
{ {
@ -66,6 +98,7 @@ public function saveVariables($isPreview)
$this->resource->environment_variables_preview()->whereNotIn('key', array_keys($variables))->delete(); $this->resource->environment_variables_preview()->whereNotIn('key', array_keys($variables))->delete();
} else { } else {
$variables = parseEnvFormatToArray($this->variables); $variables = parseEnvFormatToArray($this->variables);
ray($variables, $this->variables);
$this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->delete(); $this->resource->environment_variables()->whereNotIn('key', array_keys($variables))->delete();
} }
foreach ($variables as $key => $variable) { foreach ($variables as $key => $variable) {

View File

@ -13,7 +13,7 @@ class Configuration extends Component
public bool $is_auto_update_enabled; public bool $is_auto_update_enabled;
public bool $is_registration_enabled; public bool $is_registration_enabled;
public bool $is_dns_validation_enabled; public bool $is_dns_validation_enabled;
public bool $next_channel; // public bool $next_channel;
protected string $dynamic_config_path = '/data/coolify/proxy/dynamic'; protected string $dynamic_config_path = '/data/coolify/proxy/dynamic';
protected Server $server; protected Server $server;
@ -37,7 +37,7 @@ public function mount()
$this->do_not_track = $this->settings->do_not_track; $this->do_not_track = $this->settings->do_not_track;
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled; $this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
$this->is_registration_enabled = $this->settings->is_registration_enabled; $this->is_registration_enabled = $this->settings->is_registration_enabled;
$this->next_channel = $this->settings->next_channel; // $this->next_channel = $this->settings->next_channel;
$this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled; $this->is_dns_validation_enabled = $this->settings->is_dns_validation_enabled;
} }
@ -47,12 +47,12 @@ public function instantSave()
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled; $this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
$this->settings->is_registration_enabled = $this->is_registration_enabled; $this->settings->is_registration_enabled = $this->is_registration_enabled;
$this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled; $this->settings->is_dns_validation_enabled = $this->is_dns_validation_enabled;
if ($this->next_channel) { // if ($this->next_channel) {
$this->settings->next_channel = false; // $this->settings->next_channel = false;
$this->next_channel = false; // $this->next_channel = false;
} else { // } else {
$this->settings->next_channel = $this->next_channel; // $this->settings->next_channel = $this->next_channel;
} // }
$this->settings->save(); $this->settings->save();
$this->dispatch('success', 'Settings updated!'); $this->dispatch('success', 'Settings updated!');
} }

View File

@ -3,7 +3,7 @@
namespace App\Livewire; namespace App\Livewire;
use App\Actions\Server\UpdateCoolify; use App\Actions\Server\UpdateCoolify;
use App\Models\InstanceSettings;
use Livewire\Component; use Livewire\Component;
use DanHarrin\LivewireRateLimiting\WithRateLimiting; use DanHarrin\LivewireRateLimiting\WithRateLimiting;
@ -11,6 +11,7 @@ class Upgrade extends Component
{ {
use WithRateLimiting; use WithRateLimiting;
public bool $showProgress = false; public bool $showProgress = false;
public bool $updateInProgress = false;
public bool $isUpgradeAvailable = false; public bool $isUpgradeAvailable = false;
public string $latestVersion = ''; public string $latestVersion = '';
@ -22,23 +23,17 @@ public function checkUpdate()
if (isDev()) { if (isDev()) {
$this->isUpgradeAvailable = true; $this->isUpgradeAvailable = true;
} }
$settings = InstanceSettings::get();
if ($settings->next_channel) {
$this->isUpgradeAvailable = true;
$this->latestVersion = 'next';
}
} }
public function upgrade() public function upgrade()
{ {
try { try {
if ($this->showProgress) { if ($this->updateInProgress) {
return; return;
} }
$this->rateLimit(1, 30); $this->rateLimit(1, 60);
$this->showProgress = true; $this->updateInProgress = true;
UpdateCoolify::run(force: true, async: true); UpdateCoolify::run(force: true, async: true);
$this->dispatch('success', "Updating Coolify to {$this->latestVersion} version...");
} catch (\Throwable $e) { } catch (\Throwable $e) {
return handleError($e, $this); return handleError($e, $this);
} }

View File

@ -192,10 +192,16 @@ public function gitCommits(): Attribute
public function gitCommitLink($link): string public function gitCommitLink($link): string
{ {
if (!is_null($this->source?->html_url) && !is_null($this->git_repository) && !is_null($this->git_branch)) { if (!is_null($this->source?->html_url) && !is_null($this->git_repository) && !is_null($this->git_branch)) {
if (str($this->source->html_url)->contains('bitbucket')) {
return "{$this->source->html_url}/{$this->git_repository}/commits/{$link}";
}
return "{$this->source->html_url}/{$this->git_repository}/commit/{$link}"; return "{$this->source->html_url}/{$this->git_repository}/commit/{$link}";
} }
if (strpos($this->git_repository, 'git@') === 0) { if (strpos($this->git_repository, 'git@') === 0) {
$git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository); $git_repository = str_replace(['git@', ':', '.git'], ['', '/', ''], $this->git_repository);
if (str($this->source->html_url)->contains('bitbucket')) {
return "https://{$git_repository}/commits/{$link}";
}
return "https://{$git_repository}/commit/{$link}"; return "https://{$git_repository}/commit/{$link}";
} }
return $this->git_repository; return $this->git_repository;
@ -454,6 +460,10 @@ public function isDeploymentInprogress()
} }
return false; return false;
} }
public function get_last_successful_deployment()
{
return ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', 'finished')->orderBy('created_at', 'desc')->first();
}
public function get_last_days_deployments() public function get_last_days_deployments()
{ {
return ApplicationDeploymentQueue::where('application_id', $this->id)->where('created_at', '>=', now()->subDays(7))->orderBy('created_at', 'desc')->get(); return ApplicationDeploymentQueue::where('application_id', $this->id)->where('created_at', '>=', now()->subDays(7))->orderBy('created_at', 'desc')->get();
@ -989,7 +999,8 @@ public function getFilesFromServer(bool $isInit = false)
getFilesystemVolumesFromServer($this, $isInit); getFilesystemVolumesFromServer($this, $isInit);
} }
public function parseHealthcheckFromDockerfile($dockerfile, bool $isInit = false) { public function parseHealthcheckFromDockerfile($dockerfile, bool $isInit = false)
{
if (str($dockerfile)->contains('HEALTHCHECK') && ($this->isHealthcheckDisabled() || $isInit)) { if (str($dockerfile)->contains('HEALTHCHECK') && ($this->isHealthcheckDisabled() || $isInit)) {
$healthcheckCommand = null; $healthcheckCommand = null;
$lines = $dockerfile->toArray(); $lines = $dockerfile->toArray();

View File

@ -43,7 +43,12 @@ public function __construct(Application $application, string $deployment_uuid, A
public function via(object $notifiable): array public function via(object $notifiable): array
{ {
return setNotificationChannels($notifiable, 'deployments'); $channels = setNotificationChannels($notifiable, 'deployments');
if (isCloud()) {
// TODO: Make batch notifications work with email
$channels = array_diff($channels, ['App\Notifications\Channels\EmailChannel']);
}
return $channels;
} }
public function toMail(): MailMessage public function toMail(): MailMessage
{ {

View File

@ -14,20 +14,22 @@ public function send($notifiable, $notification): void
$buttons = data_get($data, 'buttons', []); $buttons = data_get($data, 'buttons', []);
$telegramToken = data_get($telegramData, 'token'); $telegramToken = data_get($telegramData, 'token');
$chatId = data_get($telegramData, 'chat_id'); $chatId = data_get($telegramData, 'chat_id');
$topicId = null; $topicId = null;
$topicsInstance = get_class($notification); $topicsInstance = get_class($notification);
switch ($topicsInstance) { switch ($topicsInstance) {
case 'App\Notifications\StatusChange':
$topicId = data_get($notifiable, 'telegram_notifications_status_changes_message_thread_id');
break;
case 'App\Notifications\Test': case 'App\Notifications\Test':
$topicId = data_get($notifiable, 'telegram_notifications_test_message_thread_id'); $topicId = data_get($notifiable, 'telegram_notifications_test_message_thread_id');
break; break;
case 'App\Notifications\Deployment': case 'App\Notifications\Application\StatusChanged':
$topicId = data_get($notifiable, 'telegram_notifications_status_changes_message_thread_id');
break;
case 'App\Notifications\Application\DeploymentSuccess':
case 'App\Notifications\Application\DeploymentFailed':
$topicId = data_get($notifiable, 'telegram_notifications_deployments_message_thread_id'); $topicId = data_get($notifiable, 'telegram_notifications_deployments_message_thread_id');
break; break;
case 'App\Notifications\DatabaseBackup': case 'App\Notifications\Database\BackupSuccess':
case 'App\Notifications\Database\BackupFailed':
$topicId = data_get($notifiable, 'telegram_notifications_database_backups_message_thread_id'); $topicId = data_get($notifiable, 'telegram_notifications_database_backups_message_thread_id');
break; break;
} }

View File

@ -7,7 +7,7 @@
// The release version of your application // The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD')) // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
'release' => '4.0.0-beta.280', 'release' => '4.0.0-beta.281',
// When left empty or `null` the Laravel environment will be used // When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'), 'environment' => config('app.env'),

View File

@ -1,3 +1,3 @@
<?php <?php
return '4.0.0-beta.280'; return '4.0.0-beta.281';

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('application_settings', function (Blueprint $table) {
$table->boolean('is_env_sorting_enabled')->default(true);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('application_settings', function (Blueprint $table) {
$table->dropColumn('is_env_sorting_enabled');
});
}
};

View File

@ -161,10 +161,11 @@ class="{{ request()->is('destination*') ? 'menu-item-active menu-item' : 'menu-i
class="{{ request()->is('storages*') ? 'menu-item-active menu-item' : 'menu-item' }}" class="{{ request()->is('storages*') ? 'menu-item-active menu-item' : 'menu-item' }}"
href="{{ route('storage.index') }}"> href="{{ route('storage.index') }}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"> <g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
<path d="M4 6a8 3 0 1 0 16 0A8 3 0 1 0 4 6"/> stroke-width="2">
<path d="M4 6v6a8 3 0 0 0 16 0V6"/> <path d="M4 6a8 3 0 1 0 16 0A8 3 0 1 0 4 6" />
<path d="M4 12v6a8 3 0 0 0 16 0v-6"/> <path d="M4 6v6a8 3 0 0 0 16 0V6" />
<path d="M4 12v6a8 3 0 0 0 16 0v-6" />
</g> </g>
</svg> </svg>
S3 Storages S3 Storages
@ -175,9 +176,11 @@ class="{{ request()->is('storages*') ? 'menu-item-active menu-item' : 'menu-item
class="{{ request()->is('shared-variables*') ? 'menu-item-active menu-item' : 'menu-item' }}" class="{{ request()->is('shared-variables*') ? 'menu-item-active menu-item' : 'menu-item' }}"
href="{{ route('shared-variables.index') }}"> href="{{ route('shared-variables.index') }}">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24"> <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 24 24">
<g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"> <g fill="none" stroke="currentColor" stroke-linecap="round"
<path d="M5 4C2.5 9 2.5 14 5 20M19 4c2.5 5 2.5 10 0 16M9 9h1c1 0 1 1 2.016 3.527C13 15 13 16 14 16h1"/> stroke-linejoin="round" stroke-width="2">
<path d="M8 16c1.5 0 3-2 4-3.5S14.5 9 16 9"/> <path
d="M5 4C2.5 9 2.5 14 5 20M19 4c2.5 5 2.5 10 0 16M9 9h1c1 0 1 1 2.016 3.527C13 15 13 16 14 16h1" />
<path d="M8 16c1.5 0 3-2 4-3.5S14.5 9 16 9" />
</g> </g>
</svg> </svg>
Shared Variables Shared Variables
@ -318,9 +321,7 @@ class="{{ request()->is('settings*') ? 'menu-item-active menu-item' : 'menu-item
<div class="flex-1"></div> <div class="flex-1"></div>
@if (isInstanceAdmin() && !isCloud()) @if (isInstanceAdmin() && !isCloud())
<li> <li>
@persist('upgrade') <livewire:upgrade />
<livewire:upgrade />
@endpersist
</li> </li>
@endif @endif
<li> <li>

View File

@ -1,5 +1,10 @@
@props([
'lastDeploymentInfo' => null,
'lastDeploymentLink' => null,
'resource' => null,
])
<nav class="flex pt-2 pb-10"> <nav class="flex pt-2 pb-10">
<ol class="flex items-center flex-wrap gap-y-1"> <ol class="flex flex-wrap items-center gap-y-1">
<li class="inline-flex items-center"> <li class="inline-flex items-center">
<div class="flex items-center"> <div class="flex items-center">
<a wire:navigate class="text-xs truncate lg:text-sm" <a wire:navigate class="text-xs truncate lg:text-sm"
@ -15,7 +20,6 @@
</li> </li>
<li> <li>
<div class="flex items-center"> <div class="flex items-center">
<a class="text-xs truncate lg:text-sm" <a class="text-xs truncate lg:text-sm"
href="{{ route('project.resource.index', ['environment_name' => $this->parameters['environment_name'], 'project_uuid' => $this->parameters['project_uuid']]) }}">{{ $this->parameters['environment_name'] }}</a> href="{{ route('project.resource.index', ['environment_name' => $this->parameters['environment_name'], 'project_uuid' => $this->parameters['project_uuid']]) }}">{{ $this->parameters['environment_name'] }}</a>
<svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold dark:text-warning" fill="currentColor" <svg aria-hidden="true" class="w-4 h-4 mx-1 font-bold dark:text-warning" fill="currentColor"
@ -40,7 +44,7 @@
@if ($resource->getMorphClass() == 'App\Models\Service') @if ($resource->getMorphClass() == 'App\Models\Service')
<x-status.services :service="$resource" /> <x-status.services :service="$resource" />
@else @else
<x-status.index :resource="$resource" /> <x-status.index :resource="$resource" :lastDeploymentInfo="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" />
@endif @endif
</ol> </ol>
</nav> </nav>

View File

@ -1,9 +1,14 @@
@props([
'lastDeploymentInfo' => null,
'lastDeploymentLink' => null,
'resource' => null,
])
@if (str($resource->status)->startsWith('running')) @if (str($resource->status)->startsWith('running'))
<x-status.running :status="$resource->status" /> <x-status.running :status="$resource->status" :lastDeploymentInfo="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" />
@elseif(str($resource->status)->startsWith('restarting') || @elseif(str($resource->status)->startsWith('restarting') ||
str($resource->status)->startsWith('starting') || str($resource->status)->startsWith('starting') ||
str($resource->status)->startsWith('degraded')) str($resource->status)->startsWith('degraded'))
<x-status.restarting :status="$resource->status" /> <x-status.restarting :status="$resource->status" :lastDeploymentInfo="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" />
@else @else
<x-status.stopped :status="$resource->status" /> <x-status.stopped :status="$resource->status" />
@endif @endif

View File

@ -1,12 +1,20 @@
@props([ @props([
'status' => 'Restarting', 'status' => 'Restarting',
'lastDeploymentInfo' => null,
'lastDeploymentLink' => null,
]) ])
<div class="flex items-center"> <div class="flex items-center">
<x-loading wire:loading.delay.longer /> <x-loading wire:loading.delay.longer />
<span wire:loading.remove.delay.longer class="flex items-center"> <span wire:loading.remove.delay.longer class="flex items-center">
<div class="badge badge-warning "></div> <div class="badge badge-warning "></div>
<div class="pl-2 pr-1 text-xs font-bold tracking-wider dark:text-warning"> <div class="pl-2 pr-1 text-xs font-bold tracking-wider dark:text-warning" @if($lastDeploymentInfo) title="{{$lastDeploymentInfo}}" @endif>
{{ str($status)->before(':')->headline() }} @if ($lastDeploymentLink)
<a href="{{ $lastDeploymentLink }}" class="underline cursor-pointer">
{{ str($status)->before(':')->headline() }}
</a>
@else
{{ str($status)->before(':')->headline() }}
@endif
</div> </div>
@if (!str($status)->startsWith('Proxy') && !str($status)->contains('(')) @if (!str($status)->startsWith('Proxy') && !str($status)->contains('('))
<div class="text-xs dark:text-warning">({{ str($status)->after(':') }})</div> <div class="text-xs dark:text-warning">({{ str($status)->after(':') }})</div>

View File

@ -1,12 +1,20 @@
@props([ @props([
'status' => 'Running', 'status' => 'Running',
'lastDeploymentInfo' => null,
'lastDeploymentLink' => null,
]) ])
<div class="flex items-center"> <div class="flex items-center">
<x-loading wire:loading.delay.longer /> <x-loading wire:loading.delay.longer />
<span wire:loading.remove.delay.longer class="flex items-center"> <span wire:loading.remove.delay.longer class="flex items-center">
<div class="badge badge-success "></div> <div class="badge badge-success "></div>
<div class="pl-2 pr-1 text-xs font-bold tracking-wider text-success"> <div class="pl-2 pr-1 text-xs font-bold tracking-wider text-success" @if($lastDeploymentInfo) title="{{$lastDeploymentInfo}}" @endif>
@if ($lastDeploymentLink)
<a href="{{ $lastDeploymentLink }}" class="underline cursor-pointer">
{{ str($status)->before(':')->headline() }}
</a>
@else
{{ str($status)->before(':')->headline() }} {{ str($status)->before(':')->headline() }}
@endif
</div> </div>
@if (!str($status)->startsWith('Proxy') && !str($status)->contains('(')) @if (!str($status)->startsWith('Proxy') && !str($status)->contains('('))
@if (str($status)->contains('unhealthy')) @if (str($status)->contains('unhealthy'))
@ -17,8 +25,6 @@
</svg> </svg>
</x-slot:icon> </x-slot:icon>
</x-helper> </x-helper>
{{-- @else
<div class="text-xs dark:text-success">({{ str($status)->after(':') }})</div> --}}
@endif @endif
@endif @endif
</span> </span>

View File

@ -98,47 +98,6 @@ function changePasswordFieldType(event) {
} }
} }
function revive() {
if (checkHealthInterval) return true;
console.log('Checking server\'s health...')
checkHealthInterval = setInterval(() => {
fetch('/api/health')
.then(response => {
if (response.ok) {
window.toast('Coolify is back online. Reloading...', {
type: 'success',
})
if (checkHealthInterval) clearInterval(checkHealthInterval);
setTimeout(() => {
window.location.reload();
}, 5000)
} else {
console.log('Waiting for server to come back from dead...');
}
})
}, 2000);
}
function upgrade() {
if (checkIfIamDeadInterval) return true;
console.log('Update initiated.')
checkIfIamDeadInterval = setInterval(() => {
fetch('/api/health')
.then(response => {
if (response.ok) {
console.log('It\'s alive. Waiting for server to be dead...');
} else {
window.toast('Update done, restarting Coolify!', {
type: 'success',
})
console.log('It\'s dead. Reviving... Standby... Bzz... Bzz...')
if (checkIfIamDeadInterval) clearInterval(checkIfIamDeadInterval);
revive();
}
})
}, 2000);
}
function copyToClipboard(text) { function copyToClipboard(text) {
navigator?.clipboard?.writeText(text) && window.Livewire.dispatch('success', 'Copied to clipboard.'); navigator?.clipboard?.writeText(text) && window.Livewire.dispatch('success', 'Copied to clipboard.');
} }

View File

@ -7,7 +7,7 @@
Save Save
</x-forms.button> </x-forms.button>
@if ($team->telegram_enabled) @if ($team->telegram_enabled)
<x-forms.button class="dark:text-white normal-case btn btn-xs no-animation btn-primary" <x-forms.button class="normal-case dark:text-white btn btn-xs no-animation btn-primary"
wire:click="sendTestNotification"> wire:click="sendTestNotification">
Send Test Notifications Send Test Notifications
</x-forms.button> </x-forms.button>
@ -18,40 +18,44 @@
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<x-forms.input type="password" <x-forms.input type="password"
helper="Get it from the <a class='inline-block dark:text-white underline' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram." helper="Get it from the <a class='inline-block underline dark:text-white' href='https://t.me/botfather' target='_blank'>BotFather Bot</a> on Telegram."
required id="team.telegram_token" label="Token" /> required id="team.telegram_token" label="Token" />
<x-forms.input helper="Recommended to add your bot to a group chat and add its Chat ID here." required <x-forms.input helper="Recommended to add your bot to a group chat and add its Chat ID here." required
id="team.telegram_chat_id" label="Chat ID" /> id="team.telegram_chat_id" label="Chat ID" />
</div> </div>
@if (data_get($team, 'telegram_enabled')) @if (data_get($team, 'telegram_enabled'))
<h2 class="mt-4">Subscribe to events</h2> <h2 class="mt-4">Subscribe to events</h2>
<div class="w-96"> <div class="flex flex-col gap-4 w-96">
@if (isDev()) @if (isDev())
<div class="w-64"> <div class="flex flex-col">
<h4>Test Notification</h4>
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_test" <x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_test"
label="Test" /> label="Enabled" />
<x-forms.input <x-forms.input
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used." helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
id="team.telegram_notifications_test_message_thread_id" label="Custom Topic ID" /> id="team.telegram_notifications_test_message_thread_id" label="Custom Topic ID" />
</div> </div>
@endif @endif
<div class="w-64"> <div class="flex flex-col">
<h4>Container Status Changes</h4>
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_status_changes" <x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_status_changes"
label="Container Status Changes" /> label="Enabled" />
<x-forms.input <x-forms.input
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used." helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
id="team.telegram_notifications_status_changes_message_thread_id" label="Custom Topic ID" /> id="team.telegram_notifications_status_changes_message_thread_id" label="Custom Topic ID" />
</div> </div>
<div class="w-64"> <div class="flex flex-col">
<h4>Application Deployments</h4>
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_deployments" <x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_deployments"
label="Application Deployments" /> label="Enabled" />
<x-forms.input <x-forms.input
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used." helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
id="team.telegram_notifications_deployments_message_thread_id" label="Custom Topic ID" /> id="team.telegram_notifications_deployments_message_thread_id" label="Custom Topic ID" />
</div> </div>
<div class="w-64"> <div class="flex flex-col">
<h4>Database Backup Status</h4>
<x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_database_backups" <x-forms.checkbox instantSave="saveModel" id="team.telegram_notifications_database_backups"
label="Backup Status" /> label="Enabled" />
<x-forms.input <x-forms.input
helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used." helper="If you are using Group chat with Topics, you can specify the topics ID. If empty, General topic will be used."
id="team.telegram_notifications_database_backups_message_thread_id" label="Custom Topic ID" /> id="team.telegram_notifications_database_backups_message_thread_id" label="Custom Topic ID" />

View File

@ -1,5 +1,5 @@
<nav wire:poll.5000ms="check_status"> <nav wire:poll.5000ms="check_status">
<x-resources.breadcrumbs :resource="$application" :parameters="$parameters" /> <x-resources.breadcrumbs :resource="$application" :parameters="$parameters" :lastDeploymentInfo="$lastDeploymentInfo" :lastDeploymentLink="$lastDeploymentLink" />
<div class="navbar-main"> <div class="navbar-main">
<nav class="flex items-center flex-shrink-0 gap-6 scrollbar min-h-10 whitespace-nowrap"> <nav class="flex items-center flex-shrink-0 gap-6 scrollbar min-h-10 whitespace-nowrap">
<a href="{{ route('project.application.configuration', $parameters) }}"> <a href="{{ route('project.application.configuration', $parameters) }}">

View File

@ -11,12 +11,18 @@
wire:click='switch'>{{ $view === 'normal' ? 'Developer view' : 'Normal view' }}</x-forms.button> wire:click='switch'>{{ $view === 'normal' ? 'Developer view' : 'Normal view' }}</x-forms.button>
</div> </div>
<div>Environment variables (secrets) for this resource.</div> <div>Environment variables (secrets) for this resource.</div>
@if ($this->resourceClass === 'App\Models\Application' && data_get($this->resource, 'build_pack') !== 'dockercompose')
<div class="w-64 pt-2">
<x-forms.checkbox id="resource.settings.is_env_sorting_enabled" label="Sort alphabetically"
helper="Turn this off if one environment is dependent on an other. It will be sorted by creation order." instantSave></x-forms.checkbox>
</div>
@endif
@if ($resource->type() === 'service' || $resource?->build_pack === 'dockercompose') @if ($resource->type() === 'service' || $resource?->build_pack === 'dockercompose')
<div class="pt-4 dark:text-warning text-coollabs">Hardcoded variables are not shown here.</div> <div class="pt-4 dark:text-warning text-coollabs">Hardcoded variables are not shown here.</div>
@endif @endif
</div> </div>
@if ($view === 'normal') @if ($view === 'normal')
@forelse ($resource->environment_variables->sort()->sortBy('key') as $env) @forelse ($resource->environment_variables as $env)
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}" <livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
:env="$env" :type="$resource->type()" /> :env="$env" :type="$resource->type()" />
@empty @empty
@ -27,7 +33,7 @@
<h3>Preview Deployments</h3> <h3>Preview Deployments</h3>
<div>Environment (secrets) variables for Preview Deployments.</div> <div>Environment (secrets) variables for Preview Deployments.</div>
</div> </div>
@foreach ($resource->environment_variables_preview->sort()->sortBy('key') as $env) @foreach ($resource->environment_variables_preview as $env)
<livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}" <livewire:project.shared.environment-variable.show wire:key="environment-{{ $env->id }}"
:env="$env" :type="$resource->type()" /> :env="$env" :type="$resource->type()" />
@endforeach @endforeach

View File

@ -9,7 +9,7 @@
<div>General configuration for your Coolify instance.</div> <div>General configuration for your Coolify instance.</div>
<div class="flex flex-col gap-2 pt-4"> <div class="flex flex-col gap-2 pt-4">
<div class="flex items-end gap-2 flex-wrap"> <div class="flex flex-wrap items-end gap-2">
<x-forms.input id="settings.fqdn" label="Instance's Domain" placeholder="https://coolify.io" /> <x-forms.input id="settings.fqdn" label="Instance's Domain" placeholder="https://coolify.io" />
<x-forms.input id="settings.custom_dns_servers" label="DNS Servers" <x-forms.input id="settings.custom_dns_servers" label="DNS Servers"
helper="DNS servers for validation FQDNs againts. A comma separated list of DNS servers." helper="DNS servers for validation FQDNs againts. A comma separated list of DNS servers."
@ -35,13 +35,13 @@
@endif @endif
<x-forms.checkbox instantSave id="is_registration_enabled" label="Registration Allowed" /> <x-forms.checkbox instantSave id="is_registration_enabled" label="Registration Allowed" />
<x-forms.checkbox instantSave id="do_not_track" label="Do Not Track" /> <x-forms.checkbox instantSave id="do_not_track" label="Do Not Track" />
@if ($next_channel) {{-- @if ($next_channel)
<x-forms.checkbox instantSave helper="Not recommended. Only if you like to live on the edge." <x-forms.checkbox instantSave helper="Not recommended. Only if you like to live on the edge."
id="next_channel" label="Enable pre-release (early) updates" /> id="next_channel" label="Enable pre-release (early) updates" />
@else @else
<x-forms.checkbox disabled instantSave <x-forms.checkbox disabled instantSave
helper="Currently disabled. Not recommended. Only if you like to live on the edge." id="next_channel" helper="Currently disabled. Not recommended. Only if you like to live on the edge." id="next_channel"
label="Enable pre-release (early) updates" /> label="Enable pre-release (early) updates" />
@endif @endif --}}
</div> </div>
</div> </div>

View File

@ -1,29 +1,139 @@
<div @if ($isUpgradeAvailable) title="New version available" @else title="No upgrade available" @endif <div @if ($isUpgradeAvailable) title="New version available" @else title="No upgrade available" @endif
x-init="$wire.checkUpdate" x-data> x-init="$wire.checkUpdate" x-data="upgradeModal">
@if ($isUpgradeAvailable) @if ($isUpgradeAvailable)
<button wire:key="upgrade" wire:click='upgrade' class="menu-item" x-on:click="upgrade"> <div :class="{ 'z-40': modalOpen }" class="relative w-auto h-auto">
@if ($showProgress) <button class="menu-item" @click="modalOpen=true">
<svg xmlns="http://www.w3.org/2000/svg" @if ($showProgress)
class="w-6 h-6 text-pink-500 transition-colors hover:text-pink-300 lds-heart" viewBox="0 0 24 24" <svg xmlns="http://www.w3.org/2000/svg"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" class="w-6 h-6 text-pink-500 transition-colors hover:text-pink-300 lds-heart" viewBox="0 0 24 24"
stroke-linejoin="round"> stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> stroke-linejoin="round">
<path d="M19.5 13.572l-7.5 7.428l-7.5 -7.428m0 0a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" /> <path stroke="none" d="M0 0h24v24H0z" fill="none" />
</svg> <path d="M19.5 13.572l-7.5 7.428l-7.5 -7.428m0 0a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
In progress </svg>
@else In progress
<svg xmlns="http://www.w3.org/2000/svg" @else
class="w-6 h-6 text-pink-500 transition-colors hover:text-pink-300" viewBox="0 0 24 24" <svg xmlns="http://www.w3.org/2000/svg"
stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" class="w-6 h-6 text-pink-500 transition-colors hover:text-pink-300" viewBox="0 0 24 24"
stroke-linejoin="round"> stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round"
<path stroke="none" d="M0 0h24v24H0z" fill="none" /> stroke-linejoin="round">
<path <path stroke="none" d="M0 0h24v24H0z" fill="none" />
d="M9 12h-3.586a1 1 0 0 1 -.707 -1.707l6.586 -6.586a1 1 0 0 1 1.414 0l6.586 6.586a1 1 0 0 1 -.707 1.707h-3.586v3h-6v-3z" /> <path
<path d="M9 21h6" /> d="M9 12h-3.586a1 1 0 0 1 -.707 -1.707l6.586 -6.586a1 1 0 0 1 1.414 0l6.586 6.586a1 1 0 0 1 -.707 1.707h-3.586v3h-6v-3z" />
<path d="M9 18h6" /> <path d="M9 21h6" />
</svg> <path d="M9 18h6" />
Upgrade </svg>
@endif Upgrade
</button> @endif
</button>
<template x-teleport="body">
<div x-show="modalOpen"
class="fixed top-0 lg:pt-10 left-0 z-[99] flex items-start justify-center w-screen h-screen"
x-cloak>
<div x-show="modalOpen" x-transition:enter="ease-out duration-100"
x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-100" x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="absolute inset-0 w-full h-full bg-black bg-opacity-20 backdrop-blur-sm"></div>
<div x-show="modalOpen" x-trap.inert.noscroll="modalOpen" x-transition:enter="ease-out duration-100"
x-transition:enter-start="opacity-0 -translate-y-2 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave="ease-in duration-100"
x-transition:leave-start="opacity-100 translate-y-0 sm:scale-100"
x-transition:leave-end="opacity-0 -translate-y-2 sm:scale-95"
class="relative w-full py-6 border rounded min-w-full lg:min-w-[36rem] max-w-fit bg-neutral-100 border-neutral-400 dark:bg-base px-7 dark:border-coolgray-300">
<div class="flex items-center justify-between pb-3">
<h3 class="text-lg font-semibold">Upgrade confirmation</h3>
@if (!$showProgress)
<button @click="modalOpen=false"
class="absolute top-0 right-0 flex items-center justify-center w-8 h-8 mt-5 mr-5 text-gray-600 rounded-full hover:text-gray-800 hover:bg-gray-50">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
@endif
</div>
<div class="relative w-auto pb-8">
<p>Are you sure you would like to upgrade your instance to {{ $latestVersion }}?</p>
<br />
<p>You can review the changelogs <a class="font-bold underline"
href="https://github.com/coollabsio/coolify/releases" target="_blank">here</a>.</p>
@if ($showProgress)
<div class="flex flex-col pt-4">
<h4>Progress <x-loading /></h4>
<div x-html="currentStatus"></div>
</div>
@endif
</div>
<div class="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
@if (!$showProgress)
<x-forms.button @click="modalOpen=false"
class="w-24 dark:bg-coolgray-200 dark:hover:bg-coolgray-300">Cancel
</x-forms.button>
<x-forms.button @click="confirmed" class="w-24" isHighlighted type="button">Continue
</x-forms.button>
@endif
</div>
</div>
</div>
</template>
</div>
@endif @endif
</div> </div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('upgradeModal', () => ({
modalOpen: false,
showProgress: @js($showProgress),
currentStatus: '',
confirmed() {
this.$wire.$call('upgrade')
this.upgrade();
this.$wire.showProgress = true;
},
revive() {
if (checkHealthInterval) return true;
console.log('Checking server\'s health...')
checkHealthInterval = setInterval(() => {
fetch('/api/health')
.then(response => {
if (response.ok) {
this.currentStatus =
'Coolify is back online. Reloading this page (you can manually reload if its not done automatically)...';
if (checkHealthInterval) clearInterval(
checkHealthInterval);
setTimeout(() => {
window.location.reload();
}, 5000)
} else {
this.currentStatus =
"Waiting for Coolify to come back from dead..."
}
})
}, 2000);
},
upgrade() {
if (checkIfIamDeadInterval || this.$wire.showProgress) return true;
this.currentStatus = 'Pulling new images and updating Coolify.';
checkIfIamDeadInterval = setInterval(() => {
fetch('/api/health')
.then(response => {
if (response.ok) {
this.currentStatus = "Waiting for the update process..."
} else {
this.currentStatus =
"Update done, restarting Coolify & waiting until it is revived!"
if (checkIfIamDeadInterval) clearInterval(
checkIfIamDeadInterval);
this.revive();
}
})
}, 2000);
}
}))
})
</script>

View File

@ -32,7 +32,7 @@ services:
redis: redis:
condition: service_started condition: service_started
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -16,7 +16,7 @@ services:
volumes: volumes:
- stacks-data:/appsmith-stacks - stacks-data:/appsmith-stacks
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- babybuddy-config:/config - babybuddy-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -13,7 +13,7 @@ services:
volumes: volumes:
- budge-config:/config - budge-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -17,7 +17,7 @@ services:
depends_on: depends_on:
- mariadb - mariadb
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 10 retries: 10

View File

@ -17,7 +17,7 @@ services:
depends_on: depends_on:
- mysql - mysql
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 10 retries: 10
@ -31,7 +31,7 @@ services:
- MYSQL_USER=$SERVICE_USER_CLASSICPRESS - MYSQL_USER=$SERVICE_USER_CLASSICPRESS
- MYSQL_PASSWORD=$SERVICE_PASSWORD_CLASSICPRESS - MYSQL_PASSWORD=$SERVICE_PASSWORD_CLASSICPRESS
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -11,7 +11,7 @@ services:
environment: environment:
- SERVICE_FQDN_CLASSICPRESS - SERVICE_FQDN_CLASSICPRESS
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 10 retries: 10

View File

@ -18,7 +18,7 @@ services:
volumes: volumes:
- code-server-config:/config - code-server-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8443"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8443"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -11,7 +11,7 @@ services:
volumes: volumes:
- dashboard-data:/app/data - dashboard-data:/app/data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -26,7 +26,7 @@ services:
- REDIS_PORT=6379 - REDIS_PORT=6379
- WEBSOCKETS_ENABLED=true - WEBSOCKETS_ENABLED=true
healthcheck: healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8055/admin/login"] test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8055/admin/login"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -22,7 +22,7 @@ services:
- WEBSOCKETS_ENABLED=true - WEBSOCKETS_ENABLED=true
healthcheck: healthcheck:
test: test:
["CMD", "wget", "-q", "--spider", "http://localhost:8055/admin/login"] ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8055/admin/login"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -14,7 +14,7 @@ services:
volumes: volumes:
- dokuwiki-config:/config - dokuwiki-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -16,7 +16,7 @@ services:
- duplicati-config:/config - duplicati-config:/config
- duplicati-backups:/backups - duplicati-backups:/backups
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8200"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8200"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -17,7 +17,7 @@ services:
- emby-tvshows:/tvshows - emby-tvshows:/tvshows
- emby-movies:/movies - emby-movies:/movies
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8096"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -14,7 +14,7 @@ services:
volumes: volumes:
- embystat-config:/config - embystat-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:6555"] test: ["CMD", "curl", "-f", "http://127.0.0.1:6555"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -20,7 +20,7 @@ services:
read_only: true read_only: true
content: "{}" content: "{}"
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -21,7 +21,7 @@ services:
volumes: volumes:
- firefly-upload:/var/www/html/storage/upload - firefly-upload:/var/www/html/storage/upload
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10
@ -42,7 +42,7 @@ services:
"mysqladmin", "mysqladmin",
"ping", "ping",
"-h", "-h",
"localhost", "127.0.0.1",
"-uroot", "-uroot",
"-p${SERVICE_PASSWORD_MYSQLROOT}", "-p${SERVICE_PASSWORD_MYSQLROOT}",
] ]

View File

@ -42,7 +42,7 @@ services:
postgresql: postgresql:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -41,7 +41,7 @@ services:
- MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT} - MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -25,7 +25,7 @@ services:
mariadb: mariadb:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -25,7 +25,7 @@ services:
mysql: mysql:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15
@ -40,7 +40,7 @@ services:
- MYSQL_DATABASE=${MYSQL_DATABASE} - MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT} - MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -25,7 +25,7 @@ services:
postgresql: postgresql:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -17,7 +17,7 @@ services:
- gitea-timezone:/etc/timezone:ro - gitea-timezone:/etc/timezone:ro
- gitea-localtime:/etc/localtime:ro - gitea-localtime:/etc/localtime:ro
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -20,7 +20,7 @@ services:
volumes: volumes:
- grafana-data:/var/lib/grafana - grafana-data:/var/lib/grafana
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/api/health"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- grafana-data:/var/lib/grafana - grafana-data:/var/lib/grafana
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/api/health"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -14,7 +14,7 @@ services:
volumes: volumes:
- grocy-config:/config - grocy-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -13,7 +13,7 @@ services:
volumes: volumes:
- heimdall-config:/config - heimdall-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -23,7 +23,7 @@ services:
- DB_USERNAME=${SERVICE_USER_MYSQL} - DB_USERNAME=${SERVICE_USER_MYSQL}
- DB_PASSWORD=${SERVICE_PASSWORD_MYSQL} - DB_PASSWORD=${SERVICE_PASSWORD_MYSQL}
healthcheck: healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9000'] test: ['CMD', 'curl', '-f', 'http://127.0.0.1:9000']
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10
@ -94,7 +94,7 @@ services:
"mysqladmin", "mysqladmin",
"ping", "ping",
"-h", "-h",
"localhost", "127.0.0.1",
"-uroot", "-uroot",
"-p${SERVICE_PASSWORD_MYSQLROOT}", "-p${SERVICE_PASSWORD_MYSQLROOT}",
] ]

View File

@ -18,7 +18,7 @@ services:
- jellyfin-tvshows:/data/tvshows - jellyfin-tvshows:/data/tvshows
- jellyfin-movies:/data/movies - jellyfin-movies:/data/movies
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8096"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8096"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -18,7 +18,7 @@ services:
elasticsearch: elasticsearch:
image: kuzzleio/elasticsearch:7 image: kuzzleio/elasticsearch:7
healthcheck: healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:9200" ] test: [ "CMD", "curl", "-f", "http://127.0.0.1:9200" ]
interval: 2s interval: 2s
timeout: 2s timeout: 2s
retries: 10 retries: 10
@ -51,7 +51,7 @@ services:
sysctls: sysctls:
- net.core.somaxconn=8192 - net.core.somaxconn=8192
healthcheck: healthcheck:
test: [ "CMD", "curl", "-f", "http://localhost:7512/_healthcheck" ] test: [ "CMD", "curl", "-f", "http://127.0.0.1:7512/_healthcheck" ]
timeout: 1s timeout: 1s
interval: 2s interval: 2s
retries: 30 retries: 30

View File

@ -18,7 +18,7 @@ services:
- ENDPOINT=$LOGTO_ENDPOINT - ENDPOINT=$LOGTO_ENDPOINT
- ADMIN_ENDPOINT=$LOGTO_ADMIN_ENDPOINT - ADMIN_ENDPOINT=$LOGTO_ADMIN_ENDPOINT
healthcheck: healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3002"] test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3002"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- meilisearch-data:/meili_data - meilisearch-data:/meili_data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7700/health"] test: ["CMD", "curl", "-f", "http://127.0.0.1:7700/health"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -18,7 +18,7 @@ services:
- MB_DB_USER=$SERVICE_USER_POSTGRESQL - MB_DB_USER=$SERVICE_USER_POSTGRESQL
- MB_DB_PASS=$SERVICE_PASSWORD_POSTGRESQL - MB_DB_PASS=$SERVICE_PASSWORD_POSTGRESQL
healthcheck: healthcheck:
test: curl --fail -I http://localhost:3000/api/health || exit 1 test: curl --fail -I http://127.0.0.1:3000/api/health || exit 1
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -13,7 +13,7 @@ services:
volumes: volumes:
- metube-downloads:/downloads - metube-downloads:/downloads
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8081"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- minio-data:/data - minio-data:/data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -27,7 +27,7 @@ services:
postgresql: postgresql:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:5678/"] test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -17,7 +17,7 @@ services:
volumes: volumes:
- n8n-data:/home/node/.n8n - n8n-data:/home/node/.n8n
healthcheck: healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:5678/"] test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:5678/"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -12,7 +12,7 @@ services:
- ALLOWED_REMOTE_DOMAINS=${ALLOWED_REMOTE_DOMAINS:-*} - ALLOWED_REMOTE_DOMAINS=${ALLOWED_REMOTE_DOMAINS:-*}
- IMGPROXY_URL=${IMGPROXY_URL:-http://imgproxy:8080} - IMGPROXY_URL=${IMGPROXY_URL:-http://imgproxy:8080}
healthcheck: healthcheck:
test: "wget -qO- http://localhost:3000/health || exit 1" test: "wget -qO- http://127.0.0.1:3000/health || exit 1"
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 5 retries: 5

View File

@ -15,7 +15,7 @@ services:
- nextcloud-config:/config - nextcloud-config:/config
- nextcloud-data:/data - nextcloud-data:/data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -12,7 +12,7 @@ services:
volumes: volumes:
- nocodb-data:/usr/app/data/ - nocodb-data:/usr/app/data/
healthcheck: healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080"] test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- odoo-web-data:/var/lib/odoo - odoo-web-data:/var/lib/odoo
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8069"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8069"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 30 retries: 30

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- openblocks-data:/openblocks-stacks - openblocks-data:/openblocks-stacks
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/health"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -13,7 +13,7 @@ services:
- TZ=Europe/Madrid - TZ=Europe/Madrid
- DEBUG_MODE=false - DEBUG_MODE=false
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -14,7 +14,7 @@ services:
- SERVICE_FQDN_FRONTEND - SERVICE_FQDN_FRONTEND
- PENPOT_FLAGS=${PENPOT_FRONTEND_FLAGS:-enable-login-with-password} - PENPOT_FLAGS=${PENPOT_FRONTEND_FLAGS:-enable-login-with-password}
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15
@ -48,7 +48,7 @@ services:
- PENPOT_SMTP_TLS=${PENPOT_SMTP_TLS:-false} - PENPOT_SMTP_TLS=${PENPOT_SMTP_TLS:-false}
- PENPOT_SMTP_SSL=${PENPOT_SMTP_SSL:-false} - PENPOT_SMTP_SSL=${PENPOT_SMTP_SSL:-false}
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:6060"] test: ["CMD", "curl", "-f", "http://127.0.0.1:6060"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -16,7 +16,7 @@ services:
volumes: volumes:
- phpmyadmin-config:/config - phpmyadmin-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -51,7 +51,7 @@ services:
volumes: volumes:
- minio-data:/data - minio-data:/data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] test: ["CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -14,7 +14,7 @@ services:
volumes: volumes:
- shlink-data:/etc/shlink/data - shlink-data:/etc/shlink/data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/rest/v3/health"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8080/rest/v3/health"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15
@ -25,7 +25,7 @@ services:
- SHLINK_SERVER_API_KEY=${SERVICE_BASE64_SHLINKAPIKEY} - SHLINK_SERVER_API_KEY=${SERVICE_BASE64_SHLINKAPIKEY}
- SHLINK_SERVER_URL=${SERVICE_FQDN_SHLINK} - SHLINK_SERVER_URL=${SERVICE_FQDN_SHLINK}
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -11,7 +11,7 @@ services:
volumes: volumes:
- slash-data:/var/opt/slash - slash-data:/var/opt/slash
healthcheck: healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:5231"] test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:5231"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -13,7 +13,7 @@ services:
volumes: volumes:
- snapdrop-config:/config - snapdrop-config:/config
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -16,7 +16,7 @@ services:
- SERVICE_FQDN_SPDF_8080 - SERVICE_FQDN_SPDF_8080
- DOCKER_ENABLE_SECURITY=false - DOCKER_ENABLE_SECURITY=false
healthcheck: healthcheck:
test: 'curl --fail -I http://localhost:8080 || exit 1' test: 'curl --fail -I http://127.0.0.1:8080 || exit 1'
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -285,7 +285,7 @@ services:
"CMD", "CMD",
"node", "node",
"-e", "-e",
"require('http').get('http://localhost:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})", "require('http').get('http://127.0.0.1:3000/api/profile', (r) => {if (r.statusCode !== 200) throw new Error(r.statusCode)})",
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
@ -316,7 +316,7 @@ services:
supabase-db: supabase-db:
image: supabase/postgres:15.1.1.41 image: supabase/postgres:15.1.1.41
healthcheck: healthcheck:
test: pg_isready -U postgres -h localhost test: pg_isready -U postgres -h 127.0.0.1
interval: 5s interval: 5s
timeout: 5s timeout: 5s
retries: 10 retries: 10
@ -599,7 +599,7 @@ services:
supabase-analytics: supabase-analytics:
image: supabase/logflare:1.4.0 image: supabase/logflare:1.4.0
healthcheck: healthcheck:
test: ["CMD", "curl", "http://localhost:4000/health"] test: ["CMD", "curl", "http://127.0.0.1:4000/health"]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 10 retries: 10
@ -927,7 +927,7 @@ services:
"--no-verbose", "--no-verbose",
"--tries=1", "--tries=1",
"--spider", "--spider",
"http://localhost:9999/health", "http://127.0.0.1:9999/health",
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
@ -1001,7 +1001,7 @@ services:
supabase-analytics: supabase-analytics:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "bash", "-c", "printf \\0 > /dev/tcp/localhost/4000"] test: ["CMD", "bash", "-c", "printf \\0 > /dev/tcp/127.0.0.1/4000"]
timeout: 5s timeout: 5s
interval: 5s interval: 5s
retries: 3 retries: 3
@ -1075,7 +1075,7 @@ services:
"--no-verbose", "--no-verbose",
"--tries=1", "--tries=1",
"--spider", "--spider",
"http://localhost:5000/status", "http://127.0.0.1:5000/status",
] ]
timeout: 5s timeout: 5s
interval: 5s interval: 5s

View File

@ -20,7 +20,7 @@ services:
volumes: volumes:
- tolgee-data:/data - tolgee-data:/data
healthcheck: healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080"] test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -43,7 +43,7 @@ services:
postgres: postgres:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/healthz"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/healthz"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -16,7 +16,7 @@ services:
postgresql: postgresql:
condition: service_healthy condition: service_healthy
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/heartbeat"] test: ["CMD", "curl", "-f", "http://127.0.0.1:3000/api/heartbeat"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -23,7 +23,7 @@ services:
- node - node
- index.js - index.js
healthcheck: healthcheck:
test: "wget --no-verbose --tries=1 --spider http://localhost:4242/health || exit 1" test: "wget --no-verbose --tries=1 --spider http://127.0.0.1:4242/health || exit 1"
interval: 1s interval: 1s
timeout: 1m timeout: 1m
retries: 5 retries: 5

View File

@ -20,7 +20,7 @@ services:
- node - node
- index.js - index.js
healthcheck: healthcheck:
test: 'wget --no-verbose --tries=1 --spider http://localhost:4242/health || exit 1' test: 'wget --no-verbose --tries=1 --spider http://127.0.0.1:4242/health || exit 1'
interval: 1s interval: 1s
timeout: 1m timeout: 1m
retries: 5 retries: 5

View File

@ -11,7 +11,7 @@ services:
volumes: volumes:
- vaultwarden-data:/data - vaultwarden-data:/data
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"] test: ["CMD", "curl", "-f", "http://127.0.0.1:80"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -15,7 +15,7 @@ services:
volumes: volumes:
- vikunja-data:/app/vikunja/ - vikunja-data:/app/vikunja/
healthcheck: healthcheck:
test: ["CMD", "wget", "--spider", "http://localhost:3456"] test: ["CMD", "wget", "--spider", "http://127.0.0.1:3456"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -26,7 +26,7 @@ services:
- weblate-data:/app/data - weblate-data:/app/data
- weblate-cache:/app/cache - weblate-cache:/app/cache
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"] test: ["CMD", "curl", "-f", "http://127.0.0.1:8080"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 30 retries: 30

View File

@ -9,7 +9,7 @@ services:
environment: environment:
- SERVICE_FQDN_WHOOGLE_5000 - SERVICE_FQDN_WHOOGLE_5000
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000"] test: ["CMD", "curl", "-f", "http://127.0.0.1:5000"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 15 retries: 15

View File

@ -17,7 +17,7 @@ services:
depends_on: depends_on:
- mariadb - mariadb
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 10 retries: 10

View File

@ -17,7 +17,7 @@ services:
depends_on: depends_on:
- mysql - mysql
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 10 retries: 10
@ -31,7 +31,7 @@ services:
- MYSQL_USER=$SERVICE_USER_WORDPRESS - MYSQL_USER=$SERVICE_USER_WORDPRESS
- MYSQL_PASSWORD=$SERVICE_PASSWORD_WORDPRESS - MYSQL_PASSWORD=$SERVICE_PASSWORD_WORDPRESS
healthcheck: healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
interval: 5s interval: 5s
timeout: 20s timeout: 20s
retries: 10 retries: 10

View File

@ -11,7 +11,7 @@ services:
environment: environment:
- SERVICE_FQDN_WORDPRESS - SERVICE_FQDN_WORDPRESS
healthcheck: healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] test: ["CMD", "curl", "-f", "http://127.0.0.1"]
interval: 2s interval: 2s
timeout: 10s timeout: 10s
retries: 10 retries: 10

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{ {
"coolify": { "coolify": {
"v4": { "v4": {
"version": "4.0.0-beta.280" "version": "4.0.0-beta.281"
}, },
"sentinel": { "sentinel": {
"version": "0.0.4" "version": "0.0.4"