Refactor code and update destination component

This commit is contained in:
Andras Bacsai 2023-11-21 15:31:46 +01:00
parent f58e6766e1
commit ef7fc1b260
12 changed files with 162 additions and 53 deletions

View File

@ -10,23 +10,6 @@ class ApplicationController extends Controller
{ {
use AuthorizesRequests, ValidatesRequests; use AuthorizesRequests, ValidatesRequests;
public function configuration()
{
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
if (!$project) {
return redirect()->route('dashboard');
}
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
if (!$environment) {
return redirect()->route('dashboard');
}
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
if (!$application) {
return redirect()->route('dashboard');
}
return view('project.application.configuration', ['application' => $application]);
}
public function deployments() public function deployments()
{ {
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first(); $project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();

View File

@ -0,0 +1,39 @@
<?php
namespace App\Http\Livewire\Project\Application;
use App\Models\Application;
use App\Models\Server;
use App\Models\StandaloneDocker;
use Livewire\Component;
class Configuration extends Component
{
public Application $application;
public $servers;
public function mount()
{
$project = currentTeam()->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
if (!$project) {
return redirect()->route('dashboard');
}
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
if (!$environment) {
return redirect()->route('dashboard');
}
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
if (!$application) {
return redirect()->route('dashboard');
}
$this->application = $application;
$mainServer = $application->destination->server;
$servers = Server::ownedByCurrentTeam()->get();
$this->servers = $servers->filter(function ($server) use ($mainServer) {
return $server->id != $mainServer->id;
});
}
public function render()
{
return view('livewire.project.application.configuration');
}
}

View File

@ -6,5 +6,7 @@
class Destination extends Component class Destination extends Component
{ {
public $destination; public $resource;
public $servers = [];
public $additionalServers = [];
} }

View File

@ -55,6 +55,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
private GithubApp|GitlabApp|string $source = 'other'; private GithubApp|GitlabApp|string $source = 'other';
private StandaloneDocker|SwarmDocker $destination; private StandaloneDocker|SwarmDocker $destination;
private Server $server; private Server $server;
private Server $mainServer;
private ?ApplicationPreview $preview = null; private ?ApplicationPreview $preview = null;
private ?string $git_type = null; private ?string $git_type = null;
@ -111,7 +112,7 @@ public function __construct(int $application_deployment_queue_id)
$this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first(); $this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first();
} }
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first(); $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
$this->server = $this->destination->server; $this->server = $this->mainServer = $this->destination->server;
$this->serverUser = $this->server->user; $this->serverUser = $this->server->user;
$this->basedir = "/artifacts/{$this->deployment_uuid}"; $this->basedir = "/artifacts/{$this->deployment_uuid}";
$this->workdir = "{$this->basedir}" . rtrim($this->application->base_directory, '/'); $this->workdir = "{$this->basedir}" . rtrim($this->application->base_directory, '/');
@ -181,10 +182,6 @@ public function handle(): void
$this->buildTarget = " --target {$this->application->dockerfile_target_build} "; $this->buildTarget = " --target {$this->application->dockerfile_target_build} ";
} }
// Get user home directory
$this->serverUserHomeDir = instant_remote_process(["echo \$HOME"], $this->server);
$this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
// Check custom port // Check custom port
preg_match('/(?<=:)\d+(?=\/)/', $this->application->git_repository, $matches); preg_match('/(?<=:)\d+(?=\/)/', $this->application->git_repository, $matches);
if (count($matches) === 1) { if (count($matches) === 1) {
@ -400,19 +397,19 @@ private function check_image_locally_or_remotely()
]); ]);
} }
} }
private function save_environment_variables() // private function save_environment_variables()
{ // {
$envs = collect([]); // $envs = collect([]);
foreach ($this->application->environment_variables as $env) { // foreach ($this->application->environment_variables as $env) {
$envs->push($env->key . '=' . $env->value); // $envs->push($env->key . '=' . $env->value);
} // }
$envs_base64 = base64_encode($envs->implode("\n")); // $envs_base64 = base64_encode($envs->implode("\n"));
$this->execute_remote_command( // $this->execute_remote_command(
[ // [
executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d > $this->workdir/.env") // executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d > $this->workdir/.env")
], // ],
); // );
} // }
private function deploy_simple_dockerfile() private function deploy_simple_dockerfile()
{ {
$dockerfile_base64 = base64_encode($this->application->dockerfile); $dockerfile_base64 = base64_encode($this->application->dockerfile);
@ -471,7 +468,12 @@ private function deploy_dockerfile_buildpack()
$this->generate_build_env_variables(); $this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile(); $this->add_build_env_variables_to_dockerfile();
$this->build_image(); $this->build_image();
// if ($this->application->additional_destinations) {
// $this->push_to_docker_registry();
// $this->deploy_to_additional_destinations();
// } else {
$this->rolling_update(); $this->rolling_update();
// }
} }
private function deploy_nixpacks_buildpack() private function deploy_nixpacks_buildpack()
{ {
@ -629,12 +631,15 @@ private function deploy_pull_request()
private function prepare_builder_image() private function prepare_builder_image()
{ {
$helperImage = config('coolify.helper_image'); $helperImage = config('coolify.helper_image');
// Get user home directory
$this->serverUserHomeDir = instant_remote_process(["echo \$HOME"], $this->server);
$this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
if ($this->dockerConfigFileExists === 'OK') { if ($this->dockerConfigFileExists === 'OK') {
$runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}"; $runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
} else { } else {
$runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}"; $runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
} }
$this->execute_remote_command( $this->execute_remote_command(
[ [
"echo -n 'Preparing container with helper image: $helperImage.'", "echo -n 'Preparing container with helper image: $helperImage.'",
@ -648,7 +653,31 @@ private function prepare_builder_image()
], ],
); );
} }
private function deploy_to_additional_destinations()
{
$destination_ids = collect(str($this->application->additional_destinations)->explode(','));
foreach ($destination_ids as $destination_id) {
$destination = StandaloneDocker::find($destination_id);
$server = $destination->server;
if ($server->team_id !== $this->mainServer->team_id) {
$this->execute_remote_command(
[
"echo -n 'Skipping deployment to {$server->name}. Not in the same team?!'",
],
);
continue;
}
$this->server = $server;
$this->execute_remote_command(
[
"echo -n 'Deploying to {$this->server->name}.'",
],
);
$this->prepare_builder_image();
$this->generate_image_names();
$this->rolling_update();
}
}
private function set_base_dir() private function set_base_dir()
{ {
$this->execute_remote_command( $this->execute_remote_command(

View File

@ -37,7 +37,7 @@ public function uniqueId(): int
public function handle(): void public function handle(): void
{ {
ray("checking container statuses for {$this->server->id}"); // ray("checking container statuses for {$this->server->id}");
try { try {
if (!$this->server->isServerReady()) { if (!$this->server->isServerReady()) {
return; return;

View File

@ -225,7 +225,8 @@ public function source()
return $this->morphTo(); return $this->morphTo();
} }
public function isDeploymentInprogress() { public function isDeploymentInprogress()
{
$deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', 'in_progress')->count(); $deployments = ApplicationDeploymentQueue::where('application_id', $this->id)->where('status', 'in_progress')->count();
if ($deployments > 0) { if ($deployments > 0) {
return true; return true;
@ -300,7 +301,8 @@ public function isHealthcheckDisabled(): bool
} }
return false; return false;
} }
public function isLogDrainEnabled() { public function isLogDrainEnabled()
{
return data_get($this, 'settings.is_log_drain_enabled', false); return data_get($this, 'settings.is_log_drain_enabled', false);
} }
public function isConfigurationChanged($save = false) public function isConfigurationChanged($save = false)

View File

@ -332,7 +332,6 @@ public function validateConnection()
} }
$uptime = instant_remote_process(['uptime'], $this, false); $uptime = instant_remote_process(['uptime'], $this, false);
ray($uptime);
if (!$uptime) { if (!$uptime) {
$this->settings()->update([ $this->settings()->update([
'is_reachable' => false, 'is_reachable' => false,
@ -345,7 +344,6 @@ public function validateConnection()
$this->update([ $this->update([
'unreachable_count' => 0, 'unreachable_count' => 0,
]); ]);
ray($this);
} }
if (data_get($this, 'unreachable_notification_sent') === true) { if (data_get($this, 'unreachable_notification_sent') === true) {

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('applications', function (Blueprint $table) {
$table->string('additional_destinations')->nullable()->after('destination');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn('additional_destinations');
});
}
};

View File

@ -1,4 +1,4 @@
<x-layout> <div>
<h1>Configuration</h1> <h1>Configuration</h1>
<livewire:project.application.heading :application="$application" /> <livewire:project.application.heading :application="$application" />
<div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex h-full pt-6"> <div x-data="{ activeTab: window.location.hash ? window.location.hash.substring(1) : 'general' }" class="flex h-full pt-6">
@ -66,7 +66,7 @@
</div> </div>
@endif @endif
<div x-cloak x-show="activeTab === 'server'"> <div x-cloak x-show="activeTab === 'server'">
<livewire:project.shared.destination :destination="$application->destination" /> <livewire:project.shared.destination :resource="$application" :servers="$servers" />
</div> </div>
<div x-cloak x-show="activeTab === 'storages'"> <div x-cloak x-show="activeTab === 'storages'">
<livewire:project.service.storage :resource="$application" /> <livewire:project.service.storage :resource="$application" />
@ -91,4 +91,4 @@
</div> </div>
</div> </div>
</div> </div>
</x-layout> </div>

View File

@ -3,7 +3,34 @@
<div class="">The destination server where your application will be deployed to.</div> <div class="">The destination server where your application will be deployed to.</div>
<div class="py-4 "> <div class="py-4 ">
<a class="box" <a class="box"
href="{{ route('server.show', ['server_uuid' => data_get($destination, 'server.uuid')]) }}">On server <span class="px-1 text-warning">{{ data_get($destination, 'server.name') }}</span> href="{{ route('server.show', ['server_uuid' => data_get($resource, 'destination.server.uuid')]) }}">On
in <span class="px-1 text-warning"> {{ data_get($destination, 'network') }} </span> network.</a> server <span class="px-1 text-warning">{{ data_get($resource, 'destination.server.name') }}</span>
in <span class="px-1 text-warning"> {{ data_get($resource, 'destination.network') }} </span> network.</a>
</div> </div>
{{-- {{$resource->additional_destinations}} --}}
{{-- @if (count($servers) > 0)
<div>
<h3>Additional Servers</h3>
@foreach ($servers as $server)
<form wire:submit.prevent='submit' class="p-2 border border-coolgray-400">
<h4>{{ $server->name }}</h4>
<div class="text-sm text-coolgray-600">{{ $server->description }}</div>
<x-forms.checkbox id="additionalServers.{{ $loop->index }}.enabled" label="Enabled">
</x-forms.checkbox>
<x-forms.select label="Destination" id="additionalServers.{{ $loop->index }}.destination" required>
@foreach ($server->destinations() as $destination)
@if ($loop->first)
<option selected value="{{ $destination->uuid }}">{{ $destination->name }}</option>
<option value="{{ $destination->uuid }}">{{ $destination->name }}</option>
@else
<option value="{{ $destination->uuid }}">{{ $destination->name }}</option>
<option value="{{ $destination->uuid }}">{{ $destination->name }}</option>
@endif
@endforeach
</x-forms.select>
<x-forms.button type="submit">Save</x-forms.button>
</form>
@endforeach
</div>
@endif --}}
</div> </div>

View File

@ -63,7 +63,7 @@
<livewire:project.shared.environment-variable.all :resource="$database" /> <livewire:project.shared.environment-variable.all :resource="$database" />
</div> </div>
<div x-cloak x-show="activeTab === 'server'"> <div x-cloak x-show="activeTab === 'server'">
<livewire:project.shared.destination :destination="$database->destination" /> <livewire:project.shared.destination :resource="$database" />
</div> </div>
<div x-cloak x-show="activeTab === 'storages'"> <div x-cloak x-show="activeTab === 'storages'">
<livewire:project.service.storage :resource="$database" /> <livewire:project.service.storage :resource="$database" />

View File

@ -5,6 +5,7 @@
use App\Http\Controllers\DatabaseController; use App\Http\Controllers\DatabaseController;
use App\Http\Controllers\MagicController; use App\Http\Controllers\MagicController;
use App\Http\Controllers\ProjectController; use App\Http\Controllers\ProjectController;
use App\Http\Livewire\Project\Application\Configuration as ApplicationConfiguration;
use App\Http\Livewire\Boarding\Index as BoardingIndex; use App\Http\Livewire\Boarding\Index as BoardingIndex;
use App\Http\Livewire\Project\Service\Index as ServiceIndex; use App\Http\Livewire\Project\Service\Index as ServiceIndex;
use App\Http\Livewire\Project\Service\Show as ServiceShow; use App\Http\Livewire\Project\Service\Show as ServiceShow;
@ -101,7 +102,8 @@
Route::get('/project/{project_uuid}/{environment_name}', [ProjectController::class, 'resources'])->name('project.resources'); Route::get('/project/{project_uuid}/{environment_name}', [ProjectController::class, 'resources'])->name('project.resources');
// Applications // Applications
Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}', [ApplicationController::class, 'configuration'])->name('project.application.configuration'); Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}', ApplicationConfiguration::class)->name('project.application.configuration');
Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment', [ApplicationController::class, 'deployments'])->name('project.application.deployments'); Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment', [ApplicationController::class, 'deployments'])->name('project.application.deployments');
Route::get( Route::get(
'/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}', '/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}',
@ -167,7 +169,6 @@
'private_key' => PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail() 'private_key' => PrivateKey::ownedByCurrentTeam(['name', 'description', 'private_key', 'is_git_related'])->whereUuid(request()->private_key_uuid)->firstOrFail()
]))->name('security.private-key.show'); ]))->name('security.private-key.show');
Route::get('/security/api-tokens', ApiTokens::class)->name('security.api-tokens'); Route::get('/security/api-tokens', ApiTokens::class)->name('security.api-tokens');
}); });