blob: a984d8457d5401179cd9e25d3f5c4c9a972da8f8 [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.hypervisor.vmware.mo;
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
import java.util.ArrayList;
import java.util.List;
import com.vmware.vim25.FolderFileInfo;
import com.cloud.exception.CloudException;
import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.utils.Pair;
import com.vmware.pbm.PbmProfile;
import com.vmware.vim25.DatastoreHostMount;
import com.vmware.vim25.DatastoreSummary;
import com.vmware.vim25.FileInfo;
import com.vmware.vim25.FileQueryFlags;
import com.vmware.vim25.HostDatastoreBrowserSearchResults;
import com.vmware.vim25.HostDatastoreBrowserSearchSpec;
import com.vmware.vim25.HostMountInfo;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ObjectContent;
import com.vmware.vim25.ObjectSpec;
import com.vmware.vim25.PropertyFilterSpec;
import com.vmware.vim25.PropertySpec;
import com.vmware.vim25.SelectionSpec;
import com.vmware.vim25.TraversalSpec;
public class DatastoreMO extends BaseMO {
private String _name;
private Pair<DatacenterMO, String> _ownerDc;
public DatastoreMO(VmwareContext context, ManagedObjectReference morDatastore) {
super(context, morDatastore);
}
public DatastoreMO(VmwareContext context, String morType, String morValue) {
super(context, morType, morValue);
}
@Override
public String getName() throws Exception {
if (_name == null)
_name = _context.getVimClient().getDynamicProperty(_mor, "name");
return _name;
}
public DatastoreSummary getDatastoreSummary() throws Exception {
return (DatastoreSummary)_context.getVimClient().getDynamicProperty(_mor, "summary");
}
public ManagedObjectReference getDataCenterMor() throws Exception {
return getOwnerDatacenter().first().getMor();
}
public HostDatastoreBrowserMO getHostDatastoreBrowserMO() throws Exception {
return new HostDatastoreBrowserMO(_context, (ManagedObjectReference)_context.getVimClient().getDynamicProperty(_mor, "browser"));
}
public List<DatastoreHostMount> getHostMounts() throws Exception {
return _context.getVimClient().getDynamicProperty(_mor, "host");
}
public String getInventoryPath() throws Exception {
Pair<DatacenterMO, String> dcInfo = getOwnerDatacenter();
return dcInfo.second() + "/" + getName();
}
public Pair<DatacenterMO, String> getOwnerDatacenter() throws Exception {
if (_ownerDc != null)
return _ownerDc;
PropertySpec pSpec = new PropertySpec();
pSpec.setType("Datacenter");
pSpec.getPathSet().add("name");
TraversalSpec folderParentTraversal = new TraversalSpec();
folderParentTraversal.setType("Folder");
folderParentTraversal.setPath("parent");
folderParentTraversal.setName("folderParentTraversal");
SelectionSpec sSpec = new SelectionSpec();
sSpec.setName("folderParentTraversal");
folderParentTraversal.getSelectSet().add(sSpec);
TraversalSpec dsParentTraversal = new TraversalSpec();
dsParentTraversal.setType("Datastore");
dsParentTraversal.setPath("parent");
dsParentTraversal.setName("dsParentTraversal");
dsParentTraversal.getSelectSet().add(folderParentTraversal);
ObjectSpec oSpec = new ObjectSpec();
oSpec.setObj(getMor());
oSpec.setSkip(Boolean.TRUE);
oSpec.getSelectSet().add(dsParentTraversal);
PropertyFilterSpec pfSpec = new PropertyFilterSpec();
pfSpec.getPropSet().add(pSpec);
pfSpec.getObjectSet().add(oSpec);
List<PropertyFilterSpec> pfSpecArr = new ArrayList<>();
pfSpecArr.add(pfSpec);
List<ObjectContent> ocs = _context.getService().retrieveProperties(_context.getPropertyCollector(), pfSpecArr);
assert (ocs != null && ocs.size() > 0);
assert (ocs.get(0).getObj() != null);
assert (ocs.get(0).getPropSet() != null);
String dcName = ocs.get(0).getPropSet().get(0).getVal().toString();
_ownerDc = new Pair<>(new DatacenterMO(_context, ocs.get(0).getObj()), dcName);
return _ownerDc;
}
public void renameDatastore(String newDatastoreName) throws Exception {
_context.getService().renameDatastore(_mor, newDatastoreName);
}
public void makeDirectory(String path, ManagedObjectReference morDc) throws Exception {
String datastoreName = getName();
ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();
String fullPath = path;
if (!DatastoreFile.isFullDatastorePath(fullPath))
fullPath = String.format("[%s] %s", datastoreName, path);
_context.getService().makeDirectory(morFileManager, fullPath, morDc, true);
int retry = 2;
for (int i = 0; i < retry; i++) {
DatastoreFile datastoreFile = new DatastoreFile(fullPath);
if (!folderExists(String.format("[%s]", datastoreName), datastoreFile.getFileName())) {
_context.getService().makeDirectory(morFileManager, fullPath, morDc, true);
} else {
return;
}
}
}
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 deleteFolder(String folder, ManagedObjectReference morDc) throws Exception {
ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();
ManagedObjectReference morTask = _context.getService().deleteDatastoreFileTask(morFileManager, folder, morDc);
boolean result = _context.getVimClient().waitForTask(morTask);
if (result) {
_context.waitForTaskProgressDone(morTask);
return true;
} else {
logger.error("VMware deleteDatastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask));
}
return false;
}
public boolean deleteFile(String path, ManagedObjectReference morDc, boolean testExistence) throws Exception {
return deleteFile(path, morDc, testExistence, null);
}
public boolean deleteFile(String path, ManagedObjectReference morDc, boolean testExistence, String excludeFolders) throws Exception {
String datastoreName = getName();
ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();
String fullPath = path;
if (!DatastoreFile.isFullDatastorePath(fullPath))
fullPath = String.format("[%s] %s", datastoreName, path);
DatastoreFile file = new DatastoreFile(fullPath);
// Test if file specified is null or empty. We don't need to attempt to delete and return success.
if (file.getFileName() == null || file.getFileName().isEmpty()) {
return true;
}
try {
if (testExistence && !fileExists(fullPath)) {
String searchResult = searchFileInSubFolders(file.getFileName(), true, excludeFolders);
if (searchResult == null) {
return true;
} else {
fullPath = searchResult;
}
}
} catch (Exception e) {
logger.info("Unable to test file existence due to exception " + e.getClass().getName() + ", skip deleting of it");
return true;
}
ManagedObjectReference morTask = _context.getService().deleteDatastoreFileTask(morFileManager, fullPath, morDc);
boolean result = _context.getVimClient().waitForTask(morTask);
if (result) {
_context.waitForTaskProgressDone(morTask);
return true;
} else {
logger.error("VMware deleteDatastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask));
}
return false;
}
public boolean copyDatastoreFile(String srcFilePath, ManagedObjectReference morSrcDc, ManagedObjectReference morDestDs, String destFilePath,
ManagedObjectReference morDestDc, boolean forceOverwrite) throws Exception {
String srcDsName = getName();
DatastoreMO destDsMo = new DatastoreMO(_context, morDestDs);
String destDsName = destDsMo.getName();
ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();
String srcFullPath = srcFilePath;
if (!DatastoreFile.isFullDatastorePath(srcFullPath))
srcFullPath = String.format("[%s] %s", srcDsName, srcFilePath);
String destFullPath = destFilePath;
if (!DatastoreFile.isFullDatastorePath(destFullPath))
destFullPath = String.format("[%s] %s", destDsName, destFilePath);
ManagedObjectReference morTask = _context.getService().copyDatastoreFileTask(morFileManager, srcFullPath, morSrcDc, destFullPath, morDestDc, forceOverwrite);
boolean result = _context.getVimClient().waitForTask(morTask);
if (result) {
_context.waitForTaskProgressDone(morTask);
return true;
} else {
logger.error("VMware copyDatastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask));
}
return false;
}
public boolean moveDatastoreFile(String srcFilePath, ManagedObjectReference morSrcDc, ManagedObjectReference morDestDs, String destFilePath,
ManagedObjectReference morDestDc, boolean forceOverwrite) throws Exception {
String srcDsName = getName();
DatastoreMO destDsMo = new DatastoreMO(_context, morDestDs);
String destDsName = destDsMo.getName();
ManagedObjectReference morFileManager = _context.getServiceContent().getFileManager();
String srcFullPath = srcFilePath;
if (!DatastoreFile.isFullDatastorePath(srcFullPath))
srcFullPath = String.format("[%s] %s", srcDsName, srcFilePath);
String destFullPath = destFilePath;
if (!DatastoreFile.isFullDatastorePath(destFullPath))
destFullPath = String.format("[%s] %s", destDsName, destFilePath);
DatastoreMO srcDsMo = new DatastoreMO(_context, morDestDs);
try {
if (!srcDsMo.fileExists(srcFullPath)) {
logger.error(String.format("Cannot move file to destination datastore due to file %s does not exists", srcFullPath));
return false;
}
} catch (Exception e) {
logger.error(String.format("Cannot move file to destination datastore due to file %s due to exception %s", srcFullPath, e.getMessage()));
return false;
}
ManagedObjectReference morTask = _context.getService().moveDatastoreFileTask(morFileManager, srcFullPath, morSrcDc, destFullPath, morDestDc, forceOverwrite);
boolean result = _context.getVimClient().waitForTask(morTask);
if (result) {
_context.waitForTaskProgressDone(morTask);
return true;
} else {
logger.error("VMware moveDatastoreFile_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask));
}
return false;
}
@Deprecated
public String[] listDirContent(String path) throws Exception {
String fullPath = path;
if (!DatastoreFile.isFullDatastorePath(fullPath))
fullPath = String.format("[%s] %s", getName(), fullPath);
Pair<DatacenterMO, String> dcPair = getOwnerDatacenter();
String url = getContext().composeDatastoreBrowseUrl(dcPair.second(), fullPath);
// TODO, VMware currently does not have a formal API to list Datastore directory content,
// following hacking may have performance hit if datastore has a large number of files
return _context.listDatastoreDirContent(url);
}
public boolean fileExists(String fileFullPath) throws Exception {
DatastoreFile file = new DatastoreFile(fileFullPath);
DatastoreFile dirFile = new DatastoreFile(file.getDatastoreName(), file.getDir());
HostDatastoreBrowserMO browserMo = getHostDatastoreBrowserMO();
logger.info("Search file " + file.getFileName() + " on " + dirFile.getPath());
HostDatastoreBrowserSearchResults results = browserMo.searchDatastore(dirFile.getPath(), file.getFileName(), true);
if (results != null) {
List<FileInfo> info = results.getFile();
if (info != null && info.size() == 1 && !(info.get(0) instanceof FolderFileInfo)) {
logger.info("File " + fileFullPath + " exists on datastore");
return true;
}
}
logger.info("File " + fileFullPath + " does not exist on datastore");
return false;
}
public long fileDiskSize(String fileFullPath) throws Exception {
long size = 0;
DatastoreFile file = new DatastoreFile(fileFullPath);
DatastoreFile dirFile = new DatastoreFile(file.getDatastoreName(), file.getDir());
HostDatastoreBrowserMO browserMo = getHostDatastoreBrowserMO();
HostDatastoreBrowserSearchSpec searchSpec = new HostDatastoreBrowserSearchSpec();
FileQueryFlags fqf = new FileQueryFlags();
fqf.setFileSize(true);
fqf.setFileOwner(true);
fqf.setFileType(true);
fqf.setModification(true);
searchSpec.setDetails(fqf);
searchSpec.setSearchCaseInsensitive(false);
searchSpec.getMatchPattern().add(file.getFileName());
logger.debug("Search file " + file.getFileName() + " on " + dirFile.getPath()); //ROOT-2.vmdk, [3ecf7a579d3b3793b86d9d019a97ae27] s-2-VM
HostDatastoreBrowserSearchResults result = browserMo.searchDatastore(dirFile.getPath(), searchSpec);
if (result != null) {
List<FileInfo> info = result.getFile();
for (FileInfo fi : info) {
if (file.getFileName().equals(fi.getPath())) {
logger.debug("File found = " + fi.getPath() + ", size=" + toHumanReadableSize(fi.getFileSize()));
return fi.getFileSize();
}
}
}
logger.debug("File " + fileFullPath + " does not exist on datastore");
return size;
}
public boolean folderExists(String folderParentDatastorePath, String folderName) throws Exception {
HostDatastoreBrowserMO browserMo = getHostDatastoreBrowserMO();
HostDatastoreBrowserSearchResults results = browserMo.searchDatastore(folderParentDatastorePath, folderName, true);
if (results != null) {
List<FileInfo> info = results.getFile();
if (info != null && info.size() == 1 && info.get(0) instanceof FolderFileInfo) {
logger.info("Folder " + folderName + " exists on datastore");
return true;
}
}
logger.info("Folder " + folderName + " does not exist on datastore");
return false;
}
public String searchFileInSubFolders(String fileName, boolean caseInsensitive) throws Exception {
return searchFileInSubFolders(fileName,caseInsensitive,null);
}
public String searchFileInSubFolders(String fileName, boolean caseInsensitive, String excludeFolders) throws Exception {
String datastorePath = "[" + getName() + "]";
String rootDirectoryFilePath = String.format("%s %s", datastorePath, fileName);
String[] searchExcludedFolders = getSearchExcludedFolders(excludeFolders);
if (fileExists(rootDirectoryFilePath)) {
return rootDirectoryFilePath;
}
String parentFolderPath;
String absoluteFileName = null;
logger.info("Searching file " + fileName + " in " + datastorePath);
HostDatastoreBrowserMO browserMo = getHostDatastoreBrowserMO();
ArrayList<HostDatastoreBrowserSearchResults> results = browserMo.searchDatastoreSubFolders("[" + getName() + "]", fileName, caseInsensitive);
if (results != null && results.size() > 1) {
logger.warn("Multiple files with name " + fileName + " exists in datastore " + datastorePath + ". Trying to choose first file found in search attempt.");
} else if (results == null) {
String msg = "No file found with name " + fileName + " found in datastore " + datastorePath;
logger.error(msg);
throw new CloudException(msg);
}
for (HostDatastoreBrowserSearchResults result : results) {
List<FileInfo> info = result.getFile();
if (info != null && info.size() > 0) {
for (FileInfo fi : info) {
absoluteFileName = parentFolderPath = result.getFolderPath();
logger.info("Found file " + fileName + " in datastore at " + absoluteFileName);
if (parentFolderPath.endsWith("]"))
absoluteFileName += " ";
else if (!parentFolderPath.endsWith("/"))
absoluteFileName +="/";
absoluteFileName += fi.getPath();
if(isValidCloudStackFolderPath(parentFolderPath, searchExcludedFolders)) {
return absoluteFileName;
}
break;
}
}
}
return absoluteFileName;
}
private String[] getSearchExcludedFolders(String excludeFolders) {
return excludeFolders != null ? excludeFolders.replaceAll("\\s","").split(",") : new String[] {};
}
private boolean isValidCloudStackFolderPath(String dataStoreFolderPath, String[] searchExcludedFolders) throws Exception {
String dsFolder = dataStoreFolderPath.replaceFirst("\\[" + getName() + "\\]", "").trim();
for( String excludedFolder : searchExcludedFolders) {
if (dsFolder.startsWith(excludedFolder)) {
return false;
}
}
return true;
}
public boolean isAccessibleToHost(String hostValue) throws Exception {
boolean isAccessible = true;
List<DatastoreHostMount> hostMounts = getHostMounts();
for (DatastoreHostMount hostMount : hostMounts) {
String hostMountValue = hostMount.getKey().getValue();
if (hostMountValue.equalsIgnoreCase(hostValue)) {
HostMountInfo mountInfo = hostMount.getMountInfo();
isAccessible = mountInfo.isAccessible();
break;
}
}
return isAccessible;
}
public boolean isDatastoreStoragePolicyComplaint(String storagePolicyId) throws Exception {
PbmProfileManagerMO profMgrMo = new PbmProfileManagerMO(_context);
PbmProfile profile = profMgrMo.getStorageProfile(storagePolicyId);
PbmPlacementSolverMO placementSolverMo = new PbmPlacementSolverMO(_context);
boolean isDatastoreCompatible = placementSolverMo.isDatastoreCompatibleWithStorageProfile(_mor, profile);
return isDatastoreCompatible;
}
public String getDatastoreType() throws Exception {
DatastoreSummary summary = _context.getVimClient().getDynamicProperty(getMor(), "summary");
return summary.getType() == null ? "" : summary.getType();
}
}