Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for QEMU Guest Agent and Fix Issue with IPAM #120

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
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
71 changes: 71 additions & 0 deletions app/Jobs/Server/SyncWindowsSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
namespace Convoy\Jobs\Server;

use Convoy\Models\Server;
use Convoy\Services\Servers\ServerAuthService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\Middleware\SkipIfBatchCancelled;
use Illuminate\Queue\Middleware\WithoutOverlapping;
use Illuminate\Queue\SerializesModels;

class SyncWindowsSettings implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

public int $tries = 15;

public int $timeout = 20;

public function __construct(protected int $serverId, protected string $password)
{
//
}

public function middleware(): array
{
return [new SkipIfBatchCancelled(), new WithoutOverlapping(
"server.sync-windows-settings#{$this->serverId}",
)];
}

public function handle(ServerAuthService $service): void
{
$server = Server::findOrFail($this->serverId);

$service->updateWindowsPassword($server, $this->password);
}

/**
* Determine the time at which the job should retry.
*
* @return \DateTime
*/
public function retryAfter(): \DateTime
{
return now()->addSeconds(20);
}

/**
* Determine the time at which the job should timeout.
*
* @return \DateTime
*/
public function retryUntil(): \DateTime
{
return now()->addSeconds($this->timeout * $this->tries);
}

/**
* Handle a job failure.
*
* @return void
*/
public function failed(): void
{
// Mark the job as completed
$this->delete();
}
}
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,20 +4,35 @@

use Convoy\Models\Server;
use Convoy\Repositories\Proxmox\Server\ProxmoxConfigRepository;
use Convoy\Repositories\Proxmox\Server\ProxmoxGuestAgentRepository;

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

public function updatePassword(Server $server, string $password)
{
// if (!empty($password)) {
$this->configRepository->setServer($server)->update(['cipassword' => $password]);
// } else {
// $this->configRepository->setServer($server)->update(['delete' => 'cipassword']);
// }
try {
$OsInfo = $this->guestAgentRepository->setServer($server)->guestAgentOs();
if (is_array($OsInfo) && isset($OsInfo["result"]["name"])) {
if (str_contains($OsInfo["result"]["name"], "Windows")) {
$username = "Administrator";
} else {
$username = "root";
}

$this->guestAgentRepository->setServer($server)->updateGuestAgentPassword($username, $password);
}
$this->configRepository->setServer($server)->update(['cipassword' => $password]);
} catch (\Exception $e) {
$this->configRepository->setServer($server)->update(['cipassword' => $password]);
}
}

public function updateWindowsPassword(Server $server, string $password) {
$this->guestAgentRepository->setServer($server)->updateGuestAgentPassword("Administrator", $password);
}

public function getSSHKeys(Server $server)
Expand All @@ -29,10 +44,10 @@ public function getSSHKeys(Server $server)

public function updateSSHKeys(Server $server, ?string $keys)
{
if (! empty($keys)) {
if (!empty($keys)) {
$this->configRepository->setServer($server)->update(['sshkeys' => rawurlencode($keys)]);
} else {
$this->configRepository->setServer($server)->update(['delete' => 'sshkeys']);
}
}
}
}
16 changes: 13 additions & 3 deletions app/Services/Servers/ServerBuildDispatchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Convoy\Jobs\Server\SendPowerCommandJob;
use Convoy\Jobs\Server\WaitUntilVmIsCreatedJob;
use Convoy\Jobs\Server\WaitUntilVmIsDeletedJob;
use Convoy\Jobs\Server\SyncWindowsSettings;
use Convoy\Data\Server\Deployments\ServerDeploymentData;

class ServerBuildDispatchService
Expand Down Expand Up @@ -67,11 +68,20 @@ private function getChainedBuildJobs(ServerDeploymentData $deployment): array
];
}

if (! empty($deployment->account_password)) {
$startOnce = false;

// TODO: Readd the start_on_completion check

if (!empty($deployment->account_password)) {
$jobs[] = new UpdatePasswordJob($deployment->server->id, $deployment->account_password);
if (str_contains($deployment->template->name, "Windows")) {
$jobs[] = new SendPowerCommandJob($deployment->server->id, PowerAction::START);
$startOnce = true;
$jobs[] = new SyncWindowsSettings($deployment->server->id, $deployment->account_password);
}
}

if ($deployment->start_on_completion) {
if (!$startOnce) {
$jobs[] = new SendPowerCommandJob($deployment->server->id, PowerAction::START);
}

Expand All @@ -91,4 +101,4 @@ public function getChainedDeleteJobs(Server $server): array
new WaitUntilVmIsDeletedJob($server->id),
];
}
}
}