package org.ovirt.engine.core.bll.storage.domain;
import static org.ovirt.engine.core.bll.MultiLevelAdministrationHandler.SYSTEM_OBJECT_ID;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.storage.connection.StorageHelperDirector;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.bll.utils.WipeAfterDeleteUtils;
import org.ovirt.engine.core.bll.validator.storage.StorageDomainToPoolRelationValidator;
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.StorageDomainManagementParameter;
import org.ovirt.engine.core.common.businessentities.StorageDomain;
import org.ovirt.engine.core.common.businessentities.StorageDomainDynamic;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatic;
import org.ovirt.engine.core.common.businessentities.StorageDomainType;
import org.ovirt.engine.core.common.businessentities.StorageFormatType;
import org.ovirt.engine.core.common.businessentities.StoragePool;
import org.ovirt.engine.core.common.businessentities.StorageServerConnections;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.constants.StorageConstants;
import org.ovirt.engine.core.common.errors.EngineError;
import org.ovirt.engine.core.common.errors.EngineFault;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.utils.VersionStorageFormatUtil;
import org.ovirt.engine.core.common.validation.group.CreateEntity;
import org.ovirt.engine.core.common.vdscommands.CreateStorageDomainVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.GetStorageDomainStatsVDSCommandParameters;
import org.ovirt.engine.core.common.vdscommands.StorageServerConnectionManagementVDSParameters;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.Version;
import org.ovirt.engine.core.dao.StorageDomainDynamicDao;
import org.ovirt.engine.core.dao.StorageDomainStaticDao;
import org.ovirt.engine.core.dao.StoragePoolDao;
import org.ovirt.engine.core.dao.StorageServerConnectionDao;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
public abstract class AddStorageDomainCommand<T extends StorageDomainManagementParameter> extends
StorageDomainManagementCommandBase<T> {
@Inject
private StorageDomainDynamicDao storageDomainDynamicDao;
@Inject
private StorageServerConnectionDao storageServerConnectionDao;
@Inject
private StorageDomainStaticDao storageDomainStaticDao;
@Inject
private StoragePoolDao storagePoolDao;
protected AddStorageDomainCommand(Guid commandId) {
super(commandId);
}
public AddStorageDomainCommand(T parameters,
CommandContext commandContext) {
super(parameters, commandContext);
}
protected void initializeStorageDomain() {
getStorageDomain().setId(Guid.newGuid());
updateStaticDataDefaults();
}
protected void updateStaticDataDefaults() {
updateStorageDomainWipeAfterDelete();
updateSpaceThresholds();
}
private void updateStorageDomainWipeAfterDelete() {
if(getStorageDomain().getStorageStaticData().getWipeAfterDelete() == null) {
getStorageDomain().getStorageStaticData().setWipeAfterDelete(
WipeAfterDeleteUtils.getDefaultWipeAfterDeleteFlag(
getStorageDomain().getStorageStaticData().getStorageType()));
}
}
private void updateSpaceThresholds() {
if(getStorageDomain().getWarningLowSpaceIndicator() == null) {
getStorageDomain().setWarningLowSpaceIndicator(Config.<Integer>getValue(ConfigValues.WarningLowSpaceIndicator));
}
if(getStorageDomain().getCriticalSpaceActionBlocker() == null) {
getStorageDomain().setCriticalSpaceActionBlocker(Config.<Integer>getValue(ConfigValues.CriticalSpaceActionBlocker));
}
}
protected boolean addStorageDomainInIrs() {
// No need to run in separate transaction - counting on rollback of external transaction wrapping the command
return runVdsCommand(
VDSCommandType.CreateStorageDomain,
new CreateStorageDomainVDSCommandParameters(getVds().getId(), getStorageDomain()
.getStorageStaticData(), getStorageArgs())).getSucceeded();
}
protected void addStorageDomainInDb() {
TransactionSupport.executeInNewTransaction(() -> {
StorageDomainStatic storageStaticData = getStorageDomain().getStorageStaticData();
storageDomainStaticDao.save(storageStaticData);
getCompensationContext().snapshotNewEntity(storageStaticData);
StorageDomainDynamic newStorageDynamic =
new StorageDomainDynamic(null, getStorageDomain().getId(), null);
getReturnValue().setActionReturnValue(getStorageDomain().getId());
storageDomainDynamicDao.save(newStorageDynamic);
getCompensationContext().snapshotNewEntity(newStorageDynamic);
getCompensationContext().stateChanged();
return null;
});
if (getStorageDomain().getStorageDomainType().isDataDomain()) {
createDefaultDiskProfile();
}
}
protected void updateStorageDomainDynamicFromIrs() {
final StorageDomain sd =
(StorageDomain) runVdsCommand(VDSCommandType.GetStorageDomainStats,
new GetStorageDomainStatsVDSCommandParameters(getVds().getId(),
getStorageDomain().getId()))
.getReturnValue();
TransactionSupport.executeInNewTransaction(() -> {
getCompensationContext().snapshotEntity(getStorageDomain().getStorageDynamicData());
storageDomainDynamicDao.update(sd.getStorageDynamicData());
getCompensationContext().stateChanged();
return null;
});
}
@Override
protected void executeCommand() {
initializeStorageDomain();
addStorageDomainInDb();
// check connection to storage
Pair<Boolean, Integer> connectReturnValue = connectStorage();
if (!connectReturnValue.getFirst()) {
EngineFault fault = new EngineFault();
fault.setError(EngineError.forValue(connectReturnValue.getSecond()));
getReturnValue().setFault(fault);
setSucceeded(false);
}
else if (addStorageDomainInIrs()) {
updateStorageDomainDynamicFromIrs();
setSucceeded(true);
}
}
protected Pair<Boolean, Integer> connectStorage() {
String connectionId = getStorageDomain().getStorage();
StorageServerConnections connection = storageServerConnectionDao.get(connectionId);
Map<String, String> result = (Map<String, String>) runVdsCommand(
VDSCommandType.ConnectStorageServer,
new StorageServerConnectionManagementVDSParameters(getParameters().getVdsId(), Guid.Empty,
connection.getStorageType(),
new ArrayList<>(Collections.singletonList(connection))))
.getReturnValue();
return new Pair<>(StorageHelperDirector.getInstance()
.getItem(connection.getStorageType())
.isConnectSucceeded(result, Collections.singletonList(connection)),
Integer.parseInt(result.values().iterator().next()));
}
@Override
public AuditLogType getAuditLogTypeValue() {
return getSucceeded() ? AuditLogType.USER_ADD_STORAGE_DOMAIN : AuditLogType.USER_ADD_STORAGE_DOMAIN_FAILED;
}
@Override
protected boolean validate() {
if (!super.validate() || !initializeVds() || !checkStorageDomainNameLengthValid()) {
return false;
}
if (isStorageWithSameNameExists()) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NAME_ALREADY_EXIST);
}
if (getStorageDomain().getStorageDomainType() == StorageDomainType.ISO
&& !getStorageDomain().getStorageType().isFileDomain()) {
addValidationMessageVariable("domainType", StorageConstants.ISO);
addValidationMessageVariable("storageTypes", StorageConstants.FILE);
return failValidation(EngineMessage.ACTION_TYPE_FAILED_DOMAIN_TYPE_CAN_BE_CREATED_ONLY_ON_SPECIFIC_STORAGE_DOMAINS);
}
if (getStorageDomain().getStorageDomainType() == StorageDomainType.ImportExport
&& getStorageDomain().getStorageType().isBlockDomain()) {
addValidationMessageVariable("domainType", StorageConstants.EXPORT);
addValidationMessageVariable("storageTypes", StorageConstants.FILE);
return failValidation(EngineMessage.ACTION_TYPE_FAILED_DOMAIN_TYPE_CAN_BE_CREATED_ONLY_ON_SPECIFIC_STORAGE_DOMAINS);
}
if (getStorageDomain().getStorageDomainType() == StorageDomainType.Master) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_TYPE_ILLEGAL);
}
if (!Guid.isNullOrEmpty(getParameters().getStoragePoolId()) && getTargetStoragePool() == null) {
return failValidation(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_EXIST);
}
ensureStorageFormatInitialized();
StorageDomainToPoolRelationValidator storageDomainToPoolRelationValidator = getAttachDomainValidator();
StorageDomainValidator sdValidator = getStorageDomainValidator();
if (!validate(storageDomainToPoolRelationValidator.isStorageDomainFormatCorrectForDC()) ||
!validate(sdValidator.isStorageFormatCompatibleWithDomain()) ||
!validateDiscardAfterDeleteLegal(sdValidator, getTargetStoragePool().getCompatibilityVersion())) {
return false;
}
return canAddDomain();
}
private void ensureStorageFormatInitialized() {
StorageDomain sd = getStorageDomain();
if (sd.getStorageFormat() == null) {
if (sd.getStorageDomainType().isDataDomain()) {
StoragePool sp = getTargetStoragePool();
if (sp != null) {
sd.setStorageFormat(VersionStorageFormatUtil.getForVersion(sp.getCompatibilityVersion()));
}
} else {
sd.setStorageFormat(StorageFormatType.V1);
}
}
}
private StoragePool getTargetStoragePool() {
StoragePool targetStoragePool = getStoragePool();
if (targetStoragePool == null) {
targetStoragePool = storagePoolDao.get(getVds().getStoragePoolId());
}
return targetStoragePool;
}
protected String getStorageArgs() {
return getStorageDomain().getStorage();
}
protected abstract boolean canAddDomain();
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
return Collections.singletonList(new PermissionSubject(SYSTEM_OBJECT_ID, VdcObjectType.System,
getActionType().getActionGroup()));
}
@Override
protected List<Class<?>> getValidationGroups() {
addValidationGroup(CreateEntity.class);
return super.getValidationGroups();
}
@Override
protected void setActionMessageParameters() {
super.setActionMessageParameters();
addValidationMessage(EngineMessage.VAR__ACTION__ADD);
}
public StorageDomainToPoolRelationValidator getAttachDomainValidator() {
return new StorageDomainToPoolRelationValidator(getStorageDomain().getStorageStaticData(), getTargetStoragePool());
}
public StorageDomainValidator getStorageDomainValidator() {
return new StorageDomainValidator(getStorageDomain());
}
protected abstract boolean validateDiscardAfterDeleteLegal(StorageDomainValidator storageDomainValidator,
Version compatibilityVersion);
}