From 4517ca7d2a39a3e84deee8acea2cf0b135f1bc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Borja=20Jim=C3=A9nez?= Date: Sun, 14 Apr 2024 14:34:47 +0200 Subject: [PATCH] Feature/add remote server logs (#159) --- app/Actions/Server/CreateServerLog.php | 35 +++++++++++ app/Http/Controllers/ServerController.php | 1 - app/Http/Controllers/ServerLogController.php | 31 ++++++++++ app/Http/Controllers/SiteLogController.php | 1 + app/Models/ServerLog.php | 17 ++++++ app/SSH/OS/OS.php | 14 +++-- app/SSH/OS/scripts/read-file.sh | 8 ++- ...001_add_is_remote_to_server_logs_table.php | 28 +++++++++ resources/views/application/deploy.blade.php | 3 +- .../o-document-magnifying-glass.blade.php | 14 +++++ .../heroicons/o-play-circle.blade.php | 15 +++++ resources/views/layouts/server.blade.php | 9 +++ resources/views/layouts/sidebar.blade.php | 2 +- resources/views/layouts/site.blade.php | 4 +- resources/views/server-logs/index.blade.php | 7 ++- .../server-logs/partials/add-log.blade.php | 59 +++++++++++++++++++ .../server-logs/partials/header.blade.php | 54 +++++++++++++++++ ...ist.blade.php => logs-list-live.blade.php} | 57 +++++++++++++++--- .../views/server-logs/remote-logs.blade.php | 6 ++ .../servers/partials/show-server.blade.php | 2 +- resources/views/site-logs/index.blade.php | 4 +- resources/views/sites/installing.blade.php | 2 +- routes/server.php | 3 + tests/Feature/LogsTest.php | 33 +++++++++++ tests/Feature/SitesTest.php | 2 +- 25 files changed, 385 insertions(+), 26 deletions(-) create mode 100755 app/Actions/Server/CreateServerLog.php create mode 100644 database/migrations/2024_04_07_204001_add_is_remote_to_server_logs_table.php create mode 100644 resources/views/components/heroicons/o-document-magnifying-glass.blade.php create mode 100644 resources/views/components/heroicons/o-play-circle.blade.php create mode 100644 resources/views/server-logs/partials/add-log.blade.php create mode 100644 resources/views/server-logs/partials/header.blade.php rename resources/views/server-logs/partials/{logs-list.blade.php => logs-list-live.blade.php} (52%) create mode 100644 resources/views/server-logs/remote-logs.blade.php diff --git a/app/Actions/Server/CreateServerLog.php b/app/Actions/Server/CreateServerLog.php new file mode 100755 index 0000000..9f63b31 --- /dev/null +++ b/app/Actions/Server/CreateServerLog.php @@ -0,0 +1,35 @@ +validate($input); + + $server->logs()->create([ + 'is_remote' => true, + 'name' => $input['path'], + 'type' => 'remote', + 'disk' => 'ssh', + ]); + } + + /** + * @throws ValidationException + */ + protected function validate(array $input): void + { + Validator::make($input, [ + 'path' => 'required', + ])->validate(); + } +} diff --git a/app/Http/Controllers/ServerController.php b/app/Http/Controllers/ServerController.php index 8892642..0e6e67f 100644 --- a/app/Http/Controllers/ServerController.php +++ b/app/Http/Controllers/ServerController.php @@ -54,7 +54,6 @@ public function show(Server $server): View { return view('servers.show', [ 'server' => $server, - 'logs' => $server->logs()->latest()->limit(10)->get(), ]); } diff --git a/app/Http/Controllers/ServerLogController.php b/app/Http/Controllers/ServerLogController.php index 7639c80..933c393 100644 --- a/app/Http/Controllers/ServerLogController.php +++ b/app/Http/Controllers/ServerLogController.php @@ -2,10 +2,13 @@ namespace App\Http\Controllers; +use App\Actions\Server\CreateServerLog; +use App\Facades\Toast; use App\Models\Server; use App\Models\ServerLog; use Illuminate\Contracts\View\View; use Illuminate\Http\RedirectResponse; +use Illuminate\Http\Request; class ServerLogController extends Controller { @@ -13,6 +16,7 @@ public function index(Server $server): View { return view('server-logs.index', [ 'server' => $server, + 'pageTitle' => __('Vito Logs'), ]); } @@ -26,4 +30,31 @@ public function show(Server $server, ServerLog $serverLog): RedirectResponse 'content' => $serverLog->getContent(), ]); } + + public function remote(Server $server): View + { + return view('server-logs.remote-logs', [ + 'server' => $server, + 'remote' => true, + 'pageTitle' => __('Remote Logs'), + ]); + } + + public function store(Server $server, Request $request): \App\Helpers\HtmxResponse + { + app(CreateServerLog::class)->create($server, $request->input()); + + Toast::success('Log added successfully.'); + + return htmx()->redirect(route('servers.logs.remote', ['server' => $server])); + } + + public function destroy(Server $server, ServerLog $serverLog): RedirectResponse + { + $serverLog->delete(); + + Toast::success('Remote log deleted successfully.'); + + return redirect()->route('servers.logs.remote', ['server' => $server]); + } } diff --git a/app/Http/Controllers/SiteLogController.php b/app/Http/Controllers/SiteLogController.php index 349f894..79c89b0 100644 --- a/app/Http/Controllers/SiteLogController.php +++ b/app/Http/Controllers/SiteLogController.php @@ -13,6 +13,7 @@ public function index(Server $server, Site $site): View return view('site-logs.index', [ 'server' => $server, 'site' => $site, + 'pageTitle' => __('Vito Logs'), ]); } } diff --git a/app/Models/ServerLog.php b/app/Models/ServerLog.php index 2efee2c..a78e8ab 100755 --- a/app/Models/ServerLog.php +++ b/app/Models/ServerLog.php @@ -27,11 +27,13 @@ class ServerLog extends AbstractModel 'type', 'name', 'disk', + 'is_remote', ]; protected $casts = [ 'server_id' => 'integer', 'site_id' => 'integer', + 'is_remote' => 'boolean', ]; public static function boot(): void @@ -64,6 +66,17 @@ public function site(): BelongsTo return $this->belongsTo(Site::class); } + public static function getRemote($query, bool $active = true, ?Site $site = null) + { + $query->where('is_remote', $active); + + if ($site) { + $query->where('name', 'like', $site->path.'%'); + } + + return $query; + } + public function write($buf): void { if (Str::contains($buf, 'VITO_SSH_ERROR')) { @@ -78,6 +91,10 @@ public function write($buf): void public function getContent(): ?string { + if ($this->is_remote) { + return $this->server->os()->readFile($this->name, 150); + } + if (Storage::disk($this->disk)->exists($this->name)) { return Storage::disk($this->disk)->get($this->name); } diff --git a/app/SSH/OS/OS.php b/app/SSH/OS/OS.php index ae07ce9..b91b8cd 100644 --- a/app/SSH/OS/OS.php +++ b/app/SSH/OS/OS.php @@ -108,12 +108,18 @@ public function editFile(string $path, ?string $content = null): void ); } - public function readFile(string $path): string + public function readFile(string $path, ?int $lastLines = null): string { + $params = [ + 'path' => $path, + ]; + + if ($lastLines !== null) { + $params['lines'] = $lastLines; + } + return $this->server->ssh()->exec( - $this->getScript('read-file.sh', [ - 'path' => $path, - ]) + $this->getScript('read-file.sh', $params) ); } diff --git a/app/SSH/OS/scripts/read-file.sh b/app/SSH/OS/scripts/read-file.sh index becea3d..3f8ff75 100644 --- a/app/SSH/OS/scripts/read-file.sh +++ b/app/SSH/OS/scripts/read-file.sh @@ -1 +1,7 @@ -[ -f __path__ ] && cat __path__ +if [ -f __path__ ]; then + if [ -n __lines__ ]; then + sudo tail -n __lines__ __path__ + else + sudo cat __path__ + fi +fi diff --git a/database/migrations/2024_04_07_204001_add_is_remote_to_server_logs_table.php b/database/migrations/2024_04_07_204001_add_is_remote_to_server_logs_table.php new file mode 100644 index 0000000..1e8e165 --- /dev/null +++ b/database/migrations/2024_04_07_204001_add_is_remote_to_server_logs_table.php @@ -0,0 +1,28 @@ +boolean('is_remote')->default(false); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('server_logs', function (Blueprint $table) { + $table->dropColumn('is_remote'); + }); + } +}; diff --git a/resources/views/application/deploy.blade.php b/resources/views/application/deploy.blade.php index 5afc280..7534029 100644 --- a/resources/views/application/deploy.blade.php +++ b/resources/views/application/deploy.blade.php @@ -6,8 +6,9 @@ hx-swap="outerHTML" hx-select="#deploy" > - + {{ __("Deploy") }} + @endif diff --git a/resources/views/components/heroicons/o-document-magnifying-glass.blade.php b/resources/views/components/heroicons/o-document-magnifying-glass.blade.php new file mode 100644 index 0000000..1667bdf --- /dev/null +++ b/resources/views/components/heroicons/o-document-magnifying-glass.blade.php @@ -0,0 +1,14 @@ + + + diff --git a/resources/views/components/heroicons/o-play-circle.blade.php b/resources/views/components/heroicons/o-play-circle.blade.php new file mode 100644 index 0000000..59c9979 --- /dev/null +++ b/resources/views/components/heroicons/o-play-circle.blade.php @@ -0,0 +1,15 @@ + + + + diff --git a/resources/views/layouts/server.blade.php b/resources/views/layouts/server.blade.php index d6d3572..61d66fa 100644 --- a/resources/views/layouts/server.blade.php +++ b/resources/views/layouts/server.blade.php @@ -5,6 +5,15 @@

{{ $server->name }}

+ + @if (isset($header)) +
+
+ {{ $header }} +
+
+ @endif +
@include("servers.partials.server-status") diff --git a/resources/views/layouts/sidebar.blade.php b/resources/views/layouts/sidebar.blade.php index dbced91..8cfb9f7 100644 --- a/resources/views/layouts/sidebar.blade.php +++ b/resources/views/layouts/sidebar.blade.php @@ -155,7 +155,7 @@ class="fixed left-0 top-0 z-40 h-screen w-64 -translate-x-full border-r border-g
  • diff --git a/resources/views/layouts/site.blade.php b/resources/views/layouts/site.blade.php index 1cb6bfb..dbde651 100644 --- a/resources/views/layouts/site.blade.php +++ b/resources/views/layouts/site.blade.php @@ -50,7 +50,7 @@ class="mr-1" @@ -105,7 +105,7 @@ class="flex w-full cursor-pointer items-center rounded-md border border-gray-300 Logs diff --git a/resources/views/server-logs/index.blade.php b/resources/views/server-logs/index.blade.php index af6d8ac..908e992 100644 --- a/resources/views/server-logs/index.blade.php +++ b/resources/views/server-logs/index.blade.php @@ -1,5 +1,8 @@ - {{ $server->name }} Logs + @if (isset($pageTitle)) + {{ $server->name }} - {{ $pageTitle }} + @endif - @include("server-logs.partials.logs-list") + @include("server-logs.partials.header") + @include("server-logs.partials.logs-list-live") diff --git a/resources/views/server-logs/partials/add-log.blade.php b/resources/views/server-logs/partials/add-log.blade.php new file mode 100644 index 0000000..f7a3480 --- /dev/null +++ b/resources/views/server-logs/partials/add-log.blade.php @@ -0,0 +1,59 @@ +
    + + {{ __("Manage your remote logs") }} + + {{ __("Here you can add new logs") }} + + +
    + + {{ __("Add Remote Log") }} + + + +
    $server]) }}" + hx-select="#add-log-form" + hx-swap="outerHTML" + class="p-6" + > +

    + {{ __("Add Remote Log") }} +

    + +
    + + + + @foreach ($server->sites as $site) + + @endforeach + + @error("path") + + @enderror +
    + +
    + + {{ __("Cancel") }} + + + + {{ __("Save") }} + +
    +
    +
    +
    +
    +
    +
    diff --git a/resources/views/server-logs/partials/header.blade.php b/resources/views/server-logs/partials/header.blade.php new file mode 100644 index 0000000..a67e01a --- /dev/null +++ b/resources/views/server-logs/partials/header.blade.php @@ -0,0 +1,54 @@ +@if (isset($pageTitle)) + {{ $pageTitle }} - {{ $server->name }} +@endif + + + +
    + + +
    + Select + +
    +
    + + + + {{ __("Vito Logs") }} + + + + {{ __("Remote Logs") }} + + +
    +
    +
    diff --git a/resources/views/server-logs/partials/logs-list.blade.php b/resources/views/server-logs/partials/logs-list-live.blade.php similarity index 52% rename from resources/views/server-logs/partials/logs-list.blade.php rename to resources/views/server-logs/partials/logs-list-live.blade.php index a6794bb..a7f4f60 100644 --- a/resources/views/server-logs/partials/logs-list.blade.php +++ b/resources/views/server-logs/partials/logs-list-live.blade.php @@ -1,31 +1,54 @@ @php - if (isset($site)) { - $logs = $site - ->logs() + if (isset($site) && ! isset($remote)) { + $logs = \App\Models\ServerLog::getRemote($site->logs(), false) + ->latest() + ->paginate(10); + } elseif (isset($remote)) { + $logs = \App\Models\ServerLog::getRemote($server->logs()) ->latest() ->paginate(10); } else { - $logs = $server - ->logs() + $logs = \App\Models\ServerLog::getRemote($server->logs(), false) ->latest() ->paginate(10); } @endphp -
    +
    - {{ __("Logs") }} + + {{ $pageTitle ?? "Logs" }} + - {{ __("Event") }} + + @isset($remote) + {{ __("Path") }} + @else + {{ __("Event") }} + @endisset + {{ __("Date") }} @foreach ($logs as $log) - {{ $log->type }} + + @isset($remote) + {{ $log->name }} + @else + {{ $log->type }} + @if (data_get($log, "type") === "remote") + + {{ $log->name }} + + @endif + @endif + @@ -38,6 +61,14 @@ > + + @if (isset($remote) && ! isset($site)) + + + + @endif @endforeach @@ -48,6 +79,7 @@
    @endif +

    @@ -67,4 +99,11 @@

    +
  • diff --git a/resources/views/server-logs/remote-logs.blade.php b/resources/views/server-logs/remote-logs.blade.php new file mode 100644 index 0000000..8ef9aae --- /dev/null +++ b/resources/views/server-logs/remote-logs.blade.php @@ -0,0 +1,6 @@ + + @include("server-logs.partials.header") + + @include("server-logs.partials.add-log") + @include("server-logs.partials.logs-list-live") + diff --git a/resources/views/servers/partials/show-server.blade.php b/resources/views/servers/partials/show-server.blade.php index 90513e6..d9f6795 100644 --- a/resources/views/servers/partials/show-server.blade.php +++ b/resources/views/servers/partials/show-server.blade.php @@ -15,5 +15,5 @@ @endif - @include("server-logs.partials.logs-list") + @include("server-logs.partials.logs-list-live", ["pageTitle" => "Logs"]) diff --git a/resources/views/site-logs/index.blade.php b/resources/views/site-logs/index.blade.php index e4a11de..526119d 100644 --- a/resources/views/site-logs/index.blade.php +++ b/resources/views/site-logs/index.blade.php @@ -1,5 +1,5 @@ - {{ __("Logs") }} + {{ $pageTitle }} - @include("server-logs.partials.logs-list", ["server" => $site->server, "site" => $site]) + @include("server-logs.partials.logs-list-live", ["server" => $site->server, "site" => $site]) diff --git a/resources/views/sites/installing.blade.php b/resources/views/sites/installing.blade.php index 6d90ae8..aacb058 100644 --- a/resources/views/sites/installing.blade.php +++ b/resources/views/sites/installing.blade.php @@ -11,5 +11,5 @@ @endif - @include("server-logs.partials.logs-list", ["server" => $site->server, "site" => $site]) + @include("server-logs.partials.logs-list-live", ["server" => $site->server, "site" => $site]) diff --git a/routes/server.php b/routes/server.php index d02d56f..6d9a278 100644 --- a/routes/server.php +++ b/routes/server.php @@ -150,6 +150,9 @@ // logs Route::prefix('/{server}/logs')->group(function () { Route::get('/', [ServerLogController::class, 'index'])->name('servers.logs'); + Route::get('/remote', [ServerLogController::class, 'remote'])->name('servers.logs.remote'); + Route::post('/remote', [ServerLogController::class, 'store'])->name('servers.logs.remote.store'); + Route::delete('/remote/{serverLog}', [ServerLogController::class, 'destroy'])->name('servers.logs.remote.destroy'); Route::get('/{serverLog}', [ServerLogController::class, 'show'])->name('servers.logs.show'); }); }); diff --git a/tests/Feature/LogsTest.php b/tests/Feature/LogsTest.php index 175ff43..a22996c 100644 --- a/tests/Feature/LogsTest.php +++ b/tests/Feature/LogsTest.php @@ -23,4 +23,37 @@ public function test_see_logs() ->assertSuccessful() ->assertSeeText($log->type); } + + public function test_see_logs_remote() + { + $this->actingAs($this->user); + + /** @var ServerLog $log */ + $log = ServerLog::factory()->create([ + 'server_id' => $this->server->id, + 'is_remote' => true, + 'type' => 'remote', + 'name' => 'see-remote-log', + ]); + + $this->get(route('servers.logs.remote', $this->server)) + ->assertSuccessful() + ->assertSeeText('see-remote-log'); + } + + public function test_create_remote_log() + { + $this->actingAs($this->user); + + $this->post(route('servers.logs.remote.store', [ + 'server' => $this->server->id, + ]), [ + 'path' => 'test-path', + ])->assertOk(); + + $this->assertDatabaseHas('server_logs', [ + 'is_remote' => true, + 'name' => 'test-path', + ]); + } } diff --git a/tests/Feature/SitesTest.php b/tests/Feature/SitesTest.php index 14d08cd..a89697d 100644 --- a/tests/Feature/SitesTest.php +++ b/tests/Feature/SitesTest.php @@ -282,6 +282,6 @@ public function test_see_logs(): void 'site' => $this->site, ])) ->assertSuccessful() - ->assertSee('Logs'); + ->assertSee('Vito Logs'); } }