Untitled
unknown
plain_text
3 years ago
6.8 kB
9
Indexable
<?php
namespace App\Jobs;
use App\Events\InstanceEvent;
use App\Models\Instance;
use App\Models\Project;
use App\Models\PublicIpv4;
use App\Models\User;
use Confirm\ZabbixApi\ZabbixApi;
use Illuminate\Bus\Batchable;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Log;
use Popson\CloudStack\Clients\UserClient;
use Popson\CloudStack\Model\AsyncJob;
use Popson\CloudStack\Model\VirtualMachine;
use Popson\CloudStack\Services\User\AddressApiService;
use Popson\CloudStack\Services\User\AsyncJobApiService;
use Popson\CloudStack\Services\User\FirewallApiService;
use Popson\CloudStack\Services\User\NatApiService;
use Popson\CloudStack\Services\User\VirtualMachineApiService;
class AssignIpAddressJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, Batchable;
protected User $user;
protected PublicIpv4 $ipv4;
protected AsyncJob $virtualMachineJob;
protected string $networkType;
protected string $isSourceIpUsed;
public int|float $timeout = 60 * 15; // 15 minutes
public bool $failOnTimeout = true;
public function __construct(User $user, PublicIpv4 $ipv4, AsyncJob $virtualMachineJob, string $networkType, $isSourceIpUsed)
{
$this->user = $user;
$this->ipv4 = $ipv4;
$this->virtualMachineJob = $virtualMachineJob;
$this->networkType = $networkType;
$this->isSourceIpUsed = $isSourceIpUsed;
}
public function handle()
{
// PublicIpv4 Migrated from PublicIpv4::query() to Polymorphic Relation
// So instance_id replaced with public_ipv4able_id
$instance = Instance::query()->findOrFail($this->ipv4->public_ipv4able_id);
$project = Project::find($this->ipv4->project_id);
$os_family = $instance?->os_version_offering?->osVersion?->os?->family??'Linux';
app()->singleton(UserClient::class, function () {
return new UserClient(config('services.cloudstack'), $this->user);
});
$asyncJobApiService = app(AsyncJobApiService::class);
$firewallApiService = app(FirewallApiService::class);
$addressApiService = app(AddressApiService::class);
$natApiService = app(NatApiService::class);
$virtualMachineApiService = app(VirtualMachineApiService::class);
$vm = $this->waitForTheVmToBeCreated($asyncJobApiService);
if ($vm->password_enabled) {
$instance->update([
'password_enabled' => true,
'encrypted_password' => Crypt::encryptString($vm->password ?? '<password not set>'),
]);
}
if(empty($this->ipv4->ipv4_id)){
event(new InstanceEvent($this->user->id, 'vm-ready', "Instance is ready..."));
return;
}
$this->waitForIpv4GetAllocated($this->ipv4, $addressApiService);
if($this->networkType == 'Isolated' && $this->isSourceIpUsed){
$this->batch()->add(new CreateFirewallRuleJob($this->user, $this->ipv4->ipv4_id, $os_family, $instance));
}
Log::debug('Strategy:: '. $this->ipv4->strategy);
$ipv4 = $this->ipv4;
$user = $this->user;
$this->batch()->add((function() use($project, $natApiService, $vm, $firewallApiService, $ipv4, $user, $asyncJobApiService){
sleep(30);
if ($ipv4->strategy === 'static') {
$natApiService->enableStaticNat([
'ipaddressid' => $ipv4->ipv4_id,
'virtualmachineid' => $ipv4->public_ipv4able_id,
'networkid' => $ipv4->network_id,
'projectid' => $project->id,
'domainid' => $project->account->domain_id,
'account' => $project->account->username,
'vmguestip' => $vm->nic?->first()->ipaddress,
]);
event(new InstanceEvent($user->id, 'vm-ready', "Static nat enabled successfully!"));
} else {
foreach ([80, 443, 22] as $port) {
$rule = [
'ipaddressid' => $ipv4->ipv4_id,
'privateport' => $port,
'publicport' => $port,
'virtualmachineid' => $ipv4->public_ipv4able_id,
'networkid' => $ipv4->network_id,
'openfirewall' => false,
'privateendport' => $port,
'publicendport' => $port,
];
$job = $firewallApiService->createPortForwardingRule($rule + ['protocol' => 'tcp']);
$this->followJob($asyncJobApiService, $job);
$job = $firewallApiService->createPortForwardingRule($rule + ['protocol' => 'udp']);
$this->followJob($asyncJobApiService, $job);
}
event(new InstanceEvent($user->id, 'vm-ready', "Port forwarding rules created successfully!"));
}
}));
}
protected function followJob(AsyncJobApiService $asyncJobApiService, AsyncJob $job)
{
$retries = 10;
while ($retries-- > 0) {
$result = $asyncJobApiService->queryAsyncJobResult(['jobid' => $job->jobId]);
if (!$result->finished()) sleep(3);
else return;
}
$this->release(30);
}
protected function waitForTheVmToBeCreated(mixed $asyncJobApiService): VirtualMachine
{
// wait for the vm to start
while (true) {
/** @var \Popson\CloudStack\Model\AsyncJobResult $result */
$result = $asyncJobApiService->queryAsyncJobResult(['jobid' => $this->virtualMachineJob->jobId]);
if ($result->finished()) {
return new VirtualMachine($result->job_result['virtualmachine'] ?? []);
}
sleep(5);
}
}
private function waitForIpv4GetAllocated(PublicIpv4 $ipv4, AddressApiService $addressApiService)
{
while (true) {
$publicIpAddresses = $addressApiService->listPublicIpAddresses([
'id' => $ipv4->ipv4_id,
'allocatedonly' => false
]);
/** @var \Popson\CloudStack\Model\PublicIpAddress $publicIpAddress */
$publicIpAddress = $publicIpAddresses->first();
if ($publicIpAddress->state === 'Allocated') {
return;
}
sleep(2);
}
}
}
Editor is loading...