Merge branch 'v4-next' into notifications

This commit is contained in:
Andras Bacsai
2023-06-01 08:22:07 +02:00
204 changed files with 5744 additions and 2545 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Models\ApplicationDeploymentQueue;
use Illuminate\Http\Request;
use Spatie\Activitylog\Models\Activity;
@@ -21,7 +22,7 @@ class ApplicationController extends Controller
if (!$application) {
return redirect()->route('dashboard');
}
return view('project.application.configuration', ['application' => $application,]);
return view('project.application.configuration', ['application' => $application]);
}
public function deployments()
{
@@ -37,7 +38,7 @@ class ApplicationController extends Controller
if (!$application) {
return redirect()->route('dashboard');
}
return view('project.application.deployments', ['application' => $application, 'deployments' => $application->deployments()]);
return view('project.application.deployments', ['application' => $application]);
}
public function deployment()
@@ -64,9 +65,18 @@ class ApplicationController extends Controller
'application_uuid' => $application->uuid,
]);
}
$deployment = ApplicationDeploymentQueue::where('deployment_uuid', $deployment_uuid)->first();
if (!$deployment) {
return redirect()->route('project.application.deployments', [
'project_uuid' => $project->uuid,
'environment_name' => $environment->name,
'application_uuid' => $application->uuid,
]);
}
return view('project.application.deployment', [
'application' => $application,
'activity' => $activity,
'deployment' => $deployment,
'deployment_uuid' => $deployment_uuid,
]);
}

View File

