@@ -1352,10 +1352,7 @@ private UserVmResponse baseImportInstance(ImportUnmanagedInstanceCmd cmd) {
13521352 List <String > managedVms = new ArrayList <>(additionalNameFilters );
13531353 managedVms .addAll (getHostsManagedVms (hosts ));
13541354
1355- List <String > resourceLimitHostTags = resourceLimitService .getResourceLimitHostTags (serviceOffering , template );
1356- try (CheckedReservation vmReservation = new CheckedReservation (owner , Resource .ResourceType .user_vm , resourceLimitHostTags , 1L , reservationDao , resourceLimitService );
1357- CheckedReservation cpuReservation = new CheckedReservation (owner , Resource .ResourceType .cpu , resourceLimitHostTags , Long .valueOf (serviceOffering .getCpu ()), reservationDao , resourceLimitService );
1358- CheckedReservation memReservation = new CheckedReservation (owner , Resource .ResourceType .memory , resourceLimitHostTags , Long .valueOf (serviceOffering .getRamSize ()), reservationDao , resourceLimitService )) {
1355+ try {
13591356
13601357 ActionEventUtils .onStartedActionEvent (userId , owner .getId (), EventTypes .EVENT_VM_IMPORT ,
13611358 cmd .getEventDescription (), null , null , true , 0 );
@@ -1497,7 +1494,7 @@ private UserVm importUnmanagedInstanceFromHypervisor(DataCenter zone, Cluster cl
14971494 String hostName , Account caller , Account owner , long userId ,
14981495 ServiceOfferingVO serviceOffering , Map <String , Long > dataDiskOfferingMap ,
14991496 Map <String , Long > nicNetworkMap , Map <String , Network .IpAddresses > nicIpAddressMap ,
1500- Map <String , String > details , Boolean migrateAllowed , List <String > managedVms , boolean forced ) {
1497+ Map <String , String > details , Boolean migrateAllowed , List <String > managedVms , boolean forced ) throws ResourceAllocationException {
15011498 UserVm userVm = null ;
15021499 for (HostVO host : hosts ) {
15031500 HashMap <String , UnmanagedInstanceTO > unmanagedInstances = getUnmanagedInstancesForHost (host , instanceName , managedVms );
@@ -1541,11 +1538,18 @@ private UserVm importUnmanagedInstanceFromHypervisor(DataCenter zone, Cluster cl
15411538
15421539 template .setGuestOSId (guestOSHypervisor .getGuestOsId ());
15431540 }
1544- userVm = importVirtualMachineInternal (unmanagedInstance , instanceName , zone , cluster , host ,
1545- template , displayName , hostName , CallContext .current ().getCallingAccount (), owner , userId ,
1546- serviceOffering , dataDiskOfferingMap ,
1547- nicNetworkMap , nicIpAddressMap ,
1548- details , migrateAllowed , forced , true );
1541+
1542+ List <Reserver > reservations = new ArrayList <>();
1543+ try {
1544+ checkVmResourceLimitsForUnmanagedInstanceImport (owner , unmanagedInstance , serviceOffering , template , reservations );
1545+ userVm = importVirtualMachineInternal (unmanagedInstance , instanceName , zone , cluster , host ,
1546+ template , displayName , hostName , CallContext .current ().getCallingAccount (), owner , userId ,
1547+ serviceOffering , dataDiskOfferingMap ,
1548+ nicNetworkMap , nicIpAddressMap ,
1549+ details , migrateAllowed , forced , true );
1550+ } finally {
1551+ ReservationHelper .closeAll (reservations );
1552+ }
15491553 break ;
15501554 }
15511555 if (userVm != null ) {
@@ -1555,6 +1559,36 @@ private UserVm importUnmanagedInstanceFromHypervisor(DataCenter zone, Cluster cl
15551559 return userVm ;
15561560 }
15571561
1562+ private void checkVmResourceLimitsForUnmanagedInstanceImport (Account owner , UnmanagedInstanceTO unmanagedInstance , ServiceOfferingVO serviceOffering , VMTemplateVO template , List <Reserver > reservations ) throws ResourceAllocationException {
1563+ // When importing a unmanaged instance, the amount of CPUs and memory is obtained from the hypervisor unless powered off
1564+ // and not using a dynamic offering, unlike the external VM import that always obtains it from the compute offering
1565+ Integer cpu = serviceOffering .getCpu ();
1566+ Integer memory = serviceOffering .getRamSize ();
1567+
1568+ if (serviceOffering .isDynamic () || !unmanagedInstance .getPowerState ().equals (UnmanagedInstanceTO .PowerState .PowerOff )) {
1569+ cpu = unmanagedInstance .getCpuCores ();
1570+ memory = unmanagedInstance .getMemory ();
1571+ }
1572+
1573+ if (cpu == null || cpu == 0 ) {
1574+ throw new ServerApiException (ApiErrorCode .INTERNAL_ERROR , String .format ("CPU cores [%s] is not valid for importing VM [%s]." , cpu , unmanagedInstance .getName ()));
1575+ }
1576+ if (memory == null || memory == 0 ) {
1577+ throw new ServerApiException (ApiErrorCode .INTERNAL_ERROR , String .format ("Memory [%s] is not valid for importing VM [%s]." , memory , unmanagedInstance .getName ()));
1578+ }
1579+
1580+ List <String > resourceLimitHostTags = resourceLimitService .getResourceLimitHostTags (serviceOffering , template );
1581+
1582+ CheckedReservation vmReservation = new CheckedReservation (owner , Resource .ResourceType .user_vm , resourceLimitHostTags , 1L , reservationDao , resourceLimitService );
1583+ reservations .add (vmReservation );
1584+
1585+ CheckedReservation cpuReservation = new CheckedReservation (owner , Resource .ResourceType .cpu , resourceLimitHostTags , cpu .longValue (), reservationDao , resourceLimitService );
1586+ reservations .add (cpuReservation );
1587+
1588+ CheckedReservation memReservation = new CheckedReservation (owner , Resource .ResourceType .memory , resourceLimitHostTags , memory .longValue (), reservationDao , resourceLimitService );
1589+ reservations .add (memReservation );
1590+ }
1591+
15581592 private Pair <UnmanagedInstanceTO , Boolean > getSourceVmwareUnmanagedInstance (String vcenter , String datacenterName , String username ,
15591593 String password , String clusterName , String sourceHostName ,
15601594 String sourceVM ) {
@@ -1582,7 +1616,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
15821616 Account caller , Account owner , long userId ,
15831617 ServiceOfferingVO serviceOffering , Map <String , Long > dataDiskOfferingMap ,
15841618 Map <String , Long > nicNetworkMap , Map <String , Network .IpAddresses > nicIpAddressMap ,
1585- Map <String , String > details , ImportVmCmd cmd , boolean forced ) {
1619+ Map <String , String > details , ImportVmCmd cmd , boolean forced ) throws ResourceAllocationException {
15861620 Long existingVcenterId = cmd .getExistingVcenterId ();
15871621 String vcenter = cmd .getVcenter ();
15881622 String datacenterName = cmd .getDatacenterName ();
@@ -1620,6 +1654,8 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
16201654 UnmanagedInstanceTO sourceVMwareInstance = null ;
16211655 DataStoreTO temporaryConvertLocation = null ;
16221656 String ovfTemplateOnConvertLocation = null ;
1657+ List <Reserver > reservations = new ArrayList <>();
1658+
16231659 try {
16241660 HostVO convertHost = selectKVMHostForConversionInCluster (destinationCluster , convertInstanceHostId );
16251661 HostVO importHost = selectKVMHostForImportingInCluster (destinationCluster , importInstanceHostId );
@@ -1634,6 +1670,10 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
16341670 Pair <UnmanagedInstanceTO , Boolean > sourceInstanceDetails = getSourceVmwareUnmanagedInstance (vcenter , datacenterName , username , password , clusterName , sourceHostName , sourceVMName );
16351671 sourceVMwareInstance = sourceInstanceDetails .first ();
16361672 isClonedInstance = sourceInstanceDetails .second ();
1673+
1674+ // Ensure that the configured resource limits will not be exceeded before beggining the conversion process
1675+ checkVmResourceLimitsForUnmanagedInstanceImport (owner , sourceVMwareInstance , serviceOffering , template , reservations );
1676+
16371677 boolean isWindowsVm = sourceVMwareInstance .getOperatingSystem ().toLowerCase ().contains ("windows" );
16381678 if (isWindowsVm ) {
16391679 checkConversionSupportOnHost (convertHost , sourceVMName , true );
@@ -1681,6 +1721,7 @@ protected UserVm importUnmanagedInstanceFromVmwareToKvm(DataCenter zone, Cluster
16811721 if (temporaryConvertLocation != null && StringUtils .isNotBlank (ovfTemplateOnConvertLocation )) {
16821722 removeTemplate (temporaryConvertLocation , ovfTemplateOnConvertLocation );
16831723 }
1724+ ReservationHelper .closeAll (reservations );
16841725 }
16851726 }
16861727
@@ -2400,10 +2441,7 @@ private UserVmResponse importKvmInstance(ImportVmCmd cmd) {
24002441
24012442 UserVm userVm = null ;
24022443
2403- List <String > resourceLimitHostTags = resourceLimitService .getResourceLimitHostTags (serviceOffering , template );
2404- try (CheckedReservation vmReservation = new CheckedReservation (owner , Resource .ResourceType .user_vm , resourceLimitHostTags , 1L , reservationDao , resourceLimitService );
2405- CheckedReservation cpuReservation = new CheckedReservation (owner , Resource .ResourceType .cpu , resourceLimitHostTags , Long .valueOf (serviceOffering .getCpu ()), reservationDao , resourceLimitService );
2406- CheckedReservation memReservation = new CheckedReservation (owner , Resource .ResourceType .memory , resourceLimitHostTags , Long .valueOf (serviceOffering .getRamSize ()), reservationDao , resourceLimitService )) {
2444+ try {
24072445
24082446 if (ImportSource .EXTERNAL == importSource ) {
24092447 String username = cmd .getUsername ();
@@ -2466,6 +2504,7 @@ private UserVm importExternalKvmVirtualMachine(final UnmanagedInstanceTO unmanag
24662504
24672505 List <Reserver > reservations = new ArrayList <>();
24682506 try {
2507+ checkVmResourceLimitsForExternalKvmVmImport (owner , serviceOffering , (VMTemplateVO ) template , details , reservations );
24692508 checkVolumeResourceLimitsForExternalKvmVmImport (owner , rootDisk , dataDisks , diskOffering , dataDiskOfferingMap , reservations );
24702509
24712510 // Check NICs and supplied networks
@@ -2630,24 +2669,20 @@ private UserVm importKvmVirtualMachineFromDisk(final ImportSource importSource,
26302669 profiles .add (nicProfile );
26312670 networkNicMap .put (network .getUuid (), profiles );
26322671
2672+ List <Reserver > reservations = new ArrayList <>();
26332673 try {
2674+ checkVmResourceLimitsForExternalKvmVmImport (owner , serviceOffering , (VMTemplateVO ) template , details , reservations );
26342675 userVm = userVmManager .importVM (zone , null , template , null , displayName , owner ,
26352676 null , caller , true , null , owner .getAccountId (), userId ,
26362677 serviceOffering , null , hostName ,
26372678 Hypervisor .HypervisorType .KVM , allDetails , powerState , networkNicMap );
2638- } catch (InsufficientCapacityException ice ) {
2639- logger .error (String .format ("Failed to import vm name: %s" , instanceName ), ice );
2640- throw new ServerApiException (ApiErrorCode .INSUFFICIENT_CAPACITY_ERROR , ice .getMessage ());
2641- }
2642- if (userVm == null ) {
2643- throw new ServerApiException (ApiErrorCode .INTERNAL_ERROR , String .format ("Failed to import vm name: %s" , instanceName ));
2644- }
26452679
2646- DiskOfferingVO diskOffering = diskOfferingDao .findById (serviceOffering .getDiskOfferingId ());
2680+ if (userVm == null ) {
2681+ throw new ServerApiException (ApiErrorCode .INTERNAL_ERROR , String .format ("Failed to import vm name: %s" , instanceName ));
2682+ }
26472683
2648- List <Reserver > reservations = new ArrayList <>();
2649- List <String > resourceLimitStorageTags = resourceLimitService .getResourceLimitStorageTagsForResourceCountOperation (true , diskOffering );
2650- try {
2684+ DiskOfferingVO diskOffering = diskOfferingDao .findById (serviceOffering .getDiskOfferingId ());
2685+ List <String > resourceLimitStorageTags = resourceLimitService .getResourceLimitStorageTagsForResourceCountOperation (true , diskOffering );
26512686 CheckedReservation volumeReservation = new CheckedReservation (owner , Resource .ResourceType .volume , resourceLimitStorageTags ,
26522687 CollectionUtils .isNotEmpty (resourceLimitStorageTags ) ? 1L : 0L , reservationDao , resourceLimitService );
26532688 reservations .add (volumeReservation );
@@ -2720,6 +2755,9 @@ private UserVm importKvmVirtualMachineFromDisk(final ImportSource importSource,
27202755 publishVMUsageUpdateResourceCount (userVm , dummyOffering , template );
27212756 return userVm ;
27222757
2758+ } catch (InsufficientCapacityException ice ) { // This will be thrown by com.cloud.vm.UserVmService.importVM
2759+ logger .error (String .format ("Failed to import vm name: %s" , instanceName ), ice );
2760+ throw new ServerApiException (ApiErrorCode .INSUFFICIENT_CAPACITY_ERROR , ice .getMessage ());
27232761 } catch (ResourceAllocationException e ) {
27242762 cleanupFailedImportVM (userVm );
27252763 throw e ;
@@ -2728,6 +2766,41 @@ private UserVm importKvmVirtualMachineFromDisk(final ImportSource importSource,
27282766 }
27292767 }
27302768
2769+ private void checkVmResourceLimitsForExternalKvmVmImport (Account owner , ServiceOfferingVO serviceOffering , VMTemplateVO template , Map <String , String > details , List <Reserver > reservations ) throws ResourceAllocationException {
2770+ // When importing an external VM, the amount of CPUs and memory is always obtained from the compute offering,
2771+ // unlike the unmanaged instance import that obtains it from the hypervisor unless the VM is powered off and the offering is fixed
2772+ Integer cpu = serviceOffering .getCpu ();
2773+ Integer memory = serviceOffering .getRamSize ();
2774+
2775+ if (serviceOffering .isDynamic ()) {
2776+ cpu = getDetailAsInteger (VmDetailConstants .CPU_NUMBER , details );
2777+ memory = getDetailAsInteger (VmDetailConstants .MEMORY , details );
2778+ }
2779+
2780+ List <String > resourceLimitHostTags = resourceLimitService .getResourceLimitHostTags (serviceOffering , template );
2781+
2782+ CheckedReservation vmReservation = new CheckedReservation (owner , Resource .ResourceType .user_vm , resourceLimitHostTags , 1L , reservationDao , resourceLimitService );
2783+ reservations .add (vmReservation );
2784+
2785+ CheckedReservation cpuReservation = new CheckedReservation (owner , Resource .ResourceType .cpu , resourceLimitHostTags , cpu .longValue (), reservationDao , resourceLimitService );
2786+ reservations .add (cpuReservation );
2787+
2788+ CheckedReservation memReservation = new CheckedReservation (owner , Resource .ResourceType .memory , resourceLimitHostTags , memory .longValue (), reservationDao , resourceLimitService );
2789+ reservations .add (memReservation );
2790+ }
2791+
2792+ private Integer getDetailAsInteger (String key , Map <String , String > details ) {
2793+ String detail = details .get (key );
2794+ if (detail == null ) {
2795+ throw new InvalidParameterValueException (String .format ("Detail '%s' must be provided." , key ));
2796+ }
2797+ try {
2798+ return Integer .valueOf (detail );
2799+ } catch (NumberFormatException e ) {
2800+ throw new InvalidParameterValueException (String .format ("Please provide a valid integer value for detail '%s'." , key ));
2801+ }
2802+ }
2803+
27312804 private void checkVolume (Map <VolumeOnStorageTO .Detail , String > volumeDetails ) {
27322805 if (MapUtils .isEmpty (volumeDetails )) {
27332806 return ;
0 commit comments