47 lines
1.5 KiB
PHP
47 lines
1.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Server;
|
|
use Illuminate\Support\Collection;
|
|
use Throwable;
|
|
|
|
/**
|
|
* Runs one (arbitrary, user-supplied) command across a set of servers and collects a per-server
|
|
* result. The command is INTENTIONALLY arbitrary — it runs via FleetService::runPlain (the
|
|
* credential's login user, base64 transport, no extra sudo) exactly as the web terminal would.
|
|
* One server failing (connect/exec) never aborts the batch. Remote output is byte-capped +
|
|
* mb_scrub'd so it can safely land in a Livewire property.
|
|
*/
|
|
class CommandRunner
|
|
{
|
|
private const MAX_BYTES = 262144; // 256 KiB per server
|
|
|
|
public function __construct(private FleetService $fleet) {}
|
|
|
|
/**
|
|
* @param Collection<int, Server> $servers
|
|
* @return array<int, array{server:string, ok:bool, output:string}>
|
|
*/
|
|
public function run(string $command, Collection $servers, int $timeout = 60): array
|
|
{
|
|
$results = [];
|
|
|
|
foreach ($servers as $server) {
|
|
try {
|
|
$res = $this->fleet->runPlain($server, $command, $timeout);
|
|
$results[] = ['server' => $server->name, 'ok' => (bool) $res['ok'], 'output' => $this->clean($res['output'])];
|
|
} catch (Throwable $e) {
|
|
$results[] = ['server' => $server->name, 'ok' => false, 'output' => $this->clean($e->getMessage())];
|
|
}
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
private function clean(string $output): string
|
|
{
|
|
return mb_scrub(mb_strcut($output, 0, self::MAX_BYTES), 'UTF-8');
|
|
}
|
|
}
|