CLOUDSTACK-3869: Move VMware datastore folder structure policy management to central place
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/40869a5a Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/40869a5a Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/40869a5a Branch: refs/heads/master Commit: 40869a5a2ba26c5aea349b5e9149f115b0c3d540 Parents: 458de93 Author: Kelven Yang <[email protected]> Authored: Mon Aug 5 13:40:35 2013 -0700 Committer: Kelven Yang <[email protected]> Committed: Wed Sep 4 14:49:45 2013 -0700 ---------------------------------------------------------------------- .../manager/VmwareStorageManagerImpl.java | 29 --- .../vmware/resource/VmwareResource.java | 5 +- .../resource/VmwareStorageLayoutHelper.java | 126 ++++++++++ .../resource/VmwareStorageLayoutType.java | 22 ++ .../resource/VmwareStorageProcessor.java | 233 +++++++------------ .../cloud/hypervisor/vmware/mo/DatastoreMO.java | 29 ++- .../vmware/mo/HypervisorHostHelper.java | 35 ++- .../hypervisor/vmware/mo/VirtualMachineMO.java | 2 - .../hypervisor/vmware/util/VmwareHelper.java | 19 +- 9 files changed, 291 insertions(+), 209 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java ---------------------------------------------------------------------- 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 b84c0d4..36dbe15 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 @@ -1530,35 +1530,6 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager { } } - - private VirtualMachineMO createWorkingVM(DatastoreMO dsMo, VmwareHypervisorHost hyperHost) throws Exception { - String uniqueName = UUID.randomUUID().toString(); - VirtualMachineMO workingVM = null; - VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); - vmConfig.setName(uniqueName); - vmConfig.setMemoryMB((long) 4); - vmConfig.setNumCPUs(1); - vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.toString()); - VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo(); - fileInfo.setVmPathName(String.format("[%s]", dsMo.getName())); - vmConfig.setFiles(fileInfo); - - VirtualLsiLogicController scsiController = new VirtualLsiLogicController(); - scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); - scsiController.setBusNumber(0); - scsiController.setKey(1); - VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); - scsiControllerSpec.setDevice(scsiController); - scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - - vmConfig.getDeviceChange().add(scsiControllerSpec); - hyperHost.createVm(vmConfig); - workingVM = hyperHost.findVmOnHyperHost(uniqueName); - return workingVM; - } - - - private String deleteVolumeDirOnSecondaryStorage(long volumeId, String secStorageUrl) throws Exception { String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl); String volumeMountRoot = secondaryMountPoint + "/" + getVolumeRelativeDirInSecStroage(volumeId); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java ---------------------------------------------------------------------- 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 3e79792..05fb50d 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 @@ -310,6 +310,7 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Volume; import com.cloud.storage.resource.StoragePoolResource; import com.cloud.storage.resource.StorageSubsystemCommandHandler; +import com.cloud.storage.resource.VmwareStorageLayoutHelper; import com.cloud.storage.resource.VmwareStorageProcessor; import com.cloud.storage.resource.VmwareStorageSubsystemCommandHandler; import com.cloud.storage.template.TemplateProp; @@ -5364,7 +5365,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName); synchronized (this) { s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); - VmwareHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, -1); vmMo.detachDisk(volumeDatastorePath, false); } @@ -5422,7 +5423,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa synchronized (this) { // s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); - VmwareHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo); + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo); vmMo.createDisk(volumeDatastorePath, getMBsFromBytes(dskch.getSize()), morDatastore, vmMo.getScsiDeviceControllerKey()); vmMo.detachDisk(volumeDatastorePath, false); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java new file mode 100644 index 0000000..f538392 --- /dev/null +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java @@ -0,0 +1,126 @@ +// 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.resource; + +import com.cloud.hypervisor.vmware.mo.DatacenterMO; +import com.cloud.hypervisor.vmware.mo.DatastoreMO; +import com.cloud.utils.Pair; + +/** + * + * To provide helper methods to handle storage layout in one place + * + */ +public class VmwareStorageLayoutHelper { + + public static String[] getVmdkFilePairDatastorePath(DatastoreMO dsMo, String vmName, String vmdkName, + VmwareStorageLayoutType layoutType, boolean linkedVmdk) throws Exception { + + String[] filePair = new String[2]; + switch(layoutType) { + case VMWARE : + assert(vmName != null && !vmName.isEmpty()); + filePair[0] = String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmName, vmdkName); + + if(linkedVmdk) + filePair[1] = String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmName, vmdkName); + else + filePair[1] = String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmName, vmdkName); + return filePair; + + case CLOUDSTACK_LEGACY : + filePair[0] = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName); + + if(linkedVmdk) + filePair[1] = String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName); + else + filePair[1] = String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName); + return filePair; + + default : + assert(false); + break; + } + + assert(false); + return null; + } + + public static String getTemplateOnSecStorageFilePath(String secStorageMountPoint, String templateRelativeFolderPath, + String templateName, String fileExtension) { + + StringBuffer sb = new StringBuffer(); + sb.append(secStorageMountPoint); + if(!secStorageMountPoint.endsWith("/")) + sb.append("/"); + + sb.append(templateRelativeFolderPath); + if(!secStorageMountPoint.endsWith("/")) + sb.append("/"); + + sb.append(templateName); + if(!fileExtension.startsWith(".")) + sb.append("."); + sb.append(fileExtension); + + return sb.toString(); + } + + /* + * return Pair of <Template relative path, Template name> + * Template url may or may not end with .ova extension + */ + public static Pair<String, String> decodeTemplateRelativePathAndNameFromUrl(String storeUrl, String templateUrl, + String defaultName) { + + String templateName = null; + String mountPoint = null; + if (templateUrl.endsWith(".ova")) { + int index = templateUrl.lastIndexOf("/"); + mountPoint = templateUrl.substring(0, index); + mountPoint = mountPoint.substring(storeUrl.length() + 1); + if (!mountPoint.endsWith("/")) { + mountPoint = mountPoint + "/"; + } + + templateName = templateUrl.substring(index + 1).replace(".ova", ""); + + if (templateName == null || templateName.isEmpty()) { + templateName = defaultName; + } + } else { + mountPoint = templateUrl.substring(storeUrl.length() + 1); + if (!mountPoint.endsWith("/")) { + mountPoint = mountPoint + "/"; + } + templateName = defaultName; + } + + return new Pair<String, String>(mountPoint, templateName); + } + + public static void deleteVolumeVmdkFiles(DatastoreMO dsMo, String volumeName, DatacenterMO dcMo) throws Exception { + String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeName); + dsMo.deleteFile(volumeDatastorePath, dcMo.getMor(), true); + + volumeDatastorePath = String.format("[%s] %s-flat.vmdk", dsMo.getName(), volumeName); + dsMo.deleteFile(volumeDatastorePath, dcMo.getMor(), true); + + volumeDatastorePath = String.format("[%s] %s-delta.vmdk", dsMo.getName(), volumeName); + dsMo.deleteFile(volumeDatastorePath, dcMo.getMor(), true); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutType.java ---------------------------------------------------------------------- diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutType.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutType.java new file mode 100644 index 0000000..c62bd89 --- /dev/null +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutType.java @@ -0,0 +1,22 @@ +// 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.resource; + +public enum VmwareStorageLayoutType { + VMWARE, + CLOUDSTACK_LEGACY +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java ---------------------------------------------------------------------- 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 2742974..7cfee73 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -89,6 +89,7 @@ import com.cloud.vm.VirtualMachine.State; public class VmwareStorageProcessor implements StorageProcessor { private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class); + private VmwareHostService hostService; private boolean _fullCloneFlag; private VmwareStorageMount mountService; @@ -97,8 +98,6 @@ public class VmwareStorageProcessor implements StorageProcessor { protected Integer _shutdown_waitMs; private final Gson _gson; private final StorageLayer _storage = new JavaStorageLayer(); - private final PremiumSecondaryStorageResource storageResource; - public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFlag, VmwareStorageMount mountService, Integer timeout, VmwareResource resource, @@ -111,7 +110,6 @@ public class VmwareStorageProcessor implements StorageProcessor { this.resource = resource; this._shutdown_waitMs = shutdownWaitMs; _gson = GsonHelper.getGsonLogger(); - this.storageResource = storageResource; } private String getOVFFilePath(String srcOVAFileName) { @@ -128,8 +126,9 @@ public class VmwareStorageProcessor implements StorageProcessor { } return null; } + private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl, - String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { + String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception { s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage @@ -138,9 +137,10 @@ public class VmwareStorageProcessor implements StorageProcessor { String secondaryMountPoint = mountService.getMountPoint(secondaryStorageUrl); s_logger.info("Secondary storage mount point: " + secondaryMountPoint); - String srcOVAFileName = secondaryMountPoint + "/" + templatePathAtSecondaryStorage + - templateName + "." + ImageFormat.OVA.getFileExtension(); - + String srcOVAFileName = VmwareStorageLayoutHelper.getTemplateOnSecStorageFilePath( + secondaryMountPoint, templatePathAtSecondaryStorage, + templateName, ImageFormat.OVA.getFileExtension()); + String srcFileName = getOVFFilePath(srcOVAFileName); if(srcFileName == null) { Script command = new Script("tar", 0, s_logger); @@ -193,7 +193,7 @@ public class VmwareStorageProcessor implements StorageProcessor { 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(); @@ -201,55 +201,32 @@ public class VmwareStorageProcessor implements StorageProcessor { String secondaryStorageUrl = nfsImageStore.getUrl(); assert (secondaryStorageUrl != null); - String templateUrl = secondaryStorageUrl + File.separator + srcData.getPath(); - - String templateName = null; - String mountPoint = null; - if (templateUrl.endsWith(".ova")) { - int index = templateUrl.lastIndexOf("/"); - mountPoint = templateUrl.substring(0, index); - mountPoint = mountPoint.substring(secondaryStorageUrl.length() + 1); - if (!mountPoint.endsWith("/")) { - mountPoint = mountPoint + "/"; - } - - templateName = templateUrl.substring(index + 1).replace("." + ImageFormat.OVA.getFileExtension(), ""); - - if (templateName == null || templateName.isEmpty()) { - templateName = template.getName(); - } - } else { - mountPoint = templateUrl.substring(secondaryStorageUrl.length() + 1); - if (!mountPoint.endsWith("/")) { - mountPoint = mountPoint + "/"; - } - templateName = template.getName(); - } + String templateUrl = secondaryStorageUrl + "/" + srcData.getPath(); + + Pair<String, String> templateInfo = VmwareStorageLayoutHelper.decodeTemplateRelativePathAndNameFromUrl( + secondaryStorageUrl, templateUrl, template.getName()); VmwareContext context = hostService.getServiceContext(cmd); try { VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd); - String templateUuidName = UUID.nameUUIDFromBytes((templateName + "@" + primaryStore.getUuid() + "-" + hyperHost.getMor().getValue()).getBytes()).toString(); - // truncate template name to 32 chars to ensure they work well with vSphere API's. - templateUuidName = templateUuidName.replace("-", ""); + String templateUuidName = deriveTemplateUuidOnHost(hyperHost, primaryStore.getUuid(), templateInfo.second()); DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter()); VirtualMachineMO templateMo = VmwareHelper.pickOneVmOnRunningHost(dcMo.findVmByNameAndLabel(templateUuidName), true); if (templateMo == null) { - if(s_logger.isInfoEnabled()) { - s_logger.info("Template " + templateName + " is not setup yet, setup template from secondary storage with uuid name: " + templateUuidName); - } + 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); copyTemplateFromSecondaryToPrimary(hyperHost, primaryStorageDatastoreMo, secondaryStorageUrl, - mountPoint, templateName, templateUuidName); + templateInfo.first(), templateInfo.second(), templateUuidName); } else { - s_logger.info("Template " + templateName + " has already been setup, skip the template setup process in primary storage"); + s_logger.info("Template " + templateInfo.second() + " has already been setup, skip the template setup process in primary storage"); } TemplateObjectTO newTemplate = new TemplateObjectTO(); @@ -265,6 +242,7 @@ public class VmwareStorageProcessor implements StorageProcessor { return new CopyCmdAnswer(msg); } } + private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception { @@ -275,10 +253,6 @@ public class VmwareStorageProcessor implements StorageProcessor { throw new Exception(msg); } - if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) { - dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false); - } - s_logger.info("creating linked clone from template"); if (!vmTemplate.createLinkedClone(vmdkName, morBaseSnapshot, dcMo.getVmFolder(), morPool, morDatastore)) { String msg = "Unable to clone from the template"; @@ -286,16 +260,21 @@ public class VmwareStorageProcessor implements StorageProcessor { throw new Exception(msg); } - // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know - // to move files s_logger.info("Move volume out of volume-wrapper VM "); - dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), + String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, true); + String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true); + + dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], dcMo.getMor(), dsMo.getMor(), - String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); - - dsMo.moveDatastoreFile(String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmdkName, vmdkName), + legacyCloudStackLayoutFilePair[0], + dcMo.getMor(), true); + + dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], dcMo.getMor(), dsMo.getMor(), - String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); + legacyCloudStackLayoutFilePair[1], + dcMo.getMor(), true); return true; } @@ -303,28 +282,28 @@ public class VmwareStorageProcessor implements StorageProcessor { private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo, String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception { - if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName)) { - dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false); - } - s_logger.info("creating full clone from template"); if (!vmTemplate.createFullClone(vmdkName, dcMo.getVmFolder(), morPool, morDatastore)) { String msg = "Unable to create full clone from the template"; s_logger.error(msg); throw new Exception(msg); } - - // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know - // to move files + s_logger.info("Move volume out of volume-wrapper VM "); - dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName), + String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, false); + String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, + vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false); + + dsMo.moveDatastoreFile(vmwareLayoutFilePair[0], dcMo.getMor(), dsMo.getMor(), - String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); - - dsMo.moveDatastoreFile(String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmdkName, vmdkName), + legacyCloudStackLayoutFilePair[0], + dcMo.getMor(), true); + + dsMo.moveDatastoreFile(vmwareLayoutFilePair[1], dcMo.getMor(), dsMo.getMor(), - String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true); - + legacyCloudStackLayoutFilePair[1], + dcMo.getMor(), true); return true; } @@ -337,7 +316,6 @@ public class VmwareStorageProcessor implements StorageProcessor { PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore(); PrimaryDataStoreTO srcStore = (PrimaryDataStoreTO)template.getDataStore(); - try { VmwareContext context = this.hostService.getServiceContext(null); VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(context, null); @@ -350,26 +328,28 @@ public class VmwareStorageProcessor implements StorageProcessor { DatastoreMO dsMo = new DatastoreMO(context, morDatastore); - - // attach volume id to make the name unique - String vmdkName = volume.getName() + "-" + volume.getId(); + String vmdkName = volume.getName(); if (srcStore == null) { - // create a root volume for blank VM + // create a root volume for blank VM (created from ISO) String dummyVmName = this.hostService.getWorkerName(context, cmd, 0); try { - vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName); + vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName); if (vmMo == null) { throw new Exception("Unable to create a dummy VM for volume creation"); } - String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName); + String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkName, + VmwareStorageLayoutType.CLOUDSTACK_LEGACY, + true // we only use the first file in the pair, linked or not will not matter + ); + String volumeDatastorePath = vmdkFilePair[0]; synchronized (this) { s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); - VmwareHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo); vmMo.createDisk(volumeDatastorePath, (int) (volume.getSize() / (1024L * 1024L)), morDatastore, -1); vmMo.detachDisk(volumeDatastorePath, false); - } + } VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(vmdkName); @@ -391,7 +371,6 @@ public class VmwareStorageProcessor implements StorageProcessor { ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool(); ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); - //createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool); if (!_fullCloneFlag) { createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool); } else { @@ -407,7 +386,7 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.info("destroy volume-wrapper VM " + vmdkName); vmMo.destroy(); - String srcFile = String.format("[%s] %s/", dsMo.getName(), vmdkName); + String srcFile = dsMo.getDatastorePath(vmdkName, true); dsMo.deleteFile(srcFile, dcMo.getMor(), true); VolumeObjectTO newVol = new VolumeObjectTO(); newVol.setPath(vmdkName); @@ -441,7 +420,7 @@ public class VmwareStorageProcessor implements StorageProcessor { volumeName = srcVolumePath.substring(index + 1); } - String newVolume = UUID.randomUUID().toString().replaceAll("-", ""); + String newVolume = VmwareHelper.getVCenterSafeUuid(); restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, volumeFolder, volumeName); return new Pair<String, String>(volumeFolder, newVolume); @@ -519,11 +498,11 @@ public class VmwareStorageProcessor implements StorageProcessor { String secStorageUrl, String workerVmName) throws Exception { VirtualMachineMO workerVm=null; VirtualMachineMO vmMo=null; - String exportName = UUID.randomUUID().toString(); + String exportName = UUID.randomUUID().toString().replace("-", ""); try { ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId); - + if (morDs == null) { String msg = "Unable to find volumes's storage pool for copy volume operation"; s_logger.error(msg); @@ -534,35 +513,15 @@ public class VmwareStorageProcessor implements StorageProcessor { if (vmMo == null) { // create a dummy worker vm for attaching the volume DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs); - //restrict VM name to 32 chars, (else snapshot descriptor file name will be truncated to 32 chars of vm name) - VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); - vmConfig.setName(workerVmName); - vmConfig.setMemoryMB((long) 4); - vmConfig.setNumCPUs(1); - vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.value()); - VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo(); - fileInfo.setVmPathName(String.format("[%s]", dsMo.getName())); - vmConfig.setFiles(fileInfo); - - // Scsi controller - VirtualLsiLogicController scsiController = new VirtualLsiLogicController(); - scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); - scsiController.setBusNumber(0); - scsiController.setKey(1); - VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); - scsiControllerSpec.setDevice(scsiController); - scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - vmConfig.getDeviceChange().add(scsiControllerSpec); - - hyperHost.createVm(vmConfig); - workerVm = hyperHost.findVmOnHyperHost(workerVmName); + workerVm = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVmName); + if (workerVm == null) { String msg = "Unable to create worker VM to execute CopyVolumeCommand"; s_logger.error(msg); throw new Exception(msg); } - //attach volume to worker VM + // attach volume to worker VM String datastoreVolumePath = getVolumePathInDatastore(dsMo, volumePath + ".vmdk"); workerVm.attachDisk(new String[] { datastoreVolumePath }, morDs); vmMo = workerVm; @@ -940,9 +899,8 @@ public class VmwareStorageProcessor implements StorageProcessor { postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize); writeMetaOvaForTemplate(installFullPath, backupSSUuid + ".ovf", templateVMDKName, templateUniqueName, physicalSize); return new Ternary<String, Long, Long>(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize); - } catch(Exception e) { + } finally { // TODO, clean up left over files - throw e; } } @@ -1043,6 +1001,7 @@ public class VmwareStorageProcessor implements StorageProcessor { installPath, backupUuid, workerVmName); return backupUuid + "/" + backupUuid; } + @Override public Answer backupSnapshot(CopyCommand cmd) { SnapshotObjectTO srcSnapshot = (SnapshotObjectTO)cmd.getSrcTO(); @@ -1055,7 +1014,6 @@ public class VmwareStorageProcessor implements StorageProcessor { NfsTO destNfsStore = (NfsTO)destStore; - String secondaryStorageUrl = destNfsStore.getUrl(); String snapshotUuid = srcSnapshot.getPath(); String prevSnapshotUuid = srcSnapshot.getParentSnapshotPath(); @@ -1090,21 +1048,15 @@ public class VmwareStorageProcessor implements StorageProcessor { dsMo = new DatastoreMO(hyperHost.getContext(), morDs); workerVMName = hostService.getWorkerName(context, cmd, 0); - - // attach a volume to dummay wrapper VM for taking snapshot and exporting the VM for backup - if (!hyperHost.createBlankVm(workerVMName, 1, 512, 0, false, 4, 0, VirtualMachineGuestOsIdentifier.OTHER_GUEST.value(), morDs, false)) { - String msg = "Unable to create worker VM to execute BackupSnapshotCommand"; - s_logger.error(msg); - throw new Exception(msg); - } - vmMo = hyperHost.findVmOnHyperHost(workerVMName); + + vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVMName); if (vmMo == null) { throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName); } workerVm = vmMo; // attach volume to worker VM - String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumePath); + String datastoreVolumePath = dsMo.getDatastorePath(volumePath + ".vmdk"); vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs); } } @@ -1205,7 +1157,7 @@ public class VmwareStorageProcessor implements StorageProcessor { } DatastoreMO dsMo = new DatastoreMO(this.hostService.getServiceContext(null), morDs); - String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), isManaged ? dsMo.getName() : volumeTO.getPath()); + String datastoreVolumePath = dsMo.getDatastorePath((isManaged ? dsMo.getName() : volumeTO.getPath()) + ".vmdk"); disk.setVdiUuid(datastoreVolumePath); @@ -1251,9 +1203,8 @@ public class VmwareStorageProcessor implements StorageProcessor { return morDatastore; } + private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) { - - try { VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(this.hostService.getServiceContext(null), null); VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName); @@ -1341,33 +1292,6 @@ public class VmwareStorageProcessor implements StorageProcessor { return this.attachVolume(cmd, cmd.getDisk(), false, cmd.isManaged(), cmd.getVmName(), cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort()); } - protected VirtualMachineMO prepareVolumeHostDummyVm(VmwareHypervisorHost hyperHost, DatastoreMO dsMo, String vmName) throws Exception { - assert (hyperHost != null); - - VirtualMachineMO vmMo = null; - VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); - vmConfig.setName(vmName); - vmConfig.setMemoryMB((long) 4); // vmware request minimum of 4 MB - vmConfig.setNumCPUs(1); - vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.value()); - VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo(); - fileInfo.setVmPathName(String.format("[%s]", dsMo.getName())); - vmConfig.setFiles(fileInfo); - - // Scsi controller - VirtualLsiLogicController scsiController = new VirtualLsiLogicController(); - scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); - scsiController.setBusNumber(0); - scsiController.setKey(1); - VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); - scsiControllerSpec.setDevice(scsiController); - scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - - vmConfig.getDeviceChange().add(scsiControllerSpec ); - hyperHost.createVm(vmConfig); - vmMo = hyperHost.findVmOnHyperHost(vmName); - return vmMo; - } @Override public Answer createVolume(CreateObjectCommand cmd) { @@ -1388,17 +1312,19 @@ public class VmwareStorageProcessor implements StorageProcessor { // create data volume VirtualMachineMO vmMo = null; String volumeUuid = UUID.randomUUID().toString().replace("-", ""); - String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeUuid); + String volumeDatastorePath = dsMo.getDatastorePath(volumeUuid + ".vmdk"); + String dummyVmName = this.hostService.getWorkerName(context, cmd, 0); try { - vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName); + s_logger.info("Create worker VM " + dummyVmName); + vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName); if (vmMo == null) { throw new Exception("Unable to create a dummy VM for volume creation"); } synchronized (this) { // s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath); - VmwareHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo); + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo); vmMo.createDisk(volumeDatastorePath, (int) (volume.getSize() / (1024L * 1024L)), morDatastore, vmMo.getScsiDeviceControllerKey()); vmMo.detachDisk(volumeDatastorePath, false); @@ -1410,10 +1336,11 @@ public class VmwareStorageProcessor implements StorageProcessor { return new CreateObjectAnswer(newVol); } finally { s_logger.info("Destroy dummy VM after volume creation"); - vmMo.detachAllDisks(); - vmMo.destroy(); + if(vmMo != null) { + vmMo.detachAllDisks(); + vmMo.destroy(); + } } - } catch (Throwable e) { if (e instanceof RemoteException) { s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); @@ -1674,7 +1601,7 @@ public class VmwareStorageProcessor implements StorageProcessor { String backupPath = backedUpSnapshotUuid.substring(0, index); backedUpSnapshotUuid = backedUpSnapshotUuid.substring(index + 1); String details = null; - String newVolumeName = UUID.randomUUID().toString().replaceAll("-", ""); + String newVolumeName = VmwareHelper.getVCenterSafeUuid(); VmwareContext context = hostService.getServiceContext(cmd); try { @@ -1715,4 +1642,10 @@ public class VmwareStorageProcessor implements StorageProcessor { return new Answer(cmd, false, "unsupported command"); } } + + private static String deriveTemplateUuidOnHost(VmwareHypervisorHost hyperHost, String storeIdentifier, String templateName) { + String templateUuid = UUID.nameUUIDFromBytes((templateName + "@" + storeIdentifier + "-" + hyperHost.getMor().getValue()).getBytes()).toString(); + templateUuid = templateUuid.replaceAll("-", ""); + return templateUuid; + } } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java ---------------------------------------------------------------------- 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 638104e..92a8f05 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/DatastoreMO.java @@ -125,6 +125,23 @@ public class DatastoreMO extends BaseMO { _context.getService().makeDirectory(morFileManager, fullPath, morDc, true); } + + public String getDatastoreRootPath() throws Exception { + return String.format("[%s]", getName()); + } + + public String getDatastorePath(String relativePathWithoutDatastoreName) throws Exception { + return getDatastorePath(relativePathWithoutDatastoreName, false); + } + + public String getDatastorePath(String relativePathWithoutDatastoreName, boolean endWithPathDelimiter) throws Exception { + String path = String.format("[%s] %s", getName(), relativePathWithoutDatastoreName); + if(endWithPathDelimiter) { + if(!path.endsWith("/")) + return path + "/"; + } + return path; + } public boolean deleteFile(String path, ManagedObjectReference morDc, boolean testExistence) throws Exception { String datastoreName = getName(); @@ -299,18 +316,6 @@ public class DatastoreMO extends BaseMO { s_logger.info("File " + fileFullPath + " does not exist on datastore"); return false; - -/* - String[] fileNames = listDirContent(dirFile.getPath()); - - String fileName = file.getFileName(); - for(String name : fileNames) { - if(name.equalsIgnoreCase(fileName)) - return true; - } - - return false; -*/ } public boolean folderExists(String folderParentDatastorePath, String folderName) throws Exception { http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java index c92b855..2a44fce 100755 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/HypervisorHostHelper.java @@ -58,6 +58,7 @@ import com.vmware.vim25.VirtualDeviceConfigSpecOperation; import com.vmware.vim25.VirtualLsiLogicController; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineFileInfo; +import com.vmware.vim25.VirtualMachineGuestOsIdentifier; import com.vmware.vim25.VirtualMachineVideoCard; import com.vmware.vim25.VirtualSCSISharing; import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec; @@ -1188,8 +1189,40 @@ public class HypervisorHostHelper { return false; } - public static String resolveHostNameInUrl(DatacenterMO dcMo, String url) { + public static VirtualMachineMO createWorkerVM(VmwareHypervisorHost hyperHost, + DatastoreMO dsMo, String vmName) throws Exception { + + // Allow worker VM to float within cluster so that we will have better chance to + // create it successfully + ManagedObjectReference morCluster = hyperHost.getHyperHostCluster(); + if(morCluster != null) + hyperHost = new ClusterMO(hyperHost.getContext(), morCluster); + + VirtualMachineMO workingVM = null; + VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); + vmConfig.setName(vmName); + vmConfig.setMemoryMB((long) 4); + vmConfig.setNumCPUs(1); + vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.value()); + VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo(); + fileInfo.setVmPathName(dsMo.getDatastoreRootPath()); + vmConfig.setFiles(fileInfo); + VirtualLsiLogicController scsiController = new VirtualLsiLogicController(); + scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); + scsiController.setBusNumber(0); + scsiController.setKey(1); + VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); + scsiControllerSpec.setDevice(scsiController); + scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + vmConfig.getDeviceChange().add(scsiControllerSpec); + hyperHost.createVm(vmConfig); + workingVM = hyperHost.findVmOnHyperHost(vmName); + return workingVM; + } + + public static String resolveHostNameInUrl(DatacenterMO dcMo, String url) { s_logger.info("Resolving host name in url through vCenter, url: " + url); URI uri; http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index e8cbe8f..b7c15f9 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -959,14 +959,12 @@ public class VirtualMachineMO extends BaseMO { newDisk.setCapacityInKB(sizeInMb*1024); VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); - //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); deviceConfigSpec.setDevice(newDisk); deviceConfigSpec.setFileOperation(VirtualDeviceConfigSpecFileOperation.CREATE); deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - //deviceConfigSpecArray[0] = deviceConfigSpec; reConfigSpec.getDeviceChange().add(deviceConfigSpec); ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/40869a5a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java index 5a8cdc4..e545c8e 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java @@ -27,6 +27,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Random; +import java.util.UUID; import org.apache.log4j.Logger; @@ -60,8 +61,6 @@ import com.vmware.vim25.VirtualPCNet32; import com.vmware.vim25.VirtualVmxnet2; import com.vmware.vim25.VirtualVmxnet3; -import com.cloud.hypervisor.vmware.mo.DatacenterMO; -import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.LicenseAssignmentManagerMO; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; @@ -611,17 +610,6 @@ public class VmwareHelper { return ipAddress.equals(destName); } - public static void deleteVolumeVmdkFiles(DatastoreMO dsMo, String volumeName, DatacenterMO dcMo) throws Exception { - String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeName); - dsMo.deleteFile(volumeDatastorePath, dcMo.getMor(), true); - - volumeDatastorePath = String.format("[%s] %s-flat.vmdk", dsMo.getName(), volumeName); - dsMo.deleteFile(volumeDatastorePath, dcMo.getMor(), true); - - volumeDatastorePath = String.format("[%s] %s-delta.vmdk", dsMo.getName(), volumeName); - dsMo.deleteFile(volumeDatastorePath, dcMo.getMor(), true); - } - public static String getExceptionMessage(Throwable e) { return getExceptionMessage(e, false); } @@ -694,4 +682,9 @@ public class VmwareHelper { return hotplugSupportedByLicense; } + + public static String getVCenterSafeUuid() { + // Object name that is greater than 32 is not safe in vCenter + return UUID.randomUUID().toString().replaceAll("-", ""); + } }
