Skip to content

Commit 32448e1

Browse files
committed
Merge branch '4.18'
2 parents 55f0801 + dea1373 commit 32448e1

12 files changed

Lines changed: 213 additions & 64 deletions

File tree

api/src/main/java/com/cloud/storage/VolumeApiService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account acc
164164

165165
Volume destroyVolume(long volumeId, Account caller, boolean expunge, boolean forceExpunge);
166166

167+
void destroyVolume(long volumeId);
168+
167169
Volume recoverVolume(long volumeId);
168170

169171
void validateCustomDiskOfferingSizeRange(Long sizeInGB);

api/src/main/java/com/cloud/vm/UserVmService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffe
429429
UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
430430
StorageUnavailableException, ResourceAllocationException;
431431

432+
/**
433+
* This API is mostly to trigger VM.CREATE event for deployVirtualMachine with startvm=false, because there is no code in "execute" part of VM creation.
434+
* However, it can be used for additional VM customization in the future.
435+
* @param vmId - Virtual Machine Id
436+
* @return - Virtual Machine
437+
*/
438+
UserVm finalizeCreateVirtualMachine(long vmId);
439+
432440
UserVm getUserVm(long vmId);
433441

434442
VirtualMachine getVm(long vmId);

api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,10 @@ public String getCreateEventDescription() {
769769

770770
@Override
771771
public String getEventDescription() {
772-
return "starting Vm. Vm Id: " + getEntityUuid();
772+
if(getStartVm()) {
773+
return "starting Vm. Vm Id: " + getEntityUuid();
774+
}
775+
return "deploying Vm. Vm Id: " + getEntityUuid();
773776
}
774777

775778
@Override
@@ -781,28 +784,33 @@ public ApiCommandResourceType getApiResourceType() {
781784
public void execute() {
782785
UserVm result;
783786

784-
try {
785-
CallContext.current().setEventDetails("Vm Id: " + getEntityUuid());
786-
result = _userVmService.startVirtualMachine(this);
787-
} catch (ResourceUnavailableException ex) {
788-
s_logger.warn("Exception: ", ex);
789-
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
790-
} catch (ResourceAllocationException ex) {
791-
s_logger.warn("Exception: ", ex);
792-
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
793-
} catch (ConcurrentOperationException ex) {
794-
s_logger.warn("Exception: ", ex);
795-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
796-
} catch (InsufficientCapacityException ex) {
797-
StringBuilder message = new StringBuilder(ex.getMessage());
798-
if (ex instanceof InsufficientServerCapacityException) {
799-
if (((InsufficientServerCapacityException)ex).isAffinityApplied()) {
800-
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
787+
CallContext.current().setEventDetails("Vm Id: " + getEntityUuid());
788+
if (getStartVm()) {
789+
try {
790+
result = _userVmService.startVirtualMachine(this);
791+
} catch (ResourceUnavailableException ex) {
792+
s_logger.warn("Exception: ", ex);
793+
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
794+
} catch (ResourceAllocationException ex) {
795+
s_logger.warn("Exception: ", ex);
796+
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
797+
} catch (ConcurrentOperationException ex) {
798+
s_logger.warn("Exception: ", ex);
799+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
800+
} catch (InsufficientCapacityException ex) {
801+
StringBuilder message = new StringBuilder(ex.getMessage());
802+
if (ex instanceof InsufficientServerCapacityException) {
803+
if (((InsufficientServerCapacityException)ex).isAffinityApplied()) {
804+
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
805+
}
801806
}
807+
s_logger.info(String.format("%s: %s", message.toString(), ex.getLocalizedMessage()));
808+
s_logger.debug(message.toString(), ex);
809+
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
802810
}
803-
s_logger.info(ex);
804-
s_logger.info(message.toString(), ex);
805-
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
811+
} else {
812+
s_logger.info("VM " + getEntityUuid() + " already created, load UserVm from DB");
813+
result = _userVmService.finalizeCreateVirtualMachine(getEntityId());
806814
}
807815

808816
if (result != null) {

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -500,22 +500,29 @@ public void allocate(final String vmInstanceName, final VirtualMachineTemplate t
500500

501501
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
502502

503-
if (dataDiskOfferings != null) {
504-
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
505-
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
506-
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, null);
503+
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
504+
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
505+
try {
506+
if (dataDiskOfferings != null) {
507+
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
508+
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
509+
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, null);
510+
}
507511
}
508-
}
509-
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
510-
int diskNumber = 1;
511-
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
512-
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
513-
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
514-
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
515-
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
516-
persistedVm, dataDiskTemplate, owner, Long.valueOf(diskNumber));
517-
diskNumber++;
512+
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
513+
int diskNumber = 1;
514+
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
515+
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
516+
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
517+
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
518+
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
519+
persistedVm, dataDiskTemplate, owner, Long.valueOf(diskNumber));
520+
diskNumber++;
521+
}
518522
}
523+
} finally {
524+
// Remove volumeContext and pop vmContext back
525+
CallContext.unregister();
519526
}
520527

521528
if (s_logger.isDebugEnabled()) {

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ protected DiskProfile toDiskProfile(Volume vol, DiskOffering offering) {
819819
vol.getTemplateId());
820820
}
821821

822-
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating ROOT volume", create = true)
822+
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true)
823823
@Override
824824
public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, Account owner,
825825
Long deviceId) {
@@ -1035,13 +1035,13 @@ public List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOf
10351035
private void updateRootDiskVolumeEventDetails(Type type, VirtualMachine vm, List<DiskProfile> diskProfiles) {
10361036
CallContext callContext = CallContext.current();
10371037
// Update only for volume type ROOT and API command resource type Volume
1038-
if (type == Type.ROOT && callContext != null && callContext.getEventResourceType() == ApiCommandResourceType.Volume) {
1038+
if ((type == Type.ROOT || type == Type.DATADISK) && callContext != null && callContext.getEventResourceType() == ApiCommandResourceType.Volume) {
10391039
List<Long> volumeIds = diskProfiles.stream().map(DiskProfile::getVolumeId).filter(volumeId -> volumeId != null).collect(Collectors.toList());
10401040
if (!volumeIds.isEmpty()) {
10411041
callContext.setEventResourceId(volumeIds.get(0));
10421042
}
10431043
String volumeUuids = volumeIds.stream().map(volumeId -> this._uuidMgr.getUuid(Volume.class, volumeId)).collect(Collectors.joining(", "));
1044-
callContext.setEventDetails("Volume Id: " + volumeUuids + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, vm.getId()));
1044+
callContext.setEventDetails("Volume Type: " + type + "Volume Id: " + volumeUuids + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, vm.getId()));
10451045
}
10461046
}
10471047

