From 78c434458335bdbc5300cbace1fea0a1d0000c45 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 29 Mar 2023 12:27:02 +0200 Subject: [PATCH] feat: add deployments as activity fix: tests refactor: remoteProcess --- .../RemoteProcess/DispatchRemoteProcess.php | 21 ++++++++--- .../RemoteProcess/RunRemoteProcess.php | 6 ++-- app/Data/RemoteProcessArgs.php | 20 ++++++----- app/Enums/ActivityTypes.php | 2 +- app/Http/Controllers/ProjectController.php | 5 +-- app/Http/Livewire/DeployApplication.php | 9 +++-- app/Http/Livewire/PollActivity.php | 6 +--- app/Http/Livewire/RunCommand.php | 20 +++++------ app/Models/Application.php | 7 ++-- bootstrap/helpers.php | 36 +++++++++---------- database/seeders/ServerSeeder.php | 2 +- .../views/livewire/poll-activity.blade.php | 3 -- .../views/livewire/run-command.blade.php | 9 +---- resources/views/project/deployment.blade.php | 5 ++- tests/Feature/DockerCommandsTest.php | 11 +++--- 15 files changed, 81 insertions(+), 81 deletions(-) diff --git a/app/Actions/RemoteProcess/DispatchRemoteProcess.php b/app/Actions/RemoteProcess/DispatchRemoteProcess.php index 349c847c4..0f9d60192 100644 --- a/app/Actions/RemoteProcess/DispatchRemoteProcess.php +++ b/app/Actions/RemoteProcess/DispatchRemoteProcess.php @@ -10,10 +10,23 @@ class DispatchRemoteProcess { protected Activity $activity; - public function __construct(RemoteProcessArgs $remoteProcessArgs){ - $this->activity = activity() - ->withProperties($remoteProcessArgs->toArray()) - ->log(""); + public function __construct(RemoteProcessArgs $remoteProcessArgs) + { + if ($remoteProcessArgs->model) { + $properties = $remoteProcessArgs->toArray(); + unset($properties['model']); + + $this->activity = activity() + ->withProperties($properties) + ->performedOn($remoteProcessArgs->model) + ->event('deployment') + ->log(""); + } else { + $this->activity = activity() + ->withProperties($remoteProcessArgs->toArray()) + ->event('remote_process') + ->log(""); + } } public function __invoke(): Activity diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index da2eeb8bc..14b9190e1 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -31,7 +31,7 @@ class RunRemoteProcess */ public function __construct(Activity $activity) { - if ($activity->getExtraProperty('type') !== ActivityTypes::COOLIFY_PROCESS->value) { + if ($activity->getExtraProperty('type') !== ActivityTypes::REMOTE_PROCESS->value) { throw new \RuntimeException('Incompatible Activity to run a remote command.'); } @@ -64,7 +64,7 @@ public function __invoke(): ProcessResult protected function getCommand(): string { $user = $this->activity->getExtraProperty('user'); - $destination = $this->activity->getExtraProperty('destination'); + $server_ip = $this->activity->getExtraProperty('server_ip'); $private_key_location = $this->activity->getExtraProperty('private_key_location'); $port = $this->activity->getExtraProperty('port'); $command = $this->activity->getExtraProperty('command'); @@ -80,7 +80,7 @@ protected function getCommand(): string . '-o LogLevel=ERROR ' . '-o ControlMaster=auto -o ControlPersist=yes -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' . "-p {$port} " - . "{$user}@{$destination} " + . "{$user}@{$server_ip} " . " 'bash -se' << \\$delimiter" . PHP_EOL . $command . PHP_EOL . $delimiter; diff --git a/app/Data/RemoteProcessArgs.php b/app/Data/RemoteProcessArgs.php index 139b94c71..57c46d813 100644 --- a/app/Data/RemoteProcessArgs.php +++ b/app/Data/RemoteProcessArgs.php @@ -4,17 +4,21 @@ use App\Enums\ActivityTypes; use App\Enums\ProcessStatus; +use Illuminate\Database\Eloquent\Model; use Spatie\LaravelData\Data; class RemoteProcessArgs extends Data { public function __construct( - public string $destination, - public string $private_key_location, - public string $command, - public int $port, - public string $user, - public string $type = ActivityTypes::COOLIFY_PROCESS->value, - public string $status = ProcessStatus::HOLDING->value, - ){} + public Model|null $model, + public string $server_ip, + public string $private_key_location, + public string|null $deployment_uuid, + public string $command, + public int $port, + public string $user, + public string $type = ActivityTypes::REMOTE_PROCESS->value, + public string $status = ProcessStatus::HOLDING->value, + ) { + } } diff --git a/app/Enums/ActivityTypes.php b/app/Enums/ActivityTypes.php index 52a35e2f8..ad1c10c7a 100644 --- a/app/Enums/ActivityTypes.php +++ b/app/Enums/ActivityTypes.php @@ -4,5 +4,5 @@ enum ActivityTypes: string { - case COOLIFY_PROCESS = 'coolify_process'; + case REMOTE_PROCESS = 'remote_process'; } diff --git a/app/Http/Controllers/ProjectController.php b/app/Http/Controllers/ProjectController.php index b479a6d19..43b17430c 100644 --- a/app/Http/Controllers/ProjectController.php +++ b/app/Http/Controllers/ProjectController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class ProjectController extends Controller { @@ -103,7 +104,7 @@ public function deployment() if (!$application) { return redirect()->route('home'); } - $deployment = $application->deployments->where('uuid', $deployment_uuid)->first(); - return view('project.deployment', ['project' => $project, 'deployment' => $deployment]); + $activity = $application->get_deployment($deployment_uuid); + return view('project.deployment', ['project' => $project, 'activity' => $activity]); } } diff --git a/app/Http/Livewire/DeployApplication.php b/app/Http/Livewire/DeployApplication.php index 6df06cc9e..e6889f1e4 100644 --- a/app/Http/Livewire/DeployApplication.php +++ b/app/Http/Livewire/DeployApplication.php @@ -21,7 +21,7 @@ private function execute_in_builder(string $command) } private function start_builder_container() { - $this->command[] = "docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder >/dev/null"; + $this->command[] = "docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder >/dev/null 2>&1"; } public function deploy() { @@ -36,18 +36,17 @@ public function deploy() $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; // Create Deployment ID - $this->deployment_uuid = new Cuid2(10); + $this->deployment_uuid = new Cuid2(12); $workdir = "/artifacts/{$this->deployment_uuid}"; // Start build process $this->command[] = "echo 'Starting deployment of {$application->name} ({$application->uuid})'"; $this->start_builder_container(); - $this->execute_in_builder('hostname'); + // $this->execute_in_builder('hostname'); $this->execute_in_builder("git clone -b {$application->git_branch} {$source->html_url}/{$application->git_repository}.git {$workdir}"); $this->execute_in_builder("ls -l {$workdir}"); $this->command[] = "docker stop -t 0 {$this->deployment_uuid} >/dev/null"; - - $this->activity = remoteProcess(implode("\n", $this->command), $destination->server->name); + $this->activity = remoteProcess($this->command, $destination->server, $this->deployment_uuid, $application); // Create Deployment Deployment::create([ diff --git a/app/Http/Livewire/PollActivity.php b/app/Http/Livewire/PollActivity.php index c754cca00..3a7822d8a 100644 --- a/app/Http/Livewire/PollActivity.php +++ b/app/Http/Livewire/PollActivity.php @@ -3,16 +3,12 @@ namespace App\Http\Livewire; use Livewire\Component; -use Spatie\Activitylog\Models\Activity; class PollActivity extends Component { public $activity; - public $activity_log_id; public $isKeepAliveOn = true; - public function mount() { - $this->activity = Activity::find($this->activity_log_id); - } + public function polling() { $this->activity?->refresh(); diff --git a/app/Http/Livewire/RunCommand.php b/app/Http/Livewire/RunCommand.php index 3e4db9e97..5bb84a56f 100755 --- a/app/Http/Livewire/RunCommand.php +++ b/app/Http/Livewire/RunCommand.php @@ -19,11 +19,13 @@ class RunCommand extends Component public $servers = []; + protected $rules = [ + 'server' => 'required', + ]; public function mount() { - $this->servers = Server::all()->pluck('name')->toArray(); - $this->server = $this->servers[0]; - + $this->servers = Server::all(); + $this->server = $this->servers[0]->uuid; } public function render() { @@ -33,25 +35,19 @@ public function render() public function runCommand() { $this->isKeepAliveOn = true; - - $this->activity = remoteProcess($this->command, $this->server); + $this->activity = remoteProcess([$this->command], Server::where('uuid', $this->server)->first()); } public function runSleepingBeauty() { $this->isKeepAliveOn = true; - - $this->activity = remoteProcess('x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', $this->server); + $this->activity = remoteProcess(['x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done'], Server::where('uuid', $this->server)->first()); } public function runDummyProjectBuild() { $this->isKeepAliveOn = true; - - $this->activity = remoteProcess(<<server); + $this->activity = remoteProcess([' cd projects/dummy-project', 'docker-compose build --no-cache'], Server::where('uuid', $this->server)->first()); } public function polling() diff --git a/app/Models/Application.php b/app/Models/Application.php index 78d3d9c96..afd52ae90 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -2,6 +2,8 @@ namespace App\Models; +use Spatie\Activitylog\Models\Activity; + class Application extends BaseModel { public function environment() @@ -20,8 +22,9 @@ public function source() { return $this->morphTo(); } - public function deployments() + + public function get_deployment(string $deployment_uuid) { - return $this->morphMany(Deployment::class, 'type'); + return Activity::where('subject_id', $this->id)->where('properties->deployment_uuid', '=', $deployment_uuid)->first(); } } diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 67c650b54..0b9498831 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -3,6 +3,7 @@ use App\Actions\RemoteProcess\DispatchRemoteProcess; use App\Data\RemoteProcessArgs; use App\Models\Server; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Storage; use Spatie\Activitylog\Contracts\Activity; @@ -13,36 +14,33 @@ * */ function remoteProcess( - string $command, - string $destination + array $command, + Server $server, + string|null $deployment_uuid = null, + Model|null $model = null, ): Activity { - $found_server = checkServer($destination); - checkTeam($found_server->team_id); + $command_string = implode("\n", $command); + // @TODO: Check if the user has access to this server + // checkTeam($server->team_id); - $temp_file = 'id.rsa_' . 'root' . '@' . $found_server->ip; - Storage::disk('local')->put($temp_file, $found_server->privateKey->private_key, 'private'); + $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; + return resolve(DispatchRemoteProcess::class, [ 'remoteProcessArgs' => new RemoteProcessArgs( - destination: $found_server->ip, + model: $model, + server_ip: $server->ip, + deployment_uuid: $deployment_uuid, private_key_location: $private_key_location, command: <<port, - user: $found_server->user, + port: $server->port, + user: $server->user, ), ])(); } - function checkServer(string $destination) - { - // @TODO: Use UUID instead of name - $found_server = Server::where('name', $destination)->first(); - if (!$found_server) { - throw new \RuntimeException('Server not found.'); - }; - return $found_server; - } function checkTeam(string $team_id) { $found_team = auth()->user()->teams->pluck('id')->contains($team_id); diff --git a/database/seeders/ServerSeeder.php b/database/seeders/ServerSeeder.php index 1a6514139..548856ba7 100644 --- a/database/seeders/ServerSeeder.php +++ b/database/seeders/ServerSeeder.php @@ -37,7 +37,7 @@ public function run(): void 'id' => 3, 'name' => "localhost", 'description' => "This is the local machine", - 'user' => 'andrasbacsai', + 'user' => 'root', 'ip' => "172.17.0.1", 'team_id' => $root_team->id, 'private_key_id' => $private_key_1->id, diff --git a/resources/views/livewire/poll-activity.blade.php b/resources/views/livewire/poll-activity.blade.php index 64e8a843d..fc3eeed34 100644 --- a/resources/views/livewire/poll-activity.blade.php +++ b/resources/views/livewire/poll-activity.blade.php @@ -1,8 +1,5 @@
@isset($activity?->id) -
- Activity: {{ $activity?->id ?? 'waiting' }} -
{{ data_get($activity, 'description') }}
@endisset
diff --git a/resources/views/livewire/run-command.blade.php b/resources/views/livewire/run-command.blade.php index 6482fc298..085bc9bb7 100755 --- a/resources/views/livewire/run-command.blade.php +++ b/resources/views/livewire/run-command.blade.php @@ -4,7 +4,7 @@ @@ -21,13 +21,6 @@ @endif @isset($activity?->id) -
- Activity: {{ $activity?->id ?? 'waiting' }} -
{{ data_get($activity, 'description') }}
- {{--
-
Details:
-
{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}
-
--}} @endisset diff --git a/resources/views/project/deployment.blade.php b/resources/views/project/deployment.blade.php index 5ca6091fa..4d58b00ac 100644 --- a/resources/views/project/deployment.blade.php +++ b/resources/views/project/deployment.blade.php @@ -2,7 +2,6 @@

Deployment

Name: {{ $project->name }}

UUID: {{ $project->uuid }}

- -

Deployment UUID: {{ $deployment->uuid }}

- + + diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index 8fc551a04..a8418efc1 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -1,5 +1,6 @@ format('Ymd_his'); - $host = 'testing-host'; + $host = Server::where('name', 'testing-local-docker-container')->first(); // Assert there's no containers start with coolify_test_* - $activity = remoteProcess($areThereCoolifyTestContainers, $host); + $activity = remoteProcess([$areThereCoolifyTestContainers], $host); $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName - $activity = remoteProcess("docker run -d --rm --name {$containerName} nginx", $host); + $activity = remoteProcess(["docker run -d --rm --name {$containerName} nginx"], $host); expect($activity->getExtraProperty('exitCode'))->toBe(0); // docker ps name = $container - $activity = remoteProcess($areThereCoolifyTestContainers, $host); + $activity = remoteProcess([$areThereCoolifyTestContainers], $host); $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers->where('Names', $containerName)->count())->toBe(1); // Stop testing containers - $activity = remoteProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host); + $activity = remoteProcess(["docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)"], $host); expect($activity->getExtraProperty('exitCode'))->toBe(0); });