diff --git a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java index 2a46610117f8..d93c32f99086 100644 --- a/core/src/com/cloud/agent/api/BackupSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/BackupSnapshotCommand.java @@ -39,6 +39,7 @@ public class BackupSnapshotCommand extends SnapshotCommand { private S3TO s3; StorageFilerTO pool; private Long secHostId; + private String nfsVersion; protected BackupSnapshotCommand() { @@ -107,4 +108,12 @@ public Long getSnapshotId() { public Long getSecHostId() { return secHostId; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java index 7ac2ddedd2e3..5a09994ab728 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromSnapshotCommand.java @@ -28,6 +28,7 @@ public class CreatePrivateTemplateFromSnapshotCommand extends SnapshotCommand { private String origTemplateInstallPath; private Long newTemplateId; private String templateName; + private String nfsVersion; protected CreatePrivateTemplateFromSnapshotCommand() { @@ -72,4 +73,12 @@ public Long getNewTemplateId() { public String getTemplateName() { return templateName; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java index 3025147a3044..b6cc6ac4475a 100644 --- a/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java +++ b/core/src/com/cloud/agent/api/CreatePrivateTemplateFromVolumeCommand.java @@ -32,6 +32,7 @@ public class CreatePrivateTemplateFromVolumeCommand extends SnapshotCommand { StorageFilerTO _primaryPool; // For XenServer private String _secondaryStorageUrl; + private String nfsVersion; public CreatePrivateTemplateFromVolumeCommand() { } @@ -99,4 +100,12 @@ public Long getAccountId() { public void setTemplateId(long templateId) { _templateId = templateId; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java index fa9a4d584613..933be0360686 100644 --- a/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java +++ b/core/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java @@ -26,6 +26,8 @@ */ public class CreateVolumeFromSnapshotCommand extends SnapshotCommand { + private String nfsVersion; + protected CreateVolumeFromSnapshotCommand() { } @@ -50,4 +52,12 @@ public CreateVolumeFromSnapshotCommand(StoragePool pool, String secondaryStorage super(pool, secondaryStoragePoolURL, backedUpSnapshotUuid, backedUpSnapshotName, dcId, accountId, volumeId); setWait(wait); } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java index 23e8f9e3e55d..84b54264511c 100644 --- a/core/src/com/cloud/agent/api/GetStorageStatsCommand.java +++ b/core/src/com/cloud/agent/api/GetStorageStatsCommand.java @@ -30,6 +30,7 @@ public class GetStorageStatsCommand extends Command { private StoragePoolType pooltype; private String secUrl; private DataStoreTO store; + private String nfsVersion; public String getSecUrl() { return secUrl; @@ -54,6 +55,11 @@ public GetStorageStatsCommand(DataStoreTO store) { this.store = store; } + public GetStorageStatsCommand(DataStoreTO store, String nfsVersion) { + this.store = store; + this.nfsVersion = nfsVersion; + } + public GetStorageStatsCommand(String secUrl) { this.secUrl = secUrl; } @@ -81,6 +87,14 @@ public DataStoreTO getStore() { return this.store; } + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } + @Override public boolean executeInSequence() { return false; diff --git a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java index 28e55c2f4efc..316e4698dc50 100644 --- a/core/src/com/cloud/agent/api/SecStorageSetupCommand.java +++ b/core/src/com/cloud/agent/api/SecStorageSetupCommand.java @@ -28,6 +28,7 @@ public class SecStorageSetupCommand extends Command { private String secUrl; private KeystoreManager.Certificates certs; private String postUploadKey; + private String nfsVersion; public SecStorageSetupCommand() { @@ -74,4 +75,12 @@ public String getPostUploadKey() { public void setPostUploadKey(String postUploadKey) { this.postUploadKey = postUploadKey; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java index 43c84ee2bc0b..7ab822c03bc3 100644 --- a/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java +++ b/core/src/com/cloud/agent/api/storage/CopyVolumeCommand.java @@ -32,6 +32,7 @@ public class CopyVolumeCommand extends Command { boolean toSecondaryStorage; String vmName; boolean executeInSequence = false; + String nfsVersion; public CopyVolumeCommand() { } @@ -75,4 +76,12 @@ public boolean toSecondaryStorage() { public String getVmName() { return vmName; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java index 855095280d7d..bacc83aea50a 100644 --- a/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java +++ b/core/src/com/cloud/agent/api/storage/ListTemplateCommand.java @@ -23,6 +23,7 @@ public class ListTemplateCommand extends StorageCommand { private DataStoreTO store; + private String nfsVersion; //private String secUrl; @@ -34,6 +35,11 @@ public ListTemplateCommand(DataStoreTO store) { // this.secUrl = url; } + public ListTemplateCommand(DataStoreTO store, String nfsVersion) { + this.store = store; + this.nfsVersion = nfsVersion; + } + @Override public boolean executeInSequence() { return true; @@ -43,6 +49,10 @@ public DataStoreTO getDataStore() { return store; } + public String getNfsVersion() { + return nfsVersion; + } + // public String getSecUrl() { // return secUrl; // } diff --git a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java index ce8ed217a562..9dae513b989b 100644 --- a/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java +++ b/core/src/com/cloud/agent/api/storage/PrimaryStorageDownloadCommand.java @@ -35,6 +35,7 @@ public class PrimaryStorageDownloadCommand extends AbstractDownloadCommand { String secondaryStorageUrl; String primaryStorageUrl; + String nfsVersion; protected PrimaryStorageDownloadCommand() { } @@ -87,4 +88,12 @@ public String getPrimaryStorageUrl() { public boolean executeInSequence() { return true; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java index 5d1e56bd7733..bfcd9ae9b41d 100644 --- a/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java +++ b/core/src/org/apache/cloudstack/storage/command/TemplateOrVolumePostUploadCommand.java @@ -53,6 +53,8 @@ public class TemplateOrVolumePostUploadCommand { private long accountId; + private String nfsVersion; + public TemplateOrVolumePostUploadCommand(long entityId, String entityUUID, String absolutePath, String checksum, String type, String name, String imageFormat, String dataTo, String dataToRole) { this.entityId = entityId; @@ -196,4 +198,12 @@ public void setAccountId(long accountId) { public long getAccountId() { return accountId; } + + public String getNfsVersion() { + return nfsVersion; + } + + public void setNfsVersion(String nfsVersion) { + this.nfsVersion = nfsVersion; + } } diff --git a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml index db517dbd863d..51be9d99faa8 100644 --- a/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml +++ b/engine/storage/image/resources/META-INF/cloudstack/core/spring-engine-storage-image-core-context.xml @@ -29,7 +29,7 @@ + depends-on="dataObjectManagerImpl, dataStoreManagerImpl, dataMotionServiceImpl, objectInDataStoreManagerImpl, defaultEndPointSelector, templateDataFactoryImpl, imageStoreDetailsUtil" /> diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java index 9ab35953711d..a1d10e328077 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateServiceImpl.java @@ -73,6 +73,7 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.DataStoreRole; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StoragePool; @@ -135,6 +136,8 @@ public class TemplateServiceImpl implements TemplateService { ConfigurationDao _configDao; @Inject StorageCacheManager _cacheMgr; + @Inject + ImageStoreDetailsUtil imageStoreDetailsUtil; class TemplateOpContext extends AsyncRpcContext { final TemplateObject template; @@ -564,7 +567,7 @@ public void associateCrosszoneTemplatesToZone(long dcId) { } private Map listTemplate(DataStore ssStore) { - ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO()); + ListTemplateCommand cmd = new ListTemplateCommand(ssStore.getTO(), imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); EndPoint ep = _epSelector.select(ssStore); Answer answer = null; if (ep == null) { diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java index 896342890c82..5c41dcab0ee5 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/MockLocalNfsSecondaryStorageResource.java @@ -51,7 +51,7 @@ public MockLocalNfsSecondaryStorageResource() { } @Override - public String getRootDir(String secUrl) { + public String getRootDir(String secUrl, String nfsVersion) { return "/mnt"; } diff --git a/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml b/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml index 8040d801b3e5..a45e4ee3e40c 100644 --- a/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml +++ b/engine/storage/resources/META-INF/cloudstack/core/spring-engine-storage-core-context.xml @@ -69,5 +69,7 @@ + + diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java index 751da9e3d2a3..9b1f091db71b 100644 --- a/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java +++ b/plugins/hypervisors/simulator/src/com/cloud/resource/AgentStorageResource.java @@ -109,7 +109,7 @@ public boolean configure(String name, Map params) throws Configu } @Override - public String getRootDir(String url) { + public String getRootDir(String url, String nfsVersion) { // TODO Auto-generated method stub return null; } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java index 72ee2184e399..65590500a07f 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManager.java @@ -36,7 +36,7 @@ public interface VmwareManager { String getSystemVMDefaultNicAdapterType(); - void prepareSecondaryStorageStore(String strStorageUrl); + void prepareSecondaryStorageStore(String strStorageUrl, Long storeId); void setupResourceStartupParams(Map params); @@ -48,7 +48,7 @@ public interface VmwareManager { String getManagementPortGroupName(); - String getSecondaryStorageStoreUrl(long dcId); + Pair getSecondaryStorageStoreUrlAndId(long dcId); File getSystemVMKeyFile(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 575801fa6034..f27e938e7334 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -105,6 +105,7 @@ import com.cloud.org.Cluster.ClusterType; import com.cloud.secstorage.CommandExecLogDao; import com.cloud.server.ConfigurationServer; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.JavaStorageLayer; import com.cloud.storage.StorageLayer; import com.cloud.utils.FileUtil; @@ -167,6 +168,8 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private ManagementServerHostPeerDao _mshostPeerDao; @Inject private ClusterManager _clusterMgr; + @Inject + private ImageStoreDetailsUtil imageStoreDetailsUtil; private String _mountParent; private StorageLayer _storage; @@ -439,12 +442,14 @@ public List addHostToPodCluster(VmwareContext serviceCon } @Override - public String getSecondaryStorageStoreUrl(long dcId) { + public Pair getSecondaryStorageStoreUrlAndId(long dcId) { String secUrl = null; + Long secId = null; DataStore secStore = _dataStoreMgr.getImageStore(dcId); if (secStore != null) { secUrl = secStore.getUri(); + secId = secStore.getId(); } if (secUrl == null) { @@ -453,12 +458,13 @@ public String getSecondaryStorageStoreUrl(long dcId) { DataStore cacheStore = _dataStoreMgr.getImageCacheStore(dcId); if (cacheStore != null) { secUrl = cacheStore.getUri(); + secId = cacheStore.getId(); } else { s_logger.warn("No staging storage is found when non-NFS secondary storage is used"); } } - return secUrl; + return new Pair(secUrl, secId); } @Override @@ -546,8 +552,8 @@ public boolean needRecycle(String workerTag) { } @Override - public void prepareSecondaryStorageStore(String storageUrl) { - String mountPoint = getMountPoint(storageUrl); + public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { + String mountPoint = getMountPoint(storageUrl, imageStoreDetailsUtil.getNfsVersion(storeId)); GlobalLock lock = GlobalLock.getInternLock("prepare.systemvm"); try { @@ -655,7 +661,7 @@ public void run() { } @Override - public String getMountPoint(String storageUrl) { + public String getMountPoint(String storageUrl, String nfsVersion) { String mountPoint = null; synchronized (_storageMounts) { mountPoint = _storageMounts.get(storageUrl); @@ -670,7 +676,8 @@ public String getMountPoint(String storageUrl) { s_logger.error("Invalid storage URL format ", e); throw new CloudRuntimeException("Unable to create mount point due to invalid storage URL format " + storageUrl); } - mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent); + + mountPoint = mount(uri.getHost() + ":" + uri.getPath(), _mountParent, nfsVersion); if (mountPoint == null) { s_logger.error("Unable to create mount point for " + storageUrl); return "/mnt/sec"; // throw new CloudRuntimeException("Unable to create mount point for " + storageUrl); @@ -745,7 +752,7 @@ private void shutdownCleanup() { } } - protected String mount(String path, String parent) { + protected String mount(String path, String parent, String nfsVersion) { String mountPoint = setupMountPoint(parent); if (mountPoint == null) { s_logger.warn("Unable to create a mount point"); @@ -756,6 +763,9 @@ protected String mount(String path, String parent) { String result = null; Script command = new Script(true, "mount", _timeout, s_logger); command.add("-t", "nfs"); + if (nfsVersion != null){ + command.add("-o", "vers=" + nfsVersion); + } // command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); if ("Mac OS X".equalsIgnoreCase(System.getProperty("os.name"))) { command.add("-o", "resvport"); @@ -1234,4 +1244,5 @@ public boolean hasNexusVSM(Long clusterId) { return true; } } + } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java index 4109ff2345b9..c7c53bacba99 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java @@ -92,6 +92,9 @@ import com.cloud.vm.snapshot.VMSnapshot; public class VmwareStorageManagerImpl implements VmwareStorageManager { + + private String _nfsVersion; + @Override public boolean execute(VmwareHostService hostService, CreateEntityDownloadURLCommand cmd) { DataTO data = cmd.getData(); @@ -138,6 +141,12 @@ public VmwareStorageManagerImpl(VmwareStorageMount mountService) { _mountService = mountService; } + public VmwareStorageManagerImpl(VmwareStorageMount mountService, String nfsVersion) { + assert (mountService != null); + _mountService = mountService; + _nfsVersion = nfsVersion; + } + public void configure(Map params) { s_logger.info("Configure VmwareStorageManagerImpl"); @@ -156,7 +165,7 @@ public String createOvaForTemplate(TemplateObjectTO template) { String secStorageUrl = nfsStore.getUrl(); assert (secStorageUrl != null); String installPath = template.getPath(); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; try { if (installFullPath.endsWith(".ova")) { @@ -194,7 +203,7 @@ public String createOvaForVolume(VolumeObjectTO volume) { String installPath = volume.getPath(); int index = installPath.lastIndexOf(File.separator); String volumeUuid = installPath.substring(index + 1); - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, _nfsVersion); //The real volume path String volumePath = installPath + File.separator + volumeUuid + ".ova"; String installFullPath = secondaryMountPoint + "/" + installPath; @@ -271,7 +280,8 @@ public Answer execute(VmwareHostService hostService, PrimaryStorageDownloadComma assert (morDs != null); DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(context, morDs); - copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, mountPoint, templateName, templateUuidName); + copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, mountPoint, templateName, templateUuidName, + cmd.getNfsVersion()); } else { s_logger.info("Template " + templateName + " has already been setup, skip the template setup process in primary storage"); } @@ -345,7 +355,7 @@ public Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd) snapshotBackupUuid = backupSnapshotToSecondaryStorage(vmMo, accountId, volumeId, cmd.getVolumePath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid, - hostService.getWorkerName(context, cmd, 1)); + hostService.getWorkerName(context, cmd, 1), cmd.getNfsVersion()); success = (snapshotBackupUuid != null); if (success) { @@ -413,7 +423,7 @@ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVo Ternary result = createTemplateFromVolume(vmMo, accountId, templateId, cmd.getUniqueName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), cmd.getNfsVersion()); return new CreatePrivateTemplateAnswer(cmd, true, null, result.first(), result.third(), result.second(), cmd.getUniqueName(), ImageFormat.OVA); @@ -441,7 +451,8 @@ public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSn VmwareContext context = hostService.getServiceContext(cmd); try { - Ternary result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid); + Ternary result = createTemplateFromSnapshot(accountId, newTemplateId, uniqeName, secondaryStorageUrl, volumeId, backedUpSnapshotUuid, + cmd.getNfsVersion()); return new CreatePrivateTemplateAnswer(cmd, true, null, result.first(), result.third(), result.second(), uniqeName, ImageFormat.OVA); } catch (Throwable e) { @@ -471,7 +482,7 @@ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) { if (cmd.toSecondaryStorage()) { result = copyVolumeToSecStorage(hostService, hyperHost, cmd, vmName, volumeId, cmd.getPool().getUuid(), volumePath, secondaryStorageURL, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), cmd.getNfsVersion()); } else { StorageFilerTO poolTO = cmd.getPool(); @@ -484,8 +495,9 @@ public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) { } } - result = copyVolumeFromSecStorage(hyperHost, volumeId, new DatastoreMO(context, morDatastore), secondaryStorageURL, volumePath); - deleteVolumeDirOnSecondaryStorage(volumeId, secondaryStorageURL); + result = copyVolumeFromSecStorage(hyperHost, volumeId, new DatastoreMO(context, morDatastore), secondaryStorageURL, volumePath, + cmd.getNfsVersion()); + deleteVolumeDirOnSecondaryStorage(volumeId, secondaryStorageURL, cmd.getNfsVersion()); } return new CopyVolumeAnswer(cmd, true, null, result.first(), result.second()); } catch (Throwable e) { @@ -523,7 +535,8 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - details = createVolumeFromSnapshot(hyperHost, primaryDsMo, newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid); + details = createVolumeFromSnapshot(hyperHost, primaryDsMo, newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid, + cmd.getNfsVersion()); if (details == null) { success = true; } @@ -542,12 +555,12 @@ public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCom // templateName: name in secondary storage // templateUuid: will be used at hypervisor layer private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, String nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl, nfsVersion); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = secondaryMountPoint + "/" + templatePathAtSecondaryStorage + templateName + "." + ImageFormat.OVA.getFileExtension(); @@ -598,9 +611,9 @@ private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName, String secStorageUrl, - String volumePath, String workerVmName) throws Exception { + String volumePath, String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { @@ -663,9 +676,9 @@ private Ternary createTemplateFromVolume(VirtualMachineMO vm } private Ternary createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName, String secStorageUrl, long volumeId, - String backedUpSnapshotUuid) throws Exception { + String backedUpSnapshotUuid, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl @@ -847,16 +860,16 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, long accountId, long volumeId, - String secStorageUrl, String snapshotBackupUuid) throws Exception { + String secStorageUrl, String snapshotBackupUuid, String nfsVersion) throws Exception { - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid, nfsVersion); return null; } private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName) throws Exception { + String backupName, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String srcOVAFileName = secondaryMountPoint + "/" + secStorageDir + "/" + backupName + "." + ImageFormat.OVA.getFileExtension(); String snapshotDir = ""; if (backupName.contains("/")) { @@ -914,17 +927,17 @@ private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, Datasto } private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long accountId, long volumeId, String volumePath, String snapshotUuid, String secStorageUrl, - String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { + String prevSnapshotUuid, String prevBackupUuid, String workerVmName, String nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName, nfsVersion); return backupUuid + "/" + backupUuid; } private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, String exportName, - String workerVmName) throws Exception { + String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -967,7 +980,7 @@ private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volume } private Pair copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd, String vmName, - long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName) throws Exception { + long volumeId, String poolId, String volumePath, String secStorageUrl, String workerVmName, String nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; VirtualMachineMO workerVm = null; @@ -1004,7 +1017,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, "volumes/" + volumeFolder, exportName, - hostService.getWorkerName(hyperHost.getContext(), cmd, 1)); + hostService.getWorkerName(hyperHost.getContext(), cmd, 1), nfsVersion); return new Pair(volumeFolder, exportName); } finally { @@ -1025,12 +1038,12 @@ private String getVolumePathInDatastore(DatastoreMO dsMo, String volumeFileName) return datastoreVolumePath; } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName) + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, DatastoreMO dsMo, String secStorageUrl, String exportName, String nfsVersion) throws Exception { String volumeFolder = String.valueOf(volumeId) + "/"; String newVolume = UUID.randomUUID().toString().replaceAll("-", ""); - restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName); + restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName, nfsVersion); return new Pair(volumeFolder, newVolume); } @@ -1445,8 +1458,8 @@ public RevertToVMSnapshotAnswer execute(VmwareHostService hostService, RevertToV } } - private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl) throws Exception { - String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); + private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl, String nfsVersion) throws Exception { + String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + "/" + getVolumeRelativeDirInSecStroage(volumeId); return deleteDir(volumeMountRoot); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java index dd07029766c4..54b52f6dff4c 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java @@ -17,5 +17,5 @@ package com.cloud.hypervisor.vmware.manager; public interface VmwareStorageMount { - String getMountPoint(String storageUrl); + String getMountPoint(String storageUrl, String nfsVersion); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index fdbc244997d0..e71425b9488f 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1636,12 +1636,14 @@ protected StartAnswer execute(StartCommand cmd) { // prepare systemvm patch ISO if (vmSpec.getType() != VirtualMachine.Type.User) { // attach ISO (for patching of system VM) - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); if (morSecDs == null) { @@ -3134,12 +3136,14 @@ protected Answer execute(PrepareForMigrationCommand cmd) { prepareNetworkFromNicInfo(new HostMO(getServiceContext(), _morHyperHost), nic, false, cmd.getVirtualMachine().getType()); } - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnHost(secStoreUrl); if (morSecDs == null) { @@ -3350,12 +3354,14 @@ protected Answer execute(MigrateWithStorageCommand cmd) { } // Ensure secondary storage mounted on target host - String secStoreUrl = mgr.getSecondaryStorageStoreUrl(Long.parseLong(_dcId)); + Pair secStoreUrlAndId = mgr.getSecondaryStorageStoreUrlAndId(Long.parseLong(_dcId)); + String secStoreUrl = secStoreUrlAndId.first(); + Long secStoreId = secStoreUrlAndId.second(); if (secStoreUrl == null) { String msg = "secondary storage for dc " + _dcId + " is not ready yet?"; throw new Exception(msg); } - mgr.prepareSecondaryStorageStore(secStoreUrl); + mgr.prepareSecondaryStorageStore(secStoreUrl, secStoreId); ManagedObjectReference morSecDs = prepareSecondaryDatastoreOnSpecificHost(secStoreUrl, tgtHyperHost); if (morSecDs == null) { String msg = "Failed to prepare secondary storage on host, secondary store url: " + secStoreUrl; @@ -5191,8 +5197,8 @@ else if (value != null && value.equalsIgnoreCase("ide")) value = (String)params.get("scripts.timeout"); int timeout = NumbersUtil.parseInt(value, 1440) * 1000; - _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null); - storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor); + _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null, (String)params.get("nfsVersion")); + storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, (String)params.get("nfsVersion")); _vrResource = new VirtualRoutingResource(this); if (!_vrResource.configure(name, params)) { diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java index 8e4a0d2a83db..1ec4958509bc 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/PremiumSecondaryStorageResource.java @@ -102,7 +102,7 @@ public boolean configure(String name, Map params) throws Configu VmwareSecondaryStorageContextFactory.initFactoryEnvironment(); } - registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this)); + registerHandler(Hypervisor.HypervisorType.VMware, new VmwareSecondaryStorageResourceHandler(this, (String)params.get("nfsVersion"))); return true; } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java index 8a277991aac6..3c4e6340d31f 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -66,13 +66,13 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe * private Map _activeHosts = new HashMap(); */ - public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource) { + public VmwareSecondaryStorageResourceHandler(PremiumSecondaryStorageResource resource, String nfsVersion) { _resource = resource; - _storageMgr = new VmwareStorageManagerImpl(this); + _storageMgr = new VmwareStorageManagerImpl(this, nfsVersion); _gson = GsonHelper.getGsonLogger(); - VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource); - VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor); + VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor(this, true, this, resource.getTimeout(), null, null, _resource, nfsVersion); + VmwareStorageSubsystemCommandHandler vmwareStorageSubsystemCommandHandler = new VmwareStorageSubsystemCommandHandler(storageProcessor, nfsVersion); vmwareStorageSubsystemCommandHandler.setStorageResource(_resource); vmwareStorageSubsystemCommandHandler.setStorageManager(_storageMgr); storageSubsystemHandler = vmwareStorageSubsystemCommandHandler; @@ -304,7 +304,7 @@ public String getWorkerName(VmwareContext context, Command cmd, int workerSequen } @Override - public String getMountPoint(String storageUrl) { - return _resource.getRootDir(storageUrl); + public String getMountPoint(String storageUrl, String nfsVersion) { + return _resource.getRootDir(storageUrl, nfsVersion); } } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index fa2f369afaf6..ffa839d4598a 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -109,6 +109,7 @@ import com.cloud.vm.VmDetailConstants; public class VmwareStorageProcessor implements StorageProcessor { + private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); private static final int DEFAULT_NFS_PORT = 2049; @@ -120,9 +121,10 @@ public class VmwareStorageProcessor implements StorageProcessor { protected Integer _shutdownWaitMs; private final Gson _gson; private final StorageLayer _storage = new JavaStorageLayer(); + private String _nfsVersion; public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFlag, VmwareStorageMount mountService, Integer timeout, VmwareResource resource, - Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource) { + Integer shutdownWaitMs, PremiumSecondaryStorageResource storageResource, String nfsVersion) { this.hostService = hostService; _fullCloneFlag = fullCloneFlag; this.mountService = mountService; @@ -130,6 +132,7 @@ public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFl this.resource = resource; _shutdownWaitMs = shutdownWaitMs; _gson = GsonHelper.getGsonLogger(); + _nfsVersion = nfsVersion; } @Override @@ -155,12 +158,12 @@ private String getOVFFilePath(String srcOVAFileName) { } private VirtualMachineMO copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid, boolean createSnapshot, String nfsVersion) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage + ", templateName: " + templateName); - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, nfsVersion); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); String srcOVAFileName = @@ -316,7 +319,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { if (managed) { VirtualMachineMO vmMo = copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - managedStoragePoolRootVolumeName, false); + managedStoragePoolRootVolumeName, false, _nfsVersion); vmMo.unregisterVm(); @@ -333,7 +336,7 @@ public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) { } else { copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName, true); + templateUuidName, true, _nfsVersion); } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); @@ -518,7 +521,7 @@ public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) { } } - private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait) throws Exception { + private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, String srcVolumePath, DatastoreMO dsMo, String secStorageUrl, long wait, String nfsVersion) throws Exception { String volumeFolder = null; String volumeName = null; @@ -533,13 +536,13 @@ private Pair copyVolumeFromSecStorage(VmwareHypervisorHost hyper } String newVolume = VmwareHelper.getVCenterSafeUuid(); - restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait); + restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName, wait, nfsVersion); return new Pair(volumeFolder, newVolume); } - private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + private String deleteVolumeDirOnSecondaryStorage(String volumeDir, String secStorageUrl, String nfsVersion) throws Exception { + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String volumeMountRoot = secondaryMountPoint + File.separator + volumeDir; return deleteDir(volumeMountRoot); @@ -578,8 +581,8 @@ public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) { } } - Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000); - deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl()); + Pair result = copyVolumeFromSecStorage(hyperHost, srcVolume.getPath(), new DatastoreMO(context, morDatastore), srcStore.getUrl(), (long)cmd.getWait() * 1000, _nfsVersion); + deleteVolumeDirOnSecondaryStorage(result.first(), srcStore.getUrl(), _nfsVersion); VolumeObjectTO newVolume = new VolumeObjectTO(); newVolume.setPath(result.second()); return new CopyCmdAnswer(newVolume); @@ -636,7 +639,7 @@ private Pair copyVolumeToSecStorage(VmwareHostService hostServic vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false); - exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1)); + exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, destVolumePath, exportName, hostService.getWorkerName(hyperHost.getContext(), cmd, 1), _nfsVersion); return new Pair(destVolumePath, exportName); } finally { @@ -720,9 +723,9 @@ private void postCreatePrivateTemplate(String installFullPath, long templateId, } private Ternary createTemplateFromVolume(VirtualMachineMO vmMo, String installPath, long templateId, String templateUniqueName, - String secStorageUrl, String volumePath, String workerVmName) throws Exception { + String secStorageUrl, String volumePath, String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; synchronized (installPath.intern()) { Script command = new Script(false, "mkdir", _timeout, s_logger); @@ -838,7 +841,7 @@ public Answer createTemplateFromVolume(CopyCommand cmd) { Ternary result = createTemplateFromVolume(vmMo, template.getPath(), template.getId(), template.getName(), secondaryStoragePoolURL, volumePath, - hostService.getWorkerName(context, cmd, 0)); + hostService.getWorkerName(context, cmd, 0), _nfsVersion); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -885,7 +888,7 @@ private void writeMetaOvaForTemplate(String installFullPath, String ovfFilename, } private Ternary createTemplateFromSnapshot(String installPath, String templateUniqueName, String secStorageUrl, String snapshotPath, - Long templateId, long wait) throws Exception { + Long templateId, long wait, String nfsVersion) throws Exception { //Snapshot path is decoded in this form: /snapshots/account/volumeId/uuid/uuid String backupSSUuid; String snapshotFolder; @@ -899,7 +902,7 @@ private Ternary createTemplateFromSnapshot(String installPat snapshotFolder = StringUtils.join(tokens, File.separator, 0, tokens.length - 1); } - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String installFullPath = secondaryMountPoint + "/" + installPath; String installFullOVAName = installFullPath + "/" + templateUniqueName + ".ova"; //Note: volss for tmpl String snapshotRoot = secondaryMountPoint + "/" + snapshotFolder; @@ -1029,7 +1032,7 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { } NfsTO nfsSvr = (NfsTO)imageStore; - Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000); + Ternary result = createTemplateFromSnapshot(template.getPath(), uniqeName, nfsSvr.getUrl(), snapshot.getPath(), template.getId(), (long)cmd.getWait() * 1000, _nfsVersion); TemplateObjectTO newTemplate = new TemplateObjectTO(); newTemplate.setPath(result.first()); @@ -1052,9 +1055,9 @@ public Answer createTemplateFromSnapshot(CopyCommand cmd) { // return Pair private Pair exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath, String secStorageUrl, String secStorageDir, - String exportName, String workerVmName) throws Exception { + String exportName, String workerVmName, String nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, nfsVersion); String exportPath = secondaryMountPoint + "/" + secStorageDir + "/" + exportName; synchronized (exportPath.intern()) { @@ -1096,10 +1099,10 @@ private Pair exportVolumeToSecondaryStroage(VirtualMachineMO v // Ternary private Ternary backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath, String volumePath, String snapshotUuid, - String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception { + String secStorageUrl, String prevSnapshotUuid, String prevBackupUuid, String workerVmName, String nfsVersion) throws Exception { String backupUuid = UUID.randomUUID().toString(); - Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName); + Pair snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, installPath, backupUuid, workerVmName, nfsVersion); return new Ternary(backupUuid, snapshotInfo.first(), snapshotInfo.second()); } @@ -1174,7 +1177,7 @@ public Answer backupSnapshot(CopyCommand cmd) { backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, - prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1)); + prevSnapshotUuid, prevBackupUuid, hostService.getWorkerName(context, cmd, 1), _nfsVersion); snapshotBackupUuid = backupResult.first(); success = (snapshotBackupUuid != null); @@ -1186,7 +1189,7 @@ public Answer backupSnapshot(CopyCommand cmd) { // Get snapshot physical size long physicalSize = 0l; - String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl, _nfsVersion); String snapshotDir = destSnapshot.getPath() + "/" + snapshotBackupUuid; File[] files = new File(secondaryMountPoint + "/" + snapshotDir).listFiles(); if(files != null) { @@ -2144,9 +2147,9 @@ private List getManagedIqnsFromVirtualDisks(List virtualDis } private Long restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, String secStorageUrl, String secStorageDir, - String backupName, long wait) throws Exception { + String backupName, long wait, String nfsVersion) throws Exception { - String secondaryMountPoint = mountService.getMountPoint(secStorageUrl); + String secondaryMountPoint = mountService.getMountPoint(secStorageUrl, null); String srcOVAFileName = null; String srcOVFFileName = null; @@ -2248,7 +2251,7 @@ public Answer createVolumeFromSnapshot(CopyCommand cmd) { backedUpSnapshotUuid = backedUpSnapshotUuid.replace(".ovf", ""); } DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs); - restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000); + restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, secondaryStorageUrl, backupPath, backedUpSnapshotUuid, (long)cmd.getWait() * 1000, _nfsVersion); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(newVolumeName); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java index 431286248b2d..40fa47b03bb3 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageSubsystemCommandHandler.java @@ -21,7 +21,6 @@ import java.io.File; import org.apache.log4j.Logger; - import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.DeleteCommand; @@ -40,9 +39,11 @@ import com.cloud.storage.DataStoreRole; public class VmwareStorageSubsystemCommandHandler extends StorageSubsystemCommandHandlerBase { + private static final Logger s_logger = Logger.getLogger(VmwareStorageSubsystemCommandHandler.class); private VmwareStorageManager storageManager; private PremiumSecondaryStorageResource storageResource; + private String _nfsVersion; public PremiumSecondaryStorageResource getStorageResource() { return storageResource; @@ -60,8 +61,9 @@ public void setStorageManager(VmwareStorageManager storageManager) { this.storageManager = storageManager; } - public VmwareStorageSubsystemCommandHandler(StorageProcessor processor) { + public VmwareStorageSubsystemCommandHandler(StorageProcessor processor, String nfsVersion) { super(processor); + this._nfsVersion = nfsVersion; } @Override @@ -82,7 +84,7 @@ protected Answer execute(CopyCommand cmd) { //need to take extra processing for vmware, such as packing to ova, before sending to S3 if (srcData.getObjectType() == DataObjectType.VOLUME) { NfsTO cacheStore = (NfsTO)srcDataStore; - String parentPath = storageResource.getRootDir(cacheStore.getUrl()); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion); VolumeObjectTO vol = (VolumeObjectTO)srcData; String path = vol.getPath(); int index = path.lastIndexOf(File.separator); @@ -95,7 +97,7 @@ protected Answer execute(CopyCommand cmd) { } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT) { // pack ova first // sync snapshot from NFS cache to S3 in NFS migration to S3 case - String parentPath = storageResource.getRootDir(srcDataStore.getUrl()); + String parentPath = storageResource.getRootDir(srcDataStore.getUrl(), _nfsVersion); SnapshotObjectTO snap = (SnapshotObjectTO)srcData; String path = snap.getPath(); int index = path.lastIndexOf(File.separator); @@ -138,7 +140,7 @@ protected Answer execute(CopyCommand cmd) { return answer; } NfsTO cacheStore = (NfsTO)cmd.getCacheTO().getDataStore(); - String parentPath = storageResource.getRootDir(cacheStore.getUrl()); + String parentPath = storageResource.getRootDir(cacheStore.getUrl(), _nfsVersion); SnapshotObjectTO newSnapshot = (SnapshotObjectTO)answer.getNewData(); String path = newSnapshot.getPath(); int index = path.lastIndexOf(File.separator); diff --git a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java index 3b3dd4794991..fec2aba40f64 100644 --- a/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java +++ b/plugins/hypervisors/vmware/test/com/cloud/hypervisor/vmware/VmwareDatacenterApiUnitTest.java @@ -25,18 +25,19 @@ import java.util.UUID; import javax.inject.Inject; -import javax.naming.ConfigurationException; import com.cloud.user.User; + import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; @@ -48,12 +49,13 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; - import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.RemoveVmwareDcCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.test.utils.SpringUtils; import com.cloud.agent.AgentManager; @@ -86,6 +88,7 @@ import com.cloud.org.Managed.ManagedState; import com.cloud.secstorage.CommandExecLogDao; import com.cloud.server.ConfigurationServer; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -98,6 +101,7 @@ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class) +@PrepareForTest({ComponentContext.class, ApplicationContext.class}) public class VmwareDatacenterApiUnitTest { @Inject @@ -155,10 +159,6 @@ public class VmwareDatacenterApiUnitTest { @Mock private static RemoveVmwareDcCmd removeCmd; - @BeforeClass - public static void setUp() throws ConfigurationException { - } - @Before public void testSetUp() { Mockito.when(_configDao.isPremium()).thenReturn(true); @@ -431,6 +431,22 @@ public DataStoreManager dataStoreManager() { return Mockito.mock(DataStoreManager.class); } + @Bean + public ImageStoreDetailsUtil imageStoreDetailsUtil() { + return Mockito.mock(ImageStoreDetailsUtil.class); + } + + //Mocks for ImageStoreDetailsUtil + @Bean + public ImageStoreDao imageStoreDao() { + return Mockito.mock(ImageStoreDao.class); + } + + @Bean + public ImageStoreDetailsDao imageStoreDetailsDao() { + return Mockito.mock(ImageStoreDetailsDao.class); + } + public static class Library implements TypeFilter { @Override diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index ca86cfd08049..0702335308da 100644 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -36,7 +36,6 @@ import org.apache.cloudstack.utils.usage.UsageUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; @@ -90,6 +89,7 @@ import com.cloud.resource.ResourceState; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.StorageManager; import com.cloud.storage.StorageStats; import com.cloud.storage.VolumeStats; @@ -198,6 +198,8 @@ public String toString() { private ServiceOfferingDao _serviceOfferingDao; @Inject private HostGpuGroupsDao _hostGpuGroupsDao; + @Inject + private ImageStoreDetailsUtil imageStoreDetailsUtil; private ConcurrentHashMap _hostStats = new ConcurrentHashMap(); private final ConcurrentHashMap _VmStats = new ConcurrentHashMap(); @@ -715,7 +717,7 @@ protected void runInContext() { continue; } - GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO()); + GetStorageStatsCommand command = new GetStorageStatsCommand(store.getTO(), imageStoreDetailsUtil.getNfsVersion(store.getId())); EndPoint ssAhost = _epSelector.select(store); if (ssAhost == null) { s_logger.debug("There is no secondary storage VM for secondary storage host " + store.getName()); @@ -762,6 +764,7 @@ protected void runInContext() { s_logger.error("Error trying to retrieve storage stats", t); } } + } class AutoScaleMonitor extends ManagedContextRunnable { diff --git a/server/src/com/cloud/storage/ImageStoreDetailsUtil.java b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java new file mode 100755 index 000000000000..63bd5c54d67d --- /dev/null +++ b/server/src/com/cloud/storage/ImageStoreDetailsUtil.java @@ -0,0 +1,67 @@ +// 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.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; + +public class ImageStoreDetailsUtil { + + @Inject + protected ImageStoreDao imageStoreDao; + @Inject + protected ImageStoreDetailsDao imageStoreDetailsDao; + + /** + * Obtain NFS protocol version (if provided) for a store id.
+ * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3) + * @param storeId image store id + * @return {@code null} if {@code nfs.version} is not found for storeId
+ * {@code X} if {@code nfs.version} is found found for storeId + */ + public String getNfsVersion(long storeId) { + String nfsVersion = null; + if (imageStoreDetailsDao.getDetails(storeId) != null){ + Map storeDetails = imageStoreDetailsDao.getDetails(storeId); + if (storeDetails != null && storeDetails.containsKey("nfs.version")){ + nfsVersion = storeDetails.get("nfs.version"); + } + } + return nfsVersion; + } + + /** + * Obtain NFS protocol version (if provided) for a store uuid.
+ * It can be set by adding an entry in {@code image_store_details} table, providing {@code name=nfs.version} and {@code value=X} (e.g. 3) + * @param storeId image store id + * @return {@code null} if {@code nfs.version} is not found for storeUuid
+ * {@code X} if {@code nfs.version} is found found for storeUuid + */ + public String getNfsVersionByUuid(String storeUuid){ + ImageStoreVO imageStore = imageStoreDao.findByUuid(storeUuid); + if (imageStore != null){ + return getNfsVersion(imageStore.getId()); + } + return null; + } + +} diff --git a/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java new file mode 100755 index 000000000000..026a7d346d2e --- /dev/null +++ b/server/test/com/cloud/storage/ImageStoreDetailsUtilTest.java @@ -0,0 +1,95 @@ +// 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; +import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; +import org.junit.Before; +import org.junit.Test; + +public class ImageStoreDetailsUtilTest { + + private final static long STORE_ID = 1l; + private final static String STORE_UUID = "aaaa-aaaa-aaaa-aaaa"; + private final static String NFS_VERSION = "3"; + + ImageStoreDetailsUtil imageStoreDetailsUtil = new ImageStoreDetailsUtil(); + + ImageStoreDao imgStoreDao = mock(ImageStoreDao.class); + ImageStoreDetailsDao imgStoreDetailsDao = mock(ImageStoreDetailsDao.class); + + @Before + public void setup() throws Exception { + Map imgStoreDetails = new HashMap(); + imgStoreDetails.put("nfs.version", NFS_VERSION); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + ImageStoreVO imgStoreVO = mock(ImageStoreVO.class); + when(imgStoreVO.getId()).thenReturn(Long.valueOf(STORE_ID)); + when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(imgStoreVO); + + imageStoreDetailsUtil.imageStoreDao = imgStoreDao; + imageStoreDetailsUtil.imageStoreDetailsDao = imgStoreDetailsDao; + } + + @Test + public void testGetNfsVersion(){ + String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertEquals(NFS_VERSION, nfsVersion); + } + + @Test + public void testGetNfsVersionNotFound(){ + Map imgStoreDetails = new HashMap(); + imgStoreDetails.put("other.prop", "propValue"); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertNull(nfsVersion); + } + + @Test + public void testGetNfsVersionNoDetails(){ + Map imgStoreDetails = new HashMap(); + when(imgStoreDetailsDao.getDetails(STORE_ID)).thenReturn(imgStoreDetails); + + String nfsVersion = imageStoreDetailsUtil.getNfsVersion(STORE_ID); + assertNull(nfsVersion); + } + + @Test + public void testGetNfsVersionByUuid(){ + String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + assertEquals(NFS_VERSION, nfsVersion); + } + + @Test + public void testGetNfsVersionByUuidNoImgStore(){ + when(imgStoreDao.findByUuid(STORE_UUID)).thenReturn(null); + String nfsVersion = imageStoreDetailsUtil.getNfsVersionByUuid(STORE_UUID); + assertNull(nfsVersion); + } +} \ No newline at end of file diff --git a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java index 4891b71967ac..2ff54c8dc9a7 100644 --- a/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java +++ b/services/secondary-storage/controller/src/org/apache/cloudstack/secondarystorage/SecondaryStorageManagerImpl.java @@ -101,6 +101,7 @@ import com.cloud.resource.UnableDeleteHostException; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.ImageStoreDetailsUtil; import com.cloud.storage.Storage; import com.cloud.storage.UploadVO; import com.cloud.storage.VMTemplateVO; @@ -239,6 +240,8 @@ public class SecondaryStorageManagerImpl extends ManagerBase implements Secondar TemplateDataStoreDao _tmplStoreDao; @Inject VolumeDataStoreDao _volumeStoreDao; + @Inject + private ImageStoreDetailsUtil imageStoreDetailsUtil; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private int _secStorageVmMtuSize; @@ -310,6 +313,8 @@ public boolean generateSetupCommand(Long ssHostId) { setupCmd = new SecStorageSetupCommand(ssStore.getTO(), secUrl, certs); } + setupCmd.setNfsVersion(imageStoreDetailsUtil.getNfsVersion(ssStore.getId())); + //template/volume file upload key String postUploadKey = _configDao.getValue(Config.SSVMPSK.key()); setupCmd.setPostUploadKey(postUploadKey); @@ -1046,7 +1051,6 @@ private String getSecStorageVmLockName(long id) { @Override public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, DeployDestination dest, ReservationContext context) { - SecondaryStorageVmVO vm = _secStorageVmDao.findById(profile.getId()); Map details = _vmDetailsDao.listDetailsKeyPairs(vm.getId()); vm.setDetails(details); @@ -1131,6 +1135,8 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl if (dc.getDns2() != null) { buf.append(" dns2=").append(dc.getDns2()); } + String nfsVersion = imageStoreDetailsUtil != null ? imageStoreDetailsUtil.getNfsVersion(secStore.getId()) : null; + buf.append(" nfsVersion=").append(nfsVersion); String bootArgs = buf.toString(); if (s_logger.isDebugEnabled()) { @@ -1430,4 +1436,5 @@ public List getSecondaryStorageVmAllocators() { public void setSecondaryStorageVmAllocators(List ssVmAllocators) { _ssVmAllocators = ssVmAllocators; } + } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java index 9393ee217a10..6f189ef5f3c6 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalNfsSecondaryStorageResource.java @@ -53,10 +53,10 @@ public Answer executeRequest(Command cmd) { } @Override - synchronized public String getRootDir(String secUrl) { + synchronized public String getRootDir(String secUrl, String nfsVersion) { try { URI uri = new URI(secUrl); - String dir = mountUri(uri); + String dir = mountUri(uri, nfsVersion); return _parent + "/" + dir; } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -66,14 +66,14 @@ synchronized public String getRootDir(String secUrl) { } @Override - protected void mount(String localRootPath, String remoteDevice, URI uri) { + protected void mount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { return; } - attemptMount(localRootPath, remoteDevice, uri); + attemptMount(localRootPath, remoteDevice, uri, nfsVersion); // Change permissions for the mountpoint - seems to bypass authentication Script script = new Script(true, "chmod", _timeout, s_logger); diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java index bdfe7e837f26..d953338c911d 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/LocalSecondaryStorageResource.java @@ -72,7 +72,7 @@ public void disconnected() { } @Override - public String getRootDir(String url) { + public String getRootDir(String url, String nfsVersion) { return getRootDir(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java index 768a177cdc52..663699aad2e8 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java @@ -52,6 +52,7 @@ import com.cloud.utils.EncryptionUtil; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; @@ -65,6 +66,7 @@ import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; + import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand; import org.apache.cloudstack.storage.template.UploadEntity; import org.apache.cloudstack.utils.imagestore.ImageStoreUtil; @@ -161,6 +163,7 @@ import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; import com.cloud.vm.SecondaryStorageVm; + import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; @@ -205,6 +208,7 @@ public void setTimeout(int timeout) { private String _storageIp; private String _storageNetmask; private String _storageGateway; + private String _nfsVersion; private final List nfsIps = new ArrayList(); protected String _parent = "/mnt/SecStorage"; final private String _tmpltpp = "template.properties"; @@ -352,7 +356,7 @@ protected Answer copyFromSwiftToNfs(CopyCommand cmd, DataTO srcData, SwiftTO swi final String storagePath = destImageStore.getUrl(); final String destPath = destData.getPath(); try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _nfsVersion); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -379,7 +383,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT try { - String downloadPath = determineStorageTemplatePath(storagePath, destPath); + String downloadPath = determineStorageTemplatePath(storagePath, destPath, _nfsVersion); final File downloadDirectory = _storage.getFile(downloadPath); if (downloadDirectory.exists()) { @@ -412,7 +416,7 @@ protected Answer copyFromS3ToNfs(CopyCommand cmd, DataTO srcData, S3TO s3, DataT protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, SnapshotObjectTO srcData, NfsTO srcDataStore, TemplateObjectTO destData, NfsTO destDataStore) { - String srcMountPoint = getRootDir(srcDataStore.getUrl()); + String srcMountPoint = getRootDir(srcDataStore.getUrl(), _nfsVersion); String snapshotPath = srcData.getPath(); int index = snapshotPath.lastIndexOf("/"); String snapshotName = snapshotPath.substring(index + 1); @@ -422,7 +426,7 @@ protected Answer copySnapshotToTemplateFromNfsToNfsXenserver(CopyCommand cmd, Sn snapshotPath = snapshotPath.substring(0, index); snapshotPath = srcMountPoint + File.separator + snapshotPath; - String destMountPoint = getRootDir(destDataStore.getUrl()); + String destMountPoint = getRootDir(destDataStore.getUrl(), _nfsVersion); String destPath = destMountPoint + File.separator + destData.getPath(); String errMsg = null; @@ -480,8 +484,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj if (srcData.getHypervisorType() == HypervisorType.XenServer) { return copySnapshotToTemplateFromNfsToNfsXenserver(cmd, srcData, srcDataStore, destData, destDataStore); } else if (srcData.getHypervisorType() == HypervisorType.KVM) { - File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl()); - File destFile = getFile(destData.getPath(), destDataStore.getUrl()); + File srcFile = getFile(srcData.getPath(), srcDataStore.getUrl(), _nfsVersion); + File destFile = getFile(destData.getPath(), destDataStore.getUrl(), _nfsVersion); VolumeObjectTO volumeObjectTO = srcData.getVolume(); ImageFormat srcFormat = null; @@ -565,8 +569,8 @@ protected Answer copySnapshotToTemplateFromNfsToNfs(CopyCommand cmd, SnapshotObj return new CopyCmdAnswer(""); } - protected File getFile(String path, String nfsPath) { - String filePath = getRootDir(nfsPath) + File.separator + path; + protected File getFile(String path, String nfsPath, String nfsVersion) { + String filePath = getRootDir(nfsPath, nfsVersion) + File.separator + path; File f = new File(filePath); if (!f.exists()) { _storage.mkdirs(filePath); @@ -598,7 +602,7 @@ protected Answer createTemplateFromSnapshot(CopyCommand cmd) { } s_logger.debug("starting copy template to swift"); DataTO newTemplate = answer.getNewData(); - File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl()); + File templateFile = getFile(newTemplate.getPath(), ((NfsTO)srcDataStore).getUrl(), _nfsVersion); SwiftTO swift = (SwiftTO)destDataStore; String containterName = SwiftUtil.getContainerName(destData.getObjectType().toString(), destData.getId()); String swiftPath = SwiftUtil.putObject(swift, templateFile, containterName, templateFile.getName()); @@ -705,8 +709,8 @@ protected Long determineS3VolumeIdFromKey(String key) { return Long.parseLong(StringUtils.substringAfterLast(StringUtils.substringBeforeLast(key, S3Utils.SEPARATOR), S3Utils.SEPARATOR)); } - private String determineStorageTemplatePath(final String storagePath, String dataPath) { - return join(asList(getRootDir(storagePath), dataPath), File.separator); + private String determineStorageTemplatePath(final String storagePath, String dataPath, String nfsVersion) { + return join(asList(getRootDir(storagePath, nfsVersion), dataPath), File.separator); } protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String name) { @@ -720,7 +724,7 @@ protected File downloadFromUrlToNfs(String url, NfsTO nfs, String path, String n throw new CloudRuntimeException("Failed to get url: " + url); } - String nfsMountPath = getRootDir(nfs.getUrl()); + String nfsMountPath = getRootDir(nfs.getUrl(), _nfsVersion); String filePath = nfsMountPath + File.separator + path; File directory = new File(filePath); @@ -885,7 +889,7 @@ protected Answer copyFromNfsToS3(CopyCommand cmd) { final S3TO s3 = (S3TO)destDataStore; try { - final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath()); + final String templatePath = determineStorageTemplatePath(srcStore.getUrl(), srcData.getPath(), _nfsVersion); if (s_logger.isDebugEnabled()) { s_logger.debug("Found " + srcData.getObjectType() + " from directory " + templatePath + " to upload to S3."); @@ -1098,7 +1102,7 @@ public Answer execute(DeleteSnapshotsDirCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeSnapshotPath = cmd.getDirectory(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeSnapshotPath.startsWith(File.separator)) { relativeSnapshotPath = relativeSnapshotPath.substring(1); @@ -1176,7 +1180,7 @@ private Answer execute(ComputeChecksumCommand cmd) { return new Answer(cmd, false, "can't handle non nfs data store"); } NfsTO nfsStore = (NfsTO)store; - String parent = getRootDir(nfsStore.getUrl()); + String parent = getRootDir(nfsStore.getUrl(), _nfsVersion); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1310,7 +1314,8 @@ private Answer execute(SecStorageSetupCommand cmd) { String nfsHostIp = getUriHostIp(uri); addRouteToInternalIpOrCidr(_storageGateway, _storageIp, _storageNetmask, nfsHostIp); - String dir = mountUri(uri); + + String dir = mountUri(uri, cmd.getNfsVersion()); configCerts(cmd.getCerts()); @@ -1386,7 +1391,7 @@ protected Answer deleteSnapshot(final DeleteCommand cmd) { DataStoreTO dstore = obj.getDataStore(); if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (!parent.endsWith(File.separator)) { parent += File.separator; } @@ -1557,7 +1562,7 @@ private Answer execute(ListTemplateCommand cmd) { if (store instanceof NfsTO) { NfsTO nfs = (NfsTO)store; String secUrl = nfs.getUrl(); - String root = getRootDir(secUrl); + String root = getRootDir(secUrl, cmd.getNfsVersion()); Map templateInfos = _dlMgr.gatherTemplateInfo(root); return new ListTemplateAnswer(secUrl, templateInfos); } else if (store instanceof SwiftTO) { @@ -1579,7 +1584,7 @@ private Answer execute(ListVolumeCommand cmd) { } DataStoreTO store = cmd.getDataStore(); if (store instanceof NfsTO) { - String root = getRootDir(cmd.getSecUrl()); + String root = getRootDir(cmd.getSecUrl(), _nfsVersion); Map templateInfos = _dlMgr.gatherVolumeInfo(root); return new ListVolumeAnswer(cmd.getSecUrl(), templateInfos); } else if (store instanceof S3TO) { @@ -1714,7 +1719,7 @@ protected GetStorageStatsAnswer execute(final GetStorageStatsCommand cmd) { return new GetStorageStatsAnswer(cmd, infinity, 0L); } - String rootDir = getRootDir(((NfsTO)store).getUrl()); + String rootDir = getRootDir(((NfsTO)store).getUrl(), cmd.getNfsVersion()); final long usedSize = getUsedSize(rootDir); final long totalSize = getTotalSize(rootDir); if (usedSize == -1 || totalSize == -1) { @@ -1748,7 +1753,7 @@ protected Answer deleteTemplate(DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeTemplatePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeTemplatePath.startsWith(File.separator)) { relativeTemplatePath = relativeTemplatePath.substring(1); @@ -1852,7 +1857,7 @@ protected Answer deleteVolume(final DeleteCommand cmd) { if (dstore instanceof NfsTO) { NfsTO nfs = (NfsTO)dstore; String relativeVolumePath = obj.getPath(); - String parent = getRootDir(nfs.getUrl()); + String parent = getRootDir(nfs.getUrl(), _nfsVersion); if (relativeVolumePath.startsWith(File.separator)) { relativeVolumePath = relativeVolumePath.substring(1); @@ -1954,13 +1959,13 @@ protected Answer deleteVolume(final DeleteCommand cmd) { } @Override - synchronized public String getRootDir(String secUrl) { + synchronized public String getRootDir(String secUrl, String nfsVersion) { if (!_inSystemVM) { return _parent; } try { URI uri = new URI(secUrl); - String dir = mountUri(uri); + String dir = mountUri(uri, nfsVersion); return _parent + "/" + dir; } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -2117,6 +2122,7 @@ public boolean configure(String name, Map params) throws Configu startAdditionalServices(); _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); + _nfsVersion = (String)params.get("nfsVersion"); } try { @@ -2291,10 +2297,11 @@ private String configureIpFirewall(List ipList, boolean isAppend) { * @param uri * crresponding to the remote device. Will throw for unsupported * scheme. + * @param imgStoreId * @return name of folder in _parent that device was mounted. * @throws UnknownHostException */ - protected String mountUri(URI uri) throws UnknownHostException { + protected String mountUri(URI uri, String nfsVersion) throws UnknownHostException { String uriHostIp = getUriHostIp(uri); String nfsPath = uriHostIp + ":" + uri.getPath(); @@ -2312,7 +2319,7 @@ protected String mountUri(URI uri) throws UnknownHostException { s_logger.debug("Mounting device with nfs-style path of " + remoteDevice); } - mount(localRootPath, remoteDevice, uri); + mount(localRootPath, remoteDevice, uri, nfsVersion); return dir; } @@ -2340,15 +2347,15 @@ protected void umount(String localRootPath, URI uri) { s_logger.debug("Successfully umounted " + localRootPath); } - protected void mount(String localRootPath, String remoteDevice, URI uri) { - s_logger.debug("mount " + uri.toString() + " on " + localRootPath); + protected void mount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { + s_logger.debug("mount " + uri.toString() + " on " + localRootPath + ((nfsVersion != null) ? " nfsVersion="+nfsVersion : "")); ensureLocalRootPathExists(localRootPath, uri); if (mountExists(localRootPath, uri)) { return; } - attemptMount(localRootPath, remoteDevice, uri); + attemptMount(localRootPath, remoteDevice, uri, nfsVersion); // XXX: Adding the check for creation of snapshots dir here. Might have // to move it somewhere more logical later. @@ -2356,9 +2363,10 @@ protected void mount(String localRootPath, String remoteDevice, URI uri) { checkForVolumesDir(localRootPath); } - protected void attemptMount(String localRootPath, String remoteDevice, URI uri) { + protected void attemptMount(String localRootPath, String remoteDevice, URI uri, String nfsVersion) { String result; - s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri); + s_logger.debug("Make cmdline call to mount " + remoteDevice + " at " + localRootPath + " based on uri " + uri + + ((nfsVersion != null) ? " nfsVersion=" + nfsVersion : "")); Script command = new Script(!_inSystemVM, "mount", _timeout, s_logger); String scheme = uri.getScheme().toLowerCase(); @@ -2370,7 +2378,7 @@ protected void attemptMount(String localRootPath, String remoteDevice, URI uri) command.add("-o", "resvport"); } if (_inSystemVM) { - command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0"); + command.add("-o", "soft,timeo=133,retrans=2147483647,tcp,acdirmax=0,acdirmin=0" + ((nfsVersion != null) ? ",vers=" + nfsVersion : "")); } } else if (scheme.equals("cifs")) { String extraOpts = parseCifsMountOptions(uri); @@ -2647,7 +2655,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten //relative path with out ssvm mount info. uploadEntity.setTemplatePath(absolutePath); String dataStoreUrl = cmd.getDataTo(); - String installPathPrefix = this.getRootDir(dataStoreUrl) + File.separator + absolutePath; + String installPathPrefix = this.getRootDir(dataStoreUrl, cmd.getNfsVersion()) + File.separator + absolutePath; uploadEntity.setInstallPathPrefix(installPathPrefix); uploadEntity.setHvm(cmd.getRequiresHvm()); uploadEntity.setChksum(cmd.getChecksum()); @@ -2669,7 +2677,7 @@ public UploadEntity createUploadEntity(String uuid, String metadata, long conten } private synchronized void checkSecondaryStorageResourceLimit(TemplateOrVolumePostUploadCommand cmd, int contentLengthInGB) { - String rootDir = this.getRootDir(cmd.getDataTo()) + File.separator; + String rootDir = this.getRootDir(cmd.getDataTo(), cmd.getNfsVersion()) + File.separator; long accountId = cmd.getAccountId(); long accountTemplateDirSize = 0; @@ -2716,7 +2724,7 @@ private String getSnapshotPathForAccount(long accountId) { private boolean isOneTimePostUrlUsed(TemplateOrVolumePostUploadCommand cmd) { String uuid = cmd.getEntityUUID(); - String uploadPath = this.getRootDir(cmd.getDataTo()) + File.separator + cmd.getAbsolutePath(); + String uploadPath = this.getRootDir(cmd.getDataTo(), cmd.getNfsVersion()) + File.separator + cmd.getAbsolutePath(); return uploadEntityStateMap.containsKey(uuid) || new File(uploadPath).exists(); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java index 4d3f04819e84..3c24b6c6de3e 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/resource/SecondaryStorageResource.java @@ -23,6 +23,6 @@ */ public interface SecondaryStorageResource extends ServerResource { - String getRootDir(String cmd); + String getRootDir(String cmd, String nfsVersion); } diff --git a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java index 9cf37e56596c..affe8a716a72 100644 --- a/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java +++ b/services/secondary-storage/server/src/org/apache/cloudstack/storage/template/DownloadManagerImpl.java @@ -89,6 +89,8 @@ public class DownloadManagerImpl extends ManagerBase implements DownloadManager StorageLayer _storage; public Map _processors; + private String _nfsVersion; + public class Completion implements DownloadCompleteCallback { private final String jobId; @@ -708,7 +710,7 @@ public DownloadAnswer handleDownloadCommand(SecondaryStorageResource resource, D String installPathPrefix = cmd.getInstallPath(); // for NFS, we need to get mounted path if (dstore instanceof NfsTO) { - installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl()) + File.separator + installPathPrefix; + installPathPrefix = resource.getRootDir(((NfsTO)dstore).getUrl(), _nfsVersion) + File.separator + installPathPrefix; } String user = null; String password = null; @@ -982,6 +984,7 @@ public boolean configure(String name, Map params) throws Configu String inSystemVM = (String)params.get("secondary.storage.vm"); if (inSystemVM != null && "true".equalsIgnoreCase(inSystemVM)) { s_logger.info("DownloadManager: starting additional services since we are inside system vm"); + _nfsVersion = (String)params.get("nfsVersion"); startAdditionalServices(); blockOutgoingOnPrivate(); } diff --git a/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java b/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java index 13ddb3531a82..9da5c53a9034 100644 --- a/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java +++ b/services/secondary-storage/server/test/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResourceTest.java @@ -80,7 +80,7 @@ public void testMount() throws Exception { if (!sampleMount.isEmpty()) { s_logger.info("functional test, mount " + sampleMount); URI realMntUri = new URI(sampleMount); - String mntSubDir = resource.mountUri(realMntUri); + String mntSubDir = resource.mountUri(realMntUri, null); s_logger.info("functional test, umount " + mntSubDir); resource.umount(resource.getMountingRoot() + mntSubDir, realMntUri); } else {