onConnection('provisioning'); $this->onQueue('provisioning'); } /** Anything that escapes handle() still has to reach the waiting console. */ public function failed(?Throwable $e): void { ConfigHandoff::put(json_encode(['error' => 'failed']), $this->handoffToken); } public function handle(ProxmoxClient $proxmox): void { $instance = Instance::query()->with('host')->where('uuid', $this->instanceUuid)->first(); // Only a live instance: a closed one's VMID can have been reused on the // same host, and the reset would then land on a stranger's VM. if ($instance === null || $instance->status !== 'active' || $instance->host === null || blank($instance->vmid) || blank($instance->nc_admin_ref)) { ConfigHandoff::put(json_encode(['error' => 'unavailable']), $this->handoffToken); return; } $username = $instance->nc_admin_ref; $password = Str::password(24, symbols: false); try { $result = $proxmox->forHost($instance->host)->guestExec( $instance->host->node ?? 'pve', (int) $instance->vmid, NextcloudOcc::command( 'user:resetpassword --password-from-env '.escapeshellarg($username), ['OC_PASS' => $password], ), ); } catch (Throwable $e) { // An unreachable Proxmox or guest agent throws rather than // returning a code. Without this the console would poll forever // instead of saying what happened. Log::warning('instance admin access errored', [ 'instance' => $instance->uuid, 'error' => $e->getMessage(), ]); ConfigHandoff::put(json_encode(['error' => 'failed']), $this->handoffToken); return; } if ((int) ($result['exitcode'] ?? 1) !== 0) { Log::warning('instance admin access failed', [ 'instance' => $instance->uuid, 'user' => $this->requestedBy, ]); ConfigHandoff::put(json_encode(['error' => 'failed']), $this->handoffToken); return; } // Auditable on its own: who asked, for which instance, when. The // credentials themselves are never logged. Log::info('instance admin access issued', [ 'instance' => $instance->uuid, 'user' => $this->requestedBy, ]); ConfigHandoff::put(json_encode([ // Through address(), which serves the customer's own domain only // once its DNS proof has been read. A link to an unverified // domain would not resolve to this instance anyway. 'url' => 'https://'.$instance->address(ProvisioningSettings::dnsZone()), 'username' => $username, 'password' => $password, ]), $this->handoffToken); } }