CLOUDSTACK-3869: make new folder structure to work with Create/Delete/Attach/Detach commands

This commit is contained in:
Kelven Yang 2013-08-06 18:04:57 -07:00
parent 9a2148ffc3
commit 362ef67013
5 changed files with 251 additions and 83 deletions

View File

@ -2610,6 +2610,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
s_logger.error(msg);
throw new Exception(msg);
}
DatastoreMO dsRootVolumeIsOn = getDatastoreThatRootDiskIsOn(dataStoresDetails, disks);
if(dsRootVolumeIsOn == null) {
String msg = "Unable to locate datastore details of root volume";
s_logger.error(msg);
throw new Exception(msg);
}
DatacenterMO dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter());
VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName);
if (vmMo != null) {
@ -2657,7 +2666,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
throw new Exception("Failed to find the newly create or relocated VM. vmName: " + vmInternalCSName);
}
}
int totalChangeDevices = disks.length + nics.length;
DiskTO volIso = null;
if (vmSpec.getType() != VirtualMachine.Type.User) {
@ -2823,9 +2832,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid());
assert (volumeDsDetails != null);
VirtualDevice device;
datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmName, volumeDsDetails.second(),
volumeTO.getPath());
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey, new String[] { datastoreDiskPath }, volumeDsDetails.first(),
(controllerKey==ideControllerKey)?ideUnitNumber++:scsiUnitNumber++, i + 1);
/*
datastoreDiskPath = String.format("[%s] %s.vmdk", volumeDsDetails.second().getName(), volumeTO.getPath());
String chainInfo = volumeTO.getChainInfo();
// chainInfo is no longer in use
if (chainInfo != null && !chainInfo.isEmpty()) {
String[] diskChain = _gson.fromJson(chainInfo, String[].class);
if (diskChain == null || diskChain.length < 1) {
@ -2845,6 +2863,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey, new String[] { datastoreDiskPath }, volumeDsDetails.first(),
(controllerKey==ideControllerKey)?ideUnitNumber++:scsiUnitNumber++, i + 1);
}
*/
deviceConfigSpecArray[i].setDevice(device);
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
@ -3110,8 +3130,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return validatedDetails;
}
private NicTO[] sortNicsByDeviceId(NicTO[] nics) {
List<NicTO> listForSort = new ArrayList<NicTO>();
@ -3181,6 +3199,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return poolMors;
}
private DatastoreMO getDatastoreThatRootDiskIsOn(HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> dataStoresDetails,
DiskTO disks[]) {
Pair<ManagedObjectReference, DatastoreMO> rootDiskDataStoreDetails = null;
for (DiskTO vol : disks) {
if (vol.getType() == Volume.Type.ROOT) {
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getData().getDataStore();
rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid());
}
}
if(rootDiskDataStoreDetails != null)
return rootDiskDataStoreDetails.second();
return null;
}
private String getPvlanInfo(NicTO nicTo) {
if (nicTo.getBroadcastType() == BroadcastDomainType.Pvlan) {
@ -4277,6 +4310,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
DatastoreMO dsMo = new DatastoreMO(getServiceContext(), morDs);
VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), cmd.getVmName(),
dsMo, cmd.getVolumePath());
String datastoreVolumePath = dsMo.searchFileInSubFolders(cmd.getVolumePath() + ".vmdk", true);
assert (datastoreVolumePath != null) : "Virtual disk file must exist in specified datastore for attach/detach operations.";
if (datastoreVolumePath == null) {
@ -4292,6 +4328,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
if (cmd.isManaged()) {
handleDatastoreAndVmdkDetach(cmd.get_iScsiName(), cmd.getStorageHost(), cmd.getStoragePort());
} else {
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, cmd.getVolumePath());
}
}

View File

