CLOUDSTACK-3869: Move VMware datastore folder structure policy management to central place

This commit is contained in:
Kelven Yang 2013-08-05 13:40:35 -07:00
parent 458de9321d
commit 40869a5a2b
9 changed files with 291 additions and 209 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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("-", "");
}
}