mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Added support for system VMs to make use of managed storage
This commit is contained in:
parent
c9e14c9f08
commit
088ffa0842
@ -490,7 +490,10 @@ public class SolidFirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
|
|||||||
} else if (dataObject.getType() == DataObjectType.TEMPLATE) {
|
} else if (dataObject.getType() == DataObjectType.TEMPLATE) {
|
||||||
TemplateInfo templateInfo = (TemplateInfo)dataObject;
|
TemplateInfo templateInfo = (TemplateInfo)dataObject;
|
||||||
|
|
||||||
volumeSize = (long)(templateInfo.getSize() + templateInfo.getSize() * (LOWEST_HYPERVISOR_SNAPSHOT_RESERVE / 100f));
|
// TemplateInfo sometimes has a size equal to null.
|
||||||
|
long templateSize = templateInfo.getSize() != null ? templateInfo.getSize() : 0;
|
||||||
|
|
||||||
|
volumeSize = (long)(templateSize + templateSize * (LOWEST_HYPERVISOR_SNAPSHOT_RESERVE / 100f));
|
||||||
}
|
}
|
||||||
|
|
||||||
return volumeSize;
|
return volumeSize;
|
||||||
|
|||||||
@ -21,6 +21,7 @@ package org.apache.cloudstack.storage.datastore.lifecycle;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -40,7 +41,6 @@ import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
|
|||||||
|
|
||||||
import com.cloud.agent.api.StoragePoolInfo;
|
import com.cloud.agent.api.StoragePoolInfo;
|
||||||
import com.cloud.capacity.CapacityManager;
|
import com.cloud.capacity.CapacityManager;
|
||||||
import com.cloud.dc.DataCenterVO;
|
|
||||||
import com.cloud.dc.dao.DataCenterDao;
|
import com.cloud.dc.dao.DataCenterDao;
|
||||||
import com.cloud.host.HostVO;
|
import com.cloud.host.HostVO;
|
||||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||||
@ -88,10 +88,6 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
String storageVip = SolidFireUtil.getStorageVip(url);
|
String storageVip = SolidFireUtil.getStorageVip(url);
|
||||||
int storagePort = SolidFireUtil.getStoragePort(url);
|
int storagePort = SolidFireUtil.getStoragePort(url);
|
||||||
|
|
||||||
DataCenterVO zone = _zoneDao.findById(zoneId);
|
|
||||||
|
|
||||||
String uuid = SolidFireUtil.PROVIDER_NAME + "_" + zone.getUuid() + "_" + storageVip;
|
|
||||||
|
|
||||||
if (capacityBytes == null || capacityBytes <= 0) {
|
if (capacityBytes == null || capacityBytes <= 0) {
|
||||||
throw new IllegalArgumentException("'capacityBytes' must be present and greater than 0.");
|
throw new IllegalArgumentException("'capacityBytes' must be present and greater than 0.");
|
||||||
}
|
}
|
||||||
@ -106,7 +102,7 @@ public class SolidFirePrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeC
|
|||||||
parameters.setPort(storagePort);
|
parameters.setPort(storagePort);
|
||||||
parameters.setPath(SolidFireUtil.getModifiedUrl(url));
|
parameters.setPath(SolidFireUtil.getModifiedUrl(url));
|
||||||
parameters.setType(StoragePoolType.Iscsi);
|
parameters.setType(StoragePoolType.Iscsi);
|
||||||
parameters.setUuid(uuid);
|
parameters.setUuid(UUID.randomUUID().toString());
|
||||||
parameters.setZoneId(zoneId);
|
parameters.setZoneId(zoneId);
|
||||||
parameters.setName(storagePoolName);
|
parameters.setName(storagePoolName);
|
||||||
parameters.setProviderName(providerName);
|
parameters.setProviderName(providerName);
|
||||||
|
|||||||
@ -1969,6 +1969,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
final String vmTypeString = cmd.getSystemVmType();
|
final String vmTypeString = cmd.getSystemVmType();
|
||||||
VirtualMachine.Type vmType = null;
|
VirtualMachine.Type vmType = null;
|
||||||
boolean allowNetworkRate = false;
|
boolean allowNetworkRate = false;
|
||||||
|
|
||||||
|
Boolean isCustomizedIops;
|
||||||
|
|
||||||
if (cmd.getIsSystem()) {
|
if (cmd.getIsSystem()) {
|
||||||
if (vmTypeString == null || VirtualMachine.Type.DomainRouter.toString().toLowerCase().equals(vmTypeString)) {
|
if (vmTypeString == null || VirtualMachine.Type.DomainRouter.toString().toLowerCase().equals(vmTypeString)) {
|
||||||
vmType = VirtualMachine.Type.DomainRouter;
|
vmType = VirtualMachine.Type.DomainRouter;
|
||||||
@ -1983,8 +1986,19 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
throw new InvalidParameterValueException("Invalid systemVmType. Supported types are: " + VirtualMachine.Type.DomainRouter + ", " + VirtualMachine.Type.ConsoleProxy
|
throw new InvalidParameterValueException("Invalid systemVmType. Supported types are: " + VirtualMachine.Type.DomainRouter + ", " + VirtualMachine.Type.ConsoleProxy
|
||||||
+ ", " + VirtualMachine.Type.SecondaryStorageVm);
|
+ ", " + VirtualMachine.Type.SecondaryStorageVm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cmd.isCustomizedIops() != null) {
|
||||||
|
throw new InvalidParameterValueException("Customized IOPS is not a valid parameter for a system VM.");
|
||||||
|
}
|
||||||
|
|
||||||
|
isCustomizedIops = false;
|
||||||
|
|
||||||
|
if (cmd.getHypervisorSnapshotReserve() != null) {
|
||||||
|
throw new InvalidParameterValueException("Hypervisor snapshot reserve is not a valid parameter for a system VM.");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
allowNetworkRate = true;
|
allowNetworkRate = true;
|
||||||
|
isCustomizedIops = cmd.isCustomizedIops();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.getNetworkRate() != null) {
|
if (cmd.getNetworkRate() != null) {
|
||||||
@ -2009,7 +2023,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
|
|||||||
|
|
||||||
return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(),
|
return createServiceOffering(userId, cmd.getIsSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(),
|
||||||
cmd.getProvisioningType(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(),
|
cmd.getProvisioningType(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainId(), cmd.getHostTag(),
|
||||||
cmd.getNetworkRate(), cmd.getDeploymentPlanner(), cmd.getDetails(), cmd.isCustomizedIops(), cmd.getMinIops(), cmd.getMaxIops(),
|
cmd.getNetworkRate(), cmd.getDeploymentPlanner(), cmd.getDetails(), isCustomizedIops, cmd.getMinIops(), cmd.getMaxIops(),
|
||||||
cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(), cmd.getHypervisorSnapshotReserve());
|
cmd.getBytesReadRate(), cmd.getBytesWriteRate(), cmd.getIopsReadRate(), cmd.getIopsWriteRate(), cmd.getHypervisorSnapshotReserve());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,7 @@ import org.apache.cloudstack.framework.async.AsyncCallFuture;
|
|||||||
import org.apache.cloudstack.framework.config.ConfigKey;
|
import org.apache.cloudstack.framework.config.ConfigKey;
|
||||||
import org.apache.cloudstack.framework.config.Configurable;
|
import org.apache.cloudstack.framework.config.Configurable;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
import org.apache.cloudstack.storage.command.DettachCommand;
|
||||||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
|
||||||
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
|
import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao;
|
||||||
@ -1113,7 +1114,16 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
cleanupSecondaryStorage(recurring);
|
cleanupSecondaryStorage(recurring);
|
||||||
|
|
||||||
List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed(new Date(System.currentTimeMillis() - ((long) StorageCleanupDelay.value() << 10)));
|
List<VolumeVO> vols = _volsDao.listVolumesToBeDestroyed(new Date(System.currentTimeMillis() - ((long) StorageCleanupDelay.value() << 10)));
|
||||||
|
|
||||||
for (VolumeVO vol : vols) {
|
for (VolumeVO vol : vols) {
|
||||||
|
try {
|
||||||
|
// If this fails, just log a warning. It's ideal if we clean up the host-side clustered file
|
||||||
|
// system, but not necessary.
|
||||||
|
handleManagedStorage(vol);
|
||||||
|
} catch (Exception e) {
|
||||||
|
s_logger.warn("Unable to destroy host-side clustered file system " + vol.getUuid(), e);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
volService.expungeVolumeAsync(volFactory.getVolume(vol.getId()));
|
volService.expungeVolumeAsync(volFactory.getVolume(vol.getId()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -1233,6 +1243,47 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleManagedStorage(Volume volume) {
|
||||||
|
Long instanceId = volume.getInstanceId();
|
||||||
|
|
||||||
|
// The idea of this "if" statement is to see if we need to remove an SR/datastore before
|
||||||
|
// deleting the volume that supports it on a SAN. This only applies for managed storage.
|
||||||
|
if (instanceId != null) {
|
||||||
|
StoragePoolVO storagePool = _storagePoolDao.findById(volume.getPoolId());
|
||||||
|
|
||||||
|
if (storagePool != null && storagePool.isManaged()) {
|
||||||
|
DataTO volTO = volFactory.getVolume(volume.getId()).getTO();
|
||||||
|
DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getPath(), volume.getVolumeType());
|
||||||
|
|
||||||
|
DettachCommand cmd = new DettachCommand(disk, null);
|
||||||
|
|
||||||
|
cmd.setManaged(true);
|
||||||
|
|
||||||
|
cmd.setStorageHost(storagePool.getHostAddress());
|
||||||
|
cmd.setStoragePort(storagePool.getPort());
|
||||||
|
|
||||||
|
cmd.set_iScsiName(volume.get_iScsiName());
|
||||||
|
|
||||||
|
VMInstanceVO vmInstanceVO = _vmInstanceDao.findById(instanceId);
|
||||||
|
|
||||||
|
Long lastHostId = vmInstanceVO.getLastHostId();
|
||||||
|
|
||||||
|
if (lastHostId != null) {
|
||||||
|
Answer answer = _agentMgr.easySend(lastHostId, cmd);
|
||||||
|
|
||||||
|
if (answer != null && answer.getResult()) {
|
||||||
|
VolumeInfo volumeInfo = volFactory.getVolume(volume.getId());
|
||||||
|
HostVO host = _hostDao.findById(lastHostId);
|
||||||
|
|
||||||
|
volService.revokeAccess(volumeInfo, host, volumeInfo.getDataStore());
|
||||||
|
} else {
|
||||||
|
s_logger.warn("Unable to remove host-side clustered file system for the following volume: " + volume.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@DB
|
@DB
|
||||||
List<Long> findAllVolumeIdInSnapshotTable(Long storeId) {
|
List<Long> findAllVolumeIdInSnapshotTable(Long storeId) {
|
||||||
String sql = "SELECT volume_id from snapshots, snapshot_store_ref WHERE snapshots.id = snapshot_store_ref.snapshot_id and store_id=? GROUP BY volume_id";
|
String sql = "SELECT volume_id from snapshots, snapshot_store_ref WHERE snapshots.id = snapshot_store_ref.snapshot_id and store_id=? GROUP BY volume_id";
|
||||||
|
|||||||
@ -394,10 +394,10 @@ class TestManagedSystemVMs(cloudstackTestCase):
|
|||||||
self.apiClient,
|
self.apiClient,
|
||||||
self.testdata[TestData.systemOfferingFailure]
|
self.testdata[TestData.systemOfferingFailure]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assert_(True, "The service offering was created, but should not have been.")
|
|
||||||
except:
|
except:
|
||||||
pass
|
return
|
||||||
|
|
||||||
|
self.assert_(False, "The service offering was created, but should not have been.")
|
||||||
|
|
||||||
def _prepare_to_use_managed_storage_for_system_vms(self):
|
def _prepare_to_use_managed_storage_for_system_vms(self):
|
||||||
self._update_system_vm_unique_name(TestManagedSystemVMs._secondary_storage_unique_name, TestManagedSystemVMs._secondary_storage_temp_unique_name)
|
self._update_system_vm_unique_name(TestManagedSystemVMs._secondary_storage_unique_name, TestManagedSystemVMs._secondary_storage_temp_unique_name)
|
||||||
|
|||||||
@ -1146,6 +1146,82 @@
|
|||||||
number: true
|
number: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
qosType: {
|
||||||
|
label: 'label.qos.type',
|
||||||
|
docID: 'helpDiskOfferingQoSType',
|
||||||
|
select: function(args) {
|
||||||
|
var items = [];
|
||||||
|
items.push({
|
||||||
|
id: '',
|
||||||
|
description: ''
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
id: 'hypervisor',
|
||||||
|
description: 'hypervisor'
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
id: 'storage',
|
||||||
|
description: 'storage'
|
||||||
|
});
|
||||||
|
args.response.success({
|
||||||
|
data: items
|
||||||
|
});
|
||||||
|
|
||||||
|
args.$select.change(function() {
|
||||||
|
var $form = $(this).closest('form');
|
||||||
|
var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]');
|
||||||
|
var $minIops = $form.find('.form-item[rel=minIops]');
|
||||||
|
var $maxIops = $form.find('.form-item[rel=maxIops]');
|
||||||
|
var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]');
|
||||||
|
var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]');
|
||||||
|
var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]');
|
||||||
|
var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]');
|
||||||
|
|
||||||
|
var qosId = $(this).val();
|
||||||
|
|
||||||
|
if (qosId == 'storage') { // Storage QoS
|
||||||
|
$diskBytesReadRate.hide();
|
||||||
|
$diskBytesWriteRate.hide();
|
||||||
|
$diskIopsReadRate.hide();
|
||||||
|
$diskIopsWriteRate.hide();
|
||||||
|
|
||||||
|
$minIops.css('display', 'inline-block');
|
||||||
|
$maxIops.css('display', 'inline-block');
|
||||||
|
} else if (qosId == 'hypervisor') { // Hypervisor Qos
|
||||||
|
$minIops.hide();
|
||||||
|
$maxIops.hide();
|
||||||
|
|
||||||
|
$diskBytesReadRate.css('display', 'inline-block');
|
||||||
|
$diskBytesWriteRate.css('display', 'inline-block');
|
||||||
|
$diskIopsReadRate.css('display', 'inline-block');
|
||||||
|
$diskIopsWriteRate.css('display', 'inline-block');
|
||||||
|
} else { // No Qos
|
||||||
|
$diskBytesReadRate.hide();
|
||||||
|
$diskBytesWriteRate.hide();
|
||||||
|
$diskIopsReadRate.hide();
|
||||||
|
$diskIopsWriteRate.hide();
|
||||||
|
$minIops.hide();
|
||||||
|
$maxIops.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
minIops: {
|
||||||
|
label: 'label.disk.iops.min',
|
||||||
|
docID: 'helpDiskOfferingDiskIopsMin',
|
||||||
|
validation: {
|
||||||
|
required: false,
|
||||||
|
number: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxIops: {
|
||||||
|
label: 'label.disk.iops.max',
|
||||||
|
docID: 'helpDiskOfferingDiskIopsMax',
|
||||||
|
validation: {
|
||||||
|
required: false,
|
||||||
|
number: true
|
||||||
|
}
|
||||||
|
},
|
||||||
diskBytesReadRate: {
|
diskBytesReadRate: {
|
||||||
label: 'label.disk.bytes.read.rate',
|
label: 'label.disk.bytes.read.rate',
|
||||||
docID: 'helpSystemOfferingDiskBytesReadRate',
|
docID: 'helpSystemOfferingDiskBytesReadRate',
|
||||||
@ -1255,26 +1331,44 @@
|
|||||||
networkrate: args.data.networkRate
|
networkrate: args.data.networkRate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args.data.qosType == 'storage') {
|
||||||
|
if (args.data.minIops != null && args.data.minIops.length > 0) {
|
||||||
|
$.extend(data, {
|
||||||
|
miniops: args.data.minIops
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.data.maxIops != null && args.data.maxIops.length > 0) {
|
||||||
|
$.extend(data, {
|
||||||
|
maxiops: args.data.maxIops
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (args.data.qosType == 'hypervisor') {
|
||||||
if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) {
|
if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) {
|
||||||
$.extend(data, {
|
$.extend(data, {
|
||||||
bytesreadrate: args.data.diskBytesReadRate
|
bytesreadrate: args.data.diskBytesReadRate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) {
|
if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) {
|
||||||
$.extend(data, {
|
$.extend(data, {
|
||||||
byteswriterate: args.data.diskBytesWriteRate
|
byteswriterate: args.data.diskBytesWriteRate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) {
|
if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) {
|
||||||
$.extend(data, {
|
$.extend(data, {
|
||||||
iopsreadrate: args.data.diskIopsReadRate
|
iopsreadrate: args.data.diskIopsReadRate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) {
|
if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) {
|
||||||
$.extend(data, {
|
$.extend(data, {
|
||||||
iopswriterate: args.data.diskIopsWriteRate
|
iopswriterate: args.data.diskIopsWriteRate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$.extend(data, {
|
$.extend(data, {
|
||||||
offerha: (args.data.offerHA == "on")
|
offerha: (args.data.offerHA == "on")
|
||||||
@ -1476,6 +1570,24 @@
|
|||||||
networkrate: {
|
networkrate: {
|
||||||
label: 'label.network.rate'
|
label: 'label.network.rate'
|
||||||
},
|
},
|
||||||
|
miniops: {
|
||||||
|
label: 'label.disk.iops.min',
|
||||||
|
converter: function(args) {
|
||||||
|
if (args > 0)
|
||||||
|
return args;
|
||||||
|
else
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
maxiops: {
|
||||||
|
label: 'label.disk.iops.max',
|
||||||
|
converter: function(args) {
|
||||||
|
if (args > 0)
|
||||||
|
return args;
|
||||||
|
else
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
},
|
||||||
diskBytesReadRate: {
|
diskBytesReadRate: {
|
||||||
label: 'label.disk.bytes.read.rate'
|
label: 'label.disk.bytes.read.rate'
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user