/*
* Copyright (c) 2008-2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.vnx;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.model.FSExportMap;
import com.emc.storageos.db.client.model.FileExport;
import com.emc.storageos.db.client.model.FileShare;
import com.emc.storageos.db.client.model.Operation;
import com.emc.storageos.db.client.model.QuotaDirectory;
import com.emc.storageos.db.client.model.SMBFileShare;
import com.emc.storageos.db.client.model.SMBShareMap;
import com.emc.storageos.db.client.model.Snapshot;
import com.emc.storageos.db.client.model.StorageHADomain;
import com.emc.storageos.db.client.model.StoragePort;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.exceptions.DeviceControllerErrors;
import com.emc.storageos.exceptions.DeviceControllerException;
import com.emc.storageos.model.file.ExportRule;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.util.ExportUtils;
import com.emc.storageos.util.FileSystemConstants;
import com.emc.storageos.vnx.xmlapi.VNXException;
import com.emc.storageos.vnx.xmlapi.VNXFileExport;
import com.emc.storageos.vnx.xmlapi.VNXFileSshApi;
import com.emc.storageos.vnx.xmlapi.VNXFileSystem;
import com.emc.storageos.vnx.xmlapi.VNXQuotaTree;
import com.emc.storageos.vnx.xmlapi.VNXSnapshot;
import com.emc.storageos.vnx.xmlapi.XMLApiResult;
import com.emc.storageos.volumecontroller.ControllerException;
import com.emc.storageos.volumecontroller.FileDeviceInputOutput;
import com.emc.storageos.volumecontroller.impl.BiosCommandResult;
import com.emc.storageos.volumecontroller.impl.file.AbstractFileStorageDevice;
import com.emc.storageos.volumecontroller.impl.plugins.provisioning.VNXFileCommApi;
import com.google.common.collect.Sets;
/*
* Suppressing these warnings as fix will be made in future release.
*/
@SuppressWarnings({ "findbugs:RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE", "findbugs:NP_NULL_ON_SOME_PATH" })
public class VNXFileStorageDeviceXML extends AbstractFileStorageDevice {
private static final Logger _log = LoggerFactory.getLogger(VNXFileStorageDeviceXML.class);
private static final String provision_context_file_name = "controller-vnxfile-prov.xml";
private static final String VNXCOMM_API = "vnxcommapi";
private static final String VNXCOMM_ERR_MSG = "VNXFile Provisioning context didn't get loaded properly";
private int _controllerID = 4002;
private DbClient _dbClient;
private static final String ERROR = "error";
private static final String READY = "ready";
private static int BYTESPERMB = 1048576;
public VNXFileStorageDeviceXML() {
this._controllerID = 4002;
}
public void setDbClient(DbClient dbc) {
_dbClient = dbc;
}
/**
* Loading context every time for each operation doesn't look right.
*
* TODO As of v1, adding this code, this definitely had to be changed.
*
* @return
*/
private VNXFileCommApi loadVNXFileCommunicationAPIs(ApplicationContext context) {
VNXFileCommApi vnxComm = null;
try {
vnxComm = (VNXFileCommApi) context.getBean(VNXCOMM_API);
vnxComm.setDbClient(_dbClient);
} catch (Exception e) {
throw new DeviceControllerException(
"VNXFile Provisioning context didn't get loaded properly.Terminating File System Provisioning operations.");
}
return vnxComm;
}
private ApplicationContext loadContext() {
ApplicationContext context = null;
try {
context = new ClassPathXmlApplicationContext(provision_context_file_name);
} catch (Exception e) {
throw new DeviceControllerException(
"VNXFile Provisioning context didn't get loaded properly.Terminating File System Provisioning operations.", e);
}
return context;
}
private void clearContext(ApplicationContext context) {
if (null != context) {
((ClassPathXmlApplicationContext) context).close();
}
}
@Override
public BiosCommandResult doCreateFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException {
Map<String, String> autoExtendAtts = getAutoExtendAttrs(args);
Long fsSize = args.getFsCapacity() / BYTESPERMB;
if (fsSize < 1) {
// Invalid size throw an error
String errMsg = "doCreateFS failed : FileSystem size in bytes is not valid " + args.getFsCapacity();
_log.error(errMsg);
return BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToCreateFileSystem(errMsg));
}
_log.info("FileSystem size translation : {} : {} ", args.getFsCapacity(), fsSize);
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
result = vnxComm.createFileSystem(storage,
args.getFsName(),
args.getPoolName(), // This will be used for CLI create FS
"1",
fsSize,
args.getThinProvision(),
args.getNativeDeviceFsId(),
autoExtendAtts);
if (result.isCommandSuccess()) {
VNXFileSystem vnxFS = (VNXFileSystem) result.getObject();
args.setFsNativeId(String.valueOf(vnxFS.getFsId()));
String path = "/" + args.getFsName();
// Set path & mountpath
args.setFsMountPath(path);
args.setFsPath(path);
}
} catch (VNXException e) {
throw DeviceControllerException.exceptions.unableToCreateFileSystem(e.getMessage(Locale.getDefault()));
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToCreateFileSystem(result.getMessage()));
}
return cmdResult;
}
public Map<String, String> getAutoExtendAttrs(FileDeviceInputOutput args) {
Map<String, String> autoAtts = new HashMap<String, String>();
if (args.getFsExtensions() == null) {
args.initFsExtensions();
}
String wormValue = "";
if (args.getFsExtensions().containsKey(VNXFileCommApi.WORM_ATTRIBUTE)) {
wormValue = args.getFsExtensions().get(VNXFileCommApi.WORM_ATTRIBUTE);
} else {
wormValue = args.getPoolExtensions().get(VNXFileCommApi.WORM_ATTRIBUTE);
}
wormValue = (wormValue != null) ? wormValue : VNXFileCommApi.WORM_DEF;
args.getFsExtensions().put(VNXFileCommApi.WORM_ATTRIBUTE, wormValue);
String autoExtendValue = "";
if (args.getFsExtensions().containsKey(VNXFileCommApi.AUTO_EXTEND_ENABLED_ATTRIBUTE)) {
autoExtendValue = args.getFsExtensions().get(VNXFileCommApi.AUTO_EXTEND_ENABLED_ATTRIBUTE);
} else {
autoExtendValue = args.getPoolExtensions().get(VNXFileCommApi.AUTO_EXTEND_ENABLED_ATTRIBUTE);
}
autoExtendValue = (autoExtendValue != null) ? autoExtendValue : VNXFileCommApi.AUTO_EXTEND_ENABLED_DEF;
args.getFsExtensions().put(VNXFileCommApi.AUTO_EXTEND_ENABLED_ATTRIBUTE, autoExtendValue);
String autoExtendHWM = args.getFsExtensions().get(VNXFileCommApi.AUTO_EXTEND_HWM_ATTRIBUTE);
String autoExtendMaxSize = args.getFsExtensions().get(VNXFileCommApi.AUTO_EXTEND_MAX_SIZE_ATTRIBUTE);
if (Boolean.valueOf(autoExtendValue).booleanValue() == true) {
_log.debug("AutoExtend is true");
autoExtendHWM = (autoExtendHWM != null) ? autoExtendHWM : args.getPoolExtensions().get(VNXFileCommApi.AUTO_EXTEND_HWM_DEF);
autoExtendHWM = (autoExtendHWM != null) ? autoExtendHWM : VNXFileCommApi.AUTO_EXTEND_HWM_DEF;
args.getFsExtensions().put(VNXFileCommApi.AUTO_EXTEND_HWM_ATTRIBUTE, autoExtendHWM);
autoExtendMaxSize = (autoExtendMaxSize != null) ? autoExtendMaxSize : args.getPoolExtensions().get(
VNXFileCommApi.AUTO_EXTEND_MAX_SIZE_ATTRIBUTE);
autoExtendMaxSize = (autoExtendMaxSize != null) ? autoExtendMaxSize : String.valueOf(args.getFsCapacity() * 1.1);
args.getFsExtensions().put(VNXFileCommApi.AUTO_EXTEND_MAX_SIZE_ATTRIBUTE, autoExtendMaxSize);
} else {
_log.debug("AutoExtend is false");
}
String fileSystemType = "";
if (args.getFsExtensions().containsKey(VNXFileCommApi.FILE_SYSTEM_TYPE_ATTRIBUTE)) {
fileSystemType = args.getFsExtensions().get(VNXFileCommApi.FILE_SYSTEM_TYPE_ATTRIBUTE);
} else {
fileSystemType = args.getPoolExtensions().get(VNXFileCommApi.FILE_SYSTEM_TYPE_ATTRIBUTE);
}
fileSystemType = (fileSystemType != null) ? fileSystemType : VNXFileCommApi.FILE_SYSTEM_TYPE_DEF;
args.getFsExtensions().put(VNXFileCommApi.FILE_SYSTEM_TYPE_ATTRIBUTE, fileSystemType);
String thinProvisioned = "";
if (args.getThinProvision() != null) {
thinProvisioned = String.valueOf(args.getThinProvision());
} else {
thinProvisioned = args.getPoolExtensions().get(VNXFileCommApi.THIN_PROVISIONED_ATTRIBUTE);
}
thinProvisioned = (thinProvisioned != null) ? thinProvisioned : VNXFileCommApi.THIN_PROVISIONED_DEF;
args.getFsExtensions().put(VNXFileCommApi.THIN_PROVISIONED_ATTRIBUTE, thinProvisioned);
autoAtts.put(VNXFileCommApi.FILE_SYSTEM_TYPE_ATTRIBUTE, args.getFsExtensions().get(VNXFileCommApi.FILE_SYSTEM_TYPE_ATTRIBUTE));
autoAtts.put(VNXFileCommApi.THIN_PROVISIONED_ATTRIBUTE, args.getFsExtensions().get(VNXFileCommApi.THIN_PROVISIONED_ATTRIBUTE));
autoAtts.put(VNXFileCommApi.WORM_ATTRIBUTE, args.getFsExtensions().get(VNXFileCommApi.WORM_ATTRIBUTE));
autoAtts.put(VNXFileCommApi.AUTO_EXTEND_ENABLED_ATTRIBUTE,
args.getFsExtensions().get(VNXFileCommApi.AUTO_EXTEND_ENABLED_ATTRIBUTE));
autoAtts.put(VNXFileCommApi.AUTO_EXTEND_HWM_ATTRIBUTE, args.getFsExtensions().get(VNXFileCommApi.AUTO_EXTEND_HWM_ATTRIBUTE));
autoAtts.put(VNXFileCommApi.AUTO_EXTEND_MAX_SIZE_ATTRIBUTE,
args.getFsExtensions().get(VNXFileCommApi.AUTO_EXTEND_MAX_SIZE_ATTRIBUTE));
return autoAtts;
}
@Override
public BiosCommandResult doDeleteFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException {
_log.info("doDeleteFS: fs id = {} Force Delete : {}", args.getFsNativeId(), args.getForceDelete());
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
_log.info("DBClient :" + vnxComm.getDbClient());
result = vnxComm.deleteFileSystem(storage, args.getFsNativeId(), args.getFsName(), args.getForceDelete(), args.getFs());
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToDeleteFileSystem(result.getMessage()));
}
return cmdResult;
}
@Override
public boolean doCheckFSExists(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
_log.info("checking file system existence on array: ", args.getFsName());
boolean isFSExists = true;
try {
ApplicationContext context = null;
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
isFSExists = vnxComm.checkFileSystemExists(storage, args.getFsNativeId(), args.getFsName());
} catch (VNXException e) {
_log.error("Querying FS existence failed");
}
return isFSExists;
}
@Override
public BiosCommandResult updateExportRules(StorageSystem storage,
FileDeviceInputOutput args)
throws ControllerException {
XMLApiResult result = null;
ApplicationContext context = null;
// Requested Export Rules
List<ExportRule> exportAdd = args.getExportRulesToAdd();
List<ExportRule> exportDelete = args.getExportRulesToDelete();
List<ExportRule> exportModify = args.getExportRulesToModify();
// To be processed export rules
List<ExportRule> exportsToRemove = new ArrayList<>();
List<ExportRule> exportsToAdd = new ArrayList<>();
String exportPath;
String subDir = args.getSubDirectory();
if (!args.getFileOperation()) {
exportPath = args.getSnapshotPath();
if (subDir != null && subDir.length() > 0) {
exportPath = args.getSnapshotPath() + "/" + subDir;
}
} else {
exportPath = args.getFs().getPath();
if (subDir != null && subDir.length() > 0) {
exportPath = args.getFs().getPath() + "/" + subDir;
}
}
_log.info("exportPath : {}", exportPath);
args.setExportPath(exportPath);
try {
// add the new export rule from the array into the update request.
Map<String, ExportRule> arrayExportRuleMap = extraExportRuleFromArray(storage, args);
if (!arrayExportRuleMap.isEmpty()) {
if (exportModify != null) {
// merge the end point for which sec flavor is common.
for (ExportRule exportRule : exportModify) {
ExportRule arrayExportRule = arrayExportRuleMap.remove(exportRule.getSecFlavor());
if (arrayExportRule != null) {
if (exportRule.getReadOnlyHosts() != null) {
exportRule.getReadOnlyHosts().addAll(arrayExportRule.getReadOnlyHosts());
} else {
exportRule.setReadOnlyHosts(arrayExportRule.getReadOnlyHosts());
}
if (exportRule.getReadWriteHosts() != null) {
exportRule.getReadWriteHosts().addAll(arrayExportRule.getReadWriteHosts());
} else {
exportRule.setReadWriteHosts(arrayExportRule.getReadWriteHosts());
}
if (exportRule.getRootHosts() != null) {
exportRule.getRootHosts().addAll(arrayExportRule.getRootHosts());
} else {
exportRule.setRootHosts(arrayExportRule.getRootHosts());
}
}
}
// now add the remaining export rule
exportModify.addAll(arrayExportRuleMap.values());
} else {
// if exportModify is null then create a new export rule and add
exportModify = new ArrayList<ExportRule>();
exportModify.addAll(arrayExportRuleMap.values());
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
_log.error("Not able to fetch latest Export rule from backend array.", e);
}
// ALL EXPORTS
List<ExportRule> existingDBExportRule = args.getExistingDBExportRules();
List<ExportRule> exportsToprocess = new ArrayList<>();
for (ExportRule rule : existingDBExportRule) {
if (rule.getExportPath().equalsIgnoreCase(exportPath)) {
exportsToprocess.add(rule);
}
}
_log.info("Number of existng Rules found {}", exportsToprocess.size());
// Handle Modified export Rules and add rules
// If there are no Export rules and add is allowed
if (!exportsToprocess.isEmpty() || (exportAdd != null && !exportAdd.isEmpty())) {
for (ExportRule existingRule : exportsToprocess) {
for (ExportRule modifiedrule : exportModify) {
if (modifiedrule.getSecFlavor().equals(
existingRule.getSecFlavor())) {
_log.info("Modifying Export Rule from {}, To {}",
existingRule, modifiedrule);
// use a separate list to avoid concurrent modifications for now.
exportsToRemove.add(existingRule);
exportsToAdd.add(modifiedrule);
}
}
}
// Handle Add export Rules
if (exportAdd != null && !exportAdd.isEmpty()) {
for (ExportRule newExport : exportAdd) {
_log.info("Adding Export Rule {}", newExport);
exportsToAdd.add(newExport);
}
}
// Handle Delete export Rules
if (exportDelete != null && !exportDelete.isEmpty()) {
for (ExportRule existingRule : exportsToprocess) {
for (ExportRule oldExport : exportDelete) {
if (oldExport.getSecFlavor().equals(
existingRule.getSecFlavor())) {
_log.info("Deleting Export Rule {}", existingRule);
exportsToRemove.add(existingRule);
}
}
}
}
// No of exports found to remove from the list
_log.info("No of exports found to remove from the existing exports list {}", exportsToRemove.size());
exportsToprocess.removeAll(exportsToRemove);
_log.info("No of exports found to add to the existing exports list {}", exportsToAdd.size());
exportsToprocess.addAll(exportsToAdd);
// Figure out mounted or not
SMBShareMap shares = args.getFs().getSMBFileShares();
boolean isMounted = true;
if (exportsToprocess.isEmpty() &&
(shares == null || (shares != null && shares.isEmpty()))) {
isMounted = false;
}
// Mounting is only necessary for FileSystem and not snapshot for the first time export
if (!args.getFileOperation()) {
isMounted = false;
}
// To be compatible with existing export creating an empty list
List<String> newPaths = new ArrayList<String>();
newPaths.add(exportPath);
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
// Get DataMover Name and whether it is virtual
StorageHADomain dm = this.getDataMover(args.getFs());
if (dm == null) {
Exception e = new Exception("VNX File Export Failed Data Mover not found");
throw VNXException.exceptions.createExportFailed("VNX File Export Failed Data Mover not found", e);
}
List<VNXFileExport> exportList = new ArrayList<VNXFileExport>();
for (ExportRule rule : exportsToprocess) {
VNXFileExport vnxExp = null;
// update the comment
String comments = rule.getComments();
String protocol = "nfs";
if (rule.getReadOnlyHosts() != null && !rule.getReadOnlyHosts().isEmpty()) {
vnxExp = new VNXFileExport(new ArrayList<String>(rule.getReadOnlyHosts()),
dm.getName(), exportPath,
rule.getSecFlavor(), "ro",
rule.getAnon(), protocol,
args.getFs().getStoragePort().toString(), subDir, comments);
exportList.add(vnxExp);
}
if (rule.getReadWriteHosts() != null && !rule.getReadWriteHosts().isEmpty()) {
vnxExp = new VNXFileExport(new ArrayList<String>(rule.getReadWriteHosts()),
dm.getName(), exportPath,
rule.getSecFlavor(), "rw",
rule.getAnon(), protocol,
args.getFs().getStoragePort().toString(), subDir, comments);
exportList.add(vnxExp);
}
if (rule.getRootHosts() != null && !rule.getRootHosts().isEmpty()) {
vnxExp = new VNXFileExport(new ArrayList<String>(rule.getRootHosts()),
dm.getName(), exportPath,
rule.getSecFlavor(), "root",
rule.getAnon(), protocol,
args.getFs().getStoragePort().toString(), subDir, comments);
exportList.add(vnxExp);
}
}
// When all the export rules removed, add one rule manually to meet the requirments of
// existing VNXComm API. This is required to read the subsequent information down the line.
if ((exportList != null && exportList.isEmpty()) && (exportsToRemove != null && !exportsToRemove.isEmpty())) {
_log.info("Requested to remove all export rules");
VNXFileExport vnxExp = new VNXFileExport(new ArrayList<String>(),
dm.getName(), exportPath,
"", "root", "", "",
args.getFs().getStoragePort().toString(), subDir, "");
exportList.add(vnxExp);
}
// List<VNXFileExport> vnxExports = getVNXFileExports(newExpList);
if (args.getFileOperation()) {
// Perform FileSystem export
result = vnxComm.doExport(storage, dm, exportList, newPaths, args.getFileObj(), args.getFsNativeId(), isMounted);
} else {
// perform Snapshot export
result = vnxComm.doExport(storage, dm, exportList, newPaths, args.getFileObj(), args.getSnapNativeId(), isMounted);
}
if (result.isCommandSuccess()) {
_log.info("updateExportRules result.isCommandSuccess true");
}
} catch (VNXException e) {
throw VNXException.exceptions.createExportFailed("VNX File Export Failed", e);
} finally {
clearContext(context);
}
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToUpdateExport(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doExport(StorageSystem storage, FileDeviceInputOutput args, List<FileExport> exportList)
throws ControllerException {
boolean firstExport = false;
if (args.getFileObjExports() == null || args.getFileObjExports().isEmpty()) {
args.initFileObjExports();
}
// mount the FileSystem
firstExport = !(args.isFileShareMounted());
if (firstExport) {
_log.debug("First export: no existing file exports");
}
// Mounting is only necessary for FileSystem and not snapshot for the first time export
if (!args.getFileOperation()) {
firstExport = false;
}
// Create a list of the new exports.
FSExportMap newExpList = new FSExportMap();
FSExportMap curExpList = args.getFileObjExports();
FileExport curExport = null;
FileExport newExport = null;
List<String> newPaths = new ArrayList<String>();
Iterator<String> it = curExpList.keySet().iterator();
while (it.hasNext()) {
curExport = curExpList.get(it.next());
newExport = new FileExport(curExport.getClients(), curExport.getStoragePortName(),
ExportUtils.getFileMountPoint(curExport.getStoragePort(), curExport.getPath()),
curExport.getSecurityType(), curExport.getPermissions(), curExport.getRootUserMapping(),
curExport.getProtocol(), curExport.getStoragePort(), curExport.getPath(),
curExport.getMountPath(), curExport.getSubDirectory(), curExport.getComments());
_log.info("FileExport key : {} ", newExport.getFileExportKey());
newExpList.put(newExport.getFileExportKey(), newExport);
}
for (FileExport exp : exportList) {
newExport = new FileExport(exp.getClients(), exp.getStoragePortName(),
ExportUtils.getFileMountPoint(exp.getStoragePort(), exp.getPath()),
exp.getSecurityType(), exp.getPermissions(), exp.getRootUserMapping(), exp.getProtocol(),
exp.getStoragePort(), exp.getPath(), exp.getMountPath(), exp.getSubDirectory(), exp.getComments());
_log.info("FileExport key : {} ", newExport.getFileExportKey());
newExpList.put(newExport.getFileExportKey(), newExport);
if (!newPaths.contains(newExport.getPath())) {
newPaths.add(newExport.getPath());
}
}
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
// Get DataMover Name and whether it is virtual
StorageHADomain dm = this.getDataMover(args.getFs());
if (dm == null) {
Exception e = new Exception("VNX File Export Failed Data Mover not found");
throw VNXException.exceptions.createExportFailed("VNX File Export Failed Data Mover not found", e);
}
List<VNXFileExport> vnxExports = getVNXFileExports(newExpList);
if (args.getFileOperation()) {
// Perform FileSystem export
result = vnxComm.doExport(storage, dm, vnxExports, newPaths, args.getFileObj(), args.getFsNativeId(), firstExport);
} else {
// perform Snapshot export
result = vnxComm.doExport(storage, dm, vnxExports, newPaths, args.getFileObj(), args.getSnapNativeId(), firstExport);
}
if (result.isCommandSuccess()) {
curExpList.putAll(newExpList);
}
} catch (VNXException e) {
throw VNXException.exceptions.createExportFailed("VNX File Export Failed", e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToExportFileSystem(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doUnexport(StorageSystem storage, FileDeviceInputOutput args, List<FileExport> exportList)
throws ControllerException {
_log.info("doUnExport " + args.getOperationType());
_log.info("Call FileShare UnExport");
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
for (int expCount = 0; expCount < exportList.size(); expCount++) {
List<String> endPoints = new ArrayList<String>();
FileExport export = exportList.get(expCount);
String exportEntryKey = FileExport.exportLookupKey(export.getProtocol(),
export.getSecurityType(), export.getPermissions(), export.getRootUserMapping(),
export.getPath());
FileExport fileExport = args.getFileObjExports().get(exportEntryKey);
if (fileExport != null) {
endPoints.addAll(fileExport.getClients());
}
export.setClients(endPoints);
_log.info("FileExport:" + export.getClients() + ":" + export.getStoragePortName()
+ ":" + export.getStoragePort() + ":" + export.getRootUserMapping()
+ ":" + export.getPermissions() + ":" + export.getProtocol()
+ ":" + export.getSecurityType() + ":" + export.getMountPoint()
+ ":" + export.getPath());
}
List<VNXFileExport> vnxExps = getVNXFileExports(exportList);
result = vnxComm.doUnexport(storage, vnxExps.get(0), args, false);
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToUnexportFileSystem(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doExpandFS(StorageSystem storage, FileDeviceInputOutput args)
throws ControllerException {
_log.info("Call FileSystem Expand");
// For the request to succeed to expand, the system must be mounted.
// Below snippet helps to verify whether FS Mounted or not.
// Note : Since, Every Export will mount the FileSystem at first, we
// should do cross check as below whether file system is already mounted or not
// using FSExportMap and SMBShareMap
// If FileShare mounted then Mount is not required
boolean isMountRequired = !(args.isFileShareMounted());
_log.info("Mount required or not, to expand requested FileSystem {}", isMountRequired);
Long newFsExpandSize = args.getNewFSCapacity();
if (args.getNewFSCapacity() % BYTESPERMB == 0) {
newFsExpandSize = newFsExpandSize / BYTESPERMB;
} else {
newFsExpandSize = newFsExpandSize / BYTESPERMB + 1;
}
_log.info("FileSystem new size translation : {} : {}", args.getNewFSCapacity(), args.getFsCapacity());
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
result = vnxComm.expandFS(storage, args.getFs(), newFsExpandSize, isMountRequired, args.getThinProvision());
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToExpandFileSystem(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doShare(StorageSystem storage, FileDeviceInputOutput args, SMBFileShare smbFileShare)
throws ControllerException {
_log.info("Call FileShare doShare");
boolean firstExport = false;
if (args.getFileObjShares() == null || args.getFileObjShares().isEmpty()) {
args.initFileObjShares();
}
firstExport = !(args.isFileShareMounted());
if (firstExport) {
_log.debug("First export: no existing file obj shares");
}
if (!args.getFileOperation()) {
firstExport = false;
}
String portName = smbFileShare.getPortGroup();
String path = smbFileShare.getPath();
if (path == null || path.length() == 0) {
if (args.getFileOperation()) {
path = args.getFsMountPath();
} else {
path = args.getSnapshotMountPath();
}
}
_log.debug("Data Mover: {}", portName);
_log.debug("Mount path: {}", path);
XMLApiResult result = null;
ApplicationContext context = null;
try {
List<String> clients = new ArrayList<String>();
VNXFileExport fileExport = new VNXFileExport(clients,
portName,
path,
"", // no security type
smbFileShare.getPermission(),
"", // root user mapping n/a for CIFS
VNXFileSshApi.VNX_CIFS,
"", // Port information is never used for for CIFS or NFS exports.
"", // SUB DIR
""); // Comments -- TODO
fileExport.setExportName(smbFileShare.getName());
fileExport.setComment(smbFileShare.getDescription());
fileExport.setMaxUsers(Integer.toString(smbFileShare.getMaxUsers()));
List<VNXFileExport> vnxExports = new ArrayList<VNXFileExport>();
vnxExports.add(fileExport);
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
// Get DataMover
StorageHADomain dm = this.getDataMover(args.getFs());
if (dm == null) {
Exception e = new Exception("VNX File Share creation Failed Data Mover not found");
throw VNXException.exceptions.createExportFailed("VNX File Share creation Failed Data Mover not found", e);
}
List<String> paths = new ArrayList<String>();
paths.add(path);
if (args.getFileOperation()) {
// Perform FileSystem export
result = vnxComm.doExport(storage, dm, vnxExports, paths, args.getFileObj(), args.getFsNativeId(), firstExport);
} else {
// perform Snapshot export
result = vnxComm.doExport(storage, dm, vnxExports, paths, args.getFileObj(), args.getSnapNativeId(), firstExport);
}
if ((result != null) && (result.isCommandSuccess())) {
// Set MountPoint
smbFileShare.setMountPoint(fileExport.getNetBios(), smbFileShare.getStoragePortNetworkId(),
smbFileShare.getStoragePortName(), smbFileShare.getName());
args.getFileObjShares().put(smbFileShare.getName(), smbFileShare);
}
} catch (VNXException e) {
throw new DeviceControllerException(e);
} catch (NumberFormatException e) {
// Placeholder until real handling is determined.
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToCreateFileShare(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doDeleteShare(StorageSystem storage, FileDeviceInputOutput args, SMBFileShare smbFileShare)
throws ControllerException {
_log.info("Call FileShare doDeleteShare");
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
StorageHADomain dm = null;
String mountPoint = null;
if (args.getFileOperation()) {
mountPoint = args.getFs().getMountPath();
// Get DataMover
dm = this.getDataMover(args.getFs());
if (dm == null) {
Exception e = new Exception("VNX File Share creation Failed Data Mover not found");
throw VNXException.exceptions.createExportFailed("VNX File Delete Share Failed Data Mover not found", e);
}
} else {
// Get DataMover
URI snapshotId = args.getSnapshotId();
Snapshot snapshot = _dbClient.queryObject(Snapshot.class, snapshotId);
FileShare fileshare = _dbClient.queryObject(FileShare.class, snapshot.getParent().getURI());
mountPoint = fileshare.getMountPath();
dm = this.getDataMover(fileshare);
if (dm == null) {
Exception e = new Exception("VNX File Share creation Failed Data Mover not found");
throw VNXException.exceptions.createExportFailed("VNX File Delete Share Failed Data Mover not found", e);
}
}
result = vnxComm.doDeleteShare(storage, dm, smbFileShare.getName(), mountPoint, false, args);
args.getFileObjShares().remove(smbFileShare.getName());
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToDeleteFileShare(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doDeleteShares(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
result.setCommandSuccess(false);
result.setCommandStatus(Operation.Status.error.name());
result.setMessage("SMB sharing is not supported.");
return result;
}
@Override
public BiosCommandResult doModifyFS(StorageSystem storage, FileDeviceInputOutput args)
throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
result.setCommandSuccess(false);
result.setCommandStatus(Operation.Status.error.name());
result.setMessage("Modify FS NOT supported for VNX.");
return result;
}
@Override
public BiosCommandResult doSnapshotFS(StorageSystem storage, FileDeviceInputOutput args)
throws ControllerException {
// generate checkpoint baseline name
args.setSnaphotCheckPointBaseline(args.getSnapshotName() + "_baseline");
args.setSnapshotMountPath("/" + args.getSnapshotName());
_log.info("FileShare, Snapshot {} {}", args.getFsUUID(), args.getSnapshotId());
_log.info("FSName: {}", args.getFsName());
_log.info("SnapShotName: {}", args.getSnapshotName());
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
FileShare fileShare = args.getFs();
result = vnxComm.createSnapshot(storage, args.getFsName(), args.getSnapshotName(), fileShare);
_log.info("createSnapshot call result : {}", result.isCommandSuccess());
if (result.isCommandSuccess()) {
VNXSnapshot vnxSnap = (VNXSnapshot) result.getObject();
args.setSnapNativeId(String.valueOf(vnxSnap.getId()));
String path = "/" + args.getSnapshotName();
// Set path & mountpath
args.setSnapshotMountPath(path);
args.setSnapshotPath(path);
}
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
_log.info("Status of the result {}", (result != null) ? result.isCommandSuccess() : result);
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToCreateFileSnapshot(result.getMessage()));
}
return cmdResult;
}
@Override
public BiosCommandResult doRestoreFS(StorageSystem storage, FileDeviceInputOutput args)
throws ControllerException {
_log.info("FileShare, Snapshot {} {}", args.getFsUUID(), args.getSnapshotId());
_log.info("FSName: {}", args.getFsName());
_log.info("SnapShotName: {}", args.getSnapshotName());
int snapNativeId = 0;
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
result = vnxComm.doRestoreSnapshot(storage, args.getFsNativeId(), args.getFsName(), args.getSnapNativeId(),
args.getSnapshotName());
_log.info("restoreSnapshot call result : {}", result.isCommandSuccess());
} catch (NumberFormatException ne) {
// Call failed
result = new XMLApiResult();
result.setCommandFailed();
result.setMessage("Not valid snapshot Id " + args.getSnapNativeId());
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
_log.info("restoreSnapshot call result : {}", result.isCommandSuccess());
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToRestoreFileSystem(result.getMessage()));
}
return cmdResult;
}
// Get FS snapshot list from the array
@Override
public BiosCommandResult getFSSnapshotList(StorageSystem storage,
FileDeviceInputOutput args, List<String> snapshots)
throws ControllerException {
// TODO: Implement method
String op = "getFSSnapshotList";
String devType = storage.getSystemType();
BiosCommandResult result = BiosCommandResult
.createErrorResult(DeviceControllerException.errors.unsupportedOperationOnDevType(op, devType));
return result;
}
private List<VNXFileExport> getVNXFileExports(FSExportMap existingExps) {
List<VNXFileExport> vnxExports = new ArrayList<VNXFileExport>();
if (existingExps != null && !existingExps.isEmpty()) {
for (FileExport cur : existingExps.values()) {
_log.debug("Added export sec, perm {} {}", cur.getSecurityType(), cur.getPermissions());
_log.debug(" anon,path {} {}", cur.getRootUserMapping(), cur.getPath());
VNXFileExport vnxExp = new VNXFileExport(cur.getClients(),
cur.getStoragePortName(), cur.getPath(),
cur.getSecurityType(), cur.getPermissions(),
cur.getRootUserMapping(), cur.getProtocol(),
cur.getStoragePort(), cur.getSubDirectory(), cur.getComments());
vnxExports.add(vnxExp);
}
}
return vnxExports;
}
private List<VNXFileExport> getVNXFileExports(List<FileExport> exports) {
List<VNXFileExport> vnxExports = new ArrayList<VNXFileExport>();
for (FileExport exp : exports) {
_log.debug("Added export sec, perm {} {}", exp.getSecurityType(), exp.getPermissions());
_log.debug(" anon,path {} {}", exp.getRootUserMapping(), exp.getPath());
VNXFileExport vnxExp = new VNXFileExport(exp.getClients(), exp.getStoragePortName(), exp.getPath(), exp.getSecurityType(),
exp.getPermissions(), exp.getRootUserMapping(), exp.getProtocol(), exp.getStoragePort(), exp.getSubDirectory(),
exp.getComments());
vnxExports.add(vnxExp);
}
return vnxExports;
}
@Override
public BiosCommandResult doDeleteSnapshot(StorageSystem storage, FileDeviceInputOutput args)
throws ControllerException {
// generate checkpoint baseline name
_log.info("FileShare, Snapshot {} {}", args.getFsUUID(), args.getSnapshotId());
_log.info("FSName: {}", args.getFsName());
_log.info("SnapShotName: {}", args.getSnapshotName());
_log.info("SnapShotBaseline: {}", args.getSnapshotCheckPointBaseline());
XMLApiResult result = null;
ApplicationContext context = null;
try {
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
result = vnxComm.doDeleteSnapshot(storage, args.getSnapNativeId(), args.getSnapshotName(), true);
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToDeleteFileSnapshot(result.getMessage()));
}
return cmdResult;
}
@Override
public void doConnect(StorageSystem storage) {
}
@Override
public void doDisconnect(StorageSystem storage) {
// FIX ME
}
@Override
public BiosCommandResult getPhysicalInventory(StorageSystem storage) {
BiosCommandResult result = new BiosCommandResult();
result.setCommandSuccess(true);
return result;
}
private StorageHADomain getDataMover(FileShare fileShare) {
StoragePort port = _dbClient.queryObject(StoragePort.class, fileShare.getStoragePort());
StorageHADomain dm = null;
if (port != null) {
dm = _dbClient.queryObject(StorageHADomain.class, port.getStorageHADomain());
}
return dm;
}
@Override
public BiosCommandResult deleteExportRules(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult biosResult = new BiosCommandResult();
biosResult.setCommandSuccess(true);
biosResult.setCommandStatus(Operation.Status.ready.name());
List<ExportRule> allExports = args.getExistingDBExportRules();
String subDir = args.getSubDirectory();
boolean allDirs = args.isAllDir();
String exportPath;
String subDirExportPath = "";
if (!args.getFileOperation()) {
exportPath = args.getSnapshotPath();
if (subDir != null && subDir.length() > 0) {
subDirExportPath = args.getSnapshotPath() + "/" + subDir;
}
} else {
exportPath = args.getFs().getPath();
if (subDir != null && subDir.length() > 0) {
subDirExportPath = args.getFs().getPath() + "/" + subDir;
}
}
Set<String> allPaths = new HashSet<String>();
try {
if (allDirs) {
// ALL EXPORTS
_log.info("Deleting all exports specific to filesystem at device and rules from DB including sub dirs rules and exports");
for (ExportRule rule : allExports) {
allPaths.add(rule.getExportPath());
}
} else if (subDir != null && !subDir.isEmpty()) {
// Filter for a specific Sub Directory export
_log.info(
"Deleting all subdir exports rules at ViPR and sub directory export at device {}",
subDir);
for (ExportRule rule : allExports) {
if (rule.getExportPath().endsWith("/" + subDir)) {
allPaths.add(subDirExportPath);
break;
}
}
} else {
// Filter for No SUBDIR - main export rules with no sub dirs
_log.info("Deleting all export rules from DB and export at device not included sub dirs");
allPaths.add(exportPath);
}
_log.info("Number of Exports to Delete : {}", allPaths.size());
Map<String, Boolean> operationResult = new HashMap<String, Boolean>();
XMLApiResult result = null;
ApplicationContext context = null;
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
for (String exportPathToDelete : allPaths) {
_log.info("Deleting Export Path {}", exportPathToDelete);
try {
result = vnxComm.doDeleteExport(storage, exportPathToDelete, args, false);
if (result.isCommandSuccess()) {
_log.info("Export Deleted : {}", exportPathToDelete);
operationResult.put(exportPathToDelete, true);
} else {
_log.error("Error deleting Export : {}", exportPathToDelete);
operationResult.put(exportPathToDelete, false);
biosResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToUnexportFileSystem(result
.getMessage()));
}
} catch (Exception e) {
_log.error("Error deleting Export : {}", exportPathToDelete);
operationResult.put(exportPathToDelete, false);
biosResult = BiosCommandResult
.createErrorResult(DeviceControllerErrors.vnx.unableToUnexportFileSystem(result.getMessage()));
}
}
} catch (VNXException e) {
_log.error("Exception:" + e.getMessage());
throw new DeviceControllerException(
"Exception while performing export for {0} ",
new Object[] { args.getFsId() });
}
_log.info("VNXFileStorageDevice deleteExportRules {} - complete", args.getFsId());
return biosResult;
}
@Override
public BiosCommandResult doCreateQuotaDirectory(StorageSystem storage,
FileDeviceInputOutput args, QuotaDirectory quotaDir) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
ApplicationContext context = null;
XMLApiResult apiResult = null;
try {
_log.info("VNXFileStorageDeviceXML doCreateQuotaDirectory - start");
String fsName = args.getFsName();
String quotaTreetreeName = args.getQuotaDirectoryName();
Boolean oplocks = quotaDir.getOpLock();
String securityStyle = quotaDir.getSecurityStyle();
Long size = quotaDir.getSize();
if (null == fsName) {
_log.error("VNXFileStorageDeviceXML::doCreateQuotaDirectory failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.vnx.unableToCreateQuotaDir();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == quotaTreetreeName) {
_log.error("VNXFileStorageDeviceXML::doCreateQuotaDirectory failed: Quota Tree name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.vnx.unableToCreateQuotaDir();
serviceError.setMessage(FileSystemConstants.FS_ERR_QUOTADIR_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
_log.info("FSName: {}", args.getFsName());
_log.info("Quota tree name: {}", args.getQuotaDirectoryName());
boolean isMountRequired = !(args.isFileShareMounted());
_log.info("Mount required or not, to create quota dir requested {}", isMountRequired);
// Load the context
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
// quota directory create/update takes size in MB as similar to FS create.
Long sizeMBs = size / BYTESPERMB;
apiResult = vnxComm.createQuotaDirectory(storage, args.getFsName(), quotaTreetreeName, securityStyle, sizeMBs, oplocks,
isMountRequired);
_log.info("createQuotaDirectory call result : {}", apiResult.isCommandSuccess());
if (apiResult.isCommandSuccess()) {
VNXQuotaTree quotaTree = (VNXQuotaTree) apiResult.getObject();
args.getQuotaDirectory().setNativeId(String.valueOf(quotaTree.getId()));
result = BiosCommandResult.createSuccessfulResult();
}
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
_log.info("Status of the result {}", (result != null) ? result.isCommandSuccess() : result);
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToCreateQuotaDir());
}
return cmdResult;
}
@Override
public BiosCommandResult doDeleteQuotaDirectory(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
ApplicationContext context = null;
XMLApiResult apiResult = null;
try {
_log.info("VNXFileStorageDeviceXML doDeleteQuotaDirectory - start");
String fsName = args.getFsName();
String quotaTreetreeName = args.getQuotaDirectoryName();
QuotaDirectory quotaDir = args.getQuotaDirectory();
if (null == fsName) {
_log.error("VNXFileStorageDeviceXML::doDeleteQuotaDirectory failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.vnx.unableToDeleteQuotaDir();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == quotaTreetreeName) {
_log.error("VNXFileStorageDeviceXML::doDeleteQuotaDirectory failed: Quota Tree name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.vnx.unableToDeleteQuotaDir();
serviceError.setMessage(FileSystemConstants.FS_ERR_QUOTADIR_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
_log.info("FSName: {}", args.getFsName());
_log.info("Quota tree name: {}", args.getQuotaDirectoryName());
boolean isMountRequired = !(args.isFileShareMounted());
_log.info("Mount required or not, to delete quota dir requested {}", isMountRequired);
// Load the context
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
// we can't delete quota, if the filsystem is not mount, We should changes quota cmd
apiResult = vnxComm.deleteQuotaDirectory(storage, args.getFsName(), quotaTreetreeName, true, isMountRequired);
if (apiResult.isCommandSuccess()) {
result = BiosCommandResult.createSuccessfulResult();
}
_log.info("doDeleteQuotaDirectory call result : {}", apiResult.isCommandSuccess());
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToDeleteQuotaDir());
}
return cmdResult;
}
@Override
public BiosCommandResult doUpdateQuotaDirectory(StorageSystem storage,
FileDeviceInputOutput args, QuotaDirectory quotaDir) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
ApplicationContext context = null;
XMLApiResult apiResult = null;
try {
_log.info("VNXFileStorageDeviceXML doUpdateQuotaDirectory - start");
String fslName = args.getFsName();
String quotaTreetreeName = args.getQuotaDirectoryName();
Boolean oplocks = quotaDir.getOpLock();
String securityStyle = quotaDir.getSecurityStyle();
Long size = quotaDir.getSize();
if (null == fslName) {
_log.error("VNXFileStorageDeviceXML::doUpdateQuotaDirectory failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.vnx.unableToUpdateQuotaDir();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == quotaTreetreeName) {
_log.error("VNXFileStorageDeviceXML::doUpdateQuotaDirectory failed: Quota Tree name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.vnx.unableToUpdateQuotaDir();
serviceError.setMessage(FileSystemConstants.FS_ERR_QUOTADIR_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
_log.info("FSName: {}", args.getFsName());
_log.info("Quota tree name: {}", args.getQuotaDirectoryName());
boolean isMountRequired = !(args.isFileShareMounted());
_log.info("Mount required or not, to update quota dir requested {}", isMountRequired);
// Load the context
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
// quota directory create/update takes size in MB as similar to FS create.
Long sizeMBs = size / BYTESPERMB;
apiResult = vnxComm.modifyQuotaDirectory(storage, args.getFsName(), quotaTreetreeName, securityStyle, sizeMBs, oplocks,
isMountRequired);
_log.info("doUpdateQuotaDirectory call result : {}", apiResult.isCommandSuccess());
if (apiResult.isCommandSuccess()) {
VNXQuotaTree quotaTree = (VNXQuotaTree) apiResult.getObject();
args.getQuotaDirectory().setNativeId(String.valueOf(quotaTree.getId()));
result = BiosCommandResult.createSuccessfulResult();
}
} catch (VNXException e) {
throw new DeviceControllerException(e);
} finally {
clearContext(context);
}
BiosCommandResult cmdResult = null;
if (result.isCommandSuccess()) {
cmdResult = BiosCommandResult.createSuccessfulResult();
} else {
cmdResult = BiosCommandResult.createErrorResult(DeviceControllerErrors.vnx.unableToUpdateQuotaDir());
}
return cmdResult;
}
/**
* Get the export rule which are present in array but not in CoprHD Database.
*
* @param storage
* @param args
* @return map with security flavor and export rule
*/
private Map<String, ExportRule> extraExportRuleFromArray(StorageSystem storage, FileDeviceInputOutput args) {
// map to store the export rule grouped by sec flavor
Map<String, ExportRule> exportRuleMap = new HashMap<>();
Set<String> arrayReadOnlyHost = new HashSet<>();
Set<String> arrayReadWriteHost = new HashSet<>();
Set<String> arrayRootHost = new HashSet<>();
Set<String> dbReadOnlyHost = new HashSet<>();
Set<String> dbReadWriteHost = new HashSet<>();
Set<String> dbRootHost = new HashSet<>();
// get all export rule from CoprHD data base
List<ExportRule> existingDBExportRules = args.getExistingDBExportRules();
// get the all the export from the storage system.
ApplicationContext context = null;
context = loadContext();
VNXFileCommApi vnxComm = loadVNXFileCommunicationAPIs(context);
if (null == vnxComm) {
throw VNXException.exceptions.communicationFailed(VNXCOMM_ERR_MSG);
}
for (ExportRule exportRule : existingDBExportRules) {
if (exportRule.getReadOnlyHosts() != null) {
dbReadOnlyHost.addAll(exportRule.getReadOnlyHosts());
}
if (exportRule.getReadWriteHosts() != null) {
dbReadWriteHost.addAll(exportRule.getReadWriteHosts());
}
if (exportRule.getRootHosts() != null) {
dbRootHost.addAll(exportRule.getRootHosts());
}
Map<String, String> vnxExportMap = null;
vnxExportMap = vnxComm.getNFSExport(storage, args);
String readOnlyList = vnxExportMap.get("ro");
String readWriteList = vnxExportMap.get("rw");
String rootList = vnxExportMap.get("root");
// we get multiple value each separated by :
if (readOnlyList != null) {
for (String readOnly : readOnlyList.split(":")) {
if (!readOnly.equals("null")) {
arrayReadOnlyHost.add(readOnly);
}
}
}
if (readWriteList != null) {
for (String readWrite : readWriteList.split(":")) {
if (!readWrite.equals("null")) {
arrayReadWriteHost.add(readWrite);
}
}
}
if (rootList != null) {
for (String root : rootList.split(":")) {
if (!root.equals("null")) {
arrayRootHost.add(root);
}
}
}
// find out the change between array and CoprHD database.
Set<String> arrayExtraReadOnlyHost = Sets.difference(arrayReadOnlyHost, dbReadOnlyHost);
Set<String> arrayExtraReadWriteHost = Sets.difference(arrayReadWriteHost, dbReadWriteHost);
Set<String> arrayExtraRootHost = Sets.difference(arrayRootHost, dbRootHost);
// if change found update the exportRuleMap
if (!arrayExtraReadOnlyHost.isEmpty() || !arrayExtraReadWriteHost.isEmpty() || !arrayExtraRootHost.isEmpty()) {
ExportRule extraRuleFromArray = new ExportRule();
extraRuleFromArray.setDeviceExportId(exportRule.getDeviceExportId());
extraRuleFromArray.setAnon(exportRule.getAnon());
extraRuleFromArray.setSecFlavor(exportRule.getSecFlavor());
extraRuleFromArray.setExportPath(exportRule.getExportPath());
extraRuleFromArray.setReadOnlyHosts(arrayExtraReadOnlyHost);
extraRuleFromArray.setReadWriteHosts(arrayExtraReadWriteHost);
extraRuleFromArray.setRootHosts(arrayExtraRootHost);
exportRuleMap.put(exportRule.getSecFlavor(), extraRuleFromArray);
}
}
return exportRuleMap;
}
@Override
public BiosCommandResult updateShareACLs(StorageSystem storage,
FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult deleteShareACLs(StorageSystem storageObj,
FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult updateNfsACLs(StorageSystem storage, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult deleteNfsACLs(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult assignFilePolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult unassignFilePolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult listSanpshotByPolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult updateStorageSystemFileProtectionPolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
@Override
public BiosCommandResult checkFilePolicyPathHasResourceLabel(StorageSystem system, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.vnx.operationNotSupported());
}
}