feat: Enhance vCenter integration with resource pool and folder support

- Added methods to ResourceService for fetching resource pools and updated existing methods to include datacenter filtering.
- Modified CreateVirtualMachine to accept folder and resource pool parameters from product data.
- Updated various jobs to synchronize resource pools and include them in the provisioning process.
- Introduced new ModuleResourcePool model and migration for resource pool management.
- Enhanced existing models (ModuleDatastore, ModuleNetwork, Os) to include relationships with vCenter and resource pools.
- Added netmask field to IpPool and updated related logic for IP reservation.
- Improved error handling and logging in VM creation and IP reservation processes.
- Updated API routes to include sync functionality for vCenter.
This commit is contained in:
baodev0
2026-07-21 21:37:28 +07:00
parent 2d43e95855
commit 5d3ed57b32
33 changed files with 708 additions and 152 deletions
@@ -10,25 +10,29 @@ use App\Services\VirtualMachine\Dto\VmInfrastructureContext;
use RuntimeException;
/**
* Resolves the provisioning target by walking the ACTIVE chain only:
* Resolves the provisioning target by walking the ACTIVE chain:
*
* active vCenter → active Datacenter → active Host → active Datastore + Network
*
* Product / OS bindings are now informational only — the host/datacenter/vcenter
* configured per-product no longer drive VM creation. The whole platform clones
* onto whatever single chain is currently marked status=1.
* Product/OS host binding is informational only — it no longer drives VM
* creation. Datastore, network, resource pool and folder are exceptions: if
* the OS has datastore_id / module_network_id / resource_pool_id / folder_id
* set, they override the active chain / global default (an OS can target a
* different datastore/IP pool/resource pool/folder than whatever happens to
* be "active" or configured as the system-wide default).
*/
class VmInfrastructureResolver
{
public function __construct(
private readonly VmProvisionLogger $logger,
private readonly VmActiveProviderService $activeProvider,
private readonly VmProviderSettingsService $providerSettings,
) {
}
public function resolve(OrderItem $item, $product): VmInfrastructureContext
{
$os = Os::with('osGroup')->find($item->os_id);
$os = Os::with(['osGroup', 'network', 'datastore', 'resourcePool', 'folder'])->find($item->os_id);
if (!$os) {
throw new RuntimeException(
@@ -36,15 +40,25 @@ class VmInfrastructureResolver
);
}
$chain = $this->activeProvider->resolveChain();
$chain = $this->activeProvider->resolveChain();
$network = $os->network ?? $chain['network'];
$datastore = $os->datastore ?? $chain['datastore'];
$folderId = $os->folder?->folder ?? $this->providerSettings->defaultFolder();
$resourcePoolId = $os->resourcePool?->resource_pool ?? $this->providerSettings->defaultResourcePool();
$this->logger->step('Infrastructure resolved from active chain', [
'order_item_id' => $item->id,
'vcenter_id' => $chain['vcenter']->id,
'datacenter_id' => $chain['datacenter']->id,
'host_id' => $chain['host']->id,
'datastore_id' => $chain['datastore']->id,
'network_id' => $chain['network']->id,
'order_item_id' => $item->id,
'vcenter_id' => $chain['vcenter']->id,
'datacenter_id' => $chain['datacenter']->id,
'host_id' => $chain['host']->id,
'datastore_id' => $datastore->id,
'datastore_from_os' => $os->datastore !== null,
'network_id' => $network->id,
'network_from_os' => $os->network !== null,
'folder_id' => $folderId,
'folder_from_os' => $os->folder !== null,
'resource_pool_id' => $resourcePoolId,
'resource_pool_from_os' => $os->resourcePool !== null,
]);
$osGroupName = $os->osGroup?->name ?? '';
@@ -59,8 +73,10 @@ class VmInfrastructureResolver
isWindows: $isWindows,
vmUser: $isWindows ? 'administrator' : 'root',
vmPort: $isWindows ? 3389 : 22,
datastore: $chain['datastore'],
network: $chain['network'],
datastore: $datastore,
network: $network,
folderId: $folderId,
resourcePoolId: $resourcePoolId,
);
}
}