@ -16,7 +16,10 @@
// under the License.
package com.cloud.storage.resource;
import org.apache.log4j.Logger;
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
import com.cloud.hypervisor.vmware.mo.DatastoreFile;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.utils.Pair;
@ -26,6 +29,7 @@ import com.cloud.utils.Pair;
*
*/
public class VmwareStorageLayoutHelper {
private static final Logger s_logger = Logger.getLogger(VmwareStorageLayoutHelper.class);
public static String[] getVmdkFilePairDatastorePath(DatastoreMO dsMo, String vmName, String vmdkName,
VmwareStorageLayoutType layoutType, boolean linkedVmdk) throws Exception {
@ -34,21 +38,21 @@ public class VmwareStorageLayoutHelper {
switch(layoutType) {
case VMWARE :
assert(vmName != null && !vmName.isEmpty());
filePair[0] = String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmName, vmdkName);
filePair[0] = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkName + ".vmdk");
if(linkedVmdk)
filePair[1] = String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmName, vmdkName);
filePair[1] = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkName + "-delta.vmdk");
else
filePair[1] = String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmName, vmdkName);
filePair[1] = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkName + "-flat.vmdk");
return filePair;
case CLOUDSTACK_LEGACY :
filePair[0] = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName);
filePair[0] = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkName + ".vmdk");
if(linkedVmdk)
filePair[1] = String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName);
filePair[1] = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkName + "-delta.vmdk");
else
filePair[1] = String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName);
filePair[1] = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkName + "-flat.vmdk");
return filePair;
default :
@ -60,6 +64,83 @@ public class VmwareStorageLayoutHelper {
return null;
}
public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName,
DatastoreMO ds, String vmdkName) throws Exception {
assert(ds != null);
if(!ds.folderExists(String.format("[%s]", ds.getName()), vmName)) {
s_logger.info("VM folder does not exist on target datastore, we will create one. vm: " + vmName + ", datastore: " + ds.getName());
ds.makeDirectory(String.format("[%s] %s", ds.getName(), vmName), dcMo.getMor());
}
String[] vmdkLinkedCloneModeLegacyPair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName,
VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true);
String[] vmdkFullCloneModeLegacyPair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName,
VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false);
String[] vmdkLinkedCloneModePair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName,
VmwareStorageLayoutType.VMWARE, true);
String[] vmdkFullCloneModePair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName,
VmwareStorageLayoutType.VMWARE, false);
if(!ds.fileExists(vmdkLinkedCloneModeLegacyPair[0])) {
// To protect against inconsistency caused by non-atomic datastore file management, detached disk may
// be left over in its previous owner VM. We will do a fixup synchronization here by moving it to root
// again
//
syncVolumeToRootFolder(dcMo, ds, vmdkName);
}
if(ds.fileExists(vmdkFullCloneModeLegacyPair[1])) {
s_logger.info("sync " + vmdkFullCloneModeLegacyPair[1] + "->" + vmdkFullCloneModePair[1]);
ds.moveDatastoreFile(vmdkFullCloneModeLegacyPair[1], dcMo.getMor(), ds.getMor(),
vmdkFullCloneModePair[1], dcMo.getMor(), true);
}
if(ds.fileExists(vmdkLinkedCloneModeLegacyPair[1])) {
s_logger.info("sync " + vmdkLinkedCloneModeLegacyPair[1] + "->" + vmdkLinkedCloneModePair[1]);
ds.moveDatastoreFile(vmdkLinkedCloneModeLegacyPair[1], dcMo.getMor(), ds.getMor(),
vmdkLinkedCloneModePair[1], dcMo.getMor(), true);
}
s_logger.info("sync " + vmdkLinkedCloneModeLegacyPair[0] + "->" + vmdkLinkedCloneModePair[0]);
ds.moveDatastoreFile(vmdkLinkedCloneModeLegacyPair[0], dcMo.getMor(), ds.getMor(),
vmdkLinkedCloneModePair[0], dcMo.getMor(), true);
return vmdkLinkedCloneModePair[0];
}
public static void syncVolumeToRootFolder(DatacenterMO dcMo, DatastoreMO ds, String vmdkName) throws Exception {
String fileDsFullPath = ds.searchFileInSubFolders(vmdkName + ".vmdk", false);
if(fileDsFullPath == null)
throw new Exception("Unable to find " + vmdkName + ".vmdk in datastore: " + ds.getName());
DatastoreFile srcDsFile = new DatastoreFile(fileDsFullPath);
String companionFilePath = srcDsFile.getCompanionPath(vmdkName + "-flat.vmdk");
if(ds.fileExists(companionFilePath)) {
String targetPath = getLegacyDatastorePathFromVmdkFileName(ds, vmdkName + "-flat.vmdk");
s_logger.info("Fixup folder-synchronization. move " + companionFilePath + " -> " + targetPath);
ds.moveDatastoreFile(companionFilePath, dcMo.getMor(), ds.getMor(), targetPath, dcMo.getMor(), true);
}
companionFilePath = srcDsFile.getCompanionPath(vmdkName + "-delta.vmdk");
if(ds.fileExists(companionFilePath)) {
String targetPath = getLegacyDatastorePathFromVmdkFileName(ds, vmdkName + "-delta.vmdk");
s_logger.info("Fixup folder-synchronization. move " + companionFilePath + " -> " + targetPath);
ds.moveDatastoreFile(companionFilePath, dcMo.getMor(), ds.getMor(), targetPath, dcMo.getMor(), true);
}
// move the identity VMDK file the last
String targetPath = getLegacyDatastorePathFromVmdkFileName(ds, vmdkName + ".vmdk");
s_logger.info("Fixup folder-synchronization. move " + fileDsFullPath + " -> " + targetPath);
ds.moveDatastoreFile(fileDsFullPath, dcMo.getMor(), ds.getMor(), targetPath, dcMo.getMor(), true);
}
public static String getTemplateOnSecStorageFilePath(String secStorageMountPoint, String templateRelativeFolderPath,
String templateName, String fileExtension) {
@ -114,13 +195,43 @@ public class VmwareStorageLayoutHelper {
}
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);
String fileName = volumeName + ".vmdk";
String fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
if(!dsMo.fileExists(fileFullPath))
fileFullPath = dsMo.searchFileInSubFolders(fileName, false);
if(fileFullPath != null) {
dsMo.deleteFile(fileFullPath, dcMo.getMor(), false);
} else {
s_logger.warn("Unable to locate VMDK file: " + fileName);
}
fileName = volumeName + "-flat.vmdk";
fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
if(!dsMo.fileExists(fileFullPath))
fileFullPath = dsMo.searchFileInSubFolders(fileName, false);
if(fileFullPath != null) {
dsMo.deleteFile(fileFullPath, dcMo.getMor(), false);
} else {
s_logger.warn("Unable to locate VMDK file: " + fileName);
}
fileName = volumeName + "-delta.vmdk";
fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
if(!dsMo.fileExists(fileFullPath))
fileFullPath = dsMo.searchFileInSubFolders(fileName, false);
if(fileFullPath != null) {
dsMo.deleteFile(fileFullPath, dcMo.getMor(), false);
} else {
s_logger.warn("Unable to locate VMDK file: " + fileName);
}
}
public static String getLegacyDatastorePathFromVmdkFileName(DatastoreMO dsMo, String vmdkFileName) throws Exception {
return String.format("[%s] %s", dsMo.getName(), vmdkFileName);
}
public static String getVmwareDatastorePathFromVmdkFileName(DatastoreMO dsMo, String vmName, String vmdkFileName) throws Exception {
return String.format("[%s] %s/%s", dsMo.getName(), vmName, vmdkFileName);
}
}

