package org.ovirt.engine.core.bll.storage.disk.image;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.LockMessagesMatchUtil;
import org.ovirt.engine.core.bll.NonTransactiveCommandAttribute;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.profiles.DiskProfileHelper;
import org.ovirt.engine.core.bll.quota.QuotaConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaStorageConsumptionParameter;
import org.ovirt.engine.core.bll.quota.QuotaStorageDependent;
import org.ovirt.engine.core.bll.validator.storage.StorageDomainValidator;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.LockProperties;
import org.ovirt.engine.core.common.action.RegisterCinderDiskParameters;
import org.ovirt.engine.core.common.action.RegisterDiskParameters;
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.StorageDomainType;
import org.ovirt.engine.core.common.businessentities.storage.CinderDisk;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.DiskStorageType;
import org.ovirt.engine.core.common.businessentities.storage.VolumeFormat;
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.GetUnregisteredDiskQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryReturnValue;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
import org.ovirt.engine.core.dao.DiskDao;
import org.ovirt.engine.core.dao.ImageDao;
import org.ovirt.engine.core.dao.UnregisteredDisksDao;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
@NonTransactiveCommandAttribute
public class RegisterDiskCommand <T extends RegisterDiskParameters> extends BaseImagesCommand<T> implements QuotaStorageDependent {
private static final String DEFAULT_REGISTRATION_FORMAT = "RegisteredDisk_%1$tY-%1$tm-%1$td_%1$tH-%1$tM-%1$tS";
@Inject
private DiskProfileHelper diskProfileHelper;
@Inject
private DiskDao diskDao;
@Inject
private UnregisteredDisksDao unregisteredDisksDao;
@Inject
private ImageDao imageDao;
public RegisterDiskCommand(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
setStoragePoolId(getParameters().getDiskImage().getStoragePoolId());
parameters.setEntityInfo(new EntityInfo(VdcObjectType.Disk, getParameters().getDiskImage().getId()));
}
public RegisterDiskCommand(Guid commandId) {
super(commandId);
}
private void refreshDiskImageIfNecessery() {
if (getParameters().isRefreshFromStorage()) {
GetUnregisteredDiskQueryParameters unregQueryParams =
new GetUnregisteredDiskQueryParameters(getParameters().getDiskImage().getId(),
getStorageDomainId(),
getStoragePoolId());
VdcQueryReturnValue unregQueryReturn = runInternalQuery(VdcQueryType.GetUnregisteredDisk, unregQueryParams);
if (unregQueryReturn.getSucceeded()) {
setDiskImage(unregQueryReturn.getReturnValue());
}
} else {
setDiskImage(getParameters().getDiskImage());
}
}
@Override
protected boolean validate() {
refreshDiskImageIfNecessery();
// Currently this only supports importing DiskImages or CinderDisks and does not work with LunDisks.
if (getDiskImage().getDiskStorageType() != DiskStorageType.IMAGE &&
getDiskImage().getDiskStorageType() != DiskStorageType.CINDER) {
addValidationMessageVariable("diskId", getDiskImage().getId());
addValidationMessageVariable("storageType", getDiskImage().getDiskStorageType());
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_UNSUPPORTED_DISK_STORAGE_TYPE);
return false;
}
if (!validate(new StorageDomainValidator(getStorageDomain()).isDomainExist())) {
addValidationMessageVariable("diskId", getDiskImage().getId());
addValidationMessageVariable("domainId", getStorageDomainId());
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_UNAVAILABLE);
return false;
}
if (!getStorageDomain().getStorageDomainType().isDataDomain() &&
!(getStorageDomain().getStorageDomainType() == StorageDomainType.Volume)) {
addValidationMessageVariable("domainId", getParameters().getStorageDomainId());
addValidationMessageVariable("domainType", getStorageDomain().getStorageDomainType());
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_UNSUPPORTED);
return false;
}
if (diskDao.get(getDiskImage().getId()) != null) {
String diskAlias =
ImagesHandler.getDiskAliasWithDefault(getDiskImage(),
generateDefaultAliasForRegiteredDisk(Calendar.getInstance()));
addValidationMessageVariable("diskAliases", diskAlias);
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_DISKS_LOCKED);
return false;
}
if (getDiskImage().getDiskStorageType() == DiskStorageType.IMAGE &&
!setAndValidateDiskProfiles()) {
return false;
}
return true;
}
@Override
protected void executeCommand() {
TransactionSupport.executeInNewTransaction(() -> {
if (getDiskImage().getDiskStorageType() == DiskStorageType.IMAGE) {
final DiskImage newDiskImage = getDiskImage();
newDiskImage.setDiskAlias(ImagesHandler.getDiskAliasWithDefault(newDiskImage,
generateDefaultAliasForRegiteredDisk(Calendar.getInstance())));
addRegisterInitatedAuditLog();
ArrayList<Guid> storageIds = new ArrayList<>();
storageIds.add(getParameters().getStorageDomainId());
newDiskImage.setStorageIds(storageIds);
addDiskImageToDb(newDiskImage, getCompensationContext(), Boolean.TRUE);
unregisteredDisksDao.removeUnregisteredDisk(newDiskImage.getId(), null);
getReturnValue().setActionReturnValue(newDiskImage.getId());
getReturnValue().setSucceeded(true);
} else if (getDiskImage().getDiskStorageType() == DiskStorageType.CINDER) {
VdcReturnValueBase returnValue = runInternalAction(VdcActionType.RegisterCinderDisk, new RegisterCinderDiskParameters(
(CinderDisk) getDiskImage(), getParameters().getStorageDomainId()));
setReturnValue(returnValue);
}
return null;
});
fetchQcowCompat();
}
private void addRegisterInitatedAuditLog() {
AuditLogableBase logable = new AuditLogableBase();
logable.addCustomValue("DiskAlias", getDiskImage().getDiskAlias());
auditLogDirector.log(logable, AuditLogType.USER_REGISTER_DISK_INITIATED);
}
private void fetchQcowCompat() {
if (getDiskImage().getDiskStorageType() == DiskStorageType.IMAGE
&& getDiskImage().getVolumeFormat().equals(VolumeFormat.COW)) {
DiskImage newDiskImage = getDiskImage();
try {
setQcowCompat(newDiskImage.getImage(),
newDiskImage.getStoragePoolId(),
newDiskImage.getId(),
newDiskImage.getImageId(),
getParameters().getStorageDomainId(),
null);
// TODO: We should update the insert to also set qcow compat.
imageDao.update(newDiskImage.getImage());
} catch (EngineException e) {
// Logging only
log.error("Unable to update the image info for image '{}' (image group: '{}') on domain '{}'",
newDiskImage.getImageId(),
newDiskImage.getId(),
getParameters().getStorageDomainId());
}
}
}
protected static String generateDefaultAliasForRegiteredDisk(Calendar time) {
return String.format(DEFAULT_REGISTRATION_FORMAT, time);
}
@Override
protected void setActionMessageParameters() {
addValidationMessage(EngineMessage.VAR__ACTION__IMPORT);
addValidationMessage(EngineMessage.VAR__TYPE__DISK);
}
protected boolean setAndValidateDiskProfiles() {
return validate(diskProfileHelper.setAndValidateDiskProfiles(Collections.singletonMap(getDiskImage(),
getStorageDomainId()),
getCurrentUser()));
}
@Override
public List<QuotaConsumptionParameter> getQuotaStorageConsumptionParameters() {
List<QuotaConsumptionParameter> list = new ArrayList<>();
refreshDiskImageIfNecessery();
list.add(new QuotaStorageConsumptionParameter(
getParameters().getDiskImage().getQuotaId(),
null,
QuotaConsumptionParameter.QuotaAction.CONSUME,
getStorageDomainId(),
getDiskImage().getActualSize()));
return list;
}
@Override
public AuditLogType getAuditLogTypeValue() {
addCustomValue("DiskAlias", getDiskImage().getDiskAlias());
return getSucceeded() ? AuditLogType.USER_REGISTER_DISK_FINISHED_SUCCESS
: AuditLogType.USER_REGISTER_DISK_FINISHED_FAILURE;
}
@Override
protected LockProperties applyLockProperties(LockProperties lockProperties) {
return lockProperties.withScope(LockProperties.Scope.Execution);
}
@Override
protected Map<String, Pair<String, String>> getExclusiveLocks() {
return Collections.singletonMap(getParameters().getDiskImage().getId().toString(),
LockMessagesMatchUtil.makeLockingPair(LockingGroup.DISK, EngineMessage.ACTION_TYPE_FAILED_OBJECT_LOCKED));
}
}