/**
* Copyright (C) 2010 Cloud.com, Inc. All rights reserved.
*
* This software is licensed under the GNU General Public License v3 or later.
*
* It is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.cloud.storage.allocator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.agent.api.to.DiskCharacteristicsTO;
import com.cloud.configuration.dao.ConfigurationDao;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.server.StatsCollector;
import com.cloud.service.ServiceOffering;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolVO;
import com.cloud.storage.StorageStats;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.storage.Volume.VolumeType;
import com.cloud.storage.dao.StoragePoolDao;
import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.storage.dao.VMTemplatePoolDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.template.TemplateManager;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.component.Inject;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
public abstract class AbstractStoragePoolAllocator extends AdapterBase implements StoragePoolAllocator {
private static final Logger s_logger = Logger.getLogger(FirstFitStoragePoolAllocator.class);
@Inject TemplateManager _tmpltMgr;
@Inject StorageManager _storageMgr;
@Inject StoragePoolDao _storagePoolDao;
@Inject VMTemplateHostDao _templateHostDao;
@Inject VMTemplatePoolDao _templatePoolDao;
@Inject VMTemplateDao _templateDao;
@Inject VolumeDao _volumeDao;
@Inject StoragePoolHostDao _poolHostDao;
@Inject ConfigurationDao _configDao;
int _storageOverprovisioningFactor;
long _extraBytesPerVolume = 0;
Random _rand;
boolean _dontMatter;
double _storageUsedThreshold = 1.0d;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
ComponentLocator locator = ComponentLocator.getCurrentLocator();
Map<String, String> configs = _configDao.getConfiguration(null, params);
String globalStorageOverprovisioningFactor = configs.get("storage.overprovisioning.factor");
_storageOverprovisioningFactor = NumbersUtil.parseInt(globalStorageOverprovisioningFactor, 2);
_extraBytesPerVolume = 0;
String storageUsedThreshold = configs.get("storage.capacity.threshold");
if (storageUsedThreshold != null) {
_storageUsedThreshold = Double.parseDouble(storageUsedThreshold);
}
_rand = new Random(System.currentTimeMillis());
_dontMatter = Boolean.parseBoolean(configs.get("storage.overwrite.provisioning"));
return true;
}
abstract boolean allocatorIsCorrectType(DiskCharacteristicsTO dskCh, VMInstanceVO vm, ServiceOffering offering);
protected boolean templateAvailable(long templateId, long poolId) {
VMTemplateStorageResourceAssoc thvo = _templatePoolDao.findByPoolTemplate(poolId, templateId);
if (thvo != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Template id : " + templateId + " status : " + thvo.getDownloadState().toString());
}
return (thvo.getDownloadState()==Status.DOWNLOADED);
} else {
return false;
}
}
protected boolean localStorageAllocationNeeded(DiskCharacteristicsTO dskCh, VMInstanceVO vm, ServiceOffering offering) {
if (vm == null) {
// We are finding a pool for a volume, so we need a shared storage allocator
return false;
} else if (vm.getType() == VirtualMachine.Type.User) {
// We are finding a pool for a UserVM, so check the service offering to see if we should use local storage
return offering.getUseLocalStorage();
} else {
// We are finding a pool for a DomR or ConsoleProxy, so check the configuration table to see if we should use local storage
String configValue = _configDao.getValue("system.vm.use.local.storage");
return Boolean.parseBoolean(configValue);
}
}
protected boolean poolIsCorrectType(DiskCharacteristicsTO dskCh, StoragePool pool, VMInstanceVO vm, ServiceOffering offering) {
boolean localStorageAllocationNeeded = localStorageAllocationNeeded(dskCh, vm, offering);
return ((!localStorageAllocationNeeded && pool.getPoolType().isShared()) || (localStorageAllocationNeeded && !pool.getPoolType().isShared()));
}
protected boolean checkPool(Set<? extends StoragePool> avoid, StoragePoolVO pool, DiskCharacteristicsTO dskCh, VMTemplateVO template, List<VMTemplateStoragePoolVO> templatesInPool, ServiceOffering offering,
VMInstanceVO vm, StatsCollector sc) {
if (avoid.contains(pool)) {
return false;
}
if(dskCh.getType().equals(VolumeType.ROOT) && pool.getPoolType().equals(StoragePoolType.Iscsi)){
return false;
}
// Check that the pool type is correct
if (!poolIsCorrectType(dskCh, pool, vm, offering)) {
return false;
}
// check the used size against the total size, skip this host if it's greater than the configured
// capacity check "storage.capacity.threshold"
if (sc != null) {
long totalSize = pool.getCapacityBytes();
StorageStats stats = sc.getStorageStats(pool.getId());
if (stats != null) {
double usedPercentage = ((double)stats.getByteUsed() / (double)totalSize);
if (s_logger.isDebugEnabled()) {
s_logger.debug("Attempting to look for pool " + pool.getId() + " for storage, totalSize: " + pool.getCapacityBytes() + ", usedBytes: " + stats.getByteUsed() + ", usedPct: " + usedPercentage + ", threshold: " + _storageUsedThreshold);
}
if (usedPercentage >= _storageUsedThreshold) {
return false;
}
}
}
Pair<Long, Long> sizes = _volumeDao.getCountAndTotalByPool(pool.getId());
long totalAllocatedSize = sizes.second() + (long)sizes.first() * _extraBytesPerVolume;
// Iterate through all templates on this storage pool
boolean tmpinstalled = false;
List<VMTemplateStoragePoolVO> templatePoolVOs;
if (templatesInPool != null) {
templatePoolVOs = templatesInPool;
} else {
templatePoolVOs = _templatePoolDao.listByPoolId(pool.getId());
}
for (VMTemplateStoragePoolVO templatePoolVO : templatePoolVOs) {
VMTemplateVO templateInPool = _templateDao.findById(templatePoolVO.getTemplateId());
if ((template != null) && !tmpinstalled && (templateInPool.getId() == template.getId())) {
tmpinstalled = true;
}
long templateSize = templatePoolVO.getTemplateSize();
totalAllocatedSize += templateSize + _extraBytesPerVolume;
}
if (template != null && !tmpinstalled ) {
// If the template that was passed into this allocator is not installed in the storage pool
// should add template size
// dskCh.getSize() should be template virtualsize
totalAllocatedSize += dskCh.getSize() + _extraBytesPerVolume;
}
long askingSize = dskCh.getSize();
int storageOverprovisioningFactor = 1;
if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) {
storageOverprovisioningFactor = _storageOverprovisioningFactor;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Attempting to look for pool " + pool.getId() + " for storage, maxSize : " + (pool.getCapacityBytes() * storageOverprovisioningFactor) + ", totalSize : " + totalAllocatedSize + ", askingSize : " + askingSize);
}
if ((pool.getCapacityBytes() * storageOverprovisioningFactor) < (totalAllocatedSize + askingSize)) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Found pool " + pool.getId() + " for storage, maxSize : " + (pool.getCapacityBytes() * storageOverprovisioningFactor) + ", totalSize : " + totalAllocatedSize + ", askingSize : " + askingSize);
}
return false;
}
return true;
}
@Override
public String chooseStorageIp(VirtualMachine vm, Host host, Host storage) {
return storage.getStorageIpAddress();
}
}