Merge remote-tracking branch 'origin/v4' into ijpatricio-wip-4
# Conflicts: # bootstrap/helpers.php # docker/dev/supervisord.conf
This commit is contained in:
@@ -41,6 +41,9 @@ class RunRemoteProcess
|
||||
|
||||
public function __invoke(): ProcessResult
|
||||
{
|
||||
$this->activity->properties = $this->activity->properties->merge([
|
||||
'status' => ProcessStatus::IN_PROGRESS,
|
||||
]);
|
||||
$this->timeStart = hrtime(true);
|
||||
|
||||
$processResult = Process::run($this->getCommand(), $this->handleOutput(...));
|
||||
@@ -70,22 +73,7 @@ class RunRemoteProcess
|
||||
$port = $this->activity->getExtraProperty('port');
|
||||
$command = $this->activity->getExtraProperty('command');
|
||||
|
||||
$delimiter = 'EOF-COOLIFY-SSH';
|
||||
Storage::disk('local')->makeDirectory('.ssh');
|
||||
|
||||
$ssh_command = "ssh "
|
||||
. "-i {$private_key_location} "
|
||||
. '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
|
||||
. '-o PasswordAuthentication=no '
|
||||
. '-o RequestTTY=no '
|
||||
. '-o LogLevel=ERROR '
|
||||
. '-o ControlMaster=auto -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r '
|
||||
. "-p {$port} "
|
||||
. "{$user}@{$server_ip} "
|
||||
. " 'bash -se' << \\$delimiter" . PHP_EOL
|
||||
. $command . PHP_EOL
|
||||
. $delimiter;
|
||||
return $ssh_command;
|
||||
return generateSshCommand($private_key_location, $server_ip, $user, $port, $command);
|
||||
}
|
||||
|
||||
protected function handleOutput(string $type, string $output)
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
@@ -12,7 +13,7 @@ class Kernel extends ConsoleKernel
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
{
|
||||
// $schedule->command('inspire')->hourly();
|
||||
$schedule->job(new ContainerStatusJob)->everyMinute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -6,7 +6,7 @@ class HomeController extends Controller
|
||||
{
|
||||
public function show()
|
||||
{
|
||||
$projects = session('currentTeam')->projects;
|
||||
$projects = session('currentTeam')->load(['projects'])->projects;
|
||||
return view('home', ['projects' => $projects]);
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\Environment;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
@@ -9,8 +11,7 @@ class ProjectController extends Controller
|
||||
{
|
||||
public function environments()
|
||||
{
|
||||
$project_uuid = request()->route('project_uuid');
|
||||
$project = session('currentTeam')->projects->where('uuid', $project_uuid)->first();
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first()->load(['environments']);
|
||||
if (!$project) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
@@ -18,94 +19,50 @@ class ProjectController extends Controller
|
||||
}
|
||||
public function resources()
|
||||
{
|
||||
$project_uuid = request()->route('project_uuid');
|
||||
$project = session('currentTeam')->projects->where('uuid', $project_uuid)->first();
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$environment = $project->environments->where('name', request()->route('environment_name'))->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first();
|
||||
if (!$environment) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
return view('project.resources', ['project' => $project, 'environment' => $environment]);
|
||||
}
|
||||
public function application()
|
||||
{
|
||||
$project_uuid = request()->route('project_uuid');
|
||||
$environment_name = request()->route('environment_name');
|
||||
$application_uuid = request()->route('application_uuid');
|
||||
$project = session('currentTeam')->projects->where('uuid', $project_uuid)->first();
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$environment = $project->environments->where('name', $environment_name)->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
||||
if (!$environment) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$application = $environment->applications->where('uuid', $application_uuid)->first();
|
||||
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
|
||||
if (!$application) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
return view('project.application', ['project' => $project, 'application' => $application, 'deployments' => $application->deployments()]);
|
||||
return view('project.application', ['application' => $application, 'deployments' => $application->deployments()]);
|
||||
}
|
||||
public function database()
|
||||
{
|
||||
$project_uuid = request()->route('project_uuid');
|
||||
$environment_name = request()->route('environment_name');
|
||||
$database_uuid = request()->route('database_uuid');
|
||||
$project = session('currentTeam')->projects->where('uuid', $project_uuid)->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$environment = $project->environments->where('name', $environment_name)->first();
|
||||
if (!$environment) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$database = $environment->databases->where('uuid', $database_uuid)->first();
|
||||
if (!$database) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
|
||||
return view('project.database', ['project' => $project, 'database' => $database]);
|
||||
}
|
||||
public function service()
|
||||
{
|
||||
$project_uuid = request()->route('project_uuid');
|
||||
$environment_name = request()->route('environment_name');
|
||||
$service_uuid = request()->route('service_uuid');
|
||||
|
||||
$project = session('currentTeam')->projects->where('uuid', $project_uuid)->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$environment = $project->environments->where('name', $environment_name)->first();
|
||||
if (!$environment) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$service = $environment->services->where('uuid', $service_uuid)->first();
|
||||
if (!$service) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
|
||||
return view('project.service', ['project' => $project, 'service' => $service]);
|
||||
}
|
||||
public function deployment()
|
||||
{
|
||||
$project_uuid = request()->route('project_uuid');
|
||||
$environment_name = request()->route('environment_name');
|
||||
$application_uuid = request()->route('application_uuid');
|
||||
$deployment_uuid = request()->route('deployment_uuid');
|
||||
|
||||
$project = session('currentTeam')->projects->where('uuid', $project_uuid)->first();
|
||||
$project = session('currentTeam')->load(['projects'])->projects->where('uuid', request()->route('project_uuid'))->first();
|
||||
if (!$project) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$environment = $project->environments->where('name', $environment_name)->first();
|
||||
$environment = $project->load(['environments'])->environments->where('name', request()->route('environment_name'))->first()->load(['applications']);
|
||||
if (!$environment) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$application = $environment->applications->where('uuid', $application_uuid)->first();
|
||||
$application = $environment->applications->where('uuid', request()->route('application_uuid'))->first();
|
||||
if (!$application) {
|
||||
return redirect()->route('home');
|
||||
}
|
||||
$activity = $application->get_deployment($deployment_uuid);
|
||||
return view('project.deployment', ['project' => $project, 'activity' => $activity]);
|
||||
return view('project.deployment', ['activity' => $activity]);
|
||||
}
|
||||
}
|
||||
|
@@ -2,10 +2,12 @@
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Jobs\ContainerStatusJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\CoolifyInstanceSettings;
|
||||
use DateTimeImmutable;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Livewire\Component;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
@@ -19,20 +21,31 @@ class DeployApplication extends Component
|
||||
{
|
||||
public string $application_uuid;
|
||||
public $activity;
|
||||
public $status;
|
||||
public Application $application;
|
||||
public $destination;
|
||||
|
||||
protected string $deployment_uuid;
|
||||
protected array $command = [];
|
||||
protected Application $application;
|
||||
protected $destination;
|
||||
protected $source;
|
||||
|
||||
public function mount($application_uuid)
|
||||
{
|
||||
$this->application_uuid = $application_uuid;
|
||||
$this->application = Application::where('uuid', $this->application_uuid)->first();
|
||||
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
|
||||
}
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.deploy-application');
|
||||
}
|
||||
private function execute_in_builder(string $command)
|
||||
{
|
||||
if ($this->application->settings->is_debug) {
|
||||
return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'";
|
||||
} else {
|
||||
return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}' > /dev/null 2>&1";
|
||||
}
|
||||
return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'";
|
||||
// if ($this->application->settings->is_debug) {
|
||||
// } else {
|
||||
// return $this->command[] = "docker exec {$this->deployment_uuid} bash -c '{$command}'";
|
||||
// }
|
||||
}
|
||||
private function start_builder_container()
|
||||
{
|
||||
@@ -45,7 +58,6 @@ class DeployApplication extends Component
|
||||
'services' => [
|
||||
$this->application->uuid => [
|
||||
'image' => "{$this->application->uuid}:TAG",
|
||||
'expose' => $this->application->ports_exposes,
|
||||
'container_name' => $this->application->uuid,
|
||||
'restart' => 'always',
|
||||
'labels' => $this->set_labels_for_applications(),
|
||||
@@ -144,7 +156,6 @@ class DeployApplication extends Component
|
||||
public function deploy()
|
||||
{
|
||||
$coolify_instance_settings = CoolifyInstanceSettings::find(1);
|
||||
$this->application = Application::where('uuid', $this->application_uuid)->first();
|
||||
$this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
|
||||
$this->source = $this->application->source->getMorphClass()::where('id', $this->application->source->id)->first();
|
||||
|
||||
@@ -220,7 +231,7 @@ class DeployApplication extends Component
|
||||
|
||||
$this->execute_in_builder("docker build -f {$workdir}/Dockerfile --build-arg SOURCE_COMMIT=$(cat {$workdir}/.git-commit) --progress plain -t {$this->application->uuid}:$(cat {$workdir}/.git-commit) {$workdir}");
|
||||
$this->command[] = "echo 'Done.'";
|
||||
$this->execute_in_builder("test ! -z \"$(docker ps --format '{{.State}}' --filter 'name={$this->application->uuid}')\" && docker rm -f {$this->application->uuid} >/dev/null 2>&1");
|
||||
$this->execute_in_builder("docker rm -f {$this->application->uuid} >/dev/null 2>&1");
|
||||
|
||||
$this->command[] = "echo -n 'Deploying... '";
|
||||
|
||||
@@ -233,11 +244,26 @@ class DeployApplication extends Component
|
||||
$deploymentUrl = "$currentUrl/deployment/$this->deployment_uuid";
|
||||
return redirect($deploymentUrl);
|
||||
}
|
||||
public function cancel()
|
||||
|
||||
public function stop()
|
||||
{
|
||||
runRemoteCommandSync($this->destination->server, ["docker rm -f {$this->application_uuid} >/dev/null 2>&1"]);
|
||||
$this->application->status = 'exited';
|
||||
$this->application->save();
|
||||
}
|
||||
public function render()
|
||||
public function pollingStatus()
|
||||
{
|
||||
return view('livewire.deploy-application');
|
||||
$this->application->refresh();
|
||||
}
|
||||
public function checkStatus()
|
||||
{
|
||||
$output = runRemoteCommandSync($this->destination->server, ["docker ps -a --format '{{.State}}' --filter 'name={$this->application->uuid}'"]);
|
||||
if ($output == '') {
|
||||
$this->application->status = 'exited';
|
||||
$this->application->save();
|
||||
} else {
|
||||
$this->application->status = $output;
|
||||
$this->application->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
60
app/Jobs/ContainerStatusJob.php
Normal file
60
app/Jobs/ContainerStatusJob.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Actions\RemoteProcess\RunRemoteProcess;
|
||||
use App\Models\Application;
|
||||
use App\Models\Server;
|
||||
use App\Traits\Docker;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
use Tests\Support\Output;
|
||||
|
||||
class ContainerStatusJob implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$servers = Server::all()->reject(fn (Server $server) => $server->settings->is_build_server);
|
||||
$applications = Application::all();
|
||||
$not_found_applications = $applications;
|
||||
$containers = collect();
|
||||
foreach ($servers as $server) {
|
||||
$output = runRemoteCommandSync($server, ['docker ps -a -q --format \'{{json .}}\'']);
|
||||
$containers = $containers->concat(formatDockerCmdOutputToJson($output));
|
||||
}
|
||||
foreach ($containers as $container) {
|
||||
$found_application = $applications->filter(function ($value, $key) use ($container) {
|
||||
return $value->uuid == $container['Names'];
|
||||
})->first();
|
||||
if ($found_application) {
|
||||
$not_found_applications = $not_found_applications->filter(function ($value, $key) use ($found_application) {
|
||||
return $value->uuid != $found_application->uuid;
|
||||
});
|
||||
$found_application->status = $container['State'];
|
||||
$found_application->save();
|
||||
Log::info('Found application: ' . $found_application->uuid . '. Set status to: ' . $found_application->status);
|
||||
}
|
||||
}
|
||||
foreach ($not_found_applications as $not_found_application) {
|
||||
$not_found_application->status = 'exited';
|
||||
$not_found_application->save();
|
||||
Log::info('Not found application: ' . $not_found_application->uuid . '. Set status to: ' . $not_found_application->status);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,4 +18,7 @@ class Project extends BaseModel
|
||||
public function settings() {
|
||||
return $this->hasOne(ProjectSetting::class);
|
||||
}
|
||||
public function applications() {
|
||||
return $this->hasManyThrough(Application::class, Environment::class);
|
||||
}
|
||||
}
|
||||
|
@@ -4,8 +4,20 @@ namespace App\Models;
|
||||
|
||||
class Server extends BaseModel
|
||||
{
|
||||
protected static function booted()
|
||||
{
|
||||
static::created(function ($server) {
|
||||
ServerSetting::create([
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
});
|
||||
}
|
||||
public function privateKey()
|
||||
{
|
||||
return $this->belongsTo(PrivateKey::class);
|
||||
}
|
||||
public function settings()
|
||||
{
|
||||
return $this->hasOne(ServerSetting::class);
|
||||
}
|
||||
}
|
||||
|
11
app/Models/ServerSetting.php
Normal file
11
app/Models/ServerSetting.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class ServerSetting extends BaseModel
|
||||
{
|
||||
public function server()
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
}
|
||||
}
|
@@ -16,4 +16,7 @@ class Team extends BaseModel
|
||||
public function servers() {
|
||||
return $this->hasMany(Server::class);
|
||||
}
|
||||
public function applications() {
|
||||
return $this->hasManyThrough(Application::class, Project::class);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user