mirror of
https://github.com/vitodeploy/vito.git
synced 2025-04-19 09:51:37 +00:00
remote monitor (#167)
This commit is contained in:
parent
0cd815cce6
commit
d07e9bcad2
31
app/Console/Commands/GetMetricsCommand.php
Normal file
31
app/Console/Commands/GetMetricsCommand.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class GetMetricsCommand extends Command
|
||||
{
|
||||
protected $signature = 'metrics:get';
|
||||
|
||||
protected $description = 'Get server metrics';
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$checkedMetrics = 0;
|
||||
Server::query()->whereHas('services', function (Builder $query) {
|
||||
$query->where('type', 'monitoring')
|
||||
->where('name', 'remote-monitor');
|
||||
})->chunk(10, function ($servers) use (&$checkedMetrics) {
|
||||
/** @var Server $server */
|
||||
foreach ($servers as $server) {
|
||||
$info = $server->os()->resourceInfo();
|
||||
$server->metrics()->create(array_merge($info, ['server_id' => $server->id]));
|
||||
$checkedMetrics++;
|
||||
}
|
||||
});
|
||||
$this->info("Checked $checkedMetrics metrics");
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ protected function schedule(Schedule $schedule): void
|
||||
$schedule->command('backups:run "0 0 * * 0"')->weekly();
|
||||
$schedule->command('backups:run "0 0 1 * *"')->monthly();
|
||||
$schedule->command('metrics:delete-older-metrics')->daily();
|
||||
$schedule->command('metrics:get')->everyMinute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -166,4 +166,21 @@ public function cleanup(): void
|
||||
'cleanup'
|
||||
);
|
||||
}
|
||||
|
||||
public function resourceInfo(): array
|
||||
{
|
||||
$info = $this->server->ssh()->exec(
|
||||
$this->getScript('resource-info.sh'),
|
||||
);
|
||||
|
||||
return [
|
||||
'load' => str($info)->after('load:')->before(PHP_EOL)->toString(),
|
||||
'memory_total' => str($info)->after('memory_total:')->before(PHP_EOL)->toString(),
|
||||
'memory_used' => str($info)->after('memory_used:')->before(PHP_EOL)->toString(),
|
||||
'memory_free' => str($info)->after('memory_free:')->before(PHP_EOL)->toString(),
|
||||
'disk_total' => str($info)->after('disk_total:')->before(PHP_EOL)->toString(),
|
||||
'disk_used' => str($info)->after('disk_used:')->before(PHP_EOL)->toString(),
|
||||
'disk_free' => str($info)->after('disk_free:')->before(PHP_EOL)->toString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
7
app/SSH/OS/scripts/resource-info.sh
Normal file
7
app/SSH/OS/scripts/resource-info.sh
Normal file
@ -0,0 +1,7 @@
|
||||
echo "load:$(uptime | awk -F'load average:' '{print $2}' | awk -F, '{print $1}' | tr -d ' ')"
|
||||
echo "memory_total:$(free -k | awk 'NR==2{print $2}')"
|
||||
echo "memory_used:$(free -k | awk 'NR==2{print $3}')"
|
||||
echo "memory_free:$(free -k | awk 'NR==2{print $7}')"
|
||||
echo "disk_total:$(df -BM / | awk 'NR==2{print $2}' | sed 's/M//')"
|
||||
echo "disk_used:$(df -BM / | awk 'NR==2{print $3}' | sed 's/M//')"
|
||||
echo "disk_free:$(df -BM / | awk 'NR==2{print $4}' | sed 's/M//')"
|
53
app/SSH/Services/Monitoring/RemoteMonitor/RemoteMonitor.php
Normal file
53
app/SSH/Services/Monitoring/RemoteMonitor/RemoteMonitor.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\SSH\Services\Monitoring\RemoteMonitor;
|
||||
|
||||
use App\Models\Metric;
|
||||
use App\SSH\Services\AbstractService;
|
||||
use Closure;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class RemoteMonitor extends AbstractService
|
||||
{
|
||||
public function creationRules(array $input): array
|
||||
{
|
||||
return [
|
||||
'type' => [
|
||||
function (string $attribute, mixed $value, Closure $fail) {
|
||||
$monitoringExists = $this->service->server->monitoring();
|
||||
if ($monitoringExists) {
|
||||
$fail('You already have a monitoring service on the server.');
|
||||
}
|
||||
},
|
||||
],
|
||||
'version' => [
|
||||
'required',
|
||||
Rule::in(['latest']),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function creationData(array $input): array
|
||||
{
|
||||
return [
|
||||
'data_retention' => 10,
|
||||
];
|
||||
}
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'data_retention' => $this->service->type_data['data_retention'] ?? 10,
|
||||
];
|
||||
}
|
||||
|
||||
public function install(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public function uninstall(): void
|
||||
{
|
||||
Metric::where('server_id', $this->service->server_id)->delete();
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\SSH\Services\VitoAgent;
|
||||
namespace App\SSH\Services\Monitoring\VitoAgent;
|
||||
|
||||
use App\Models\Metric;
|
||||
use App\SSH\HasScripts;
|
@ -142,6 +142,7 @@
|
||||
'ufw' => 'firewall',
|
||||
'supervisor' => 'process_manager',
|
||||
'vito-agent' => 'monitoring',
|
||||
'remote-monitor' => 'monitoring',
|
||||
],
|
||||
'service_handlers' => [
|
||||
'nginx' => \App\SSH\Services\Webserver\Nginx::class,
|
||||
@ -152,7 +153,8 @@
|
||||
'php' => \App\SSH\Services\PHP\PHP::class,
|
||||
'ufw' => \App\SSH\Services\Firewall\Ufw::class,
|
||||
'supervisor' => \App\SSH\Services\ProcessManager\Supervisor::class,
|
||||
'vito-agent' => \App\SSH\Services\VitoAgent\VitoAgent::class,
|
||||
'vito-agent' => \App\SSH\Services\Monitoring\VitoAgent\VitoAgent::class,
|
||||
'remote-monitor' => \App\SSH\Services\Monitoring\RemoteMonitor\RemoteMonitor::class,
|
||||
],
|
||||
'service_units' => [
|
||||
'nginx' => [
|
||||
|
29
public/static/images/remote-monitor.svg
Normal file
29
public/static/images/remote-monitor.svg
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 -5.23 70 70" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work>
|
||||
<dc:subject>
|
||||
Miscellaneous
|
||||
</dc:subject>
|
||||
<dc:identifier>
|
||||
health-monitoring
|
||||
</dc:identifier>
|
||||
<dc:title>
|
||||
Health Monitoring
|
||||
</dc:title>
|
||||
<dc:format>
|
||||
image/svg+xml
|
||||
</dc:format>
|
||||
<dc:publisher>
|
||||
Amido Limited
|
||||
</dc:publisher>
|
||||
<dc:creator>
|
||||
Richard Slater
|
||||
</dc:creator>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<path d="m -633.94123,753.25889 c -6.59942,-3.2916 -17.80605,-13.7307 -24.90952,-23.2035 l -0.38611,-0.5149 4.90905,0 c 3.3284,0 5.08031,-0.051 5.44092,-0.1594 0.95525,-0.2862 1.50799,-0.9179 2.58607,-2.9554 1.97619,-3.735 2.24879,-4.2224 2.2879,-4.0904 0.0218,0.074 0.44604,4.3009 0.94276,9.3939 0.87326,8.9538 0.91529,9.2823 1.27154,9.9368 0.62081,1.1407 1.47439,1.6301 2.85312,1.6359 1.01617,0 1.76269,-0.3415 2.41627,-1.1191 0.25355,-0.3016 1.82033,-3.2056 3.48173,-6.4532 l 3.02073,-5.9047 10.36659,-0.039 c 10.32236,-0.039 10.36894,-0.041 10.91581,-0.3356 1.1802,-0.6369 1.77594,-1.6202 1.77528,-2.9304 -6.9e-4,-1.3721 -0.67396,-2.4208 -1.91258,-2.9791 -0.5125,-0.231 -1.30161,-0.2501 -11.80218,-0.2858 -7.69785,-0.026 -11.47959,0.01 -11.97032,0.1108 -1.27206,0.264 -1.77303,0.7868 -3.0106,3.1416 l -1.08999,2.0739 -0.1043,-0.5158 c -0.0574,-0.2837 -0.47667,-4.3775 -0.9318,-9.0974 -0.45513,-4.7199 -0.88563,-8.7992 -0.95668,-9.0652 -0.36496,-1.3662 -1.62876,-2.2659 -3.16688,-2.2544 -1.04822,0.01 -1.94772,0.4395 -2.48617,1.1931 -0.17485,0.2447 -1.92936,3.5346 -3.8989,7.311 l -3.581,6.866 -5.76782,0.036 -5.76783,0.036 -0.83086,-1.6834 c -2.06318,-4.1804 -2.89449,-7.6097 -2.738,-11.2949 0.12425,-2.9261 0.69392,-5.0125 2.04328,-7.4832 1.10812,-2.029 3.06519,-4.3559 4.69277,-5.5795 1.78333,-1.3407 4.15216,-2.2461 6.64618,-2.5403 2.10735,-0.2485 4.60651,0.089 7.37391,0.9964 1.2153,0.3984 4.21499,1.9073 5.62954,2.8318 2.45012,1.6012 5.68511,4.4633 7.84072,6.9369 l 0.80955,0.929 0.94007,-1.2397 c 1.88483,-2.4857 4.78785,-5.1075 7.55221,-6.8208 5.19337,-3.2187 11.05786,-4.2791 15.6703,-2.8335 3.74959,1.1752 6.7744,3.9944 8.98105,8.3706 2.19828,4.3596 2.39398,9.8576 0.53892,15.1404 -1.06649,3.0372 -2.39805,5.6594 -4.46756,8.7979 -2.55838,3.88 -4.87538,6.6471 -9.08862,10.8542 -5.31708,5.3093 -11.00984,9.9038 -16.48777,13.3068 -1.60577,0.9976 -3.84246,2.2037 -4.0818,2.201 -0.0583,0 -0.75536,-0.325 -1.54898,-0.7208 z" fill="#00bcf2" transform="translate(667.003 -694.43)"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
@ -22,7 +22,12 @@ class="p-6"
|
||||
<x-input-label for="data_retention" value="Delete metrics older than" />
|
||||
<x-select-input id="data_retention" name="data_retention" class="mt-1 w-full">
|
||||
@foreach (config("core.metrics_data_retention") as $item)
|
||||
<option value="{{ $item }}">{{ $item }} Days</option>
|
||||
<option
|
||||
value="{{ $item }}"
|
||||
@if($server->monitoring()->handler()->data()['data_retention'] == $item) selected @endif
|
||||
>
|
||||
{{ $item }} Days
|
||||
</option>
|
||||
@endforeach
|
||||
</x-select-input>
|
||||
@error("data_retention")
|
||||
|
@ -0,0 +1,6 @@
|
||||
@include("services.partials.unit-actions.restart", ["disabled" => true])
|
||||
@include("services.partials.unit-actions.start", ["disabled" => true])
|
||||
@include("services.partials.unit-actions.stop", ["disabled" => true])
|
||||
@include("services.partials.unit-actions.enable", ["disabled" => true])
|
||||
@include("services.partials.unit-actions.disable", ["disabled" => true])
|
||||
@include("services.partials.unit-actions.uninstall")
|
@ -0,0 +1,37 @@
|
||||
<x-secondary-button class="!w-full" x-on:click="$dispatch('open-modal', 'install-remote-monitor')">
|
||||
Install
|
||||
</x-secondary-button>
|
||||
@push("modals")
|
||||
<x-modal name="install-remote-monitor">
|
||||
<form
|
||||
id="install-remote-monitor-form"
|
||||
hx-post="{{ route("servers.services.install", ["server" => $server]) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-select="#install-remote-monitor-form"
|
||||
class="p-6"
|
||||
>
|
||||
@csrf
|
||||
<input type="hidden" name="name" value="remote-monitor" />
|
||||
<input type="hidden" name="type" value="monitoring" />
|
||||
<input type="hidden" name="version" value="latest" />
|
||||
|
||||
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">
|
||||
{{ __("Install Remote Monitor") }}
|
||||
</h2>
|
||||
|
||||
@error("type")
|
||||
<x-input-error class="mt-2" :messages="$message" />
|
||||
@enderror
|
||||
|
||||
<div class="mt-6 flex justify-end">
|
||||
<x-secondary-button type="button" x-on:click="$dispatch('close')">
|
||||
{{ __("Cancel") }}
|
||||
</x-secondary-button>
|
||||
|
||||
<x-primary-button id="btn-remote-monitor" hx-disable class="ml-3">
|
||||
{{ __("Install") }}
|
||||
</x-primary-button>
|
||||
</div>
|
||||
</form>
|
||||
</x-modal>
|
||||
@endpush
|
@ -21,7 +21,8 @@ class="p-6"
|
||||
|
||||
<div class="mt-6">
|
||||
<x-alert-warning>
|
||||
Vito Agent is only works if you are running your Vito instance on a cloud not local!
|
||||
Vito Agent is only works if you are running your Vito instance on a cloud not local! Consider
|
||||
installing remote-monitor instead.
|
||||
</x-alert-warning>
|
||||
</div>
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
<x-icon-button
|
||||
:disabled="isset($disabled) ? $disabled : false"
|
||||
data-tooltip="Disable Service"
|
||||
class="cursor-pointer"
|
||||
href="{{ route('servers.services.disable', ['server' => $server, 'service' => $service]) }}"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<x-icon-button
|
||||
:disabled="$service->status != \App\Enums\ServiceStatus::DISABLED"
|
||||
:disabled="isset($disabled) ? $disabled : $service->status != \App\Enums\ServiceStatus::DISABLED"
|
||||
data-tooltip="Enable Service"
|
||||
class="cursor-pointer"
|
||||
href="{{ route('servers.services.enable', ['server' => $server, 'service' => $service]) }}"
|
||||
|
@ -1,4 +1,5 @@
|
||||
<x-icon-button
|
||||
:disabled="isset($disabled) ? $disabled : false"
|
||||
data-tooltip="Restart Service"
|
||||
class="cursor-pointer"
|
||||
href="{{ route('servers.services.restart', ['server' => $server, 'service' => $service]) }}"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<x-icon-button
|
||||
:disabled="$service->status != \App\Enums\ServiceStatus::STOPPED"
|
||||
:disabled="isset($disabled) ? $disabled : $service->status != \App\Enums\ServiceStatus::STOPPED"
|
||||
data-tooltip="Start Service"
|
||||
class="cursor-pointer"
|
||||
href="{{ route('servers.services.start', ['server' => $server, 'service' => $service]) }}"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<x-icon-button
|
||||
:disabled="isset($disabled) ? $disabled : $service->status != \App\Enums\ServiceStatus::READY"
|
||||
data-tooltip="Stop Service"
|
||||
:disabled="$service->status != \App\Enums\ServiceStatus::READY"
|
||||
class="cursor-pointer"
|
||||
href="{{ route('servers.services.stop', ['server' => $server, 'service' => $service]) }}"
|
||||
>
|
||||
|
52
tests/Unit/Commands/GetMetricsCommandTest.php
Normal file
52
tests/Unit/Commands/GetMetricsCommandTest.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Commands;
|
||||
|
||||
use App\Enums\ServiceStatus;
|
||||
use App\Facades\SSH;
|
||||
use App\Models\Service;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GetMetricsCommandTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_get_metrics(): void
|
||||
{
|
||||
SSH::fake(<<<'EOF'
|
||||
load:1
|
||||
memory_total:1
|
||||
memory_used:1
|
||||
memory_free:1
|
||||
disk_total:1
|
||||
disk_used:1
|
||||
disk_free:1
|
||||
EOF);
|
||||
|
||||
Service::factory()->create([
|
||||
'server_id' => $this->server->id,
|
||||
'name' => 'remote-monitor',
|
||||
'type' => 'monitoring',
|
||||
'type_data' => [
|
||||
'data_retention' => 7,
|
||||
],
|
||||
'version' => 'latest',
|
||||
'status' => ServiceStatus::READY,
|
||||
]);
|
||||
|
||||
$this->artisan('metrics:get')
|
||||
->expectsOutput('Checked 1 metrics');
|
||||
|
||||
$this->assertDatabaseHas('metrics', [
|
||||
'server_id' => $this->server->id,
|
||||
'load' => 1,
|
||||
'memory_total' => 1,
|
||||
'memory_used' => 1,
|
||||
'memory_free' => 1,
|
||||
'disk_total' => 1,
|
||||
'disk_used' => 1,
|
||||
'disk_free' => 1,
|
||||
]);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user