CluPilotCloud/app/Services/Proxmox/HttpProxmoxClient.php

92 lines
2.6 KiB
PHP

<?php
namespace App\Services\Proxmox;
use App\Models\Host;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
/**
* Real Proxmox VE REST client. Token auth over the WireGuard tunnel; the PVE
* certificate is self-signed so TLS verification is disabled (traffic already
* runs inside the encrypted tunnel). Not unit-tested (live I/O).
*/
class HttpProxmoxClient implements ProxmoxClient
{
private string $baseUrl = '';
private string $token = '';
public function forHost(Host $host): static
{
$this->baseUrl = 'https://'.$host->wg_ip.':8006/api2/json';
$this->token = (string) $host->api_token_ref;
return $this;
}
private function http(): PendingRequest
{
return Http::withoutVerifying()
->withHeaders(['Authorization' => 'PVEAPIToken='.$this->token])
->baseUrl($this->baseUrl)
->timeout(15);
}
public function listNodes(): array
{
return $this->http()->get('/nodes')->throw()->json('data', []);
}
public function nodeStatus(string $node): array
{
return $this->http()->get("/nodes/{$node}/status")->throw()->json('data', []);
}
public function nodeStorage(string $node): array
{
return $this->http()->get("/nodes/{$node}/storage")->throw()->json('data', []);
}
public function createRole(string $roleId, string $privs): void
{
$response = $this->http()->asForm()->post('/access/roles', [
'roleid' => $roleId,
'privs' => $privs,
]);
// Idempotent: an existing role is not an error.
if ($response->failed() && ! str_contains($response->body(), 'already exists')) {
$response->throw();
}
}
public function createUserAndToken(string $user, string $roleId): array
{
// Ensure the user exists (ignore "already exists"), grant the role, mint a token.
$this->http()->asForm()->post('/access/users', [
'userid' => $user,
'password' => Str::random(40),
]);
$this->http()->asForm()->put('/access/acl', [
'path' => '/',
'users' => $user,
'roles' => $roleId,
])->throw();
$tokenName = config('provisioning.proxmox.token_name', 'clupilot');
$data = $this->http()->asForm()
->post("/access/users/{$user}/token/{$tokenName}", ['privsep' => 0])
->throw()
->json('data', []);
return [
'token_id' => $data['full-tokenid'] ?? "{$user}!{$tokenName}",
'secret' => $data['value'] ?? '',
];
}
}