From 1577e75a3def02e01b8e9b3bb8ab4595c95437c3 Mon Sep 17 00:00:00 2001 From: Mike Tutkowski Date: Sat, 29 Mar 2014 23:49:56 -0600 Subject: [PATCH] CLOUDSTACK-6170 (VMware root-disk support for managed storage) --- .../storage/to/PrimaryDataStoreTO.java | 1 + .../api/storage/PrimaryDataStoreInfo.java | 1 + .../storage/volume/VolumeServiceImpl.java | 6 +- .../vmware/manager/VmwareHostService.java | 5 + .../vmware/resource/VmwareResource.java | 15 ++- ...VmwareSecondaryStorageResourceHandler.java | 7 ++ .../resource/VmwareStorageProcessor.java | 115 +++++++++++++++--- .../resource/XenServerStorageProcessor.java | 2 +- .../hypervisor/vmware/mo/DatastoreMO.java | 17 +++ 9 files changed, 145 insertions(+), 24 deletions(-) diff --git a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index 6a5d6793312..29e53b0d958 100644 --- a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -27,6 +27,7 @@ import com.cloud.storage.Storage.StoragePoolType; public class PrimaryDataStoreTO implements DataStoreTO { public static final String MANAGED = PrimaryDataStore.MANAGED; public static final String STORAGE_HOST = PrimaryDataStore.STORAGE_HOST; + public static final String STORAGE_PORT = PrimaryDataStore.STORAGE_PORT; public static final String MANAGED_STORE_TARGET = PrimaryDataStore.MANAGED_STORE_TARGET; public static final String MANAGED_STORE_TARGET_ROOT_VOLUME = PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME; public static final String CHAP_INITIATOR_USERNAME = PrimaryDataStore.CHAP_INITIATOR_USERNAME; diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index bb9f2dad1ff..f08d9a45509 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -29,6 +29,7 @@ import com.cloud.storage.StoragePool; public interface PrimaryDataStoreInfo extends StoragePool { static final String MANAGED = "managed"; static final String STORAGE_HOST= "storageHost"; + static final String STORAGE_PORT = "storagePort"; static final String MANAGED_STORE_TARGET = "managedStoreTarget"; static final String MANAGED_STORE_TARGET_ROOT_VOLUME = "managedStoreTargetRootVolume"; static final String CHAP_INITIATOR_USERNAME = "chapInitiatorUsername"; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 68e5a5680e7..3a71147f8aa 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -527,7 +527,10 @@ public class VolumeServiceImpl implements VolumeService { TemplateObjectTO templateObjectTo = (TemplateObjectTO)answer.getNewData(); volume.setPath(templateObjectTo.getPath()); - volume.setFormat(templateObjectTo.getFormat()); + + if (templateObjectTo.getFormat() != null) { + volume.setFormat(templateObjectTo.getFormat()); + } volDao.update(volume.getId(), volume); } @@ -682,6 +685,7 @@ public class VolumeServiceImpl implements VolumeService { details.put(PrimaryDataStore.MANAGED, Boolean.TRUE.toString()); details.put(PrimaryDataStore.STORAGE_HOST, destPrimaryDataStore.getHostAddress()); + details.put(PrimaryDataStore.STORAGE_PORT, String.valueOf(destPrimaryDataStore.getPort())); // for managed storage, the storage repository (XenServer) or datastore (ESX) name is based off of the iScsiName property of a volume details.put(PrimaryDataStore.MANAGED_STORE_TARGET, volumeInfo.get_iScsiName()); details.put(PrimaryDataStore.MANAGED_STORE_TARGET_ROOT_VOLUME, volumeInfo.getName()); diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java index 91a03ca6098..db67b6b2213 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareHostService.java @@ -33,9 +33,14 @@ public interface VmwareHostService { String getWorkerName(VmwareContext context, Command cmd, int workerSequence); + ManagedObjectReference prepareManagedDatastore(VmwareHypervisorHost hyperHost, String iScsiName, + String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, + String chapTargetUsername, String chapTargetSecret) throws Exception; + ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName, String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception; + void handleDatastoreAndVmdkDetach(String iqn, String storageHost, int storagePort) throws Exception; void removeManagedTargetsFromCluster(List managedIqns) throws Exception; 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 85fe91b69cb..d3fcc069565 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1824,13 +1824,20 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.ensureScsiDeviceController(); } + @Override + public ManagedObjectReference prepareManagedDatastore(VmwareHypervisorHost hyperHost, String iScsiName, + String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, + String chapTargetUsername, String chapTargetSecret) throws Exception { + return getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), storageHost, storagePort, + VmwareResource.trimIqn(iScsiName), chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret); + } + @Override public ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName, String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, String chapTargetUsername, String chapTargetSecret, long size, Command cmd) throws Exception { - ManagedObjectReference morDs = getVmfsDatastore(hyperHost, VmwareResource.getDatastoreName(iScsiName), - storageHost, storagePort, VmwareResource.trimIqn(iScsiName), chapInitiatorUsername, chapInitiatorSecret, - chapTargetUsername, chapTargetSecret); + ManagedObjectReference morDs = prepareManagedDatastore(hyperHost, iScsiName, storageHost, storagePort, + chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret); DatastoreMO dsMo = new DatastoreMO(getServiceContext(null), morDs); @@ -1908,7 +1915,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa if (isManaged) { if (volumeTO.getVolumeType() == Volume.Type.ROOT) { - datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, dsMo.getName()); + datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, volumeTO.getName()); } else { datastoreDiskPath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk"); 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 baaaf217332..f23e74c18d4 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java @@ -314,6 +314,13 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe return _resource.getRootDir(storageUrl); } + @Override + public ManagedObjectReference prepareManagedDatastore(VmwareHypervisorHost hyperHost, String iScsiName, + String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, + String chapTargetUsername, String chapTargetSecret) throws Exception { + throw new OperationNotSupportedException(); + } + @Override public ManagedObjectReference prepareManagedStorage(VmwareHypervisorHost hyperHost, String iScsiName, String storageHost, int storagePort, String chapInitiatorUsername, String chapInitiatorSecret, 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 86e655467bd..b6639f4c004 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -188,44 +188,121 @@ public class VmwareStorageProcessor implements StorageProcessor { DataTO srcData = cmd.getSrcTO(); TemplateObjectTO template = (TemplateObjectTO)srcData; DataStoreTO srcStore = srcData.getDataStore(); + if (!(srcStore instanceof NfsTO)) { return new CopyCmdAnswer("unsupported protocol"); } + NfsTO nfsImageStore = (NfsTO)srcStore; DataTO destData = cmd.getDestTO(); DataStoreTO destStore = destData.getDataStore(); DataStoreTO primaryStore = destStore; + String secondaryStorageUrl = nfsImageStore.getUrl(); + assert (secondaryStorageUrl != null); + boolean managed = false; + String storageHost = null; + int storagePort = Integer.MIN_VALUE; + String managedStoragePoolName = null; + String managedStoragePoolRootVolumeName = null; + String chapInitiatorUsername = null; + String chapInitiatorSecret = null; + String chapTargetUsername = null; + String chapTargetSecret = null; + + if (destStore instanceof PrimaryDataStoreTO) { + PrimaryDataStoreTO destPrimaryDataStoreTo = (PrimaryDataStoreTO)destStore; + + Map details = destPrimaryDataStoreTo.getDetails(); + + if (details != null) { + managed = Boolean.parseBoolean(details.get(PrimaryDataStoreTO.MANAGED)); + + if (managed) { + storageHost = details.get(PrimaryDataStoreTO.STORAGE_HOST); + + try { + storagePort = Integer.parseInt(details.get(PrimaryDataStoreTO.STORAGE_PORT)); + } + catch (Exception ex) { + storagePort = 3260; + } + + managedStoragePoolName = details.get(PrimaryDataStoreTO.MANAGED_STORE_TARGET); + managedStoragePoolRootVolumeName = details.get(PrimaryDataStoreTO.MANAGED_STORE_TARGET_ROOT_VOLUME); + chapInitiatorUsername = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_USERNAME); + chapInitiatorSecret = details.get(PrimaryDataStoreTO.CHAP_INITIATOR_SECRET); + chapTargetUsername = details.get(PrimaryDataStoreTO.CHAP_TARGET_USERNAME); + chapTargetSecret = details.get(PrimaryDataStoreTO.CHAP_TARGET_SECRET); + } + } + } + String templateUrl = secondaryStorageUrl + "/" + srcData.getPath(); Pair templateInfo = VmwareStorageLayoutHelper.decodeTemplateRelativePathAndNameFromUrl(secondaryStorageUrl, templateUrl, template.getName()); VmwareContext context = hostService.getServiceContext(cmd); + try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); - - String templateUuidName = deriveTemplateUuidOnHost(hyperHost, primaryStore.getUuid(), templateInfo.second()); - + String storageUuid = managed ? managedStoragePoolName : primaryStore.getUuid(); + String templateUuidName = deriveTemplateUuidOnHost(hyperHost, storageUuid, templateInfo.second()); DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter()); VirtualMachineMO templateMo = VmwareHelper.pickOneVmOnRunningHost(dcMo.findVmByNameAndLabel(templateUuidName), true); + DatastoreMO dsMo = null; if (templateMo == null) { - if (s_logger.isInfoEnabled()) - s_logger.info("Template " + templateInfo.second() + " is not setup yet, setup template from secondary storage with uuid name: " + templateUuidName); - ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid()); - assert (morDs != null); - DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(context, morDs); + if (s_logger.isInfoEnabled()) { + s_logger.info("Template " + templateInfo.second() + " is not setup yet. Set up template from secondary storage with uuid name: " + templateUuidName); + } - copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), - templateUuidName); + final ManagedObjectReference morDs; + + if (managed) { + morDs = hostService.prepareManagedDatastore(hyperHost, managedStoragePoolName, storageHost, storagePort, + chapInitiatorUsername, chapInitiatorSecret, chapTargetUsername, chapTargetSecret); + } + else { + morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, storageUuid); + } + + assert (morDs != null); + + dsMo = new DatastoreMO(context, morDs); + + copyTemplateFromSecondaryToPrimary(hyperHost, dsMo, secondaryStorageUrl, templateInfo.first(), templateInfo.second(), + managed ? managedStoragePoolRootVolumeName : templateUuidName); + + if (managed) { + String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, managedStoragePoolRootVolumeName, managedStoragePoolRootVolumeName, + VmwareStorageLayoutType.VMWARE, false); + String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, managedStoragePoolRootVolumeName, + VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false); + + dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[0], dcMo.getMor(), true); + dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], dcMo.getMor(), dsMo.getMor(), legacyCloudStackLayoutFilePair[1], dcMo.getMor(), true); + + String folderToDelete = dsMo.getDatastorePath(managedStoragePoolRootVolumeName, true); + dsMo.deleteFolder(folderToDelete, dcMo.getMor()); + } } else { s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); } TemplateObjectTO newTemplate = new TemplateObjectTO(); - newTemplate.setPath(templateUuidName); + + if (managed) { + String path = dsMo.getDatastorePath(managedStoragePoolRootVolumeName + ".vmdk"); + + newTemplate.setPath(path); + } + else { + newTemplate.setPath(templateUuidName); + } + return new CopyCmdAnswer(newTemplate); } catch (Throwable e) { if (e instanceof RemoteException) { @@ -233,7 +310,9 @@ public class VmwareStorageProcessor implements StorageProcessor { } String msg = "Unable to copy template to primary storage due to exception:" + VmwareHelper.getExceptionMessage(e); + s_logger.error(msg, e); + return new CopyCmdAnswer(msg); } } @@ -1176,9 +1255,9 @@ public class VmwareStorageProcessor implements StorageProcessor { Map details = disk.getDetails(); morDs = hostService.prepareManagedStorage(hyperHost, iScsiName, storageHost, storagePort, - details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), - details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET), - volumeTO.getSize(), cmd); + details.get(DiskTO.CHAP_INITIATOR_USERNAME), details.get(DiskTO.CHAP_INITIATOR_SECRET), + details.get(DiskTO.CHAP_TARGET_USERNAME), details.get(DiskTO.CHAP_TARGET_SECRET), + volumeTO.getSize(), cmd); } else { morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid()); @@ -1572,15 +1651,15 @@ public class VmwareStorageProcessor implements StorageProcessor { VirtualDiskFlatVer2BackingInfo backingInfo = (VirtualDiskFlatVer2BackingInfo)virtualDisk.getBacking(); String path = backingInfo.getFileName(); - path = new DatastoreFile(path).getFileBaseName(); - - String search = "-"; + String search = "[-"; int index = path.indexOf(search); if (index > -1) { path = path.substring(index + search.length()); - index = path.lastIndexOf(search); + String search2 = "-0]"; + + index = path.lastIndexOf(search2); if (index > -1) { path = path.substring(0, index); diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java index 265d910a6de..e326770867f 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java @@ -911,7 +911,7 @@ public class XenServerStorageProcessor implements StorageProcessor { String chapInitiatorSecret = null; if (destDataStoreTo instanceof PrimaryDataStoreTO) { - PrimaryDataStoreTO destPrimaryDataStoreTo = (PrimaryDataStoreTO) destDataStoreTo; + PrimaryDataStoreTO destPrimaryDataStoreTo = (PrimaryDataStoreTO)destDataStoreTo; Map details = destPrimaryDataStoreTo.getDetails(); diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java index 363b91f9c68..7a1c28aab8c 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java @@ -142,6 +142,23 @@ public class DatastoreMO extends BaseMO { return path; } + public boolean deleteFolder(String folder, ManagedObjectReference morDc) throws Exception { + ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager(); + ManagedObjectReference morTask = _context.getService().deleteDatastoreFileTask(morFileManager, folder, morDc); + + boolean result = _context.getVimClient().waitForTask(morTask); + + if (result) { + _context.waitForTaskProgressDone(morTask); + + return true; + } else { + s_logger.error("VMware deleteDatastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + } + + return false; + } + public boolean deleteFile(String path, ManagedObjectReference morDc, boolean testExistence) throws Exception { String datastoreName = getName(); ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();