CLOUDSTACK-6928: fix issue disk I/O throttling not applied
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/976b3b7d Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/976b3b7d Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/976b3b7d Branch: refs/heads/4.8 Commit: 976b3b7df4fda3e51a9e32ca00729caacec3983e Parents: 7a0b37a Author: Wei Zhou <w.z...@tech.leaseweb.com> Authored: Tue Feb 9 12:55:41 2016 +0100 Committer: Wei Zhou <w.z...@tech.leaseweb.com> Committed: Thu May 19 11:26:43 2016 +0200 ---------------------------------------------------------------------- .../src/com/cloud/storage/StorageManager.java | 137 +++++++++++++++++++ .../orchestration/VolumeOrchestrator.java | 20 ++- .../kvm/storage/KVMStorageProcessor.java | 21 ++- .../src/com/cloud/storage/StorageManager.java | 128 ----------------- .../com/cloud/storage/StorageManagerImpl.java | 53 ++++++- .../com/cloud/storage/VolumeApiServiceImpl.java | 5 +- 6 files changed, 221 insertions(+), 143 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/976b3b7d/engine/components-api/src/com/cloud/storage/StorageManager.java ---------------------------------------------------------------------- diff --git a/engine/components-api/src/com/cloud/storage/StorageManager.java b/engine/components-api/src/com/cloud/storage/StorageManager.java new file mode 100644 index 0000000..aa6c0ce --- /dev/null +++ b/engine/components-api/src/com/cloud/storage/StorageManager.java @@ -0,0 +1,137 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.storage; + +import java.math.BigDecimal; +import java.util.List; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; +import com.cloud.agent.manager.Commands; +import com.cloud.capacity.CapacityVO; +import com.cloud.exception.ConnectionException; +import com.cloud.exception.StorageConflictException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.Host; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.offering.DiskOffering; +import com.cloud.offering.ServiceOffering; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.utils.Pair; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.VMInstanceVO; + +public interface StorageManager extends StorageService { + static final ConfigKey<Integer> StorageCleanupInterval = new ConfigKey<Integer>(Integer.class, "storage.cleanup.interval", "Advanced", "86400", + "The interval (in seconds) to wait before running the storage cleanup thread.", false, ConfigKey.Scope.Global, null); + static final ConfigKey<Integer> StorageCleanupDelay = new ConfigKey<Integer>(Integer.class, "storage.cleanup.delay", "Advanced", "86400", + "Determines how long (in seconds) to wait before actually expunging destroyed volumes. The default value = the default value of storage.cleanup.interval.", false, ConfigKey.Scope.Global, null); + static final ConfigKey<Boolean> StorageCleanupEnabled = new ConfigKey<Boolean>(Boolean.class, "storage.cleanup.enabled", "Advanced", "true", + "Enables/disables the storage cleanup thread.", false, ConfigKey.Scope.Global, null); + + /** + * Returns a comma separated list of tags for the specified storage pool + * @param poolId + * @return comma separated list of tags + */ + public String getStoragePoolTags(long poolId); + + Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException; + + Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException; + + Answer[] sendToPool(long poolId, Commands cmd) throws StorageUnavailableException; + + Answer[] sendToPool(StoragePool pool, Commands cmds) throws StorageUnavailableException; + + Pair<Long, Answer[]> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Commands cmds) throws StorageUnavailableException; + + Pair<Long, Answer> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Command cmd) throws StorageUnavailableException; + + /** + * Checks if a host has running VMs that are using its local storage pool. + * @return true if local storage is active on the host + */ + boolean isLocalStorageActiveOnHost(Long hostId); + + /** + * Cleans up storage pools by removing unused templates. + * @param recurring - true if this cleanup is part of a recurring garbage collection thread + */ + void cleanupStorage(boolean recurring); + + String getPrimaryStorageNameLabel(VolumeVO volume); + + void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated); + + Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException; + + CapacityVO getSecondaryStorageUsedStats(Long hostId, Long zoneId); + + CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId); + + List<StoragePoolVO> ListByDataCenterHypervisor(long datacenterId, HypervisorType type); + + List<VMInstanceVO> listByStoragePool(long storagePoolId); + + StoragePoolVO findLocalStorageOnHost(long hostId); + + Host updateSecondaryStorage(long secStorageId, String newUrl); + + List<Long> getUpHostsInPool(long poolId); + + void cleanupSecondaryStorage(boolean recurring); + + HypervisorType getHypervisorTypeFromFormat(ImageFormat format); + + boolean storagePoolHasEnoughIops(List<Volume> volume, StoragePool pool); + + boolean storagePoolHasEnoughSpace(List<Volume> volume, StoragePool pool); + + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); + + void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException; + + void createCapacityEntry(long poolId); + + DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException; + + BigDecimal getStorageOverProvisioningFactor(Long dcId); + + Long getDiskBytesReadRate(ServiceOffering offering, DiskOffering diskOffering); + + Long getDiskBytesWriteRate(ServiceOffering offering, DiskOffering diskOffering); + + Long getDiskIopsReadRate(ServiceOffering offering, DiskOffering diskOffering); + + Long getDiskIopsWriteRate(ServiceOffering offering, DiskOffering diskOffering); + + void cleanupDownloadUrls(); + + void setDiskProfileThrottling(DiskProfile dskCh, ServiceOffering offering, DiskOffering diskOffering); + + DiskTO getDiskWithThrottling(DataTO volTO, Volume.Type volumeType, long deviceId, String path, long offeringId, long diskOfferingId); + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/976b3b7d/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java ---------------------------------------------------------------------- diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index d407bb1..8de6bd2 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -94,6 +94,7 @@ import com.cloud.storage.ScopeType; import com.cloud.storage.Snapshot; import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.Volume; @@ -175,6 +176,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati protected AsyncJobManager _jobMgr; @Inject ClusterManager clusterManager; + @Inject + StorageManager storageMgr; private final StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine; protected List<StoragePoolAllocator> _storagePoolAllocators; @@ -207,10 +210,11 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati // Find a destination storage pool with the specified criteria DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, volume.getDiskOfferingId()); - ; DiskProfile dskCh = new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(), diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null); dskCh.setHyperType(dataDiskHyperType); + storageMgr.setDiskProfileThrottling(dskCh, null, diskOffering); + DataCenter destPoolDataCenter = _entityMgr.findById(DataCenter.class, destPoolDcId); Pod destPoolPod = _entityMgr.findById(Pod.class, destPoolPodId); @@ -458,6 +462,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati final HashSet<StoragePool> avoidPools = new HashSet<StoragePool>(avoids); DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); dskCh.setHyperType(vm.getHypervisorType()); + storageMgr.setDiskProfileThrottling(dskCh, null, diskOffering); + // Find a suitable storage to create volume on StoragePool destPool = findStoragePool(dskCh, dc, pod, clusterId, null, vm, avoidPools); DataStore destStore = dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); @@ -490,8 +496,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati DiskProfile dskCh = null; if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { dskCh = createDiskCharacteristics(volume, template, dc, offering); + storageMgr.setDiskProfileThrottling(dskCh, offering, diskOffering); } else { dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); + storageMgr.setDiskProfileThrottling(dskCh, null, diskOffering); } if (diskOffering != null && diskOffering.isCustomized()) { @@ -1054,9 +1062,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati } for (VolumeVO vol : vols) { - DataTO volTO = volFactory.getVolume(vol.getId()).getTO(); - DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), vol.getPath(), vol.getVolumeType()); VolumeInfo volumeInfo = volFactory.getVolume(vol.getId()); + DataTO volTO = volumeInfo.getTO(); + DiskTO disk = storageMgr.getDiskWithThrottling(volTO, vol.getVolumeType(), vol.getDeviceId(), vol.getPath(), + vm.getServiceOfferingId(), vol.getDiskOfferingId()); DataStore dataStore = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); disk.setDetails(getDetails(volumeInfo, dataStore)); @@ -1337,9 +1346,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati pool = (StoragePool)dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary); vol = result.first(); } - DataTO volumeTO = volFactory.getVolume(vol.getId()).getTO(); - DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), vol.getPath(), vol.getVolumeType()); VolumeInfo volumeInfo = volFactory.getVolume(vol.getId()); + DataTO volTO = volumeInfo.getTO(); + DiskTO disk = storageMgr.getDiskWithThrottling(volTO, vol.getVolumeType(), vol.getDeviceId(), vol.getPath(), + vm.getServiceOfferingId(), vol.getDiskOfferingId()); DataStore dataStore = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); disk.setDetails(getDetails(volumeInfo, dataStore)); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/976b3b7d/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 51931db..749cbd8 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -944,8 +944,8 @@ public class KVMStorageProcessor implements StorageProcessor { return null; } - protected synchronized String attachOrDetachDisk(final Connect conn, final boolean attach, final String vmName, final KVMPhysicalDisk attachingDisk, final int devId, final String serial) throws LibvirtException, - InternalErrorException { + protected synchronized String attachOrDetachDisk(final Connect conn, final boolean attach, final String vmName, final KVMPhysicalDisk attachingDisk, final int devId, final String serial, + final Long bytesReadRate, final Long bytesWriteRate, final Long iopsReadRate, final Long iopsWriteRate) throws LibvirtException, InternalErrorException { List<DiskDef> disks = null; Domain dm = null; DiskDef diskdef = null; @@ -1006,6 +1006,19 @@ public class KVMStorageProcessor implements StorageProcessor { } else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) { diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId, DiskDef.DiskBus.VIRTIO); } + + if ((bytesReadRate != null) && (bytesReadRate > 0)) { + diskdef.setBytesReadRate(bytesReadRate); + } + if ((bytesWriteRate != null) && (bytesWriteRate > 0)) { + diskdef.setBytesWriteRate(bytesWriteRate); + } + if ((iopsReadRate != null) && (iopsReadRate > 0)) { + diskdef.setIopsReadRate(iopsReadRate); + } + if ((iopsWriteRate != null) && (iopsWriteRate > 0)) { + diskdef.setIopsWriteRate(iopsWriteRate); + } } final String xml = diskdef.toString(); @@ -1031,7 +1044,7 @@ public class KVMStorageProcessor implements StorageProcessor { final KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath()); - attachOrDetachDisk(conn, true, vmName, phyDisk, disk.getDiskSeq().intValue(), serial); + attachOrDetachDisk(conn, true, vmName, phyDisk, disk.getDiskSeq().intValue(), serial, vol.getBytesReadRate(), vol.getBytesWriteRate(), vol.getIopsReadRate(), vol.getIopsWriteRate()); return new AttachAnswer(disk); } catch (final LibvirtException e) { @@ -1056,7 +1069,7 @@ public class KVMStorageProcessor implements StorageProcessor { final KVMPhysicalDisk phyDisk = storagePoolMgr.getPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath()); - attachOrDetachDisk(conn, false, vmName, phyDisk, disk.getDiskSeq().intValue(), serial); + attachOrDetachDisk(conn, false, vmName, phyDisk, disk.getDiskSeq().intValue(), serial, vol.getBytesReadRate(), vol.getBytesWriteRate(), vol.getIopsReadRate(), vol.getIopsWriteRate()); storagePoolMgr.disconnectPhysicalDisk(primaryStore.getPoolType(), primaryStore.getUuid(), vol.getPath()); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/976b3b7d/server/src/com/cloud/storage/StorageManager.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java deleted file mode 100644 index a399a08..0000000 --- a/server/src/com/cloud/storage/StorageManager.java +++ /dev/null @@ -1,128 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package com.cloud.storage; - -import java.math.BigDecimal; -import java.util.List; - -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; - -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.StoragePoolInfo; -import com.cloud.agent.manager.Commands; -import com.cloud.capacity.CapacityVO; -import com.cloud.exception.ConnectionException; -import com.cloud.exception.StorageConflictException; -import com.cloud.exception.StorageUnavailableException; -import com.cloud.host.Host; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.service.ServiceOfferingVO; -import com.cloud.storage.Storage.ImageFormat; -import com.cloud.utils.Pair; -import com.cloud.vm.VMInstanceVO; - -public interface StorageManager extends StorageService { - static final ConfigKey<Integer> StorageCleanupInterval = new ConfigKey<Integer>(Integer.class, "storage.cleanup.interval", "Advanced", "86400", - "The interval (in seconds) to wait before running the storage cleanup thread.", false, ConfigKey.Scope.Global, null); - static final ConfigKey<Integer> StorageCleanupDelay = new ConfigKey<Integer>(Integer.class, "storage.cleanup.delay", "Advanced", "86400", - "Determines how long (in seconds) to wait before actually expunging destroyed volumes. The default value = the default value of storage.cleanup.interval.", false, ConfigKey.Scope.Global, null); - static final ConfigKey<Boolean> StorageCleanupEnabled = new ConfigKey<Boolean>(Boolean.class, "storage.cleanup.enabled", "Advanced", "true", - "Enables/disables the storage cleanup thread.", false, ConfigKey.Scope.Global, null); - - /** - * Returns a comma separated list of tags for the specified storage pool - * @param poolId - * @return comma separated list of tags - */ - public String getStoragePoolTags(long poolId); - - Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException; - - Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException; - - Answer[] sendToPool(long poolId, Commands cmd) throws StorageUnavailableException; - - Answer[] sendToPool(StoragePool pool, Commands cmds) throws StorageUnavailableException; - - Pair<Long, Answer[]> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Commands cmds) throws StorageUnavailableException; - - Pair<Long, Answer> sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List<Long> hostIdsToAvoid, Command cmd) throws StorageUnavailableException; - - /** - * Checks if a host has running VMs that are using its local storage pool. - * @return true if local storage is active on the host - */ - boolean isLocalStorageActiveOnHost(Long hostId); - - /** - * Cleans up storage pools by removing unused templates. - * @param recurring - true if this cleanup is part of a recurring garbage collection thread - */ - void cleanupStorage(boolean recurring); - - String getPrimaryStorageNameLabel(VolumeVO volume); - - void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated); - - Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException; - - CapacityVO getSecondaryStorageUsedStats(Long hostId, Long zoneId); - - CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId); - - List<StoragePoolVO> ListByDataCenterHypervisor(long datacenterId, HypervisorType type); - - List<VMInstanceVO> listByStoragePool(long storagePoolId); - - StoragePoolVO findLocalStorageOnHost(long hostId); - - Host updateSecondaryStorage(long secStorageId, String newUrl); - - List<Long> getUpHostsInPool(long poolId); - - void cleanupSecondaryStorage(boolean recurring); - - HypervisorType getHypervisorTypeFromFormat(ImageFormat format); - - boolean storagePoolHasEnoughIops(List<Volume> volume, StoragePool pool); - - boolean storagePoolHasEnoughSpace(List<Volume> volume, StoragePool pool); - - boolean registerHostListener(String providerUuid, HypervisorHostListener listener); - - void connectHostToSharedPool(long hostId, long poolId) throws StorageUnavailableException, StorageConflictException; - - void createCapacityEntry(long poolId); - - DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException; - - BigDecimal getStorageOverProvisioningFactor(Long dcId); - - Long getDiskBytesReadRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering); - - Long getDiskBytesWriteRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering); - - Long getDiskIopsReadRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering); - - Long getDiskIopsWriteRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering); - - void cleanupDownloadUrls(); -} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/976b3b7d/server/src/com/cloud/storage/StorageManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 3d7146e..97a4db6 100644 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -95,11 +95,14 @@ import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao; import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreVO; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; +import org.apache.cloudstack.storage.to.VolumeObjectTO; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.agent.api.to.DataTO; +import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.manager.Commands; import com.cloud.api.ApiDBUtils; import com.cloud.api.query.dao.TemplateJoinDao; @@ -138,13 +141,14 @@ import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.offering.DiskOffering; +import com.cloud.offering.ServiceOffering; import com.cloud.org.Grouping; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceState; import com.cloud.server.ConfigurationServer; import com.cloud.server.ManagementServer; import com.cloud.server.StatsCollector; -import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume.Type; @@ -173,6 +177,7 @@ import com.cloud.utils.component.ComponentContext; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; +import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.GlobalLock; import com.cloud.utils.db.JoinBuilder; @@ -185,6 +190,7 @@ import com.cloud.utils.db.TransactionCallbackNoReturn; import com.cloud.utils.db.TransactionLegacy; import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DiskProfile; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.VMInstanceDao; @@ -280,6 +286,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C private DiskOfferingDao _diskOfferingDao; @Inject ResourceLimitService _resourceLimitMgr; + @Inject + EntityManager _entityMgr; protected List<StoragePoolDiscoverer> _discoverers; @@ -2237,7 +2245,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // get bytesReadRate from service_offering, disk_offering and vm.disk.throttling.bytes_read_rate @Override - public Long getDiskBytesReadRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering) { + public Long getDiskBytesReadRate(final ServiceOffering offering, final DiskOffering diskOffering) { if ((offering != null) && (offering.getBytesReadRate() != null) && (offering.getBytesReadRate() > 0)) { return offering.getBytesReadRate(); } else if ((diskOffering != null) && (diskOffering.getBytesReadRate() != null) && (diskOffering.getBytesReadRate() > 0)) { @@ -2253,7 +2261,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // get bytesWriteRate from service_offering, disk_offering and vm.disk.throttling.bytes_write_rate @Override - public Long getDiskBytesWriteRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering) { + public Long getDiskBytesWriteRate(final ServiceOffering offering, final DiskOffering diskOffering) { if ((offering != null) && (offering.getBytesWriteRate() != null) && (offering.getBytesWriteRate() > 0)) { return offering.getBytesWriteRate(); } else if ((diskOffering != null) && (diskOffering.getBytesWriteRate() != null) && (diskOffering.getBytesWriteRate() > 0)) { @@ -2269,7 +2277,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // get iopsReadRate from service_offering, disk_offering and vm.disk.throttling.iops_read_rate @Override - public Long getDiskIopsReadRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering) { + public Long getDiskIopsReadRate(final ServiceOffering offering, final DiskOffering diskOffering) { if ((offering != null) && (offering.getIopsReadRate() != null) && (offering.getIopsReadRate() > 0)) { return offering.getIopsReadRate(); } else if ((diskOffering != null) && (diskOffering.getIopsReadRate() != null) && (diskOffering.getIopsReadRate() > 0)) { @@ -2285,7 +2293,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C // get iopsWriteRate from service_offering, disk_offering and vm.disk.throttling.iops_write_rate @Override - public Long getDiskIopsWriteRate(ServiceOfferingVO offering, DiskOfferingVO diskOffering) { + public Long getDiskIopsWriteRate(final ServiceOffering offering, final DiskOffering diskOffering) { if ((offering != null) && (offering.getIopsWriteRate() != null) && (offering.getIopsWriteRate() > 0)) { return offering.getIopsWriteRate(); } else if ((diskOffering != null) && (diskOffering.getIopsWriteRate() != null) && (diskOffering.getIopsWriteRate() > 0)) { @@ -2308,4 +2316,39 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public ConfigKey<?>[] getConfigKeys() { return new ConfigKey<?>[] {StorageCleanupInterval, StorageCleanupDelay, StorageCleanupEnabled}; } + + @Override + public void setDiskProfileThrottling(DiskProfile dskCh, final ServiceOffering offering, final DiskOffering diskOffering) { + dskCh.setBytesReadRate(getDiskBytesReadRate(offering, diskOffering)); + dskCh.setBytesWriteRate(getDiskBytesWriteRate(offering, diskOffering)); + dskCh.setIopsReadRate(getDiskIopsReadRate(offering, diskOffering)); + dskCh.setIopsWriteRate(getDiskIopsWriteRate(offering, diskOffering)); + } + + @Override + public DiskTO getDiskWithThrottling(final DataTO volTO, final Volume.Type volumeType, final long deviceId, final String path, final long offeringId, final long diskOfferingId) { + DiskTO disk = null; + if (volTO != null && volTO instanceof VolumeObjectTO) { + VolumeObjectTO volumeTO = (VolumeObjectTO) volTO; + ServiceOffering offering = _entityMgr.findById(ServiceOffering.class, offeringId); + DiskOffering diskOffering = _entityMgr.findById(DiskOffering.class, diskOfferingId); + if (volumeType == Volume.Type.ROOT) { + setVolumeObjectTOThrottling(volumeTO, offering, diskOffering); + } else { + setVolumeObjectTOThrottling(volumeTO, null, diskOffering); + } + disk = new DiskTO(volumeTO, deviceId, path, volumeType); + } else { + disk = new DiskTO(volTO, deviceId, path, volumeType); + } + return disk; + } + + private void setVolumeObjectTOThrottling(VolumeObjectTO volumeTO, final ServiceOffering offering, final DiskOffering diskOffering) { + volumeTO.setBytesReadRate(getDiskBytesReadRate(offering, diskOffering)); + volumeTO.setBytesWriteRate(getDiskBytesWriteRate(offering, diskOffering)); + volumeTO.setIopsReadRate(getDiskIopsReadRate(offering, diskOffering)); + volumeTO.setIopsWriteRate(getDiskIopsWriteRate(offering, diskOffering)); + } + } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/976b3b7d/server/src/com/cloud/storage/VolumeApiServiceImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java index 4c3de3e..9243503 100644 --- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java @@ -251,6 +251,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Inject UserVmManager _userVmMgr; protected Gson _gson; + @Inject + StorageManager storageMgr; private List<StoragePoolAllocator> _storagePoolAllocators; @@ -2479,7 +2481,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic deviceId = getDeviceId(vm.getId(), deviceId); - DiskTO disk = new DiskTO(volTO, deviceId, volumeToAttach.getPath(), volumeToAttach.getVolumeType()); + DiskTO disk = storageMgr.getDiskWithThrottling(volTO, volumeToAttach.getVolumeType(), deviceId, volumeToAttach.getPath(), + vm.getServiceOfferingId(), volumeToAttach.getDiskOfferingId()); AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName());