blob: 9b2acbc5179e10ae1febddc4eaf3f1e69e65af62 [file] [log] [blame]
// 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 java.util.List;
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;
/**
*
* To provide helper methods to handle storage layout in one place
*
*/
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 {
String[] filePair = new String[2];
switch (layoutType) {
case VMWARE:
assert (vmName != null && !vmName.isEmpty());
filePair[0] = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkName + ".vmdk");
if (linkedVmdk)
filePair[1] = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkName + "-delta.vmdk");
else
filePair[1] = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkName + "-flat.vmdk");
return filePair;
case CLOUDSTACK_LEGACY:
filePair[0] = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkName + ".vmdk");
if (linkedVmdk)
filePair[1] = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkName + "-delta.vmdk");
else
filePair[1] = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkName + "-flat.vmdk");
return filePair;
default:
assert (false);
break;
}
assert (false);
return null;
}
public static String findVolumeDatastoreFullPath(DatastoreMO dsMo, String vmName, String vmdkFileName) throws Exception {
return findVolumeDatastoreFullPath(dsMo, vmName, vmdkFileName, null);
}
public static String findVolumeDatastoreFullPath(DatastoreMO dsMo, String vmName, String vmdkFileName, String excludeFolders) throws Exception {
if (vmName != null) {
String path = getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkFileName);
if (!dsMo.fileExists(path)) {
path = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkFileName);
// to save one call to vCenter, we won't check file existence for this round, so the caller
// may still fail with exception, but if that's case, we will let it fail anyway
}
return path;
} else {
String path = getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkFileName);
if (!dsMo.fileExists(path)) {
// Datastore file movement is not atomic operations, we need to sync and repair
path = dsMo.searchFileInSubFolders(vmdkFileName, false, excludeFolders);
// to save one call to vCenter, we won't check file existence for this round, so the caller
// may still fail with exception, but if that's case, we will let it fail anyway
}
return path;
}
}
public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName) throws Exception {
return syncVolumeToVmDefaultFolder(dcMo, vmName, ds, vmdkName, null);
}
public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName, String excludeFolders) 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]) && !ds.fileExists(vmdkLinkedCloneModePair[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, vmName, excludeFolders);
}
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);
}
if (ds.fileExists(vmdkLinkedCloneModeLegacyPair[0])) {
s_logger.info("sync " + vmdkLinkedCloneModeLegacyPair[0] + "->" + vmdkLinkedCloneModePair[0]);
ds.moveDatastoreFile(vmdkLinkedCloneModeLegacyPair[0], dcMo.getMor(), ds.getMor(), vmdkLinkedCloneModePair[0], dcMo.getMor(), true);
}
// Note: we will always return a path
return vmdkLinkedCloneModePair[0];
}
public static void syncVolumeToRootFolder(DatacenterMO dcMo, DatastoreMO ds, String vmdkName, String vmName) throws Exception {
syncVolumeToRootFolder(dcMo, ds, vmdkName, vmName, null);
}
public static void syncVolumeToRootFolder(DatacenterMO dcMo, DatastoreMO ds, String vmdkName, String vmName, String excludeFolders) throws Exception {
String fileDsFullPath = ds.searchFileInSubFolders(vmdkName + ".vmdk", false, excludeFolders);
if (fileDsFullPath == null)
return;
String folderName = null;
if (ds.folderExists(String.format("[%s]", ds.getName()), vmName)) {
folderName = String.format("[%s] %s", ds.getName(), vmName);
}
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);
if (folderName != null) {
String[] files = ds.listDirContent(folderName);
if (files == null || files.length == 0) {
ds.deleteFolder(folderName, dcMo.getMor());
}
}
}
public static void moveVolumeToRootFolder(DatacenterMO dcMo, List<String> detachedDisks) throws Exception {
if (detachedDisks.size() > 0) {
for (String fileFullDsPath : detachedDisks) {
DatastoreFile file = new DatastoreFile(fileFullDsPath);
s_logger.info("Check if we need to move " + fileFullDsPath + " to its root location");
DatastoreMO dsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(file.getDatastoreName()));
if (dsMo.getMor() != null) {
DatastoreFile targetFile = new DatastoreFile(file.getDatastoreName(), file.getFileName());
if (!targetFile.getPath().equalsIgnoreCase(file.getPath())) {
s_logger.info("Move " + file.getPath() + " -> " + targetFile.getPath());
dsMo.moveDatastoreFile(file.getPath(), dcMo.getMor(), dsMo.getMor(), targetFile.getPath(), dcMo.getMor(), true);
String pairSrcFilePath = file.getCompanionPath(file.getFileBaseName() + "-flat.vmdk");
String pairTargetFilePath = targetFile.getCompanionPath(file.getFileBaseName() + "-flat.vmdk");
if (dsMo.fileExists(pairSrcFilePath)) {
s_logger.info("Move " + pairSrcFilePath + " -> " + pairTargetFilePath);
dsMo.moveDatastoreFile(pairSrcFilePath, dcMo.getMor(), dsMo.getMor(), pairTargetFilePath, dcMo.getMor(), true);
}
pairSrcFilePath = file.getCompanionPath(file.getFileBaseName() + "-delta.vmdk");
pairTargetFilePath = targetFile.getCompanionPath(file.getFileBaseName() + "-delta.vmdk");
if (dsMo.fileExists(pairSrcFilePath)) {
s_logger.info("Move " + pairSrcFilePath + " -> " + pairTargetFilePath);
dsMo.moveDatastoreFile(pairSrcFilePath, dcMo.getMor(), dsMo.getMor(), pairTargetFilePath, dcMo.getMor(), true);
}
}
} else {
s_logger.warn("Datastore for " + fileFullDsPath + " no longer exists, we have to skip");
}
}
}
}
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 {
deleteVolumeVmdkFiles(dsMo, volumeName, dcMo, null);
}
public static void deleteVolumeVmdkFiles(DatastoreMO dsMo, String volumeName, DatacenterMO dcMo, String excludeFolders) throws Exception {
String fileName = volumeName + ".vmdk";
String fileFullPath = getLegacyDatastorePathFromVmdkFileName(dsMo, fileName);
if (!dsMo.fileExists(fileFullPath))
fileFullPath = dsMo.searchFileInSubFolders(fileName, false, excludeFolders);
if (fileFullPath != null) {
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true, excludeFolders);
} 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, excludeFolders);
if (fileFullPath != null) {
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true, excludeFolders);
} 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, excludeFolders);
if (fileFullPath != null) {
dsMo.deleteFile(fileFullPath, dcMo.getMor(), true, excludeFolders);
} 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);
}
}