From ceb4e9dd3312680fb530ffe0d3a9e4c7a9c5c5bb Mon Sep 17 00:00:00 2001 From: mprokopchuk Date: Wed, 30 Nov 2022 10:35:05 -0800 Subject: [PATCH] When VM is created and ROOT volume is created it should emit a VOLUME.CREATE event (#209) * When VM is created and ROOT volume is created it should emit a VOLUME.CREATE event * added space between methods * Updated volume context comments. Co-authored-by: Maxim Prokopchuk --- .../cloudstack/context/CallContext.java | 14 +++++++ .../cloud/vm/VirtualMachineManagerImpl.java | 26 ++++++++----- .../orchestration/VolumeOrchestrator.java | 39 +++++++++++++++---- .../java/com/cloud/vm/UserVmManagerImpl.java | 4 +- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/context/CallContext.java b/api/src/main/java/org/apache/cloudstack/context/CallContext.java index d63ccefd4d3..50049b30a07 100644 --- a/api/src/main/java/org/apache/cloudstack/context/CallContext.java +++ b/api/src/main/java/org/apache/cloudstack/context/CallContext.java @@ -223,6 +223,20 @@ public class CallContext { return register(user, account); } + /** + * Register child CallContext. + * @param parent - parent CallContext + * @param eventResourceType - command resource type + * @return Call context + * @throws CloudAuthenticationException + */ + public static CallContext register(CallContext parent, ApiCommandResourceType eventResourceType) throws CloudAuthenticationException { + CallContext callContext = register(parent.getCallingUserId(), parent.getCallingAccountId()); + callContext.setStartEventId(parent.getStartEventId()); + callContext.setEventResourceType(eventResourceType); + return callContext; + } + public static CallContext register(long callingUserId, long callingAccountId) throws CloudAuthenticationException { Account account = s_entityMgr.findById(Account.class, callingAccountId); if (account == null) { diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 6c15ad05b53..1e87657efce 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -48,6 +48,7 @@ import javax.persistence.EntityExistsException; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin; @@ -485,15 +486,22 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Allocating disks for " + vmFinal); } - String rootVolumeName = String.format("ROOT-%s", vmFinal.getId()); - if (template.getFormat() == ImageFormat.ISO) { - volumeMgr.allocateRawVolume(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(), - rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), vmFinal, template, owner, null); - } else if (template.getFormat() == ImageFormat.BAREMETAL) { - s_logger.debug(String.format("%s has format [%s]. Skipping ROOT volume [%s] allocation.", template.toString(), ImageFormat.BAREMETAL, rootVolumeName)); - } else { - volumeMgr.allocateTemplatedVolumes(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskSizeFinal, - rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vmFinal, owner); + // 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 { + String rootVolumeName = String.format("ROOT-%s", vmFinal.getId()); + if (template.getFormat() == ImageFormat.ISO) { + volumeMgr.allocateRawVolume(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(), + rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), vmFinal, template, owner, null); + } else if (template.getFormat() == ImageFormat.BAREMETAL) { + s_logger.debug(String.format("%s has format [%s]. Skipping ROOT volume [%s] allocation.", template.toString(), ImageFormat.BAREMETAL, rootVolumeName)); + } else { + volumeMgr.allocateTemplatedVolumes(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskSizeFinal, + rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), template, vmFinal, owner); + } + } finally { + // Remove volumeContext and pop vmContext back + CallContext.unregister(); } if (dataDiskOfferings != null) { diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index e42720266f9..73047c4851a 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -37,6 +37,16 @@ import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.event.ActionEvent; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UUIDManager; +import org.apache.cloudstack.api.ApiCommandResourceType; +import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.secret.dao.PassphraseDao; import org.apache.cloudstack.secret.PassphraseVO; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; @@ -138,12 +148,6 @@ import com.cloud.uservm.UserVm; import com.cloud.utils.Pair; import com.cloud.utils.StringUtils; import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallback; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; @@ -177,6 +181,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati @Inject EntityManager _entityMgr; + + @Inject + private UUIDManager _uuidMgr; + @Inject protected TemplateManager _tmpltMgr; @Inject @@ -788,6 +796,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati vol.getTemplateId()); } + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating ROOT 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) { @@ -847,7 +856,15 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume, vol.isDisplayVolume()); _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, vol.isDisplayVolume(), new Long(vol.getSize())); } - return toDiskProfile(vol, offering); + DiskProfile diskProfile = toDiskProfile(vol, offering); + // Set context information for VOLUME.CREATE event for ROOT disk. + CallContext volumeContext = CallContext.current(); + if (type == Type.ROOT && volumeContext != null && volumeContext.getEventResourceType() == ApiCommandResourceType.Volume) { + volumeContext.setEventDetails("Volume Id: " + this._uuidMgr.getUuid(Volume.class, diskProfile.getVolumeId()) + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, vm.getId())); + volumeContext.setEventResourceId(diskProfile.getVolumeId()); + } + + return diskProfile; } private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm, @@ -928,6 +945,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati return toDiskProfile(vol, offering); } + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating ROOT volume", create = true) @Override public List allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm, Account owner) { @@ -978,6 +996,13 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati template, vm, owner, deviceId, configurationId); profiles.add(diskProfile); } + // Set context information for VOLUME.CREATE event for ROOT disk. + CallContext volumeContext = CallContext.current(); + if (type == Type.ROOT && volumeContext != null && volumeContext.getEventResourceType() == ApiCommandResourceType.Volume) { + String volumeIds = profiles.stream().map(diskProfile -> this._uuidMgr.getUuid(Volume.class, diskProfile.getVolumeId())).collect(Collectors.joining(", ")); + volumeContext.setEventDetails("Volume Id: " + volumeIds + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, vm.getId())); + volumeContext.setEventResourceId(profiles.stream().findFirst().map(DiskProfile::getVolumeId).orElse(null)); + } handleRootDiskControllerTpeForDeployAsIs(templateAsIsDisks, vm); return profiles; diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 3bc93b39917..f4bd018a21e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -7985,14 +7985,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private void detachVolumesFromVm(List volumes) { for (VolumeVO volume : volumes) { - CallContext vmContext = CallContext.current(); // 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(vmContext.getCallingUserId(), vmContext.getCallingAccountId()); + 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.setEventResourceType(ApiCommandResourceType.Volume); volumeContext.setEventResourceId(volume.getId()); - volumeContext.setStartEventId(vmContext.getStartEventId()); Volume detachResult = null; try {