@@ -2,13 +2,24 @@
namespace App\Http\Controllers;
use Spatie\Activitylog\Models\Activity;
use App\Models\Project;
class ProjectController extends Controller
{
public function environments()
public function all()
{
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
$team_id = session('currentTeam')->id;
$projects = Project::where('team_id', $team_id)->get();
return view('projects', ['projects' => $projects]);
}
public function show()
{
$project_uuid = request()->route('project_uuid');
$team_id = session('currentTeam')->id;
$project = Project::where('team_id', $team_id)->where('uuid', $project_uuid)->first();
if (!$project) {
return redirect()->route('dashboard');
}
@@ -16,7 +27,7 @@ class ProjectController extends Controller
if (count($project->environments) == 1) {
return redirect()->route('project.resources', ['project_uuid' => $project->uuid, 'environment_name' => $project->environments->first()->name]);
}
return view('project.environments', ['project' => $project]);
return view('project.show', ['project' => $project]);
}
public function new()

View File

@@ -13,7 +13,7 @@ class CheckUpdate extends Component
public function checkUpdate()
{
$this->latestVersion = getLatestVersionOfCoolify();
$this->latestVersion = get_latest_version_of_coolify();
$this->currentVersion = config('version');
if ($this->latestVersion === 'latest') {
$this->updateAvailable = true;

View File

@@ -25,13 +25,13 @@ class Form extends Component
if ($this->destination->attachedTo()) {
return $this->emit('error', 'You must delete all resources before deleting this destination.');
}
instantRemoteProcess(["docker network disconnect {$this->destination->network} coolify-proxy"], $this->destination->server, throwError: false);
instantRemoteProcess(['docker network rm -f ' . $this->destination->network], $this->destination->server);
instant_remote_process(["docker network disconnect {$this->destination->network} coolify-proxy"], $this->destination->server, throwError: false);
instant_remote_process(['docker network rm -f ' . $this->destination->network], $this->destination->server);
}
$this->destination->delete();
return redirect()->route('dashboard');
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
}

View File

@@ -33,7 +33,7 @@ class StandaloneDocker extends Component
}
}
$this->network = new Cuid2(7);
$this->name = generateRandomName();
$this->name = generate_random_name();
}
public function submit()
@@ -45,8 +45,8 @@ class StandaloneDocker extends Component
return;
}
$server = Server::find($this->server_id);
instantRemoteProcess(['docker network create --attachable ' . $this->network], $server, throwError: false);
instantRemoteProcess(["docker network connect $this->network coolify-proxy"], $server, throwError: false);
instant_remote_process(['docker network create --attachable ' . $this->network], $server, throwError: false);
instant_remote_process(["docker network connect $this->network coolify-proxy"], $server, throwError: false);
$docker = ModelsStandaloneDocker::create([
'name' => $this->name,

View File

@@ -2,51 +2,19 @@
namespace App\Http\Livewire;
use App\Enums\ActivityTypes;
use App\Models\Server;
use App\Jobs\InstanceAutoUpdateJob;
use Livewire\Component;
class ForceUpgrade extends Component
{
public bool $visible = false;
public function upgrade()
{
if (config('app.env') === 'local') {
$server = Server::where('ip', 'coolify-testing-host')->first();
if (!$server) {
return;
}
instantRemoteProcess([
"sleep 2"
], $server);
remoteProcess([
"sleep 10"
], $server, ActivityTypes::INLINE->value);
$this->emit('updateInitiated');
} else {
$latestVersion = getLatestVersionOfCoolify();
$cdn = "https://coolify-cdn.b-cdn.net/files";
$server = Server::where('ip', 'host.docker.internal')->first();
if (!$server) {
return;
}
instantRemoteProcess([
"curl -fsSL $cdn/docker-compose.yml -o /data/coolify/source/docker-compose.yml",
"curl -fsSL $cdn/docker-compose.prod.yml -o /data/coolify/source/docker-compose.prod.yml",
"curl -fsSL $cdn/.env.production -o /data/coolify/source/.env.production",
"curl -fsSL $cdn/upgrade.sh -o /data/coolify/source/upgrade.sh",
], $server);
instantRemoteProcess([
"docker compose -f /data/coolify/source/docker-compose.yml -f /data/coolify/source/docker-compose.prod.yml pull",
], $server);
remoteProcess([
"bash /data/coolify/source/upgrade.sh $latestVersion"
], $server, ActivityTypes::INLINE->value);
$this->emit('updateInitiated');
try {
$this->visible = true;
dispatch(new InstanceAutoUpdateJob(force: true));
} catch (\Exception $e) {
return general_error_handler($e, $this);
}
}
}

View File

@@ -35,7 +35,7 @@ class Change extends Component
$this->private_key->save();
session('currentTeam')->privateKeys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Livewire\Profile;
use App\Models\User;
use Livewire\Component;
class Form extends Component
{
public int $userId;
public string $name;
public string $email;
protected $rules = [
'name' => 'required',
];
public function mount()
{
$this->userId = auth()->user()->id;
$this->name = auth()->user()->name;
$this->email = auth()->user()->email;
}
public function submit()
{
try {
$this->validate();
User::where('id', $this->userId)->update([
'name' => $this->name,
]);
} catch (\Throwable $error) {
return general_error_handler($error, $this);
}
}
}

View File

@@ -2,8 +2,27 @@
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Livewire\Component;
class Danger extends Component
{
public Application $application;
public array $parameters;
public function mount()
{
$this->parameters = get_parameters();
}
public function delete()
{
$destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
instant_remote_process(["docker rm -f {$this->application->uuid}"], $destination->server);
$this->application->delete();
return redirect()->route('project.resources', [
'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->parameters['environment_name']
]);
}
}

View File

@@ -2,9 +2,8 @@
namespace App\Http\Livewire\Project\Application;
use App\Jobs\DeployApplicationJob;
use App\Jobs\ContainerStopJob;
use App\Models\Application;
use Illuminate\Support\Facades\Route;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
@@ -21,67 +20,47 @@ class Deploy extends Component
protected array $command = [];
protected $source;
protected $listeners = [
'applicationStatusChanged' => 'applicationStatusChanged',
];
public function mount()
{
$this->parameters = getParameters();
$this->parameters = get_parameters();
$this->application = Application::where('id', $this->applicationId)->first();
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
}
protected function setDeploymentUuid()
public function applicationStatusChanged()
{
$this->application->refresh();
}
protected function set_deployment_uuid()
{
// Create Deployment ID
$this->deployment_uuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
}
protected function redirectToDeployment()
public function deploy(bool $force = false)
{
return redirect()->route('project.application.deployment', $this->parameters);
}
public function start()
{
$this->setDeploymentUuid();
$this->set_deployment_uuid();
dispatch(new DeployApplicationJob(
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deployment_uuid,
application_uuid: $this->application->uuid,
force_rebuild: false,
));
return $this->redirectToDeployment();
}
public function forceRebuild()
{
$this->setDeploymentUuid();
dispatch(new DeployApplicationJob(
deployment_uuid: $this->deployment_uuid,
application_uuid: $this->application->uuid,
force_rebuild: true,
));
return $this->redirectToDeployment();
}
public function delete()
{
$this->stop();
Application::find($this->applicationId)->delete();
return redirect()->route('project.resources', [
force_rebuild: $force,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'environment_name' => $this->parameters['environment_name']
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deployment_uuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
public function stop()
{
instantRemoteProcess(["docker rm -f {$this->application->uuid}"], $this->destination->server);
if ($this->application->status != 'exited') {
$this->application->status = 'exited';
$this->application->save();
}
}
public function pollingStatus()
{
$this->application->refresh();
instant_remote_process(["docker rm -f {$this->application->uuid}"], $this->application->destination->server);
$this->application->status = get_container_status(server: $this->application->destination->server, container_id: $this->application->uuid);
$this->application->save();
}
}

View File

@@ -3,18 +3,21 @@
namespace App\Http\Livewire\Project\Application;
use App\Enums\ActivityTypes;
use App\Models\Application;
use Illuminate\Support\Facades\Redis;
use Livewire\Component;
use Spatie\Activitylog\Models\Activity;
class PollDeployment extends Component
class DeploymentLogs extends Component
{
public Application $application;
public $activity;
public $isKeepAliveOn = true;
public $deployment_uuid;
public function polling()
{
if ( is_null($this->activity) && isset($this->deployment_uuid)) {
$this->emit('deploymentFinished');
if (is_null($this->activity) && isset($this->deployment_uuid)) {
$this->activity = Activity::query()
->where('properties->type', '=', ActivityTypes::DEPLOYMENT->value)
->where('properties->type_uuid', '=', $this->deployment_uuid)
@@ -23,7 +26,7 @@ class PollDeployment extends Component
$this->activity?->refresh();
}
if (data_get($this->activity, 'properties.status') == 'finished' || data_get($this->activity, 'properties.status') == 'failed' ) {
if (data_get($this->activity, 'properties.status') == 'finished' || data_get($this->activity, 'properties.status') == 'failed') {
$this->isKeepAliveOn = false;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Enums\ProcessStatus;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use Livewire\Component;
class DeploymentNavbar extends Component
{
public Application $application;
public $activity;
public string $deployment_uuid;
protected $listeners = ['deploymentFinished'];
public function deploymentFinished()
{
$this->activity->refresh();
}
public function cancel()
{
try {
ray('Cancelling deployment: ' . $this->deployment_uuid . ' of application: ' . $this->application->uuid);
// Update deployment queue
$deployment = ApplicationDeploymentQueue::where('deployment_uuid', $this->deployment_uuid)->first();
$deployment->status = 'cancelled by user';
$deployment->save();
// Update activity
$this->activity->properties = $this->activity->properties->merge([
'exitCode' => 1,
'status' => ProcessStatus::CANCELLED->value,
]);
$this->activity->save();
// Remove builder container
instant_remote_process(["docker rm -f {$this->deployment_uuid}"], $this->application->destination->server, throwError: false, repeat: 25);
queue_next_deployment($this->application);
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Livewire\Component;
class Deployments extends Component
{
public int $application_id;
public $deployments = [];
public int $deployments_count = 0;
public string $current_url;
public int $skip = 0;
public int $default_take = 8;
public bool $show_next = true;
public function mount()
{
$this->current_url = url()->current();
}
public function reload_deployments()
{
$this->load_deployments();
}
public function load_deployments(int|null $take = null)
{
if ($take) {
$this->skip = $this->skip + $take;
}
$take = $this->default_take;
['deployments' => $deployments, 'count' => $count] = Application::find($this->application_id)->deployments($this->skip, $take);
$this->deployments = $deployments;
$this->deployments_count = $count;
if (count($this->deployments) !== 0 && count($this->deployments) < $take) {
$this->show_next = false;
return;
}
}
}

View File

@@ -23,7 +23,7 @@ class Add extends Component
];
public function mount()
{
$this->parameters = getParameters();
$this->parameters = get_parameters();
}
public function submit()
{

View File

@@ -26,7 +26,7 @@ class All extends Component
$this->application->refresh();
$this->emit('clearAddEnv');
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -17,7 +17,7 @@ class Show extends Component
];
public function mount()
{
$this->parameters = getParameters();
$this->parameters = get_parameters();
}
public function submit()
{

View File

@@ -3,8 +3,10 @@
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use App\Models\InstanceSettings;
use Livewire\Component;
use Illuminate\Support\Str;
use Spatie\Url\Url;
class General extends Component
{
@@ -17,16 +19,17 @@ class General extends Component
public string $git_branch;
public string|null $git_commit_sha;
public string $build_pack;
public string|null $wildcard_domain = null;
public string|null $project_wildcard_domain = null;
public string|null $global_wildcard_domain = null;
public bool $is_static;
public bool $is_git_submodules_allowed;
public bool $is_git_lfs_allowed;
public bool $is_debug;
public bool $is_previews;
public bool $is_custom_ssl;
public bool $is_http2;
public bool $is_auto_deploy;
public bool $is_dual_cert;
public bool $is_git_submodules_enabled;
public bool $is_git_lfs_enabled;
public bool $is_debug_enabled;
public bool $is_preview_deployments_enabled;
public bool $is_auto_deploy_enabled;
public bool $is_force_https_enabled;
protected $rules = [
'application.name' => 'required|min:6',
@@ -48,41 +51,68 @@ class General extends Component
{
// @TODO: find another way - if possible
$this->application->settings->is_static = $this->is_static;
$this->application->settings->is_git_submodules_allowed = $this->is_git_submodules_allowed;
$this->application->settings->is_git_lfs_allowed = $this->is_git_lfs_allowed;
$this->application->settings->is_debug = $this->is_debug;
$this->application->settings->is_previews = $this->is_previews;
$this->application->settings->is_custom_ssl = $this->is_custom_ssl;
$this->application->settings->is_http2 = $this->is_http2;
$this->application->settings->is_auto_deploy = $this->is_auto_deploy;
$this->application->settings->is_dual_cert = $this->is_dual_cert;
$this->application->settings->is_git_submodules_enabled = $this->is_git_submodules_enabled;
$this->application->settings->is_git_lfs_enabled = $this->is_git_lfs_enabled;
$this->application->settings->is_debug_enabled = $this->is_debug_enabled;
$this->application->settings->is_preview_deployments_enabled = $this->is_preview_deployments_enabled;
$this->application->settings->is_auto_deploy_enabled = $this->is_auto_deploy_enabled;
$this->application->settings->is_force_https_enabled = $this->is_force_https_enabled;
$this->application->settings->save();
$this->application->refresh();
$this->emit('saved', 'Application settings updated!');
$this->checkWildCardDomain();
}
protected function checkWildCardDomain()
{
$coolify_instance_settings = InstanceSettings::get();
$this->project_wildcard_domain = data_get($this->application, 'environment.project.settings.wildcard_domain');
$this->global_wildcard_domain = data_get($coolify_instance_settings, 'wildcard_domain');
$this->wildcard_domain = $this->project_wildcard_domain ?? $this->global_wildcard_domain ?? null;
}
public function mount()
{
$this->is_static = $this->application->settings->is_static;
$this->is_git_submodules_allowed = $this->application->settings->is_git_submodules_allowed;
$this->is_git_lfs_allowed = $this->application->settings->is_git_lfs_allowed;
$this->is_debug = $this->application->settings->is_debug;
$this->is_previews = $this->application->settings->is_previews;
$this->is_custom_ssl = $this->application->settings->is_custom_ssl;
$this->is_http2 = $this->application->settings->is_http2;
$this->is_auto_deploy = $this->application->settings->is_auto_deploy;
$this->is_dual_cert = $this->application->settings->is_dual_cert;
$this->is_git_submodules_enabled = $this->application->settings->is_git_submodules_enabled;
$this->is_git_lfs_enabled = $this->application->settings->is_git_lfs_enabled;
$this->is_debug_enabled = $this->application->settings->is_debug_enabled;
$this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_enabled;
$this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled;
$this->is_force_https_enabled = $this->application->settings->is_force_https_enabled;
$this->checkWildCardDomain();
}
public function generateGlobalRandomDomain()
{
// Set wildcard domain based on Global wildcard domain
$url = Url::fromString($this->global_wildcard_domain);
$host = $url->getHost();
$path = $url->getPath() === '/' ? '' : $url->getPath();
$scheme = $url->getScheme();
$this->application->fqdn = $scheme . '://' . $this->application->uuid . '.' . $host . $path;
$this->application->save();
}
public function generateProjectRandomDomain()
{
// Set wildcard domain based on Project wildcard domain
$url = Url::fromString($this->project_wildcard_domain);
$host = $url->getHost();
$path = $url->getPath() === '/' ? '' : $url->getPath();
$scheme = $url->getScheme();
$this->application->fqdn = $scheme . '://' . $this->application->uuid . '.' . $host . $path;
$this->application->save();
}
public function submit()
{
try {
$this->validate();
$domains = Str::of($this->application->fqdn)->trim()->explode(',')->map(function ($domain) {
return Str::of($domain)->trim()->lower();
});
$this->application->fqdn = $domains->implode(',');
$this->application->save();
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Http\Livewire\Project\Application;
use Livewire\Component;
use Spatie\Activitylog\Models\Activity;
class GetDeployments extends Component
{
public string $deployment_uuid;
public string $created_at;
public string $status;
public function polling()
{
$activity = Activity::where('properties->type_uuid', '=', $this->deployment_uuid)->first();
$this->created_at = $activity->created_at;
$this->status = data_get($activity, 'properties.status');
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Http\Livewire\Project\Application\Preview;
use App\Models\Application;
use Illuminate\Support\Str;
use Livewire\Component;
use Spatie\Url\Url;
class Form extends Component
{
public Application $application;
public string $preview_url_template;
protected $rules = [
'application.preview_url_template' => 'required',
];
public function resetToDefault()
{
$this->application->preview_url_template = '{{pr_id}}.{{domain}}';
$this->preview_url_template = $this->application->preview_url_template;
$this->application->save();
$this->generate_real_url();
}
public function generate_real_url()
{
if (data_get($this->application, 'fqdn')) {
$url = Url::fromString($this->application->fqdn);
$host = $url->getHost();
$this->preview_url_template = Str::of($this->application->preview_url_template)->replace('{{domain}}', $host);
}
}
public function mount()
{
$this->generate_real_url();
}
public function submit()
{
$this->validate();
$this->application->preview_url_template = str_replace(' ', '', $this->application->preview_url_template);
$this->application->save();
$this->generate_real_url();
}
}

View File

@@ -2,10 +2,84 @@
namespace App\Http\Livewire\Project\Application;
use App\Jobs\ContainerStatusJob;
use App\Models\Application;
use App\Models\ApplicationPreview;
use Illuminate\Support\Collection;
use Livewire\Component;
use Visus\Cuid2\Cuid2;
class Previews extends Component
{
public Application $application;
public string $deployment_uuid;
public array $parameters;
public Collection $pull_requests;
public int $rate_limit_remaining;
public function mount()
{
$this->pull_requests = collect();
$this->parameters = get_parameters();
}
public function loadStatus($pull_request_id)
{
dispatch(new ContainerStatusJob(
application: $this->application,
container_name: generate_container_name($this->application->uuid, $pull_request_id),
pull_request_id: $pull_request_id
));
}
protected function set_deployment_uuid()
{
$this->deployment_uuid = new Cuid2(7);
$this->parameters['deployment_uuid'] = $this->deployment_uuid;
}
public function load_prs()
{
['rate_limit_remaining' => $rate_limit_remaining, 'data' => $data] = get_from_git_api($this->application->source, "/repos/{$this->application->git_repository}/pulls");
$this->rate_limit_remaining = $rate_limit_remaining;
$this->pull_requests = $data->sortBy('number')->values();
}
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
{
try {
$this->set_deployment_uuid();
$found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
if (!$found && !is_null($pull_request_html_url)) {
ApplicationPreview::create([
'application_id' => $this->application->id,
'pull_request_id' => $pull_request_id,
'pull_request_html_url' => $pull_request_html_url
]);
}
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $this->deployment_uuid,
force_rebuild: true,
pull_request_id: $pull_request_id,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $this->deployment_uuid,
'environment_name' => $this->parameters['environment_name'],
]);
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
public function stop(int $pull_request_id)
{
try {
$container_name = generate_container_name($this->application->uuid, $pull_request_id);
ray('Stopping container: ' . $container_name);
instant_remote_process(["docker rm -f $container_name"], $this->application->destination->server, throwError: false);
ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->delete();
$this->application->refresh();
} catch (\Throwable $th) {
return general_error_handler($th, $this);
}
}
}

View File

@@ -13,7 +13,6 @@ class ResourceLimits extends Component
'application.limits_memory_swap' => 'required|string',
'application.limits_memory_swappiness' => 'required|integer|min:0|max:100',
'application.limits_memory_reservation' => 'required|string',
'application.limits_memory_oom_kill' => 'boolean',
'application.limits_cpus' => 'nullable',
'application.limits_cpuset' => 'nullable',
'application.limits_cpu_shares' => 'nullable',
@@ -45,7 +44,7 @@ class ResourceLimits extends Component
$this->validate();
$this->application->save();
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -5,27 +5,48 @@ namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Livewire\Component;
use Illuminate\Support\Str;
use Visus\Cuid2\Cuid2;
class Rollback extends Component
{
public Application $application;
public $images = [];
public string|null $current;
public function revertImage($tag)
public array $parameters;
public function mount()
{
dd("Reverting to {$this->application->uuid}:{$tag}");
$this->parameters = get_parameters();
}
public function rollbackImage($commit)
{
$deployment_uuid = new Cuid2(7);
queue_application_deployment(
application_id: $this->application->id,
deployment_uuid: $deployment_uuid,
commit: $commit,
force_rebuild: false,
);
return redirect()->route('project.application.deployment', [
'project_uuid' => $this->parameters['project_uuid'],
'application_uuid' => $this->parameters['application_uuid'],
'deployment_uuid' => $deployment_uuid,
'environment_name' => $this->parameters['environment_name'],
]);
}
public function loadImages()
{
try {
$image = $this->application->uuid;
$output = instantRemoteProcess([
$output = instant_remote_process([
"docker inspect --format='{{.Config.Image}}' {$this->application->uuid}",
], $this->application->destination->server, throwError: false);
$current_tag = Str::of($output)->trim()->explode(":");
$this->current = data_get($current_tag, 1);
$output = instantRemoteProcess([
$output = instant_remote_process([
"docker images --format '{{.Repository}}#{{.Tag}}#{{.CreatedAt}}'",
], $this->application->destination->server);
$this->images = Str::of($output)->trim()->explode("\n")->filter(function ($item) use ($image) {
@@ -33,7 +54,7 @@ class Rollback extends Component
})->map(function ($item) {
$item = Str::of($item)->explode('#');
if ($item[1] === $this->current) {
$is_current = true;
// $is_current = true;
}
return [
'tag' => $item[1],
@@ -42,7 +63,7 @@ class Rollback extends Component
];
})->toArray();
} catch (\Throwable $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use Livewire\Component;
class Status extends Component
{
public Application $application;
public function applicationStatusChanged()
{
$this->emit('applicationStatusChanged');
$this->application->refresh();
}
}

View File

@@ -23,7 +23,7 @@ class Add extends Component
];
public function mount()
{
$this->parameters = getParameters();
$this->parameters = get_parameters();
}
public function submit()
{

View File

@@ -27,7 +27,7 @@ class All extends Component
$this->application->refresh();
$this->emit('clearAddStorage');
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Livewire\Project;
use App\Models\Environment;
use App\Models\Project;
use Livewire\Component;
class DeleteEnvironment extends Component
{
public array $parameters;
public int $environment_id;
public int $resource_count = 0;
public function mount()
{
$this->parameters = get_parameters();
}
public function delete()
{
$this->validate([
'environment_id' => 'required|int',
]);
$environment = Environment::findOrFail($this->environment_id);
if ($environment->applications->count() > 0) {
return $this->emit('error', 'Environment has resources defined, please delete them first.');
}
$environment->delete();
return redirect()->route('project.show', ['project_uuid' => $this->parameters['project_uuid']]);
}
}

View File

@@ -5,11 +5,16 @@ namespace App\Http\Livewire\Project;
use App\Models\Project;
use Livewire\Component;
class Delete extends Component
class DeleteProject extends Component
{
public array $parameters;
public int $project_id;
public int $resource_count = 0;
public function mount()
{
$this->parameters = get_parameters();
}
public function delete()
{
$this->validate([
@@ -17,9 +22,9 @@ class Delete extends Component
]);
$project = Project::findOrFail($this->project_id);
if ($project->applications->count() > 0) {
return $this->emit('error', 'Project has applications, please delete them first.');
return $this->emit('error', 'Project has resources defined, please delete them first.');
}
$project->delete();
return redirect()->route('dashboard');
return redirect()->route('projects');
}
}

View File

@@ -10,9 +10,9 @@ class EmptyProject extends Component
public function createEmptyProject()
{
$project = Project::create([
'name' => generateRandomName(),
'name' => generate_random_name(),
'team_id' => session('currentTeam')->id,
]);
return redirect()->route('project.environments', ['project_uuid' => $project->uuid, 'environment_name' => 'production']);
return redirect()->route('project.show', ['project_uuid' => $project->uuid, 'environment_name' => 'production']);
}
}

View File

@@ -110,7 +110,7 @@ class GithubPrivateRepository extends Component
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
$application = Application::create([
'name' => generateRandomName(),
'name' => generate_random_name(),
'repository_project_id' => $this->selected_repository_id,
'git_repository' => "{$this->selected_repository_owner}/{$this->selected_repository_repo}",
'git_branch' => $this->selected_branch_name,
@@ -129,12 +129,12 @@ class GithubPrivateRepository extends Component
'environment_name' => $environment->name
]);
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
public function mount()
{
$this->parameters = getParameters();
$this->parameters = get_parameters();
$this->query = request()->query();
$this->repositories = $this->branches = collect();
$this->github_apps = GithubApp::private();

View File

@@ -34,7 +34,7 @@ class GithubPrivateRepositoryDeployKey extends Component
if (config('app.env') === 'local') {
$this->repository_url = 'https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify';
}
$this->parameters = getParameters();
$this->parameters = get_parameters();
$this->query = request()->query();
$this->private_keys = PrivateKey::where('team_id', session('currentTeam')->id)->get();
}
@@ -74,7 +74,7 @@ class GithubPrivateRepositoryDeployKey extends Component
$project = Project::where('uuid', $this->parameters['project_uuid'])->first();
$environment = $project->load(['environments'])->environments->where('name', $this->parameters['environment_name'])->first();
$application_init = [
'name' => generateRandomName(),
'name' => generate_random_name(),
'git_repository' => $git_repository,
'git_branch' => $git_branch,
'git_full_url' => "git@$git_host:$git_repository.git",
@@ -96,7 +96,7 @@ class GithubPrivateRepositoryDeployKey extends Component
'application_uuid' => $application->uuid,
]);
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -37,7 +37,7 @@ class PublicGitRepository extends Component
$this->repository_url = 'https://github.com/coollabsio/coolify-examples/tree/nodejs-fastify';
$this->port = 3000;
}
$this->parameters = getParameters();
$this->parameters = get_parameters();
$this->query = request()->query();
}
@@ -78,7 +78,7 @@ class PublicGitRepository extends Component
$application_init = [
'name' => generateRandomName(),
'name' => generate_application_name($git_repository, $git_branch),
'git_repository' => $git_repository,
'git_branch' => $git_branch,
'build_pack' => 'nixpacks',
@@ -106,7 +106,7 @@ class PublicGitRepository extends Component
'application_uuid' => $application->uuid,
]);
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
}

View File

@@ -26,10 +26,10 @@ class RunCommand extends Component
{
try {
$this->validate();
$activity = remoteProcess([$this->command], Server::where('uuid', $this->server)->first(), ActivityTypes::INLINE->value);
$activity = remote_process([$this->command], Server::where('uuid', $this->server)->first());
$this->emit('newMonitorActivity', $activity->id);
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
}

View File

@@ -36,7 +36,7 @@ class Form extends Component
public function validateServer()
{
try {
$this->uptime = instantRemoteProcess(['uptime'], $this->server, false);
$this->uptime = instant_remote_process(['uptime'], $this->server, false);
if (!$this->uptime) {
$this->uptime = 'Server not reachable.';
throw new \Exception('Server not reachable.');
@@ -47,16 +47,16 @@ class Form extends Component
$this->emit('serverValidated');
}
}
$this->dockerVersion = instantRemoteProcess(['docker version|head -2|grep -i version'], $this->server, false);
$this->dockerVersion = instant_remote_process(['docker version|head -2|grep -i version'], $this->server, false);
if (!$this->dockerVersion) {
$this->dockerVersion = 'Not installed.';
}
$this->dockerComposeVersion = instantRemoteProcess(['docker compose version|head -2|grep -i version'], $this->server, false);
$this->dockerComposeVersion = instant_remote_process(['docker compose version|head -2|grep -i version'], $this->server, false);
if (!$this->dockerComposeVersion) {
$this->dockerComposeVersion = 'Not installed.';
}
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
public function delete()

View File

@@ -30,7 +30,7 @@ class ByIp extends Component
];
public function mount()
{
$this->name = generateRandomName();
$this->name = generate_random_name();
$this->private_key_id = $this->private_keys->first()->id;
}
public function setPrivateKey(string $private_key_id)
@@ -61,7 +61,7 @@ class ByIp extends Component
$server->settings->save();
return redirect()->route('server.show', $server->uuid);
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
}

View File

@@ -4,7 +4,6 @@ namespace App\Http\Livewire\Server;
use App\Models\PrivateKey as ModelsPrivateKey;
use App\Models\Server;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Storage;
use Livewire\Component;
@@ -19,13 +18,12 @@ class PrivateKey extends Component
'private_key_id' => $private_key_id
]);
// Delete the old ssh mux file to force a new one to be created
Storage::disk('local')->delete(".ssh/ssh_mux_{$server->first()->ip}_{$server->first()->port}_{$server->first()->user}");
Storage::disk('ssh-mux')->delete("{$server->first()->ip}_{$server->first()->port}_{$server->first()->user}");
return redirect()->route('server.show', $this->parameters['server_uuid']);
}
public function mount()
{
$this->parameters = getParameters();
$this->parameters = get_parameters();
$this->private_keys = ModelsPrivateKey::where('team_id', session('currentTeam')->id)->get();
}
}

View File

@@ -39,7 +39,7 @@ class Proxy extends Component
public function proxyStatus()
{
$this->server->extra_attributes->proxy_status = checkContainerStatus(server: $this->server, container_id: 'coolify-proxy');
$this->server->extra_attributes->proxy_status = get_container_status(server: $this->server, container_id: 'coolify-proxy');
$this->server->save();
$this->server->refresh();
}
@@ -51,7 +51,7 @@ class Proxy extends Component
}
public function stopProxy()
{
instantRemoteProcess([
instant_remote_process([
"docker rm -f coolify-proxy",
], $this->server);
$this->server->extra_attributes->proxy_status = 'exited';
@@ -65,11 +65,11 @@ class Proxy extends Component
$docker_compose_yml_base64 = base64_encode($this->proxy_settings);
$this->server->extra_attributes->last_saved_proxy_settings = Str::of($docker_compose_yml_base64)->pipe('md5')->value;
$this->server->save();
instantRemoteProcess([
instant_remote_process([
"echo '$docker_compose_yml_base64' | base64 -d > $proxy_path/docker-compose.yml",
], $this->server);
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
public function resetProxy()
@@ -77,7 +77,7 @@ class Proxy extends Component
try {
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server, true);
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
public function checkProxySettingsInSync()
@@ -85,7 +85,7 @@ class Proxy extends Component
try {
$this->proxy_settings = resolve(CheckProxySettingsInSync::class)($this->server);
} catch (\Exception $e) {
return generalErrorHandler($e);
return general_error_handler($e);
}
}
}

View File

@@ -3,7 +3,10 @@
namespace App\Http\Livewire\Settings;
use App\Models\InstanceSettings as ModelsInstanceSettings;
use App\Models\Server;
use Livewire\Component;
use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml;
class Form extends Component
{
@@ -11,30 +14,174 @@ class Form extends Component
public $do_not_track;
public $is_auto_update_enabled;
public $is_registration_enabled;
public $is_https_forced;
protected string $dynamic_config_path;
protected Server $server;
protected $rules = [
'settings.fqdn' => 'nullable',
'settings.wildcard_domain' => 'nullable',
'settings.public_port_min' => 'required',
'settings.public_port_max' => 'required',
'settings.default_redirect_404' => 'nullable',
];
public function mount()
{
$this->do_not_track = $this->settings->do_not_track;
$this->is_auto_update_enabled = $this->settings->is_auto_update_enabled;
$this->is_registration_enabled = $this->settings->is_registration_enabled;
$this->is_https_forced = $this->settings->is_https_forced;
}
public function instantSave()
{
$this->settings->do_not_track = $this->do_not_track;
$this->settings->is_auto_update_enabled = $this->is_auto_update_enabled;
$this->settings->is_registration_enabled = $this->is_registration_enabled;
$this->settings->is_https_forced = $this->is_https_forced;
$this->settings->save();
$this->emit('saved', 'Settings updated!');
}
private function setup_instance_fqdn()
{
$file = "$this->dynamic_config_path/coolify.yaml";
if (empty($this->settings->fqdn)) {
remote_process([
"rm -f $file",
], $this->server);
} else {
$url = Url::fromString($this->settings->fqdn);
$host = $url->getHost();
$schema = $url->getScheme();
$traefik_dynamic_conf = [
'http' =>
[
'routers' =>
[
'coolify-http' =>
[
'entryPoints' => [
0 => 'http',
],
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
],
],
'services' =>
[
'coolify' =>
[
'loadBalancer' =>
[
'servers' =>
[
0 =>
[
'url' => 'http://coolify:80',
],
],
],
],
],
],
];
if ($schema === 'https') {
$traefik_dynamic_conf['http']['routers']['coolify-http']['middlewares'] = [
0 => 'redirect-to-https@docker',
];
$traefik_dynamic_conf['http']['routers']['coolify-https'] = [
'entryPoints' => [
0 => 'https',
],
'service' => 'coolify',
'rule' => "Host(`{$host}`)",
'tls' => [
'certresolver' => 'letsencrypt',
],
];
}
$this->save_configuration_to_disk($traefik_dynamic_conf, $file);
}
}
private function setup_default_redirect_404()
{
$file = "$this->dynamic_config_path/default_redirect_404.yaml";
if (empty($this->settings->default_redirect_404)) {
remote_process([
"rm -f $file",
], $this->server);
} else {
$url = Url::fromString($this->settings->default_redirect_404);
$host = $url->getHost();
$schema = $url->getScheme();
$traefik_dynamic_conf = [
'http' =>
[
'routers' =>
[
'catchall' =>
[
'entryPoints' => [
0 => 'http',
1 => 'https',
],
'service' => 'noop',
'rule' => "HostRegexp(`{catchall:.*}`)",
'priority' => 1,
'middlewares' => [
0 => 'redirect-regexp@file',
],
],
],
'services' =>
[
'noop' =>
[
'loadBalancer' =>
[
'servers' =>
[
0 =>
[
'url' => '',
],
],
],
],
],
'middlewares' =>
[
'redirect-regexp' =>
[
'redirectRegex' =>
[
'regex' => '(.*)',
'replacement' => $this->settings->default_redirect_404,
'permanent' => false,
],
],
],
],
];
$this->save_configuration_to_disk($traefik_dynamic_conf, $file);
}
}
private function save_configuration_to_disk(array $traefik_dynamic_conf, string $file)
{
$yaml = Yaml::dump($traefik_dynamic_conf, 12, 2);
$yaml =
"# This file is automatically generated by Coolify.\n" .
"# Do not edit it manually (only if you know what are you doing).\n\n" .
$yaml;
$base64 = base64_encode($yaml);
remote_process([
"mkdir -p $this->dynamic_config_path",
"echo '$base64' | base64 -d > $file",
], $this->server);
if (config('app.env') == 'local') {
ray($yaml);
}
}
public function submit()
{
$this->resetErrorBag();
@@ -44,5 +191,14 @@ class Form extends Component
}
$this->validate();
$this->settings->save();
$this->dynamic_config_path = '/data/coolify/proxy/dynamic';
if (config('app.env') == 'local') {
$this->server = Server::findOrFail(1);
} else {
$this->server = Server::findOrFail(0);
}
$this->setup_instance_fqdn();
$this->setup_default_redirect_404();
}
}

View File

@@ -35,7 +35,7 @@ class Change extends Component
$this->validate();
$this->github_app->save();
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
public function instantSave()
@@ -45,7 +45,7 @@ class Change extends Component
$this->github_app->save();
$this->emit('saved', 'GitHub settings updated!');
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
public function mount()
@@ -54,7 +54,7 @@ class Change extends Component
if ($settings->fqdn) {
$this->host = $settings->fqdn;
}
$this->parameters = getParameters();
$this->parameters = get_parameters();
$this->is_system_wide = $this->github_app->is_system_wide;
}
public function delete()
@@ -63,7 +63,7 @@ class Change extends Component
$this->github_app->delete();
redirect()->route('dashboard');
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace App\Http\Livewire\Source;
namespace App\Http\Livewire\Source\Github;
use App\Models\GithubApp;
use Livewire\Component;
@@ -17,7 +17,7 @@ class Create extends Component
public function mount()
{
$this->name = generateRandomName();
$this->name = generate_random_name();
}
public function createGitHubApp()
{
@@ -43,7 +43,7 @@ class Create extends Component
]);
redirect()->route('source.github.show', ['github_app_uuid' => $github_app->uuid]);
} catch (\Exception $e) {
return generalErrorHandler($e, $this);
return general_error_handler($e, $this);
}
}
}

View File

@@ -0,0 +1,15 @@
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class Upgrading extends Component
{
public bool $visible = false;
protected $listeners = ['updateInitiated'];
public function updateInitiated()
{
$this->visible = true;
}
}

View File

@@ -12,7 +12,7 @@ class TrustProxies extends Middleware
*
* @var array<int, string>|string|null
*/
protected $proxies;
protected $proxies = '*';
/**
* The headers that should be used to detect proxies.
@@ -20,7 +20,7 @@ class TrustProxies extends Middleware
* @var int
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |