When VM is created and ROOT volume is created it should emit a VOLUME.CREATE event (#6939)

* When VM is created and ROOT volume is created it should emit a VOLUME.CREATE event

Co-authored-by: Maxim Prokopchuk <mprokopchuk@apple.com>
This commit is contained in:
mprokopchuk 2022-12-08 08:14:17 -08:00 committed by GitHub
parent 74623aa3d3
commit ffe2fa51d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 14 deletions

View File

@ -223,6 +223,20 @@ public class CallContext {
return register(user, account); 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 { public static CallContext register(long callingUserId, long callingAccountId) throws CloudAuthenticationException {
Account account = s_entityMgr.findById(Account.class, callingAccountId); Account account = s_entityMgr.findById(Account.class, callingAccountId);
if (account == null) { if (account == null) {

View File

@ -49,6 +49,7 @@ import com.cloud.storage.VolumeApiServiceImpl;
import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao;
import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin; import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin;
@ -485,16 +486,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
s_logger.debug("Allocating disks for " + vmFinal); s_logger.debug("Allocating disks for " + vmFinal);
} }
String rootVolumeName = String.format("ROOT-%s", vmFinal.getId()); allocateRootVolume(vmFinal, template, rootDiskOfferingInfo, owner, rootDiskSizeFinal);
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);
}
if (dataDiskOfferings != null) { if (dataDiskOfferings != null) {
for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) { for (final DiskOfferingInfo dataDiskOfferingInfo : dataDiskOfferings) {
@ -521,6 +513,26 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} }
} }
private void allocateRootVolume(VMInstanceVO vm, VirtualMachineTemplate template, DiskOfferingInfo rootDiskOfferingInfo, Account owner, Long rootDiskSizeFinal) {
// 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", vm.getId());
if (template.getFormat() == ImageFormat.ISO) {
volumeMgr.allocateRawVolume(Type.ROOT, rootVolumeName, rootDiskOfferingInfo.getDiskOffering(), rootDiskOfferingInfo.getSize(),
rootDiskOfferingInfo.getMinIops(), rootDiskOfferingInfo.getMaxIops(), vm, 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, vm, owner);
}
} finally {
// Remove volumeContext and pop vmContext back
CallContext.unregister();
}
}
@Override @Override
public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering, public void allocate(final String vmInstanceName, final VirtualMachineTemplate template, final ServiceOffering serviceOffering,
final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException { final LinkedHashMap<? extends Network, List<? extends NicProfile>> networks, final DeploymentPlan plan, final HypervisorType hyperType) throws InsufficientCapacityException {

View File

@ -37,7 +37,11 @@ import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.event.ActionEvent;
import com.cloud.storage.StorageUtil; import com.cloud.storage.StorageUtil;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.secret.dao.PassphraseDao; import org.apache.cloudstack.secret.dao.PassphraseDao;
import org.apache.cloudstack.secret.PassphraseVO; import org.apache.cloudstack.secret.PassphraseVO;
import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
@ -135,6 +139,7 @@ import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB; import com.cloud.utils.db.DB;
import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.UUIDManager;
import com.cloud.utils.db.Transaction; import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback; import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.TransactionCallbackNoReturn;
@ -176,6 +181,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
@Inject @Inject
EntityManager _entityMgr; EntityManager _entityMgr;
@Inject @Inject
private UUIDManager _uuidMgr;
@Inject
protected TemplateManager _tmpltMgr; protected TemplateManager _tmpltMgr;
@Inject @Inject
protected VolumeDao _volsDao; protected VolumeDao _volsDao;
@ -812,6 +819,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
vol.getTemplateId()); vol.getTemplateId());
} }
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating ROOT volume", create = true)
@Override @Override
public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, Account owner, public DiskProfile allocateRawVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, Account owner,
Long deviceId) { Long deviceId) {
@ -871,7 +879,11 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
_resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume, vol.isDisplayVolume()); _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume, vol.isDisplayVolume());
_resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, vol.isDisplayVolume(), new Long(vol.getSize())); _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.primary_storage, vol.isDisplayVolume(), new Long(vol.getSize()));
} }
return toDiskProfile(vol, offering); DiskProfile diskProfile = toDiskProfile(vol, offering);
updateRootDiskVolumeEventDetails(type, vm, List.of(diskProfile));
return diskProfile;
} }
private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm, private DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
@ -953,6 +965,7 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
return toDiskProfile(vol, offering); return toDiskProfile(vol, offering);
} }
@ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating ROOT volume", create = true)
@Override @Override
public List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm, public List<DiskProfile> allocateTemplatedVolumes(Type type, String name, DiskOffering offering, Long rootDisksize, Long minIops, Long maxIops, VirtualMachineTemplate template, VirtualMachine vm,
Account owner) { Account owner) {
@ -1006,10 +1019,32 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
profiles.add(diskProfile); profiles.add(diskProfile);
} }
updateRootDiskVolumeEventDetails(type, vm, profiles);
handleRootDiskControllerTpeForDeployAsIs(templateAsIsDisks, vm); handleRootDiskControllerTpeForDeployAsIs(templateAsIsDisks, vm);
return profiles; return profiles;
} }
/**
* Set context information for VOLUME.CREATE event for ROOT disk.
*
* @param type - Volume Type
* @param vm - Virtual Machine
* @param diskProfiles - Disk Profiles
*/
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) {
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()));
}
}
private void handleRootDiskControllerTpeForDeployAsIs(List<DatadiskTO> disksAsIs, VirtualMachine vm) { private void handleRootDiskControllerTpeForDeployAsIs(List<DatadiskTO> disksAsIs, VirtualMachine vm) {
if (CollectionUtils.isNotEmpty(disksAsIs)) { if (CollectionUtils.isNotEmpty(disksAsIs)) {
String diskControllerSubType = disksAsIs.get(0).getDiskControllerSubType(); String diskControllerSubType = disksAsIs.get(0).getDiskControllerSubType();

View File

@ -8099,14 +8099,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private void detachVolumesFromVm(List<VolumeVO> volumes) { private void detachVolumesFromVm(List<VolumeVO> volumes) {
for (VolumeVO volume : volumes) { for (VolumeVO volume : volumes) {
CallContext vmContext = CallContext.current();
// Create new context and inject correct event resource type, id and details, // 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. // 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.setEventDetails("Volume Id: " + this._uuidMgr.getUuid(Volume.class, volume.getId()) + " Vm Id: " + this._uuidMgr.getUuid(VirtualMachine.class, volume.getInstanceId()));
volumeContext.setEventResourceType(ApiCommandResourceType.Volume); volumeContext.setEventResourceType(ApiCommandResourceType.Volume);
volumeContext.setEventResourceId(volume.getId()); volumeContext.setEventResourceId(volume.getId());
volumeContext.setStartEventId(vmContext.getStartEventId());
Volume detachResult = null; Volume detachResult = null;
try { try {