diff --git a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java index 70375c30a1bb..3922e7d798de 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/MigrateVolumeCommand.java @@ -36,6 +36,7 @@ public class MigrateVolumeCommand extends Command { String attachedVmName; Volume.Type volumeType; String hostGuidInTargetCluster; + Long newIops; private DataTO srcData; private DataTO destData; @@ -146,6 +147,14 @@ public int getWaitInMillSeconds() { public String getChainInfo() { return chainInfo; } + public void setNewIops(Long newIops) { + this.newIops = newIops; + } + + public Long getNewIops() { + return newIops; + } + @Override public boolean isReconcile() { return true; diff --git a/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java b/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java index db867698e91e..a8d88ca3124d 100644 --- a/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java +++ b/core/src/main/java/com/cloud/agent/api/storage/ResizeVolumeCommand.java @@ -33,6 +33,8 @@ public class ResizeVolumeCommand extends Command { private boolean shrinkOk; private String vmInstance; private String chainInfo; + private Long newMaxIops; + private Long newMinIops; /* For managed storage */ private boolean managed; @@ -70,7 +72,6 @@ public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, L public ResizeVolumeCommand(String path, StorageFilerTO pool, Long currentSize, Long newSize, boolean shrinkOk, String vmInstance, boolean isManaged, String iScsiName) { this(path, pool, currentSize, newSize, shrinkOk, vmInstance); - this.iScsiName = iScsiName; this.managed = isManaged; } @@ -120,4 +121,20 @@ public void clearPassphrase() { public boolean executeInSequence() { return false; } + + public Long getNewMaxIops() { + return newMaxIops; + } + + public void setNewMaxIops(Long newMaxIops) { + this.newMaxIops = newMaxIops; + } + + public Long getNewMinIops() { + return newMinIops; + } + + public void setNewMinIops(Long newMinIops) { + this.newMinIops = newMinIops; + } } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index afc33eb51904..ee15e577c6f4 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -110,7 +110,7 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) throws StorageUnavailableException; - Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException; + Volume migrateVolume(Volume volume, StoragePool destPool, DiskOffering newDiskOffering) throws StorageUnavailableException; Volume liveMigrateVolume(Volume volume, StoragePool destPool); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index e0075888caf7..969efa5608d3 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -321,7 +321,7 @@ public VolumeInfo moveVolume(VolumeInfo volumeInfo, long destPoolDcId, Long dest throw new CloudRuntimeException(String.format("Failed to find a storage pool with enough capacity to move the volume [%s] to.", volumeToString)); } - Volume newVol = migrateVolume(volumeInfo, destPool); + Volume newVol = migrateVolume(volumeInfo, destPool, diskOffering); return volFactory.getVolume(newVol.getId()); } @@ -1359,13 +1359,14 @@ private void checkConcurrentJobsPerDatastoreThreshhold(final StoragePool destPoo @Override @DB - public Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException { + public Volume migrateVolume(Volume volume, StoragePool destPool, DiskOffering newDiskOffering) throws StorageUnavailableException { String volumeToString = getVolumeIdentificationInfos(volume); VolumeInfo vol = volFactory.getVolume(volume.getId()); if (vol == null){ throw new CloudRuntimeException(String.format("Volume migration failed because volume [%s] is null.", volumeToString)); } + vol.addPayload(newDiskOffering); if (destPool == null) { throw new CloudRuntimeException("Volume migration failed because the destination storage pool is not available."); } @@ -1494,7 +1495,7 @@ public boolean storageMigration(VirtualMachineProfile vm, Map entry : volumeStoragePoolMap.entrySet()) { - Volume result = migrateVolume(entry.getKey(), entry.getValue()); + Volume result = migrateVolume(entry.getKey(), entry.getValue(), null); if (result == null) { return false; } @@ -1955,7 +1956,7 @@ public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws Sto } else if (task.type == VolumeTaskType.MIGRATE) { store = (PrimaryDataStore) dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); updateVolumeSize(store, task.volume); - vol = migrateVolume(task.volume, store); + vol = migrateVolume(task.volume, store, null); } else if (task.type == VolumeTaskType.RECREATE) { Pair result = recreateVolume(task.volume, vm, dest); store = (PrimaryDataStore) dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary); diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java index 0b0065361d07..bb4703555a8f 100644 --- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java +++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -69,6 +69,7 @@ import com.cloud.storage.DataStoreRole; import com.cloud.storage.Snapshot.Type; import com.cloud.storage.SnapshotVO; +import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.StorageManager; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePool; @@ -459,6 +460,16 @@ protected Answer migrateVolumeToPool(DataObject srcData, DataObject destData) { StoragePool srcPool = (StoragePool)dataStoreMgr.getDataStore(srcData.getDataStore().getId(), DataStoreRole.Primary); StoragePool destPool = (StoragePool)dataStoreMgr.getDataStore(destData.getDataStore().getId(), DataStoreRole.Primary); MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool, volume.getAttachedVmName(), volume.getVolumeType(), waitInterval, volume.getChainInfo()); + + if (volume.getpayload() instanceof DiskOfferingVO) { + DiskOfferingVO offering = (DiskOfferingVO) volume.getpayload(); + Long newIops = null; + if (offering.getIopsReadRate() != null && offering.getIopsWriteRate() != null) { + newIops = offering.getIopsReadRate() + offering.getIopsWriteRate(); + } + command.setNewIops(newIops); + } + if (srcPool.getParent() != 0) { command.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 478ccf1d2afb..b5f2d94ef842 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -45,6 +45,7 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.vmware.vim25.StorageIOAllocationInfo; import com.cloud.agent.api.CleanupVMCommand; import javax.naming.ConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; @@ -78,6 +79,7 @@ import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.logging.log4j.ThreadContext; +import org.apache.commons.lang3.ObjectUtils; import org.joda.time.Duration; import com.cloud.agent.IAgentControl; @@ -873,6 +875,8 @@ private Answer execute(ResizeVolumeCommand cmd) { boolean managed = cmd.isManaged(); String poolUUID = cmd.getPoolUuid(); String chainInfo = cmd.getChainInfo(); + Long newMinIops = cmd.getNewMinIops(); + Long newMaxIops = cmd.getNewMaxIops(); boolean useWorkerVm = false; VmwareContext context = getServiceContext(); @@ -887,8 +891,6 @@ private Answer execute(ResizeVolumeCommand cmd) { oldSize / (float) ResourceType.bytesToMiB, newSize / (float) ResourceType.bytesToMiB, vmName); logger.error(errorMsg); throw new Exception(errorMsg); - } else if (newSize == oldSize) { - return new ResizeVolumeAnswer(cmd, true, "success", newSize * ResourceType.bytesToKiB); } if (vmName.equalsIgnoreCase("none")) { @@ -982,6 +984,8 @@ private Answer execute(ResizeVolumeCommand cmd) { VirtualDisk disk = getDiskAfterResizeDiskValidations(vmMo, path); String vmdkAbsFile = VmwareHelper.getAbsoluteVmdkFile(disk); + setDiskIops(disk, newMinIops, newMaxIops); + if (vmdkAbsFile != null && !vmdkAbsFile.isEmpty()) { vmMo.updateAdapterTypeIfRequired(vmdkAbsFile); } @@ -1033,6 +1037,22 @@ private Answer execute(ResizeVolumeCommand cmd) { } } + /** + * Sets the disk IOPS which is the sum of min IOPS and max IOPS; if they are null, the IOPS limit is set to -1 (unlimited). + */ + private void setDiskIops(VirtualDisk disk, Long newMinIops, Long newMaxIops) { + StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo(); + Long iops = -1L; + + if (ObjectUtils.allNotNull(newMinIops, newMaxIops) && newMinIops > 0 && newMaxIops > 0) { + iops = newMinIops + newMaxIops; + } + + storageIOAllocation.setLimit(iops); + logger.debug(LogUtils.logGsonWithoutException("Setting [%s] as the IOPS limit of disk [%s].", iops == -1L ? "unlimited" : iops, disk)); + disk.setStorageIOAllocation(storageIOAllocation); + } + private VirtualDisk getDiskAfterResizeDiskValidations(VirtualMachineMO vmMo, String volumePath) throws Exception { Pair vdisk = vmMo.getDiskDevice(volumePath); if (vdisk == null) { @@ -4425,7 +4445,7 @@ protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) { for (String diskPath : disks) { DatastoreFile file = new DatastoreFile(diskPath); VirtualMachineMO vmMo = dcMo.findVm(file.getDir()); - Pair vds = vmMo.getDiskDevice(file.getFileName(), true); + Pair vds = vmMo.getDiskDevice(file.getFileName(), true, false); long virtualsize = vds.first().getCapacityInKB() * 1024; long physicalsize = primaryStorageDatastoreMo.fileDiskSize(file.getPath()); if (statEntry.containsKey(chainInfo)) { @@ -5178,6 +5198,8 @@ private Answer execute(MigrateVolumeCommand cmd) { volumePath = vmMo.getVmdkFileBaseName(disk); } } + + setDiskIops(cmd, vmMo, volumePath); VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); chainInfo = _gson.toJson(diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, targetDsMo.getName())); MigrateVolumeAnswer answer = new MigrateVolumeAnswer(cmd, true, null, volumePath); @@ -5190,6 +5212,33 @@ private Answer execute(MigrateVolumeCommand cmd) { } } + /** + * Sets the disk IOPS limitation, if the {@link MigrateVolumeCommand} did not specify this limitation, then it is set to -1 (unlimited). + */ + private void setDiskIops(MigrateVolumeCommand cmd, VirtualMachineMO vmMo, String volumePath) throws Exception { + Long newIops = cmd.getNewIops() == null ? -1L : cmd.getNewIops(); + VirtualDisk disk = vmMo.getDiskDevice(volumePath, true, true).first(); + + try { + logger.debug(LogUtils.logGsonWithoutException("Trying to change disk [%s] IOPS to [%s].", disk, newIops)); + VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + + StorageIOAllocationInfo storageIOAllocation = new StorageIOAllocationInfo(); + storageIOAllocation.setLimit(newIops); + disk.setStorageIOAllocation(storageIOAllocation); + + deviceConfigSpec.setDevice(disk); + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.EDIT); + vmConfigSpec.getDeviceChange().add(deviceConfigSpec); + vmMo.configureVm(vmConfigSpec); + } catch (Exception e) { + String vmwareDocumentation = "https://kb.vmware.com/s/article/68164"; + logger.error(LogUtils.logGsonWithoutException("Failed to change disk [%s] IOPS to [%s] due to [%s]. This happens when the disk controller is IDE." + + " Please read this documentation for more information: [%s]. ", disk, newIops, e.getMessage(), vmwareDocumentation), e); + } + } + private Pair getVirtualDiskInfo(VirtualMachineMO vmMo, String srcDiskName) throws Exception { Pair deviceInfo = vmMo.getDiskDevice(srcDiskName); if (deviceInfo == null) { diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java index b0cacf60a176..0e641cad7785 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/storage/motion/VmwareStorageMotionStrategy.java @@ -27,6 +27,7 @@ import javax.inject.Inject; import com.cloud.agent.api.to.DiskTO; +import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.Storage; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy; @@ -251,6 +252,17 @@ public void copyAsync(DataObject srcData, DataObject destData, Host destHost, As , sourcePool , targetPool , hostIdForVmAndHostGuidInTargetCluster.second(), ((VolumeObjectTO) srcData.getTO()).getChainInfo()); + + VolumeInfo volumeInfo = (VolumeInfo) srcData; + if (volumeInfo.getpayload() instanceof DiskOfferingVO) { + DiskOfferingVO offering = (DiskOfferingVO) volumeInfo.getpayload(); + Long newIops = null; + if (offering.getIopsReadRate() != null && offering.getIopsWriteRate() != null) { + newIops = offering.getIopsReadRate() + offering.getIopsWriteRate(); + } + cmd.setNewIops(newIops); + } + if (sourcePool.getParent() != 0) { cmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java index d2f0076f95f4..e762d6be1791 100644 --- a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java +++ b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java @@ -469,6 +469,8 @@ public void resize(DataObject data, AsyncCompletionCallback cal } ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(vol.getPath(), new StorageFilerTO(pool), vol.getSize(), resizeParameter.newSize, resizeParameter.shrinkOk, resizeParameter.instanceName, vol.getChainInfo(), vol.getPassphrase(), vol.getEncryptFormat()); + resizeCmd.setNewMinIops(resizeParameter.newMinIops); + resizeCmd.setNewMaxIops(resizeParameter.newMaxIops); if (pool.getParent() != 0) { resizeCmd.setContextParam(DiskTO.PROTOCOL_TYPE, Storage.StoragePoolType.DatastoreCluster.toString()); } diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 2048ee4cfc9f..cf6b5ecf100d 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -1253,8 +1253,8 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep validateIops(newMinIops, newMaxIops, volume.getPoolType()); } else { - newMinIops = newDiskOffering.getMinIops(); - newMaxIops = newDiskOffering.getMaxIops(); + newMinIops = newDiskOffering.getMinIops() != null ? newDiskOffering.getMinIops() : newDiskOffering.getIopsReadRate(); + newMaxIops = newDiskOffering.getMaxIops() != null ? newDiskOffering.getMaxIops() : newDiskOffering.getIopsWriteRate(); } // if the hypervisor snapshot reserve value is null, it must remain null (currently only KVM uses null and null is all KVM uses for a value here) @@ -1322,10 +1322,8 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep volumeMigrateRequired = true; } - boolean volumeResizeRequired = false; - if (currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops())) { - volumeResizeRequired = true; - } + boolean volumeResizeRequired = currentSize != newSize || !compareEqualsIncludingNullOrZero(newMaxIops, volume.getMaxIops()) || !compareEqualsIncludingNullOrZero(newMinIops, volume.getMinIops()) + || !compareEqualsIncludingNullOrZero(newMaxIops, diskOffering.getIopsWriteRate()) || !compareEqualsIncludingNullOrZero(newMinIops, diskOffering.getIopsReadRate()); if (!volumeMigrateRequired && !volumeResizeRequired && newDiskOffering != null) { _volsDao.updateDiskOffering(volume.getId(), newDiskOffering.getId()); volume = _volsDao.findById(volume.getId()); @@ -1390,7 +1388,11 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep } else if (jobResult instanceof Throwable) { throw new RuntimeException("Unexpected exception", (Throwable) jobResult); } else if (jobResult instanceof Long) { - return _volsDao.findById((Long) jobResult); + Long volumeId = (Long) jobResult; + if (newDiskOffering != null) { + _volsDao.updateDiskOffering(volumeId, newDiskOffering.getId()); + } + return _volsDao.findById(volumeId); } } @@ -3730,9 +3732,9 @@ private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, b Volume newVol = null; try { if (liveMigrateVolume) { - newVol = liveMigrateVolume(volume, destPool); + newVol = liveMigrateVolume(volume, destPool, newDiskOffering); } else { - newVol = _volumeMgr.migrateVolume(volume, destPool); + newVol = _volumeMgr.migrateVolume(volume, destPool, newDiskOffering); } if (newDiskOffering != null) { _volsDao.updateDiskOffering(newVol.getId(), newDiskOffering.getId()); @@ -3748,9 +3750,9 @@ private Volume orchestrateMigrateVolume(VolumeVO volume, StoragePool destPool, b } @DB - protected Volume liveMigrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException { + protected Volume liveMigrateVolume(Volume volume, StoragePool destPool, DiskOfferingVO newDiskOffering) throws StorageUnavailableException { VolumeInfo vol = volFactory.getVolume(volume.getId()); - + vol.addPayload(newDiskOffering); DataStore dataStoreTarget = dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); AsyncCallFuture future = volService.migrateVolume(vol, dataStoreTarget); try { diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index 8d5387b3ffd5..dc5f2755cca7 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -1005,7 +1005,7 @@ private UserVm migrateImportedVM(HostVO sourceHost, VirtualMachineTemplate templ if (vm.getState().equals(VirtualMachine.State.Running)) { volume = volumeManager.liveMigrateVolume(volumeVO, storagePool); } else { - volume = volumeManager.migrateVolume(volumeVO, storagePool); + volume = volumeManager.migrateVolume(volumeVO, storagePool, dOffering); } if (volume == null) { String msg = ""; diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 5b9e3520da1b..0d5b1c501154 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -2785,9 +2785,13 @@ public Pair getDiskDevice(String vmdkDatastorePath) throws } // return pair of VirtualDisk and disk device bus name(ide0:0, etc) - public Pair getDiskDevice(String vmdkDatastorePath, boolean matchExactly) throws Exception { + public Pair getDiskDevice(String vmdkDatastorePath, boolean matchExactly, boolean ignoreDotOnPath) throws Exception { List devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + if (ignoreDotOnPath) { + vmdkDatastorePath = vmdkDatastorePath + "."; + } + DatastoreFile dsSrcFile = new DatastoreFile(vmdkDatastorePath); String srcBaseName = dsSrcFile.getFileBaseName(); String trimmedSrcBaseName = VmwareHelper.trimSnapshotDeltaPostfix(srcBaseName);