@@ -1245,7 +1245,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
12451245
// Destroy volume if not already destroyed
12461246
boolean volumeAlreadyDestroyed = (vol.getState() == Volume.State.Destroy || vol.getState() == Volume.State.Expunged || vol.getState() == Volume.State.Expunging);
12471247
if (!volumeAlreadyDestroyed) {
1248-
volService.destroyVolume(vol.getId());
1248+
destroyVolumeInContext(vol);
12491249
} else {
12501250
s_logger.debug(String.format("Skipping destroy for the volume [%s] as it is in [%s] state.", volumeToString, vol.getState().toString()));
12511251
}
@@ -1277,6 +1277,21 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
12771277
}
12781278
}
12791279

1280+
private void destroyVolumeInContext(Volume volume) {
1281+
// Create new context and inject correct event resource type, id and details,
1282+
// otherwise VOLUME.DESTROY event will be associated with VirtualMachine and contain VM id and other information.
1283+
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
1284+
volumeContext.setEventDetails("Volume Type: " + volume.getVolumeType() + " Volume Id: " + volume.getUuid() + " Vm Id: " + _uuidMgr.getUuid(VirtualMachine.class, volume.getInstanceId()));
1285+
volumeContext.setEventResourceType(ApiCommandResourceType.Volume);
1286+
volumeContext.setEventResourceId(volume.getId());
1287+
try {
1288+
_volumeApiService.destroyVolume(volume.getId());
1289+
} finally {
1290+
// Remove volumeContext and pop vmContext back
1291+
CallContext.unregister();
1292+
}
1293+
}
1294+
12801295
@Override
12811296
public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) {
12821297
DataStoreDriver dataStoreDriver = dataStore != null ? dataStore.getDriver() : null;
@@ -2080,7 +2095,7 @@ public void destroyVolume(Volume volume) {
20802095
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplay());
20812096
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplay(), new Long(volume.getSize()));
20822097
} else {
2083-
volService.destroyVolume(volume.getId());
2098+
destroyVolumeInContext(volume);
20842099
}
20852100
// FIXME - All this is boiler plate code and should be done as part of state transition. This shouldn't be part of orchestrator.
20862101
// publish usage event for the volume