View File

@ -1148,7 +1148,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
else {
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid());
}
}
if (morDs == null) {
String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + vmName;
@ -1157,19 +1157,33 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
DatastoreMO dsMo = new DatastoreMO(this.hostService.getServiceContext(null), morDs);
String datastoreVolumePath = dsMo.getDatastorePath((isManaged ? dsMo.getName() : volumeTO.getPath()) + ".vmdk");
String datastoreVolumePath;
if(isAttach) {
if(!isManaged)
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName,
dsMo, volumeTO.getPath());
else
datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
} else {
datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
if(!dsMo.fileExists(datastoreVolumePath))
datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
}
disk.setVdiUuid(datastoreVolumePath);
AttachAnswer answer = new AttachAnswer(disk);
if (isAttach) {
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
} else {
} else {
vmMo.removeAllSnapshots();
vmMo.detachDisk(datastoreVolumePath, false);
if (isManaged) {
hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort);
this.hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort);
} else {
VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath());
}
}
@ -1428,23 +1442,10 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
}
if (s_logger.isInfoEnabled()) {
if (s_logger.isInfoEnabled())
s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
}
dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
// root volume may be created via linked-clone, delete the delta disk as well
if (_fullCloneFlag) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
}
dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
} else {
if (s_logger.isInfoEnabled()) {
s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-delta.vmdk");
}
dsMo.deleteFile(vol.getPath() + "-delta.vmdk", morDc, true);
}
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc));
return new Answer(cmd, true, "Success");
}
@ -1464,41 +1465,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
}
String chainInfo = vol.getChainInfo();
if (chainInfo != null && !chainInfo.isEmpty()) {
s_logger.info("Destroy volume by chain info: " + chainInfo);
String[] diskChain = _gson.fromJson(chainInfo, String[].class);
if (diskChain != null && diskChain.length > 0) {
for (String backingName : diskChain) {
if (s_logger.isInfoEnabled()) {
s_logger.info("Delete volume backing file: " + backingName);
}
dsMo.deleteFile(backingName, morDc, true);
}
} else {
if (s_logger.isInfoEnabled()) {
s_logger.info("Empty disk chain info, fall back to try to delete by original backing file name");
}
dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
if (s_logger.isInfoEnabled()) {
s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
}
dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
}
} else {
if (s_logger.isInfoEnabled()) {
s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
}
dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
if (s_logger.isInfoEnabled()) {
s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
}
dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
}
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc));
return new Answer(cmd, true, "Success");
} catch (Throwable e) {
if (e instanceof RemoteException) {

View File

@ -351,17 +351,15 @@ public class DatastoreMO extends BaseMO {
s_logger.warn("Multiple files with name " + fileName + " exists in datastore " + datastorePath + ". Trying to choose first file found in search attempt.");
}
for (HostDatastoreBrowserSearchResults result : results) {
if (result != null) {
List<FileInfo> info = result.getFile();
if (info != null && info.size() > 0) {
for (FileInfo fi : info) {
absoluteFileName = parentFolderPath = result.getFolderPath();
s_logger.info("Found file " + fileName + " in datastore at " + absoluteFileName);
if(parentFolderPath.endsWith("]"))
absoluteFileName += " ";
absoluteFileName += fi.getPath();
break;
}
List<FileInfo> info = result.getFile();
if (info != null && info.size() > 0) {
for (FileInfo fi : info) {
absoluteFileName = parentFolderPath = result.getFolderPath();
s_logger.info("Found file " + fileName + " in datastore at " + absoluteFileName);
if(parentFolderPath.endsWith("]"))
absoluteFileName += " ";
absoluteFileName += fi.getPath();
break;
}
}
}

View File

@ -0,0 +1,53 @@
//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.hypervisor.vmware.mo;
import org.apache.log4j.Logger;
import com.cloud.hypervisor.vmware.util.VmwareClient;
import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.utils.StringUtils;
public class TestVmwareContextFactory {
private static final Logger s_logger = Logger.getLogger(TestVmwareContextFactory.class);
private static volatile int s_seq = 1;
static {
// skip certificate check
System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");
}
public static VmwareContext create(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception {
assert(vCenterAddress != null);
assert(vCenterUserName != null);
assert(vCenterPassword != null);
String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService";
if(s_logger.isDebugEnabled())
s_logger.debug("initialize VmwareContext. url: " + serviceUrl + ", username: " + vCenterUserName + ", password: " + StringUtils.getMaskedPasswordForDisplay(vCenterPassword));
VmwareClient vimClient = new VmwareClient(vCenterAddress + "-" + s_seq++);
vimClient.connect(serviceUrl, vCenterUserName, vCenterPassword);
VmwareContext context = new VmwareContext(vimClient, vCenterAddress);
return context;
}
}