mirror of https://github.com/apache/cloudstack.git
VM.CREATE/VOLUME.DELETE/VOLUME.DESTROY not being emitted (#7760)
VM.CREATE/VOLUME.DELETE/VOLUME.DESTROY not being emitted * Update server/src/main/java/com/cloud/vm/UserVmManagerImpl.java Co-authored-by: dahn <daan.hoogland@gmail.com> * Update api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeployVMCmd.java Co-authored-by: dahn <daan.hoogland@gmail.com> --------- Co-authored-by: Maxim Prokopchuk <mprokopchuk@apple.com> Co-authored-by: dahn <daan.hoogland@gmail.com>
This commit is contained in:
parent
dc5e4f3ec6
commit
ab0297ea9b
|
|
@ -163,6 +163,8 @@ public interface VolumeApiService {
|
|||
|
||||
Volume destroyVolume(long volumeId, Account caller, boolean expunge, boolean forceExpunge);
|
||||
|
||||
void destroyVolume(long volumeId);
|
||||
|
||||
Volume recoverVolume(long volumeId);
|
||||
|
||||
void validateCustomDiskOfferingSizeRange(Long sizeInGB);
|
||||
|
|
|
|||
|
|
@ -432,6 +432,14 @@ public interface UserVmService {
|
|||
UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException,
|
||||
StorageUnavailableException, ResourceAllocationException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* However, it can be used for additional VM customization in the future.
|
||||
* @param vmId - Virtual Machine Id
|
||||
* @return - Virtual Machine
|
||||
*/
|
||||
UserVm finalizeCreateVirtualMachine(long vmId);
|
||||
|
||||
UserVm getUserVm(long vmId);
|
||||
|
||||
VirtualMachine getVm(long vmId);
|
||||
|
|
|
|||
|
|
@ -753,7 +753,10 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||
|
||||
@Override
|
||||
public String getEventDescription() {
|
||||
return "starting Vm. Vm Id: " + getEntityUuid();
|
||||
if(getStartVm()) {
|
||||
return "starting Vm. Vm Id: " + getEntityUuid();
|
||||
}
|
||||
return "deploying Vm. Vm Id: " + getEntityUuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -765,28 +768,33 @@ public class DeployVMCmd extends BaseAsyncCreateCustomIdCmd implements SecurityG
|
|||
public void execute() {
|
||||
UserVm result;
|
||||
|
||||
try {
|
||||
CallContext.current().setEventDetails("Vm Id: " + getEntityUuid());
|
||||
result = _userVmService.startVirtualMachine(this);
|
||||
} catch (ResourceUnavailableException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
||||
} catch (ResourceAllocationException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
|
||||
} catch (ConcurrentOperationException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
|
||||
} catch (InsufficientCapacityException ex) {
|
||||
StringBuilder message = new StringBuilder(ex.getMessage());
|
||||
if (ex instanceof InsufficientServerCapacityException) {
|
||||
if (((InsufficientServerCapacityException)ex).isAffinityApplied()) {
|
||||
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
|
||||
CallContext.current().setEventDetails("Vm Id: " + getEntityUuid());
|
||||
if (getStartVm()) {
|
||||
try {
|
||||
result = _userVmService.startVirtualMachine(this);
|
||||
} catch (ResourceUnavailableException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
|
||||
} catch (ResourceAllocationException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage());
|
||||
} catch (ConcurrentOperationException ex) {
|
||||
s_logger.warn("Exception: ", ex);
|
||||
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
|
||||
} catch (InsufficientCapacityException ex) {
|
||||
StringBuilder message = new StringBuilder(ex.getMessage());
|
||||
if (ex instanceof InsufficientServerCapacityException) {
|
||||
if (((InsufficientServerCapacityException)ex).isAffinityApplied()) {
|
||||
message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them");
|
||||
}
|
||||
}
|
||||
s_logger.info(String.format("%s: %s", message.toString(), ex.getLocalizedMessage()));
|
||||
s_logger.debug(message.toString(), ex);
|
||||
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
|
||||
}
|
||||
s_logger.info(ex);
|
||||
s_logger.info(message.toString(), ex);
|
||||
throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString());
|
||||
} else {
|
||||
s_logger.info("VM " + getEntityUuid() + " already created, load UserVm from DB");
|
||||
result = _userVmService.finalizeCreateVirtualMachine(getEntityId());
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
|
|
|
|||
|
|
@ -500,22 +500,29 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
|
|||
|
||||
allocateRootVolume(persistedVm, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
|
||||
|
||||
if (dataDiskOfferings != null) {
|
||||
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
|
||||
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, null);
|
||||
// Create new Volume context and inject event resource type, id and details to generate VOLUME.CREATE event for the ROOT disk.
|
||||
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
|
||||
try {
|
||||
if (dataDiskOfferings != null) {
|
||||
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId(), dataDiskOfferingInfo.getDiskOffering(), dataDiskOfferingInfo.getSize(),
|
||||
dataDiskOfferingInfo.getMinIops(), dataDiskOfferingInfo.getMaxIops(), persistedVm, template, owner, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
|
||||
int diskNumber = 1;
|
||||
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
|
||||
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
|
||||
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
|
||||
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
|
||||
persistedVm, dataDiskTemplate, owner, Long.valueOf(diskNumber));
|
||||
diskNumber++;
|
||||
if (datadiskTemplateToDiskOfferingMap != null && !datadiskTemplateToDiskOfferingMap.isEmpty()) {
|
||||
int diskNumber = 1;
|
||||
for (Entry<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap : datadiskTemplateToDiskOfferingMap.entrySet()) {
|
||||
DiskOffering diskOffering = dataDiskTemplateToDiskOfferingMap.getValue();
|
||||
long diskOfferingSize = diskOffering.getDiskSize() / (1024 * 1024 * 1024);
|
||||
VMTemplateVO dataDiskTemplate = _templateDao.findById(dataDiskTemplateToDiskOfferingMap.getKey());
|
||||
volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + persistedVm.getId() + "-" + String.valueOf(diskNumber), diskOffering, diskOfferingSize, null, null,
|
||||
persistedVm, dataDiskTemplate, owner, Long.valueOf(diskNumber));
|
||||
diskNumber++;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Remove volumeContext and pop vmContext back
|
||||
CallContext.unregister();
|
||||
}
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||
vol.getTemplateId());
|
||||
}
|
||||
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating ROOT volume", create = true)
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true)
|
||||
@Override
|
||||
public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, Account owner,
|
||||
Long deviceId) {
|
||||
|
|
@ -1035,13 +1035,13 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||
private void updateRootDiskVolumeEventDetails(Type type, VirtualMachine vm, List<DiskProfile> diskProfiles) {
|
||||
CallContext callContext = CallContext.current();
|
||||
// Update only for volume type ROOT and API command resource type Volume
|
||||
if (type == Type.ROOT && callContext != null && callContext.getEventResourceType() == ApiCommandResourceType.Volume) {
|
||||
if ((type == Type.ROOT || type == Type.DATADISK) && callContext != null && callContext.getEventResourceType() == ApiCommandResourceType.Volume) {
|
||||
List<Long> volumeIds = diskProfiles.stream().map(DiskProfile::getVolumeId).filter(volumeId -> volumeId != null).collect(Collectors.toList());
|
||||
if (!volumeIds.isEmpty()) {
|
||||
callContext.setEventResourceId(volumeIds.get(0));
|
||||
}
|
||||
String volumeUuids = volumeIds.stream().map(volumeId -> this._uuidMgr.getUuid(Volume.class, volumeId)).collect(Collectors.joining(", "));
|
||||
callContext.setEventDetails("Volume Id: " + volumeUuids + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, vm.getId()));
|
||||
callContext.setEventDetails("Volume Type: " + type + "Volume Id: " + volumeUuids + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, vm.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1245,7 +1245,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||
// Destroy volume if not already destroyed
|
||||
boolean volumeAlreadyDestroyed = (vol.getState() == Volume.State.Destroy || vol.getState() == Volume.State.Expunged || vol.getState() == Volume.State.Expunging);
|
||||
if (!volumeAlreadyDestroyed) {
|
||||
volService.destroyVolume(vol.getId());
|
||||
destroyVolumeInContext(vol);
|
||||
} else {
|
||||
s_logger.debug(String.format("Skipping destroy for the volume [%s] as it is in [%s] state.", volumeToString, vol.getState().toString()));
|
||||
}
|
||||
|
|
@ -1277,6 +1277,21 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||
}
|
||||
}
|
||||
|
||||
private void destroyVolumeInContext(Volume volume) {
|
||||
// Create new context and inject correct event resource type, id and details,
|
||||
// otherwise VOLUME.DESTROY event will be associated with VirtualMachine and contain VM id and other information.
|
||||
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
|
||||
volumeContext.setEventDetails("Volume Type: " + volume.getVolumeType() + " Volume Id: " + volume.getUuid() + " Vm Id: " + _uuidMgr.getUuid(VirtualMachine.class, volume.getInstanceId()));
|
||||
volumeContext.setEventResourceType(ApiCommandResourceType.Volume);
|
||||
volumeContext.setEventResourceId(volume.getId());
|
||||
try {
|
||||
_volumeApiService.destroyVolume(volume.getId());
|
||||
} finally {
|
||||
// Remove volumeContext and pop vmContext back
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeAccess(DataObject dataObject, Host host, DataStore dataStore) {
|
||||
DataStoreDriver dataStoreDriver = dataStore != null ? dataStore.getDriver() : null;
|
||||
|
|
@ -2080,7 +2095,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
|
|||
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume, volume.isDisplay());
|
||||
_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, volume.isDisplay(), new Long(volume.getSize()));
|
||||
} else {
|
||||
volService.destroyVolume(volume.getId());
|
||||
destroyVolumeInContext(volume);
|
||||
}
|
||||
// FIXME - All this is boiler plate code and should be done as part of state transition. This shouldn't be part of orchestrator.
|
||||
// publish usage event for the volume
|
||||
|
|
|
|||
|
|
@ -721,6 +721,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
|
||||
|
||||
Filter searchFilter = new Filter(EventJoinVO.class, "createDate", false, cmd.getStartIndex(), cmd.getPageSizeVal());
|
||||
// additional order by since createdDate does not have milliseconds
|
||||
// and two events, created within one second can be incorrectly ordered (for example VM.CREATE Completed before Scheduled)
|
||||
searchFilter.addOrderBy(EventJoinVO.class, "id", false);
|
||||
|
||||
SearchBuilder<EventJoinVO> sb = _eventJoinDao.createSearchBuilder();
|
||||
_accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
|
||||
|
||||
|
|
|
|||
|
|
@ -1728,6 +1728,12 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
|
|||
return volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DESTROY, eventDescription = "destroying a volume")
|
||||
public void destroyVolume(long volumeId) {
|
||||
volService.destroyVolume(volumeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_RECOVER, eventDescription = "recovering a volume in Destroy state")
|
||||
public Volume recoverVolume(long volumeId) {
|
||||
|
|
|
|||
|
|
@ -3272,7 +3272,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
|
||||
autoScaleManager.removeVmFromVmGroup(vmId);
|
||||
|
||||
deleteVolumesFromVm(volumesToBeDeleted, expunge);
|
||||
deleteVolumesFromVm(vm, volumesToBeDeleted, expunge);
|
||||
|
||||
if (getDestroyRootVolumeOnVmDestruction(vm.getDomainId())) {
|
||||
VolumeVO rootVolume = _volsDao.getInstanceRootVolume(vm.getId());
|
||||
|
|
@ -3716,6 +3716,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
dataDiskTemplateToDiskOfferingMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, overrideDiskOfferingId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "deploying Vm")
|
||||
public UserVm finalizeCreateVirtualMachine(long vmId) {
|
||||
s_logger.info("Loading UserVm " + vmId + " from DB");
|
||||
UserVm userVm = getUserVm(vmId);
|
||||
if (userVm == null) {
|
||||
s_logger.info("Loaded UserVm " + vmId + " (" + userVm.getUuid() + ") from DB");
|
||||
} else {
|
||||
s_logger.warn("UserVm " + vmId + " does not exist in DB");
|
||||
}
|
||||
return userVm;
|
||||
}
|
||||
|
||||
private NetworkVO getNetworkToAddToNetworkList(VirtualMachineTemplate template, Account owner, HypervisorType hypervisor,
|
||||
List<HypervisorType> vpcSupportedHTypes, Long networkId) {
|
||||
NetworkVO network = _networkDao.findById(networkId);
|
||||
|
|
@ -8002,7 +8015,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
// Create new context and inject correct event resource type, id and details,
|
||||
// otherwise VOLUME.DETACH event will be associated with VirtualMachine and contain VM id and other information.
|
||||
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
|
||||
volumeContext.setEventDetails("Volume Id: " + this._uuidMgr.getUuid(Volume.class, volume.getId()) + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, volume.getInstanceId()));
|
||||
volumeContext.setEventDetails("Volume Type: " + volume.getVolumeType() + " Volume Id: " + this._uuidMgr.getUuid(Volume.class, volume.getId()) + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, volume.getInstanceId()));
|
||||
volumeContext.setEventResourceType(ApiCommandResourceType.Volume);
|
||||
volumeContext.setEventResourceId(volume.getId());
|
||||
|
||||
|
|
@ -8020,15 +8033,29 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
|
|||
}
|
||||
}
|
||||
|
||||
private void deleteVolumesFromVm(List<VolumeVO> volumes, boolean expunge) {
|
||||
private void deleteVolumesFromVm(UserVmVO vm, List<VolumeVO> volumes, boolean expunge) {
|
||||
|
||||
for (VolumeVO volume : volumes) {
|
||||
destroyVolumeInContext(vm, expunge, volume);
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyVolumeInContext(UserVmVO vm, boolean expunge, VolumeVO volume) {
|
||||
// Create new context and inject correct event resource type, id and details,
|
||||
// otherwise VOLUME.DESTROY event will be associated with VirtualMachine and contain VM id and other information.
|
||||
CallContext volumeContext = CallContext.register(CallContext.current(), ApiCommandResourceType.Volume);
|
||||
volumeContext.setEventDetails("Volume Type: " + volume.getVolumeType() + " Volume Id: " + this._uuidMgr.getUuid(Volume.class, volume.getId()) + " Vm Id: " + vm.getUuid());
|
||||
volumeContext.setEventResourceType(ApiCommandResourceType.Volume);
|
||||
volumeContext.setEventResourceId(volume.getId());
|
||||
try {
|
||||
Volume result = _volumeService.destroyVolume(volume.getId(), CallContext.current().getCallingAccount(), expunge, false);
|
||||
|
||||
if (result == null) {
|
||||
s_logger.error("DestroyVM remove volume - failed to delete volume " + volume.getInstanceId() + " from instance " + volume.getId());
|
||||
s_logger.error(String.format("DestroyVM remove volume - failed to delete volume %s from instance %s", volume.getId(), volume.getInstanceId()));
|
||||
}
|
||||
} finally {
|
||||
// Remove volumeContext and pop vmContext back
|
||||
CallContext.unregister();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
# under the License.
|
||||
""" BVT tests for Events Resource
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
|
|
@ -184,7 +185,7 @@ class TestEventsResource(cloudstackTestCase):
|
|||
for event in events:
|
||||
if event.type.startswith("VM.") or (event.type.startswith("NETWORK.") and not event.type.startswith("NETWORK.ELEMENT")) or event.type.startswith("VOLUME.") or event.type.startswith("ACCOUNT.") or event.type.startswith("DOMAIN.") or event.type.startswith("TEMPLATE."):
|
||||
if event.resourceid is None or event.resourcetype is None:
|
||||
self.debug("Failed event:: %" % event)
|
||||
self.debug("Failed event:: %s" % json.dumps(event, indent=2))
|
||||
self.fail("resourceid or resourcetype for the event not found!")
|
||||
else:
|
||||
self.debug("Event %s at %s:: Resource Type: %s, Resource ID: %s" % (event.type, event.created, event.resourcetype, event.resourceid))
|
||||
|
|
|
|||
Loading…
Reference in New Issue