diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index 790f21efd..fbd62df91 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -41,6 +41,9 @@ public function __construct(Activity $activity) 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 @@ protected function getCommand(): string $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) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index e6b9960ec..2e89847f0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -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(); } /** diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index f3e987682..7e96700a0 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -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]); } } diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index d6cadf308..f9bc0e8bb 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -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 @@ public function environments() } 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]); } } diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 461fe0765..342e2e2f3 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -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 @@ private function generate_docker_compose() '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 @@ private function generate_jwt_token_for_github() 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 @@ public function deploy() $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 @@ public function deploy() $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(); + } } } diff --git a/app/Jobs/ContainerStatusJob.php b/app/Jobs/ContainerStatusJob.php new file mode 100644 index 000000000..b3432d3ec --- /dev/null +++ b/app/Jobs/ContainerStatusJob.php @@ -0,0 +1,60 @@ +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()); + } + } +} diff --git a/app/Models/Project.php b/app/Models/Project.php index 1b0a71049..e3f2f105b 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -18,4 +18,7 @@ public function environments() { public function settings() { return $this->hasOne(ProjectSetting::class); } + public function applications() { + return $this->hasManyThrough(Application::class, Environment::class); + } } diff --git a/app/Models/Server.php b/app/Models/Server.php index 2f5e67971..da302d056 100644 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -4,8 +4,20 @@ 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); + } } diff --git a/app/Models/ServerSetting.php b/app/Models/ServerSetting.php new file mode 100644 index 000000000..7b76e829c --- /dev/null +++ b/app/Models/ServerSetting.php @@ -0,0 +1,11 @@ +belongsTo(Server::class); + } +} diff --git a/app/Models/Team.php b/app/Models/Team.php index 3b05aa1ee..55ffe6afb 100644 --- a/app/Models/Team.php +++ b/app/Models/Team.php @@ -16,4 +16,7 @@ public function projects() { public function servers() { return $this->hasMany(Server::class); } + public function applications() { + return $this->hasManyThrough(Application::class, Project::class); + } } diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 941705cfa..b613cf109 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -5,6 +5,9 @@ use App\Enums\ActivityTypes; use App\Models\Server; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Process; use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Contracts\Activity; @@ -24,33 +27,105 @@ function remoteProcess( // @TODO: Check if the user has access to this server // checkTeam($server->team_id); - $temp_file = 'id.rsa_' . 'root' . '@' . $server->ip; - Storage::disk('local')->put($temp_file, $server->privateKey->private_key, 'private'); - $private_key_location = '/var/www/html/storage/app/' . $temp_file; + $private_key_location = savePrivateKey($server); return resolve(DispatchRemoteProcess::class, [ 'remoteProcessArgs' => new RemoteProcessArgs( + type: $deployment_uuid ? ActivityTypes::DEPLOYMENT->value : ActivityTypes::REMOTE_PROCESS->value, model: $model, server_ip: $server->ip, - private_key_location: $private_key_location, deployment_uuid: $deployment_uuid, + private_key_location: $private_key_location, command: <<port, user: $server->user, - type: $deployment_uuid ? ActivityTypes::DEPLOYMENT->value : ActivityTypes::REMOTE_PROCESS->value, ), ])(); } + // function checkTeam(string $team_id) + // { + // $found_team = auth()->user()->teams->pluck('id')->contains($team_id); + // if (!$found_team) { + // throw new \RuntimeException('You do not have access to this server.'); + // } + // } } -if (!function_exists('checkTeam')) { - function checkTeam(string $team_id) +if (!function_exists('savePrivateKey')) { + function savePrivateKey(Server $server) { - $found_team = auth()->user()->teams->pluck('id')->contains($team_id); - if (!$found_team) { - throw new \RuntimeException('You do not have access to this server.'); - } + $temp_file = 'id.rsa_' . 'root' . '@' . $server->ip; + Storage::disk('local')->put($temp_file, $server->privateKey->private_key, 'private'); + return '/var/www/html/storage/app/' . $temp_file; + } +} + +if (!function_exists('generateSshCommand')) { + function generateSshCommand(string $private_key_location, string $server_ip, string $user, string $port, string $command, bool $isMux = true) + { + $delimiter = 'EOF-COOLIFY-SSH'; + Storage::disk('local')->makeDirectory('.ssh'); + $ssh_command = "ssh "; + if ($isMux) { + $ssh_command .= '-o ControlMaster=auto -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r '; + } + $ssh_command .= "-i {$private_key_location} " + . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' + . '-o PasswordAuthentication=no ' + . '-o RequestTTY=no ' + . '-o LogLevel=ERROR ' + . "-p {$port} " + . "{$user}@{$server_ip} " + . " 'bash -se' << \\$delimiter" . PHP_EOL + . $command . PHP_EOL + . $delimiter; + + return $ssh_command; + } +} +if (!function_exists('formatDockerCmdOutputToJson')) { + function formatDockerCmdOutputToJson($rawOutput): Collection + { + $outputLines = explode(PHP_EOL, $rawOutput); + + return collect($outputLines) + ->reject(fn ($line) => empty($line)) + ->map(fn ($outputLine) => json_decode($outputLine, true, flags: JSON_THROW_ON_ERROR)); + } +} +if (!function_exists('formatDockerLabelsToJson')) { + function formatDockerLabelsToJson($rawOutput): Collection + { + $outputLines = explode(PHP_EOL, $rawOutput); + + return collect($outputLines) + ->reject(fn ($line) => empty($line)) + ->map(function ($outputLine) { + $outputArray = explode(',', $outputLine); + return collect($outputArray) + ->map(function ($outputLine) { + return explode('=', $outputLine); + }) + ->mapWithKeys(function ($outputLine) { + return [$outputLine[0] => $outputLine[1]]; + }); + })[0]; + } +} +if (!function_exists('runRemoteCommandSync')) { + function runRemoteCommandSync($server, array $command) { + $command_string = implode("\n", $command); + $private_key_location = savePrivateKey($server); + $ssh_command = generateSshCommand($private_key_location, $server->ip, $server->user, $server->port, $command_string); + $process = Process::run($ssh_command); + $output = trim($process->output()); + $exitCode = $process->exitCode(); + if ($exitCode !== 0) { + Log::error($output); + throw new \RuntimeException('There was an error running the command.'); + } + return $output; } } diff --git a/composer.lock b/composer.lock index 28478c6fd..87f668056 100644 --- a/composer.lock +++ b/composer.lock @@ -1193,16 +1193,16 @@ }, { "name": "laravel/framework", - "version": "v10.4.1", + "version": "v10.5.1", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "7d15f7eef442633cff108f83d9fe43d8c3b8b76f" + "reference": "485f22333e8c1dff5bae0fe0421c1e2e139713de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/7d15f7eef442633cff108f83d9fe43d8c3b8b76f", - "reference": "7d15f7eef442633cff108f83d9fe43d8c3b8b76f", + "url": "https://api.github.com/repos/laravel/framework/zipball/485f22333e8c1dff5bae0fe0421c1e2e139713de", + "reference": "485f22333e8c1dff5bae0fe0421c1e2e139713de", "shasum": "" }, "require": { @@ -1389,7 +1389,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-03-18T11:34:02+00:00" + "time": "2023-03-29T15:09:16+00:00" }, { "name": "laravel/sanctum", @@ -2683,16 +2683,16 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.7.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5" + "reference": "dfc078e8af9c99210337325ff5aa152872c98714" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", - "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714", + "reference": "dfc078e8af9c99210337325ff5aa152872c98714", "shasum": "" }, "require": { @@ -2735,9 +2735,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.0" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1" }, - "time": "2023-03-12T10:13:29+00:00" + "time": "2023-03-27T19:02:04+00:00" }, { "name": "phpoption/phpoption", @@ -3378,16 +3378,16 @@ }, { "name": "psy/psysh", - "version": "v0.11.13", + "version": "v0.11.14", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "722317c9f5627e588788e340f29b923e58f92f54" + "reference": "8c2e264def7a8263a68ef6f0b55ce90b77d41e17" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/722317c9f5627e588788e340f29b923e58f92f54", - "reference": "722317c9f5627e588788e340f29b923e58f92f54", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/8c2e264def7a8263a68ef6f0b55ce90b77d41e17", + "reference": "8c2e264def7a8263a68ef6f0b55ce90b77d41e17", "shasum": "" }, "require": { @@ -3448,9 +3448,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.11.13" + "source": "https://github.com/bobthecow/psysh/tree/v0.11.14" }, - "time": "2023-03-21T14:22:44+00:00" + "time": "2023-03-28T03:41:01+00:00" }, { "name": "ralouphie/getallheaders", @@ -7534,16 +7534,16 @@ }, { "name": "laravel/sail", - "version": "v1.21.2", + "version": "v1.21.3", "source": { "type": "git", "url": "https://github.com/laravel/sail.git", - "reference": "19d6fe167e2389b41fe1b4ee52293d1eaf8a43fc" + "reference": "3042ff8cf403817c340d5a7762b2d32900239f46" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/sail/zipball/19d6fe167e2389b41fe1b4ee52293d1eaf8a43fc", - "reference": "19d6fe167e2389b41fe1b4ee52293d1eaf8a43fc", + "url": "https://api.github.com/repos/laravel/sail/zipball/3042ff8cf403817c340d5a7762b2d32900239f46", + "reference": "3042ff8cf403817c340d5a7762b2d32900239f46", "shasum": "" }, "require": { @@ -7595,7 +7595,7 @@ "issues": "https://github.com/laravel/sail/issues", "source": "https://github.com/laravel/sail" }, - "time": "2023-03-06T14:23:15+00:00" + "time": "2023-03-13T01:22:10+00:00" }, { "name": "mockery/mockery", @@ -7889,16 +7889,16 @@ }, { "name": "pestphp/pest", - "version": "v2.2.3", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "6c8970e0a3b9bb36544bb1eacba0a4175dbafe97" + "reference": "5ae061d2080ea09608fe37fb05ebadcd183cef85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/6c8970e0a3b9bb36544bb1eacba0a4175dbafe97", - "reference": "6c8970e0a3b9bb36544bb1eacba0a4175dbafe97", + "url": "https://api.github.com/repos/pestphp/pest/zipball/5ae061d2080ea09608fe37fb05ebadcd183cef85", + "reference": "5ae061d2080ea09608fe37fb05ebadcd183cef85", "shasum": "" }, "require": { @@ -7908,10 +7908,10 @@ "pestphp/pest-plugin": "^2.0.1", "pestphp/pest-plugin-arch": "^2.0.2", "php": "^8.1.0", - "phpunit/phpunit": "^10.0.18" + "phpunit/phpunit": "^10.0.19" }, "conflict": { - "phpunit/phpunit": ">10.0.18", + "phpunit/phpunit": ">10.0.19", "webmozart/assert": "<1.11.0" }, "require-dev": { @@ -7972,7 +7972,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.2.3" + "source": "https://github.com/pestphp/pest/tree/v2.3.0" }, "funding": [ { @@ -7984,7 +7984,7 @@ "type": "github" } ], - "time": "2023-03-24T11:26:54+00:00" + "time": "2023-03-28T09:16:29+00:00" }, { "name": "pestphp/pest-plugin", @@ -8606,16 +8606,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.0.18", + "version": "10.0.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "582563ed2edc62d1455cdbe00ea49fe09428eef3" + "reference": "20c23e85c86e5c06d63538ba464e8054f4744e62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/582563ed2edc62d1455cdbe00ea49fe09428eef3", - "reference": "582563ed2edc62d1455cdbe00ea49fe09428eef3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/20c23e85c86e5c06d63538ba464e8054f4744e62", + "reference": "20c23e85c86e5c06d63538ba464e8054f4744e62", "shasum": "" }, "require": { @@ -8687,7 +8687,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.0.18" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.0.19" }, "funding": [ { @@ -8703,7 +8703,7 @@ "type": "tidelift" } ], - "time": "2023-03-22T06:15:31+00:00" + "time": "2023-03-27T11:46:33+00:00" }, { "name": "sebastian/cli-parser", diff --git a/database/migrations/2023_03_24_140712_create_server_settings_table.php b/database/migrations/2023_03_24_140712_create_server_settings_table.php new file mode 100644 index 000000000..a82f49a92 --- /dev/null +++ b/database/migrations/2023_03_24_140712_create_server_settings_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('uuid')->unique(); + $table->boolean('is_build_server')->default(false); + + $table->foreignId('server_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('server_settings'); + } +}; diff --git a/database/migrations/2023_03_27_081716_create_applications_table.php b/database/migrations/2023_03_27_081716_create_applications_table.php index 701a70c17..021f8f434 100644 --- a/database/migrations/2023_03_27_081716_create_applications_table.php +++ b/database/migrations/2023_03_27_081716_create_applications_table.php @@ -52,7 +52,7 @@ public function up(): void $table->integer('health_check_retries')->default(10); $table->integer('health_check_start_period')->default(5); - $table->string('status')->default('killed'); + $table->string('status')->default('exited'); $table->morphs('destination'); $table->morphs('source'); diff --git a/database/seeders/ApplicationSeeder.php b/database/seeders/ApplicationSeeder.php index ccfa74045..3a8fcde68 100644 --- a/database/seeders/ApplicationSeeder.php +++ b/database/seeders/ApplicationSeeder.php @@ -25,7 +25,7 @@ public function run(): void $github_private_source = GithubApp::find(2); Application::create([ 'id' => 1, - 'name' => 'My first application', + 'name' => 'Public application (from GitHub)', 'git_repository' => 'coollabsio/coolify-examples', 'git_branch' => 'nodejs-fastify', 'build_pack' => 'nixpacks', @@ -39,7 +39,7 @@ public function run(): void ]); Application::create([ 'id' => 2, - 'name' => 'My second application', + 'name' => 'Private application (through GitHub App)', 'git_repository' => 'coollabsio/nodejs-example', 'git_branch' => 'main', 'build_pack' => 'nixpacks', diff --git a/database/seeders/DBSeeder.php b/database/seeders/DBSeeder.php index 68bbeb01c..35effa0c6 100644 --- a/database/seeders/DBSeeder.php +++ b/database/seeders/DBSeeder.php @@ -13,12 +13,12 @@ public function run(): void { $environment_1 = Environment::find(1); $standalone_docker_1 = StandaloneDocker::find(1); - Database::create([ - 'id' => 1, - 'name'=> "My first database", - 'environment_id' => $environment_1->id, - 'destination_id' => $standalone_docker_1->id, - 'destination_type' => StandaloneDocker::class, - ]); + // Database::create([ + // 'id' => 1, + // 'name'=> "My first database", + // 'environment_id' => $environment_1->id, + // 'destination_id' => $standalone_docker_1->id, + // 'destination_type' => StandaloneDocker::class, + // ]); } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 00797ca1c..76395f2b0 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -14,6 +14,7 @@ public function run(): void TeamSeeder::class, PrivateKeySeeder::class, ServerSeeder::class, + ServerSettingSeeder::class, ProjectSeeder::class, ProjectSettingSeeder::class, EnvironmentSeeder::class, diff --git a/database/seeders/ServerSettingSeeder.php b/database/seeders/ServerSettingSeeder.php new file mode 100644 index 000000000..a7d5dd97d --- /dev/null +++ b/database/seeders/ServerSettingSeeder.php @@ -0,0 +1,25 @@ +load(['settings']); + $server_1->settings->is_build_server = true; + $server_1->settings->save(); + + $server_2 = Server::find(2)->load(['settings']); + $server_2->settings->is_build_server = true; + $server_2->settings->save(); + + } +} diff --git a/database/seeders/ServiceSeeder.php b/database/seeders/ServiceSeeder.php index f79b72144..360c946c5 100644 --- a/database/seeders/ServiceSeeder.php +++ b/database/seeders/ServiceSeeder.php @@ -16,12 +16,12 @@ public function run(): void { $environment_1 = Environment::find(1); $standalone_docker_1 = StandaloneDocker::find(1); - Service::create([ - 'id' => 1, - 'name'=> "My first service", - 'environment_id' => $environment_1->id, - 'destination_id' => $standalone_docker_1->id, - 'destination_type' => StandaloneDocker::class, - ]); + // Service::create([ + // 'id' => 1, + // 'name'=> "My first service", + // 'environment_id' => $environment_1->id, + // 'destination_id' => $standalone_docker_1->id, + // 'destination_type' => StandaloneDocker::class, + // ]); } } diff --git a/docker/builder/Dockerfile b/docker/builder/Dockerfile index 32099603b..bbeca59b1 100644 --- a/docker/builder/Dockerfile +++ b/docker/builder/Dockerfile @@ -22,5 +22,5 @@ RUN curl -sSL https://nixpacks.com/install.sh | bash RUN chmod +x ~/.docker/cli-plugins/docker-compose /usr/bin/docker /usr/local/bin/pack ENTRYPOINT ["/sbin/tini", "--"] -CMD ["sh", "-c", "while true; do sleep 1000; done"] +CMD ["sh", "-c", "while true; do sleep 69420; done"] diff --git a/docker/dev/supervisord.conf b/docker/dev/supervisord.conf index 8664759b2..b88d3ffa0 100644 --- a/docker/dev/supervisord.conf +++ b/docker/dev/supervisord.conf @@ -27,3 +27,16 @@ stderr_logfile_maxbytes=0 #redirect_stderr=true #stdout_logfile=/var/www/html/storage/logs/worker.log #stopwaitsecs=3600 + +[program:laravel-schedule] +process_name=%(program_name)s_%(process_num)02d +command=/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan schedule:work +user=sail +autostart=true +autorestart=true +stopasgroup=true +killasgroup=true +numprocs=1 +redirect_stderr=true +stdout_logfile=/var/www/html/storage/logs/worker.log +stopwaitsecs=3600 diff --git a/resources/views/livewire/demo-deploy-application.blade.php b/resources/views/livewire/demo-deploy-application.blade.php deleted file mode 100644 index 628c5de78..000000000 --- a/resources/views/livewire/demo-deploy-application.blade.php +++ /dev/null @@ -1,9 +0,0 @@ -
- @isset($activity?->id) -
- Activity: {{ $activity?->id ?? 'waiting' }} -
-
{{ data_get($activity, 'description') }}
- @endisset - -
diff --git a/resources/views/livewire/deploy-application.blade.php b/resources/views/livewire/deploy-application.blade.php index 27d01c442..21ba7248e 100644 --- a/resources/views/livewire/deploy-application.blade.php +++ b/resources/views/livewire/deploy-application.blade.php @@ -1,4 +1,6 @@
- + + + status: {{ $application->status }}
diff --git a/resources/views/livewire/poll-activity.blade.php b/resources/views/livewire/poll-activity.blade.php index fc3eeed34..389483dc1 100644 --- a/resources/views/livewire/poll-activity.blade.php +++ b/resources/views/livewire/poll-activity.blade.php @@ -2,4 +2,5 @@ @isset($activity?->id)
{{ data_get($activity, 'description') }}
@endisset + {{--
{{ data_get($activity, 'properties') }}
--}} diff --git a/resources/views/project/application.blade.php b/resources/views/project/application.blade.php index db9ba59ee..716fb3765 100644 --- a/resources/views/project/application.blade.php +++ b/resources/views/project/application.blade.php @@ -1,14 +1,14 @@

Application

-

Name: {{ $project->name }}

-

UUID: {{ $project->uuid }}

+

Name: {{ $application->name }}

-

Deployments

+

Deployments

@foreach ($deployments as $deployment)

{{ data_get($deployment->properties, 'deployment_uuid') }} + {{ data_get($deployment->properties, 'status') }}

@endforeach
diff --git a/resources/views/project/deployment.blade.php b/resources/views/project/deployment.blade.php index 4d58b00ac..c49e8112e 100644 --- a/resources/views/project/deployment.blade.php +++ b/resources/views/project/deployment.blade.php @@ -1,7 +1,4 @@

Deployment

-

Name: {{ $project->name }}

-

UUID: {{ $project->uuid }}

-
diff --git a/resources/views/project/environments.blade.php b/resources/views/project/environments.blade.php index bf9efb655..ceb0a579c 100644 --- a/resources/views/project/environments.blade.php +++ b/resources/views/project/environments.blade.php @@ -1,6 +1,5 @@

Environments

- @foreach ($project->environments as $environment)
diff --git a/resources/views/project/resources.blade.php b/resources/views/project/resources.blade.php index cdc5946ef..cf451b2c5 100644 --- a/resources/views/project/resources.blade.php +++ b/resources/views/project/resources.blade.php @@ -8,7 +8,7 @@

@endforeach - @foreach ($environment->databases as $database) + {{-- @foreach ($environment->databases as $database)

{{ $database->name }} @@ -21,6 +21,6 @@ {{ $service->name }}

- @endforeach + @endforeach --}}
diff --git a/routes/web.php b/routes/web.php index 067b0536f..c2ce8690b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -26,8 +26,8 @@ Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}', [ProjectController::class, 'application'])->name('project.application'); Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/deployment/{deployment_uuid}', [ProjectController::class, 'deployment'])->name('project.deployment'); - Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}', [ProjectController::class, 'database'])->name('project.database'); - Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', [ProjectController::class, 'service'])->name('project.service'); + // Route::get('/database/{database_uuid}', [ProjectController::class, 'database'])->name('project.database'); + // Route::get('//service/{service_uuid}', [ProjectController::class, 'service'])->name('project.service'); Route::get('/profile', function () { return view('profile'); diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index 3f3595f59..f7b88de6c 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -46,7 +46,7 @@ // Assert there's no containers start with coolify_test_* $activity = remoteProcess([$areThereCoolifyTestContainers], $host); - $containers = Output::containerList($activity->getExtraProperty('stdout')); + $containers = formatDockerCmdOutputToJson($activity->getExtraProperty('stdout')); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName @@ -55,7 +55,7 @@ // docker ps name = $container $activity = remoteProcess([$areThereCoolifyTestContainers], $host); - $containers = Output::containerList($activity->getExtraProperty('stdout')); + $containers = formatDockerCmdOutputToJson($activity->getExtraProperty('stdout')); expect($containers->where('Names', $containerName)->count())->toBe(1); // Stop testing containers diff --git a/tests/Support/Output.php b/tests/Support/Output.php deleted file mode 100644 index a3bd2c52e..000000000 --- a/tests/Support/Output.php +++ /dev/null @@ -1,17 +0,0 @@ -reject(fn($line) => empty($line)) - ->map(fn($outputLine) => json_decode($outputLine, flags: JSON_THROW_ON_ERROR)); - } -}