/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.volumecontroller.impl.netappc;
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.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.model.file.ShareACL;
import com.emc.storageos.netapp.NetAppException;
import com.emc.storageos.netappc.NetAppCException;
import com.emc.storageos.netappc.NetAppClusterApi;
import com.emc.storageos.svcs.errorhandling.model.ServiceError;
import com.emc.storageos.util.FileSystemConstants;
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.NativeGUIDGenerator;
import com.emc.storageos.volumecontroller.impl.file.AbstractFileStorageDevice;
import com.iwave.ext.netappc.model.CifsAccess;
import com.iwave.ext.netappc.model.CifsAcl;
public class NetAppClusterModeDevice extends AbstractFileStorageDevice {
private static final Logger _log = LoggerFactory
.getLogger(NetAppClusterModeDevice.class);
private DbClient _dbClient;
private static int BYTESPERMB = 1048576;
private static final String VOL_ROOT = "/vol/";
private static final String SNAPSHOT = "/.snapshot";
private static final String RO_PERM = "ro";
private static final String RW_PERM = "rw";
private static final String ROOT_PERM = "root";
private static final String UNIX_SEC_FLAVOR = "sys";
private static final String DEFAULT_HOSTS = "Default";
private static final String USER_NONE = "nobody";
private static final String RO_HOSTS = "roHosts";
private static final String ROOT_HOSTS = "rootHosts";
private static final String RW_HOSTS = "rwHosts";
private static final int QUOTA_DIR_MAX_PATH = 100;
private static final int QUOTA_DIR_MAX_NAME = 64;
private enum AclOperation {
ADD, MODIFY, DELETE, FORCE_ADD, FORCE_DELETE
};
public NetAppClusterModeDevice() {
}
public void setDbClient(DbClient dbc) {
_dbClient = dbc;
}
private String genDetailedMessage(String methodName, String entityName) {
StringBuilder detailedMessage = new StringBuilder("NetAppClusterModeDevice ");
detailedMessage.append(methodName);
detailedMessage.append(" failed for ");
detailedMessage.append(entityName);
return detailedMessage.toString();
}
private String genDetailedMessage(String methodName, String entityName, String reason) {
StringBuilder detailedMessage = new StringBuilder("NetAppClusterModeDevice ");
detailedMessage.append(methodName);
detailedMessage.append(" failed for ");
detailedMessage.append(entityName);
detailedMessage.append(" : ");
detailedMessage.append(reason);
return detailedMessage.toString();
}
@Override
public BiosCommandResult doCreateFS(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doCreateFS - start");
if (null == args.getFsName()) {
_log.error("NetAppClusterModeDevice::doCreateFS failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileSystem();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == args.getPoolNativeId()) {
_log.error("NetAppClusterModeDevice::doCreateFS failed: PoolNativeId either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileSystem();
serviceError.setMessage(FileSystemConstants.FS_ERR_POOL_NATIVE_ID_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == args.getFsCapacity()) {
_log.error("NetAppClusterModeDevice::doCreateFS failed: Filesystem capacity is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileSystem();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_CAPACITY_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
String nativeId = "/" + args.getFsName();
args.setFsNativeId(nativeId);
String fsNativeGuid = NativeGUIDGenerator.generateNativeGuid(
storage.getSystemType(), storage.getSerialNumber(),
nativeId);
args.setFsNativeGuid(fsNativeGuid);
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
Long fsSize = args.getFsCapacity() / BYTESPERMB;
String strFsSize = fsSize.toString() + "m";
if (!ncApi.createFS(args.getFsName(), args.getPoolNativeId(),
strFsSize, args.getThinProvision())) {
_log.error("NetAppClusterModeDevice doCreateFS {} - failed", args.getFsName());
BiosCommandResult rollbackResult = doDeleteFS(storage, args);
if (rollbackResult.isCommandSuccess()) {
_log.info(
"NetAppClusterModeDevice doCreateFS rollback completed failed for fs, {}", args.getFsName());
} else {
_log.error(
"NetAppClusterModeDevice doCreateFS rollback failed for fs, {} with {}.",
args.getFsName(), rollbackResult.getMessage());
}
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileSystem();
result = BiosCommandResult.createErrorResult(serviceError);
} else {
_log.info("NetAppClusterModeDevice doCreateFS {} - complete",
args.getFsName());
// Set FS path and Mount Path information
args.setFsPath(nativeId);
args.setFsMountPath(nativeId);
result = BiosCommandResult.createSuccessfulResult();
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doCreateFS failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doCreateFS failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult doDeleteFS(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doDeleteFS - start");
if (null == args.getFsName()) {
_log.error("NetAppClusterModeDevice::doDeletFS failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileSystem();
serviceError.setMessage("Filesystem name is either missing or empty");
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
// Now get the SVM from the fileShare
String portGroup = findSVMName(args.getFs());
if (null != args.getFsShares() && !args.getFsShares().isEmpty()) {
if (!netAppDeleteCIFSExports(storage, args.getFsShares(), portGroup)) {
_log.info("NetAppClusterModeDevice doDeletFS:netAppDeleteCIFSExports {} - failed", args.getFsName());
} else {
_log.info("NetAppClusterModeDevice doDeletFS:netAppDeleteCIFSExports {} - succeeded", args.getFsName());
}
}
boolean failedStatus = false;
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
if (!ncApi.deleteFS(args.getFsName())) {
failedStatus = true;
}
if (failedStatus == true) {
_log.error("NetAppClusterModeDevice doDeletFS {} - failed",
args.getFsName());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileSystem();
result = BiosCommandResult.createErrorResult(serviceError);
} else {
_log.info("NetAppClusterModeDevice doDeletFS {} - complete",
args.getFsName());
result = BiosCommandResult.createSuccessfulResult();
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doDeleteFS failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doDeleteFS failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
/**
* Checking a file system: - Check if the FS exists on Array or not
*
* @param StorageSystem storage
* @param args FileDeviceInputOutput
* @return boolean true if exists else false
* @throws ControllerException
*/
@Override
public boolean doCheckFSExists(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
_log.info("checking file system existence on array: ", args.getFsName());
boolean isFSExists = true;
try {
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
List<String> fs = ncApi.listFileSystems();
if (!fs.isEmpty() && fs.contains(args.getFsName())) {
isFSExists = true;
} else {
isFSExists = false;
}
} catch (NetAppException e) {
_log.error("NetAppClusterModeDevice::doCheckFSExists failed with an Exception", e);
}
return isFSExists;
}
@Override
public BiosCommandResult doExport(StorageSystem storage,
FileDeviceInputOutput args, List<FileExport> exportList)
throws ControllerException {
_log.info("NetAppClusterModeDevice doExport - start");
// Verify inputs.
validateExportArgs(exportList);
List<String> rootHosts = new ArrayList<String>();
List<String> rwHosts = new ArrayList<String>();
List<String> roHosts = new ArrayList<String>();
BiosCommandResult result = new BiosCommandResult();
if (args.getFileObjExports() == null
|| args.getFileObjExports().isEmpty()) {
args.initFileObjExports();
}
FSExportMap existingExpMap = args.getFileObjExports();
List<FileExport> existingExportList = new ArrayList<FileExport>();
FileExport existingExport = null;
Iterator<String> it = existingExpMap.keySet().iterator();
while (it.hasNext()) {
existingExport = existingExpMap.get(it.next());
if (existingExport.getMountPath().equals(args.getFsMountPath())) {
_log.info("Existing export FileExport key : {} ",
existingExport.getFileExportKey());
existingExportList.add(existingExport);
}
}
// If it's a sub-directory no need to take existing hosts.
boolean isSubDir = checkIfSubDirectory(args.getFsMountPath(), exportList.get(0).getMountPath());
if (isSubDir) {
existingExportList = null;
if (exportList.get(0).getMountPath().contains(SNAPSHOT)) {
_log.error("NetAppClusterModeDevice::doExport {} : Snapshot export is not Supported", args.getSnapshotId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportSnapshot();
serviceError
.setMessage(genDetailedMessage("doExport", args.getSnapshotId().toString(), "Snapshot export is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
}
// TODO: Revisit once new Data Model for Exports is implemented.
Map<String, List<String>> existingHosts = null;
if ((null != existingExportList) && (!existingExportList.isEmpty())) {
existingHosts = sortHostsFromCurrentExports(existingExportList);
}
if (null != existingHosts) {
if ((null != existingHosts.get(ROOT_HOSTS))
&& (!existingHosts.get(ROOT_HOSTS).isEmpty())) {
addNewHostsOnly(rootHosts, existingHosts.get(ROOT_HOSTS));
}
if ((null != existingHosts.get(RW_HOSTS))
&& (!existingHosts.get(RW_HOSTS).isEmpty())) {
addNewHostsOnly(rwHosts, existingHosts.get(RW_HOSTS));
}
if ((null != existingHosts.get(RO_HOSTS))
&& (!existingHosts.get(RO_HOSTS).isEmpty())) {
addNewHostsOnly(roHosts, existingHosts.get(RO_HOSTS));
}
}
try {
for (int expCount = 0; expCount < exportList.size(); expCount++) {
FileExport export = exportList.get(expCount);
FileExport fileExport = new FileExport(export.getClients(),
export.getStoragePortName(), export.getMountPoint(),
export.getSecurityType(), export.getPermissions(),
export.getRootUserMapping(), export.getProtocol(),
export.getStoragePort(), export.getPath(),
export.getMountPath(), export.getSubDirectory(), export.getComments());
String portGroup = null;
FileShare fileshare = null;
if (args.getFileOperation() == true) {
fileshare = args.getFs();
portGroup = findSVMName(fileshare);
} else {
_log.error("NetAppClusterModeDevice::doExport {} : Snapshot export is not Supported", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportSnapshot();
serviceError.setMessage(genDetailedMessage("doExport", args.getSnapshotId().toString(),
"Snapshot export is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
List<String> endpointsList = export.getClients();
if (endpointsList == null) {
_log.error("NetAppClusterModeDevice::doExport {} failed: No endpoints specified", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(FileSystemConstants.FS_ERR_NO_ENDPOINTS_SPECIFIED);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
sortNewEndPoints(rootHosts, rwHosts, roHosts, endpointsList,
export.getPermissions());
String root_user = export.getRootUserMapping();
String mountPath = export.getMountPath();
String exportPath = export.getPath();
String fsName = fileshare.getName();
String qtreeName = null;
if (isSubDir) {
if (ncApi.isQtree(fileshare.getName(), export.getSubDirectory())) {
qtreeName = export.getSubDirectory();
exportPath = constructQtreePath(fileshare.getName(), export.getSubDirectory());
} else {
_log.error("NetAppClusterModeDevice::doExport {} : Sub-directory export is not Supported", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(genDetailedMessage("doExport", args.getFsId().toString(),
"Sub-directory export is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
}
if (!ncApi.exportFS(fsName, qtreeName, exportPath, mountPath, rootHosts, rwHosts,
roHosts, root_user, export.getSecurityType())) {
_log.error("NetAppClusterModeDevice::doExport {} failed", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(genDetailedMessage("doExport", args.getFsId().toString()));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
args.getFileObjExports().put(fileExport.getFileExportKey(),
fileExport);
result = BiosCommandResult.createSuccessfulResult();
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doExport failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doExport failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
_log.info("NetAppClusterModeDevice::doExport {} - complete", args.getFsId());
return result;
}
// Validate the export arguments for the NetApp Cluster-mode
//
// The root user mapping must be an integer or the value 'nobody'. Since
// 'nobody' is the default value on the NetApp, it does not need to be sent.
// The CLI only accepts UIDs (integer values).
private void validateExportArgs(List<FileExport> exports)
throws ControllerException {
String rootUser = "";
for (FileExport exp : exports) {
// Validate the root user mapping
_log.info("FileExport:Clients:" + exp.getClients() + ":SPName:"
+ exp.getStoragePortName() + ":SP:" + exp.getStoragePort()
+ ":rootusermapping:" + exp.getRootUserMapping() + ":perm:"
+ exp.getPermissions() + ":protocol:" + exp.getProtocol()
+ ":security:" + exp.getSecurityType() + ":subDir:"
+ exp.getPath());
rootUser = exp.getRootUserMapping();
try {
if (!rootUser.equalsIgnoreCase(USER_NONE)
&& !rootUser.equalsIgnoreCase(ROOT_PERM)) {
Integer.parseInt(rootUser);
}
} catch (NumberFormatException nfe) {
throw new DeviceControllerException(
"Invalid Root User Mapping {0} ",
new Object[] { nfe });
}
}
}
/*
* We check to see if fsMountPath is same as exportMountPath, if not we know that it's a sub-directory
* Also we need to make sure that fsMountPath is a substring of exportMountPath if it were to be a sub-directory.
*/
private boolean checkIfSubDirectory(String fsMountPath, String exportMountPath) {
if (exportMountPath.contains(fsMountPath) && !exportMountPath.equals(fsMountPath)) {
return true;
} else {
return false;
}
}
private String getSubDirectory(String fsMountPath, String exportMountPath) {
if (exportMountPath.contains(fsMountPath) && !exportMountPath.equals(fsMountPath)) {
String[] pathString = exportMountPath.split("/");
return pathString[pathString.length - 1];
} else {
return "";
}
}
private void addNewHostsOnly(List<String> permHosts, List<String> newHosts) {
if (null != newHosts) {
for (String newHost : newHosts) {
if (!(permHosts.contains(newHost))) {
permHosts.add(newHost);
}
}
}
}
private Map<String, List<String>> sortHostsFromCurrentExports(
List<FileExport> curExpList) {
Map<String, List<String>> currentHostsList = new HashMap<String, List<String>>();
for (FileExport curExport : curExpList) {
if ((null != curExport.getClients())
&& (!curExport.getClients().isEmpty())) {
if (curExport.getPermissions().toString().equals(ROOT_PERM)) {
currentHostsList.put(ROOT_HOSTS, curExport.getClients());
} else if (curExport.getPermissions().toString()
.equals(RW_PERM)) {
currentHostsList.put(RW_HOSTS, curExport.getClients());
} else if (curExport.getPermissions().toString()
.equals(RO_PERM)) {
currentHostsList.put(RO_HOSTS, curExport.getClients());
}
}
}
return currentHostsList;
}
private void sortNewEndPoints(List<String> rootHosts, List<String> rwHosts,
List<String> roHosts, List<String> endPointList, String permission) {
for (String endPoint : endPointList) {
if ((null != endPointList) && (!endPointList.isEmpty())) {
if (permission.equals(ROOT_PERM)
&& !(rootHosts.contains(endPoint))) {
rootHosts.add(endPoint);
} else if (permission.equals(RW_PERM)
&& !(rwHosts.contains(endPoint))) {
rwHosts.add(endPoint);
} else if (permission.equals(RO_PERM)
&& !(roHosts.contains(endPoint))) {
roHosts.add(endPoint);
}
}
}
}
@Override
public BiosCommandResult doShare(StorageSystem storage,
FileDeviceInputOutput args, SMBFileShare smbFileShare)
throws ControllerException {
// To be in-sync with isilon implementation, currently forceGroup is
// set to null which will set the group name as "everyone" by default.
String forceGroup = null;
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doShare - start");
SMBShareMap smbShareMap = args.getFileObjShares();
SMBFileShare existingShare = (smbShareMap == null) ? null
: smbShareMap.get(smbFileShare.getName());
Boolean modOrCreateShareSuccess = false;
if (existingShare != null) {
modOrCreateShareSuccess = modifyNtpShare(storage, args, smbFileShare, forceGroup, existingShare);
} else if (existingShare == null) {
modOrCreateShareSuccess = createNtpShare(storage, args, smbFileShare, forceGroup);
}
if (modOrCreateShareSuccess.booleanValue() == true) {
_log.info("NetAppClusterModeDevice doShare {} - complete",
smbFileShare.getName());
// Update the collection.
if (args.getFileObjShares() == null) {
args.initFileObjShares();
}
// set Mount Point
smbFileShare.setMountPoint(smbFileShare.getNetBIOSName(), smbFileShare.getStoragePortNetworkId(),
smbFileShare.getStoragePortName(), smbFileShare.getName());
args.getFileObjShares().put(smbFileShare.getName(), smbFileShare);
result = BiosCommandResult.createSuccessfulResult();
} else {
_log.error("NetAppClusterModeDevice doShare {} - failed",
smbFileShare.getName());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileShare();
result = BiosCommandResult.createErrorResult(serviceError);
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doShare failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileShare();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doShare failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateFileShare();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult doDeleteShare(StorageSystem storage,
FileDeviceInputOutput args, SMBFileShare smbFileShare)
throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doDeleteShare - start");
FileShare fileshare = null;
if (args.getFileOperation() == true) {
fileshare = args.getFs();
} else {
URI snapShotUID = args.getSnapshotId();
Snapshot snapshot = _dbClient.queryObject(Snapshot.class, snapShotUID);
fileshare = _dbClient.queryObject(FileShare.class, snapshot.getParent().getURI());
}
// Now get the VFiler from the fileShare
String portGroup = findSVMName(fileshare);
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
SMBShareMap shares = args.getFileObjShares();
if (shares == null || shares.isEmpty()) {
_log.error("NetAppClusterModeDevice::doDeleteShare failed: FileShare(s) is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileShare();
serviceError.setMessage("FileShare(s) is either missing or empty");
result = BiosCommandResult.createErrorResult(serviceError);
}
SMBFileShare fileShare = shares.get(smbFileShare.getName());
if (fileShare != null) {
if (!ncApi.deleteShare(smbFileShare.getName())) {
_log.error("NetAppClusterModeDevice doDeleteShare {} - failed",
args.getFileObjId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileShare();
serviceError.setMessage("Deletion of CIFS File Share failed");
result = BiosCommandResult.createErrorResult(serviceError);
} else {
_log.info("NetAppClusterModeDevice doDeleteShare {} - complete",
args.getFileObjId());
args.getFileObjShares().remove(smbFileShare.getName());
args.getFileObjShares().remove(smbFileShare.getNativeId());
result = BiosCommandResult.createSuccessfulResult();
}
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doDeleteShare failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileShare();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doDeleteShare failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteFileShare();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@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("Delete shares for multiple SMB is not supported.");
return result;
}
@Override
public BiosCommandResult doUnexport(StorageSystem storage,
FileDeviceInputOutput args, List<FileExport> exportList)
throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doUnexport: {} - start", args.getFileObjId());
if (!args.getFileOperation()) {
_log.error("NetAppClusterModeDevice::doUnexport {} : Snapshot unexport is not Supported", args.getSnapshotId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUnexportSnapshot();
serviceError.setMessage(genDetailedMessage("doUnExport", args.getSnapshotId().toString(),
"Snapshot unexport is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
for (int expCount = 0; expCount < exportList.size(); expCount++) {
FileExport export = exportList.get(expCount);
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
if (export.getPermissions() == null) {
export.setPermissions(RO_PERM);
}
String mountPath = export.getMountPath();
String exportPath = export.getPath();
if (!ncApi.unexportFS(exportPath, mountPath)) {
_log.error("NetAppClusterModeDevice::doUnexport {} failed", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUnexportFileSystem();
serviceError.setMessage(genDetailedMessage("doUnexport", args.getFsId().toString()));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
} else {
_log.info("NetAppClusterModeDevice doUnexport {} - completed", args.getFsId());
result = BiosCommandResult.createSuccessfulResult();
}
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doUnexport failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUnexportFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doUnexport failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUnexportFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
_log.info("NetAppClusterModeDevice doUnexport {} - complete", args.getFileObjId());
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 NetAppC.");
return result;
}
@Override
public BiosCommandResult doExpandFS(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doExpandFS - start");
long newFsExpandSize = args.getNewFSCapacity();
String volumeName = args.getFsName();
if (args.getNewFSCapacity() % BYTESPERMB == 0) {
newFsExpandSize = newFsExpandSize / BYTESPERMB;
} else {
newFsExpandSize = newFsExpandSize / BYTESPERMB + 1;
}
_log.info("FileSystem new size translation : {} : {}", args.getNewFSCapacity(), newFsExpandSize);
String strNewFsSize = String.valueOf(newFsExpandSize) + "m";
String portGroup = findSVMName(args.getFs());
NetAppClusterApi nApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
if (!nApi.setVolumeSize(volumeName, strNewFsSize)) {
_log.error("NetAppClusterModeDevice doExpandFS - failed");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExpandFileSystem();
result = BiosCommandResult.createErrorResult(serviceError);
} else {
_log.info("NetAppClusterModeDevice doExpandFS - complete");
result = BiosCommandResult.createSuccessfulResult();
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doExpandFS failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExpandFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doExpandFS failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExpandFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult doSnapshotFS(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doSnapshotFS - start");
if (null == args.getFsName()) {
_log.error("NetAppClusterModeDevice::doSnapshotFS failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateSnapshot();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == args.getSnapshotName()) {
_log.error("NetAppClusterModeDevice::doSnapshotFS failed: Snapshot name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateSnapshot();
serviceError.setMessage(FileSystemConstants.FS_ERR_SNAPSHOT_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
boolean failedStatus = false;
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(), storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
if (!ncApi.createSnapshot(args.getFsName(), args.getSnapshotName())) {
failedStatus = true;
}
if (failedStatus == true) {
_log.error("NetAppClusterModeDevice doSnapshotFS {} - failed", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateSnapshot();
serviceError.setMessage(genDetailedMessage("doSnapshotFS", args.getFsName()));
result = BiosCommandResult.createErrorResult(serviceError);
} else {
_log.info("doSnapshotFS - Snapshot, {} was successfully created for filesystem, {} ", args.getSnapshotName(),
args.getFsName());
// Set snapshot Path and MountPath information
args.setSnapshotMountPath(getSnapshotMountPath(args.getFsMountPath(), args.getSnapshotName()));
args.setSnapshotPath(getSnapshotPath(args.getFsPath(), args.getSnapshotName()));
args.setSnapNativeId(args.getSnapshotName());
result = BiosCommandResult.createSuccessfulResult();
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doSnapshotFS failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateSnapshot();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doSnapshotFS failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateSnapshot();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult doRestoreFS(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doRestoreFS - start");
if (null == args.getFsName()) {
_log.error("NetAppClusterModeDevice::doRestoreFS failed: Filesystem name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToRestoreFileSystem();
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == args.getSnapshotName()) {
_log.error("NetAppClusterModeDevice::doRestoreFS failed: Snapshot name is either missing or empty");
ServiceError serviceError = DeviceControllerErrors.netappc.unableToRestoreFileSystem();
serviceError.setMessage(FileSystemConstants.FS_ERR_SNAPSHOT_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(), storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
if (!ncApi.restoreSnapshot(args.getFsName(), args.getSnapshotName())) {
_log.error("NetAppClusterModeDevice doRestoreFS {} - failed", args.getFsName());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToRestoreFileSystem();
result = BiosCommandResult.createErrorResult(serviceError);
} else {
_log.info("doRestoreFS - restore of snapshot, {} was successfully for filesystem, {} ", args.getSnapshotName(),
args.getFsName());
result = BiosCommandResult.createSuccessfulResult();
}
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doRestoreFS failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToRestoreFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doRestoreFS failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToRestoreFileSystem();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult getFSSnapshotList(StorageSystem storage,
FileDeviceInputOutput args, List<String> dbSnapshots)
throws ControllerException {
if (null == args.getFsName()) {
throw new DeviceControllerException(
"Filesystem name is either missing or empty",
new Object[] {});
}
_log.info("NetAppClusterModeDevice getFSSnapshotList: {} - start",
args.getFsName());
BiosCommandResult result = new BiosCommandResult();
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(), storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
try {
List<String> deviceSnapshots = ncApi.listSnapshots(args.getFsName());
if (deviceSnapshots == null) {
_log.warn("NetAppClusterModeDevice getFSSnapshotList {} - failed",
args.getFsId());
result.setCommandSuccess(false);
result.setMessage("NetAppClusterModeDevice getFSSnapshotList failed for FS {}"
+ args.getFsName());
result.setCommandStatus(Operation.Status.error.name());
} else {
for (String deviceSnapshotName : deviceSnapshots) {
dbSnapshots.add(deviceSnapshotName);
}
_log.info(
"NetAppClusterModeDevice getFSSnapshotList - successful for filesystem, {} ",
args.getFsName());
result.setCommandSuccess(true);
result.setCommandStatus(Operation.Status.ready.name());
result.setMessage("List of snapshots for FS " + args.getFsName()
+ " was successfully retreived from device ");
}
} catch (NetAppCException e) {
String[] params = { storage.getId().toString(), args.getFsName() };
throw new DeviceControllerException(
"Failed to retrieve list of snapshots from device {1} for filesystem {2}",
params);
}
return result;
}
@Override
public BiosCommandResult doDeleteSnapshot(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
if (null == args.getFsName()) {
throw new DeviceControllerException(
"Filesystem name is either missing or empty",
new Object[] {});
}
if (null == args.getSnapshotName()) {
throw new DeviceControllerException(
"Snapshot name is either missing or empty for filesystem name {0}",
new Object[] { args.getFsName() });
}
_log.info("NetAppClusterModeDevice doDeleteSnapshot: {},{} - start",
args.getSnapshotId(), args.getSnapshotName());
BiosCommandResult result = new BiosCommandResult();
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
try {
if (!ncApi.deleteSnapshot(args.getFsName(), args.getSnapshotName())) {
_log.error(
"NetAppClusterModeDevice doDeleteSnapshot {} - failed",
args.getFsId());
result.setCommandSuccess(false);
result.setMessage("NetAppClusterModeDevice doDeleteSnapshot - failed");
result.setCommandStatus(Operation.Status.error.name());
} else {
_log.info(
"doDeleteSnapshot for snapshot {} on filesystem {} successful",
args.getSnapshotName(), args.getFsName());
result.setCommandSuccess(true);
result.setCommandStatus(Operation.Status.ready.name());
result.setMessage("Snapshot," + args.getSnapshotName()
+ " has been successfully deleted");
}
} catch (NetAppCException e) {
throw new DeviceControllerException(
"Failed to delete snapshot, {0} for filesystem, {1} with: {2}",
new Object[] { args.getSnapshotName(), args.getFsName(),
e.getMessage() });
}
return result;
}
@Override
public void doConnect(StorageSystem storage) throws ControllerException {
// TODO Auto-generated method stub
}
@Override
public void doDisconnect(StorageSystem storage) throws ControllerException {
// TODO Auto-generated method stub
}
@Override
public BiosCommandResult getPhysicalInventory(StorageSystem storage) {
// TODO Auto-generated method stub
return null;
}
/**
* Return true if qtree name and its path in valid length, otherwise false.
*/
private Boolean validQuotaDirectoryPath(String volName, String quotaDirName) {
if (volName == null && quotaDirName == null) {
_log.info("Invalid volume name and quota directory name ");
return false;
} else {
// NetApp accepts maximum of 64-character as a quota directory name.
if (quotaDirName.length() > QUOTA_DIR_MAX_NAME) {
_log.error("quota directory name is too long {}, maximum {} chars", quotaDirName.length(), QUOTA_DIR_MAX_NAME);
return false;
}
String qtreePath = VOL_ROOT + volName + "/" + quotaDirName;
// each entry in /etc/quotas file is with maximum of 160 characters.
// "/vol/<volname>/qtreename tree <size> - - - -"
if (qtreePath.length() > QUOTA_DIR_MAX_PATH) {
_log.error("quota directory path is too long {}, maximum {} chars", qtreePath.length(), QUOTA_DIR_MAX_PATH);
return false;
}
}
return true;
}
public BiosCommandResult validateQuotaDirectoryParams(String volName, String qtreeName, String method) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
result = BiosCommandResult.createSuccessfulResult();
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateQtree();
if (method.equals("doCreateQuotaDirectory")) {
serviceError = DeviceControllerErrors.netappc.unableToCreateQtree();
} else if (method.equals("doDeleteQuotaDirectory")) {
serviceError = DeviceControllerErrors.netappc.unableToDeleteQtree();
} else {
serviceError = DeviceControllerErrors.netappc.unableToUpdateQtree();
}
if (null == volName) {
_log.error("NetAppClusterModeDevice:: {} failed: Filesystem name is either missing or empty", method);
serviceError.setMessage(FileSystemConstants.FS_ERR_FS_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (null == qtreeName) {
_log.error("NetAppClusterModeDevice::{} failed: Qtree name is either missing or empty", method);
serviceError.setMessage(FileSystemConstants.FS_ERR_QUOTADIR_NAME_MISSING_OR_EMPTY);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
if (method.equals("doCreateQuotaDirectory") && !validQuotaDirectoryPath(volName, qtreeName)) {
_log.error("NetAppClusterModeDevice::{} failed: Qtree name or path is too long", method);
serviceError.setMessage(FileSystemConstants.FS_ERR_QUOTADIR_NAME_PATH_TOO_LONG);
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
return result;
}
@Override
public BiosCommandResult doCreateQuotaDirectory(StorageSystem storage,
FileDeviceInputOutput args, QuotaDirectory qtree)
throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doCreateQuotaDirectory - start");
String volName = args.getFsName(); // Using NetApp terminology here
String qtreeName = args.getQuotaDirectoryName();
Boolean oplocks = qtree.getOpLock();
String securityStyle = qtree.getSecurityStyle();
Long size = qtree.getSize();
String method = new String("doCreateQuotaDirectory");
result = validateQuotaDirectoryParams(volName, qtreeName, method);
if (!result.isCommandSuccess()) {
return result;
}
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
ncApi.createQtree(qtreeName, volName, oplocks, securityStyle, size, portGroup);
result = BiosCommandResult.createSuccessfulResult();
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doCreateQuotaDirectory failed with a NetAppCException", e);
_log.info("NetAppClusterModeDevice::doCreateQuotaDirectory e.getLocalizedMessage(): {}", e.getLocalizedMessage());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateQtree();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doCreateQuotaDirectory failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToCreateQtree();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult doDeleteQuotaDirectory(StorageSystem storage,
FileDeviceInputOutput args) throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doDeleteQuotaDirectory - start");
String volName = args.getFsName(); // Using NetApp terminology here
String qtreeName = args.getQuotaDirectoryName();
String method = new String("doDeleteQuotaDirectory");
result = validateQuotaDirectoryParams(volName, qtreeName, method);
if (!result.isCommandSuccess()) {
return result;
}
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
ncApi.deleteQtree(qtreeName, volName, portGroup);
result = BiosCommandResult.createSuccessfulResult();
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doDeleteQuotaDirectory failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteQtree();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doDeleteQuotaDirectory failed with an Exception ", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteQtree();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult doUpdateQuotaDirectory(StorageSystem storage,
FileDeviceInputOutput args, QuotaDirectory qtree)
throws ControllerException {
BiosCommandResult result = new BiosCommandResult();
try {
_log.info("NetAppClusterModeDevice doUpdateQuotaDirectory - start");
String volName = args.getFsName(); // Using NetApp terminology here
String qtreeName = args.getQuotaDirectoryName();
Boolean oplocks = qtree.getOpLock();
String securityStyle = qtree.getSecurityStyle();
Long size = qtree.getSize();
String method = new String("doUpdateQuotaDirectory");
result = validateQuotaDirectoryParams(volName, qtreeName, method);
if (!result.isCommandSuccess()) {
return result;
}
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
ncApi.updateQtree(qtreeName, volName, oplocks, securityStyle, size, portGroup);
result = BiosCommandResult.createSuccessfulResult();
} catch (NetAppCException e) {
_log.error("NetAppClusterModeDevice::doUpdateQuotaDirectory failed with a NetAppCException", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUpdateQtree();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::doUpdateQuotaDirectory failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUpdateQtree();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult updateExportRules(StorageSystem storage,
FileDeviceInputOutput args) {
// 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<>();
List<ExportRule> exportsRemove = new ArrayList<>();
// ALL EXPORTS
List<ExportRule> exportsToprocess = args.getExistingDBExportRules();
String fsName = "";
if (exportsToprocess == null) {
exportsToprocess = new ArrayList<>();
}
_log.info("Number of existng Rules found {}", exportsToprocess.size());
String exportPath;
String subDir = args.getSubDirectory();
BiosCommandResult result = new BiosCommandResult();
if (!args.getFileOperation()) {
_log.error("NetAppClusterModeDevice::updateExportRules {} : Snapshot export/unexport is not Supported", args.getSnapshotId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUnexportSnapshot();
serviceError.setMessage(genDetailedMessage("updateExportRules", args.getSnapshotId().toString(),
"Snapshot export/unexport is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
} else {
exportPath = args.getFs().getPath();
if (subDir != null
&& subDir.length() > 0) {
exportPath = args.getFs().getPath() + "/"
+ subDir;
}
}
// if only delete provided with no existing rules -- How do we handle this?
_log.info("Number of Export Rules to update after processing found {}", exportsToprocess.size());
try {
String portGroup = null;
if (args.getFileOperation() == true) {
FileShare fileshare = args.getFs();
fsName = fileshare.getName();
portGroup = findSVMName(fileshare);
}
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
String qtreePath = "";
String qtreeName = null;
if (args.getFileOperation()) {
qtreePath = exportPath;
if (subDir != null
&& subDir.length() > 0) {
if (ncApi.isQtree(args.getFsName(), subDir)) {
qtreeName = subDir;
qtreePath = constructQtreePath(args.getFsName(), subDir);
} else {
_log.error("NetAppClusterModeDevice::updateExportRules {} : Sub-directory export/unexport is not Supported",
args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(genDetailedMessage("updateExportRules", args.getFsId().toString(),
"Sub-directory export/unexport is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
}
}
_log.info("exportPath : {}", exportPath);
args.setExportPath(exportPath);
// Handle Modified export Rules
if (!exportsToprocess.isEmpty()) {
for (ExportRule existingRule : exportsToprocess) {
if (existingRule.getExportPath().equalsIgnoreCase(exportPath)) {
for (ExportRule modifiedrule : exportModify) {
if (modifiedrule.getSecFlavor().equals(
existingRule.getSecFlavor())) {
_log.info("Modifying Export Rule from {}, To {}",
existingRule, modifiedrule);
if (!ncApi.modifyNFSShare(fsName, qtreeName, qtreePath, existingRule, modifiedrule)) {
_log.error("NetAppClusterModeDevice updateFSExportRules {} - failed",
args.getFsId());
result.setMessage("NetAppClusterModeDevice updateFSExportRules {} - failed");
result.setCommandStatus(Operation.Status.error.name());
return result;
}
}
}
}
}
// Handle Add export Rules
if (exportAdd != null && !exportAdd.isEmpty()) {
for (ExportRule newExport : exportAdd) {
_log.info("Adding Export Rule {}", newExport);
if (!ncApi.addNFSShare(fsName, qtreeName, qtreePath, newExport)) {
_log.error("NetAppClusterModeDevice updateFSExportRules {} - failed",
args.getFsId());
result.setMessage("NetAppClusterModeDevice updateFSExportRules {} - failed");
result.setCommandStatus(Operation.Status.error.name());
return result;
}
}
}
// Handle Delete export Rules
if (exportDelete != null && !exportDelete.isEmpty()) {
for (ExportRule existingRule : exportsToprocess) {
if (existingRule.getExportPath().equalsIgnoreCase(exportPath)) {
exportsToRemove.add(existingRule);
for (ExportRule oldExport : exportDelete) {
if (oldExport.getSecFlavor().equals(
existingRule.getSecFlavor())) {
_log.info("Deleting Export Rule {}", existingRule);
exportsRemove.add(existingRule);
if (!ncApi.deleteNFSShare(fsName, qtreeName, existingRule, qtreePath)) {
_log.error("NetAppClusterModeDevice updateFSExportRules {} - failed",
args.getFsId());
result.setMessage("NetAppClusterModeDevice updateFSExportRules {} - failed");
result.setCommandStatus(Operation.Status.error.name());
return result;
}
}
}
}
}
}
// No of exports found to remove from the list
_log.info("No of exports found to remove from the existing exports list {}", exportsRemove.size());
exportsToRemove.removeAll(exportsRemove);
_log.info("No of exports found to add to the existing exports list {}", exportsToAdd.size());
// delete the export if no export rule left.
// If we delete filesystem without deleting export policy. Export policy will not get cleared on Array.
if (exportsToRemove.isEmpty() && !exportsRemove.isEmpty()) {
ncApi.deleteNFSExport(qtreePath);
}
}
} catch (NetAppCException e) {
_log.info("Exception:" + e.getMessage());
throw new DeviceControllerException(
"Exception while performing export for {0} - {1} ",
new Object[] { args.getFsId(), e.getMessage() });
}
_log.info("NetAppClusterModeDevice updateFSExportRules {} - complete",
args.getFsId());
result.setCommandSuccess(true);
result.setCommandStatus(Operation.Status.ready.name());
return result;
}
@Override
public BiosCommandResult deleteExportRules(StorageSystem storage,
FileDeviceInputOutput args) {
BiosCommandResult result = new BiosCommandResult();
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
List<ExportRule> allExports = args.getExistingDBExportRules();
String subDir = args.getSubDirectory();
boolean allDirs = args.isAllDir();
String exportPath;
String qtreePath = "";
if (!args.getFileOperation()) {
_log.error("NetAppClusterModeDevice::doUnexport {} : Snapshot unexport is not Supported", args.getSnapshotId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUnexportSnapshot();
serviceError
.setMessage(genDetailedMessage("doUnExport", args.getSnapshotId().toString(), "Snapshot unexport is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
} else {
exportPath = args.getFs().getPath();
qtreePath = exportPath;
if (subDir != null
&& subDir.length() > 0) {
exportPath = args.getFs().getPath() + "/"
+ subDir;
if (ncApi.isQtree(args.getFsName(), subDir)) {
qtreePath = constructQtreePath(args.getFsName(), subDir);
} else {
_log.error("NetAppClusterModeDevice::doUnexport {} : Sub-directory unexport is not Supported", args.getFsId());
ServiceError serviceError = DeviceControllerErrors.netappc.unableToExportFileSystem();
serviceError.setMessage(genDetailedMessage("doUnExport", args.getFsId().toString(),
"Sub-directory unexport is not Supported"));
result = BiosCommandResult.createErrorResult(serviceError);
return result;
}
}
}
_log.info("exportPath : {}", exportPath);
args.setExportPath(exportPath);
_log.info("Number of existing exports found {}", allExports.size());
try {
if (allDirs) {
Set<String> allPaths = new HashSet<String>();
// 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());
}
for (String path : allPaths) {
boolean isSubDir = checkIfSubDirectory(args.getFsMountPath(), path);
if (isSubDir) {
subDir = getSubDirectory(args.getFsMountPath(), path);
if (ncApi.isQtree(args.getFsName(), subDir)) {
path = constructQtreePath(args.getFsName(), subDir);
}
}
_log.info("deleting export path : {} ", path);
ncApi.deleteNFSExport(path);
}
} 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)) {
ncApi.deleteNFSExport(qtreePath);
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");
ncApi.deleteNFSExport(qtreePath);
}
} catch (NetAppCException e) {
_log.info("Exception:" + e.getMessage());
throw new DeviceControllerException(
"Exception while performing export for {0} ",
new Object[] { args.getFsId() });
}
_log.info("NetAppClusterModeDevice unexportFS {} - complete",
args.getFsId());
result.setCommandSuccess(true);
result.setCommandStatus(Operation.Status.ready.name());
return result;
}
/**
* Return the svm name associated with the file system. If a svm is not associated with
* this file system, then it will return null.
*/
private String findSVMName(FileShare fs) {
String portGroup = null;
URI port = fs.getStoragePort();
if (port == null) {
_log.info("No storage port URI to retrieve svm name");
} else {
StoragePort stPort = _dbClient.queryObject(StoragePort.class, port);
if (stPort != null) {
URI haDomainUri = stPort.getStorageHADomain();
if (haDomainUri == null) {
_log.info("No Port Group URI for port {}", port);
} else {
StorageHADomain haDomain = _dbClient.queryObject(StorageHADomain.class, haDomainUri);
if (haDomain != null && haDomain.getVirtual() == true) {
portGroup = stPort.getPortGroup();
_log.debug("using port {} and svm {}", stPort.getPortNetworkId(), portGroup);
}
}
}
}
return portGroup;
}
/**
* create NetAppC share with right permissions
*
* @param StorageSystem mount path of the fileshare
* @param args containing input/out arguments of filedevice
* @param smbFileShare smbFileshare object
* @param forceGroup Name of the group the fileshare belongs.
* @return
*/
private Boolean createNtpShare(StorageSystem storage,
FileDeviceInputOutput args, SMBFileShare smbFileShare,
String forceGroup) throws NetAppCException {
String shareId = null;
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
shareId = smbFileShare.getPath();
_log.info("NetAppClusterModeDevice doShare for {} with id {}", shareId, args.getFileObjId());
if (!ncApi.doShare(shareId, smbFileShare.getName(),
smbFileShare.getDescription(), smbFileShare.getMaxUsers(),
smbFileShare.getPermission(), forceGroup)) {
_log.info("NetAppClusterModeDevice doShare for {} with id {} - failed",
shareId, args.getFileObjId());
return false;
} else {
// Since share creation is successful, now update with right
// permission.
if (!ncApi.modifyShare(shareId,
smbFileShare.getName(), smbFileShare.getDescription(),
smbFileShare.getMaxUsers(),
smbFileShare.getPermission(), forceGroup)) {
// Cleanup the share if permission update is
// unsuccessful.
doDeleteShare(storage, args, smbFileShare);
_log.info("NetAppClusterModeDevice doShare for {} with id {} - failed",
shareId, args.getFileObjId());
return false;
} else {
smbFileShare.setNativeId(shareId);
// share creation is successful,no need to set permission,clear the default one.
List<CifsAcl> existingAcls = new ArrayList<CifsAcl>();
CifsAcl defaultAcl = new CifsAcl();
// By default NetApp share get everyone full access.
defaultAcl.setUserName("everyone");
defaultAcl.setAccess(CifsAccess.full);
existingAcls.add(defaultAcl);
ncApi.deleteCIFSShareAcl(smbFileShare.getName(), existingAcls);
smbFileShare.setNetBIOSName(ncApi.getNetBiosName());
_log.info("NetAppClusterModeDevice doShare for {} with id {} - complete",
shareId, args.getFileObjId());
return true;
}
}
}
/**
* modify NetAppC share with right permissions and other parameters
*
* @param StorageSystem mount path of the fileshare
* @param args containing input/out arguments of filedevice
* @param smbFileShare existingShare smbFileshare object that needs to be modified.
* @param forceGroup Name of the group the fileshare belongs.
* @return
*/
private Boolean modifyNtpShare(StorageSystem storage,
FileDeviceInputOutput args, SMBFileShare smbFileShare,
String forceGroup, SMBFileShare existingShare) throws NetAppCException {
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
String shareId = smbFileShare.getPath();
if (!ncApi.modifyShare(shareId, smbFileShare.getName(), smbFileShare.getDescription(),
smbFileShare.getMaxUsers(), smbFileShare.getPermission(), forceGroup)) {
_log.info(
"NetAppClusterModeDevice doShare (modification) for {} with id {} - failed",
shareId, args.getFileObjId());
return false;
} else {
_log.info(
"NetAppClusterModeDevice doShare (modification) for {} with id {} - complete",
shareId, args.getFileObjId());
return true;
}
}
private Boolean netAppDeleteCIFSExports(StorageSystem storage,
SMBShareMap currentShares, String portGroup) throws NetAppCException {
int failedCount = 0;
Iterator<Entry<String, SMBFileShare>> it = currentShares.entrySet()
.iterator();
List<String> removedShareKeys = new ArrayList<String>();
while (it.hasNext()) {
Map.Entry<String, SMBFileShare> entry = it.next();
String key = entry.getKey();
SMBFileShare smbFileShare = entry.getValue();
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
if (!ncApi.deleteShare(smbFileShare.getName())) {
failedCount++;
} else {
removedShareKeys.add(key);
}
}
for (String keys : removedShareKeys) {
currentShares.remove(keys);
}
if (failedCount > 0) {
return false;
} else {
return true;
}
}
/**
* create NetAppC snapshot path from file share path and snapshot name
*
* @param fsPath mount path of the fileshare
* @param name snapshot name
* @return String
*/
private String getSnapshotPath(String fsPath, String name) {
return String.format("%1$s/.snapshot/%2$s",
fsPath, name);
}
/**
* create NetAppC snapshot path from file share path and snapshot name
*
* @param fsPath mount path of the fileshare
* @param name snapshot name
* @return String
*/
private String getSnapshotMountPath(String fsPath, String name) {
return String.format("%1$s/.snapshot/%2$s",
fsPath, name);
}
@Override
public BiosCommandResult updateShareACLs(StorageSystem storage,
FileDeviceInputOutput args) {
List<ShareACL> existingAcls = new ArrayList<ShareACL>();
existingAcls = args.getExistingShareAcls();
String portGroup = findSVMName(args.getFs());
BiosCommandResult result = new BiosCommandResult();
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
try {
processAclsForShare(ncApi, args);
result = BiosCommandResult.createSuccessfulResult();
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::updateShareACLs failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUpdateCIFSShareAcl();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
// if delete or modify fails , revert to old acl
rollbackShareACLs(storage, args, existingAcls);
}
return result;
}
private void processAclsForShare(NetAppClusterApi ncApi,
FileDeviceInputOutput args) {
String ShareName = args.getShareName();
List<ShareACL> aclsToAdd = new ArrayList<ShareACL>();
List<ShareACL> aclsToModify = new ArrayList<ShareACL>();
List<ShareACL> aclsToDelete = new ArrayList<ShareACL>();
aclsToAdd.addAll(args.getShareAclsToAdd());
aclsToModify.addAll(args.getShareAclsToModify());
aclsToDelete.addAll(args.getShareAclsToDelete());
if (!aclsToAdd.isEmpty()) {
updateShareAcl(ncApi, ShareName, aclsToAdd, AclOperation.ADD);
}
if (!aclsToModify.isEmpty()) {
updateShareAcl(ncApi, ShareName, aclsToModify, AclOperation.MODIFY);
}
if (!aclsToDelete.isEmpty()) {
updateShareAcl(ncApi, ShareName, aclsToDelete, AclOperation.DELETE);
}
}
/**
* updateShareAcl is method to perform add, modify and delete acl operation based
* on the param action
*
* @param ncApi
* @param shareName
* @param inputAcls
* @param action
*/
private void updateShareAcl(NetAppClusterApi ncApi, String shareName, List<ShareACL> inputAcls, AclOperation action) {
if (inputAcls.isEmpty()) {
return;
}
List<CifsAcl> acls = new ArrayList<CifsAcl>();
for (ShareACL newAcl : inputAcls) {
CifsAcl cif_new = new CifsAcl();
String domain = newAcl.getDomain();
String userOrGroup = newAcl.getGroup() == null ? newAcl.getUser() : newAcl.getGroup();
if (domain != null && !domain.isEmpty()) {
userOrGroup = domain + "\\" + userOrGroup;
}
cif_new.setUserName(userOrGroup);
cif_new.setAccess(getAccessEnum(newAcl.getPermission()));
acls.add(cif_new);
}
switch (action) {
case ADD:
ncApi.addCIFSShareAcl(shareName, acls);
break;
case MODIFY:
ncApi.modifyCIFSShareAcl(shareName, acls);
break;
case DELETE:
ncApi.deleteCIFSShareAcl(shareName, acls);
break;
case FORCE_ADD:
for (CifsAcl cifsAcl : acls) {
try {
List<CifsAcl> singleACL = new ArrayList<CifsAcl>();
singleACL.add(cifsAcl);
ncApi.addCIFSShareAcl(shareName, singleACL);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice:: Force add of ACL for user [" + cifsAcl.getUserName()
+ "] failed with an Exception", e);
}
}
break;
case FORCE_DELETE:
for (CifsAcl cifsAcl : acls) {
try {
List<CifsAcl> singleACL = new ArrayList<CifsAcl>();
singleACL.add(cifsAcl);
ncApi.deleteCIFSShareAcl(shareName, singleACL);
} catch (Exception e) {
_log.error("NetAppClusterModeDevice:: Force delete of ACL for user [" + cifsAcl.getUserName()
+ "] failed with an Exception", e);
}
}
break;
default:
throw new IllegalArgumentException(action + " is not a valid action for acl");
}
}
private CifsAccess getAccessEnum(String permission) throws NetAppCException {
CifsAccess access = null;
if (permission != null) {
switch (permission.toLowerCase()) {
case "read":
access = CifsAccess.read;
break;
case "change":
access = CifsAccess.change;
break;
case "fullcontrol":
access = CifsAccess.full;
break;
default:
throw new IllegalArgumentException(permission + " is not a valid permission for Cifs Share");
}
}
return access;
}
private BiosCommandResult rollbackShareACLs(StorageSystem storage, FileDeviceInputOutput args,
List<ShareACL> existingList) {
BiosCommandResult result = new BiosCommandResult();
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
try {
// We can have multiple ace added/modified in one put call ,some of them can fail due to some reason.
// In case of failure, to make it consistent in vipr db and NetApp share, delete all currently
// added and modified ace and revert it to old acl list
_log.info("NetAppClusterModeDevice::Rolling back update ACL by trying delete ACL for share {}", args.getShareName());
List<ShareACL> aclsToClear = new ArrayList<ShareACL>();
aclsToClear.addAll(args.getShareAclsToAdd());
aclsToClear.addAll(args.getShareAclsToModify());
updateShareAcl(ncApi, args.getShareName(), aclsToClear, AclOperation.FORCE_DELETE);
_log.info("NetAppClusterModeDevice::Adding back old ACL to Share {}", args.getShareName());
updateShareAcl(ncApi, args.getShareName(), existingList, AclOperation.FORCE_ADD);
result = BiosCommandResult.createSuccessfulResult();
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::Roll Back of ACL failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToUpdateCIFSShareAcl();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
@Override
public BiosCommandResult deleteShareACLs(StorageSystem storage,
FileDeviceInputOutput args) {
BiosCommandResult result = new BiosCommandResult();
List<ShareACL> existingAcls = new ArrayList<ShareACL>();
existingAcls = args.getExistingShareAcls();
String portGroup = findSVMName(args.getFs());
NetAppClusterApi ncApi = new NetAppClusterApi.Builder(storage.getIpAddress(),
storage.getPortNumber(), storage.getUsername(),
storage.getPassword()).https(true).svm(portGroup).build();
try {
updateShareAcl(ncApi, args.getShareName(), existingAcls, AclOperation.DELETE);
result = BiosCommandResult.createSuccessfulResult();
} catch (Exception e) {
_log.error("NetAppClusterModeDevice::Delete All ACL failed with an Exception", e);
ServiceError serviceError = DeviceControllerErrors.netappc.unableToDeleteCIFSShareAcl();
serviceError.setMessage(e.getLocalizedMessage());
result = BiosCommandResult.createErrorResult(serviceError);
}
return result;
}
private String constructQtreePath(String volumeName, String qtreeName) throws NetAppCException {
String qtreePath = null;
if (volumeName.contains(VOL_ROOT)) {
if (volumeName.endsWith("/")) {
// i.e. volume name is something like /vol/lookAtMe/
qtreePath = volumeName + qtreeName;
} else {
// i.e. volume name is something like /vol/lookAtMe
qtreePath = volumeName + "/" + qtreeName;
}
} else {
// i.e. volume name is something like "lookAtMe"
qtreePath = "/vol/" + volumeName + "/" + qtreeName;
}
_log.info("NetAppClusterApi::createQtree -> qtreePath = {}", qtreePath);
return qtreePath;
}
@Override
public BiosCommandResult updateNfsACLs(StorageSystem storage, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
@Override
public BiosCommandResult deleteNfsACLs(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
@Override
public BiosCommandResult assignFilePolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
@Override
public BiosCommandResult unassignFilePolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
@Override
public BiosCommandResult listSanpshotByPolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
@Override
public BiosCommandResult updateStorageSystemFileProtectionPolicy(StorageSystem storageObj, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
@Override
public BiosCommandResult checkFilePolicyPathHasResourceLabel(StorageSystem system, FileDeviceInputOutput args) {
return BiosCommandResult.createErrorResult(
DeviceControllerErrors.netappc.operationNotSupported());
}
}