engine/schema/src/main/resources/META-INF/db/schema-41800to41810.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VM
3131
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VMware', '8.0', 'windows2019srvNext_64Guest');
3232
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'VMware', '8.0.0.1', 'windows2019srvNext_64Guest');
3333
CALL ADD_GUEST_OS_AND_HYPERVISOR_MAPPING (6, 'Windows Server 2022 (64-bit)', 'Xenserver', '8.2.0', 'Windows Server 2022 (64-bit)');
34+
35+
-- Don't enable CPU cap for default system offerings, fixes regression from https://github.com/apache/cloudstack/pull/6420
36+
UPDATE `cloud`.`service_offering` so
37+
SET so.limit_cpu_use = 0
38+
WHERE so.default_use = 1 AND so.vm_type IN ('domainrouter', 'secondarystoragevm', 'consoleproxy', 'internalloadbalancervm', 'elasticloadbalancervm');

server/src/main/java/com/cloud/api/query/QueryManagerImpl.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,10 @@ private Pair<List<EventJoinVO>, Integer> searchForEventsInternal(ListEventsCmd c
727727
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
728728

729729
Filter searchFilter = new Filter(EventJoinVO.class, "createDate", false, cmd.getStartIndex(), cmd.getPageSizeVal());
730+
// additional order by since createdDate does not have milliseconds
731+
// and two events, created within one second can be incorrectly ordered (for example VM.CREATE Completed before Scheduled)
732+
searchFilter.addOrderBy(EventJoinVO.class, "id", false);
733+
730734
SearchBuilder<EventJoinVO> sb = _eventJoinDao.createSearchBuilder();
731735
_accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
732736

@@ -1317,7 +1321,7 @@ private Pair<List<UserVmJoinVO>, Integer> searchForUserVMsInternal(ListVMsCmd cm
13171321
vmIds[i++] = v.getId();
13181322
}
13191323
List<UserVmJoinVO> vms = _userVmJoinDao.searchByIds(vmIds);
1320-
return new Pair<List<UserVmJoinVO>, Integer>(vms, count);
1324+
return new Pair<>(vms, count);
13211325
}
13221326

13231327
@Override

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,6 +1728,12 @@ public Volume destroyVolume(long volumeId, Account caller, boolean expunge, bool
17281728
return volume;
17291729
}
17301730

1731+
@Override
1732+
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DESTROY, eventDescription = "destroying a volume")
1733+
public void destroyVolume(long volumeId) {
1734+
volService.destroyVolume(volumeId);
1735+
}
1736+
17311737
@Override
17321738
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_RECOVER, eventDescription = "recovering a volume in Destroy state")
17331739
public Volume recoverVolume(long volumeId) {

0 commit comments

Comments
 (0)