Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public interface DeploymentClusterPlanner extends DeploymentPlanner {
"vm.allocation.algorithm",
"Advanced",
"random",
"Order in which hosts within a cluster will be considered for VM/volume allocation. The value can be 'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit', or 'firstfitleastconsumed'.",
"Order in which hosts within a cluster will be considered for VM allocation. The value can be 'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit', or 'firstfitleastconsumed'.",
true,
ConfigKey.Scope.Global, null, null, null, null, null,
ConfigKey.Kind.Select,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ public interface VolumeOrchestrationService {
"The maximum size for a volume (in GiB).",
true);

ConfigKey<String> VolumeAllocationAlgorithm = new ConfigKey<>(
String.class,
"volume.allocation.algorithm",
"Advanced",
"random",
"Order in which storage pool within a cluster will be considered for volume allocation. The value can be 'random', 'firstfit', 'userdispersing', 'userconcentratedpod_random', 'userconcentratedpod_firstfit', or 'firstfitleastconsumed'.",
true,
ConfigKey.Scope.Global, null, null, null, null, null,
ConfigKey.Kind.Select,
"random,firstfit,userdispersing,userconcentratedpod_random,userconcentratedpod_firstfit,firstfitleastconsumed");

VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType)
throws ConcurrentOperationException, StorageUnavailableException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;

import com.cloud.deploy.DeploymentClusterPlanner;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.VMTemplateVO;
Expand Down Expand Up @@ -73,6 +74,7 @@
import org.apache.cloudstack.framework.config.ConfigDepot;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.jobs.AsyncJobManager;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.apache.cloudstack.resourcedetail.DiskOfferingDetailVO;
Expand Down Expand Up @@ -257,6 +259,10 @@
StoragePoolHostDao storagePoolHostDao;
@Inject
DiskOfferingDao diskOfferingDao;
@Inject
ConfigDepot configDepot;
@Inject
ConfigurationDao configurationDao;

@Inject
protected SnapshotHelper snapshotHelper;
Expand Down Expand Up @@ -2018,7 +2024,9 @@

@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {RecreatableSystemVmEnabled, MaxVolumeSize, StorageHAMigrationEnabled, StorageMigrationEnabled, CustomDiskOfferingMaxSize, CustomDiskOfferingMinSize, VolumeUrlCheck};
return new ConfigKey<?>[] {

Check warning on line 2027 in engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

View check run for this annotation

Codecov / codecov/patch

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java#L2027

Added line #L2027 was not covered by tests
RecreatableSystemVmEnabled, MaxVolumeSize, StorageHAMigrationEnabled, StorageMigrationEnabled,
CustomDiskOfferingMaxSize, CustomDiskOfferingMinSize, VolumeUrlCheck, VolumeAllocationAlgorithm};
}

@Override
Expand All @@ -2031,6 +2039,18 @@
return true;
}

@Override
public boolean start() {

Check warning on line 2043 in engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

View check run for this annotation

Codecov / codecov/patch

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java#L2043

Added line #L2043 was not covered by tests
if (configDepot.isNewConfig(VolumeAllocationAlgorithm)) {
String vmAllocationAlgo = DeploymentClusterPlanner.VmAllocationAlgorithm.value();

Check warning on line 2045 in engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

View check run for this annotation

Codecov / codecov/patch

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java#L2045

Added line #L2045 was not covered by tests
if (com.cloud.utils.StringUtils.isNotEmpty(vmAllocationAlgo) && !VolumeAllocationAlgorithm.defaultValue().equalsIgnoreCase(vmAllocationAlgo)) {
logger.debug("Updating value for configuration: {} to {}", VolumeAllocationAlgorithm.key(), vmAllocationAlgo);
configurationDao.update(VolumeAllocationAlgorithm.key(), vmAllocationAlgo);

Check warning on line 2048 in engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

View check run for this annotation

Codecov / codecov/patch

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java#L2047-L2048

Added lines #L2047 - L2048 were not covered by tests
}
}
return true;
}

Check warning on line 2052 in engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java

View check run for this annotation

Codecov / codecov/patch

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java#L2051-L2052

Added lines #L2051 - L2052 were not covered by tests

private void cleanupVolumeDuringAttachFailure(Long volumeId, Long vmId) {
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ List<SummedCapacity> listCapacitiesGroupedByLevelAndType(Integer capacityType, L

float findClusterConsumption(Long clusterId, short capacityType, long computeRequested);

List<Long> orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityType);
Pair<List<Long>, Map<Long, Double>> orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1028,10 +1028,11 @@
}

