Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function index(Request $request, AddressPool $addressPool)
AllowedFilter::exact('server_id')->nullable(),
],
)
->paginate(min($request->query('per_page', 50), 100))->appends(
->paginate(min($request->query('per_page', 50), 999999))->appends(
$request->query(),
);

Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Admin/Nodes/AddressController.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function index(Request $request, Node $node)
new FiltersAddressWildcard(),
), AllowedFilter::exact('server_id')->nullable()],
)
->paginate(min($request->query('per_page', 50), 100))->appends(
->paginate(min($request->query('per_page', 50), 999999))->appends(
$request->query(),
);

Expand Down
61 changes: 61 additions & 0 deletions app/Repositories/Proxmox/Server/ProxmoxGuestAgentRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace Convoy\Repositories\Proxmox\Server;

use Convoy\Models\Server;
use Webmozart\Assert\Assert;
use Convoy\Repositories\Proxmox\ProxmoxRepository;
use Convoy\Exceptions\Repository\Proxmox\ProxmoxConnectionException;

class ProxmoxGuestAgentRepository extends ProxmoxRepository
{
/**
* Get Guest Agent status.
*
* @return mixed
*
* @throws ProxmoxConnectionException
*/
public function guestAgentOs()
{
Assert::isInstanceOf($this->server, Server::class);

$response = $this->getHttpClient()
->withUrlParameters([
'node' => $this->node->cluster,
'server' => $this->server->vmid,
])
->get('/api2/json/nodes/{node}/qemu/{server}/agent/get-osinfo')
->json();

return $this->getData($response);
}

/**
* Update Guest Agent password for Administrator user.
*
* @param string $password
* @return mixed
*
* @throws ProxmoxConnectionException
*/
public function updateGuestAgentPassword(string $username, string $password)
{
Assert::isInstanceOf($this->server, Server::class);

$params = [
'username' => $username,
'password' => $password,
];

$response = $this->getHttpClient()
->withUrlParameters([
'node' => $this->node->cluster,
'server' => $this->server->vmid,
])
->post('/api2/json/nodes/{node}/qemu/{server}/agent/set-user-password', $params)
->json();

return $this->getData($response);
}
}
31 changes: 23 additions & 8 deletions app/Services/Servers/ServerAuthService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,45 @@

use Convoy\Models\Server;
use Convoy\Repositories\Proxmox\Server\ProxmoxConfigRepository;
use Convoy\Repositories\Proxmox\Server\ProxmoxGuestAgentRepository;
use Illuminate\Support\Str;

class ServerAuthService
{
public function __construct(private ProxmoxConfigRepository $configRepository)
public function __construct(private ProxmoxConfigRepository $configRepository, private ProxmoxGuestAgentRepository $guestAgentRepository)
{
}

public function updatePassword(Server $server, string $password)
public function updatePassword(Server $server, string $password): void
{
// if (!empty($password)) {
// Always store CIPassword first
$this->configRepository->setServer($server)->update(['cipassword' => $password]);
// } else {
// $this->configRepository->setServer($server)->update(['delete' => 'cipassword']);
// }

try {
$osInfo = $this->guestAgentRepository->setServer($server)->guestAgentOs();

// If we have valid OS info, decide which username to use
if (is_array($osInfo) && isset($osInfo['result']['name'])) {
$osName = $osInfo['result']['name'];
$username = Str::contains(Str::lower($osName), 'windows') ? 'Administrator' : 'root';

$this->guestAgentRepository
->setServer($server)
->updateGuestAgentPassword($username, $password);
}
} catch (\Exception $e) {
// Optionally log or handle exceptions
}
}

public function getSSHKeys(Server $server)
public function getSSHKeys(Server $server): string
{
$raw = collect($this->configRepository->setServer($server)->getConfig())->where('key', '=', 'sshkeys')->first()['value'] ?? '';

return rawurldecode($raw);
}

public function updateSSHKeys(Server $server, ?string $keys)
public function updateSSHKeys(Server $server, ?string $keys): void
{
if (! empty($keys)) {
$this->configRepository->setServer($server)->update(['sshkeys' => rawurlencode($keys)]);
Expand Down
48 changes: 31 additions & 17 deletions app/Services/Servers/ServerBuildDispatchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@

namespace Convoy\Services\Servers;

use Convoy\Models\Server;
use Convoy\Data\Server\Deployments\ServerDeploymentData;
use Convoy\Enums\Server\PowerAction;
use Convoy\Enums\Server\State;
use Convoy\Enums\Server\Status;
use Illuminate\Support\Facades\Bus;
use Convoy\Enums\Server\PowerAction;
use Convoy\Jobs\Server\SyncBuildJob;
use Convoy\Jobs\Server\BuildServerJob;
use Convoy\Jobs\Server\DeleteServerJob;
use Convoy\Jobs\Server\MonitorStateJob;
use Convoy\Jobs\Server\UpdatePasswordJob;
use Convoy\Jobs\Server\SendPowerCommandJob;
use Convoy\Jobs\Server\SyncBuildJob;
use Convoy\Jobs\Server\UpdatePasswordJob;
use Convoy\Jobs\Server\WaitUntilVmIsCreatedJob;
use Convoy\Jobs\Server\WaitUntilVmIsDeletedJob;
use Convoy\Data\Server\Deployments\ServerDeploymentData;
use Convoy\Models\Server;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Str;

class ServerBuildDispatchService
{
Expand Down Expand Up @@ -55,26 +56,39 @@ public function rebuild(ServerDeploymentData $deployment): void

private function getChainedBuildJobs(ServerDeploymentData $deployment): array
{
if ($deployment->should_create_server) {
$jobs = [
// Base jobs: either create a new server or sync an existing one
$jobs = $deployment->should_create_server
? [
new BuildServerJob($deployment->server->id, $deployment->template->id),
new WaitUntilVmIsCreatedJob($deployment->server->id),
new SyncBuildJob($deployment->server->id),
];
} else {
$jobs = [
]
: [
new SyncBuildJob($deployment->server->id),
];
}

if (! empty($deployment->account_password)) {
$jobs[] = new UpdatePasswordJob($deployment->server->id, $deployment->account_password);
}
if (Str::contains(Str::lower($deployment->template->name), 'windows')) {
$jobs = [
...$jobs,
new SendPowerCommandJob($deployment->server->id, PowerAction::START),
new MonitorStateJob($deployment->server->id, State::RUNNING),
];

if ($deployment->start_on_completion) {
$jobs[] = new SendPowerCommandJob($deployment->server->id, PowerAction::START);
if (! empty($deployment->account_password)) {
$jobs[] = new UpdatePasswordJob($deployment->server->id, $deployment->account_password);
}
} else {
// For non-Windows, update password first if provided
if (! empty($deployment->account_password)) {
$jobs[] = new UpdatePasswordJob($deployment->server->id, $deployment->account_password);
}
// Then power on if user wants to start on completion
if ($deployment->start_on_completion) {
$jobs[] = new SendPowerCommandJob($deployment->server->id, PowerAction::START);
}
}

// Final callback to clear the status
$jobs[] = function () use ($deployment) {
Server::findOrFail($deployment->server->id)->update(['status' => null]);
};
Expand Down
Loading