package org.ovirt.engine.core.bll.storage;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.apache.commons.lang.StringUtils;
import org.ovirt.engine.core.bll.CommandBase;
import org.ovirt.engine.core.bll.RetrieveImageDataParameters;
import org.ovirt.engine.core.bll.context.CommandContext;
import org.ovirt.engine.core.bll.interfaces.BackendInternal;
import org.ovirt.engine.core.bll.network.macpool.MacPool;
import org.ovirt.engine.core.bll.network.macpool.MacPoolPerCluster;
import org.ovirt.engine.core.bll.snapshots.SnapshotsValidator;
import org.ovirt.engine.core.bll.storage.disk.cinder.CinderBroker;
import org.ovirt.engine.core.bll.storage.disk.image.MetadataDiskDescriptionHandler;
import org.ovirt.engine.core.bll.storage.pool.ActivateDeactivateSingleAsyncOperationFactory;
import org.ovirt.engine.core.bll.storage.pool.StoragePoolStatusHandler;
import org.ovirt.engine.core.bll.utils.PermissionSubject;
import org.ovirt.engine.core.common.AuditLogType;
import org.ovirt.engine.core.common.VdcObjectType;
import org.ovirt.engine.core.common.action.RegisterDiskParameters;
import org.ovirt.engine.core.common.action.StoragePoolParametersBase;
import org.ovirt.engine.core.common.action.VdcActionType;
import org.ovirt.engine.core.common.action.VdcReturnValueBase;
import org.ovirt.engine.core.common.businessentities.OvfEntityData;
import org.ovirt.engine.core.common.businessentities.StorageDomain;
import org.ovirt.engine.core.common.businessentities.StorageDomainOvfInfo;
import org.ovirt.engine.core.common.businessentities.StorageDomainOvfInfoStatus;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatic;
import org.ovirt.engine.core.common.businessentities.StorageDomainStatus;
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.StoragePoolStatus;
import org.ovirt.engine.core.common.businessentities.VDS;
import org.ovirt.engine.core.common.businessentities.VDSStatus;
import org.ovirt.engine.core.common.businessentities.VM;
import org.ovirt.engine.core.common.businessentities.VmBase;
import org.ovirt.engine.core.common.businessentities.VmEntityType;
import org.ovirt.engine.core.common.businessentities.VmTemplate;
import org.ovirt.engine.core.common.businessentities.network.VmNic;
import org.ovirt.engine.core.common.businessentities.storage.Disk;
import org.ovirt.engine.core.common.businessentities.storage.DiskContentType;
import org.ovirt.engine.core.common.businessentities.storage.DiskImage;
import org.ovirt.engine.core.common.businessentities.storage.UnregisteredDisk;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.errors.EngineException;
import org.ovirt.engine.core.common.errors.EngineMessage;
import org.ovirt.engine.core.common.queries.GetUnregisteredDisksQueryParameters;
import org.ovirt.engine.core.common.queries.VdcQueryType;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
import org.ovirt.engine.core.common.vdscommands.VDSParametersBase;
import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.TransactionScopeOption;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable;
import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableImpl;
import org.ovirt.engine.core.dao.ClusterDao;
import org.ovirt.engine.core.dao.DiskImageDao;
import org.ovirt.engine.core.dao.StorageDomainDao;
import org.ovirt.engine.core.dao.StorageDomainOvfInfoDao;
import org.ovirt.engine.core.dao.StorageDomainStaticDao;
import org.ovirt.engine.core.dao.StoragePoolDao;
import org.ovirt.engine.core.dao.UnregisteredDisksDao;
import org.ovirt.engine.core.dao.UnregisteredOVFDataDao;
import org.ovirt.engine.core.dao.VdsDao;
import org.ovirt.engine.core.dao.VmDao;
import org.ovirt.engine.core.dao.VmTemplateDao;
import org.ovirt.engine.core.dao.network.VmNicDao;
import org.ovirt.engine.core.utils.JsonHelper;
import org.ovirt.engine.core.utils.OvfUtils;
import org.ovirt.engine.core.utils.SyncronizeNumberOfAsyncOperations;
import org.ovirt.engine.core.utils.ovf.OvfInfoFileConstants;
import org.ovirt.engine.core.utils.ovf.OvfParser;
import org.ovirt.engine.core.utils.transaction.TransactionMethod;
import org.ovirt.engine.core.utils.transaction.TransactionSupport;
public abstract class StorageHandlingCommandBase<T extends StoragePoolParametersBase> extends CommandBase<T> {
private CinderBroker cinderBroker;
protected List<DiskImage> ovfDisks;
protected List<UnregisteredDisk> unregisteredDisks = new ArrayList<>();
@Inject
private MacPoolPerCluster macPoolPerCluster;
@Inject
private SnapshotsValidator snapshotsValidator;
@Inject
private VdsDao vdsDao;
@Inject
private StoragePoolDao storagePoolDao;
@Inject
private StorageDomainDao storageDomainDao;
@Inject
private VmTemplateDao vmTemplateDao;
@Inject
private DiskImageDao diskImageDao;
@Inject
private UnregisteredOVFDataDao unregisteredOVFDataDao;
@Inject
private VmNicDao vmNicDao;
@Inject
private ClusterDao clusterDao;
@Inject
private StorageDomainOvfInfoDao storageDomainOvfInfoDao;
@Inject
private StorageDomainStaticDao storageDomainStaticDao;
@Inject
private UnregisteredDisksDao unregisteredDisksDao;
@Inject
private VmDao vmDao;
protected StorageHandlingCommandBase(T parameters, CommandContext commandContext) {
super(parameters, commandContext);
}
@Override
public void init() {
super.init();
setVdsId(getParameters().getVdsId());
if (getParameters() != null && !getParameters().getStoragePoolId().equals(Guid.Empty)) {
setStoragePoolId(getParameters().getStoragePoolId());
}
}
/**
* Constructor for command creation when compensation is applied on startup
*/
protected StorageHandlingCommandBase(Guid commandId) {
super(commandId);
}
protected List<VDS> getAllRunningVdssInPool() {
return vdsDao.getAllForStoragePoolAndStatus(getStoragePool().getId(), VDSStatus.Up);
}
protected void updateStoragePoolMasterDomainVersionInDiffTransaction() {
executeInScope(TransactionScopeOption.Suppress, () -> {
int master_domain_version = storagePoolDao.increaseStoragePoolMasterVersion(getStoragePool().getId());
getStoragePool().setMasterDomainVersion(master_domain_version);
return null;
});
}
protected Guid getMasterDomainIdFromDb() {
Guid ret = Guid.Empty;
if (getStoragePool() != null) {
ret = storageDomainDao.getMasterStorageDomainIdForPool(getStoragePool().getId());
}
return ret;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected boolean initializeVds() {
boolean returnValue = true;
if (getVds() == null) {
// select random host to avoid executing almost every time through the same one
// (as the db query will return the hosts in the same order on most times).
setVds(checkForActiveVds());
if (getVds() == null) {
returnValue = false;
}
}
return returnValue;
}
protected VDS checkForActiveVds() {
List<VDS> hosts = vdsDao.getAllForStoragePoolAndStatus(getStoragePool().getId(),
VDSStatus.Up);
if (!hosts.isEmpty()) {
return hosts.get(new Random().nextInt(hosts.size()));
}
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_NO_VDS_IN_POOL);
return null;
}
protected boolean checkStoragePool() {
if (getStoragePool() == null) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_NOT_EXIST);
return false;
}
return true;
}
protected boolean canDetachStorageDomainWithVmsAndDisks(StorageDomain storageDomain) {
if (!storageDomain.getStorageDomainType().isDataDomain()) {
return true;
}
List<VM> vmRelatedToDomain = vmDao.getAllForStorageDomain(storageDomain.getId());
List<String> vmsInPreview = vmRelatedToDomain.stream().filter(vm -> !snapshotsValidator.vmNotInPreview(vm.getId()).isValid()).map(VM::getName).collect(Collectors.toList());
List<VM> vmsWithDisksOnMultipleStorageDomain = vmDao.getAllVMsWithDisksOnOtherStorageDomain(storageDomain.getId());
vmRelatedToDomain.removeAll(vmsWithDisksOnMultipleStorageDomain);
List<String> entitiesDeleteProtected = new ArrayList<>();
List<String> vmsInPool = new ArrayList<>();
for (VM vm : vmRelatedToDomain) {
if (vm.isDeleteProtected()) {
entitiesDeleteProtected.add(vm.getName());
}
if (vm.getVmPoolId() != null) {
vmsInPool.add(vm.getName());
}
}
List<VmTemplate> templatesRelatedToDomain = vmTemplateDao.getAllForStorageDomain(storageDomain.getId());
List<VmTemplate> vmTemplatesWithDisksOnMultipleStorageDomain =
vmTemplateDao.getAllTemplatesWithDisksOnOtherStorageDomain(storageDomain.getId());
templatesRelatedToDomain.removeAll(vmTemplatesWithDisksOnMultipleStorageDomain);
entitiesDeleteProtected.addAll(templatesRelatedToDomain.stream().filter(VmBase::isDeleteProtected).map(VmTemplate::getName).collect(Collectors.toList()));
boolean succeeded = true;
if (!entitiesDeleteProtected.isEmpty()) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DELETE_PROTECTED);
addValidationMessageVariable("vms", StringUtils.join(entitiesDeleteProtected, ","));
succeeded = false;
}
if (!vmsInPool.isEmpty()) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_VMS_IN_POOL);
addValidationMessageVariable("vms", StringUtils.join(vmsInPool, ","));
succeeded = false;
}
if (!vmsInPreview.isEmpty()) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DELETE_VMS_IN_PREVIEW);
addValidationMessageVariable("vms", StringUtils.join(vmsInPreview, ","));
succeeded = false;
}
return succeeded;
}
protected void detachStorageDomainWithEntities(StorageDomain storageDomain) {
// Check if we have entities related to the Storage Domain.
List<VM> vmsForStorageDomain = vmDao.getAllForStorageDomain(storageDomain.getId());
List<VmTemplate> vmTemplatesForStorageDomain = vmTemplateDao.getAllForStorageDomain(storageDomain.getId());
List<DiskImage> disksForStorageDomain = diskImageDao.getAllForStorageDomain(storageDomain.getId());
removeEntitiesFromStorageDomain(vmsForStorageDomain, vmTemplatesForStorageDomain, disksForStorageDomain, storageDomain.getId());
}
private void removeEntityLeftOver(Guid entityId, String entityName, Guid storageDomainId) {
List<OvfEntityData> ovfEntityList =
unregisteredOVFDataDao.getByEntityIdAndStorageDomain(entityId, storageDomainId);
if (!ovfEntityList.isEmpty()) {
log.info("Entity '{}' with id '{}', already exists as unregistered entity. override it with the new entity from the engine",
entityName,
entityId);
unregisteredOVFDataDao.removeEntity(entityId, storageDomainId);
}
}
protected void releaseStorageDomainMacPool(List<VM> vmList) {
Map<Guid, List<Guid>> vmsByCluster = vmList.stream()
.collect(Collectors.groupingBy(VM::getClusterId, Collectors.mapping(VM::getId, Collectors.toList())));
vmsByCluster.entrySet().forEach(e -> {
Guid clusterId = e.getKey();
List<Guid> vmsId = e.getValue();
MacPool macPool = macPoolPerCluster.getMacPoolForCluster(clusterId, getContext());
macPool.freeMacs(vmsId
.stream()
.flatMap(v -> vmNicDao.getAllForVm(v).stream())
.map(VmNic::getMacAddress)
.filter(Objects::nonNull)
.collect(Collectors.toList()));
});
}
/**
* Remove all related entities of the Storage Domain from the DB.
*/
private void removeEntitiesFromStorageDomain(final List<VM> vmsForStorageDomain,
final List<VmTemplate> vmTemplatesForStorageDomain,
final List<DiskImage> disksForStorageDomain,
final Guid storageDomainId) {
if (!vmsForStorageDomain.isEmpty() || !vmTemplatesForStorageDomain.isEmpty() || !disksForStorageDomain.isEmpty()) {
TransactionSupport.executeInNewTransaction(() -> {
for (VM vm : vmsForStorageDomain) {
removeEntityLeftOver(vm.getId(), vm.getName(), storageDomainId);
unregisteredOVFDataDao.saveOVFData(new OvfEntityData(
vm.getId(),
vm.getName(),
VmEntityType.VM,
vm.getClusterArch(),
vm.getCompatibilityVersion(),
storageDomainId,
null,
null));
}
for (VmTemplate vmTemplate : vmTemplatesForStorageDomain) {
removeEntityLeftOver(vmTemplate.getId(), vmTemplate.getName(), storageDomainId);
unregisteredOVFDataDao.saveOVFData(new OvfEntityData(
vmTemplate.getId(),
vmTemplate.getName(),
VmEntityType.TEMPLATE,
vmTemplate.getClusterArch(),
clusterDao.get(vmTemplate.getClusterId()).getCompatibilityVersion(),
storageDomainId,
null,
null));
}
storageDomainDao.removeEntitesFromStorageDomain(storageDomainId);
return null;
});
}
}
protected boolean checkStoragePoolStatus(StoragePoolStatus status) {
boolean returnValue = false;
StoragePool storagePool = getStoragePool();
if (storagePool != null) {
returnValue = storagePool.getStatus() == status;
if (!returnValue
&& !getReturnValue().getValidationMessages().contains(
EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_STATUS_ILLEGAL.toString())) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_POOL_STATUS_ILLEGAL);
}
}
return returnValue;
}
protected boolean checkStoragePoolStatusNotEqual(StoragePoolStatus status, EngineMessage onFailMessage) {
boolean returnValue = false;
StoragePool storagePool = getStoragePool();
if (storagePool != null) {
returnValue = storagePool.getStatus() != status;
if (!returnValue
&& !getReturnValue().getValidationMessages().contains(onFailMessage.name())) {
addValidationMessage(onFailMessage);
}
}
return returnValue;
}
protected boolean isStorageDomainNotNull(StorageDomain domain) {
if (domain == null) {
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_STORAGE_DOMAIN_NOT_EXIST);
return false;
}
return true;
}
protected void calcStoragePoolStatusByDomainsStatus() {
StorageDomain masterDomain =
storageDomainDao.getStorageDomains(getStoragePool().getId(), StorageDomainType.Master)
.stream().findFirst().orElse(null);
// if no master then Uninitialized
// if master not active maintenance
StoragePoolStatus newStatus =
(masterDomain == null) ? StoragePoolStatus.Uninitialized
: (masterDomain.getStatus() != null && masterDomain.getStatus() == StorageDomainStatus.Maintenance) ? StoragePoolStatus.Maintenance
: (masterDomain.getStatus() != null && masterDomain.getStatus() == StorageDomainStatus.Active) ? StoragePoolStatus.Up
: StoragePoolStatus.NonResponsive;
if (newStatus != getStoragePool().getStatus()) {
getCompensationContext().snapshotEntity(getStoragePool());
getStoragePool().setStatus(newStatus);
StoragePool poolFromDb = storagePoolDao.get(getStoragePool().getId());
if ((getStoragePool().getSpmVdsId() == null && poolFromDb.getSpmVdsId() != null)
|| (getStoragePool().getSpmVdsId() != null && !getStoragePool().getSpmVdsId().equals(
poolFromDb.getSpmVdsId()))) {
getStoragePool().setSpmVdsId(poolFromDb.getSpmVdsId());
}
if (getStoragePool().getStatus() == StoragePoolStatus.Uninitialized) {
getStoragePool().setSpmVdsId(null);
}
executeInScope(TransactionScopeOption.Required, () -> {
storagePoolDao.update(getStoragePool());
return null;
});
StoragePoolStatusHandler.poolStatusChanged(getStoragePool().getId(), getStoragePool().getStatus());
}
}
protected void castDiskImagesToUnregisteredDisks(List<DiskImage> disksFromStorage, Guid storageDomainId) {
for (DiskImage disk : disksFromStorage) {
disk.getStorageIds().set(0, storageDomainId);
UnregisteredDisk unregisteredDisk = new UnregisteredDisk(disk);
unregisteredDisks.add(unregisteredDisk);
}
}
protected void registerAllOvfDisks(List<DiskImage> ovfStoreDiskImages, Guid storageDomainId) {
for (DiskImage ovfStoreDiskImage : ovfStoreDiskImages) {
ovfStoreDiskImage.setDiskAlias(OvfInfoFileConstants.OvfStoreDescriptionLabel);
ovfStoreDiskImage.setDiskDescription(OvfInfoFileConstants.OvfStoreDescriptionLabel);
ovfStoreDiskImage.setShareable(true);
ovfStoreDiskImage.setContentType(DiskContentType.OVF_STORE);
RegisterDiskParameters registerDiskParams =
new RegisterDiskParameters(ovfStoreDiskImage, storageDomainId);
boolean registerDiskResult = runInternalAction(VdcActionType.RegisterDisk, registerDiskParams,
cloneContext()).getSucceeded();
log.info("Register new floating OVF_STORE disk with disk id '{}' for storage domain '{}' has {}",
ovfStoreDiskImage.getId(),
storageDomainId,
registerDiskResult ? "succeeded" : "failed");
if (registerDiskResult) {
addOvfStoreDiskToDomain(ovfStoreDiskImage);
}
}
}
/**
* Register all the OVF_STORE disks as floating disks in the engine.
*/
private void addOvfStoreDiskToDomain(DiskImage ovfDisk) {
// Setting OVF_STORE disk to be outdated so it will be updated.
StorageDomainOvfInfo storageDomainOvfInfo =
new StorageDomainOvfInfo(getStorageDomainId(),
null,
ovfDisk.getId(),
StorageDomainOvfInfoStatus.OUTDATED,
null);
storageDomainOvfInfoDao.save(storageDomainOvfInfo);
}
protected void updateStorageDomainFormatIfNeeded(StorageDomain domain) {
final StorageDomainType sdType = domain.getStorageDomainType();
if (!sdType.isDataDomain()) {
log.debug("Skipping format update for domain '{}' (type '{}')",
getStorageDomain().getId(), sdType);
return;
}
final StorageDomainStatic storageStaticData = domain.getStorageStaticData();
final StorageFormatType targetFormat = getStoragePool().getStoragePoolFormatType();
if (storageStaticData.getStorageFormat() != targetFormat) {
log.info("Updating storage domain '{}' (type '{}') to format '{}'",
getStorageDomain().getId(), sdType, targetFormat);
storageStaticData.setStorageFormat(targetFormat);
storageDomainStaticDao.update(storageStaticData);
} else {
log.debug("Skipping format update for domain '{}' format is '{}'",
getStorageDomain().getId(), storageStaticData.getStorageFormat());
}
}
protected List<DiskImage> getAllOVFDisks(Guid storageDomainId, Guid storagePoolId) {
// Null ovfDisks indicating that the ovfDisks list was not set and also that the unregisteredDisks were not
// fetched yet.
if (ovfDisks == null) {
ovfDisks = new ArrayList<>();
// Get all unregistered disks.
List<DiskImage> disksFromStorage = getBackend().runInternalQuery(VdcQueryType.GetUnregisteredDisks,
new GetUnregisteredDisksQueryParameters(storageDomainId,
storagePoolId)).getReturnValue();
if (disksFromStorage == null) {
log.error("An error occurred while fetching unregistered disks from Storage Domain id '{}'",
storageDomainId);
return ovfDisks;
} else {
castDiskImagesToUnregisteredDisks(disksFromStorage, storageDomainId);
}
for (Disk disk : disksFromStorage) {
DiskImage ovfStoreDisk = (DiskImage) disk;
String diskDescription = ovfStoreDisk.getDescription();
if (diskDescription.contains(OvfInfoFileConstants.OvfStoreDescriptionLabel)) {
Map<String, Object> diskDescriptionMap;
try {
diskDescriptionMap = JsonHelper.jsonToMap(diskDescription);
} catch (IOException e) {
log.warn("Exception while generating json containing ovf store info: {}", e.getMessage());
log.debug("Exception", e);
continue;
}
// The purpose of this check is to verify that it's an OVF store with data related to the Storage
// Domain.
if (!isDomainExistsInDiskDescription(diskDescriptionMap, storageDomainId)) {
log.warn("The disk description does not contain the storage domain id '{}'", storageDomainId);
continue;
}
ovfDisks.add(ovfStoreDisk);
}
}
}
return ovfDisks;
}
/**
* Returns the best match for OVF disk from all the disks. If no OVF disk was found, it returns null for disk and
* size 0. If there are OVF disks, we first match the updated ones, and from them we retrieve the one which was last
* updated.
*
* @param ovfStoreDiskImages
* - A list of OVF_STORE disks
* @return A Pair which contains the best OVF disk to retrieve data from and its size.
*/
private Pair<DiskImage, Long> getLatestOVFDisk(List<DiskImage> ovfStoreDiskImages) {
Date foundOvfDiskUpdateDate = new Date();
boolean isFoundOvfDiskUpdated = false;
Long size = 0L;
Disk ovfDisk = null;
for (DiskImage ovfStoreDisk : ovfStoreDiskImages) {
boolean isBetterOvfDiskFound = false;
Map<String, Object> diskDescriptionMap;
try {
diskDescriptionMap = JsonHelper.jsonToMap(ovfStoreDisk.getDescription());
} catch (IOException e) {
log.warn("Exception while generating json containing ovf store info: {}", e.getMessage());
log.debug("Exception", e);
continue;
}
boolean isUpdated = Boolean.valueOf(diskDescriptionMap.get(OvfInfoFileConstants.IsUpdated).toString());
Date date = getDateFromDiskDescription(diskDescriptionMap);
if (date == null) {
continue;
}
if (isFoundOvfDiskUpdated && !isUpdated) {
continue;
}
if ((isUpdated && !isFoundOvfDiskUpdated) || date.after(foundOvfDiskUpdateDate)) {
isBetterOvfDiskFound = true;
}
if (isBetterOvfDiskFound) {
isFoundOvfDiskUpdated = isUpdated;
foundOvfDiskUpdateDate = date;
ovfDisk = ovfStoreDisk;
size = Long.valueOf(diskDescriptionMap.get(OvfInfoFileConstants.Size).toString());
}
}
return new Pair<>((DiskImage)ovfDisk, size);
}
protected List<OvfEntityData> getEntitiesFromStorageOvfDisk(Guid storageDomainId, Guid storagePoolId) {
// Initialize a new ArrayList with all the ovfDisks in the specified Storage Domain,
// so the entities can be removed from the list every time we register the latest OVF disk and we can keep the
// ovfDisks cache list updated.
List<DiskImage> ovfStoreDiskImages = new ArrayList<>(getAllOVFDisks(storageDomainId, storagePoolId));
if (!ovfStoreDiskImages.isEmpty()) {
while (!ovfStoreDiskImages.isEmpty()) {
Pair<DiskImage, Long> ovfDiskAndSize = getLatestOVFDisk(ovfStoreDiskImages);
DiskImage ovfDisk = ovfDiskAndSize.getFirst();
if (ovfDisk != null) {
try {
VdcReturnValueBase vdcReturnValue = runInternalAction(VdcActionType.RetrieveImageData,
new RetrieveImageDataParameters(getParameters().getStoragePoolId(),
storageDomainId,
ovfDisk.getId(),
ovfDisk.getImage().getId(),
ovfDiskAndSize.getSecond()), cloneContextAndDetachFromParent());
getReturnValue().getVdsmTaskIdList().addAll(vdcReturnValue.getInternalVdsmTaskIdList());
if (vdcReturnValue.getSucceeded()) {
List<OvfEntityData> returnedMap =
OvfUtils.getOvfEntities(vdcReturnValue.getActionReturnValue(),
unregisteredDisks,
storageDomainId);
return returnedMap;
} else {
log.error("Image data could not be retrieved for disk id '{}' in storage domain id '{}'",
ovfDisk.getId(),
storageDomainId);
}
} catch (RuntimeException e) {
// We are catching RuntimeException, since the call for OvfUtils.getOvfEntities will throw
// a RuntimeException if there is a problem to untar the file.
log.error("Image data could not be retrieved for disk id '{}' in storage domain id '{}': {}",
ovfDisk.getId(),
storageDomainId,
e.getMessage());
log.debug("Exception", e);
}
ovfStoreDiskImages.remove(ovfDisk);
} else {
log.error("Couldn't find additional ovf store to retrieve the ovf data from in storage domain '{}'",
storageDomainId);
break;
}
}
AuditLogable logable = new AuditLogableImpl();
logable.setStorageDomainId(storageDomainId);
logable.setStorageDomainName(storageDomainStaticDao.get(storageDomainId).getName());
auditLogDirector.log(logable, AuditLogType.RETRIEVE_OVF_STORE_FAILED);
} else {
log.warn("There are no OVF_STORE disks on storage domain id {}", storageDomainId);
}
return new ArrayList<>();
}
protected void initUnregisteredDisksToDB(Guid storageDomainId) {
List<DiskImage> existingDisks = diskImageDao.getAllForStorageDomain(storageDomainId);
for (Object unregisteredDiskObj : unregisteredDisks) {
UnregisteredDisk unregisteredDisk = (UnregisteredDisk) unregisteredDiskObj;
if (existingDisks.stream().anyMatch(diskImage -> diskImage.getId().equals(unregisteredDisk.getId()))) {
log.info("Disk {} with id '{}' already exists in the engine, therefore will not be " +
"part of the unregistered disks.",
unregisteredDisk.getDiskAlias(),
unregisteredDisk.getId());
continue;
}
unregisteredDisksDao.removeUnregisteredDisk(unregisteredDisk.getId(), storageDomainId);
unregisteredDisksDao.saveUnregisteredDisk(unregisteredDisk);
log.info("Adding unregistered disk of disk id '{}' and disk alias '{}'",
unregisteredDisk.getId(),
unregisteredDisk.getDiskAlias());
}
}
protected boolean checkStoragePoolNameLengthValid() {
boolean result = true;
if (getStoragePool().getName().length() > Config.<Integer>getValue(ConfigValues.StoragePoolNameSizeLimit)) {
result = false;
addValidationMessage(EngineMessage.ACTION_TYPE_FAILED_NAME_LENGTH_IS_TOO_LONG);
}
return result;
}
private Date getDateFromDiskDescription(Map<String, Object> map) {
try {
Object lastUpdate = map.get(OvfInfoFileConstants.LastUpdated);
if (lastUpdate != null) {
return new SimpleDateFormat(OvfParser.formatStrFromDiskDescription).parse(lastUpdate.toString());
} else {
log.info("LastUpdate Date is not initialized in the OVF_STORE disk.");
}
} catch (java.text.ParseException e) {
log.error("LastUpdate Date could not be parsed from disk description: {}", e.getMessage());
log.debug("Exception", e);
}
return null;
}
protected void runSynchronizeOperation(ActivateDeactivateSingleAsyncOperationFactory factory,
Object... addionalParams) {
List<VDS> allRunningVdsInPool = getAllRunningVdssInPool();
ArrayList<Object> parameters = initAsyncOperationParameters(allRunningVdsInPool);
if (addionalParams.length > 0) {
parameters.addAll(Arrays.asList(addionalParams));
}
SyncronizeNumberOfAsyncOperations sync = new SyncronizeNumberOfAsyncOperations(allRunningVdsInPool.size(),
parameters, factory);
sync.execute();
}
private ArrayList<Object> initAsyncOperationParameters(List<VDS> allRunningVdsInPool) {
ArrayList<Object> parameters = new ArrayList<>();
parameters.add(allRunningVdsInPool);
parameters.add(getStorageDomain());
parameters.add(getStoragePool());
return parameters;
}
private boolean isDomainExistsInDiskDescription(Map<String, Object> map, Guid storageDomainId) {
return Objects.toString(map.get(OvfInfoFileConstants.Domains), "").contains(storageDomainId.toString());
}
protected String getJsonDiskDescription(Disk disk) {
try {
return MetadataDiskDescriptionHandler.getInstance().generateJsonDiskDescription(disk);
} catch (IOException e) {
log.error("Exception while generating json for disk. ERROR: '{}'", e);
return StringUtils.EMPTY;
}
}
@Override
public List<PermissionSubject> getPermissionCheckSubjects() {
return Collections.singletonList(new PermissionSubject(getStoragePoolId(),
VdcObjectType.StoragePool, getActionType().getActionGroup()));
}
@Override
public Map<String, String> getJobMessageProperties() {
if (jobProperties == null) {
jobProperties = super.getJobMessageProperties();
jobProperties.put(VdcObjectType.StoragePool.name().toLowerCase(), getStoragePoolName());
jobProperties.put(VdcObjectType.Storage.name().toLowerCase(), getStorageDomainName());
jobProperties.put(VdcObjectType.VDS.name().toLowerCase(), getVdsName());
}
return jobProperties;
}
/* Overidden Dao access methods, for easier testing */
@Override
public BackendInternal getBackend() {
return super.getBackend();
}
/* Transaction methods */
protected void executeInScope(TransactionScopeOption scope, TransactionMethod<?> code) {
TransactionSupport.executeInScope(scope, code);
}
@Override
public VDSReturnValue runVdsCommand(VDSCommandType commandType, VDSParametersBase parameters) throws
EngineException {
return super.runVdsCommand(commandType, parameters);
}
public CinderBroker getCinderBroker() {
if (cinderBroker == null) {
cinderBroker = new CinderBroker(getStorageDomainId(), getReturnValue().getExecuteFailedMessages());
}
return cinderBroker;
}
protected void resetOvfStoreAndUnregisteredDisks() {
ovfDisks = null;
unregisteredDisks = new ArrayList<>();
}
}