@Override
public List<Long> orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityTypeForOrdering){
public Pair<List<Long>, Map<Long, Double>> orderHostsByFreeCapacity(Long zoneId, Long clusterId, short capacityTypeForOrdering){

Check warning on line 1031 in engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java#L1031

Added line #L1031 was not covered by tests
TransactionLegacy txn = TransactionLegacy.currentTxn();
PreparedStatement pstmt = null;
List<Long> result = new ArrayList<Long>();
List<Long> result = new ArrayList<>();
Map<Long, Double> hostCapacityMap = new HashMap<>();

Check warning on line 1035 in engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java#L1034-L1035

Added lines #L1034 - L1035 were not covered by tests
StringBuilder sql = new StringBuilder(ORDER_HOSTS_BY_FREE_CAPACITY_PART1);
if (zoneId != null) {
sql.append(" AND data_center_id = ?");
Expand All @@ -1054,9 +1055,11 @@

ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
result.add(rs.getLong(1));
Long hostId = rs.getLong(1);
result.add(hostId);
hostCapacityMap.put(hostId, rs.getDouble(2));

Check warning on line 1060 in engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java#L1058-L1060

Added lines #L1058 - L1060 were not covered by tests
}
return result;
return new Pair<>(result, hostCapacityMap);

Check warning on line 1062 in engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java

View check run for this annotation

Codecov / codecov/patch

engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java#L1062

Added line #L1062 was not covered by tests
} catch (SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + sql, e);
} catch (Throwable e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,59 +16,63 @@
// under the License.
package org.apache.cloudstack.storage.allocator;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.naming.ConfigurationException;

import com.cloud.api.query.dao.StoragePoolJoinDao;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.storage.ScopeType;
import com.cloud.storage.StoragePoolStatus;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.collections.CollectionUtils;

import com.cloud.utils.Pair;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;

import com.cloud.capacity.Capacity;
import com.cloud.capacity.dao.CapacityDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.ScopeType;
import com.cloud.storage.Storage;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolStatus;
import com.cloud.storage.StorageUtil;
import com.cloud.storage.Volume;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.Account;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.AdapterBase;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachineProfile;

import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;

import org.apache.commons.collections.CollectionUtils;

import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.math.BigDecimal;
import java.security.SecureRandom;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public abstract class AbstractStoragePoolAllocator extends AdapterBase implements StoragePoolAllocator {

protected BigDecimal storageOverprovisioningFactor = new BigDecimal(1);
protected String allocationAlgorithm = "random";
protected long extraBytesPerVolume = 0;
static DecimalFormat decimalFormat = new DecimalFormat("#.##");
@Inject protected DataStoreManager dataStoreMgr;
@Inject protected PrimaryDataStoreDao storagePoolDao;
@Inject protected VolumeDao volumeDao;
Expand All @@ -95,10 +99,6 @@
String globalStorageOverprovisioningFactor = configs.get("storage.overprovisioning.factor");
storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat(globalStorageOverprovisioningFactor, 2.0f));
extraBytesPerVolume = 0;
String allocationAlgorithm = configs.get("vm.allocation.algorithm");
if (allocationAlgorithm != null) {
this.allocationAlgorithm = allocationAlgorithm;
}
return true;
}
return false;
Expand Down Expand Up @@ -142,12 +142,16 @@
capacityType, storagePool.getName(), storagePool.getUuid(), storageType
));

List<Long> poolIdsByCapacity = capacityDao.orderHostsByFreeCapacity(zoneId, clusterId, capacityType);

logger.debug(String.format("List of pools in descending order of available capacity [%s].", poolIdsByCapacity));
Pair<List<Long>, Map<Long, Double>> result = capacityDao.orderHostsByFreeCapacity(zoneId, clusterId, capacityType);
List<Long> poolIdsByCapacity = result.first();
Map<Long, String> sortedHostByCapacity = result.second().entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(Map.Entry::getKey, entry -> decimalFormat.format(entry.getValue() * 100) + "%", (e1, e2) -> e1, LinkedHashMap::new));
logger.debug("List of pools in descending order of hostId: [{}] available capacity (percentage): {}",

Check warning on line 151 in engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java

View check run for this annotation

Codecov / codecov/patch

engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java#L145-L151

Added lines #L145 - L151 were not covered by tests
poolIdsByCapacity, sortedHostByCapacity);


//now filter the given list of Pools by this ordered list
// now filter the given list of Pools by this ordered list
Map<Long, StoragePool> poolMap = new HashMap<>();
for (StoragePool pool : pools) {
poolMap.put(pool.getId(), pool);
Expand Down Expand Up @@ -227,16 +231,16 @@
}

