package org.ovirt.engine.core.bll;
import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_ACTIVE;
import static org.ovirt.engine.core.bll.storage.disk.image.DisksFilter.ONLY_NOT_SHAREABLE;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.job.ExecutionHandler;
import org.ovirt.engine.core.bll.profiles.CpuProfileHelper;
import org.ovirt.engine.core.bll.profiles.DiskProfileHelper;
import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaSanityParameter;
import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaStorageDependent;
import org.ovirt.engine.core.bll.quota.QuotaVdsDependent;
import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator;
import org.ovirt.engine.core.bll.storage.disk.DiskHandler;
import org.ovirt.engine.core.bll.storage.disk.image.DisksFilter;
import org.ovirt.engine.core.bll.storage.disk.image.ImagesHandler;
import org.ovirt.engine.core.bll.tasks.CommandCoordinatorUtil;
import org.ovirt.engine.core.bll.tasks.interfaces.CommandCallback;
import org.ovirt.engine.core.bll.utils.IconUtils;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.bll.validator.IconValidator;
import org.ovirt.engine.core.bll.validator.VmValidator;
import org.ovirt.engine.core.bll.validator.VmWatchdogValidator;
import org.ovirt.engine.core.bll.validator.storage.CinderDisksValidator;
import org.ovirt.engine.core.bll.validator.storage.DiskImagesValidator;
import org.ovirt.engine.core.bll.validator.storage.MultipleDiskVmElementValidator;
import org.ovirt.engine.core.bll.validator.storage.MultipleStorageDomainsValidator;
import org.ovirt.engine.core.bll.validator.storage.StoragePoolValidator;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.AddVmTemplateParameters;
import org.ovirt.engine.core.common.action.AddVmTemplateParameters.Phase;
import org.ovirt.engine.core.common.action.CreateAllTemplateDisksParameters;
import org.ovirt.engine.core.common.action.GraphicsParameters;
import org.ovirt.engine.core.common.action.LockProperties;
import org.ovirt.engine.core.common.action.LockProperties.Scope;
import org.ovirt.engine.core.common.action.SealVmTemplateParameters;
import org.ovirt.engine.core.common.action.UpdateAllTemplateDisksParameters;
import org.ovirt.engine.core.common.action.UpdateVmVersionParameters;
import org.ovirt.engine.core.common.action.VdcActionParametersBase.EndProcedure;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.asynctasks.EntityInfo;
import org.ovirt.engine.core.common.businessentities.ActionGroup;
import org.ovirt.engine.core.common.businessentities.ArchitectureType;
import org.ovirt.engine.core.common.businessentities.GraphicsDevice;
import org.ovirt.engine.core.common.businessentities.GraphicsType;
import org.ovirt.engine.core.common.businessentities.Permission;
import org.ovirt.engine.core.common.businessentities.StorageDomain;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VMStatus;
import org.ovirt.engine.core.common.businessentities.VmDeviceId;
import org.ovirt.engine.core.common.businessentities.VmDynamic;
import org.ovirt.engine.core.common.businessentities.VmEntityType;
import org.ovirt.engine.core.common.businessentities.VmStatic;
import org.ovirt.engine.core.common.businessentities.VmTemplate;
import org.ovirt.engine.core.common.businessentities.VmTemplateStatus;
import org.ovirt.engine.core.common.businessentities.network.VmInterfaceType;
import org.ovirt.engine.core.common.businessentities.network.VmNic;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.CopyVolumeType;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskVmElement;
import org.ovirt.engine.core.common.errors.EngineError;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.locks.LockingGroup;
import org.ovirt.engine.core.common.queries.VmIconIdSizePair;
import org.ovirt.engine.core.common.utils.CompatibilityVersionUtils;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.utils.customprop.VmPropertiesUtils;
import org.ovirt.engine.core.common.validation.group.CreateEntity;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.compat.backendcompat.CommandExecutionStatus;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
import org.ovirt.engine.core.dao.DiskVmElementDao;
import org.ovirt.engine.core.dao.PermissionDao;
import org.ovirt.engine.core.dao.StorageDomainDao;
import org.ovirt.engine.core.dao.StorageDomainStaticDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.dao.VmDynamicDao;
import org.ovirt.engine.core.dao.VmStaticDao;
import org.ovirt.engine.core.dao.VmTemplateDao;
import org.ovirt.engine.core.dao.network.VmNicDao;
import org.ovirt.engine.core.utils.collections.MultiValueMapUtils;
import org.ovirt.engine.core.utils.timer.OnTimerMethodAnnotation;
import org.ovirt.engine.core.utils.timer.SchedulerUtil;
import org.ovirt.engine.core.utils.timer.SchedulerUtilQuartzImpl;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@DisableInPrepareMode
@NonTransactiveCommandAttribute(forceCompensation = true)
public class AddVmTemplateCommand<T extends AddVmTemplateParameters> extends VmTemplateManagementCommand<T>
implements QuotaStorageDependent, QuotaVdsDependent, SerialChildExecutingCommand {
@Inject
private AuditLogDirector auditLogDirector;
@Inject
private SchedulerUtilQuartzImpl schedulerUtil;
@Inject
private CpuProfileHelper cpuProfileHelper;
@Inject
private DiskHandler diskHandler;
@Inject
private DiskProfileHelper diskProfileHelper;
@Inject
protected SnapshotsValidator snapshotsValidator;
@Inject
private VmDao vmDao;
@Inject
private PermissionDao permissionDao;
@Inject
private VmDynamicDao vmDynamicDao;
@Inject
private VmTemplateDao vmTemplateDao;
@Inject
private StorageDomainDao storageDomainDao;
@Inject
private StorageDomainStaticDao storageDomainStaticDao;
@Inject
private VmNicDao vmNicDao;
@Inject
private DiskVmElementDao diskVmElementDao;
@Inject
private VmStaticDao vmStaticDao;
protected final List<DiskImage> images = new ArrayList<>();
private Guid[] targetDiskIds;
private List<PermissionSubject> permissionCheckSubject;
protected Map<Guid, DiskImage> diskInfoDestinationMap;
private Map<Guid, List<DiskImage>> sourceImageDomainsImageMap;
private boolean isVmInDb;
private boolean pendingAsyncTasks;
private static final String BASE_TEMPLATE_VERSION_NAME = "base version";
private static Map<Guid, String> updateVmsJobIdMap = new ConcurrentHashMap<>();
private VmTemplate cachedBaseTemplate;
private List<CinderDisk> cinderDisks;
/**
* Constructor for command creation when compensation is applied on startup
*/
protected AddVmTemplateCommand(Guid commandId) {
super(commandId);
}
public AddVmTemplateCommand(T parameters, CommandContext cmdContext) {
super(parameters, cmdContext);
}
@Override
protected void init() {
if (Guid.isNullOrEmpty(getParameters().getVmTemplateId())) {
getParameters().setVmTemplateId(Guid.newGuid());
}
setVmTemplateId(getParameters().getVmTemplateId());
getParameters().setEntityInfo(new EntityInfo(VdcObjectType.VmTemplate, getVmTemplateId()));
setVmTemplateName(getParameters().getName());
VmStatic masterVm = getParameters().getMasterVm();
if (masterVm != null) {
setVmId(masterVm.getId());
setClusterId(masterVm.getClusterId());
// API backward compatibility
if (getVmDeviceUtils().shouldOverrideSoundDevice(
masterVm,
getMasterVmCompatibilityVersion(),
getParameters().isSoundDeviceEnabled())) {
getParameters().setSoundDeviceEnabled(true);
}
if (getParameters().isSoundDeviceEnabled() == null) {
getParameters().setSoundDeviceEnabled(false);
}
if (getParameters().isConsoleEnabled() == null) {
getParameters().setConsoleEnabled(false);
}
vmHandler.updateDefaultTimeZone(masterVm);
vmHandler.autoSelectUsbPolicy(masterVm);
vmHandler.autoSelectDefaultDisplayType(getVmId(),
masterVm,
getCluster(),
getParameters().getGraphicsDevices());
vmHandler.autoSelectGraphicsDevice(getVmId(),
masterVm,
getCluster(),
getParameters().getGraphicsDevices(),
getMasterVmCompatibilityVersion());
separateCustomProperties(masterVm);
}
if (getVm() != null) {
updateVmDevices();
images.addAll(getVmDisksFromDB());
setStoragePoolId(getVm().getStoragePoolId());
isVmInDb = true;
} else if (getCluster() != null && masterVm != null) {
VM vm = new VM(masterVm, new VmDynamic(), null);
vm.setClusterCompatibilityVersion(getCluster().getCompatibilityVersion());
setVm(vm);
setStoragePoolId(getCluster().getStoragePoolId());
}
updateDiskInfoDestinationMap();
generateTargetDiskIds();
getParameters().setUseCinderCommandCallback(!getCinderDisks().isEmpty());
}
protected void separateCustomProperties(VmStatic parameterMasterVm) {
if (getCluster() != null) {
// Parses the custom properties field that was filled by frontend to
// predefined and user defined fields
VmPropertiesUtils.getInstance().separateCustomPropertiesToUserAndPredefined(
getMasterVmCompatibilityVersion(), parameterMasterVm);
}
}
private void updateDiskInfoDestinationMap() {
diskInfoDestinationMap = getParameters().getDiskInfoDestinationMap();
if (diskInfoDestinationMap == null) {
diskInfoDestinationMap = new HashMap<>();
}
sourceImageDomainsImageMap = new HashMap<>();
for (DiskImage image : images) {
MultiValueMapUtils.addToMap(image.getStorageIds().get(0), image, sourceImageDomainsImageMap);
if (!diskInfoDestinationMap.containsKey(image.getId())) {
// The volume's format and type were not specified and thus should be null.
image.setVolumeFormat(null);
image.setVolumeType(null);
diskInfoDestinationMap.put(image.getId(), image);
}
}
}
private void generateTargetDiskIds() {
targetDiskIds = Stream.generate(Guid::newGuid).limit(images.size()).toArray(Guid[]::new);
}
private void updateVmDevices() {
getVmDeviceUtils().setVmDevices(getVm().getStaticData());
}
protected List<DiskImage> getVmDisksFromDB() {
vmHandler.updateDisksFromDb(getVm());
vmHandler.filterImageDisksForVM(getVm());
return getVm().getDiskList();
}
private List<CinderDisk> getCinderDisks() {
if (cinderDisks == null) {
cinderDisks = DisksFilter.filterCinderDisks(images);
}
return cinderDisks;
}
@Override
protected void executeCommand() {
// get vm status from db to check its really down before locking
// relevant only if template created from vm
if (isVmInDb) {
VmDynamic vmDynamic = vmDynamicDao.get(getVmId());
if (!isVmStatusValid(vmDynamic.getStatus())) {
throw new EngineException(EngineError.IRS_IMAGE_STATUS_ILLEGAL);
}
vmHandler.lockVm(vmDynamic, getCompensationContext());
}
setActionReturnValue(Guid.Empty);
// set template id as base for new templates
if (!isTemplateVersion()) {
getParameters().setBaseTemplateId(getVmTemplateId());
if (StringUtils.isEmpty(getParameters().getTemplateVersionName())) {
getParameters().setTemplateVersionName(BASE_TEMPLATE_VERSION_NAME);
}
} else {
// template version name should be the same as the base template name
setVmTemplateName(getBaseTemplate().getName());
String jobId = updateVmsJobIdMap.remove(getParameters().getBaseTemplateId());
if (!StringUtils.isEmpty(jobId)) {
log.info("Cancelling current running update for vms for base template id '{}'", getParameters().getBaseTemplateId());
try {
getSchedulerUtil().deleteJob(jobId);
} catch (Exception e) {
log.warn("Failed deleting job '{}' at cancelRecoveryJob", jobId);
}
}
}
TransactionSupport.executeInNewTransaction(() -> {
addVmTemplateToDb();
getCompensationContext().stateChanged();
return null;
});
final Map<Guid, Guid> srcDeviceIdToTargetDeviceIdMapping = addAllTemplateDisks();
srcDeviceIdToTargetDeviceIdMapping
.forEach((oldImageId, newImageId) -> addTemplateDiskVmElement(newImageId, oldImageId));
TransactionSupport.executeInNewTransaction(() -> {
addPermission();
addVmInterfaces(srcDeviceIdToTargetDeviceIdMapping);
Set<GraphicsType> graphicsToSkip = getParameters().getGraphicsDevices().keySet();
if (isVmInDb) {
getVmDeviceUtils().copyVmDevices(getVmId(),
getVmTemplateId(),
srcDeviceIdToTargetDeviceIdMapping,
getParameters().isSoundDeviceEnabled(),
getParameters().isConsoleEnabled(),
getParameters().isVirtioScsiEnabled(),
getVmDeviceUtils().hasMemoryBalloon(getVmId()),
graphicsToSkip,
false,
getEffectiveCompatibilityVersion());
} else {
// for instance type and new template without a VM
getVmDeviceUtils().copyVmDevices(VmTemplateHandler.BLANK_VM_TEMPLATE_ID,
getVmTemplateId(),
srcDeviceIdToTargetDeviceIdMapping,
getParameters().isSoundDeviceEnabled(),
getParameters().isConsoleEnabled(),
getParameters().isVirtioScsiEnabled(),
Boolean.TRUE.equals(getParameters().isBalloonEnabled()),
graphicsToSkip,
false,
getEffectiveCompatibilityVersion());
}
updateWatchdog(getVmTemplateId());
updateRngDevice(getVmTemplateId());
addGraphicsDevice();
setSucceeded(true);
return null;
});
if (getParameters().getTemplateType() != VmEntityType.INSTANCE_TYPE) {
vmHandler.warnMemorySizeLegal(getVmTemplate(), getVm().getCompatibilityVersion());
}
// means that there are no asynchronous tasks to execute and that we can
// end the command synchronously
pendingAsyncTasks = !getReturnValue().getVdsmTaskIdList().isEmpty() ||
!CommandCoordinatorUtil.getChildCommandIds(getCommandId()).isEmpty();
if (!pendingAsyncTasks) {
endSuccessfullySynchronous();
}
}
/**
* Execute {@link org.ovirt.engine.core.bll.storage.disk.CreateAllTemplateDisksCommand} to create all disks
* of the template.
*
* @return a map where keys are IDs of the disks that were copied and values are IDs of the corresponding disks
* of the template that were created
*/
protected Map<Guid, Guid> addAllTemplateDisks() {
VdcReturnValueBase returnValue = runInternalAction(
getAddAllTemplateDisksActionType(),
buildCreateAllTemplateDisksParameters(),
ExecutionHandler.createDefaultContextForTasks(getContext()));
if (!returnValue.getSucceeded()) {
throw new EngineException(returnValue.getFault().getError(), returnValue.getFault().getMessage());
}
return returnValue.getActionReturnValue();
}
private CreateAllTemplateDisksParameters buildCreateAllTemplateDisksParameters() {
CreateAllTemplateDisksParameters parameters =
new CreateAllTemplateDisksParameters(getVm() != null ? getVmId() : Guid.Empty);
parameters.setVmTemplateId(getVmTemplateId());
parameters.setVmTemplateName(getVmTemplateName());
parameters.setDiskInfoDestinationMap(diskInfoDestinationMap);
parameters.setTargetDiskIds(targetDiskIds);
if (getParameters().isSealTemplate()) {
parameters.setCopyVolumeType(CopyVolumeType.LeafVol);
}
parameters.setParentCommand(getActionType());
parameters.setParentParameters(getParameters());
parameters.setEndProcedure(EndProcedure.COMMAND_MANAGED);
return parameters;
}
protected VdcActionType getAddAllTemplateDisksActionType() {
return VdcActionType.CreateAllTemplateDisks;
}
private Version getMasterVmCompatibilityVersion() {
return getVm() == null
? CompatibilityVersionUtils.getEffective(getParameters().getMasterVm(), getCluster())
: getVm().getCompatibilityVersion();
}
private Version getEffectiveCompatibilityVersion() {
return CompatibilityVersionUtils.getEffective(getParameters().getMasterVm(), this::getCluster);
}
/**
* Add graphics based on parameters.
*/
private void addGraphicsDevice() {
for (GraphicsDevice graphicsDevice : getParameters().getGraphicsDevices().values()) {
if (graphicsDevice == null) {
continue;
}
graphicsDevice.setVmId(getVmTemplateId());
GraphicsParameters parameters = new GraphicsParameters(graphicsDevice).setVm(false);
getBackend().runInternalAction(VdcActionType.AddGraphicsDevice, parameters);
}
}
@Override
public boolean performNextOperation(int completedChildCount) {
if (!getParameters().isSealTemplate()) {
return false;
}
restoreCommandState();
switch (getParameters().getPhase()) {
case CREATE_TEMPLATE:
getParameters().setPhase(Phase.ASSIGN_ILLEGAL);
break;
case ASSIGN_ILLEGAL:
getParameters().setPhase(Phase.SEAL);
break;
case SEAL:
getParameters().setPhase(Phase.ASSIGN_LEGAL_SHARED);
break;
case ASSIGN_LEGAL_SHARED:
return false;
}
persistCommandIfNeeded();
executeNextOperation();
return true;
}
private void executeNextOperation() {
switch (getParameters().getPhase()) {
case ASSIGN_ILLEGAL:
assignLegalAndShared(false);
break;
case SEAL:
sealVmTemplate();
break;
case ASSIGN_LEGAL_SHARED:
assignLegalAndShared(true);
break;
}
}
private void assignLegalAndShared(boolean legalAndShared) {
VdcReturnValueBase returnValue = runInternalAction(VdcActionType.UpdateAllTemplateDisks,
buildUpdateAllTemplateDisksParameters(legalAndShared),
ExecutionHandler.createDefaultContextForTasks(getContext()));
if (!returnValue.getSucceeded()) {
throw new EngineException(returnValue.getFault().getError(), returnValue.getFault().getMessage());
}
}
private UpdateAllTemplateDisksParameters buildUpdateAllTemplateDisksParameters(boolean legalAndShared) {
UpdateAllTemplateDisksParameters parameters = new UpdateAllTemplateDisksParameters(getVmTemplateId(),
legalAndShared,
legalAndShared ? true : null);
parameters.setParentCommand(getActionType());
parameters.setParentParameters(getParameters());
parameters.setEndProcedure(EndProcedure.COMMAND_MANAGED);
return parameters;
}
private void sealVmTemplate() {
VdcReturnValueBase returnValue = runInternalAction(VdcActionType.SealVmTemplate,
buildSealVmTemplateParameters(),
ExecutionHandler.createDefaultContextForTasks(getContext()));
if (!returnValue.getSucceeded()) {
throw new EngineException(returnValue.getFault().getError(), returnValue.getFault().getMessage());
}
}
private SealVmTemplateParameters buildSealVmTemplateParameters() {
SealVmTemplateParameters parameters = new SealVmTemplateParameters();
parameters.setVmTemplateId(getVmTemplateId());
parameters.setParentCommand(getActionType());
parameters.setParentParameters(getParameters());
parameters.setEndProcedure(EndProcedure.COMMAND_MANAGED);
return parameters;
}
@Override
protected boolean validate() {
boolean isInstanceType = getParameters().getTemplateType() == VmEntityType.INSTANCE_TYPE;
if (getCluster() == null && !isInstanceType) {
return failValidation(EngineMessage.VDS_CLUSTER_IS_NOT_VALID);
}
if (!VmHandler.isVmPriorityValueLegal(getParameters().getMasterVm().getPriority(),
getReturnValue().getValidationMessages())) {
return false;
}
if (isVmInDb && !isVmStatusValid(getVm().getStatus())) {
return failValidation(EngineMessage.VMT_CANNOT_CREATE_TEMPLATE_FROM_DOWN_VM);
}
// validate uniqueness of template name. If template is a regular template, uniqueness
// is considered in context of the datacenter. If template is an 'Instance' name must
// be unique also across datacenters.
if (!isTemplateVersion()) {
if (isInstanceType) {
if (isInstanceWithSameNameExists(getVmTemplateName())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
}
} else {
if (isVmTemplateWithSameNameExist(getVmTemplateName(), getCluster().getStoragePoolId())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_NAME_ALREADY_USED);
}
}
}
if (isTemplateVersion()) {
VmTemplate userSelectedBaseTemplate = getBaseTemplate();
if (userSelectedBaseTemplate == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_DOES_NOT_EXIST);
} else if (!userSelectedBaseTemplate.isBaseTemplate()) {
// currently template version cannot be base template
return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_VERSION_CANNOT_BE_BASE_TEMPLATE);
}
}
if (isTemplateVersion() && getBaseTemplate().isBlank()) {
return failValidation(EngineMessage.BLANK_TEMPLATE_CANT_HAVE_SUBTEMPLATES);
}
if (!setAndValidateDiskProfiles()) {
return false;
}
if (!setAndValidateCpuProfile()) {
return false;
}
if (!isDisksAliasNotEmpty()) {
return false;
}
if (getParameters().getVmLargeIcon() != null && !validate(IconValidator.validate(
IconValidator.DimensionsType.LARGE_CUSTOM_ICON,
getParameters().getVmLargeIcon()))) {
return false;
}
if (getParameters().getMasterVm().getSmallIconId() != null
&& getParameters().getVmLargeIcon() == null // icon id is ignored if large icon is sent
&& !validate(IconValidator.validateIconId(getParameters().getMasterVm().getSmallIconId(), "Small"))) {
return false;
}
if (getParameters().getMasterVm().getLargeIconId() != null
&& getParameters().getVmLargeIcon() == null // icon id is ignored if large icon is sent
&& !validate(IconValidator.validateIconId(getParameters().getMasterVm().getLargeIconId(), "Large"))) {
return false;
}
if (getParameters().getWatchdog() != null) {
if (!validate(new VmWatchdogValidator.VmWatchdogClusterIndependentValidator(
getParameters().getWatchdog()).isValid())) {
return false;
}
}
if (!validate(VmHandler.validateMaxMemorySize(
getParameters().getMasterVm(),
CompatibilityVersionUtils.getEffective(getParameters().getMasterVm(), this::getCluster)))) {
return false;
}
if (getParameters().isSealTemplate() && vmHandler.isWindowsVm(getVm())) {
return failValidation(EngineMessage.VM_TEMPLATE_CANNOT_SEAL_WINDOWS);
}
if (isInstanceType) {
return true;
}
return validateCluster()
&& validateImages()
&& validate(VmValidator.validateCpuSockets(
getParameters().getMasterVm(),
getVm().getCompatibilityVersion()));
}
protected boolean isVmStatusValid(VMStatus status) {
return status == VMStatus.Down;
}
protected boolean setAndValidateCpuProfile() {
// cpu profile isn't supported for instance types.
if (getParameters().getTemplateType() == VmEntityType.INSTANCE_TYPE) {
return true;
}
return validate(cpuProfileHelper.setAndValidateCpuProfile(
getParameters().getMasterVm(),
getUserIdIfExternal().orElse(null)));
}
protected boolean isDisksAliasNotEmpty() {
// Check that all the template's allocated disk's aliases are not an empty string.
for (DiskImage diskImage : diskInfoDestinationMap.values()) {
if (StringUtils.isEmpty(diskImage.getDiskAlias())) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_CANNOT_BE_CREATED_WITH_EMPTY_DISK_ALIAS);
}
}
return true;
}
protected boolean setAndValidateDiskProfiles() {
if (diskInfoDestinationMap != null && !diskInfoDestinationMap.isEmpty()) {
Map<DiskImage, Guid> map = diskInfoDestinationMap.values().stream()
.filter(DisksFilter.ONLY_IMAGES)
.collect(Collectors.toMap(Function.identity(), d -> d.getStorageIds().get(0)));
return validate(diskProfileHelper.setAndValidateDiskProfiles(map, getCurrentUser()));
}
return true;
}
private VmTemplate getBaseTemplate() {
if (cachedBaseTemplate == null) {
cachedBaseTemplate = vmTemplateDao.get(getParameters().getBaseTemplateId());
}
return cachedBaseTemplate;
}
private boolean isTemplateVersion() {
return getParameters().getBaseTemplateId() != null;
}
private boolean validateCluster() {
// A Template cannot be added in a cluster without a defined architecture
if (getCluster().getArchitecture() == ArchitectureType.undefined) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_CLUSTER_UNDEFINED_ARCHITECTURE);
}
if (!vmHandler.isOsTypeSupported(getParameters().getMasterVm().getOsId(),
getCluster().getArchitecture(), getReturnValue().getValidationMessages())) {
return false;
}
// Check if the display type is supported
Guid srcId = isVmInDb ? getVmId() : VmTemplateHandler.BLANK_VM_TEMPLATE_ID;
if (!vmHandler.isGraphicsAndDisplaySupported(getParameters().getMasterVm().getOsId(),
vmHandler.getResultingVmGraphics(getVmDeviceUtils().getGraphicsTypesOfEntity(srcId),
getParameters().getGraphicsDevices()),
getParameters().getMasterVm().getDefaultDisplayType(),
getReturnValue().getValidationMessages(),
getVm().getCompatibilityVersion())) {
return false;
}
if (getParameters().getVm().getSingleQxlPci() &&
!vmHandler.isSingleQxlDeviceLegal(getParameters().getVm().getDefaultDisplayType(),
getParameters().getVm().getOs(),
getReturnValue().getValidationMessages())) {
return false;
}
// Check if the watchdog model is supported
if (getParameters().getWatchdog() != null) {
if (!validate(new VmWatchdogValidator.VmWatchdogClusterDependentValidator(getParameters().getMasterVm().getOsId(),
getParameters().getWatchdog(),
getVm().getCompatibilityVersion()).isValid())) {
return false;
}
}
// Disallow cross-DC template creation
if (!getStoragePoolId().equals(getCluster().getStoragePoolId())) {
addValidationMessage(EngineMessage.VDS_CLUSTER_ON_DIFFERENT_STORAGE_POOL);
return false;
}
if (!VmPropertiesUtils.getInstance().validateVmProperties(
getVm().getCompatibilityVersion(),
getParameters().getMasterVm().getCustomProperties(),
getReturnValue().getValidationMessages())) {
return false;
}
return true;
}
protected boolean validateImages() {
// images related checks
if (!images.isEmpty()) {
if (!validateVmNotDuringSnapshot()) {
return false;
}
if (!validate(new StoragePoolValidator(getStoragePool()).isUp())) {
return false;
}
List<CinderDisk> cinderDisks = getCinderDisks();
CinderDisksValidator cinderDisksValidator = new CinderDisksValidator(cinderDisks);
if (!validate(cinderDisksValidator.validateCinderDiskLimits())) {
return false;
}
if (!validate(isPassDiscardSupportedForImagesDestSds())) {
return false;
}
List<DiskImage> diskImagesToCheck = DisksFilter.filterImageDisks(images, ONLY_NOT_SHAREABLE, ONLY_ACTIVE);
diskImagesToCheck.addAll(cinderDisks);
DiskImagesValidator diskImagesValidator = new DiskImagesValidator(diskImagesToCheck);
if (!validate(diskImagesValidator.diskImagesNotIllegal()) ||
!validate(diskImagesValidator.diskImagesNotLocked())) {
return false;
}
MultipleStorageDomainsValidator storageDomainsValidator =
getStorageDomainsValidator(getStoragePoolId(), sourceImageDomainsImageMap.keySet());
if (!validate(storageDomainsValidator.allDomainsExistAndActive())) {
return false;
}
Set<Guid> destImageDomains = getStorageGuidSet();
destImageDomains.removeAll(sourceImageDomainsImageMap.keySet());
for (Guid destImageDomain : destImageDomains) {
StorageDomain storage = storageDomainDao.getForStoragePool(destImageDomain, getVm().getStoragePoolId());
if (storage == null) {
// if storage is null then we need to check if it doesn't exist or
// domain is not in the same storage pool as the vm
if (storageDomainStaticDao.get(destImageDomain) == null) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST);
} else {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_IN_STORAGE_POOL);
}
return false;
}
if (storage.getStatus() == null || storage.getStatus() != StorageDomainStatus.Active) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_STATUS_ILLEGAL);
return false;
}
if (storage.getStorageDomainType().isIsoOrImportExportDomain()) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL);
return false;
}
}
return validateSpaceRequirements();
}
return true;
}
protected ValidationResult isPassDiscardSupportedForImagesDestSds() {
Map<Disk, DiskVmElement> diskToDiskVmElement = diskHandler.getDiskToDiskVmElementMap(
getVm().getId(), diskInfoDestinationMap);
Map<Guid, Guid> diskIdToDestSdId = diskInfoDestinationMap.values().stream()
.collect(Collectors.toMap(DiskImage::getId, diskImage -> diskImage.getStorageIds().get(0)));
MultipleDiskVmElementValidator multipleDiskVmElementValidator =
createMultipleDiskVmElementValidator(diskToDiskVmElement);
return multipleDiskVmElementValidator.isPassDiscardSupportedForDestSds(diskIdToDestSdId);
}
protected MultipleDiskVmElementValidator createMultipleDiskVmElementValidator(
Map<Disk, DiskVmElement> diskToDiskVmElement) {
return new MultipleDiskVmElementValidator(diskToDiskVmElement);
}
protected boolean validateSpaceRequirements() {
// update vm snapshots for storage free space check
ImagesHandler.fillImagesBySnapshots(getVm());
List<DiskImage> disksList = DisksFilter.filterImageDisks(getVm().getDiskMap().values(), ONLY_NOT_SHAREABLE,
ONLY_ACTIVE);
List<DiskImage> disksListForStorageChecks = createDiskDummiesForSpaceValidations(disksList);
MultipleStorageDomainsValidator multipleSdValidator = getStorageDomainsValidator(
getVm().getStoragePoolId(), getStorageGuidSet());
return validate(multipleSdValidator.allDomainsWithinThresholds())
&& validate(multipleSdValidator.allDomainsHaveSpaceForClonedDisks(disksListForStorageChecks));
}
protected MultipleStorageDomainsValidator getStorageDomainsValidator(Guid spId, Set<Guid> disks) {
return new MultipleStorageDomainsValidator(spId, disks);
}
protected boolean validateVmNotDuringSnapshot() {
return validate(snapshotsValidator.vmNotDuringSnapshot(getVmId()));
}
private Set<Guid> getStorageGuidSet() {
return diskInfoDestinationMap.values().stream().map(d -> d.getStorageIds().get(0)).collect(Collectors.toSet());
}
/**
* Space Validations are done using data extracted from the disks. The disks in question in this command
* don't have all the needed data, and in order not to contaminate the command's data structures, an alter
* one is created specifically for this validation - hence dummy.
*/
private List<DiskImage> createDiskDummiesForSpaceValidations(Collection<DiskImage> disksList) {
List<DiskImage> dummies = new ArrayList<>(disksList.size());
for (DiskImage image : disksList) {
Guid targetSdId = diskInfoDestinationMap.get(image.getId()).getStorageIds().get(0);
DiskImage dummy = ImagesHandler.createDiskImageWithExcessData(image, targetSdId);
dummies.add(dummy);
}
return dummies;
}
private void addVmTemplateToDb() {
// TODO: add timezone handling
setVmTemplate(
new VmTemplate(
0,
new Date(),
getParameters().getDescription(),
getParameters().getMasterVm().getComment(),
getParameters().getMasterVm().getMemSizeMb(),
getParameters().getMasterVm().getMaxMemorySizeMb(),
getVmTemplateName(),
getParameters().getMasterVm().getNumOfSockets(),
getParameters().getMasterVm().getCpuPerSocket(),
getParameters().getMasterVm().getThreadsPerCpu(),
getParameters().getMasterVm().getOsId(),
getParameters().getMasterVm().getClusterId(),
getVmTemplateId(),
getParameters().getMasterVm().getNumOfMonitors(),
getParameters().getMasterVm().getSingleQxlPci(),
VmTemplateStatus.Locked.getValue(),
getParameters().getMasterVm().getUsbPolicy().getValue(),
getParameters().getMasterVm().getTimeZone(),
getParameters().getMasterVm().getNiceLevel(),
getParameters().getMasterVm().getCpuShares(),
getParameters().getMasterVm().isFailBack(),
getParameters().getMasterVm().getDefaultBootSequence(),
getParameters().getMasterVm().getVmType(),
getParameters().getMasterVm().isSmartcardEnabled(),
getParameters().getMasterVm().isDeleteProtected(),
getParameters().getMasterVm().getSsoMethod(),
getParameters().getMasterVm().getTunnelMigration(),
getParameters().getMasterVm().getVncKeyboardLayout(),
getParameters().getMasterVm().getMinAllocatedMem(),
getParameters().getMasterVm().isStateless(),
getParameters().getMasterVm().isRunAndPause(),
getUserId(),
getParameters().getTemplateType(),
getParameters().getMasterVm().isAutoStartup(),
getParameters().getMasterVm().getPriority(),
getParameters().getMasterVm().getDefaultDisplayType(),
getParameters().getMasterVm().getInitrdUrl(),
getParameters().getMasterVm().getKernelUrl(),
getParameters().getMasterVm().getKernelParams(),
getParameters().getMasterVm().getQuotaId(),
getParameters().getMasterVm().getDedicatedVmForVdsList(),
getParameters().getMasterVm().getMigrationSupport(),
getParameters().getMasterVm().isAllowConsoleReconnect(),
getParameters().getMasterVm().getIsoPath(),
getParameters().getMasterVm().getMigrationDowntime(),
getParameters().getBaseTemplateId(),
getParameters().getTemplateVersionName(),
getParameters().getMasterVm().getSerialNumberPolicy(),
getParameters().getMasterVm().getCustomSerialNumber(),
getParameters().getMasterVm().isBootMenuEnabled(),
getParameters().getMasterVm().isSpiceFileTransferEnabled(),
getParameters().getMasterVm().isSpiceCopyPasteEnabled(),
getParameters().getMasterVm().getCpuProfileId(),
getParameters().getMasterVm().getNumaTuneMode(),
getParameters().getMasterVm().getAutoConverge(),
getParameters().getMasterVm().getMigrateCompressed(),
getParameters().getMasterVm().getUserDefinedProperties(),
getParameters().getMasterVm().getPredefinedProperties(),
getParameters().getMasterVm().getCustomProperties(),
getParameters().getMasterVm().getCustomEmulatedMachine(),
getParameters().getMasterVm().getCustomCpuName(),
getParameters().getMasterVm().getSmallIconId(),
getParameters().getMasterVm().getLargeIconId(),
getParameters().getMasterVm().getNumOfIoThreads(),
getParameters().getMasterVm().getConsoleDisconnectAction(),
getParameters().getMasterVm().getCustomCompatibilityVersion(),
getParameters().getMasterVm().getMigrationPolicyId(),
null));
updateVmIcons();
vmTemplateDao.save(getVmTemplate());
getCompensationContext().snapshotNewEntity(getVmTemplate());
setActionReturnValue(getVmTemplate().getId());
// Load Vm Init from DB and set it to the template
vmHandler.updateVmInitFromDB(getParameters().getMasterVm(), false);
getVmTemplate().setVmInit(getParameters().getMasterVm().getVmInit());
vmHandler.addVmInitToDB(getVmTemplate());
}
private void updateVmIcons() {
if (getParameters().getVmLargeIcon() != null) {
final VmIconIdSizePair iconIdPair =
IconUtils.ensureIconPairInDatabase(getParameters().getVmLargeIcon());
getVmTemplate().setSmallIconId(iconIdPair.getSmall());
getVmTemplate().setLargeIconId(iconIdPair.getLarge());
}
}
private void addVmInterfaces(Map<Guid, Guid> srcDeviceIdToTargetDeviceIdMapping) {
List<VmNic> interfaces = vmNicDao.getAllForVm(getParameters().getMasterVm().getId());
for (VmNic iface : interfaces) {
VmNic iDynamic = new VmNic();
iDynamic.setId(Guid.newGuid());
iDynamic.setVmTemplateId(getVmTemplateId());
iDynamic.setName(iface.getName());
iDynamic.setVnicProfileId(iface.getVnicProfileId());
iDynamic.setSpeed(VmInterfaceType.forValue(iface.getType()).getSpeed());
iDynamic.setType(iface.getType());
iDynamic.setLinked(iface.isLinked());
vmNicDao.save(iDynamic);
srcDeviceIdToTargetDeviceIdMapping.put(iface.getId(), iDynamic.getId());
}
}
private void addTemplateDiskVmElement(Guid newDiskId, Guid oldDiskId) {
DiskVmElement oldDve = diskVmElementDao.get(new VmDeviceId(oldDiskId, getVmId()));
DiskVmElement newDve = DiskVmElement.copyOf(oldDve);
newDve.setId(new VmDeviceId(newDiskId, getVmTemplateId()));
diskVmElementDao.save(newDve);
}
private Guid getVmIdFromImageParameters(){
return getParameters().getMasterVm().getId();
}
private void restoreCommandState() {
setVmId(getVmIdFromImageParameters());
isVmInDb = !getVmId().equals(Guid.Empty) && getVm() != null;
}
@Override
protected void endSuccessfully() {
restoreCommandState();
vmStaticDao.incrementDbGeneration(getVmTemplateId());
if (reloadVmTemplateFromDB() != null) {
endDefaultOperations();
}
checkTrustedService();
setSucceeded(true);
}
private void checkTrustedService() {
if (getVm().isTrustedService() && !getVmTemplate().isTrustedService()) {
auditLogDirector.log(this, AuditLogType.USER_ADD_VM_TEMPLATE_FROM_TRUSTED_TO_UNTRUSTED);
}
else if (!getVm().isTrustedService() && getVmTemplate().isTrustedService()) {
auditLogDirector.log(this, AuditLogType.USER_ADD_VM_TEMPLATE_FROM_UNTRUSTED_TO_TRUSTED);
}
}
private void endSuccessfullySynchronous() {
if (reloadVmTemplateFromDB() != null) {
endDefaultOperations();
}
setSucceeded(true);
}
private void endDefaultOperations() {
endUnlockOps();
// in case of new version of a template, update vms marked to use latest
if (isTemplateVersion()) {
updateVmsJobIdMap.put(getParameters().getBaseTemplateId(), StringUtils.EMPTY);
String jobId = getSchedulerUtil().scheduleAOneTimeJob(this, "updateVmVersion", new Class[0],
new Object[0], 0, TimeUnit.SECONDS);
updateVmsJobIdMap.put(getParameters().getBaseTemplateId(), jobId);
}
}
@OnTimerMethodAnnotation("updateVmVersion")
public void updateVmVersion() {
for (Guid vmId : vmDao.getVmIdsForVersionUpdate(getParameters().getBaseTemplateId())) {
// if the job was removed, stop executing, we probably have new version creation going on
if (!updateVmsJobIdMap.containsKey(getParameters().getBaseTemplateId())) {
break;
}
UpdateVmVersionParameters params = new UpdateVmVersionParameters(vmId);
params.setSessionId(getParameters().getSessionId());
getBackend().runInternalAction(VdcActionType.UpdateVmVersion, params, cloneContextAndDetachFromParent());
}
updateVmsJobIdMap.remove(getParameters().getBaseTemplateId());
}
private void endUnlockOps() {
if (isVmInDb) {
vmHandler.unLockVm(getVm());
}
vmTemplateHandler.unlockVmTemplate(getVmTemplateId());
}
private VmTemplate reloadVmTemplateFromDB() {
// set it to null to reload the template from the db
setVmTemplate(null);
return getVmTemplate();
}
@Override
protected void endWithFailure() {
// We evaluate 'VmTemplate' so it won't be null in the last 'if'
// statement.
// (a template without images doesn't exist in the 'vm_template_view').
restoreCommandState();
if (CommandCoordinatorUtil.getCommandExecutionStatus(getParameters().getCommandId()) == CommandExecutionStatus.EXECUTED) {
// if template exist in db remove it
if (getVmTemplate() != null) {
vmTemplateDao.remove(getVmTemplateId());
removeNetwork();
}
}
if (!getVmId().equals(Guid.Empty) && getVm() != null) {
vmHandler.unLockVm(getVm());
}
setSucceeded(true);
}
/**
* in case of non-existing cluster the backend query will return a null
*/
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
if (permissionCheckSubject == null) {
permissionCheckSubject = new ArrayList<>();
if (getParameters().getTemplateType() != VmEntityType.INSTANCE_TYPE) {
Guid storagePoolId = getCluster() == null ? null : getCluster().getStoragePoolId();
permissionCheckSubject.add(new PermissionSubject(storagePoolId,
VdcObjectType.StoragePool,
getActionType().getActionGroup()));
// host-specific parameters can be changed by administration role only
if (!new HashSet<>(getParameters().getMasterVm().getDedicatedVmForVdsList())
.equals(new HashSet<>(getVm().getDedicatedVmForVdsList()))
|| !StringUtils.isEmpty(getParameters().getMasterVm().getCpuPinning())) {
permissionCheckSubject.add(
new PermissionSubject(storagePoolId,
VdcObjectType.StoragePool,
ActionGroup.EDIT_ADMIN_TEMPLATE_PROPERTIES));
}
} else {
permissionCheckSubject.add(new PermissionSubject(Guid.SYSTEM,
VdcObjectType.System,
getActionType().getActionGroup()));
}
}
return permissionCheckSubject;
}
private void addPermission() {
UniquePermissionsSet permissionsToAdd = new UniquePermissionsSet();
if (getCurrentUser() == null) {
setCurrentUser(getParameters().getParametersCurrentUser());
}
addPermissionForTemplate(permissionsToAdd, getCurrentUser().getId(), PredefinedRoles.TEMPLATE_OWNER);
// if the template is for public use, set EVERYONE as a TEMPLATE_USER.
if (getParameters().isPublicUse()) {
addPermissionForTemplate(permissionsToAdd, MultiLevelAdministrationHandler.EVERYONE_OBJECT_ID, PredefinedRoles.TEMPLATE_USER);
} else {
addPermissionForTemplate(permissionsToAdd, getCurrentUser().getId(), PredefinedRoles.TEMPLATE_USER);
}
copyVmPermissions(permissionsToAdd);
if (!permissionsToAdd.isEmpty()) {
List<Permission> permissionsList = permissionsToAdd.asPermissionList();
MultiLevelAdministrationHandler.addPermission(permissionsList.toArray(new Permission[permissionsList.size()]));
}
}
private void copyVmPermissions(UniquePermissionsSet permissionsToAdd) {
if (!isVmInDb || !getParameters().isCopyVmPermissions()) {
return;
}
List<Permission> vmPermissions = permissionDao.getAllForEntity(getVmId(), getEngineSessionSeqId(), false);
for (Permission vmPermission : vmPermissions) {
permissionsToAdd.addPermission(vmPermission.getAdElementId(), vmPermission.getRoleId(),
getParameters().getVmTemplateId(), VdcObjectType.VmTemplate);
}
}
private void addPermissionForTemplate(UniquePermissionsSet permissionsToAdd, Guid userId, PredefinedRoles role) {
permissionsToAdd.addPermission(userId, role.getId(), getParameters().getVmTemplateId(), VdcObjectType.VmTemplate);
}
@Override
protected List<Class<?>> getValidationGroups() {
addValidationGroup(CreateEntity.class);
return super.getValidationGroups();
}
@Override
protected void setActionMessageParameters() {
addValidationMessage(EngineMessage.VAR__ACTION__ADD);
addValidationMessage(EngineMessage.VAR__TYPE__VM_TEMPLATE);
}
@Override
public AuditLogType getAuditLogTypeValue() {
switch (getActionState()) {
case EXECUTE:
if (isVmInDb) {
if (pendingAsyncTasks) {
return getSucceeded() ? AuditLogType.USER_ADD_VM_TEMPLATE : AuditLogType.USER_FAILED_ADD_VM_TEMPLATE;
} else {
return getSucceeded() ? AuditLogType.USER_ADD_VM_TEMPLATE_FINISHED_SUCCESS : getAuditLogFailureType();
}
} else {
return getSucceeded() ? AuditLogType.USER_ADD_VM_TEMPLATE_SUCCESS : AuditLogType.USER_ADD_VM_TEMPLATE_FAILURE;
}
case END_SUCCESS:
return getSucceeded() ? AuditLogType.USER_ADD_VM_TEMPLATE_FINISHED_SUCCESS : getAuditLogFailureType();
default:
return getAuditLogFailureType();
}
}
private AuditLogType getAuditLogFailureType() {
switch (getParameters().getPhase()) {
case CREATE_TEMPLATE:
return AuditLogType.USER_ADD_VM_TEMPLATE_CREATE_TEMPLATE_FAILURE;
case ASSIGN_ILLEGAL:
return AuditLogType.USER_ADD_VM_TEMPLATE_ASSIGN_ILLEGAL_FAILURE;
case SEAL:
return AuditLogType.USER_ADD_VM_TEMPLATE_SEAL_FAILURE;
case ASSIGN_LEGAL_SHARED:
default:
return AuditLogType.USER_ADD_VM_TEMPLATE_FINISHED_FAILURE;
}
}
@Override
public Map<String, String> getJobMessageProperties() {
jobProperties.put("phase", getParameters().getPhase().name());
return jobProperties;
}
@Override
protected boolean isQuotaDependant() {
if (getParameters().getTemplateType() == VmEntityType.INSTANCE_TYPE) {
return false;
}
return super.isQuotaDependant();
}
private Guid getQuotaIdForDisk(DiskImage diskImage) {
// If the DiskInfoDestinationMap is available and contains information about the disk
if (getParameters().getDiskInfoDestinationMap() != null
&& getParameters().getDiskInfoDestinationMap().get(diskImage.getId()) != null) {
return getParameters().getDiskInfoDestinationMap().get(diskImage.getId()).getQuotaId();
}
return diskImage.getQuotaId();
}
@Override
public List<QuotaConsumptionParameter> getQuotaStorageConsumptionParameters() {
return getVm().getDiskList()
.stream()
.map(disk -> new QuotaStorageConsumptionParameter(
getQuotaIdForDisk(disk),
null,
QuotaStorageConsumptionParameter.QuotaAction.CONSUME,
disk.getStorageIds().get(0),
(double) disk.getSizeInGigabytes()))
.collect(Collectors.toList());
}
@Override
public List<QuotaConsumptionParameter> getQuotaVdsConsumptionParameters() {
Guid quotaId = getQuotaManager().getDefaultQuotaIfNull(
getParameters().getMasterVm().getQuotaId(),
getStoragePoolId());
List<QuotaConsumptionParameter> list = new ArrayList<>();
list.add(new QuotaSanityParameter(quotaId, null));
return list;
}
@Override
protected LockProperties applyLockProperties(LockProperties lockProperties) {
return lockProperties.withScope(Scope.Command);
}
@Override
protected Map<String, Pair<String, String>> getExclusiveLocks() {
Map<String, Pair<String, String>> locks = new HashMap<>();
if (getVmTemplateName() != null && !isTemplateVersion()) {
locks.put(getVmTemplateName(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.TEMPLATE_NAME,
EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_NAME_IS_USED));
}
locks.put(getVmTemplateId().toString(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.TEMPLATE,
EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_CREATED));
Arrays.stream(targetDiskIds)
.forEach(id -> locks.put(id.toString(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.DISK,
EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_CREATED)));
return locks;
}
@Override
protected Map<String, Pair<String, String>> getSharedLocks() {
Map<String, Pair<String, String>> locks = new HashMap<>();
if (isTemplateVersion()) {
locks.put(getParameters().getBaseTemplateId().toString(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.TEMPLATE,
EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_VERSION_IS_BEING_CREATED));
}
locks.put(getParameters().getVm().getId().toString(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.VM,
EngineMessage.ACTION_TYPE_FAILED_TEMPLATE_IS_BEING_CREATED_FROM_VM));
return locks;
}
private SchedulerUtil getSchedulerUtil() {
return schedulerUtil;
}
@Override
public CommandCallback getCallback() {
return new SerialChildCommandsExecutionCallback();
}
}