/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.plugins.provisioning; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.nas.vnxfile.xmlapi.Checkpoint; import com.emc.nas.vnxfile.xmlapi.TreeQuota; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.constraint.ContainmentConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.FSExportMap; import com.emc.storageos.db.client.model.FileExport; import com.emc.storageos.db.client.model.FileObject; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.QuotaDirectory; import com.emc.storageos.db.client.model.SMBFileShare; import com.emc.storageos.db.client.model.SMBShareMap; import com.emc.storageos.db.client.model.Snapshot; import com.emc.storageos.db.client.model.StorageHADomain; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.plugins.common.domainmodel.Namespace; import com.emc.storageos.plugins.common.domainmodel.NamespaceList; import com.emc.storageos.plugins.metering.vnxfile.VNXFileConstants; import com.emc.storageos.vnx.xmlapi.VNXCifsServer; import com.emc.storageos.vnx.xmlapi.VNXException; import com.emc.storageos.vnx.xmlapi.VNXFileExport; import com.emc.storageos.vnx.xmlapi.VNXFileSshApi; import com.emc.storageos.vnx.xmlapi.VNXFileSystem; import com.emc.storageos.vnx.xmlapi.VNXQuotaTree; import com.emc.storageos.vnx.xmlapi.VNXSnapshot; import com.emc.storageos.vnx.xmlapi.XMLApiResult; import com.emc.storageos.volumecontroller.FileDeviceInputOutput; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.plugins.metering.vnxfile.VNXFileDiscExecutor; /** * VNXFileCommApi is responsible for communicating with the VNX File Control Station to perform * provisioning. */ public class VNXFileCommApi { private static final Logger _log = LoggerFactory.getLogger(VNXFileCommApi.class); private static final String PROV_FSCR_FILE = "vnxfile-prov-file"; private static final String PROV_FSDEL_FILE = "vnxfile-prov-del-file"; private static final String PROV_FS_FORCE_DEL_FILE = "vnxfile-prov-force-del-file"; private static final String PROV_CREATE_SNAP = "vnxfile-prov-cr-snap"; private static final String PROV_FILE_EXPORT = "vnxfile-prov-file-export"; private static final String PROV_FILE_EXPORT_MOUNT = "vnxfile-prov-file-export-mount"; private static final String PROV_DELETE_SNAP = "vnxfile-prov-delete-snap"; private static final String PROV_FILE_UNEXPORT = "vnxfile-prov-file-unexport"; private static final String PROV_FILE_UNEXPORT_UNMOUNT = "vnxfile-prov-file-unexport-unmount"; private static final String PROV_FILE_EXPAND = "vnxfile-prov-file-expand"; private static final String PROV_FILE_DELSHARE = "vnxfile-prov-file-delshare"; private static final String PROV_FILE_MOUNT_EXPAND = "vnxfile-prov-file-mount-expand"; private static final String PROV_SNAP_RESTORE = "vnxfile-prov-snap-restore"; private static final String PROV_FSIDQUERY_FILE = "vnxfile-prov-filesysid-query"; private static final String PROV_FSIDQUERY_FILE_DELETE = "vnxfile-prov-filesysid-delete-query"; private static final String PROV_CIFS_SERVERS = "vnxfile-prov-cifsserver-query"; private static final String PROV_FILE_QUOTA_DIR_CREATE = "vnxfile-prov-quota-dir-create"; private static final String PROV_FILE_QUOTA_DIR_MODIFY = "vnxfile-prov-quota-dir-modify"; private static final String PROV_FILE_QUOTA_DIR_DELETE = "vnxfile-prov-quota-dir-delete"; private static final String PROV_FILE_QUOTA_DIR_CREATE_MOUNT = "vnxfile-prov-mount-quota-dir-create"; private static final String PROV_FILE_QUOTA_DIR_MODIFY_MOUNT = "vnxfile-prov-mount-quota-dir-modify"; private static final String PROV_FILE_QUOTA_DIR_DELETE_MOUNT = "vnxfile-prov-mount-quota-dir-delete"; public static final String WORM_ATTRIBUTE = "WORM"; public static final String WORM_DEF = "off"; public static final String AUTO_EXTEND_ENABLED_ATTRIBUTE = "AutoExtendEnabled"; public static final String AUTO_EXTEND_ENABLED_DEF = "false"; public static final String AUTO_EXTEND_HWM_ATTRIBUTE = "AutoExtendHWM"; public static final String AUTO_EXTEND_MAX_SIZE_ATTRIBUTE = "AutoExtendMaxSize"; public static final String AUTO_EXTEND_HWM_DEF = "90"; public static final String FILE_SYSTEM_TYPE_ATTRIBUTE = "FileSystemType"; public static final String FILE_SYSTEM_TYPE_DEF = "uxfs"; public static final String THIN_PROVISIONED_ATTRIBUTE = "ThinProvisioned"; public static final String THIN_PROVISIONED_DEF = "false"; public static final String THIN_PROVISIONED_FS_SIZE_MB = "1024"; private static final String SERVER_URI = "/servlets/CelerraManagementServices"; private VNXFileDiscExecutor _provExecutor; private NamespaceList _provNamespaces; private DbClient _dbClient; private String _thinFsAllocPercentage; public DbClient getDbClient() { return _dbClient; } public void setDbClient(DbClient dbClient) { _dbClient = dbClient; } public String getThinFsAllocPercentage() { return _thinFsAllocPercentage; } public void setThinFsAllocPercentage(String thinFsAllocPercentage) { _thinFsAllocPercentage = thinFsAllocPercentage; } private final VNXFileSshApi sshApi = new VNXFileSshApi(); public VNXFileCommApi() { } public XMLApiResult createFileSystem(final StorageSystem system, final String fileSys, final String pool, final String dataMover, final Long size, final boolean virtualProvisioning, final String nativeFsId, final Map autoAtts) throws VNXException { _log.info("Create VNX File System: {} on data mover {}", fileSys, dataMover); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fileSys); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, "/" + fileSys); reqAttributeMap.put(VNXFileConstants.POOL_NAME, pool); reqAttributeMap.put(VNXFileConstants.FS_INIT_SIZE, size); reqAttributeMap.put(VNXFileConstants.MOVER_ID, dataMover); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_VIRTUAL_PROVISIONING, virtualProvisioning); _provExecutor.setKeyMap(reqAttributeMap); String cmdResult = VNXFileConstants.CMD_SUCCESS; // CHeck for FSId provided // If provided query the array for the FSId in use // If in use error out // if not in use create the FS thin or thick Boolean foundFSwithId = false; if (null != nativeFsId && !nativeFsId.isEmpty()) { String fileSysId = nativeFsId; _log.info("Query file system query with id {}.", fileSysId); _provExecutor.getKeyMap().put(VNXFileConstants.FILESYSTEM_ID, fileSysId); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FSIDQUERY_FILE)); cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { fileSysId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FILESYSTEM_ID); foundFSwithId = (Boolean) _provExecutor.getKeyMap().get(VNXFileConstants.IS_FILESYSTEM_AVAILABLE_ON_ARRAY); } if (foundFSwithId) { _log.info("There is a FileSystem exist with the id {} so fail the create.", fileSysId); result.setCommandFailed(); result.setMessage("File System creation failed because a File System with exist with id " + nativeFsId); return result; } else { _log.info("There is no FileSystem with the id {} so proceed with create.", fileSysId); } } else { _log.info("FileSystem Id provided is null or empty so we will use system generated id"); } // calculate the thin fs allocation size String thinProvFsSizeMBs = THIN_PROVISIONED_FS_SIZE_MB; if (virtualProvisioning) { thinProvFsSizeMBs = getThinFSAllocSize(size, true).toString(); } // FileSystem doesnt exist on the array, so now create it sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); String createFSCmd = sshApi.formatCreateFS(fileSys, FILE_SYSTEM_TYPE_DEF, thinProvFsSizeMBs, size.toString(), pool, "", virtualProvisioning, nativeFsId); _log.info("parsed createFSCmd {}.", createFSCmd); result = sshApi.executeSshRetry(VNXFileSshApi.NAS_FS, createFSCmd); if (!result.isCommandSuccess()) { cmdResult = VNXFileConstants.CMD_FAILURE; } if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { String fileSysId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FILESYSTEM_ID); int fsId = 0; if (null == fileSysId || fileSysId.isEmpty()) { // Since there was no error but the file system id was not found, query for id again. _log.info("Second file system create query."); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FSIDQUERY_FILE)); cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { fileSysId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FILESYSTEM_ID); if (null != fileSysId && !fileSysId.isEmpty()) { fsId = Integer.parseInt(fileSysId); } } } else { fsId = Integer.parseInt(fileSysId); } if (0 < fsId) { _log.info("VNX File System create success! ID: {}", fsId); String fsType = (String) autoAtts.get(FILE_SYSTEM_TYPE_ATTRIBUTE); String worm = (String) autoAtts.get(WORM_ATTRIBUTE); VNXFileSystem newFs = new VNXFileSystem(fileSys, -1, pool, fsType, worm, dataMover, Long.toString(size), autoAtts); result.setCommandSuccess(); newFs.setFsId(fsId); result.setObject(newFs); } else { result.setCommandFailed(); result.setMessage("File System creation failed"); } } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw VNXException.exceptions.createFileSystemFailed(e.getMessage()); } return result; } public boolean checkFileSystemExists(StorageSystem system, String fileId, String fileSys) throws VNXException { Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); boolean isFsAvailable = true; try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fileSys); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_ID, fileId); _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FSIDQUERY_FILE)); String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (null != cmdResult && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { isFsAvailable = (Boolean) _provExecutor.getKeyMap().get(VNXFileConstants.IS_FILESYSTEM_AVAILABLE_ON_ARRAY); } } catch (Exception e) { throw VNXException.exceptions.communicationFailed(e.getMessage()); } return isFsAvailable; } public XMLApiResult createSnapshot(final StorageSystem system, final String fsName, final String snapshotName, final FileShare fileShare) throws VNXException { _log.info("Create Snap for file sys : {} snap name : {}", fsName, snapshotName); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { // get the data mover StorageHADomain dataMover = this.getDataMover(fileShare); if (null != dataMover) { sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); Map<String, String> existingMounts = sshApi.getFsMountpathMap(dataMover.getAdapterName()); if (existingMounts.get(fileShare.getName()) == null) { String mountCmdArgs = sshApi.formatMountCmd(dataMover.getAdapterName(), fileShare.getName(), fileShare.getMountPath()); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_MOUNT_CMD, mountCmdArgs); _log.info("filesystem mount is successful for filesystem: {} mount path: {}", fileShare.getName(), fileShare.getMountPath()); } } else { Exception e = new Exception( "VNX File snapshot creation failed because suitable Data mover to mount the File System not found"); throw VNXException.exceptions.createExportFailed("VNX File Snapshot create is Failed", e); } updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fsName); reqAttributeMap.put(VNXFileConstants.SNAPSHOT_NAME, snapshotName); _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_CREATE_SNAP)); String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult != null && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { String snapId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.SNAPSHOT_ID); String fsysId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FILESYSTEM_ID); if (snapId != null) { int fsId = Integer.parseInt(fsysId); int snId = Integer.parseInt(snapId); VNXSnapshot vnxSnap = new VNXSnapshot(snapshotName, -1, fsId); vnxSnap.setId(snId); result.setObject(vnxSnap); result.setCommandSuccess(); } else { result.setCommandFailed(); result.setMessage((String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_MSG)); } } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_MSG); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("Failure", e); } return result; } public XMLApiResult createQuotaDirectory(final StorageSystem system, final String fsName, final String quotaDirName, final String securityStyle, final Long size, final Boolean oplocks, Boolean isMountRequired) throws VNXException { _log.info("Create VNX File System Quota dir: {} on file system {}", quotaDirName, fsName); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fsName); reqAttributeMap.put(VNXFileConstants.QUOTA_DIR_NAME, quotaDirName); reqAttributeMap.put(VNXFileConstants.HARD_QUOTA, size); reqAttributeMap.put(VNXFileConstants.SECURITY_STYLE, securityStyle); reqAttributeMap.put(VNXFileConstants.OPLOCKS, oplocks); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, "/" + fsName); _provExecutor.setKeyMap(reqAttributeMap); if (isMountRequired) { _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_QUOTA_DIR_CREATE_MOUNT)); } else { _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_QUOTA_DIR_CREATE)); } String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult != null && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { String quotaDirId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.QUOTA_DIR_ID); String fsysId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FILESYSTEM_ID); if (quotaDirId != null) { int fsId = Integer.parseInt(fsysId); int qdId = Integer.parseInt(quotaDirId); VNXQuotaTree vnxQuotaTree = new VNXQuotaTree(quotaDirName, -1, fsId); vnxQuotaTree.setId(qdId); result.setObject(vnxQuotaTree); result.setCommandSuccess(); } else { result.setCommandFailed(); result.setMessage((String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC)); } } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("Failure", e); } return result; } public XMLApiResult modifyQuotaDirectory(final StorageSystem system, final String fsName, final String quotaDirName, final String securityStyle, final Long size, final Boolean oplocks, Boolean isMountRequired) throws VNXException { _log.info("Modify VNX File System Quota dir: {} on file system {}", quotaDirName, fsName); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fsName); reqAttributeMap.put(VNXFileConstants.QUOTA_DIR_NAME, quotaDirName); reqAttributeMap.put(VNXFileConstants.HARD_QUOTA, size); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, "/" + fsName); reqAttributeMap.put(VNXFileConstants.SECURITY_STYLE, securityStyle); reqAttributeMap.put(VNXFileConstants.OPLOCKS, oplocks); _provExecutor.setKeyMap(reqAttributeMap); if (isMountRequired) { _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_QUOTA_DIR_MODIFY_MOUNT)); } else { _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_QUOTA_DIR_MODIFY)); } String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult != null && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { String quotaDirId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.QUOTA_DIR_ID); String fsysId = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FILESYSTEM_ID); if (quotaDirId != null) { int fsId = Integer.parseInt(fsysId); int qdId = Integer.parseInt(quotaDirId); VNXQuotaTree vnxQuotaTree = new VNXQuotaTree(quotaDirName, -1, fsId); vnxQuotaTree.setId(qdId); result.setObject(vnxQuotaTree); result.setCommandSuccess(); } else { result.setCommandFailed(); result.setMessage((String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC)); } } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("Failure", e); } return result; } public XMLApiResult deleteQuotaDirectory(final StorageSystem system, final String fsName, final String quotaDirName, final Boolean forceDelete, Boolean isMountRequired) throws VNXException { _log.info("Delete VNX File System Quota dir: {} on file system {}", quotaDirName, fsName); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fsName); reqAttributeMap.put(VNXFileConstants.QUOTA_DIR_NAME, quotaDirName); reqAttributeMap.put(VNXFileConstants.QTREE_FORCE_DELETE, forceDelete); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, "/" + fsName); _provExecutor.setKeyMap(reqAttributeMap); if (isMountRequired) { _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_QUOTA_DIR_DELETE_MOUNT)); } else { _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_QUOTA_DIR_DELETE)); } String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult != null && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { result.setCommandSuccess(); } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("Failure", e); } return result; } public XMLApiResult deleteFileSystem(final StorageSystem system, final String fileId, final String fileSys, final boolean isForceDelete, FileShare fs) throws VNXException { _log.info("Delete VNX File System: fs id {}, Force Delete {}", fileId, isForceDelete); XMLApiResult result = new XMLApiResult(); if (null == fileId || null == fileSys || fileId.trim().equals("") || fileSys.trim().equals("")) { result.setCommandFailed(); result.setMessage("Invalid Input Parameters."); return result; } Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fileSys); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_ID, fileId); _provExecutor.setKeyMap(reqAttributeMap); // Before deleting check whether it is available or not on the array - This need to be done as part of // deleting un-managed FS. _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FSIDQUERY_FILE_DELETE)); boolean isFsAvailable = false; _log.debug("Listing VNX File File Systems"); String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (null != cmdResult && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { isFsAvailable = (Boolean) _provExecutor.getKeyMap().get(VNXFileConstants.IS_FILESYSTEM_AVAILABLE_ON_ARRAY); } if (!isFsAvailable) { _log.debug("File System **Not found on array which requested to delete."); result.setCommandSuccess(); // No need to set Inactive and persist here as this will be done in upper layer(FileDeviceController) } if (isForceDelete) { // handle snapshots _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FS_FORCE_DEL_FILE)); cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); StorageHADomain dataMover = getDataMover(fs); if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { List<Checkpoint> snaps = (List<Checkpoint>) _provExecutor.getKeyMap().get(VNXFileConstants.SNAPSHOTS_LIST); int numSnapshots = (snaps != null) ? snaps.size() : 0; _log.info("Number of Snapshots found {} for a file system {}", numSnapshots, fileId); if (snaps != null && !snaps.isEmpty()) { for (Checkpoint checkpoint : snaps) { _log.info("Deleting Snapshot having name {} - and id {}", checkpoint.getName(), checkpoint.getCheckpoint()); String nativeGuid = NativeGUIDGenerator.getNativeGuidforSnapshot(system, system.getSerialNumber(), checkpoint.getCheckpoint()); _log.info("NativeGuid {} built for snapshot {}", nativeGuid, checkpoint.getCheckpoint()); Snapshot snapshot = null; List<URI> snapShotUris = _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getSnapshotNativeGuidConstraint(nativeGuid)); _log.info("{} Snapshots found with native guid : {} ", snapShotUris.size(), nativeGuid); if (!snapShotUris.isEmpty()) { _log.info("Retriving Snapshot using URI : {} ", snapShotUris.get(0)); snapshot = _dbClient.queryObject(Snapshot.class, snapShotUris.get(0)); } if (snapshot != null) { result = deleteAllExportsAndShares(system, dataMover, fs, snapshot); XMLApiResult status = doDeleteSnapshot(system, checkpoint.getCheckpoint(), checkpoint.getName(), false); if (!status.isCommandSuccess()) { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); return result; } } } } // Delete All Quota directories of FileShare. result = deleteAllQuotaDirs(system, dataMover, fs); // Delete Exports/SMB Shares of FileShare result = deleteAllExportsAndShares(system, dataMover, fs, null); } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); return result; } } if (isFsAvailable) { _log.debug("File System found on array which requested to delete. Now, deleting on Array."); // First unmount it StorageHADomain dataMover = getDataMover(fs); if (dataMover != null) { Map<String, String> existingMounts = sshApi.getFsMountpathMap(dataMover.getAdapterName()); // is FS mount still exists? if (existingMounts.get(fs.getName()) != null) { // The File system is mounted and we need to unmount it before deleting it String unMountCmd = sshApi.formatUnMountCmd(dataMover.getAdapterName(), fs.getMountPath(), "NFS"); _log.info("Unmount FS {}", unMountCmd); sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, unMountCmd); } } else { _log.info("No need to Unmount FS {} since there is no mount info", fs.getMountPath()); } _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FSDEL_FILE)); cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (null != cmdResult && cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { result.setCommandSuccess(); } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } } catch (Exception e) { throw new VNXException("File system delete exception: ", e); } return result; } private XMLApiResult deleteAllQuotaDirs(StorageSystem system, StorageHADomain dataMover, FileShare fs) { XMLApiResult result = new XMLApiResult(); result.setCommandSuccess(); _log.info("deleteAllQuotaDirs for {}", fs.getName()); try { // Process for quota dir delete on this file share. List<TreeQuota> quotaDirs = (List<TreeQuota>) _provExecutor.getKeyMap().get(VNXFileConstants.QUOTA_DIR_LIST); if (quotaDirs != null && !quotaDirs.isEmpty() && dataMover != null) { _log.info("Number of quota dirs found {} for a file system {}", quotaDirs.size(), fs.getName()); // In the process of delete file system, we are unmounting the FileSystem. // In order to delete Quota Directory, file system should be mounted. // we just mount the file system temporarily. if it was un-mounted. sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); Map<String, String> existingMounts = sshApi.getFsMountpathMap(dataMover.getAdapterName()); if (existingMounts.get(fs.getName()) == null) { String mountCmdArgs = sshApi.formatMountCmd(dataMover.getAdapterName(), fs.getName(), fs.getMountPath()); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_MOUNT_CMD, mountCmdArgs); } for (TreeQuota quota : quotaDirs) { if (quota != null) { String quotaDirName = quota.getPath().substring(1); // exclude the "/" in the beginning of the // path. XMLApiResult status = deleteQuotaDirectory(system, fs.getName(), quotaDirName, true, false); if (!status.isCommandSuccess()) { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); return result; } } } } return result; } catch (Exception e) { throw new VNXException("File system quota directory delete exception: ", e); } } private XMLApiResult deleteAllExportsAndShares(StorageSystem system, StorageHADomain dataMover, FileShare fs, Snapshot snapshot) { FSExportMap exports; SMBShareMap shares; XMLApiResult result = new XMLApiResult(); result.setCommandSuccess(); String fileId = fs.getId().toString(); FileObject fObj = fs; _log.info("deleteAllExportsAndShares for {} {}", fs.getName(), snapshot); boolean fileOperation = false; if (snapshot == null) { // FileShare operation _log.info("deleteAllExportsAndShares FileShare delete operation"); exports = fs.getFsExports(); shares = fs.getSMBFileShares(); fileOperation = true; fObj = fs; } else { _log.info("deleteAllExportsAndShares Snapshot delete operation"); exports = snapshot.getFsExports(); shares = snapshot.getSMBFileShares(); fObj = snapshot; fileId = snapshot.getId().toString(); } int exportsToUnExport = 0; Set<String> keys = new HashSet(); if (exports != null) { exportsToUnExport = exports.size(); keys = exports.keySet(); } int noOfShares = 0; if (shares != null) { noOfShares = shares.size(); } _log.info("Number of NFS exports {} SMB Shares found {} for File/Snapshot Id {}", new Object[] { exportsToUnExport, noOfShares, fileId }); // To avoid concurrent modification exceptions Set<String> exportKeys = new HashSet(); exportKeys.addAll(keys); FileDeviceInputOutput args = new FileDeviceInputOutput(); args.setFileOperation(fileOperation); args.addFSFileObject(fs); if (fileOperation) { args.setFileOperation(true); args.addFSFileObject(fs); } else { args.setFileOperation(false); args.addFSFileObject(fs); args.addSnapshot(snapshot); } for (String key : exportKeys) { FileExport exp = exports.get(key); VNXFileExport fileExport = new VNXFileExport(exp.getClients(), exp.getStoragePortName(), exp.getPath(), exp.getSecurityType(), exp.getPermissions(), exp.getRootUserMapping(), exp.getProtocol(), exp.getStoragePort(), exp.getSubDirectory(), exp.getComments()); fileExport.setStoragePort(fs.getStoragePort().toString()); boolean deleteMount = false; if (exportsToUnExport == 1 && noOfShares == 0 && fileOperation) { deleteMount = true; } XMLApiResult status = doUnexport(system, fileExport, args, deleteMount); if (!status.isCommandSuccess()) { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); return result; } else { fObj.getFsExports().remove(key); _log.info("Export removed : " + key); exportsToUnExport--; } // Persist the object after exports removed _dbClient.persistObject(fObj); } // Now Let Handle SMB/CIFS Shares keys = new HashSet<>(); int noOfSharesToDelete = 0; if (shares != null) { keys = shares.keySet(); noOfSharesToDelete = keys.size(); } int noOfExports = 0; if (exports != null) { noOfExports = exports.size(); } _log.info("Number of CIFS/SMB Shares {} NFS Exports found {} for File/Snapshot Id {}", new Object[] { noOfSharesToDelete, noOfExports, fileId }); // To avoid concurrent modification exceptions Set<String> shareKeys = new HashSet(); shareKeys.addAll(keys); for (String key : shareKeys) { SMBFileShare share = shares.get(key); _log.info("Delete SMB/CIFS Share {} from FS/Snapshot {}", share.getName(), fileId); boolean deleteMount = false; if (noOfSharesToDelete == 1 && noOfExports == 0 && fileOperation) { deleteMount = true; } XMLApiResult status = doDeleteShare(system, dataMover, share.getName(), fs.getMountPath(), deleteMount, args); if (!status.isCommandSuccess()) { _log.info("SMBFileShare deletion failed key {} : {} ", key, share.getName()); String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); return result; } else { fObj.getSMBFileShares().remove(key); _log.info("SMBFileShare removed : " + key); noOfSharesToDelete--; } // Persist the object after SMBShares removed _dbClient.persistObject(fObj); } return result; } /** * Performs an export for a VNX File array. If this is the first export of a file system path, * then the path must be mounted on a data mover first. Also, if the root user mapping contains a * user account name, then it must be converted into a UID. * * @param system * @param exports * @param fsName * @param fsId * @param firstExport * @return * @throws VNXException */ public XMLApiResult doExport(final StorageSystem system, StorageHADomain dataMover, List<VNXFileExport> exports, List<String> newPaths, FileObject fileObject, String fsId, boolean firstExport) throws VNXException { VNXFileExport vnxExp = exports.get(0); String port = vnxExp.getStoragePortName(); String storagePortNetworkId = vnxExp.getStoragePort(); _log.info("Export for {}, data mover {}", fileObject.getLabel(), port + ":" + storagePortNetworkId); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); FileShare fs = null; if (fileObject instanceof FileShare) { fs = _dbClient.queryObject(FileShare.class, fileObject.getId()); } String moverOrVdmId = ""; String moverOrVdmName = ""; String parentDMName = ""; String isVdm = "false"; try { if (null == dataMover) { result.setCommandFailed(); result.setMessage("Export failed: data mover or vdm not found."); return result; } moverOrVdmId = dataMover.getName(); moverOrVdmName = dataMover.getAdapterName(); if (dataMover.getVirtual() != null && dataMover.getVirtual() == true) { isVdm = "true"; parentDMName = getParentMoverName(dataMover.getParentHADomainURI()); } sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); Map<String, String> userInfo = sshApi.getUserInfo(parentDMName); _log.info("Using Mover {} to export FS mounted at {}", moverOrVdmId + ":" + moverOrVdmName, exports.get(0).getMountPoint()); updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.DATAMOVER_ID, port); reqAttributeMap.put(VNXFileConstants.MOVER_ID, moverOrVdmId); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_ID, fsId); reqAttributeMap.put(VNXFileConstants.DATAMOVER_NAME, moverOrVdmName); reqAttributeMap.put(VNXFileConstants.ISVDM, isVdm); if (vnxExp.getComment() != null && !vnxExp.getComment().isEmpty()) { reqAttributeMap.put(VNXFileConstants.TASK_DESCRIPTION, vnxExp.getComment()); } Set<String> moverIds = new HashSet<String>(); moverIds.add(port); reqAttributeMap.put(VNXFileConstants.MOVERLIST, moverIds); _provExecutor.setKeyMap(reqAttributeMap); if (firstExport) { reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, fs.getMountPath()); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_EXPORT_MOUNT)); } else { reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, vnxExp.getMountPoint()); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_FILE_EXPORT)); } List<VNXCifsServer> cifsServers = (List<VNXCifsServer>) _provExecutor.getKeyMap().get(VNXFileConstants.CIFS_SERVERS); if (cifsServers == null || cifsServers.isEmpty()) { _log.info("No CIFS Servers retrieved for mover {} with id {}", moverOrVdmName, moverOrVdmId); } else { for (VNXCifsServer cifsServer : cifsServers) { _log.debug("CIFServer:" + cifsServer.toString()); } } // Format and issue separate ssh api commands for each new file system and subdirectory List<VNXFileExport> newExportEntries = new ArrayList<VNXFileExport>(); sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); for (String newPath : newPaths) { String netBios = null; // Only set netbios for VDM CIFS exports if (cifsServers != null && !cifsServers.isEmpty() && dataMover.getVirtual()) { netBios = cifsServers.get(0).getName(); } for (VNXFileExport export : exports) { if (export.getMountPoint().equals(newPath)) { export.setNetBios(netBios); newExportEntries.add(export); } } _log.info("Export info {} {}", moverOrVdmName, netBios); // Check for existance of share by name String shareNameCheckData = sshApi.formatCheckShareForExportCmd(moverOrVdmName, newExportEntries, userInfo, netBios); if (shareNameCheckData != null) { XMLApiResult shareNameCheckCommandResult = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, shareNameCheckData); if (shareNameCheckCommandResult.isCommandSuccess()) { _log.error("Export command failed for share name {}", newExportEntries.get(0).getExportName()); StringBuilder errorMessageBuilder = new StringBuilder(); errorMessageBuilder.append("Share by the name "); errorMessageBuilder.append(newExportEntries.get(0).getExportName()); errorMessageBuilder.append(" Already exists on server "); errorMessageBuilder.append(moverOrVdmName); result.setCommandFailed(); result.setMessage(errorMessageBuilder.toString()); return result; } } String data = sshApi.formatExportCmd(moverOrVdmName, newExportEntries, userInfo, netBios); _log.info("Export command {}", data); if (data != null) { result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); } if (!result.isCommandSuccess()) { if (firstExport) { data = sshApi.formatUnMountCmd(moverOrVdmName, fs.getMountPath(), "NFS"); XMLApiResult unmountResult = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, data); if (!unmountResult.isCommandSuccess()) { _log.warn("Unmounting the file system {} failed due to {}", fs.getId(), unmountResult.getMessage()); } else { _log.info("Unmounted the file system {} successfully", fs.getId()); } } return result; } newExportEntries.clear(); } sshApi.clearConnParams(); } catch (Exception e) { throw VNXException.exceptions.createExportFailed(result.getMessage(), e); } _log.info("doExport result: " + result.getMessage()); return result; } public XMLApiResult doDeleteExport(final StorageSystem system, String exportPath, FileDeviceInputOutput args, boolean deleteMount) { XMLApiResult result = new XMLApiResult(); result.setCommandSuccess(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); _log.info("Delete VNX Export : {}", exportPath); if (exportPath == null || (exportPath != null && exportPath.isEmpty())) { _log.info("Invalid Export Path"); return result; } try { updateAttributes(reqAttributeMap, system); String moverId; StorageHADomain dataMover = null; String mountPath = ""; if (args.getFileOperation()) { StoragePort storagePort = _dbClient.queryObject(StoragePort.class, args.getFs().getStoragePort()); URI dataMoverId = storagePort.getStorageHADomain(); dataMover = _dbClient.queryObject(StorageHADomain.class, dataMoverId); moverId = dataMover.getName(); mountPath = args.getFsMountPath(); _log.info("Using Mover Id {} to unexport FS mounted at {}", moverId, exportPath); // Delete export from storage system. sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); if (sshApi.getNFSExportsForPath(dataMover.getAdapterName(), exportPath).containsKey(exportPath)) { // Delete the Export. String data = sshApi.formatDeleteNfsExportCmd(dataMover.getAdapterName(), exportPath); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); } // umount root directory should once, again umount operation on same directory fails // we check for any exports and share exists and then run umount operation if (result.isCommandSuccess() && getVNXFSDependencies(args.getFs(), false) <= 1) { // Delete the mount String data = sshApi.formatUnMountCmd(dataMover.getAdapterName(), mountPath, "NFS"); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, data); } sshApi.clearConnParams(); } else { String isVdm = "false"; Snapshot snapshot = _dbClient.queryObject(Snapshot.class, args.getSnapshotId()); FileShare fileshare = _dbClient.queryObject(FileShare.class, snapshot.getParent().getURI()); StoragePort storagePort = _dbClient.queryObject(StoragePort.class, fileshare.getStoragePort()); URI dataMoverId = storagePort.getStorageHADomain(); dataMover = _dbClient.queryObject(StorageHADomain.class, dataMoverId); moverId = dataMover.getName(); _log.info("Using Mover Id {} to unexport FS mounted at {}", moverId, exportPath); if (dataMover.getVirtual()) { isVdm = "true"; } // Delete export from storage system. reqAttributeMap.put(VNXFileConstants.MOVER_ID, moverId); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, exportPath); reqAttributeMap.put(VNXFileConstants.ISVDM, isVdm); _provExecutor.setKeyMap(reqAttributeMap); sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); if (sshApi.getNFSExportsForPath(dataMover.getAdapterName(), exportPath).containsKey(exportPath)) { String data = sshApi.formatDeleteNfsExportCmd(dataMover.getAdapterName(), exportPath); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); } // Delete the Snapshot mount, only if No depending exports, shares for that snapshot. if (result.isCommandSuccess() && getVNXFSDependencies(args.getFs(), true) <= 1) { // Delete the mount String data = sshApi.formatUnMountCmd(dataMover.getAdapterName(), exportPath, "NFS"); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, data); } sshApi.clearConnParams(); } } catch (Exception e) { throw new VNXException("File Export Delete Exception: ", e); } return result; } public XMLApiResult doUnexport(final StorageSystem system, VNXFileExport fileExport, FileDeviceInputOutput args, boolean deleteMount) throws VNXException { _log.info("Unexport file sys mounted at : {}", fileExport.getMountPoint()); XMLApiResult result = new XMLApiResult(); result.setCommandSuccess(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); String moverId; StorageHADomain dataMover = null; if (args.getFileOperation()) { StoragePort storagePort = _dbClient.queryObject(StoragePort.class, args.getFs().getStoragePort()); URI dataMoverId = storagePort.getStorageHADomain(); dataMover = _dbClient.queryObject(StorageHADomain.class, dataMoverId); moverId = dataMover.getName(); String fsMountPath = args.getFsPath(); _log.info("Using Mover Id {} to unexport FS mounted at {}", moverId, fsMountPath); // Retrieve export object from the DB. If there are multiple "ro", // "rw", "root", and "access" endpoints, just remove this entry and update // export properties on the array and in the DB boolean thisEntryFound = false; boolean moreEntries = false; Set<String> keysToRemove = new HashSet<String>(); String exportEntryKey = FileExport.exportLookupKey(fileExport.getProtocol(), fileExport.getSecurityType(), fileExport.getPermissions(), fileExport.getRootUserMapping(), fileExport.getMountPoint()); FileExport export = args.getFileObjExports().get(exportEntryKey); if (export != null) { thisEntryFound = true; keysToRemove.add(exportEntryKey); } Set<String> keys = args.getFileObjExports().keySet(); for (String key : keys) { if ((fileExport.getMountPoint().equals(args.getFileObjExports().get(key).getPath())) && (!exportEntryKey.equalsIgnoreCase(key))) { moreEntries = true; break; } } for (String key : keysToRemove) { args.getFsExports().remove(key); } boolean deleteExportFromDevice = true; if ((!thisEntryFound) || (moreEntries)) { // Don't unexport, just update properties deleteExportFromDevice = false; } if (deleteExportFromDevice) { // Delete export from storage system. String mntPoint = fileExport.getMountPoint(); sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); if (sshApi.getNFSExportsForPath(dataMover.getAdapterName(), mntPoint).containsKey(mntPoint)) { String data = sshApi.formatDeleteNfsExportCmd(dataMover.getAdapterName(), mntPoint); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); } // As we already removed the export entry from Map, Check for any other dependents. if (result.isCommandSuccess() && getVNXFSDependencies(args.getFs(), false) < 1) { // Delete the mount String data = sshApi.formatUnMountCmd(dataMover.getAdapterName(), fsMountPath, "NFS"); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, data); } sshApi.clearConnParams(); } else { // Just update export properties. List<VNXFileExport> vnxExports = new ArrayList<VNXFileExport>(); keys = args.getFsExports().keySet(); for (String key : keys) { FileExport exp = args.getFileObjExports().get(key); VNXFileExport vnxExp = new VNXFileExport(exp.getClients(), exp.getStoragePortName(), exp.getPath(), exp.getSecurityType(), exp.getPermissions(), exp.getRootUserMapping(), exp.getProtocol(), exp.getStoragePort(), exp.getSubDirectory(), exp.getComments()); vnxExports.add(vnxExp); } sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); String data = sshApi.formatExportCmd(dataMover.getAdapterName(), vnxExports, null, null); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); sshApi.clearConnParams(); if (result.isCommandSuccess()) { result.setCommandSuccess(); } else { result.setCommandFailed(); } } } else { String isVdm = "false"; Snapshot snapshot = _dbClient.queryObject(Snapshot.class, args.getSnapshotId()); FileShare fileshare = _dbClient.queryObject(FileShare.class, snapshot.getParent().getURI()); StoragePort storagePort = _dbClient.queryObject(StoragePort.class, fileshare.getStoragePort()); URI dataMoverId = storagePort.getStorageHADomain(); dataMover = _dbClient.queryObject(StorageHADomain.class, dataMoverId); moverId = dataMover.getName(); _log.info("Using Mover Id {} to unexport FS mounted at {}", moverId, fileExport.getMountPoint()); if (dataMover.getVirtual()) { isVdm = "true"; } // Delete export from storage system. reqAttributeMap.put(VNXFileConstants.MOVER_ID, moverId); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, fileExport.getMountPoint()); reqAttributeMap.put(VNXFileConstants.ISVDM, isVdm); _provExecutor.setKeyMap(reqAttributeMap); sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); String mntPoint = fileExport.getMountPoint(); if (sshApi.getNFSExportsForPath(dataMover.getAdapterName(), mntPoint).containsKey(mntPoint)) { String data = sshApi.formatDeleteNfsExportCmd(dataMover.getAdapterName(), mntPoint); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); } if (result.isCommandSuccess() && getVNXFSDependencies(fileshare, true) <= 1) { // Delete the mount String data = sshApi.formatUnMountCmd(dataMover.getAdapterName(), fileExport.getMountPoint(), "NFS"); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, data); } sshApi.clearConnParams(); } } catch (Exception e) { throw new VNXException("File unexport exception: ", e); } return result; } /** * Delete a CIFS Share * * @param system * @param moverOrVdm * data mover the share is on. * @param shareName * name of the CIFS share. * @return result of the operation. */ public XMLApiResult doDeleteShare(StorageSystem system, StorageHADomain moverOrVdm, String shareName, String mountPoint, boolean deleteMount, FileDeviceInputOutput args) { _log.info("CommApi: delete share {}", shareName); XMLApiResult result = new XMLApiResult(); result.setCommandSuccess(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); if (null == moverOrVdm) { result.setCommandFailed(); result.setMessage("Export failed: data mover or VDM not found."); return result; } String moverOrVdmName = moverOrVdm.getAdapterName(); String isVdm = "false"; String moverOrVdmId = moverOrVdm.getName(); reqAttributeMap.put(VNXFileConstants.MOVER_ID, moverOrVdmId); reqAttributeMap.put(VNXFileConstants.ISVDM, isVdm); if (moverOrVdm.getVirtual() != null && moverOrVdm.getVirtual() == true) { isVdm = "true"; } _log.info("Using Mover {} to Delete share {}", moverOrVdmId + ":" + moverOrVdmName, shareName); updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.MOVER_ID, moverOrVdmId); reqAttributeMap.put(VNXFileConstants.DATAMOVER_NAME, moverOrVdmName); reqAttributeMap.put(VNXFileConstants.ISVDM, isVdm); _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get(PROV_CIFS_SERVERS)); List<VNXCifsServer> cifsServers = (List<VNXCifsServer>) _provExecutor.getKeyMap().get(VNXFileConstants.CIFS_SERVERS); for (VNXCifsServer cifsServer : cifsServers) { _log.info("CIFServer:" + cifsServer.toString()); } if (cifsServers == null || cifsServers.isEmpty()) { _log.info("No CIFS Servers retrieved for mover {} with id {}", moverOrVdmName, moverOrVdmId); } String netBios = null; // Only set netbios for VDM CIFS exports if (cifsServers != null && !cifsServers.isEmpty() && moverOrVdm.getVirtual()) { netBios = cifsServers.get(0).getName(); } sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); String data = sshApi.formatDeleteShareCmd(moverOrVdmName, shareName, netBios); _log.info("doDeleteShare command {}", data); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_EXPORT_CMD, data); FileShare fileShare = null; if (!args.getFileOperation()) { Snapshot snapshot = _dbClient.queryObject(Snapshot.class, args.getSnapshotId()); fileShare = _dbClient.queryObject(FileShare.class, snapshot.getParent().getURI()); } else { fileShare = _dbClient.queryObject(FileShare.class, args.getFileObjId()); } if (result.isCommandSuccess() && getVNXFSDependencies(fileShare, false) <= 1) { // FileSystem Mount Point // Delete the mount data = sshApi.formatUnMountCmd(moverOrVdmName, mountPoint, "CIFS"); _log.info("Unmount filesystem command {}", data); result = sshApi.executeSshRetry(VNXFileSshApi.SERVER_UNMOUNT_CMD, data); } sshApi.clearConnParams(); } catch (Exception e) { throw new VNXException("Failure", e); } return result; } /* * getThinFSAllocSize - calculate the allocation size for thin file system * based on the allocation percentage set in conf file. * and make sure the minimum allocation size to be 1024M or FS size, if fs size less than 1024M. */ private Long getThinFSAllocSize(Long fsSizeMBs, boolean considerMinAlloc) { Long allocPer = 10L; Long thinFsSizeMin = Long.parseLong(THIN_PROVISIONED_FS_SIZE_MB); Long allocSize = thinFsSizeMin; String allocPerStr = this.getThinFsAllocPercentage(); if (allocPerStr != null && !allocPerStr.isEmpty()) { _log.info("Allocation percentage from conf file {}", allocPerStr); allocPer = Long.parseLong(allocPerStr); } allocSize = (fsSizeMBs * allocPer) / 100; if (!considerMinAlloc) { _log.info("getThinFSAllocSize return allocation size {}", allocSize.toString()); return allocSize; } // allocation size less than 1GB or file size less than 1GB // set the allocation size accordingly!!! if (allocSize < thinFsSizeMin) { allocSize = thinFsSizeMin; if (allocSize > fsSizeMBs) { allocSize = fsSizeMBs; } } _log.info("getThinFSAllocSize return allocation size {}", allocSize.toString()); return allocSize; } private String getFSSize(final StorageSystem system, String fsName) { sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); String fsSizeInfo = sshApi.getFSSizeInfo(fsName); return fsSizeInfo; } /** * Get the export from the storage system based on the export path * * @param system storage system details * @param args FileDeviceInputOutput object with export path details * @return export map */ public Map<String, String> getNFSExport(StorageSystem system, FileDeviceInputOutput args) { sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); StoragePort storagePort = _dbClient.queryObject(StoragePort.class, args.getFs().getStoragePort()); String moverId; String exportPath = args.getExportPath(); StorageHADomain dataMover = null; URI dataMoverId = storagePort.getStorageHADomain(); dataMover = _dbClient.queryObject(StorageHADomain.class, dataMoverId); moverId = dataMover.getName(); _log.info("Getting Mover Id {} to list FS export at {}", moverId, exportPath); // get export from storage system. sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); Map<String, String> exportMap = sshApi.getNFSExportsForPath(dataMover.getAdapterName(), exportPath).get(exportPath); return exportMap; } public XMLApiResult expandFS(final StorageSystem system, String fsName, long extendSize, boolean isMountRequired, boolean isVirtualProvisioned) throws VNXException { _log.info("Expand File System {} : new size requested {}", fsName, extendSize); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); long fsSize = Long.parseLong(getFSSize(system, fsName)); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fsName); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_SIZE, extendSize); reqAttributeMap.put(VNXFileConstants.MOUNT_PATH, "/" + fsName); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_VIRTUAL_PROVISIONING, isVirtualProvisioned); reqAttributeMap.put(VNXFileConstants.ORIGINAL_FS_SIZE, fsSize); // calculate the thin fs allocation size Long thinProvFsSizeMBs = Long.parseLong(THIN_PROVISIONED_FS_SIZE_MB); if (isVirtualProvisioned) { thinProvFsSizeMBs = getThinFSAllocSize(extendSize, false); } reqAttributeMap.put(VNXFileConstants.THIN_FS_ALLOC_SIZE, thinProvFsSizeMBs); _provExecutor.setKeyMap(reqAttributeMap); if (isMountRequired) { _provExecutor.execute((Namespace) _provNamespaces.getNsList() .get(PROV_FILE_MOUNT_EXPAND)); } else { _provExecutor.execute((Namespace) _provNamespaces.getNsList() .get(PROV_FILE_EXPAND)); } String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { result.setCommandSuccess(); } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("File system expand exception: ", e); } return result; } public XMLApiResult expandFS(final StorageSystem system, final FileShare fileShare, long extendSize, boolean isMountRequired, boolean isVirtualProvisioned) throws VNXException { // get the data mover boolean isMounted = false; StorageHADomain dataMover = this.getDataMover(fileShare); if (null != dataMover) { sshApi.setConnParams(system.getIpAddress(), system.getUsername(), system.getPassword()); Map<String, String> existingMounts = sshApi.getFsMountpathMap(dataMover.getAdapterName()); if (existingMounts.get(fileShare.getName()) == null) { isMounted = true; } else { isMounted = false; } } _log.info("expandFS for fileName{} and isMountRequired {}", fileShare.getName(), String.valueOf(isMounted)); return expandFS(system, fileShare.getName(), extendSize, isMounted, isVirtualProvisioned); } public XMLApiResult doRestoreSnapshot(final StorageSystem system, String fsId, String fsName, String id, String snapshotName) throws VNXException { _log.info("Restore Snapshot name :{} : file system : {}", snapshotName, fsName); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_NAME, fsName); reqAttributeMap.put(VNXFileConstants.FILESYSTEM_ID, fsId); reqAttributeMap.put(VNXFileConstants.SNAPSHOT_NAME, snapshotName); reqAttributeMap.put(VNXFileConstants.SNAPSHOT_ID, id); _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList() .get(PROV_SNAP_RESTORE)); String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { result.setCommandSuccess(); } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("Failure", e); } return result; } public XMLApiResult doDeleteSnapshot(final StorageSystem system, final String snapId, String snapshotName, boolean deleteBaseline) throws VNXException { _log.info("Delete VNX Snapshot id : {}", snapId); XMLApiResult result = new XMLApiResult(); Map<String, Object> reqAttributeMap = new ConcurrentHashMap<String, Object>(); try { updateAttributes(reqAttributeMap, system); reqAttributeMap.put(VNXFileConstants.SNAPSHOT_NAME, snapshotName); reqAttributeMap.put(VNXFileConstants.SNAPSHOT_ID, snapId); _provExecutor.setKeyMap(reqAttributeMap); _provExecutor.execute((Namespace) _provNamespaces.getNsList().get( PROV_DELETE_SNAP)); String cmdResult = (String) _provExecutor.getKeyMap().get(VNXFileConstants.CMD_RESULT); if (cmdResult.equals(VNXFileConstants.CMD_SUCCESS)) { result.setCommandSuccess(); } else { String errMsg = (String) _provExecutor.getKeyMap().get(VNXFileConstants.FAULT_DESC); result.setCommandFailed(); result.setMessage(errMsg); } } catch (Exception e) { throw new VNXException("Failure", e); } return result; } private void updateAttributes(final Map<String, Object> reqAttributeMap, final StorageSystem system) { reqAttributeMap.put(VNXFileConstants.DEVICETYPE, system.getSystemType()); reqAttributeMap.put(VNXFileConstants.USERNAME, system.getUsername()); reqAttributeMap.put(VNXFileConstants.USER_PASS_WORD, system.getPassword()); reqAttributeMap.put(VNXFileConstants.PORTNUMBER, system.getPortNumber()); reqAttributeMap.put(VNXFileConstants.URI, getServerUri(system)); reqAttributeMap.put(VNXFileConstants.AUTHURI, getLoginUri(system)); } private String getLoginUri(final StorageSystem system) { try { final URI deviceURI = new URI("https", system.getIpAddress(), "/Login", null); return deviceURI.toString(); } catch (URISyntaxException ex) { _log.error("Error while creating server uri for IP {}", system.getIpAddress()); } return ""; } private String getServerUri(final StorageSystem system) { try { final URI deviceURI = new URI("https", system.getIpAddress(), SERVER_URI, null); return deviceURI.toString(); } catch (URISyntaxException ex) { _log.error("Error while creating server uri for IP {}", system.getIpAddress()); } return ""; } public void setProvExecutor(VNXFileDiscExecutor discExec) { _provExecutor = discExec; } public VNXFileDiscExecutor getProvExecutor() { return _provExecutor; } public void setProvNamespaces(NamespaceList namespaces) { _provNamespaces = namespaces; } public NamespaceList getProvNamespaces() { return _provNamespaces; } private StorageHADomain getMoverOrVdmName(StorageSystem system, String moverOrVdmId, String portNetworkId) { _log.info("getMoverOrVdmName(StorageSystem {}, String {})", system.getId(), moverOrVdmId); StorageHADomain matchingMoverOrVdm = null; List<StoragePort> ports = CustomQueryUtility.queryActiveResourcesByRelation( _dbClient, system.getId(), StoragePort.class, "storageDevice"); for (StoragePort port : ports) { if (port.getPortGroup().equalsIgnoreCase(moverOrVdmId) && port.getPortNetworkId().equalsIgnoreCase(portNetworkId)) { matchingMoverOrVdm = _dbClient.queryObject(StorageHADomain.class, port.getStorageHADomain()); _log.info("getMoverOrVdmName match for Port {} and MoverOrVdm {}", port.getLabel() + ":" + port.getPortNetworkId() + ":" + port.getPortGroup(), matchingMoverOrVdm.getAdapterName() + ":" + matchingMoverOrVdm.getName()); break; } } _log.info("getMoverOrVdmName return () ", matchingMoverOrVdm); return matchingMoverOrVdm; } private String getParentMoverName(URI parentMoverId) { String parentMoverName = null; _log.info("getParentMoverName {} ", parentMoverId); StorageHADomain matchingMover = _dbClient.queryObject(StorageHADomain.class, parentMoverId); if (matchingMover != null) { parentMoverName = matchingMover.getAdapterName(); } return parentMoverName; } private StorageHADomain getDataMover(FileShare fileShare) { StorageHADomain dm = null; if (fileShare.getStoragePort() != null) { StoragePort port = _dbClient.queryObject(StoragePort.class, fileShare.getStoragePort()); if (port != null) { dm = _dbClient.queryObject(StorageHADomain.class, port.getStorageHADomain()); } } return dm; } private List<Snapshot> getFSSnapshots(FileShare fs) { URI fsId = fs.getId(); List<Snapshot> snapshots = new ArrayList<Snapshot>(); URIQueryResultList snapIDList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(fsId), snapIDList); while (snapIDList.iterator().hasNext()) { URI uri = snapIDList.iterator().next(); Snapshot snap = _dbClient.queryObject(Snapshot.class, uri); if (!snap.getInactive()) { snapshots.add(snap); } } return snapshots; } private List<QuotaDirectory> getFSQuotaDirs(FileShare fs) { URI fsId = fs.getId(); List<QuotaDirectory> quotaDirs = new ArrayList<QuotaDirectory>(); URIQueryResultList qdIDList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory.getQuotaDirectoryConstraint(fsId), qdIDList); while (qdIDList.iterator().hasNext()) { URI uri = qdIDList.iterator().next(); QuotaDirectory quotaDir = _dbClient.queryObject(QuotaDirectory.class, uri); if (!quotaDir.getInactive()) { quotaDirs.add(quotaDir); } } return quotaDirs; } /* * Check the dependencies on file share or on snap shot. * input : * fs: File share object * considerSnapshots: consider the snap shot dependencies. * return: this function will check and return the number of dependencies like * exports, shares, snapshot and quota directories on the given file share. */ private int getVNXFSDependencies(FileShare fs, Boolean considerSnapshots) { FSExportMap exports = null; SMBShareMap shares = null; int totalDependencies = 0; // FileShare operation if (fs.getFsExports() != null) { exports = fs.getFsExports(); } if (fs.getSMBFileShares() != null) { shares = fs.getSMBFileShares(); } if (exports != null) { totalDependencies += exports.size(); } if (shares != null) { totalDependencies += shares.size(); } List<Snapshot> snapshots = getFSSnapshots(fs); if (snapshots != null && !snapshots.isEmpty()) { totalDependencies += snapshots.size(); } List<QuotaDirectory> quotaDirs = getFSQuotaDirs(fs); if (quotaDirs != null && !quotaDirs.isEmpty()) { totalDependencies += quotaDirs.size(); } if (considerSnapshots && snapshots != null) { totalDependencies = snapshots.size(); for (Snapshot snap : snapshots) { exports = snap.getFsExports(); shares = snap.getSMBFileShares(); if (exports != null) { totalDependencies += exports.size(); } if (shares != null) { totalDependencies += shares.size(); } } } _log.info("FileShare : total dependencies {} ", totalDependencies); return totalDependencies; } }