List<StoragePool> reorderStoragePoolsBasedOnAlgorithm(List<StoragePool> pools, DeploymentPlan plan, Account account) {
logger.debug(String.format("Using allocation algorithm [%s] to reorder pools.", allocationAlgorithm));

if (allocationAlgorithm.equals("random") || allocationAlgorithm.equals("userconcentratedpod_random") || (account == null)) {
String volumeAllocationAlgorithm = VolumeOrchestrationService.VolumeAllocationAlgorithm.value();
logger.debug("Using volume allocation algorithm {} to reorder pools.", volumeAllocationAlgorithm);
if (volumeAllocationAlgorithm.equals("random") || volumeAllocationAlgorithm.equals("userconcentratedpod_random") || (account == null)) {
reorderRandomPools(pools);
} else if (StringUtils.equalsAny(allocationAlgorithm, "userdispersing", "firstfitleastconsumed")) {
} else if (StringUtils.equalsAny(volumeAllocationAlgorithm, "userdispersing", "firstfitleastconsumed")) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Using reordering algorithm [%s]", allocationAlgorithm));
logger.trace("Using reordering algorithm {}", volumeAllocationAlgorithm);

Check warning on line 240 in engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java

View check run for this annotation

Codecov / codecov/patch

engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java#L240

Added line #L240 was not covered by tests
}

if (allocationAlgorithm.equals("userdispersing")) {
if (volumeAllocationAlgorithm.equals("userdispersing")) {
pools = reorderPoolsByNumberOfVolumes(plan, pools, account);
} else {
pools = reorderPoolsByCapacity(plan, pools);
Expand All @@ -248,7 +252,7 @@
void reorderRandomPools(List<StoragePool> pools) {
StorageUtil.traceLogStoragePools(pools, logger, "pools to choose from: ");
if (logger.isTraceEnabled()) {
logger.trace(String.format("Shuffle this so that we don't check the pools in the same order. Algorithm == '%s' (or no account?)", allocationAlgorithm));
logger.trace("Shuffle this so that we don't check the pools in the same order. Algorithm == 'random' (or no account?)");

Check warning on line 255 in engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java

View check run for this annotation

Codecov / codecov/patch

engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java#L255

Added line #L255 was not covered by tests
}
StorageUtil.traceLogStoragePools(pools, logger, "pools to shuffle: ");
Collections.shuffle(pools, secureRandom);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,27 @@
// under the License.
package org.apache.cloudstack.storage.allocator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;
import javax.naming.ConfigurationException;

import com.cloud.storage.VolumeApiServiceImpl;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.springframework.stereotype.Component;

import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.ScopeType;
import com.cloud.storage.StoragePool;
import com.cloud.storage.VolumeApiServiceImpl;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.vm.DiskProfile;
import com.cloud.vm.VirtualMachineProfile;

import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;

import org.springframework.stereotype.Component;

import javax.inject.Inject;
import javax.naming.ConfigurationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Component
public class ClusterScopeStoragePoolAllocator extends AbstractStoragePoolAllocator {

Expand Down Expand Up @@ -116,14 +116,6 @@ protected List<StoragePool> select(DiskProfile dskCh, VirtualMachineProfile vmPr
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);

if (configDao != null) {
Map<String, String> configs = configDao.getConfiguration(params);
String allocationAlgorithm = configs.get("vm.allocation.algorithm");
if (allocationAlgorithm != null) {
this.allocationAlgorithm = allocationAlgorithm;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.inject.Inject;

import com.cloud.utils.Pair;
import org.springframework.stereotype.Component;

import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
Expand Down Expand Up @@ -122,9 +126,16 @@
return null;
}

List<Long> poolIdsByCapacity = capacityDao.orderHostsByFreeCapacity(zoneId, null, capacityType);
Pair<List<Long>, Map<Long, Double>> result = capacityDao.orderHostsByFreeCapacity(zoneId, null, capacityType);
List<Long> poolIdsByCapacity = result.first();
Map<Long, String> sortedHostByCapacity = result.second().entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.collect(Collectors.toMap(Map.Entry::getKey, entry -> decimalFormat.format(entry.getValue() * 100) + "%",
(e1, e2) -> e1, LinkedHashMap::new));

Check warning on line 135 in engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java

View check run for this annotation

Codecov / codecov/patch

engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java#L129-L135

Added lines #L129 - L135 were not covered by tests
if (logger.isDebugEnabled()) {
logger.debug("List of zone-wide storage pools in descending order of free capacity: "+ poolIdsByCapacity);
logger.debug("List of zone-wide storage pools: [{}] in descending order of free capacity (percentage): {}",

Check warning on line 137 in engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java

View check run for this annotation

Codecov / codecov/patch

engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/ZoneWideStoragePoolAllocator.java#L137

Added line #L137 was not covered by tests
poolIdsByCapacity, sortedHostByCapacity);
}

//now filter the given list of Pools by this ordered list
Expand Down
Loading
Loading