/* * Copyright (c) 2008-2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.isilon; import java.net.URI; import java.net.URISyntaxException; 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.Set; import java.util.TreeSet; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.customconfigcontroller.CustomConfigConstants; import com.emc.storageos.customconfigcontroller.DataSource; import com.emc.storageos.customconfigcontroller.DataSourceFactory; import com.emc.storageos.customconfigcontroller.impl.CustomConfigHandler; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.model.FSExportMap; import com.emc.storageos.db.client.model.FileExport; import com.emc.storageos.db.client.model.FilePolicy; import com.emc.storageos.db.client.model.FilePolicy.FilePolicyApplyLevel; import com.emc.storageos.db.client.model.FilePolicy.FilePolicyPriority; import com.emc.storageos.db.client.model.FilePolicy.FilePolicyType; import com.emc.storageos.db.client.model.FilePolicy.FileReplicationCopyMode; import com.emc.storageos.db.client.model.FilePolicy.FileReplicationType; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.FileShare.PersonalityTypes; import com.emc.storageos.db.client.model.NASServer; import com.emc.storageos.db.client.model.NamedURI; import com.emc.storageos.db.client.model.OpStatusMap; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.model.PolicyStorageResource; import com.emc.storageos.db.client.model.Project; 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.SchedulePolicy; import com.emc.storageos.db.client.model.SchedulePolicy.ScheduleFrequency; import com.emc.storageos.db.client.model.SchedulePolicy.SnapshotExpireType; import com.emc.storageos.db.client.model.Snapshot; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringMap; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.Task; import com.emc.storageos.db.client.model.VirtualNAS; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.db.client.model.util.TaskUtils; import com.emc.storageos.exceptions.DeviceControllerErrors; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.fileorchestrationcontroller.FileOrchestrationUtils; import com.emc.storageos.isilon.restapi.IsilonApi; import com.emc.storageos.isilon.restapi.IsilonApi.IsilonList; import com.emc.storageos.isilon.restapi.IsilonApiFactory; import com.emc.storageos.isilon.restapi.IsilonException; import com.emc.storageos.isilon.restapi.IsilonExport; import com.emc.storageos.isilon.restapi.IsilonNFSACL; import com.emc.storageos.isilon.restapi.IsilonNFSACL.Acl; import com.emc.storageos.isilon.restapi.IsilonSMBShare; import com.emc.storageos.isilon.restapi.IsilonSMBShare.Permission; import com.emc.storageos.isilon.restapi.IsilonSmartQuota; import com.emc.storageos.isilon.restapi.IsilonSnapshot; import com.emc.storageos.isilon.restapi.IsilonSnapshotSchedule; import com.emc.storageos.isilon.restapi.IsilonSshApi; import com.emc.storageos.isilon.restapi.IsilonSyncPolicy; import com.emc.storageos.isilon.restapi.IsilonSyncPolicy.Action; import com.emc.storageos.isilon.restapi.IsilonSyncPolicy.JobState; import com.emc.storageos.isilon.restapi.IsilonSyncPolicy8Above; import com.emc.storageos.model.ResourceOperationTypeEnum; import com.emc.storageos.model.file.ExportRule; import com.emc.storageos.model.file.NfsACE; import com.emc.storageos.model.file.ShareACL; import com.emc.storageos.model.file.policy.FilePolicyScheduleParams; import com.emc.storageos.model.file.policy.FilePolicyUpdateParam; import com.emc.storageos.model.file.policy.FileReplicationPolicyParam; import com.emc.storageos.model.file.policy.FileSnapshotPolicyExpireParam; import com.emc.storageos.model.file.policy.FileSnapshotPolicyParam; import com.emc.storageos.services.OperationTypeEnum; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; import com.emc.storageos.svcs.errorhandling.model.ServiceError; import com.emc.storageos.util.VersionChecker; import com.emc.storageos.volumecontroller.ControllerException; import com.emc.storageos.volumecontroller.FileControllerConstants; import com.emc.storageos.volumecontroller.FileDeviceInputOutput; import com.emc.storageos.volumecontroller.FileShareExport; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.BiosCommandResult; import com.emc.storageos.volumecontroller.impl.file.AbstractFileStorageDevice; import com.google.common.collect.Sets; /** * Isilon specific file controller implementation. */ public class IsilonFileStorageDevice extends AbstractFileStorageDevice { private static final Logger _log = LoggerFactory.getLogger(IsilonFileStorageDevice.class); private static final String IFS_ROOT = "/ifs"; private static final String FW_SLASH = "/"; private static final String VIPR_DIR = "vipr"; private static final String QUOTA = "quota"; private static final String EXPORT_OP_NAME = "Snapshot Export"; private static final String SHARE_OP_NAME = "Snapshot Share"; public static final long SEC_IN_MILLI = 1000L; private static final String STR_WITH_NO_SPECIAL_SYMBOLS = "[^A-Za-z0-9_\\-/]"; private static final String MIRROR_POLICY = "_mirror"; private static final String ONEFS_V8 = "8.0.0.0"; private IsilonApiFactory _factory; private HashMap<String, String> configinfo; private DbClient _dbClient; @Autowired private CustomConfigHandler customConfigHandler; @Autowired private DataSourceFactory dataSourceFactory; private IsilonMirrorOperations mirrorOperations; public IsilonMirrorOperations getMirrorOperations() { return mirrorOperations; } public void setMirrorOperations(IsilonMirrorOperations mirrorOperations) { this.mirrorOperations = mirrorOperations; } /** * Set Isilon API factory * * @param factory */ public void setIsilonApiFactory(IsilonApiFactory factory) { _factory = factory; } /** * Get Isilon config info * * @param factory */ public HashMap<String, String> getConfiginfo() { return configinfo; } /** * Set Isilon config info * * @param factory */ public void setConfiginfo(HashMap<String, String> configinfo) { this.configinfo = configinfo; } public void setDbClient(DbClient dbc) { _dbClient = dbc; } /** * Set the controller config info * * @return */ public void setCustomConfigHandler(CustomConfigHandler customConfigHandler) { this.customConfigHandler = customConfigHandler; } /** * Get isilon device represented by the StorageDevice * * @param StorageSystem * object * @return IsilonSshApi object */ IsilonSshApi getIsilonDeviceSsh(StorageSystem device) throws IsilonException { IsilonSshApi sshDmApi = new IsilonSshApi(); sshDmApi.setConnParams(device.getIpAddress(), device.getUsername(), device.getPassword()); return sshDmApi; } /** * Get isilon device represented by the StorageDevice * * @param device * StorageDevice object * @return IsilonApi object * @throws IsilonException */ IsilonApi getIsilonDevice(StorageSystem device) throws IsilonException { IsilonApi isilonAPI; URI deviceURI; try { deviceURI = new URI("https", null, device.getIpAddress(), device.getPortNumber(), "/", null, null); } catch (URISyntaxException ex) { throw IsilonException.exceptions.errorCreatingServerURL(device.getIpAddress(), device.getPortNumber(), ex); } if (device.getUsername() != null && !device.getUsername().isEmpty()) { isilonAPI = _factory.getRESTClient(deviceURI, device.getUsername(), device.getPassword()); } else { isilonAPI = _factory.getRESTClient(deviceURI); } return isilonAPI; } /** * create isilon snapshot path from file share path and snapshot name * * @param fsMountPath * mount path of the fileshare * @param name * snapshot name * @return String */ private String getSnapshotPath(String fsMountPath, String name) { String prefix = IFS_ROOT + "/" + VIPR_DIR; return String.format("%1$s/.snapshot/%2$s/%3$s%4$s", IFS_ROOT, name, VIPR_DIR, fsMountPath.substring(prefix.length())); } /** * Delete isilon export * * @param isi * IsilonApi object * @param exportMap * exports to be deleted * @throws IsilonException */ private void isiDeleteExports(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { FSExportMap exportMap = null; if (args.getFileOperation()) { FileShare fileObj = args.getFs(); if (fileObj != null) { exportMap = fileObj.getFsExports(); } } else { Snapshot snap = args.getFileSnapshot(); if (snap != null) { exportMap = snap.getFsExports(); } } if (exportMap == null || exportMap.isEmpty()) { return; } String zoneName = getZoneName(args.getvNAS()); Set<String> deletedExports = new HashSet<String>(); Iterator<Map.Entry<String, FileExport>> it = exportMap.entrySet().iterator(); try { while (it.hasNext()) { Map.Entry<String, FileExport> entry = it.next(); String key = entry.getKey(); FileExport fsExport = entry.getValue(); if (zoneName != null) { isi.deleteExport(fsExport.getIsilonId(), zoneName); } else { isi.deleteExport(fsExport.getIsilonId()); } // Safe removal from the backing map. Can not do this through // iterator since this does not track changes and is not // reflected in the database. deletedExports.add(key); } } finally { // remove exports from the map in database. for (String key : deletedExports) { exportMap.remove(key); } } } /** * Deleting a file share: - deletes existing exports and smb shares for the * file share (only created by storage os) * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput * @throws IsilonException */ private void isiDeleteFS(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { /* * Delete the exports for this file system */ isiDeleteExports(isi, args); /* * Delete the SMB shares for this file system */ isiDeleteShares(isi, args); /* * Delete quota on this path, if one exists */ if (args.getFsExtensions() != null && args.getFsExtensions().containsKey(QUOTA)) { isi.deleteQuota(args.getFsExtensions().get(QUOTA)); // delete from extensions args.getFsExtensions().remove(QUOTA); } /* * Delete the snapshots for this file system */ isiDeleteSnapshots(isi, args); /* * Delete quota dirs, if one exists */ isiDeleteQuotaDirs(isi, args); /** * Delete the directory associated with the file share. */ isi.deleteDir(args.getFsMountPath(), true); /** * Delete the Schedule Policy for the file system */ isiDeleteSnapshotSchedules(isi, args); } /** * Deleting snapshots: - deletes snapshots of a file system * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput * @throws IsilonException */ private void isiDeleteSnapshots(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { List<URI> snapURIList = _dbClient .queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(args.getFsId())); for (URI snapURI : snapURIList) { Snapshot snap = _dbClient.queryObject(Snapshot.class, snapURI); if (snap != null && (!snap.getInactive())) { args.addSnapshot(snap); isiDeleteSnapshot(isi, args); } } } /** * Deleting snapshots: - deletes snapshots of a file system * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput * @throws IsilonException */ private void isiDeleteSnapshotSchedules(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { StringSet policies = args.getFs().getFilePolicies(); for (String policy : policies) { SchedulePolicy fp = _dbClient.queryObject(SchedulePolicy.class, URI.create(policy)); String snapshotScheduleName = fp.getPolicyName() + "_" + args.getFsName(); isi.deleteSnapshotSchedule(snapshotScheduleName); } } /** * Deleting a snapshot: - deletes existing exports and smb shares for the * snapshot (only created by storage os) * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput * @throws IsilonException */ private void isiDeleteSnapshot(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { args.setFileOperation(false); /* * Delete the exports first */ isiDeleteExports(isi, args); /* * Delete the SMB shares */ isiDeleteShares(isi, args); /** * Delete the snapshot. */ if (args.getSnapshotExtensions() != null && args.getSnapshotExtensions().containsKey("id")) { isi.deleteSnapshot(args.getSnapshotExtensions().get("id")); } } /** * Deleting Quota dirs: - deletes quota dirs of a file system * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput * @throws IsilonException */ private void isiDeleteQuotaDirs(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { List<URI> quotaDirURIList = _dbClient .queryByConstraint(ContainmentConstraint.Factory.getQuotaDirectoryConstraint(args.getFsId())); for (URI quotaDirURI : quotaDirURIList) { QuotaDirectory quotaDir = _dbClient.queryObject(QuotaDirectory.class, quotaDirURI); if (quotaDir != null && (!quotaDir.getInactive())) { if (quotaDir.getExtensions() != null && quotaDir.getExtensions().containsKey(QUOTA)) { String quotaId = quotaDir.getExtensions().get(QUOTA); _log.info("IsilonFileStorageDevice isiDeleteQuotaDirs , Delete Quota {}", quotaId); isi.deleteQuota(quotaId); // delete from quota extensions quotaDir.getExtensions().remove(QUOTA); // delete directory for the Quota Directory String quotaDirPath = args.getFsMountPath() + "/" + quotaDir.getName(); isi.deleteDir(quotaDirPath, true); } } } } /** * Create/modify Isilon SMB share. * * @param isi * @param args * @param smbFileShare * @throws IsilonException */ private void isiShare(IsilonApi isi, FileDeviceInputOutput args, SMBFileShare smbFileShare) throws IsilonException { IsilonSMBShare isilonSMBShare = new IsilonSMBShare(smbFileShare.getName(), smbFileShare.getPath(), smbFileShare.getDescription()); // Check if this is a new share or update of the existing share SMBShareMap smbShareMap = args.getFileObjShares(); SMBFileShare existingShare = (smbShareMap == null) ? null : smbShareMap.get(smbFileShare.getName()); String shareId; String zoneName = getZoneName(args.getvNAS()); if (existingShare != null) { shareId = existingShare.getNativeId(); // modify share if (zoneName != null) { isi.modifyShare(shareId, zoneName, isilonSMBShare); } else { isi.modifyShare(shareId, isilonSMBShare); } } else { /** * inheritablePathAcl - true: Apply Windows Default ACLs false: Do * not change existing permissions. **/ boolean inheritablePathAcl = true; if (configinfo != null && configinfo.containsKey("inheritablePathAcl")) { inheritablePathAcl = Boolean.parseBoolean(configinfo.get("inheritablePathAcl")); isilonSMBShare.setInheritablePathAcl(inheritablePathAcl); } // new share if (zoneName != null) { _log.debug("Share will be created in zone: {}", zoneName); shareId = isi.createShare(isilonSMBShare, zoneName); } else { shareId = isi.createShare(isilonSMBShare); } } smbFileShare.setNativeId(shareId); // Set Mount Point smbFileShare.setMountPoint(smbFileShare.getStoragePortNetworkId(), smbFileShare.getStoragePortName(), smbFileShare.getName()); // int file share map if (args.getFileObjShares() == null) { args.initFileObjShares(); } args.getFileObjShares().put(smbFileShare.getName(), smbFileShare); } private void isiDeleteShare(IsilonApi isi, FileDeviceInputOutput args, SMBFileShare smbFileShare) throws IsilonException { SMBShareMap currentShares = args.getFileObjShares(); // Do nothing if there are no shares if (currentShares == null || smbFileShare == null) { return; } SMBFileShare fileShare = currentShares.get(smbFileShare.getName()); if (fileShare != null) { String nativeId = fileShare.getNativeId(); String zoneName = getZoneName(args.getvNAS()); _log.info("delete the share {} with native id {}", smbFileShare.getName(), nativeId); if (zoneName != null) { isi.deleteShare(nativeId, zoneName); } else { isi.deleteShare(nativeId); } currentShares.remove(smbFileShare.getName()); } } private void isiDeleteShares(IsilonApi isi, FileDeviceInputOutput args) throws IsilonException { _log.info("IsilonFileStorageDevice:isiDeleteShares()"); SMBShareMap currentShares = null; if (args.getFileOperation()) { FileShare fileObj = args.getFs(); if (fileObj != null) { currentShares = fileObj.getSMBFileShares(); } } else { Snapshot snap = args.getFileSnapshot(); if (snap != null) { currentShares = snap.getSMBFileShares(); } } if (currentShares == null || currentShares.isEmpty()) { return; } Set<String> deletedShares = new HashSet<String>(); Iterator<Map.Entry<String, SMBFileShare>> it = currentShares.entrySet().iterator(); String zoneName = getZoneName(args.getvNAS()); try { while (it.hasNext()) { Map.Entry<String, SMBFileShare> entry = it.next(); String key = entry.getKey(); SMBFileShare smbFileShare = entry.getValue(); _log.info("delete the share name {} and native id {}", smbFileShare.getName(), smbFileShare.getNativeId()); if (zoneName != null) { isi.deleteShare(smbFileShare.getNativeId(), zoneName); } else { isi.deleteShare(smbFileShare.getNativeId()); } // Safe removal from the backing map. Can not do this through // iterator since this does not track changes and is not // reflected in the database. deletedShares.add(key); } } finally { // remove shares from the map in database. for (String key : deletedShares) { currentShares.remove(key); } } } /** * Create isilon exports * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput object * @param exports * new exports to add * @throws IsilonException */ private void isiExport(IsilonApi isi, FileDeviceInputOutput args, List<FileExport> exports) throws IsilonException { // process and export each NFSExport independently. for (FileExport fileExport : exports) { // create and set IsilonExport instance from NFSExport String permissions = fileExport.getPermissions(); Set<String> orderedSecTypes = new TreeSet<String>(); for (String securityType : fileExport.getSecurityType().split(",")) { securityType = securityType.trim(); orderedSecTypes.add(securityType); } Iterator<String> orderedList = orderedSecTypes.iterator(); String strCSSecurityType = orderedList.next().toString(); while (orderedList.hasNext()) { strCSSecurityType += "," + orderedList.next().toString(); } String root_user = fileExport.getRootUserMapping(); String storagePortName = fileExport.getStoragePortName(); String storagePort = fileExport.getStoragePort(); String protocol = fileExport.getProtocol(); String path = fileExport.getPath(); String mountPath = fileExport.getMountPath(); String comments = fileExport.getComments(); String subDirectory = fileExport.getSubDirectory(); List<String> securityTypes = new ArrayList<String>(orderedSecTypes); IsilonExport newIsilonExport = setIsilonExport(fileExport, permissions, securityTypes, root_user, mountPath, comments); _log.info("IsilonExport:" + fileExport.getClients() + ":" + fileExport.getStoragePortName() + ":" + fileExport.getStoragePort() + ":" + fileExport.getRootUserMapping() + ":" + fileExport.getPermissions() + ":" + fileExport.getProtocol() + ":" + fileExport.getSecurityType() + ":" + fileExport.getMountPoint() + ":" + fileExport.getPath() + ":" + fileExport.getSubDirectory() + ":" + fileExport.getComments()); // Initialize exports map, if its not already initialized if (args.getFileObjExports() == null) { args.initFileObjExports(); } String accessZoneName = getZoneName(args.getvNAS()); // Create/update export in Isilon. String exportKey = fileExport.getFileExportKey(); // If export with the given key does not exist, we create a new // export in Isilon and add it to the exports map. // In the other case, when export with a given key already exists in // Isilon, we need to overwrite endpoints in the current // export with endpoints in the // new export. FileExport fExport = args.getFileObjExports().get(exportKey); // check Isilon to verify if export does not exist. IsilonExport currentIsilonExport = null; if (fExport != null) { if (accessZoneName != null) { currentIsilonExport = isi.getExport(fExport.getIsilonId(), accessZoneName); } else { currentIsilonExport = isi.getExport(fExport.getIsilonId()); } } if (fExport == null || currentIsilonExport == null) { // There is no Isilon export. Create Isilon export and set it // the map. String id = null; if (accessZoneName != null) { _log.debug("Export will be created in zone: {}", accessZoneName); id = isi.createExport(newIsilonExport, accessZoneName, args.getBypassDnsCheck()); } else { id = isi.createExport(newIsilonExport, args.getBypassDnsCheck()); } // set file export data and add it to the export map fExport = new FileExport(newIsilonExport.getClients(), storagePortName, mountPath, strCSSecurityType, permissions, root_user, protocol, storagePort, path, mountPath, subDirectory, comments); fExport.setIsilonId(id); } else { // There is export in Isilon with the given id. // Overwrite this export with a new set of clients. // We overwrite only clients element in exports. Isilon API does // not use read_only_clients, read_write_clients or // root_clients. List<String> newClients = newIsilonExport.getClients(); newIsilonExport.setClients(new ArrayList<String>(newClients)); // modify current export in isilon. if (accessZoneName != null) { isi.modifyExport(fExport.getIsilonId(), accessZoneName, newIsilonExport, args.getBypassDnsCheck()); } else { isi.modifyExport(fExport.getIsilonId(), newIsilonExport, args.getBypassDnsCheck()); } // update clients fExport.setClients(newIsilonExport.getClients()); } args.getFileObjExports().put(exportKey, fExport); } } private IsilonExport setIsilonExport(FileExport fileExport, String permissions, List<String> securityType, String root_user, String mountPath, String comments) { IsilonExport newIsilonExport = new IsilonExport(); newIsilonExport.addPath(mountPath); if (comments == null) { comments = ""; } newIsilonExport.setComment(comments); // Empty list of clients means --- all clients. newIsilonExport.addClients(fileExport.getClients()); // set security type // Need to use "unix" instead of "sys" . Isilon requires "unix", not // "sys". List<String> securityFlavors = new ArrayList<String>(); for (String secType : securityType) { if (secType.equals(FileShareExport.SecurityTypes.sys.name())) { securityFlavors.add("unix"); } else { securityFlavors.add(secType); } } newIsilonExport.setSecurityFlavors(new ArrayList<String>(securityFlavors)); newIsilonExport.setMapRoot(root_user); // set permission and add clients (endpoints) to the right group // we need to set/reset read_only and map_all to support case when list // of clients in the request is empty. if (permissions.equals(FileShareExport.Permissions.ro.name())) { newIsilonExport.addReadOnlyClients(fileExport.getClients()); newIsilonExport.setReadOnly(); } else if (permissions.equals(FileShareExport.Permissions.rw.name())) { newIsilonExport.addReadWriteClients(fileExport.getClients()); newIsilonExport.resetReadOnly(); } else if (permissions.equals(FileShareExport.Permissions.root.name())) { newIsilonExport.addRootClients(fileExport.getClients()); newIsilonExport.resetReadOnly(); } return newIsilonExport; } private IsilonExport setIsilonExport(ExportRule expRule) { // String permissions, List<String> securityType, String root_user, // String mountPath, String comments) { _log.info("setIsilonExport called with {}", expRule.toString()); String mountPath = expRule.getExportPath(); String comments = ""; String root_user = expRule.getAnon(); IsilonExport newIsilonExport = new IsilonExport(); newIsilonExport.addPath(mountPath); newIsilonExport.setComment(comments); int roHosts = 0; int rwHosts = 0; int rootHosts = 0; // Empty list of clients means --- all clients. if (expRule.getReadOnlyHosts() != null) { newIsilonExport.addClients(new ArrayList<String>(expRule.getReadOnlyHosts())); roHosts = expRule.getReadOnlyHosts().size(); newIsilonExport.addReadOnlyClients(new ArrayList<String>(expRule.getReadOnlyHosts())); } if (expRule.getReadWriteHosts() != null) { newIsilonExport.addClients(new ArrayList<String>(expRule.getReadWriteHosts())); rwHosts = expRule.getReadWriteHosts().size(); newIsilonExport.addReadWriteClients(new ArrayList<String>(expRule.getReadWriteHosts())); } if (expRule.getRootHosts() != null) { newIsilonExport.addClients(new ArrayList<String>(expRule.getRootHosts())); rootHosts = expRule.getRootHosts().size(); newIsilonExport.addRootClients(new ArrayList<String>(expRule.getRootHosts())); } // set security type // Need to use "unix" instead of "sys" . Isilon requires "unix", not // "sys". // input export may contain one or more security types in a string separated by comma. ArrayList<String> secFlavors = new ArrayList<>(); for (String securityType : expRule.getSecFlavor().split(",")) { securityType = securityType.trim(); if (securityType.equals(FileShareExport.SecurityTypes.sys.name())) { securityType = "unix"; } secFlavors.add(securityType); } newIsilonExport.setSecurityFlavors(secFlavors); newIsilonExport.setMapRoot(root_user); newIsilonExport.resetReadOnly(); if (roHosts > 0 && rwHosts == 0 && rootHosts == 0) { // RO Export newIsilonExport.setReadOnly(); } _log.info("setIsilonExport completed with creating {}", newIsilonExport.toString()); return newIsilonExport; } /** * Delete exports * * @param isi * IsilonApi object to be used for communicating to the isilon * system * @param currentExports * Current exports map * @param exports * exports to be deleted * @throws ControllerException * @throws IsilonException */ private void isiUnexport(IsilonApi isi, FileDeviceInputOutput args, List<FileExport> exports) throws ControllerException, IsilonException { FSExportMap currentExports = args.getFileObjExports(); // Do nothing if there are no exports if (currentExports == null || exports == null || exports.isEmpty()) { return; } for (FileExport fileExport : exports) { String key = fileExport.getFileExportKey(); // isiExportKey(req); String id = null; FileExport fExport = currentExports.get(key); if (fExport != null) { id = fExport.getIsilonId(); } if (id != null) { String zoneName = getZoneName(args.getvNAS()); if (zoneName != null) { isi.deleteExport(id, zoneName); } else { isi.deleteExport(id); } currentExports.remove(key); } } } private void isiExpandFS(IsilonApi isi, String quotaId, FileDeviceInputOutput args) throws ControllerException, IsilonException { // get quota from Isilon and check that requested capacity is larger than the current capacity Long capacity = args.getNewFSCapacity(); IsilonSmartQuota quota = isi.getQuota(quotaId); Long hard = quota.getThresholds().getHard(); if (capacity.compareTo(hard) < 0) { String msg = String .format( "In expanding Isilon FS requested capacity is less than current capacity of file system. Path: %s, current capacity: %d", quota.getPath(), quota.getThresholds().getHard()); _log.error(msg); throw IsilonException.exceptions.expandFsFailedinvalidParameters(quota.getPath(), quota.getThresholds().getHard()); } // Modify quota for file system. IsilonSmartQuota expandedQuota = getExpandedQuota(isi, args, capacity); isi.modifyQuota(quotaId, expandedQuota); } private IsilonSmartQuota getExpandedQuota(IsilonApi isi, FileDeviceInputOutput args, Long capacity) { Long notificationLimit = 0L; Long softLimit = 0L; Long softGracePeriod = 0L; if (args.getFsNotificationLimit() != null) { notificationLimit = Long.valueOf(args.getFsNotificationLimit()); } if (args.getFsSoftLimit() != null) { softLimit = Long.valueOf(args.getFsSoftLimit()); } if (args.getFsSoftGracePeriod() != null) { softGracePeriod = Long.valueOf(args.getFsSoftGracePeriod()); } return isi.constructIsilonSmartQuotaObjectWithThreshold(null, null, capacity, false, null, capacity, notificationLimit, softLimit, softGracePeriod); } @Override public BiosCommandResult doCreateFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doCreateFS {} with name {} - start", args.getFsId(), args.getFsName()); IsilonApi isi = getIsilonDevice(storage); VirtualNAS vNAS = args.getvNAS(); String vNASPath = null; // get the custom path from the controller configuration String customPath = getCustomPath(storage, args); if (vNAS != null) { vNASPath = vNAS.getBaseDirPath(); _log.info("vNAS base directory path: {}", vNASPath); } String usePhysicalNASForProvisioning = customConfigHandler.getComputedCustomConfigValue( CustomConfigConstants.USE_PHYSICAL_NAS_FOR_PROVISIONING, "isilon", null); _log.info("Use System access zone to provision filesystem? {}", usePhysicalNASForProvisioning); String mountPath = null; String fsName = args.getFsName(); if (args.getFs().getPersonality() != null && args.getFs().getPersonality().equalsIgnoreCase(PersonalityTypes.TARGET.name())) { FileShare fsParent = _dbClient.queryObject(FileShare.class, args.getFs().getParentFileShare().getURI()); fsName = fsParent.getName(); // Add if there is any suffix in target fs label!! if (args.getFs().getLabel().contains("-target")) { String[] fsNameSuffix = args.getFs().getLabel().split(fsParent.getName() + "-target"); if (fsNameSuffix != null && fsNameSuffix.length > 1 && !fsNameSuffix[1].isEmpty()) { fsName = fsName + fsNameSuffix[1]; } } else if (args.getFs().getLabel().contains("-localTarget")) { String[] fsNameSuffix = args.getFs().getLabel().split(fsParent.getName() + "-localTarget"); if (fsNameSuffix != null && fsNameSuffix.length > 1 && !fsNameSuffix[1].isEmpty()) { fsName = fsName + fsNameSuffix[1]; } } } // Update the mount path as required if (vNASPath != null && !vNASPath.trim().isEmpty()) { mountPath = vNASPath + FW_SLASH + customPath + FW_SLASH + fsName; } else if (Boolean.valueOf(usePhysicalNASForProvisioning)) { mountPath = IFS_ROOT + FW_SLASH + getSystemAccessZoneNamespace() + FW_SLASH + customPath + FW_SLASH + fsName; } else { _log.error( "No suitable access zone found for provisioning. Provisioning on System access zone is disabled"); throw DeviceControllerException.exceptions.createFileSystemOnPhysicalNASDisabled(); } // replace extra forward slash with single one mountPath = mountPath.replaceAll("/+", "/"); _log.info("Mount path to mount the Isilon File System {}", mountPath); args.setFsMountPath(mountPath); args.setFsNativeGuid(args.getFsMountPath()); args.setFsNativeId(args.getFsMountPath()); args.setFsPath(args.getFsMountPath()); // Update the mount path for local target!!! updateLocalTargetFileSystemPath(storage, args); // Create the target directory only if the replication policy was not applied!! // If policy was applied at higher level, policy would create target file system directories! if (FileOrchestrationUtils.isPrimaryFileSystemOrNormalFileSystem(args.getFs()) || !FileOrchestrationUtils.isReplicationPolicyExistsOnTarget(_dbClient, storage, args.getVPool(), args.getProject(), args.getFs())) { // create directory for the file share isi.createDir(args.getFsMountPath(), true); Long softGrace = null; if (args.getFsSoftGracePeriod() != null) { softGrace = Long.valueOf(args.getFsSoftGracePeriod()); } // set quota - save the quota id to extensions String qid = createQuotaWithThreshold(args.getFsMountPath(), args.getFsCapacity(), args.getFsSoftLimit(), args.getFsNotificationLimit(), softGrace, null, isi); if (args.getFsExtensions() == null) { args.initFsExtensions(); } args.getFsExtensions().put(QUOTA, qid); } // set protection level // String protection = args.getFSProtectionLevel(); // Call isilon api to set protection level _log.info("IsilonFileStorageDevice doCreateFS {} - complete", args.getFsId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doCreateFS failed.", e); // rollback this operation to prevent partial result of file share // create BiosCommandResult rollbackResult = doDeleteFS(storage, args); if (rollbackResult.isCommandSuccess()) { _log.info("IsilonFileStorageDevice doCreateFS {} - rollback completed.", args.getFsId()); } else { _log.error("IsilonFileStorageDevice doCreateFS {} - rollback failed, message: {} .", args.getFsId(), rollbackResult.getMessage()); } return BiosCommandResult.createErrorResult(e); } } private FileDeviceInputOutput prepareFileDeviceInputOutput(boolean forceDelete, URI uri, String opId) { FileDeviceInputOutput args = new FileDeviceInputOutput(); boolean isFile = false; args.setOpId(opId); if (URIUtil.isType(uri, FileShare.class)) { isFile = true; args.setForceDelete(forceDelete); FileShare fsObj = _dbClient.queryObject(FileShare.class, uri); if (fsObj.getVirtualNAS() != null) { VirtualNAS vNAS = _dbClient.queryObject(VirtualNAS.class, fsObj.getVirtualNAS()); args.setvNAS(vNAS); } args.addFileShare(fsObj); args.setFileOperation(isFile); } return args; } @Override public BiosCommandResult doDeleteFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doDeleteFS {} - start", args.getFsId()); IsilonApi isi = getIsilonDevice(storage); isiDeleteFS(isi, args); _log.info("IsilonFileStorageDevice doDeleteFS {} - complete", args.getFsId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doDeleteFS failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public boolean doCheckFSExists(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { _log.info("checking file system existence on array: ", args.getFsName()); boolean isFSExists = true; // setting true by default for safer side try { IsilonApi isi = getIsilonDevice(storage); isFSExists = isi.existsDir(args.getFsMountPath()); } catch (IsilonException e) { _log.error("Querying FS failed", e); } return isFSExists; } @Override public BiosCommandResult doExpandFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doExpandFS {} - start", args.getFsId()); IsilonApi isi = getIsilonDevice(storage); String quotaId = null; if (args.getFsExtensions() != null && args.getFsExtensions().get(QUOTA) != null) { quotaId = args.getFsExtensions().get(QUOTA); } else { final ServiceError serviceError = DeviceControllerErrors.isilon.doExpandFSFailed(args.getFsId()); _log.error(serviceError.getMessage()); return BiosCommandResult.createErrorResult(serviceError); } isiExpandFS(isi, quotaId, args); _log.info("IsilonFileStorageDevice doExpandFS {} - complete", args.getFsId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doExpandFS failed.", e); return BiosCommandResult.createErrorResult(e); } catch (Exception e) { _log.error("doExpandFS failed.", e); // convert this to a ServiceError and create/or reuse a service // code ServiceError serviceError = DeviceControllerErrors.isilon.unableToExpandFileSystem(); return BiosCommandResult.createErrorResult(serviceError); } } @Override public BiosCommandResult doExport(StorageSystem storage, FileDeviceInputOutput args, List<FileExport> exportList) throws ControllerException { // Snapshot Export operation is not supported by ISILON. if (args.getFileOperation() == false) { return BiosCommandResult .createErrorResult(DeviceControllerErrors.isilon.unSupportedOperation(EXPORT_OP_NAME)); } try { _log.info("IsilonFileStorageDevice doExport {} - start", args.getFileObjId()); IsilonApi isi = getIsilonDevice(storage); isiExport(isi, args, exportList); _log.info("IsilonFileStorageDevice doExport {} - complete", args.getFileObjId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doExport failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doUnexport(StorageSystem storage, FileDeviceInputOutput args, List<FileExport> exportList) throws ControllerException { try { _log.info("IsilonFileStorageDevice doUnexport: {} - start", args.getFileObjId()); IsilonApi isi = getIsilonDevice(storage); isiUnexport(isi, args, exportList); _log.info("IsilonFileStorageDevice doUnexport {} - complete", args.getFileObjId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doUnexport failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doShare(StorageSystem storage, FileDeviceInputOutput args, SMBFileShare smbFileShare) throws ControllerException { // Snapshot Share operation is not supported by ISILON. if (args.getFileOperation() == false) { return BiosCommandResult .createErrorResult(DeviceControllerErrors.isilon.unSupportedOperation(SHARE_OP_NAME)); } try { _log.info("IsilonFileStorageDevice doShare() - start"); IsilonApi isi = getIsilonDevice(storage); isiShare(isi, args, smbFileShare); _log.info("IsilonFileStorageDevice doShare() - complete"); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doShare failed.", e); return BiosCommandResult.createErrorResult(e); } catch (Exception e) { _log.error("doShare failed.", e); // convert this to a ServiceError and create/or reuse a service // code ServiceError serviceError = DeviceControllerErrors.isilon.unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } } @Override public BiosCommandResult doDeleteShare(StorageSystem storage, FileDeviceInputOutput args, SMBFileShare smbFileShare) throws ControllerException { try { _log.info("IsilonFileStorageDevice doDeleteShare: {} - start"); IsilonApi isi = getIsilonDevice(storage); isiDeleteShare(isi, args, smbFileShare); _log.info("IsilonFileStorageDevice doDeleteShare {} - complete"); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doDeleteShare failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doDeleteShares(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doDeleteShares: {} - start"); IsilonApi isi = getIsilonDevice(storage); isiDeleteShares(isi, args); _log.info("IsilonFileStorageDevice doDeleteShares {} - complete"); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doDeleteShares failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doModifyFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doModifyFS {} - start", args.getFsId()); IsilonApi isi = getIsilonDevice(storage); String quotaId = null; if (args.getFsExtensions() != null && args.getFsExtensions().get(QUOTA) != null) { quotaId = args.getFsExtensions().get(QUOTA); } else { final ServiceError serviceError = DeviceControllerErrors.isilon.unableToUpdateFileSystem(args.getFsId()); _log.error(serviceError.getMessage()); return BiosCommandResult.createErrorResult(serviceError); } IsilonSmartQuota expandedQuota = getExpandedQuota(isi, args, args.getFsCapacity()); isi.modifyQuota(quotaId, expandedQuota); _log.info("IsilonFileStorageDevice doModifyFS {} - complete", args.getFsId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doModifyFS failed.", e); return BiosCommandResult.createErrorResult(e); } catch (Exception e) { _log.error("doModifyFS failed.", e); // convert this to a ServiceError and create/or reuse a service // code ServiceError serviceError = DeviceControllerErrors.isilon.unableToUpdateFileSystem(args.getFsId()); return BiosCommandResult.createErrorResult(serviceError); } } @Override public BiosCommandResult doSnapshotFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doSnapshotFS {} {} - start", args.getSnapshotId(), args.getSnapshotName()); IsilonApi isi = getIsilonDevice(storage); // To Do - add timestamp for uniqueness String snapId = isi.createSnapshot(args.getSnapshotName(), args.getFsMountPath()); if (args.getSnapshotExtensions() == null) { args.initSnapshotExtensions(); } args.getSnapshotExtensions().put("id", snapId); args.setSnapNativeId(snapId); String path = getSnapshotPath(args.getFsMountPath(), args.getSnapshotName()); args.setSnapshotMountPath(path); args.setSnapshotPath(path); _log.info("IsilonFileStorageDevice doSnapshotFS {} - complete", args.getSnapshotId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doSnapshotFS failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doRestoreFS(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { BiosCommandResult result = new BiosCommandResult(); String opName = ResourceOperationTypeEnum.RESTORE_FILE_SNAPSHOT.getName(); ServiceError serviceError = IsilonException.errors.jobFailed(opName); result.error(serviceError); return result; } @Override public BiosCommandResult doDeleteSnapshot(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { _log.info("IsilonFileStorageDevice doDeleteSnapshot {} - start", args.getSnapshotId()); IsilonApi isi = getIsilonDevice(storage); isiDeleteSnapshot(isi, args); _log.info("IsilonFileStorageDevice doDeleteSnapshot {} - complete", args.getSnapshotId()); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doDeleteSnapshot failed.", e); return BiosCommandResult.createErrorResult(e); } } // Get FS snapshot list from the array @Override public BiosCommandResult getFSSnapshotList(StorageSystem storage, FileDeviceInputOutput args, List<String> snapshots) throws ControllerException { String op = "getFSSnapshotList"; String devType = storage.getSystemType(); BiosCommandResult result = BiosCommandResult .createErrorResult(DeviceControllerException.errors.unsupportedOperationOnDevType(op, devType)); return result; } @Override public void doConnect(StorageSystem storage) throws ControllerException { try { _log.info("doConnect {} - start", storage.getId()); IsilonApi isi = getIsilonDevice(storage); isi.getClusterInfo(); String msg = String.format("doConnect %1$s - complete", storage.getId()); _log.info(msg); } catch (IsilonException e) { _log.error("doConnect failed.", e); throw DeviceControllerException.exceptions.connectStorageFailed(e); } } @Override public void doDisconnect(StorageSystem storage) { // not much to do here ... just reply success } @Override public BiosCommandResult getPhysicalInventory(StorageSystem storage) { ServiceError serviceError = DeviceControllerErrors.isilon.unableToGetPhysicalInventory(storage.getId()); return BiosCommandResult.createErrorResult(serviceError); } @Override public BiosCommandResult doCreateQuotaDirectory(StorageSystem storage, FileDeviceInputOutput args, QuotaDirectory quotaDir) throws ControllerException { // Get Parent FS mount path // Get Quota Directory Name // Get Quota Size // Call create Directory // Call create Quota (Aways use that quota for updating the size) String fsMountPath = args.getFsMountPath(); Long qDirSize = quotaDir.getSize(); String qDirPath = fsMountPath + "/" + quotaDir.getName(); _log.info("IsilonFileStorageDevice doCreateQuotaDirectory {} with size {} - start", qDirPath, qDirSize); try { IsilonApi isi = getIsilonDevice(storage); // create directory for the file share isi.createDir(qDirPath, true); String qid = checkThresholdAndcreateQuota(quotaDir, qDirSize, qDirPath, args.getFsCapacity(), isi); if (args.getQuotaDirExtensions() == null) { args.initQuotaDirExtensions(); } args.getQuotaDirExtensions().put(QUOTA, qid); _log.info("IsilonFileStorageDevice doCreateQuotaDirectory {} with size {} - complete", qDirPath, qDirSize); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doCreateQuotaDirectory failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doDeleteQuotaDirectory(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { // Get Parent FS Mount Path // Get Quota Directory Name // Get Quota Size // Call Delete Quota // Call Delete Directory recursively QuotaDirectory quotaDir = args.getQuotaDirectory(); String fsMountPath = args.getFsMountPath(); Long qDirSize = quotaDir.getSize(); String qDirPath = fsMountPath + "/" + quotaDir.getName(); _log.info("IsilonFileStorageDevice doDeleteQuotaDirectory {} with size {} - start", qDirPath, qDirSize); try { IsilonApi isi = getIsilonDevice(storage); String quotaId = null; if (quotaDir.getExtensions() != null) { quotaId = quotaDir.getExtensions().get(QUOTA); } if (quotaId != null) { _log.info("IsilonFileStorageDevice doDeleteQuotaDirectory , Delete Quota {}", quotaId); isi.deleteQuota(quotaId); } // delete directory for the Quota Directory isi.deleteDir(qDirPath, true); _log.info("IsilonFileStorageDevice doDeleteQuotaDirectory {} with size {} - complete", qDirPath, qDirSize); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doDeleteQuotaDirectory failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doUpdateQuotaDirectory(StorageSystem storage, FileDeviceInputOutput args, QuotaDirectory quotaDir) throws ControllerException { // Get Parent FS mount path // Get Quota Directory Name // Get Quota Size // Call Update Quota (Aways use that quota for updating the size) String fsMountPath = args.getFsMountPath(); Long qDirSize = quotaDir.getSize(); String qDirPath = fsMountPath + "/" + quotaDir.getName(); _log.info("IsilonFileStorageDevice doUpdateQuotaDirectory {} with size {} - start", qDirPath, qDirSize); try { IsilonApi isi = getIsilonDevice(storage); String quotaId = null; if (quotaDir.getExtensions() != null) { quotaId = quotaDir.getExtensions().get(QUOTA); } if (quotaId != null) { // Isilon does not allow to update quota directory to zero. if (qDirSize > 0) { _log.info("IsilonFileStorageDevice doUpdateQuotaDirectory , Update Quota {} with Capacity {}", quotaId, qDirSize); IsilonSmartQuota expandedQuota = getQuotaDirectoryExpandedSmartQuota(quotaDir, qDirSize, args.getFsCapacity(), isi); isi.modifyQuota(quotaId, expandedQuota); } } else { // Create a new Quota String qid = checkThresholdAndcreateQuota(quotaDir, qDirSize, qDirPath, null, isi); if (args.getQuotaDirExtensions() == null) { args.initQuotaDirExtensions(); } args.getQuotaDirExtensions().put(QUOTA, qid); } _log.info("IsilonFileStorageDevice doUpdateQuotaDirectory {} with size {} - complete", qDirPath, qDirSize); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("doUpdateQuotaDirectory failed.", e); return BiosCommandResult.createErrorResult(e); } } private IsilonSmartQuota getQuotaDirectoryExpandedSmartQuota(QuotaDirectory quotaDir, Long qDirSize, Long fsSize, IsilonApi isi) { Long notificationLimit = 0L; Long softlimit = 0L; Long softGrace = 0L; if (quotaDir.getNotificationLimit() != null) { notificationLimit = Long.valueOf(quotaDir.getNotificationLimit()); } if (quotaDir.getSoftLimit() != null) { softlimit = Long.valueOf(quotaDir.getSoftLimit()); } if (quotaDir.getSoftGrace() != null) { softGrace = Long.valueOf(quotaDir.getSoftGrace()); } return isi.constructIsilonSmartQuotaObjectWithThreshold(null, null, fsSize, false, null, qDirSize, notificationLimit, softlimit, softGrace); } private String checkThresholdAndcreateQuota(QuotaDirectory quotaDir, Long qDirSize, String qDirPath, Long fsSize, IsilonApi isi) { Long notificationLimit = 0L; Long softlimit = 0L; Long softGrace = 0L; if (quotaDir.getNotificationLimit() != null) { notificationLimit = Long.valueOf(quotaDir.getNotificationLimit()); } if (quotaDir.getSoftLimit() != null) { softlimit = Long.valueOf(quotaDir.getSoftLimit()); } if (quotaDir.getSoftGrace() != null) { softGrace = Long.valueOf(quotaDir.getSoftGrace()); } return createQuotaWithThreshold(qDirPath, qDirSize, softlimit, notificationLimit, softGrace, fsSize, isi); } public String createQuotaWithThreshold(String qDirPath, Long qDirSize, Long softLimitSize, Long notificationLimitSize, Long softGracePeriod, Long fsSize, IsilonApi isi) { boolean bThresholdsIncludeOverhead = true; boolean bIncludeSnapshots = true; if (configinfo != null) { if (configinfo.containsKey("thresholdsIncludeOverhead")) { bThresholdsIncludeOverhead = Boolean.parseBoolean(configinfo.get("thresholdsIncludeOverhead")); } if (configinfo.containsKey("includeSnapshots")) { bIncludeSnapshots = Boolean.parseBoolean(configinfo.get("includeSnapshots")); } } // set quota - save the quota id to extensions String qid = isi.createQuota(qDirPath, fsSize, bThresholdsIncludeOverhead, bIncludeSnapshots, qDirSize, notificationLimitSize != null ? notificationLimitSize : 0L, softLimitSize != null ? softLimitSize : 0L, softGracePeriod != null ? softGracePeriod : 0L); return qid; } @Override public BiosCommandResult deleteExportRules(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { BiosCommandResult result = new BiosCommandResult(); List<ExportRule> allExports = args.getExistingDBExportRules(); String subDir = args.getSubDirectory(); boolean allDirs = args.isAllDir(); String exportPath; String subDirExportPath = ""; subDir = args.getSubDirectory(); 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; } } _log.info("exportPath : {}", exportPath); args.setExportPath(exportPath); _log.info("Number of existing exports found {}", allExports.size()); try { IsilonApi isi = getIsilonDevice(storage); String zoneName = getZoneName(args.getvNAS()); 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) { _log.info("Delete IsilonExport id {} for path {}", rule.getDeviceExportId(), rule.getExportPath()); if (zoneName != null) { isi.deleteExport(rule.getDeviceExportId(), zoneName); } else { isi.deleteExport(rule.getDeviceExportId()); } } } 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) { _log.info("Delete IsilonExport id for path {} f containing subdirectory {}", rule.getDeviceExportId() + ":" + rule.getExportPath(), subDir); String fsExportPathWithSub = args.getFsPath() + "/" + subDir; if (rule.getExportPath().equalsIgnoreCase(fsExportPathWithSub)) { _log.info("Delete IsilonExport id {} for path {}", rule.getDeviceExportId(), rule.getExportPath()); if (zoneName != null) { isi.deleteExport(rule.getDeviceExportId(), zoneName); } else { isi.deleteExport(rule.getDeviceExportId()); } } } } 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"); for (ExportRule rule : allExports) { if (rule.getExportPath().equalsIgnoreCase(exportPath)) { _log.info("Delete IsilonExport id {} for path {}", rule.getDeviceExportId(), rule.getExportPath()); if (zoneName != null) { isi.deleteExport(rule.getDeviceExportId(), zoneName); } else { isi.deleteExport(rule.getDeviceExportId()); } } } } } catch (IsilonException ie) { _log.info("Exception: {}", ie); throw new DeviceControllerException("Exception while performing export for {0} ", new Object[] { args.getFsId() }); } _log.info("IsilonFileStorageDevice exportFS {} - complete", args.getFsId()); result.setCommandSuccess(true); result.setCommandStatus(Operation.Status.ready.name()); return result; } @Override public BiosCommandResult updateExportRules(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { // 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> exportsToModify = new ArrayList<>(); List<ExportRule> exportsToAdd = new ArrayList<>(); // Calculate Export Path String exportPath; String subDir = args.getSubDirectory(); // It is a Snapshot Export Update and so Sub Directory will be // ".snapshot" 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 existing Rules found {} for exportPath {}", exportsToprocess.size(), exportPath); // Isilon have separate entry for read only and read/write host list // if we want to modify export from host H1 with permission read to H2 // with read/write. then need to delete the entry from read // list and add to read/Write list. if (!exportsToprocess.isEmpty() || !exportAdd.isEmpty()) { if (exportModify != null && !exportModify.isEmpty()) { for (ExportRule existingRule : exportsToprocess) { for (ExportRule newExportRule : exportModify) { if (newExportRule.getSecFlavor().equals(existingRule.getSecFlavor())) { newExportRule.setDeviceExportId(existingRule.getDeviceExportId()); exportsToModify.add(newExportRule); } } } } // 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); // Handle Add Export Rules if (exportAdd != null && !exportAdd.isEmpty()) { for (ExportRule newExport : exportAdd) { _log.info("Add Export Rule {}", newExport); newExport.setExportPath(exportPath); exportsToAdd.add(newExport); } } exportsToprocess.addAll(exportAdd); } // Process Mods IsilonApi isi = getIsilonDevice(storage); for (ExportRule existingRule : exportsToModify) { _log.info("Modify Export rule : {}", existingRule.toString()); } processIsiExport(isi, args, exportsToModify); for (ExportRule existingRule : exportsToRemove) { _log.info("Remove Export rule : {}", existingRule.toString()); } processRemoveIsiExport(isi, args, exportsToRemove); for (ExportRule existingRule : exportsToAdd) { _log.info("Add Export rule : {}", existingRule.toString()); } processAddIsiExport(isi, args, exportsToAdd); BiosCommandResult result = BiosCommandResult.createSuccessfulResult(); return result; } /** * Get the export rule which are present in arry 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<>(); List<IsilonExport> exportsList = new ArrayList<IsilonExport>(); 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. IsilonApi isi = getIsilonDevice(storage); 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()); } String isilonExportId = exportRule.getDeviceExportId(); if (isilonExportId != null) { IsilonExport isilonExport = null; String zoneName = getZoneName(args.getvNAS()); if (zoneName != null) { isilonExport = isi.getExport(isilonExportId, zoneName); } else { isilonExport = isi.getExport(isilonExportId); } exportsList.add(isilonExport); arrayReadOnlyHost.addAll(isilonExport.getReadOnlyClients()); arrayReadWriteHost.addAll(isilonExport.getReadWriteClients()); arrayRootHost.addAll(isilonExport.getRootClients()); } // 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; } /** * Add isilon exports * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput object * @param exports * new exports to add * @throws IsilonException */ private void processAddIsiExport(IsilonApi isi, FileDeviceInputOutput args, List<ExportRule> exports) throws IsilonException { _log.info("ProcessAddExport Start"); List<ExportRule> modifyRules = new ArrayList<>(); // process and export each NFSExport independently. for (ExportRule exportRule : exports) { // create and set IsilonExport instance from ExportRule _log.info("Add this export rule {}", exportRule.toString()); String isilonExportId = exportRule.getDeviceExportId(); String zoneName = getZoneName(args.getvNAS()); if (isilonExportId != null) { // The Export Rule already exists on the array so modify it _log.info("Export rule exists on the device so modify it: {}", exportRule); modifyRules.add(exportRule); } else { // Create the Export _log.info("Export rule does not exist on the device so create it: {}", exportRule); IsilonExport newIsilonExport = setIsilonExport(exportRule); String expId = null; if (zoneName != null) { expId = isi.createExport(newIsilonExport, zoneName, args.getBypassDnsCheck()); } else { expId = isi.createExport(newIsilonExport, args.getBypassDnsCheck()); } exportRule.setDeviceExportId(expId); } if (!modifyRules.isEmpty()) { // Call Process Isi Export processIsiExport(isi, args, modifyRules); } } _log.info("ProcessAddExport completed."); } /** * Update isilon exports * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput object * @param exports * new exports to add * @throws IsilonException */ private void processIsiExport(IsilonApi isi, FileDeviceInputOutput args, List<ExportRule> exports) throws IsilonException { _log.info("ProcessIsiExport Start"); // process and export each NFSExport independently. for (ExportRule exportRule : exports) { // create and set IsilonExport instance from ExportRule String root_user = exportRule.getAnon(); Set<String> rootHosts = exportRule.getRootHosts(); String isilonExportId = exportRule.getDeviceExportId(); if (isilonExportId != null) { IsilonExport isilonExport = null; String zoneName = getZoneName(args.getvNAS()); if (zoneName != null) { isilonExport = isi.getExport(isilonExportId, zoneName); } else { isilonExport = isi.getExport(isilonExportId); } // Update the comment if (exportRule.getComments() != null && !exportRule.getComments().isEmpty()) { isilonExport.setComment(exportRule.getComments()); } _log.info("Update Isilon Export with id {} and {}", isilonExportId, isilonExport); List<String> allClients = new ArrayList<>(); if (isilonExport != null) { boolean hasrwClients = false; boolean hasrootClients = false; if ((isilonExport.getReadWriteClients() != null && !isilonExport.getReadWriteClients().isEmpty()) || (exportRule.getReadWriteHosts() != null && !exportRule.getReadWriteHosts().isEmpty())) { hasrwClients = true; } if ((isilonExport.getRootClients() != null && !isilonExport.getRootClients().isEmpty()) || (exportRule.getRootHosts() != null && !exportRule.getRootHosts().isEmpty())) { hasrootClients = true; } List<String> roClients = new ArrayList<>(); // over write roClients if (exportRule.getReadOnlyHosts() != null) { roClients.addAll(exportRule.getReadOnlyHosts()); allClients.addAll(exportRule.getReadOnlyHosts()); List<String> existingRWRootClients = new ArrayList<String>(); existingRWRootClients.addAll(isilonExport.getReadWriteClients()); existingRWRootClients.addAll(isilonExport.getRootClients()); List<String> commonHosts = getIntersection(existingRWRootClients, roClients); if (!commonHosts.isEmpty()) { // RW, RO and Root permissions cannot co-exist for // same client hosts // Using Set to eliminate duplicates Set<String> existingRWClients = new HashSet<String>(isilonExport.getReadWriteClients()); Set<String> existingRootClients = new HashSet<String>(isilonExport.getRootClients()); // Remove common hosts existingRWClients.removeAll(commonHosts); existingRootClients.removeAll(commonHosts); isilonExport.setRootClients(new ArrayList<String>(existingRootClients)); isilonExport.setReadWriteClients(new ArrayList<String>(existingRWClients)); } else { setClientsIntoIsilonExport("root", exportRule.getRootHosts(), isilonExport); setClientsIntoIsilonExport("rw", exportRule.getReadWriteHosts(), isilonExport); } isilonExport.setReadOnlyClients(new ArrayList<String>(roClients)); } List<String> rwClients = new ArrayList<>(); // over write rwClients has emptypayload or it contains // elements if (exportRule.getReadWriteHosts() != null) { rwClients.addAll(exportRule.getReadWriteHosts()); allClients.addAll(exportRule.getReadWriteHosts()); List<String> existingRORootClients = new ArrayList<String>(); existingRORootClients.addAll(isilonExport.getReadOnlyClients()); existingRORootClients.addAll(isilonExport.getRootClients()); List<String> commonHosts = getIntersection(existingRORootClients, rwClients); if (!commonHosts.isEmpty()) { // RW, RO and Root permissions cannot co-exist for // same client hosts // Using Set to eliminate duplicates Set<String> existingROClients = new HashSet<String>(isilonExport.getReadOnlyClients()); Set<String> existingRootClients = new HashSet<String>(isilonExport.getRootClients()); // Remove common hosts existingROClients.removeAll(commonHosts); existingRootClients.removeAll(commonHosts); isilonExport.setRootClients(new ArrayList<String>(existingRootClients)); isilonExport.setReadOnlyClients(new ArrayList<String>(existingROClients)); } else { setClientsIntoIsilonExport("root", exportRule.getRootHosts(), isilonExport); setClientsIntoIsilonExport("ro", exportRule.getReadOnlyHosts(), isilonExport); } isilonExport.setReadWriteClients(new ArrayList<String>(rwClients)); } // over write rootClients List<String> rootClients = new ArrayList<>(); if (rootHosts != null) { rootClients.addAll(rootHosts); allClients.addAll(rootHosts); List<String> existingRORWClients = new ArrayList<String>(); existingRORWClients.addAll(isilonExport.getReadOnlyClients()); existingRORWClients.addAll(isilonExport.getReadWriteClients()); List<String> commonHosts = getIntersection(existingRORWClients, rootClients); if (!commonHosts.isEmpty()) { // RW, RO and Root permissions cannot co-exist for // same client hosts Set<String> existingROClients = new HashSet<String>(isilonExport.getReadOnlyClients()); Set<String> existingRWClients = new HashSet<String>(isilonExport.getReadWriteClients()); existingROClients.removeAll(commonHosts); existingRWClients.removeAll(commonHosts); isilonExport.setReadWriteClients(new ArrayList<String>(existingRWClients)); isilonExport.setReadOnlyClients(new ArrayList<String>(existingROClients)); } else { setClientsIntoIsilonExport("ro", exportRule.getReadOnlyHosts(), isilonExport); setClientsIntoIsilonExport("rw", exportRule.getReadWriteHosts(), isilonExport); } isilonExport.setRootClients(new ArrayList<String>(rootClients)); } if (hasrwClients || hasrootClients) { isilonExport.resetReadOnly(); } else { isilonExport.setReadOnly(); } isilonExport.setMapAll(null); isilonExport.setMapRoot(root_user); // There is export in Isilon with the given id. // Overwrite this export with a new set of clients. // We overwrite only clients element in exports. Isilon API // does not use read_only_clients, // read_write_clients or root_clients. // List<String> newClients = isilonExport.getClients(); // newClients.addAll(allClients); isilonExport.setClients(new ArrayList<String>(allClients)); IsilonExport clonedExport = cloneExport(isilonExport); _log.info("Update Isilon Export with id {} and new info {}", isilonExportId, clonedExport.toString()); if (zoneName != null) { isi.modifyExport(isilonExportId, zoneName, clonedExport, args.getBypassDnsCheck()); } else { isi.modifyExport(isilonExportId, clonedExport, args.getBypassDnsCheck()); } } } } _log.info("ProcessIsiExport Completed"); } /** * Delete isilon exports * * @param isi * IsilonApi object * @param args * FileDeviceInputOutput object * @param exports * new exports to add * @throws IsilonException */ private void processRemoveIsiExport(IsilonApi isi, FileDeviceInputOutput args, List<ExportRule> exports) throws IsilonException { _log.info("processRemoveIsiExport Start"); // process and export each NFSExport independently. for (ExportRule exportRule : exports) { // create and set IsilonExport instance from ExportRule _log.info("Remove this export rule {}", exportRule.toString()); String isilonExportId = exportRule.getDeviceExportId(); if (isilonExportId != null) { // The Export Rule already exists on the array so modify it _log.info("Export rule exists on the device so remove it: {}", exportRule); String zoneName = getZoneName(args.getvNAS()); if (zoneName != null) { isi.deleteExport(isilonExportId, zoneName); } else { isi.deleteExport(isilonExportId); } } } _log.info("processRemoveIsiExport Completed"); } private IsilonExport cloneExport(IsilonExport exp) { IsilonExport newExport = new IsilonExport(); newExport.addPath(exp.getPaths().get(0)); newExport.addRootClients(exp.getRootClients()); newExport.addReadWriteClients(exp.getReadWriteClients()); newExport.addReadOnlyClients(exp.getReadOnlyClients()); if (exp.getReadOnly()) { newExport.setReadOnly(); } else { newExport.resetReadOnly(); } if (exp.getAllDirs()) { newExport.setAllDirs(); } else { newExport.resetAllDirs(); } newExport.addClients(exp.getClients()); if (exp.getComment() != null) { newExport.setComment(exp.getComment()); } newExport.setSecurityFlavors(exp.getSecurityFlavors()); if (exp.getMap_all().getUser() != null && !exp.getMap_all().getUser().isEmpty()) { newExport.setMapAll(exp.getMap_all().getUser()); } if (exp.getMap_root().getUser() != null && !exp.getMap_root().getUser().isEmpty()) { newExport.setMapRoot(exp.getMap_root().getUser()); } return newExport; } private List<String> getIntersection(List<String> oldList, List<String> newList) { Set<String> a = new HashSet<String>(oldList); a.retainAll(newList); return new ArrayList<String>(a); } @Override public BiosCommandResult updateShareACLs(StorageSystem storage, FileDeviceInputOutput args) { // Requested Share ACL List<ShareACL> aclsToAdd = args.getShareAclsToAdd(); List<ShareACL> aclsToDelete = args.getShareAclsToDelete(); List<ShareACL> aclsToModify = args.getShareAclsToModify(); try { // add the new Share ACL from the array into the add request. Map<String, ShareACL> arrayExtraShareACL = extraShareACLFromArray(storage, args); _log.info("Number of extra ACLs found on array is: {}", arrayExtraShareACL.size()); if (!arrayExtraShareACL.isEmpty()) { if (aclsToAdd != null) { // now add the remaining Share ACL aclsToAdd.addAll(arrayExtraShareACL.values()); } else { // if add acl is null then create a new Share ACL and add aclsToAdd = new ArrayList<ShareACL>(); aclsToAdd.addAll(arrayExtraShareACL.values()); // update the args so new acl get persisted in CoprHD DB. args.setShareAclsToAdd(aclsToAdd); } } } catch (Exception e) { // TODO Auto-generated catch block _log.error("Not able to fetch latest Share ACL from backend array.", e); } // Get existing Acls for the share List<ShareACL> aclsToProcess = args.getExistingShareAcls(); _log.info("Share name : {}", args.getShareName()); // Process Acls _log.info("Number of existing ACLs found {}", aclsToProcess.size()); // Process ACLs to add aclsToProcess.addAll(aclsToAdd); // Process ACLs to modify for (ShareACL existingAcl : aclsToProcess) { String domainOfExistingAce = existingAcl.getDomain(); if (domainOfExistingAce == null) { domainOfExistingAce = ""; } for (ShareACL aclToModify : aclsToModify) { String domainOfmodifiedAce = aclToModify.getDomain(); if (domainOfmodifiedAce == null) { domainOfmodifiedAce = ""; } if (aclToModify.getUser() != null && existingAcl.getUser() != null) { if (domainOfExistingAce.concat(existingAcl.getUser()) .equalsIgnoreCase(domainOfmodifiedAce.concat(aclToModify.getUser()))) { existingAcl.setPermission(aclToModify.getPermission()); } } if (aclToModify.getGroup() != null && existingAcl.getGroup() != null) { if (domainOfExistingAce.concat(existingAcl.getGroup()) .equalsIgnoreCase(domainOfmodifiedAce.concat(aclToModify.getGroup()))) { existingAcl.setPermission(aclToModify.getPermission()); } } } } // Process ACLs to delete for (ShareACL aclToDelete : aclsToDelete) { String domainOfDeleteAce = aclToDelete.getDomain(); if (domainOfDeleteAce == null) { domainOfDeleteAce = ""; } for (Iterator<ShareACL> iterator = aclsToProcess.iterator(); iterator.hasNext();) { ShareACL existingAcl = iterator.next(); String domainOfExistingAce = existingAcl.getDomain(); if (domainOfExistingAce == null) { domainOfExistingAce = ""; } if (aclToDelete.getUser() != null && existingAcl.getUser() != null) { if (domainOfDeleteAce.concat(aclToDelete.getUser()) .equalsIgnoreCase(domainOfExistingAce.concat(existingAcl.getUser()))) { iterator.remove(); } } if (aclToDelete.getGroup() != null && existingAcl.getGroup() != null) { if (domainOfDeleteAce.concat(aclToDelete.getGroup()) .equalsIgnoreCase(domainOfExistingAce.concat(existingAcl.getGroup()))) { iterator.remove(); } } } } // Process new ACLs IsilonApi isi = getIsilonDevice(storage); processAclsForShare(isi, args, aclsToProcess); BiosCommandResult result = BiosCommandResult.createSuccessfulResult(); return result; } /** * Get the Share ACL which are present in array but not in CoprHD Database. * * @param storage * @param args * @return Map with domain+ group or username with ShareACL */ private Map<String, ShareACL> extraShareACLFromArray(StorageSystem storage, FileDeviceInputOutput args) { // get all Share ACL from CoprHD data base List<ShareACL> existingDBShareACL = args.getExistingShareAcls(); Map<String, ShareACL> arrayShareACLMap = new HashMap<>(); // get the all the Share ACL from the storage system. IsilonApi isi = getIsilonDevice(storage); String zoneName = getZoneName(args.getvNAS()); IsilonSMBShare share = null; if (zoneName != null) { share = isi.getShare(args.getShareName(), zoneName); } else { share = isi.getShare(args.getShareName()); } if (share != null) { List<Permission> permissions = share.getPermissions(); for (Permission perm : permissions) { if (perm.getPermissionType().equalsIgnoreCase(Permission.PERMISSION_TYPE_ALLOW)) { ShareACL shareACL = new ShareACL(); shareACL.setPermission(perm.getPermission()); String userAndDomain = perm.getTrustee().getName(); String[] trustees = new String[2]; trustees = userAndDomain.split("\\\\"); String trusteesType = perm.getTrustee().getType(); if (trustees.length > 1) { shareACL.setDomain(trustees[0]); if (trusteesType.equals("group")) { shareACL.setGroup(trustees[1]); } else { shareACL.setUser(trustees[1]); } } else { if (trusteesType.equals("group")) { shareACL.setGroup(trustees[0]); } else { shareACL.setUser(trustees[0]); } } arrayShareACLMap.put(perm.getTrustee().getName(), shareACL); } } for (Iterator iterator = existingDBShareACL.iterator(); iterator.hasNext();) { ShareACL shareACL = (ShareACL) iterator.next(); String key = ""; String domain = ""; String user = shareACL.getUser(); String group = shareACL.getGroup(); if (shareACL.getDomain() != null && !shareACL.getDomain().isEmpty()) { domain = shareACL.getDomain() + "\\"; } if (user != null && !user.isEmpty()) { key = domain + user; } else if (group != null && !group.isEmpty()) { key = domain + group; } if (arrayShareACLMap.containsKey(key)) { arrayShareACLMap.remove(key); } } } return arrayShareACLMap; } /** * get share details * * @param isilonApi * @param shareId * @return */ private IsilonSMBShare getIsilonSMBShare(IsilonApi isilonApi, String shareId, String zoneName) { _log.debug("call getIsilonSMBShare for {} ", shareId); IsilonSMBShare isilonSMBShare = null; try { if (isilonApi != null) { isilonSMBShare = isilonApi.getShare(shareId, zoneName); _log.debug("call getIsilonSMBShare {}", isilonSMBShare.toString()); } } catch (Exception e) { _log.error("Exception while getting SMBShare for {}", shareId); } return isilonSMBShare; } @Override public BiosCommandResult deleteShareACLs(StorageSystem storage, FileDeviceInputOutput args) { IsilonApi isi = getIsilonDevice(storage); processAclsForShare(isi, args, null); BiosCommandResult result = BiosCommandResult.createSuccessfulResult(); return result; } /** * Sets permissions on Isilon SMB share. * * @param isi * the isilon API handle * @param args * in which the attribute <code>shareName</code> must be set * @param aclsToProcess * the ACEs to set on Isilon SMB share. If this value is null, * then no permissions (ACEs) will be set */ private void processAclsForShare(IsilonApi isi, FileDeviceInputOutput args, List<ShareACL> aclsToProcess) { _log.info("Start processAclsForShare to set ACL for share {}: ACL: {}", args.getShareName(), aclsToProcess); IsilonSMBShare isilonSMBShare = new IsilonSMBShare(args.getShareName()); ArrayList<Permission> permissions = new ArrayList<Permission>(); String permissionValue = null; String permissionTypeValue = null; if (aclsToProcess != null) { for (ShareACL acl : aclsToProcess) { String domain = acl.getDomain(); if (domain == null) { domain = ""; } domain = domain.toLowerCase(); String userOrGroup = acl.getUser() == null ? acl.getGroup().toLowerCase() : acl.getUser().toLowerCase(); if (domain.length() > 0) { userOrGroup = domain + "\\" + userOrGroup; } permissionValue = acl.getPermission().toLowerCase(); if (permissionValue.startsWith("full")) { permissionValue = Permission.PERMISSION_FULL; } permissionTypeValue = Permission.PERMISSION_TYPE_ALLOW; Permission permission = isilonSMBShare.new Permission(permissionTypeValue, permissionValue, userOrGroup); permissions.add(permission); } } /* * If permissions array list is empty, it means to remove all ACEs on * the share. */ isilonSMBShare.setPermissions(permissions); _log.info("Calling Isilon API: modifyShare. Share {}, permissions {}", isilonSMBShare, permissions); String zoneName = getZoneName(args.getvNAS()); if (zoneName != null) { isi.modifyShare(args.getShareName(), zoneName, isilonSMBShare); } else { isi.modifyShare(args.getShareName(), isilonSMBShare); } _log.info("End processAclsForShare"); } /** * getIsilonAclFromNfsACE function will convert the nfsACE object to Isilon * ACL object. * * @param nfsACE * - vipr ACE object. * @return */ private Acl getIsilonAclFromNfsACE(NfsACE nfsACE) { IsilonNFSACL isilonAcl = new IsilonNFSACL(); Acl acl = isilonAcl.new Acl(); ArrayList<String> inheritFlags = new ArrayList<String>(); inheritFlags.add("object_inherit"); inheritFlags.add("inherit_only"); acl.setInherit_flags(inheritFlags); acl.setAccessrights(getIsilonAccessList(nfsACE.getPermissionSet())); acl.setOp("add"); acl.setAccesstype(nfsACE.getPermissionType()); String user = nfsACE.getUser(); if (nfsACE.getDomain() != null && !nfsACE.getDomain().isEmpty()) { user = nfsACE.getDomain() + "\\" + nfsACE.getUser(); } IsilonNFSACL.Persona trustee = isilonAcl.new Persona(nfsACE.getType(), null, user); acl.setTrustee(trustee); return acl; } @Override public BiosCommandResult updateNfsACLs(StorageSystem storage, FileDeviceInputOutput args) { IsilonNFSACL isilonAcl = new IsilonNFSACL(); ArrayList<Acl> aclCompleteList = new ArrayList<Acl>(); List<NfsACE> aceToAdd = args.getNfsAclsToAdd(); for (NfsACE nfsACE : aceToAdd) { Acl acl = getIsilonAclFromNfsACE(nfsACE); acl.setOp("add"); aclCompleteList.add(acl); } List<NfsACE> aceToModify = args.getNfsAclsToModify(); for (NfsACE nfsACE : aceToModify) { Acl acl = getIsilonAclFromNfsACE(nfsACE); acl.setOp("replace"); aclCompleteList.add(acl); } List<NfsACE> aceToDelete = args.getNfsAclsToDelete(); for (NfsACE nfsACE : aceToDelete) { Acl acl = getIsilonAclFromNfsACE(nfsACE); acl.setOp("delete"); aclCompleteList.add(acl); } isilonAcl.setAction("update"); isilonAcl.setAuthoritative("acl"); isilonAcl.setAcl(aclCompleteList); String path = args.getFileSystemPath(); if (args.getSubDirectory() != null && !args.getSubDirectory().isEmpty()) { path = path + "/" + args.getSubDirectory(); } // Process new ACLs IsilonApi isi = getIsilonDevice(storage); _log.info("Calling Isilon API: modify NFS Acl for {}, acl {}", args.getFileSystemPath(), isilonAcl); isi.modifyNFSACL(path, isilonAcl); _log.info("End updateNfsACLs"); BiosCommandResult result = BiosCommandResult.createSuccessfulResult(); return result; } private ArrayList<String> getIsilonAccessList(Set<String> permissions) { ArrayList<String> accessRights = new ArrayList<String>(); for (String per : permissions) { if (per.equalsIgnoreCase(FileControllerConstants.NFS_FILE_PERMISSION_READ)) { accessRights.add(IsilonNFSACL.AccessRights.dir_gen_read.toString()); } if (per.equalsIgnoreCase(FileControllerConstants.NFS_FILE_PERMISSION_WRITE)) { accessRights.add(IsilonNFSACL.AccessRights.dir_gen_write.toString()); } if (per.equalsIgnoreCase(FileControllerConstants.NFS_FILE_PERMISSION_EXECUTE)) { accessRights.add(IsilonNFSACL.AccessRights.dir_gen_execute.toString()); } if (per.equalsIgnoreCase(FileControllerConstants.NFS_FILE_PERMISSION_FULLCONTROL)) { accessRights.add(IsilonNFSACL.AccessRights.dir_gen_all.toString()); } } return accessRights; } @Override public BiosCommandResult deleteNfsACLs(StorageSystem storage, FileDeviceInputOutput args) { IsilonNFSACL isilonAcl = new IsilonNFSACL(); ArrayList<Acl> aclCompleteList = new ArrayList<Acl>(); List<NfsACE> aceToDelete = args.getNfsAclsToDelete(); for (NfsACE nfsACE : aceToDelete) { Acl acl = getIsilonAclFromNfsACE(nfsACE); acl.setOp("delete"); aclCompleteList.add(acl); } isilonAcl.setAction("update"); isilonAcl.setAuthoritative("acl"); isilonAcl.setAcl(aclCompleteList); String path = args.getFileSystemPath(); if (args.getSubDirectory() != null && !args.getSubDirectory().isEmpty()) { path = path + "/" + args.getSubDirectory(); } // Process new ACLs IsilonApi isi = getIsilonDevice(storage); _log.info("Calling Isilon API: to delete NFS Acl for {}, acl {}", args.getFileSystemPath(), isilonAcl); isi.modifyNFSACL(path, isilonAcl); _log.info("End deleteNfsACLs"); BiosCommandResult result = BiosCommandResult.createSuccessfulResult(); return result; } private String getZoneName(VirtualNAS vNAS) { String zoneName = null; if (vNAS != null) { zoneName = vNAS.getNasName(); } return zoneName; } /** * Set the clients to isilon export based on type * * @param type * one of "rw", "root" or "ro" * @param hosts * the clients to be set * @param isilonExport */ private void setClientsIntoIsilonExport(String type, Set<String> hosts, IsilonExport isilonExport) { ArrayList<String> clients = new ArrayList<String>(); if (hosts != null && !hosts.isEmpty()) { clients.addAll(hosts); } switch (type) { case "root": isilonExport.setRootClients(clients); break; case "rw": isilonExport.setReadWriteClients(clients); break; case "ro": isilonExport.setReadOnlyClients(clients); break; } } @Override public void doCreateMirrorLink(StorageSystem system, URI source, URI target, TaskCompleter completer) { // mirrorOperations.createMirrorFileShareLink(system, source, target, completer); } @Override public BiosCommandResult doStartMirrorLink(StorageSystem system, FileShare fs, TaskCompleter completer) { FileShare sourceFS = null; if (fs.getPersonality().equals(PersonalityTypes.TARGET.name())) { sourceFS = _dbClient.queryObject(FileShare.class, fs.getParentFileShare()); } else if (fs.getPersonality().equals(PersonalityTypes.SOURCE.name())) { sourceFS = fs; } PolicyStorageResource policyStrRes = getEquivalentPolicyStorageResource(sourceFS, _dbClient); if (policyStrRes != null) { String policyName = policyStrRes.getPolicyNativeId(); // In case of fail back we need to append _mirror name since we are starting the target FS mirror policy if (fs.getPersonality().equals(PersonalityTypes.TARGET.name())) { policyName = policyName.concat(MIRROR_POLICY); } return mirrorOperations.doStartReplicationPolicy(system, policyName, completer); } ServiceError serviceError = DeviceControllerErrors.isilon.unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } @Override public BiosCommandResult doRefreshMirrorLink(StorageSystem system, FileShare source) { PolicyStorageResource policyStrRes = getEquivalentPolicyStorageResource(source, _dbClient); if (policyStrRes != null) { String policyName = policyStrRes.getPolicyNativeId(); return mirrorOperations.doRefreshMirrorFileShareLink(system, source, policyName); } ServiceError serviceError = DeviceControllerErrors.isilon.unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } @Override public BiosCommandResult doPauseLink(StorageSystem system, FileShare source) { PolicyStorageResource policyStrRes = getEquivalentPolicyStorageResource(source, _dbClient); if (policyStrRes != null) { String policyName = policyStrRes.getPolicyNativeId(); IsilonApi isi = getIsilonDevice(system); IsilonSyncPolicy policy = isi.getReplicationPolicy(policyName); JobState policyState = policy.getLastJobState(); if (policyState.equals(JobState.running) || policyState.equals(JobState.paused)) { mirrorOperations.doCancelReplicationPolicy(system, policyName); } return mirrorOperations.doStopReplicationPolicy(system, policyName); } ServiceError serviceError = DeviceControllerErrors.isilon.unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } String gerneratePolicyName(StorageSystem system, FileShare fileShare) { return fileShare.getLabel(); } @Override public BiosCommandResult doResumeLink(StorageSystem system, FileShare source, TaskCompleter completer) { PolicyStorageResource policyStrRes = getEquivalentPolicyStorageResource(source, _dbClient); if (policyStrRes != null) { String policyName = policyStrRes.getPolicyNativeId(); return mirrorOperations.doResumeReplicationPolicy(system, policyName); } ServiceError serviceError = DeviceControllerErrors.isilon.unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } @Override public BiosCommandResult doFailoverLink(StorageSystem systemTarget, FileShare fs, TaskCompleter completer) { FileShare sourceFS = null; if (fs.getPersonality().equals(PersonalityTypes.TARGET.name())) { sourceFS = _dbClient.queryObject(FileShare.class, fs.getParentFileShare()); } else if (fs.getPersonality().equals(PersonalityTypes.SOURCE.name())) { sourceFS = fs; } PolicyStorageResource policyStrRes = getEquivalentPolicyStorageResource(sourceFS, _dbClient); if (policyStrRes != null) { String policyName = policyStrRes.getPolicyNativeId(); // In case of failback we do failover on the source file system, so we need to append _mirror if (fs.getPersonality().equals(PersonalityTypes.SOURCE.name())) { policyName = policyName.concat(MIRROR_POLICY); } return mirrorOperations.doFailover(systemTarget, policyName, completer); } ServiceError serviceError = DeviceControllerErrors.isilon .unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } @Override public BiosCommandResult doResyncLink(StorageSystem system, FileShare fs, TaskCompleter completer) { FileShare sourceFS = null; if (fs.getPersonality().equals(PersonalityTypes.TARGET.name())) { sourceFS = _dbClient.queryObject(FileShare.class, fs.getParentFileShare()); } else if (fs.getPersonality().equals(PersonalityTypes.SOURCE.name())) { sourceFS = fs; } PolicyStorageResource policyStrRes = getEquivalentPolicyStorageResource(sourceFS, _dbClient); if (policyStrRes != null) { String policyName = policyStrRes.getPolicyNativeId(); // In case of failback step 4 we do resysc on the target file system, so we need to append _mirror if (fs.getPersonality().equals(PersonalityTypes.TARGET.name())) { policyName = policyName.concat(MIRROR_POLICY); } return mirrorOperations.doResyncPrep(system, policyName, completer); } ServiceError serviceError = DeviceControllerErrors.isilon.unableToCreateFileShare(); return BiosCommandResult.createErrorResult(serviceError); } /** * rollback the target filesystems */ @Override public void doRollbackMirrorLink(StorageSystem system, List<URI> sources, List<URI> targets, TaskCompleter completer, String opId) { BiosCommandResult biosCommandResult = null; // delete the target objects if (targets != null && !targets.isEmpty()) { for (URI target : targets) { FileShare fileShare = _dbClient.queryObject(FileShare.class, target); StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, fileShare.getStorageDevice()); URI uriParent = fileShare.getParentFileShare().getURI(); if (sources.contains(uriParent) == true) { biosCommandResult = rollbackCreatedFilesystem(storageSystem, target, opId, true); if (biosCommandResult.getCommandSuccess()) { fileShare.getOpStatus().updateTaskStatus(opId, biosCommandResult.toOperation()); fileShare.setInactive(true); _dbClient.updateObject(fileShare); } } } } completer.ready(_dbClient); } /** * rollback the filesystem * * @param system * @param uri * @param opId * @param isForceDelete * @return */ private BiosCommandResult rollbackCreatedFilesystem(StorageSystem system, URI uri, String opId, boolean isForceDelete) { FileDeviceInputOutput fileInputOutput = this.prepareFileDeviceInputOutput(isForceDelete, uri, opId); return this.doDeleteFS(system, fileInputOutput); } @Deprecated @Override public BiosCommandResult assignFilePolicy(StorageSystem storage, FileDeviceInputOutput args) { // for isilon we need to create a new policy for each individual file system SchedulePolicy fp = args.getFilePolicy(); String snapshotScheduleName = fp.getPolicyName() + "_" + args.getFsName(); String pattern = snapshotScheduleName + "_%Y-%m-%d_%H-%M"; String Schedulevalue = getIsilonScheduleString(fp); Integer expireValue = getSnapshotExpireValue(fp); _log.info("File Policy name : {}", snapshotScheduleName); IsilonApi isi = getIsilonDevice(storage); try { isi.createSnapshotSchedule(snapshotScheduleName, args.getFileSystemPath(), Schedulevalue, pattern, expireValue); } catch (IsilonException e) { _log.error("assign file policy failed.", e); return BiosCommandResult.createErrorResult(e); } return BiosCommandResult.createSuccessfulResult(); } @Deprecated @Override public BiosCommandResult unassignFilePolicy(StorageSystem storageObj, FileDeviceInputOutput args) { SchedulePolicy fp = args.getFilePolicy(); String snapshotScheduleName = fp.getPolicyName() + "_" + args.getFsName(); IsilonApi isi = getIsilonDevice(storageObj); try { isi.deleteSnapshotSchedule(snapshotScheduleName); } catch (IsilonException e) { _log.error("unassign file policy failed.", e); return BiosCommandResult.createErrorResult(e); } return BiosCommandResult.createSuccessfulResult(); } @Deprecated private String getIsilonScheduleString(SchedulePolicy schedule) { StringBuilder builder = new StringBuilder(); ScheduleFrequency scheduleFreq = ScheduleFrequency.valueOf(schedule.getScheduleFrequency().toUpperCase()); switch (scheduleFreq) { case DAYS: builder.append("every "); builder.append(schedule.getScheduleRepeat()); builder.append(" days at "); builder.append(schedule.getScheduleTime()); break; case WEEKS: builder.append("every "); builder.append(schedule.getScheduleRepeat()); builder.append(" weeks on "); builder.append(schedule.getScheduleDayOfWeek()); builder.append(" at "); builder.append(schedule.getScheduleTime()); break; case MONTHS: builder.append("the "); builder.append(schedule.getScheduleDayOfMonth()); builder.append(" every "); builder.append(schedule.getScheduleRepeat()); builder.append(" month at "); builder.append(schedule.getScheduleTime()); break; default: _log.error("Not a valid schedule frequency: " + schedule.getScheduleFrequency().toLowerCase()); return null; } return builder.toString(); } @Deprecated private Integer getSnapshotExpireValue(SchedulePolicy schedulePolicy) { Long seconds = 0L; String snapshotExpire = schedulePolicy.getSnapshotExpireType(); if (snapshotExpire != null && !snapshotExpire.isEmpty()) { Long expireValue = schedulePolicy.getSnapshotExpireTime(); SnapshotExpireType expireType = SnapshotExpireType.valueOf(snapshotExpire.toUpperCase()); switch (expireType) { case HOURS: seconds = TimeUnit.HOURS.toSeconds(expireValue); break; case DAYS: seconds = TimeUnit.DAYS.toSeconds(expireValue); break; case WEEKS: seconds = TimeUnit.DAYS.toSeconds(expireValue * 7); break; case MONTHS: seconds = TimeUnit.DAYS.toSeconds(expireValue * 30); break; case NEVER: return null; default: _log.error("Not a valid expire type: " + expireType); return null; } } return seconds.intValue(); } private Integer getSnapshotExpireValue(FileSnapshotPolicyExpireParam snapExpireParam) { Long seconds = 0L; String snapshotExpire = snapExpireParam.getExpireType(); if (snapshotExpire != null && !snapshotExpire.isEmpty()) { int expireValue = snapExpireParam.getExpireValue(); SnapshotExpireType expireType = SnapshotExpireType.valueOf(snapshotExpire.toUpperCase()); switch (expireType) { case HOURS: seconds = TimeUnit.HOURS.toSeconds(expireValue); break; case DAYS: seconds = TimeUnit.DAYS.toSeconds(expireValue); break; case WEEKS: seconds = TimeUnit.DAYS.toSeconds(expireValue * 7); break; case MONTHS: seconds = TimeUnit.DAYS.toSeconds(expireValue * 30); break; case NEVER: return null; default: _log.error("Not a valid expire type: " + expireType); return null; } } return seconds.intValue(); } @Override public BiosCommandResult listSanpshotByPolicy(StorageSystem storageObj, FileDeviceInputOutput args) { FilePolicy sp = args.getFileProtectionPolicy(); FileShare fs = args.getFs(); String snapshotScheduleName = sp.getFilePolicyName() + "_" + args.getFsName(); if (sp.getPolicyStorageResources() != null && !sp.getPolicyStorageResources().isEmpty()) { for (String uriResource : sp.getPolicyStorageResources()) { PolicyStorageResource policyRes = _dbClient.queryObject(PolicyStorageResource.class, URI.create(uriResource)); if (policyRes != null && policyRes.getStorageSystem().equals(storageObj.getId())) { snapshotScheduleName = policyRes.getPolicyNativeId(); break; } } } IsilonApi isi = getIsilonDevice(storageObj); String resumeToken = null; try { do { IsilonList<IsilonSnapshot> snapshots = isi.listSnapshotsCreatedByPolicy(resumeToken, snapshotScheduleName); if (snapshots != null) { for (IsilonSnapshot islon_snap : snapshots.getList()) { _log.info("file policy snapshot is : " + islon_snap.getName()); Snapshot snap = new Snapshot(); snap.setLabel(islon_snap.getName()); snap.setMountPath(islon_snap.getPath()); snap.setName(islon_snap.getName()); snap.setId(URIUtil.createId(Snapshot.class)); snap.setOpStatus(new OpStatusMap()); snap.setProject(new NamedURI(fs.getProject().getURI(), islon_snap.getName())); snap.setMountPath(getSnapshotPath(islon_snap.getPath(), islon_snap.getName())); snap.setParent(new NamedURI(fs.getId(), islon_snap.getName())); StringMap map = new StringMap(); Long createdTime = Long.parseLong(islon_snap.getCreated()) * SEC_IN_MILLI; String expiresTime = "Never"; if (islon_snap.getExpires() != null && !islon_snap.getExpires().isEmpty()) { Long expTime = Long.parseLong(islon_snap.getExpires()) * SEC_IN_MILLI; expiresTime = expTime.toString(); } map.put("created", createdTime.toString()); map.put("expires", expiresTime); map.put("schedule", sp.getFilePolicyName()); snap.setExtensions(map); _dbClient.updateObject(snap); } resumeToken = snapshots.getToken(); } } while (resumeToken != null && !resumeToken.equalsIgnoreCase("null")); } catch (IsilonException e) { _log.error("listing snapshot by file policy failed.", e); return BiosCommandResult.createErrorResult(e); } Task task = TaskUtils.findTaskForRequestId(_dbClient, fs.getId(), args.getOpId()); // set task to completed and progress to 100 and store in DB, so waiting thread in apisvc can read it. task.ready(); task.setProgress(100); _dbClient.updateObject(task); return BiosCommandResult.createSuccessfulResult(); } @Override public BiosCommandResult updateStorageSystemFileProtectionPolicy(StorageSystem storage, FileDeviceInputOutput args) { FilePolicy existingPolicy = args.getFileProtectionPolicy(); PolicyStorageResource policyRes = args.getPolicyStorageResource(); FilePolicyUpdateParam policyUpdateParam = args.getFileProtectionPolicyUpdateParam(); IsilonApi isi = getIsilonDevice(storage); BiosCommandResult result = null; try { if (existingPolicy.getFilePolicyType().equals(FilePolicy.FilePolicyType.file_replication.name())) { boolean isVersion8above = false; if (VersionChecker.verifyVersionDetails(ONEFS_V8, storage.getFirmwareVersion()) >= 0) { isVersion8above = true; } return updateStorageSystemFileReplicationPolicy(isi, policyRes, existingPolicy, policyUpdateParam, isVersion8above); } else if (existingPolicy.getFilePolicyType().equals(FilePolicy.FilePolicyType.file_snapshot.name())) { return updateStorageSystemFileSnapshotPolicy(isi, policyRes, existingPolicy, policyUpdateParam); } else { String errorMsg = "Invalid policy type {} " + existingPolicy.getFilePolicyType(); _log.error(errorMsg); final ServiceCoded serviceCoded = DeviceControllerException.errors.jobFailedOpMsg( OperationTypeEnum.UPDATE_STORAGE_SYSTEM_POLICY_BY_POLICY_RESOURCE.toString(), errorMsg); result = BiosCommandResult.createErrorResult(serviceCoded); existingPolicy.getOpStatus().updateTaskStatus(args.getOpId(), result.toOperation()); return result; } } catch (IsilonException e) { _log.error("Update storage system policy for file policy failed.", e); return BiosCommandResult.createErrorResult(e); } } private BiosCommandResult updateStorageSystemFileReplicationPolicy(IsilonApi isi, PolicyStorageResource policyRes, FilePolicy viprPolicy, FilePolicyUpdateParam policyUpdateParam, boolean isVersion8above) { try { ArrayList<IsilonSyncPolicy> isiSyncIQPolicies = isi.getReplicationPolicies().getList(); IsilonSyncPolicy syncpolicyAtPath = null; _log.info("Checking the right syncIQ policy ..."); for (IsilonSyncPolicy syncIqPolicy : isiSyncIQPolicies) { // check for policy path if (syncIqPolicy.getSourceRootPath() != null && syncIqPolicy.getSourceRootPath().equalsIgnoreCase(policyRes.getResourcePath()) && syncIqPolicy.getName() != null && syncIqPolicy.getName().equalsIgnoreCase(policyRes.getPolicyNativeId())) { syncpolicyAtPath = syncIqPolicy; break; } } if (syncpolicyAtPath != null) { _log.info("Found SyncIQ policy{} for path {} ", syncpolicyAtPath.getName(), syncpolicyAtPath.getSourceRootPath()); boolean bModifyPolicy = false; // Temp policy to store modified values. IsilonSyncPolicy modifiedPolicy = new IsilonSyncPolicy(); modifiedPolicy.setName(syncpolicyAtPath.getName()); if (policyUpdateParam.getNumWorkerThreads() > 0 && syncpolicyAtPath.getWorkersPerNode() != policyUpdateParam.getNumWorkerThreads()) { _log.debug("Changing NumWorkerThreads to {} ", policyUpdateParam.getNumWorkerThreads()); modifiedPolicy.setWorkersPerNode(policyUpdateParam.getNumWorkerThreads()); bModifyPolicy = true; } if (policyUpdateParam.getPolicyDescription() != null && !policyUpdateParam.getPolicyDescription().isEmpty() && !policyUpdateParam.getPolicyDescription().equalsIgnoreCase(syncpolicyAtPath.getDescription())) { modifiedPolicy.setDescription(policyUpdateParam.getPolicyDescription()); bModifyPolicy = true; } if (policyUpdateParam.getReplicationPolicyParams() != null) { FileReplicationPolicyParam replParam = policyUpdateParam.getReplicationPolicyParams(); if (replParam.getReplicationCopyMode() != null && !replParam.getReplicationCopyMode().isEmpty() && !FileReplicationCopyMode.ASYNC.name().equalsIgnoreCase(replParam.getReplicationCopyMode())) { _log.warn("Replication copy mode {} is not supported by Isilon {} ", replParam.getReplicationCopyMode()); } if (replParam.getPolicySchedule() != null) { String strSchedule = getIsilonPolicySchedule(replParam.getPolicySchedule()); if (strSchedule != null && !strSchedule.isEmpty() && !strSchedule.equalsIgnoreCase(syncpolicyAtPath.getSchedule())) { modifiedPolicy.setSchedule(strSchedule); bModifyPolicy = true; } } } /* * Changes made for addressing new fields added in sync Policy in OneFSv 8.0 and above */ IsilonSyncPolicy8Above modifiedPolicycopy = new IsilonSyncPolicy8Above(); IsilonSyncPolicy8Above syncpolicyAtPath8 = null; if (isVersion8above && policyUpdateParam.getPriority() != null) { syncpolicyAtPath8 = isi.getReplicationPolicy8above(syncpolicyAtPath.getName()); modifiedPolicycopy = modifiedPolicycopy.copy(modifiedPolicy); if (syncpolicyAtPath8 != null) { if (FilePolicyPriority.valueOf(policyUpdateParam.getPriority()).ordinal() != syncpolicyAtPath8.getPriority()) { modifiedPolicycopy.setPriority(FilePolicyPriority.valueOf(policyUpdateParam.getPriority()).ordinal()); bModifyPolicy = true; } } } if (bModifyPolicy) { JobState policyState = syncpolicyAtPath.getLastJobState(); if (!policyState.equals(JobState.running) && !policyState.equals(JobState.paused)) { if (isVersion8above) { isi.modifyReplicationPolicy8above(syncpolicyAtPath8.getName(), modifiedPolicycopy); _log.info("Modify Replication Policy- {} finished successfully", syncpolicyAtPath8.getName()); } else { isi.modifyReplicationPolicy(syncpolicyAtPath.getName(), modifiedPolicy); _log.info("Modify Replication Policy- {} finished successfully", syncpolicyAtPath.getName()); } return BiosCommandResult.createSuccessfulResult(); } else { _log.error("Replication Policy - {} can't be MODIFIED because policy has an active job", syncpolicyAtPath.getName()); ServiceError error = DeviceControllerErrors.isilon .jobFailed("doModifyReplicationPolicy as : The policy has an active job and cannot be modified."); return BiosCommandResult.createErrorResult(error); } } else { _log.info("No parameters changed to modify Replication Policy- {} finished successfully", syncpolicyAtPath.getName()); return BiosCommandResult.createSuccessfulResult(); } } else { _log.error("No SyncIQ policy found at path {} , Hence can't be MODIFIED", policyRes.getResourcePath()); ServiceError error = DeviceControllerErrors.isilon .jobFailed("doModifyReplicationPolicy as : No SyncIQ policy found at given path."); return BiosCommandResult.createErrorResult(error); } } catch (IsilonException e) { return BiosCommandResult.createErrorResult(e); } } private BiosCommandResult updateStorageSystemFileSnapshotPolicy(IsilonApi isi, PolicyStorageResource policyRes, FilePolicy viprPolicy, FilePolicyUpdateParam policyUpdateParam) { try { ArrayList<IsilonSnapshotSchedule> isiSnapshotPolicies = isi.getSnapshotSchedules().getList(); IsilonSnapshotSchedule snapPolicyAtPath = null; _log.info("Checking the right snapshotIQ policy ..."); for (IsilonSnapshotSchedule snapPolicy : isiSnapshotPolicies) { // check for policy path if (snapPolicy.getPath() != null && snapPolicy.getPath().equalsIgnoreCase(policyRes.getResourcePath()) && snapPolicy.getName() != null && snapPolicy.getName().equalsIgnoreCase(policyRes.getPolicyNativeId())) { snapPolicyAtPath = snapPolicy; break; } } if (snapPolicyAtPath != null) { _log.info("Found SnapshotIQ policy{} for path {} ", snapPolicyAtPath.getName(), snapPolicyAtPath.getPath()); boolean bModifyPolicy = false; // Temp policy to store modified values. IsilonSnapshotSchedule modifiedPolicy = new IsilonSnapshotSchedule(); modifiedPolicy.setName(snapPolicyAtPath.getName()); if (policyUpdateParam.getSnapshotPolicyPrams() != null) { FileSnapshotPolicyParam snapParam = policyUpdateParam.getSnapshotPolicyPrams(); if (snapParam.getSnapshotExpireParams() != null) { Integer expireTime = getSnapshotExpireValue(snapParam.getSnapshotExpireParams()); if (expireTime != null && snapPolicyAtPath.getDuration() != null) { if (snapPolicyAtPath.getDuration().intValue() != expireTime.intValue()) { modifiedPolicy.setDuration(expireTime); bModifyPolicy = true; } } else if (expireTime != null && snapPolicyAtPath.getDuration() == null) { modifiedPolicy.setDuration(expireTime); bModifyPolicy = true; } else if (snapPolicyAtPath.getDuration() != null) { modifiedPolicy.setDuration(0); bModifyPolicy = true; } } if (snapParam.getPolicySchedule() != null) { String strSchedule = getIsilonPolicySchedule(snapParam.getPolicySchedule()); if (strSchedule != null && !strSchedule.isEmpty() && !strSchedule.equalsIgnoreCase(snapPolicyAtPath.getSchedule())) { modifiedPolicy.setSchedule(strSchedule); bModifyPolicy = true; } } } if (bModifyPolicy) { isi.modifySnapshotSchedule(snapPolicyAtPath.getName(), modifiedPolicy); _log.info("Modify Snapshot Policy- {} finished successfully", snapPolicyAtPath.getName()); return BiosCommandResult.createSuccessfulResult(); } else { _log.info("No parameters changed to modify Snapshot Policy- {} finished successfully", snapPolicyAtPath.getName()); return BiosCommandResult.createSuccessfulResult(); } } else { _log.error("No SnapshotIQ policy found at path {} , Hence can't be MODIFIED", policyRes.getResourcePath()); ServiceError error = DeviceControllerErrors.isilon .jobFailed("Modify Snapshot policy Failed as : No SnapshotIQ policy found at given path."); return BiosCommandResult.createErrorResult(error); } } catch (IsilonException e) { return BiosCommandResult.createErrorResult(e); } } /** * Gets the file system custom path value from controller configuration * * @param storage * Isilon storage system * @param args * FileDeviceInputOutput object * @return evaluated custom path */ private String getCustomPath(StorageSystem storage, FileDeviceInputOutput args) { String path = ""; IsilonApi isi = getIsilonDevice(storage); String clusterName = isi.getClusterConfig().getName(); FileShare fs = args.getFs(); // Source and taget path sould be same // source cluster name should be included in target path instead of target cluster name. if (fs != null && fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.TARGET.name())) { FileShare sourceFS = _dbClient.queryObject(FileShare.class, fs.getParentFileShare()); if (sourceFS != null && sourceFS.getStorageDevice() != null) { StorageSystem sourceSystem = _dbClient.queryObject(StorageSystem.class, sourceFS.getStorageDevice()); if (sourceSystem != null) { IsilonApi sourceCluster = getIsilonDevice(sourceSystem); clusterName = sourceCluster.getClusterConfig().getName(); // Add source access zone name to cluster name // if the replication happens from user defined access zone to system access zone!! if (sourceFS.getVirtualNAS() != null) { VirtualNAS sourcevNAS = _dbClient.queryObject(VirtualNAS.class, sourceFS.getVirtualNAS()); String vNASName = sourcevNAS.getNasName(); vNASName = getNameWithNoSpecialCharacters(vNASName, args); clusterName = clusterName + vNASName; } _log.debug("Generating path for target and the source cluster is is {}", clusterName); } } } else if (args.isTarget()) { if (args.getSourceSystem() != null) { IsilonApi sourceCluster = getIsilonDevice(args.getSourceSystem()); clusterName = sourceCluster.getClusterConfig().getName(); } // Add source access zone name to cluster name // if the replication happens from user defined access zone to system access zone!! if (args.getSourceVNAS() != null && args.getvNAS() == null) { VirtualNAS sourcevNAS = args.getSourceVNAS(); String vNASName = sourcevNAS.getNasName(); vNASName = getNameWithNoSpecialCharacters(vNASName, args); clusterName = clusterName + vNASName; } _log.debug("Generating path for target and the source cluster is is {}", clusterName); } DataSource dataSource = dataSourceFactory.createIsilonFileSystemPathDataSource(args.getProject(), args.getVPool(), args.getTenantOrg(), storage); dataSource.addProperty(CustomConfigConstants.ISILON_CLUSTER_NAME, clusterName); String configPath = customConfigHandler.getComputedCustomConfigValue(CustomConfigConstants.ISILON_PATH_CUSTOMIZATION, "isilon", dataSource); _log.debug("The isilon user defined custom path is {}", configPath); if (configPath != null && !configPath.isEmpty()) { path = args.getPathWithoutSpecialCharacters(configPath); } return path; } /** * Get the File System default system access zone from * controller configuration. * * @return access zone folder name */ private String getSystemAccessZoneNamespace() { String namespace = ""; DataSource dataSource = new DataSource(); dataSource.addProperty(CustomConfigConstants.ISILON_NO_DIR, ""); dataSource.addProperty(CustomConfigConstants.ISILON_DIR_NAME, ""); namespace = customConfigHandler.getComputedCustomConfigValue(CustomConfigConstants.ISILON_SYSTEM_ACCESS_ZONE_NAMESPACE, "isilon", dataSource); // framework does't allow empty variable to be set. To work around if = is added to variable via conf and then // remove it here namespace = namespace.replaceAll("=", ""); return namespace; } @Override public BiosCommandResult doApplyFilePolicy(StorageSystem storageObj, FileDeviceInputOutput args) { FileShare fs = args.getFs(); FileShare targetFS = null; try { IsilonApi isi = getIsilonDevice(storageObj); FilePolicy filePolicy = args.getFileProtectionPolicy(); if (filePolicy.getFilePolicyType().equals(FilePolicy.FilePolicyType.file_replication.name())) { String sourcePath = generatePathForPolicy(filePolicy, fs, args); checkAppliedResourceNamePartOfFilePolicyPath(sourcePath, filePolicy, args); String scheduleValue = getIsilonPolicySchedule(filePolicy); String targetPath = null; String targetHost = null; StorageSystem targetSystem = null; NASServer targetNasServer = null; if (fs.getPersonality() != null && PersonalityTypes.SOURCE.name().equalsIgnoreCase(fs.getPersonality())) { String targetFs = fs.getMirrorfsTargets().iterator().next(); targetFS = _dbClient.queryObject(FileShare.class, URI.create(targetFs)); targetPath = generatePathForPolicy(filePolicy, targetFS, args); if (filePolicy.getFileReplicationType().equalsIgnoreCase(FileReplicationType.LOCAL.name())) { targetPath = targetPath + "_localTarget"; } // Get the target smart connect zone!! targetHost = FileOrchestrationUtils.getTargetHostPortForReplication(_dbClient, targetFS); targetSystem = _dbClient.queryObject(StorageSystem.class, targetFS.getStorageDevice()); if (targetFS.getVirtualNAS() != null) { targetNasServer = _dbClient.queryObject(VirtualNAS.class, targetFS.getVirtualNAS()); } } IsilonSyncPolicy isiSynIQPolicy = getEquivalentIsilonSyncIQPolicy(isi, sourcePath); if (isiSynIQPolicy != null) { boolean validPolicy = validateIsilonReplicationPolicy(isiSynIQPolicy, filePolicy, targetPath, targetSystem, storageObj); if (validPolicy) { _log.info("File Policy {} is already applied and running.", filePolicy.toString()); // Verify the policy was mapped to FileStorageResource if (null == FileOrchestrationUtils.findPolicyStorageResourceByNativeId(_dbClient, storageObj, filePolicy, args, sourcePath)) { _log.info("Isilon policy found for {}, creating policy storage resouce to further management", filePolicy.getFilePolicyName()); FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, storageObj, filePolicy, args, sourcePath, isiSynIQPolicy.getName(), targetSystem, targetNasServer, targetPath); } return BiosCommandResult.createSuccessfulResult(); } else { throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "File policy and Isilon syncIQ policy differs for path: " + sourcePath); } } else { IsilonApi isiApiOfTarget = getIsilonDevice(targetSystem); String targetClusterName = isiApiOfTarget.getClusterConfig().getName(); String sourceClustername = isi.getClusterConfig().getName(); String policyName = FileOrchestrationUtils.generateNameForSyncIQPolicy(sourceClustername, targetClusterName, filePolicy, fs, args); IsilonSyncPolicy policy = new IsilonSyncPolicy(policyName, sourcePath, targetPath, targetHost, IsilonSyncPolicy.Action.sync); IsilonSyncPolicy8Above policycopy = new IsilonSyncPolicy8Above(); if (scheduleValue != null && !scheduleValue.isEmpty()) { policy.setSchedule(scheduleValue); } if (filePolicy.getFilePolicyDescription() != null) { policy.setDescription(filePolicy.getFilePolicyDescription()); } if (filePolicy.getNumWorkerThreads() != null && filePolicy.getNumWorkerThreads() > 0) { policy.setWorkersPerNode(filePolicy.getNumWorkerThreads().intValue()); } policy.setEnabled(true); String policyId = null; if (VersionChecker.verifyVersionDetails(ONEFS_V8, storageObj.getFirmwareVersion()) >= 0) { if (filePolicy.getPriority() != null) { policycopy = policycopy.copy(policy); policycopy.setPriority(FilePolicyPriority.valueOf(filePolicy.getPriority()).ordinal()); } policyId = isi.createReplicationPolicy8above(policycopy); } else { policyId = isi.createReplicationPolicy(policy); } if (policyId != null) { _log.info("Isilon File Policy {} created successfully.", policyId); FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, storageObj, filePolicy, args, sourcePath, policyName, targetSystem, targetNasServer, targetPath); return BiosCommandResult.createSuccessfulResult(); } } } else if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_snapshot.name())) { String path = generatePathForPolicy(filePolicy, fs, args); checkAppliedResourceNamePartOfFilePolicyPath(path, filePolicy, args); String clusterName = isi.getClusterConfig().getName(); String snapshotScheduleName = FileOrchestrationUtils.generateNameForSnapshotIQPolicy(clusterName, filePolicy, fs, args); IsilonSnapshotSchedule isiSnapshotSch = getEquivalentIsilonSnapshotSchedule(isi, path); if (isiSnapshotSch != null) { String filePolicySnapshotSchedule = getIsilonPolicySchedule(filePolicy); _log.info("Comparing snapshot schedule between CoprHD policy: {} and Isilon policy: {}.", filePolicySnapshotSchedule, isiSnapshotSch.getSchedule()); if (isiSnapshotSch.getSchedule() != null && isiSnapshotSch.getSchedule().equalsIgnoreCase(filePolicySnapshotSchedule)) { // Verify the policy was mapped to FileStorageResource if (null == FileOrchestrationUtils.findPolicyStorageResourceByNativeId(_dbClient, storageObj, filePolicy, args, path)) { _log.info("Isilon snapshot policy found for {}, creating policy storage resouce to further management", filePolicy.getFilePolicyName()); FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, storageObj, filePolicy, args, path, isiSnapshotSch.getName(), null, null, null); _log.info("File Policy {} is already applied and running.", filePolicy.getFilePolicyName()); } return BiosCommandResult.createSuccessfulResult(); } else { _log.info("Snapshot schedule differs between Isilon policy and CoprHD file policy. So, create policy in Isilon..."); // Create snapshot policy. createIsilonSnapshotPolicySchedule(storageObj, filePolicy, path, snapshotScheduleName, args, path); return BiosCommandResult.createSuccessfulResult(); } } else { // Create snapshot policy. createIsilonSnapshotPolicySchedule(storageObj, filePolicy, path, snapshotScheduleName, args, path); return BiosCommandResult.createSuccessfulResult(); } } return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("apply file policy failed.", e); return BiosCommandResult.createErrorResult(e); } } @Override public BiosCommandResult doUnassignFilePolicy(StorageSystem storage, FileDeviceInputOutput args) throws ControllerException { try { IsilonApi isi = getIsilonDevice(storage); FilePolicy filePolicy = args.getFileProtectionPolicy(); PolicyStorageResource policyResource = args.getPolicyStorageResource(); if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_replication.name())) { IsilonSyncPolicy isiSyncPolicy = getEquivalentIsilonSyncIQPolicy(isi, policyResource.getResourcePath()); if (isiSyncPolicy != null) { _log.info("deleting Isilon replication policy: {}", isiSyncPolicy.toString()); IsilonSyncPolicy policy = isi.getReplicationPolicy(isiSyncPolicy.getName()); String policyName = isiSyncPolicy.getName(); JobState policyState = policy.getLastJobState(); if (policyState.equals(JobState.running) || policyState.equals(JobState.paused)) { _log.info("Canceling Replication Policy -{} because policy is in - {} state ", policyName, policyState); IsilonSyncPolicy modifiedPolicy = new IsilonSyncPolicy(); modifiedPolicy.setName(policyName); modifiedPolicy.setLastJobState(JobState.canceled); isi.modifyReplicationPolicy(policyName, modifiedPolicy); } isi.deleteReplicationPolicy(policyName); isi.deleteReplicationPolicy(policyResource.getPolicyNativeId()); } else { _log.info("replication policy: {} doesn't exists on storage system", filePolicy.toString()); } return BiosCommandResult.createSuccessfulResult(); } else if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_snapshot.name())) { IsilonSnapshotSchedule isiSchedulePolicy = getEquivalentIsilonSnapshotSchedule(isi, policyResource.getResourcePath()); if (isiSchedulePolicy != null) { _log.info("deleting Isilon Snapshot schedule: {}", isiSchedulePolicy.toString()); isi.deleteSnapshotSchedule(policyResource.getPolicyNativeId()); } else { _log.info("snapshot schedule: {} doesn't exists on storage system", filePolicy.toString()); } return BiosCommandResult.createSuccessfulResult(); } return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("unassign file policy failed.", e); return BiosCommandResult.createErrorResult(e); } } private String getNameWithNoSpecialCharacters(String str, FileDeviceInputOutput args) { // Custom configuration using the below two level regular expressions to generate name with no special symbols. // Using the same here. String regex = STR_WITH_NO_SPECIAL_SYMBOLS; String path = str.replaceAll(regex, ""); if (path != null && !path.isEmpty()) { path = args.getPathWithoutSpecialCharacters(path); } return path; } private String generatePathForPolicy(FilePolicy filePolicy, FileShare fileShare, FileDeviceInputOutput args) { String policyPath = ""; FilePolicyApplyLevel applyLevel = FilePolicyApplyLevel.valueOf(filePolicy.getApplyAt()); switch (applyLevel) { case vpool: String vpool = getNameWithNoSpecialCharacters(args.getVPool().getLabel(), args); policyPath = fileShare.getNativeId().split(vpool)[0] + vpool; break; case project: String project = getNameWithNoSpecialCharacters(args.getProject().getLabel(), args); policyPath = fileShare.getNativeId().split(project)[0] + project; break; case file_system: policyPath = fileShare.getNativeId(); break; default: _log.error("Not a valid policy apply level: " + applyLevel); } return policyPath; } private static IsilonSnapshotSchedule getEquivalentIsilonSnapshotSchedule(IsilonApi isi, String path) { IsilonSnapshotSchedule isiSchedule = null; ArrayList<IsilonSnapshotSchedule> isiSnapshotPolicies = isi.getSnapshotSchedules().getList(); if (isiSnapshotPolicies != null && !isiSnapshotPolicies.isEmpty()) { for (IsilonSnapshotSchedule isiSnapshotPolicy : isiSnapshotPolicies) { if (isiSnapshotPolicy.getPath().equals(path)) { isiSchedule = isiSnapshotPolicy; break; } } } return isiSchedule; } private static IsilonSyncPolicy getEquivalentIsilonSyncIQPolicy(IsilonApi isi, String path) { IsilonSyncPolicy isiSyncPolicy = null; ArrayList<IsilonSyncPolicy> isiSyncIQPolicies = isi.getReplicationPolicies().getList(); if (isiSyncIQPolicies != null && !isiSyncIQPolicies.isEmpty()) { for (IsilonSyncPolicy isiSyncIQPolicy : isiSyncIQPolicies) { if (isiSyncIQPolicy.getSourceRootPath().equals(path)) { isiSyncPolicy = isiSyncIQPolicy; } } } return isiSyncPolicy; } private static String getIsilonPolicySchedule(FilePolicy policy) { FilePolicyScheduleParams scheduleParam = new FilePolicyScheduleParams(); scheduleParam.setScheduleDayOfMonth(policy.getScheduleDayOfMonth()); scheduleParam.setScheduleDayOfWeek(policy.getScheduleDayOfWeek()); scheduleParam.setScheduleFrequency(policy.getScheduleFrequency()); scheduleParam.setScheduleRepeat(policy.getScheduleRepeat()); scheduleParam.setScheduleTime(policy.getScheduleTime()); return getIsilonPolicySchedule(scheduleParam); } private static String getIsilonPolicySchedule(FilePolicyScheduleParams schedule) { StringBuilder builder = new StringBuilder(); ScheduleFrequency scheduleFreq = ScheduleFrequency.valueOf(schedule.getScheduleFrequency().toUpperCase()); switch (scheduleFreq) { case MINUTES: builder.append("every 1 days every "); builder.append(schedule.getScheduleRepeat()); builder.append(" minutes between "); builder.append(schedule.getScheduleTime()); builder.append(" and "); // If we add 23 hours 59 min to start time to get end time // result time come smaller in most of the case // Like for start time 3:00 AM it comes at 2:59 AM. and Isilon API does not accept it. // Fixing End time at 11:59 PM for now.(need to get it from user in future) builder.append("11:59 PM"); break; case HOURS: builder.append("every 1 days every "); builder.append(schedule.getScheduleRepeat()); builder.append(" hours between "); builder.append(schedule.getScheduleTime()); builder.append(" and "); builder.append("11:59 PM"); break; case DAYS: builder.append("every "); builder.append(schedule.getScheduleRepeat()); builder.append(" days at "); builder.append(schedule.getScheduleTime()); break; case WEEKS: builder.append("every "); builder.append(schedule.getScheduleRepeat()); builder.append(" weeks on "); builder.append(schedule.getScheduleDayOfWeek()); builder.append(" at "); builder.append(schedule.getScheduleTime()); break; case MONTHS: builder.append("the "); builder.append(schedule.getScheduleDayOfMonth()); builder.append(" every "); builder.append(schedule.getScheduleRepeat()); builder.append(" month at "); builder.append(schedule.getScheduleTime()); break; default: _log.error("Not a valid schedule frequency: " + schedule.getScheduleFrequency().toLowerCase()); return null; } return builder.toString(); } private Integer getIsilonSnapshotExpireValue(FilePolicy policy) { Long seconds = 0L; String snapshotExpire = policy.getSnapshotExpireType(); if (snapshotExpire != null && !snapshotExpire.isEmpty()) { Long expireValue = policy.getSnapshotExpireTime(); SnapshotExpireType expireType = SnapshotExpireType.valueOf(snapshotExpire.toUpperCase()); switch (expireType) { case HOURS: seconds = TimeUnit.HOURS.toSeconds(expireValue); break; case DAYS: seconds = TimeUnit.DAYS.toSeconds(expireValue); break; case WEEKS: seconds = TimeUnit.DAYS.toSeconds(expireValue * 7); break; case MONTHS: seconds = TimeUnit.DAYS.toSeconds(expireValue * 30); break; case NEVER: return null; default: _log.error("Not a valid expire type: " + expireType); return null; } } return seconds.intValue(); } private String generatePathForLocalTarget(FilePolicy filePolicy, FileShare fileShare, FileDeviceInputOutput args) { String policyPath = ""; FilePolicyApplyLevel applyLevel = FilePolicyApplyLevel.valueOf(filePolicy.getApplyAt()); String[] fsPathParts = new String[3]; switch (applyLevel) { case vpool: String vpool = args.getVPoolNameWithNoSpecialCharacters(); fsPathParts = fileShare.getNativeId().split(vpool); policyPath = fsPathParts[0] + vpool + "_localTarget" + fsPathParts[1]; break; case project: String project = args.getProjectNameWithNoSpecialCharacters(); fsPathParts = fileShare.getNativeId().split(project); policyPath = fsPathParts[0] + project + "_localTarget" + fsPathParts[1]; break; case file_system: policyPath = fileShare.getNativeId() + "_localTarget"; break; default: _log.error("Not a valid policy apply level: " + applyLevel); } return policyPath; } /** * * @param dbClient * @param project * @param storageSystem * @return */ public void updateLocalTargetFileSystemPath(StorageSystem system, FileDeviceInputOutput args) { VirtualPool vpool = args.getVPool(); Project project = args.getProject(); FileShare fs = args.getFs(); if (fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.TARGET.name())) { List<FilePolicy> replicationPolicies = FileOrchestrationUtils.getReplicationPolices(_dbClient, vpool, project, null); if (replicationPolicies != null && !replicationPolicies.isEmpty()) { if (replicationPolicies.size() > 1) { _log.warn("More than one replication policy found {}", replicationPolicies.size()); } else { FilePolicy replPolicy = replicationPolicies.get(0); if (replPolicy.getFileReplicationType().equalsIgnoreCase(FileReplicationType.LOCAL.name())) { // For local replication, the path should be different // add localTaget to file path at directory level where the policy is applied!!! String mountPath = generatePathForLocalTarget(replPolicy, fs, args); // replace extra forward slash with single one mountPath = mountPath.replaceAll("/+", "/"); _log.info("Mount path to mount the Isilon File System {}", mountPath); args.setFsMountPath(mountPath); args.setFsNativeGuid(args.getFsMountPath()); args.setFsNativeId(args.getFsMountPath()); args.setFsPath(args.getFsMountPath()); } } } else if (fs.getLabel().contains("-localTarget")) { String mountPath = fs.getNativeId() + "_localTarget"; // replace extra forward slash with single one mountPath = mountPath.replaceAll("/+", "/"); _log.info("Mount path to mount the Isilon File System {}", mountPath); args.setFsMountPath(mountPath); args.setFsNativeGuid(args.getFsMountPath()); args.setFsNativeId(args.getFsMountPath()); args.setFsPath(args.getFsMountPath()); } } return; } @Override public BiosCommandResult checkFilePolicyExistsOrCreate(StorageSystem storageObj, FileDeviceInputOutput args) { FilePolicy filePolicy = args.getFileProtectionPolicy(); BiosCommandResult result = null; try { IsilonApi isi = getIsilonDevice(storageObj); String clusterName = isi.getClusterConfig().getName(); String snapshotPolicySceduleName = FileOrchestrationUtils .generateNameForSnapshotIQPolicy(clusterName, filePolicy, null, args); String filePolicyBasePath = getFilePolicyPath(storageObj, args); checkAppliedResourceNamePartOfFilePolicyPath(filePolicyBasePath, filePolicy, args); IsilonSnapshotSchedule isilonSnapshotSchedule = getEquivalentIsilonSnapshotSchedule(isi, filePolicyBasePath); if (isilonSnapshotSchedule != null) { String filePolicySnapshotSchedule = getIsilonPolicySchedule(filePolicy); _log.info("Comparing snapshot schedule between CoprHD policy: {} and Isilon policy: {}.", filePolicySnapshotSchedule, isilonSnapshotSchedule.getSchedule()); if (isilonSnapshotSchedule.getSchedule().equalsIgnoreCase(filePolicySnapshotSchedule)) { // Verify the policy was mapped to FileStorageResource if (null == FileOrchestrationUtils.findPolicyStorageResourceByNativeId(_dbClient, storageObj, filePolicy, args, filePolicyBasePath)) { _log.info("Isilon policy found for {}, creating policy storage resouce to further management", filePolicy.getFilePolicyName()); FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, storageObj, filePolicy, args, filePolicyBasePath, isilonSnapshotSchedule.getName(), null, null, null); } result = BiosCommandResult.createSuccessfulResult(); } else { _log.info("Snapshot schedule differs between Isilon policy and CoprHD file policy. So, create policy in Isilon..."); // Create snapshot policy. createIsilonSnapshotPolicySchedule(storageObj, filePolicy, filePolicyBasePath, snapshotPolicySceduleName, args, filePolicyBasePath); result = BiosCommandResult.createSuccessfulResult(); } } else { // Create snapshot policy. createIsilonSnapshotPolicySchedule(storageObj, filePolicy, filePolicyBasePath, snapshotPolicySceduleName, args, filePolicyBasePath); result = BiosCommandResult.createSuccessfulResult(); } } catch (IsilonException e) { _log.error("Assigning file policy failed.", e); result = BiosCommandResult.createErrorResult(e); } return result; } private void createIsilonSnapshotPolicySchedule(StorageSystem storageObj, FilePolicy filePolicy, String path, String snapshotSchedulePolicyName, FileDeviceInputOutput args, String filePolicyBasePath) { String pattern = snapshotSchedulePolicyName + "_%Y-%m-%d_%H-%M"; String scheduleValue = getIsilonPolicySchedule(filePolicy); Integer expireValue = getIsilonSnapshotExpireValue(filePolicy); _log.info("File Policy : {} creation started", filePolicy.toString()); try { IsilonApi isi = getIsilonDevice(storageObj); isi.createDir(path, true); isi.createSnapshotSchedule(snapshotSchedulePolicyName, path, scheduleValue, pattern, expireValue); _log.info("Isilon File Policy {} created successfully.", snapshotSchedulePolicyName); FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, storageObj, filePolicy, args, filePolicyBasePath, snapshotSchedulePolicyName, null, null, null); } catch (IsilonException e) { throw e; } } @Override public BiosCommandResult checkFileReplicationPolicyExistsOrCreate(StorageSystem sourceStorageObj, StorageSystem targetStorageObj, FileDeviceInputOutput sourceSytemArgs, FileDeviceInputOutput targetSytemArgs) { FilePolicy filePolicy = sourceSytemArgs.getFileProtectionPolicy(); // Source Path String sourcePath = getFilePolicyPath(sourceStorageObj, sourceSytemArgs); String targetPath = getFilePolicyPath(targetStorageObj, targetSytemArgs); if (FileReplicationType.LOCAL.name().equalsIgnoreCase(filePolicy.getFileReplicationType())) { targetPath = targetPath + "_localTarget"; } // Policy Name BiosCommandResult result = null; try { IsilonApi sourceIsi = getIsilonDevice(sourceStorageObj); IsilonApi targetIsi = getIsilonDevice(targetStorageObj); String sourceClusterName = sourceIsi.getClusterConfig().getName(); String targetClusterName = targetIsi.getClusterConfig().getName(); String policyName = FileOrchestrationUtils.generateNameForSyncIQPolicy(sourceClusterName, targetClusterName, filePolicy, null, sourceSytemArgs); checkAppliedResourceNamePartOfFilePolicyPath(sourcePath, filePolicy, sourceSytemArgs); ArrayList<IsilonSyncPolicy> isiReplicationPolicies = sourceIsi.getReplicationPolicies().getList(); IsilonSyncPolicy isilonReplicationSchedule = checkForReplicationPolicyOnIsilon(isiReplicationPolicies, filePolicy, sourcePath, targetPath); if (isilonReplicationSchedule != null) { boolean validPolicy = validateIsilonReplicationPolicy(isilonReplicationSchedule, filePolicy, targetPath, targetStorageObj, sourceStorageObj); if (validPolicy) { // Verify the policy was mapped to FileStorageResource if (null == FileOrchestrationUtils.findPolicyStorageResourceByNativeId(_dbClient, sourceStorageObj, filePolicy, sourceSytemArgs, sourcePath)) { _log.info("Isilon policy found for {}, creating policy storage resouce to further management", filePolicy.getFilePolicyName()); FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, sourceStorageObj, filePolicy, sourceSytemArgs, sourcePath, isilonReplicationSchedule.getName(), targetStorageObj, targetSytemArgs.getvNAS(), targetPath); } result = BiosCommandResult.createSuccessfulResult(); } else { throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "File policy and Isilon syncIQ policy differs for path: " + sourcePath); } } else { // Create replication sync policy. createIsilonSyncPolicy(sourceStorageObj, targetStorageObj, filePolicy, sourcePath, targetPath, policyName, sourceSytemArgs, targetSytemArgs); result = BiosCommandResult.createSuccessfulResult(); } } catch (IsilonException e) { _log.error("Assigning file policy failed.", e); result = BiosCommandResult.createErrorResult(e); } return result; } private String createIsilonSyncPolicy(StorageSystem storageObj, StorageSystem targetStorage, FilePolicy filePolicy, String sourcePath, String targetPath, String syncPolicyName, FileDeviceInputOutput sourceSystemArgs, FileDeviceInputOutput targetSystemArgs) { String scheduleValue = getIsilonPolicySchedule(filePolicy); _log.info("File replication policy : {} creation started", filePolicy.toString()); try { VirtualNAS targetVNas = targetSystemArgs.getvNAS(); URI targetVNasURI = null; if (targetVNas != null) { targetVNasURI = targetVNas.getId(); } String targetHost = FileOrchestrationUtils.getTargetHostPortForReplication(_dbClient, targetStorage.getId(), targetSystemArgs.getVarray().getId(), targetVNasURI); IsilonApi isi = getIsilonDevice(storageObj); isi.createDir(sourcePath, true); IsilonSyncPolicy replicationPolicy = new IsilonSyncPolicy(syncPolicyName, sourcePath, targetPath, targetHost, Action.sync); if (scheduleValue != null && !scheduleValue.isEmpty()) { replicationPolicy.setSchedule(scheduleValue); } if (filePolicy.getFilePolicyDescription() != null) { replicationPolicy.setDescription(filePolicy.getFilePolicyDescription()); } if (filePolicy.getNumWorkerThreads() != null && filePolicy.getNumWorkerThreads() > 0) { replicationPolicy.setWorkersPerNode(filePolicy.getNumWorkerThreads().intValue()); } replicationPolicy.setEnabled(true); replicationPolicy.setSchedule(scheduleValue); String scheduleId; if (VersionChecker.verifyVersionDetails(ONEFS_V8, storageObj.getFirmwareVersion()) >= 0) { IsilonSyncPolicy8Above replicationPolicyCopy = new IsilonSyncPolicy8Above(); replicationPolicyCopy = replicationPolicyCopy.copy(replicationPolicy); if (filePolicy.getPriority() != null) { replicationPolicyCopy.setPriority(FilePolicyPriority.valueOf(filePolicy.getPriority()).ordinal()); } scheduleId = isi.createReplicationPolicy8above(replicationPolicyCopy); } else { scheduleId = isi.createReplicationPolicy(replicationPolicy); } FileOrchestrationUtils.updatePolicyStorageResource(_dbClient, storageObj, filePolicy, sourceSystemArgs, sourcePath, syncPolicyName, targetStorage, targetSystemArgs.getvNAS(), targetPath); return scheduleId; } catch (IsilonException e) { throw e; } } private boolean isValidTargetHostOnExistingPolicy(String existingPolicyTargetHost, StorageSystem system) { if (existingPolicyTargetHost != null && !existingPolicyTargetHost.isEmpty()) { // target cluster IP address is matching???? if (existingPolicyTargetHost.equalsIgnoreCase(system.getIpAddress())) { return true; } IsilonApi isi = getIsilonDevice(system); String targetClusterName = isi.getClusterConfig().getName(); // target cluster name is matching???? if (existingPolicyTargetHost.equalsIgnoreCase(targetClusterName)) { return true; } // target cluster smart connect zone is matching??? for (com.emc.storageos.db.client.model.StoragePort port : FileOrchestrationUtils .getStorageSystemPorts(_dbClient, system)) { if (existingPolicyTargetHost.equalsIgnoreCase(port.getPortName())) { return true; } else if (existingPolicyTargetHost.equalsIgnoreCase(port.getPortNetworkId())) { return true; } } } return false; } private boolean validateIsilonReplicationPolicy(IsilonSyncPolicy isiMatchedPolicy, FilePolicy filePolicy, String targetPath, StorageSystem targetSystem, StorageSystem sourceSystem) { _log.info("Comparing filepolicy: {} with SyncIQ policy: {}", filePolicy.getFilePolicyName(), isiMatchedPolicy.getName()); if (isiMatchedPolicy != null) { // replication type validation if (!isiMatchedPolicy.getAction().equals(IsilonSyncPolicy.Action.sync)) { _log.error("Isilon policy replication type is not valid: {}", isiMatchedPolicy.getAction().name()); return false; } // Verify the remote/local cluster if (filePolicy.getFileReplicationType().equalsIgnoreCase(FilePolicy.FileReplicationType.REMOTE.name())) { if (!isValidTargetHostOnExistingPolicy(isiMatchedPolicy.getTargetHost(), targetSystem)) { _log.error("Target host is not matching for REMOTE replication."); return false; } } else { if (!isValidTargetHostOnExistingPolicy(isiMatchedPolicy.getTargetHost(), sourceSystem)) { _log.error("Target host is not matching for LOCAL replication."); return false; } } // schedule validation String viprSchedule = getIsilonPolicySchedule(filePolicy); String isiSchedule = StringUtils.substringBefore(isiMatchedPolicy.getSchedule(), " between"); if (!viprSchedule.equalsIgnoreCase(isiSchedule)) { _log.error("File policy schedule: {} is different compared to isilon SyncIQ schedule: {}", viprSchedule, isiSchedule); return false; } // target path validation if (!isiMatchedPolicy.getTargetPath().equals(targetPath)) { _log.error("Target path: {} is different compared to SyncIQ policy path: {}", targetPath, isiMatchedPolicy); return false; } } return true; } private static IsilonSyncPolicy checkForReplicationPolicyOnIsilon(ArrayList<IsilonSyncPolicy> isiPolicies, FilePolicy filePolicy, String sourceRootPath, String targetPath) { IsilonSyncPolicy isiMatchedPolicy = null; for (IsilonSyncPolicy isiPolicy : isiPolicies) { if (isiPolicy.getSourceRootPath().equals(sourceRootPath) && isiPolicy.getTargetPath().equals(targetPath)) { isiMatchedPolicy = isiPolicy; break; } } return isiMatchedPolicy; } private String getFilePolicyPath(StorageSystem storageObj, FileDeviceInputOutput args) { String customPath = getCustomPath(storageObj, args); String filePolicyBasePath = null; VirtualNAS vNAS = args.getvNAS(); if (vNAS != null) { String vNASPath = vNAS.getBaseDirPath(); if (vNASPath != null && !vNASPath.trim().isEmpty()) { filePolicyBasePath = vNASPath + FW_SLASH + customPath; } else { filePolicyBasePath = IFS_ROOT + FW_SLASH + getSystemAccessZoneNamespace() + FW_SLASH + customPath; } } else { filePolicyBasePath = IFS_ROOT + FW_SLASH + getSystemAccessZoneNamespace() + FW_SLASH + customPath; } filePolicyBasePath = filePolicyBasePath.replaceAll("/+", "/").replaceAll("/$", ""); _log.info("Computed file policy path: {}", filePolicyBasePath); return filePolicyBasePath; } private void checkAppliedResourceNamePartOfFilePolicyPath(String filePolicyBasePath, FilePolicy filePolicy, FileDeviceInputOutput args) { FilePolicyApplyLevel appliedAt = FilePolicyApplyLevel.valueOf(filePolicy.getApplyAt()); String resourceName = null; switch (appliedAt) { case project: if (args.getProject() != null) { resourceName = args.getProjectNameWithNoSpecialCharacters().replaceAll("_", ""); if (!filePolicyBasePath.contains(resourceName)) { _log.error("File policy base path does not contain project: {}", resourceName); throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "File policy base path does not contain project: " + resourceName); } } else { throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "No project was provided in the input."); } break; case vpool: if (args.getVPool() != null) { resourceName = args.getVPoolNameWithNoSpecialCharacters().replaceAll("_", ""); if (!filePolicyBasePath.contains(resourceName)) { _log.error("File policy base path does not contain vpool: {}", resourceName); throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "File policy base path does not contain vpool: " + resourceName); } } else { throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "No vpool was provided in the input."); } break; case file_system: if (args.getFs() != null) { resourceName = args.getFsLabel(); if (!filePolicyBasePath.contains(resourceName)) { _log.error("File policy base path does not contain fileshare: {}", resourceName); throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "File policy base path does not contain fileshare: " + resourceName); } } else { throw DeviceControllerException.exceptions.assignFilePolicyFailed(filePolicy.getFilePolicyName(), filePolicy.getApplyAt(), "No fileshare was provided in the input."); } break; default: break; } } public static FilePolicy getReplicationPolicyAppliedOnFS(FileShare fs, DbClient dbClient) { StringSet existingFSPolicies = fs.getFilePolicies(); List<URI> existingFSPolicyURIs = new ArrayList<>(); for (String filePolicyURI : existingFSPolicies) { existingFSPolicyURIs.add(URI.create(filePolicyURI)); } Iterator<FilePolicy> iterator = dbClient.queryIterativeObjects(FilePolicy.class, existingFSPolicyURIs, true); while (iterator.hasNext()) { FilePolicy fp = iterator.next(); if (fp.getFilePolicyType().equals(FilePolicy.FilePolicyType.file_replication.name())) { _log.info("Found replication policy :{} applied to the file system: {}.", fp.toString(), fs.getId()); return fp; } } return null; } public static PolicyStorageResource getEquivalentPolicyStorageResource(FileShare fs, DbClient dbClient) { FilePolicy fp = getReplicationPolicyAppliedOnFS(fs, dbClient); if (fp != null) { StringSet policyStrResources = fp.getPolicyStorageResources(); List<URI> policyStrURIs = new ArrayList<>(); for (String policyStrResource : policyStrResources) { policyStrURIs.add(URI.create(policyStrResource)); } Iterator<PolicyStorageResource> iterator = dbClient.queryIterativeObjects(PolicyStorageResource.class, policyStrURIs, true); while (iterator.hasNext()) { PolicyStorageResource policyRes = iterator.next(); if (policyRes.getAppliedAt().equals(fs.getId()) && policyRes.getStorageSystem().equals(fs.getStorageDevice())) { _log.info("Found replication policy:{} corresponding storage resource: {} applied to the file system: {}.", fp.getLabel(), policyRes.toString(), fs.getId()); return policyRes; } } } return null; } @Override public BiosCommandResult checkFilePolicyPathHasResourceLabel(StorageSystem system, FileDeviceInputOutput args) { _log.info("Inside checkFilePolicyPathHasResourceLabel()"); try { FilePolicy filePolicy = args.getFileProtectionPolicy(); String filePolicyBasePath = getFilePolicyPath(system, args); checkAppliedResourceNamePartOfFilePolicyPath(filePolicyBasePath, filePolicy, args); _log.info("checkFilePolicyPathHasResourceLabel successful."); return BiosCommandResult.createSuccessfulResult(); } catch (IsilonException e) { _log.error("checkFilePolicyPathHasResourceLabel failed.", e); return BiosCommandResult.createErrorResult(e); } } }