/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl; import static java.util.Arrays.asList; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.computesystemcontroller.hostmountadapters.LinuxMountUtils; import com.emc.storageos.computesystemorchestrationcontroller.ComputeSystemOrchestrationDeviceController; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; 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.CifsShareACL; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject.Type; import com.emc.storageos.db.client.model.FSExportMap; import com.emc.storageos.db.client.model.FileExport; import com.emc.storageos.db.client.model.FileExportRule; import com.emc.storageos.db.client.model.FileMountInfo; import com.emc.storageos.db.client.model.FileObject; import com.emc.storageos.db.client.model.FilePolicy; import com.emc.storageos.db.client.model.FilePolicy.FilePolicyType; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.FileShare.PersonalityTypes; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.NFSShareACL; 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.Snapshot; import com.emc.storageos.db.client.model.Stat; import com.emc.storageos.db.client.model.StatTimeSeries; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.TenantOrg; import com.emc.storageos.db.client.model.VirtualArray; import com.emc.storageos.db.client.model.VirtualNAS; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.FileOperationUtils; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.fileorchestrationcontroller.FileDescriptor; import com.emc.storageos.fileorchestrationcontroller.FileOrchestrationInterface; import com.emc.storageos.locking.LockTimeoutValue; import com.emc.storageos.locking.LockType; import com.emc.storageos.model.file.CifsShareACLUpdateParams; import com.emc.storageos.model.file.ExportRule; import com.emc.storageos.model.file.ExportRules; import com.emc.storageos.model.file.FileExportUpdateParams; import com.emc.storageos.model.file.FileShareExportUpdateParams; import com.emc.storageos.model.file.MountInfo; import com.emc.storageos.model.file.NfsACE; import com.emc.storageos.model.file.NfsACLUpdateParams; import com.emc.storageos.model.file.ShareACL; import com.emc.storageos.model.file.ShareACLs; import com.emc.storageos.model.file.policy.FilePolicyUpdateParam; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.security.audit.AuditLogManager; import com.emc.storageos.security.audit.AuditLogManagerFactory; 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.svcs.errorhandling.resources.APIException; import com.emc.storageos.svcs.errorhandling.resources.InternalException; import com.emc.storageos.util.ExportUtils; import com.emc.storageos.volumecontroller.AsyncTask; import com.emc.storageos.volumecontroller.ControllerException; import com.emc.storageos.volumecontroller.FileController; import com.emc.storageos.volumecontroller.FileControllerConstants; import com.emc.storageos.volumecontroller.FileDeviceInputOutput; import com.emc.storageos.volumecontroller.FileSMBShare; import com.emc.storageos.volumecontroller.FileShareExport; import com.emc.storageos.volumecontroller.FileShareQuotaDirectory; import com.emc.storageos.volumecontroller.FileStorageDevice; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.file.MirrorFilePauseTaskCompleter; import com.emc.storageos.volumecontroller.impl.file.MirrorFileRefreshTaskCompleter; import com.emc.storageos.volumecontroller.impl.file.MirrorFileResumeTaskCompleter; import com.emc.storageos.volumecontroller.impl.file.MirrorFileResyncTaskCompleter; import com.emc.storageos.volumecontroller.impl.file.MirrorFileStartTaskCompleter; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableBourneEvent; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager; import com.emc.storageos.volumecontroller.impl.monitoring.cim.enums.RecordType; import com.emc.storageos.workflow.Workflow; import com.emc.storageos.workflow.WorkflowException; import com.emc.storageos.workflow.WorkflowService; import com.emc.storageos.workflow.WorkflowStepCompleter; /** * Generic File Controller Implementation that does all of the database * operations and calls methods on the array specific implementations * * @author burckb * */ public class FileDeviceController implements FileOrchestrationInterface, FileController { private DbClient _dbClient; private static final String EVENT_SERVICE_TYPE = "file"; private static final String EVENT_SERVICE_SOURCE = "FileController"; private static final Logger _log = LoggerFactory.getLogger(FileDeviceController.class); private Map<String, FileStorageDevice> _devices; private static final String UNMOUNT_FILESYSTEM_EXPORT_METHOD = "unmountDevice"; private static final String CHECK_IF_MOUNT_EXISTS_ON_HOST = "checkIfMountExistsOnHost"; private WorkflowService _workflowService; private RecordableEventManager _eventManager; private AuditLogManager _auditMgr; private static ComputeSystemOrchestrationDeviceController computeSystemOrchestrationDeviceController; public void setDbClient(DbClient dbc) { _dbClient = dbc; } public void setDevices(Map<String, FileStorageDevice> deviceInterfaces) { _devices = deviceInterfaces; } public void setEventManager(RecordableEventManager eventManager) { _eventManager = eventManager; } public void setAuditLogManager(AuditLogManager auditManager) { _auditMgr = auditManager; } private FileStorageDevice getDevice(String deviceType) { return _devices.get(deviceType); } public void setWorkflowService(WorkflowService workflowService) { _workflowService = workflowService; } public static ComputeSystemOrchestrationDeviceController getComputeSystemOrchestrationDeviceController() { return computeSystemOrchestrationDeviceController; } public static void setComputeSystemOrchestrationDeviceController( ComputeSystemOrchestrationDeviceController computeSystemOrchestrationDeviceController) { FileDeviceController.computeSystemOrchestrationDeviceController = computeSystemOrchestrationDeviceController; } /** * Create a nice event based on the File Share * * @param fs * FileShare for which the event is about * @param type * Type of event such as FileShareCreated or FileShareDeleted * @param description * Description for the event if needed */ public static void recordFsEvent(DbClient dbClient, FileShare fs, String type, String description, String extensions) { if (fs == null) { _log.error("Invalid FileShare event"); return; } RecordableEventManager eventManager = new RecordableEventManager(); eventManager.setDbClient(dbClient); // fix the bogus user ID once we have AuthZ working RecordableBourneEvent event = ControllerUtils.convertToRecordableBourneEvent(fs, type, description, extensions, dbClient, EVENT_SERVICE_TYPE, RecordType.Event.name(), EVENT_SERVICE_SOURCE); try { eventManager.recordEvents(event); } catch (Exception th) { _log.error("Failed to record event. Event description: {}.", description, th); } } /** * Create a nice event based on the FileShare * * @param snap * Snapshot for which the event is about * @param fs * FileShare from which the snapshot was created * @param type * Type of event such as FileShareCreated or FileShareDeleted * @param description * Description for the event if needed */ public static void recordSnapshotEvent(DbClient dbClient, Snapshot snap, FileShare fs, String type, String description, String extensions) { if (snap == null || fs == null) { _log.error("Invalid Snapshot event"); return; } RecordableEventManager eventManager = new RecordableEventManager(); eventManager.setDbClient(dbClient); // fix the bogus user ID once we have AuthZ working RecordableBourneEvent event = new RecordableBourneEvent( type, fs.getTenant().getURI(), URI.create("ViPR-User"), // user ID when AAA fixed fs.getProject().getURI(), fs.getVirtualPool(), EVENT_SERVICE_TYPE, snap.getId(), description, System.currentTimeMillis(), extensions, snap.getNativeGuid(), RecordType.Event.name(), EVENT_SERVICE_SOURCE, "", ""); try { eventManager.recordEvents(event); } catch (Exception ex) { _log.error("Failed to record event. Event description: {}.", description, ex); } } public static void recordQuotaDirectoryEvent(DbClient dbClient, QuotaDirectory quotaDir, FileShare fs, String type, String description, String extensions) { if (quotaDir == null || fs == null) { _log.error("Invalid quota directory event"); return; } RecordableEventManager eventManager = new RecordableEventManager(); eventManager.setDbClient(dbClient); // fix the bogus user ID once we have AuthZ working RecordableBourneEvent event = new RecordableBourneEvent( type, fs.getTenant().getURI(), URI.create("ViPR-User"), // user ID when AAA fixed fs.getProject().getURI(), fs.getVirtualPool(), EVENT_SERVICE_TYPE, quotaDir.getId(), description, System.currentTimeMillis(), extensions, quotaDir.getNativeGuid(), RecordType.Event.name(), EVENT_SERVICE_SOURCE, "", ""); try { eventManager.recordEvents(event); } catch (Exception ex) { _log.error("Failed to record event. Event description: {}.", description, ex); } } /** * Record audit log for file service * * @param auditType * Type of AuditLog * @param operationalStatus * Status of operation * @param description * Description for the AuditLog * @param descparams * Description paramters */ public static void auditFile(DbClient dbClient, OperationTypeEnum auditType, boolean operationalStatus, String description, Object... descparams) { AuditLogManager auditMgr = AuditLogManagerFactory.getAuditLogManager(); auditMgr.recordAuditLog(null, null, EVENT_SERVICE_TYPE, auditType, System.currentTimeMillis(), operationalStatus ? AuditLogManager.AUDITLOG_SUCCESS : AuditLogManager.AUDITLOG_FAILURE, description, descparams); } @Override public void createFS(URI storage, URI pool, URI fs, String nativeId, String opId) throws ControllerException { FileObject fileObject = null; FileShare fsObj = null; StorageSystem storageObj = null; try { ControllerUtils.setThreadLocalLogData(fs, opId); storageObj = _dbClient.queryObject(StorageSystem.class, storage); String[] params = { storage.toString(), pool.toString(), fs.toString() }; _log.info("Create FS: {}, {}, {}", params); StoragePool poolObj = _dbClient.queryObject(StoragePool.class, pool); fsObj = _dbClient.queryObject(FileShare.class, fs); VirtualPool vPool = _dbClient.queryObject(VirtualPool.class, fsObj.getVirtualPool()); fileObject = fsObj; FileDeviceInputOutput args = new FileDeviceInputOutput(); args.addFileShare(fsObj); args.addStoragePool(poolObj); args.setVPool(vPool); args.setNativeDeviceFsId(nativeId); args.setOpId(opId); Project proj = _dbClient.queryObject(Project.class, fsObj.getProject()); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, fsObj.getTenant()); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); args.setTenantOrg(tenant); args.setProject(proj); // work flow and we need to add TaskCompleter(TBD for vnxfile) WorkflowStepCompleter.stepExecuting(opId); acquireStepLock(storageObj, opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doCreateFS(storageObj, args); if (!result.getCommandPending()) { fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); } else { // we need to add task completer fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); } if (result.isCommandSuccess()) { fsObj.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(_dbClient, fsObj)); fsObj.setInactive(false); WorkflowStepCompleter.stepSucceded(opId); } else if (!result.getCommandPending()) { fsObj.setInactive(true); WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } _dbClient.updateObject(fsObj); if (!result.getCommandPending()) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM, result.isCommandSuccess(), "", "", fsObj); } } catch (Exception e) { String[] params = { storage.toString(), pool.toString(), fs.toString(), e.getMessage() }; _log.error("Unable to create file system: storage {}, pool {}, FS {}: {}", params); // work flow fail ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); if ((fsObj != null) && (storageObj != null)) { fsObj.setInactive(true); _dbClient.updateObject(fsObj); recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM, false, e.getMessage(), "", fsObj, storageObj); } updateTaskStatus(opId, fileObject, e); } } @Override public void delete(URI storage, URI pool, URI uri, boolean forceDelete, String deleteType, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(uri, opId); StorageSystem storageObj = null; FileObject fileObject = null; FileShare fsObj = null; Snapshot snapshotObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); String[] params = { storage.toString(), uri.toString(), String.valueOf(forceDelete), deleteType }; _log.info("Delete : storage : {}, URI : {}, forceDelete : {}, delete_type : {} ", params); FileDeviceInputOutput args = new FileDeviceInputOutput(); boolean isFile = false; args.setOpId(opId); if (URIUtil.isType(uri, FileShare.class)) { isFile = true; args.setForceDelete(forceDelete); fsObj = _dbClient.queryObject(FileShare.class, uri); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); fileObject = fsObj; args.addFileShare(fsObj); args.setFileOperation(isFile); BiosCommandResult result; WorkflowStepCompleter.stepExecuting(opId); if (FileControllerConstants.DeleteTypeEnum.VIPR_ONLY.toString().equalsIgnoreCase(deleteType) && !fsObj.getInactive()) { result = BiosCommandResult.createSuccessfulResult(); } else { if (!fsObj.getInactive()) { // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); result = getDevice(storageObj.getSystemType()).doDeleteFS(storageObj, args); } else { result = BiosCommandResult.createSuccessfulResult(); } } // In case of VNXe if (result.getCommandPending()) { return; } fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); if (result.isCommandSuccess() && (FileControllerConstants.DeleteTypeEnum.FULL.toString().equalsIgnoreCase(deleteType))) { fsObj.setInactive(true); if (forceDelete) { doDeleteSnapshotsFromDB(fsObj, true, null, args); // Delete Snapshot and its references from DB args.addQuotaDirectory(null); doFSDeleteQuotaDirsFromDB(args); // Delete Quota Directory from DB deleteShareACLsFromDB(args); // Delete CIFS Share ACLs from DB doDeleteExportRulesFromDB(true, null, args); // Delete Export Rules from DB doDeletePolicyReferenceFromDB(fsObj); // Remove FileShare Reference from Schedule Policy } generateZeroStatisticsRecord(fsObj); WorkflowStepCompleter.stepSucceded(opId); } else if (!result.getCommandPending() && FileControllerConstants.DeleteTypeEnum.FULL.toString().equalsIgnoreCase(deleteType)) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess() && (FileControllerConstants.DeleteTypeEnum.VIPR_ONLY.toString().equalsIgnoreCase(deleteType))) { boolean snapshotsExist = snapshotsExistsOnFS(fsObj); boolean quotaDirsExist = quotaDirectoriesExistsOnFS(fsObj); boolean fsCheck = getDevice(storageObj.getSystemType()).doCheckFSExists(storageObj, args); if (fsCheck) { String errMsg = null; if (snapshotsExist) { errMsg = new String( "delete file system from ViPR database failed because snapshots exist for file system " + fsObj.getLabel() + " and once deleted the snapshot cannot be ingested into ViPR"); } else if (quotaDirsExist && !quotaDirectoryIngestionSupported(storageObj.getSystemType())) { errMsg = new String( "delete file system from ViPR database failed because quota directories exist for file system " + fsObj.getLabel() + " and once deleted the quota directory cannot be ingested into ViPR"); } if (errMsg != null) { _log.error(errMsg); final ServiceCoded serviceCoded = DeviceControllerException.errors.jobFailedOpMsg( OperationTypeEnum.DELETE_FILE_SYSTEM.toString(), errMsg); result = BiosCommandResult.createErrorResult(serviceCoded); fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM, result.isCommandSuccess(), "", "", fsObj, storageObj); _dbClient.updateObject(fsObj); WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); return; } } doDeleteSnapshotsFromDB(fsObj, true, null, args); // Delete Snapshot and its references from DB args.addQuotaDirectory(null); doFSDeleteQuotaDirsFromDB(args); deleteShareACLsFromDB(args); doDeleteExportRulesFromDB(true, null, args); doDeletePolicyReferenceFromDB(fsObj); // Remove FileShare Reference from Schedule Policy SMBShareMap cifsSharesMap = fsObj.getSMBFileShares(); if (cifsSharesMap != null && !cifsSharesMap.isEmpty()) { cifsSharesMap.clear(); } fsObj.setInactive(true); generateZeroStatisticsRecord(fsObj); WorkflowStepCompleter.stepSucceded(opId); } else if (!result.getCommandPending() && FileControllerConstants.DeleteTypeEnum.VIPR_ONLY.toString().equalsIgnoreCase(deleteType)) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } _dbClient.updateObject(fsObj); recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM, result.isCommandSuccess(), "", "", fsObj, storageObj); } else { snapshotObj = _dbClient.queryObject(Snapshot.class, uri); fileObject = snapshotObj; args.addSnapshot(snapshotObj); fsObj = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); args.addFileShare(fsObj); args.setFileOperation(isFile); WorkflowStepCompleter.stepExecuting(opId); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doDeleteSnapshot(storageObj, args); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } snapshotObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); snapshotObj.setInactive(true); // delete the corresponding export rules if available. args.addSnapshot(snapshotObj); doDeleteExportRulesFromDB(true, null, args); } _dbClient.updateObject(snapshotObj); recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SNAPSHOT, result.isCommandSuccess(), "", "", snapshotObj, fsObj, storageObj); } } catch (Exception e) { String[] params = { storage.toString(), uri.toString(), String.valueOf(forceDelete), e.getMessage().toString() }; _log.error("Unable to delete file system or snapshot: storage {}, FS/snapshot {}, forceDelete {}: {}", params); updateTaskStatus(opId, fileObject, e); // work flow fail for fileshare delete if (URIUtil.isType(uri, FileShare.class)) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } if (URIUtil.isType(uri, FileShare.class)) { if ((fsObj != null) && (storageObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM, false, e.getMessage(), "", fsObj, storageObj); } } else { if ((fsObj != null) && (storageObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SNAPSHOT, false, e.getMessage(), "", snapshotObj, fsObj, storageObj); } } } } private boolean quotaDirectoryIngestionSupported(String storageType) { StorageSystem.Type storageSystemType = StorageSystem.Type.valueOf(storageType); boolean qDIngestionSupported = false; if (storageSystemType.equals(StorageSystem.Type.unity) || storageSystemType.equals(StorageSystem.Type.netapp) || storageSystemType.equals(StorageSystem.Type.netappc) || storageSystemType.equals(StorageSystem.Type.vnxfile) || storageSystemType.equals(StorageSystem.Type.isilon)) { qDIngestionSupported = true; } return qDIngestionSupported; } private List<QuotaDirectory> queryFileQuotaDirs(FileDeviceInputOutput args) { if (args.getFileOperation()) { FileShare fs = args.getFs(); _log.info("Querying all quota directories Using FsId {}", fs.getId()); try { ContainmentConstraint containmentConstraint = ContainmentConstraint.Factory .getQuotaDirectoryConstraint(fs.getId()); List<QuotaDirectory> fsQuotaDirs = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, QuotaDirectory.class, containmentConstraint); return fsQuotaDirs; } catch (Exception e) { _log.error("Error while querying {}", e); } } return null; } private void doFSDeleteQuotaDirsFromDB(FileDeviceInputOutput args) throws Exception { List<QuotaDirectory> quotaDirs = queryFileQuotaDirs(args); if (quotaDirs != null && !quotaDirs.isEmpty()) { _log.info("Doing CRUD Operations on all DB QuotaDirectory for requested fs"); for (QuotaDirectory dir : quotaDirs) { _log.info("Deleting quota dir from DB - Dir :{}", dir); dir.setInactive(true); _dbClient.updateObject(dir); } } } /** * Generate zero statistics record. * * @param fsObj * the file share object */ private void generateZeroStatisticsRecord(FileShare fsObj) { try { Stat zeroStatRecord = new Stat(); zeroStatRecord.setTimeInMillis(System.currentTimeMillis()); zeroStatRecord.setTimeCollected(System.currentTimeMillis()); zeroStatRecord.setServiceType(Constants._File); zeroStatRecord.setAllocatedCapacity(0); zeroStatRecord.setProvisionedCapacity(0); zeroStatRecord.setBandwidthIn(0); zeroStatRecord.setBandwidthOut(0); zeroStatRecord.setNativeGuid(fsObj.getNativeGuid()); zeroStatRecord.setSnapshotCapacity(0); zeroStatRecord.setSnapshotCount(0); zeroStatRecord.setResourceId(fsObj.getId()); zeroStatRecord.setVirtualPool(fsObj.getVirtualPool()); zeroStatRecord.setProject(fsObj.getProject().getURI()); zeroStatRecord.setTenant(fsObj.getTenant().getURI()); _dbClient.insertTimeSeries(StatTimeSeries.class, zeroStatRecord); } catch (Exception e) { _log.error("Zero Stat Record Creation failed for FileShare : {}", fsObj.getId(), e); } } @Override public void export(URI storage, URI uri, List<FileShareExport> exports, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(uri, opId); FileObject fsObj = null; FileShare fs = null; Snapshot snapshotObj = null; StorageSystem storageObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); FileDeviceInputOutput args = new FileDeviceInputOutput(); boolean isFile = false; if (URIUtil.isType(uri, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, uri); fsObj = fs; args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); setVirtualNASinArgs(fs.getVirtualNAS(), args); } else { snapshotObj = _dbClient.queryObject(Snapshot.class, uri); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); args.addFileShare(fs); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); setVirtualNASinArgs(fs.getVirtualNAS(), args); } args.setFileOperation(isFile); args.setOpId(opId); _log.info("Export details... "); List<FileExport> fileExports = new ArrayList<FileExport>(); if (exports != null) { for (FileShareExport fileShareExport : exports) { args.setBypassDnsCheck(fileShareExport.getBypassDnsCheck()); FileExport fExport = fileShareExport.getFileExport(); fExport.setMountPoint(fileShareExport.getMountPath()); _log.info("FileExport:clients:" + fExport.getClients() + ":portName:" + fExport.getStoragePortName() + ":port:" + fExport.getStoragePort() + ":rootMapping:" + fExport.getRootUserMapping() + ":permissions:" + fExport.getPermissions() + ":protocol:" + fExport.getProtocol() + ":security:" + fExport.getSecurityType() + ":mountpoint:" + fExport.getMountPoint() + ":path:" + fExport.getPath() + ":comments:" + fExport.getComments() + ":subDirectory:" + fExport.getSubDirectory()); fileExports.add(fExport); } } else { _log.info("Exports are null"); } // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doExport(storageObj, args, fileExports); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Set Mount path info for the exports FSExportMap fsExports = fsObj.getFsExports(); // Per New model get the rules and see if any rules that are already saved and available. List<FileExportRule> existingRules = queryFileExports(args); if (null != fsExports) { Iterator it = fsExports.keySet().iterator(); while (it.hasNext()) { String fsExpKey = (String) it.next(); FileExport fileExport = fsObj.getFsExports().get(fsExpKey); if ((fileExport.getMountPath() != null) && (fileExport.getMountPath().length() > 0)) { fileExport.setMountPoint(ExportUtils.getFileMountPoint(fileExport.getStoragePort(), fileExport.getMountPath())); } else { fileExport.setMountPoint(ExportUtils.getFileMountPoint(fileExport.getStoragePort(), fileExport.getPath())); } _log.info("FileExport mountpath set to {} {}", fsExpKey, fileExport.getMountPoint()); // Per New Model of Export Rules Lets create the rule and save it as FileExportRule. if (result.isCommandSuccess()) { FileExportRule newRule = getFileExportRule(fsObj.getId(), fileExport, args); _log.debug("ExportRule Constucted per expotkey {}, {}", fsExpKey, newRule); if (existingRules != null && existingRules.isEmpty()) { newRule.setId(URIUtil.createId(FileExportRule.class)); _log.info("No Existing rules available for this FS Export and so creating the rule now {}", newRule); _dbClient.createObject(newRule); } else { _log.debug("Checking for existing rule(s) available for this export..."); boolean isRuleFound = false; for (FileExportRule rule : existingRules) { _log.debug("Available Export Rule {} - Matching with New Rule {}", rule, newRule); if (newRule.getFsExportIndex() != null && rule.getFsExportIndex().equals(newRule.getFsExportIndex())) { isRuleFound = true; _log.info("Match Found : Skipping this rule as already available {}", newRule); break; } } if (!isRuleFound) { _log.info("Creating new Export Rule {}", newRule); newRule.setId(URIUtil.createId(FileExportRule.class)); _dbClient.createObject(newRule); isRuleFound = false; } } } } } String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); OperationTypeEnum auditType = null; auditType = (isFile) ? OperationTypeEnum.EXPORT_FILE_SYSTEM : OperationTypeEnum.EXPORT_FILE_SNAPSHOT; fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getExportClientExtensions(fileExports), fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getExportClientExtensions(fileExports), snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] params = { storage.toString(), uri.toString(), e.getMessage() }; _log.error("Unable to export file system or snapshot: storage {}, FS/snapshot URI {}: {}", params); for (FileShareExport fsExport : exports) { _log.error("{}", fsExport); } updateTaskStatus(opId, fsObj, e); if (URIUtil.isType(uri, FileShare.class)) { if ((fs != null) && (storageObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.EXPORT_FILE_SYSTEM, false, e.getMessage(), "", fs, storageObj); } } else { if ((fs != null) && (storageObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.EXPORT_FILE_SNAPSHOT, false, e.getMessage(), "", snapshotObj, fs, storageObj); } } } } /** * Gets the list of export clients to be recorded as an extension in the * event for FileSystem/snapshot export/unexport operations. The extension * is specified in the format: * * ExtensionName=client1, client2, ..., client3 * * @param fExports * The list of FileSystem export maps. * * @return A string specifying export/unexport clients. */ private String getExportClientExtensions(List<FileExport> fExports) { if (fExports == null) { return ""; } StringBuilder strBuilder = new StringBuilder(); int exportSize = fExports.size(); if (exportSize > 0) { strBuilder.append(RecordableBourneEvent.FS_CLIENT_EXTENSION_NAME); strBuilder.append("="); for (int i = 0; i < exportSize; i++) { List<String> clients = fExports.get(i).getClients(); for (int j = 0; j < clients.size(); j++) { strBuilder.append(clients.get(j)); if (j < clients.size() - 1) { strBuilder.append(","); } } if (!clients.isEmpty() && (i < fExports.size() - 1)) { strBuilder.append(","); } } } return strBuilder.toString(); } @Override public void unexport(URI storage, URI fileUri, List<FileShareExport> exports, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(fileUri, opId); FileObject fsObj = null; FileShare fs = null; Snapshot snapshotObj = null; StorageSystem storageObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); FileDeviceInputOutput args = new FileDeviceInputOutput(); boolean isFile = false; if (URIUtil.isType(fileUri, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fileUri); setVirtualNASinArgs(fs.getVirtualNAS(), args); fsObj = fs; args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } else { snapshotObj = _dbClient.queryObject(Snapshot.class, fileUri); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fs.getVirtualNAS(), args); args.addFileShare(fs); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } args.setFileOperation(isFile); args.setOpId(opId); _log.info("Export details... "); List<FileExport> fileExports = new ArrayList<FileExport>(); List<FileExportRule> exportRules = new ArrayList<FileExportRule>(); if (exports != null) { for (FileShareExport fileShareExport : exports) { FileExport fileExport = fileShareExport.getFileExport(); fileExports.add(fileExport); _log.info("FileExport:" + fileExport.getClients() + ":" + fileExport.getStoragePortName() + ":" + fileExport.getStoragePort() + ":" + fileExport.getRootUserMapping() + ":" + fileExport.getPermissions() + ":" + fileExport.getProtocol() + ":" + fileExport.getSecurityType() + ":" + fileExport.getMountPoint() + ":" + fileExport.getMountPath() + ":" + fileExport.getPath()); _log.info("FileShareExport: " + fileExport.getFileExportKey()); // Per New Model : Lets create the Export Rules, So these will not get missed. FileExportRule rule = getFileExportRule(fileUri, fileExport, args); exportRules.add(rule); } } else { _log.info("Exports are null"); } WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doUnexport(storageObj, args, fileExports); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Set status fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); OperationTypeEnum auditType = (isFile) ? OperationTypeEnum.UNEXPORT_FILE_SYSTEM : OperationTypeEnum.UNEXPORT_FILE_SNAPSHOT; if (result.isCommandSuccess()) { // Remove Export for (FileExport fileExport : fileExports) { fsObj.getFsExports().remove(fileExport.getFileExportKey()); _log.info("FileShareExport removed : " + fileExport.getFileExportKey()); } // Query Existing Export rule and if found set to delete. for (FileExportRule rule : exportRules) { URIQueryResultList dbresult = new URIQueryResultList(); if (!args.getFileOperation() && rule.getSnapshotExportIndex() != null) { _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getSnapshotExportRuleConstraint(rule.getSnapshotExportIndex()), dbresult); } else if (rule.getFsExportIndex() != null) { _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getFileExportRuleConstraint(rule.getFsExportIndex()), dbresult); } Iterator<URI> it = dbresult.iterator(); while (it.hasNext()) { if (dbresult.iterator().hasNext()) { rule = _dbClient.queryObject(FileExportRule.class, it.next()); if (rule != null && !rule.getInactive()) { _log.info("Existing DB Model found {}", rule); rule.setInactive(true); _dbClient.updateObject(rule); break; } } } } FSExportMap exportsMap = fsObj.getFsExports(); List<FileExport> fsExports = new ArrayList<FileExport>(exportsMap.values()); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getExportClientExtensions(fsExports), fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getExportClientExtensions(fsExports), snapshotObj, fs, storageObj); } } _dbClient.updateObject(fsObj); if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] params = { storage.toString(), fileUri.toString(), e.getMessage() }; _log.error("Unable to unexport file system or snapshot: storage {}, FS/snapshot URI {}: {}", params); for (FileShareExport fsExport : exports) { _log.error("{} ", fsExport); } updateTaskStatus(opId, fsObj, e); if (URIUtil.isType(fileUri, FileShare.class)) { if ((fs != null) && (storageObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UNEXPORT_FILE_SYSTEM, false, e.getMessage(), "", fs, storageObj); } } else { if ((fs != null) && (storageObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, false, e.getMessage(), "", snapshotObj, fs, storageObj); } } } } @Override public void expandFS(URI storage, URI uri, long newFSsize, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(uri, opId); FileShare fs = null; try { StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); FileDeviceInputOutput args = new FileDeviceInputOutput(); fs = _dbClient.queryObject(FileShare.class, uri); args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); args.setFileOperation(true); args.setNewFSCapacity(newFSsize); args.setOpId(opId); // work flow and we need to add TaskCompleter(TBD for vnxfile) WorkflowStepCompleter.stepExecuting(opId); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doExpandFS(storageObj, args); if (result.getCommandPending()) { // async operation return; } if (result.isCommandSuccess()) { _log.info("FileSystem old capacity :" + args.getFsCapacity() + ":Expanded Size:" + args.getNewFSCapacity()); args.setFsCapacity(args.getNewFSCapacity()); _log.info("FileSystem new capacity :" + args.getFsCapacity()); WorkflowStepCompleter.stepSucceded(opId); } else if (!result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Set status fs.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(fs); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.EXPAND_FILE_SYSTEM, result.isCommandSuccess(), eventMsg, "", fs, String.valueOf(newFSsize)); } catch (Exception e) { String[] params = { storage.toString(), uri.toString(), String.valueOf(newFSsize), e.getMessage() }; _log.error("Unable to expand file system: storage {}, FS URI {}, size {}: {}", params); ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); updateTaskStatus(opId, fs, e); if (fs != null) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.EXPAND_FILE_SYSTEM, false, e.getMessage(), "", fs, String.valueOf(newFSsize)); } } } @Override public void share(URI storage, URI uri, FileSMBShare smbShare, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(uri, opId); FileObject fileObject = null; StorageSystem storageObj = null; FileShare fsObj = null; Snapshot snapshotObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); _log.info(String.format( "Create SMB share details --- name: %1$s, description: %2$s, permissionType: %3$s, permission: %4$s , maxUsers: %5$s", smbShare.getName(), smbShare.getDescription(), smbShare.getPermissionType(), smbShare.getPermission(), (smbShare.getMaxUsers() > 0) ? smbShare.getMaxUsers() : "unlimited")); _log.info("Path {}", smbShare.getPath()); // get db object for smb share SMBFileShare smbFileShare = smbShare.getSMBFileShare(); FileDeviceInputOutput args = new FileDeviceInputOutput(); args.setOpId(opId); if (URIUtil.isType(uri, FileShare.class)) { fsObj = _dbClient.queryObject(FileShare.class, uri); fileObject = fsObj; args.addFSFileObject(fsObj); args.setFileOperation(true); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); // Acquire lock for VNXFILE Storage System WorkflowStepCompleter.stepExecuting(opId); acquireStepLock(storageObj, opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doShare(storageObj, args, smbFileShare); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(fsObj); List<SMBFileShare> shares = new ArrayList<SMBFileShare>(); shares.add(smbFileShare); if (result.isCommandSuccess()) { _log.info("File share created successfully"); createDefaultACEForSMBShare(uri, smbShare, storageObj.getSystemType()); WorkflowStepCompleter.stepSucceded(opId); } String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_SHARE, result.isCommandSuccess(), eventMsg, getShareNameExtensions(shares), fsObj, smbShare); } else { snapshotObj = _dbClient.queryObject(Snapshot.class, uri); fileObject = snapshotObj; args.addSnapshotFileObject(snapshotObj); fsObj = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); args.addFileShare(fsObj); args.setFileOperation(false); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); WorkflowStepCompleter.stepExecuting(opId); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doShare(storageObj, args, smbFileShare); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } snapshotObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(snapshotObj); List<SMBFileShare> shares = new ArrayList<SMBFileShare>(); shares.add(smbFileShare); if (result.isCommandSuccess()) { _log.info("File snapshot share created successfully"); WorkflowStepCompleter.stepSucceded(opId); createDefaultACEForSMBShare(uri, smbShare, storageObj.getSystemType()); } String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SNAPSHOT_SHARE, result.isCommandSuccess(), eventMsg, getShareNameExtensions(shares), snapshotObj, fsObj, smbShare); } } catch (Exception e) { String[] params = { storage.toString(), uri.toString(), smbShare.getName(), e.getMessage() }; _log.error("Unable to create file system or snapshot share: storage {}, FS/snapshot URI {}, SMB share {}: {}", params); ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); updateTaskStatus(opId, fileObject, e); if (URIUtil.isType(uri, FileShare.class)) { if ((fsObj != null) && (storageObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_SHARE, false, e.getMessage(), "", fsObj, smbShare, storageObj); } } else { if ((fsObj != null) && (storageObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SNAPSHOT_SHARE, false, e.getMessage(), "", snapshotObj, fsObj, smbShare, storageObj); } } } } @Override public void deleteShare(URI storage, URI uri, FileSMBShare smbShare, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(uri, opId); FileObject fileObject = null; StorageSystem storageObj = null; FileShare fsObj = null; Snapshot snapshotObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); _log.info(String.format( "Delete SMB share details --- name: %1$s, description: %2$s, permissionType: %3$s, permission: %4$s , maxUsers: %5$s ", smbShare.getName(), smbShare.getDescription(), smbShare.getPermissionType(), smbShare.getPermission(), (smbShare.getMaxUsers() > 0) ? smbShare.getMaxUsers() : "unlimited")); // get db object for smb share SMBFileShare smbFileShare = smbShare.getSMBFileShare(); FileDeviceInputOutput args = new FileDeviceInputOutput(); args.setShareName(smbShare.getName()); args.setOpId(opId); if (URIUtil.isType(uri, FileShare.class)) { fsObj = _dbClient.queryObject(FileShare.class, uri); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); fileObject = fsObj; args.addFSFileObject(fsObj); args.setFileOperation(true); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doDeleteShare(storageObj, args, smbFileShare); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(fsObj); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); List<SMBFileShare> shares = null; if (result.isCommandSuccess()) { SMBShareMap shareMap = fsObj.getSMBFileShares(); shares = new ArrayList<SMBFileShare>(shareMap.values()); deleteShareACLsFromDB(args); WorkflowStepCompleter.stepSucceded(opId); } else { shares = new ArrayList<SMBFileShare>(); shares.add(smbFileShare); } recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE, result.isCommandSuccess(), eventMsg, getShareNameExtensions(shares), fsObj, smbShare); } else { snapshotObj = _dbClient.queryObject(Snapshot.class, uri); fileObject = snapshotObj; args.addSnapshotFileObject(snapshotObj); args.setFileOperation(false); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doDeleteShare(storageObj, args, smbFileShare); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } snapshotObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(snapshotObj); fsObj = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); List<SMBFileShare> shares = null; if (result.isCommandSuccess()) { SMBShareMap shareMap = snapshotObj.getSMBFileShares(); shares = new ArrayList<SMBFileShare>(shareMap.values()); deleteShareACLsFromDB(args); WorkflowStepCompleter.stepSucceded(opId); } else { shares = new ArrayList<SMBFileShare>(); shares.add(smbFileShare); } recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE, result.isCommandSuccess(), eventMsg, getShareNameExtensions(shares), snapshotObj, fsObj, smbShare); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] params = { storage.toString(), uri.toString(), smbShare.getName(), e.getMessage() }; _log.error("Unable to delete file system or snapshot share: storage {}, FS/snapshot URI {}, SMB share {}: {}", params); updateTaskStatus(opId, fileObject, e); if (URIUtil.isType(uri, FileShare.class)) { if ((fsObj != null) && (storageObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE, false, e.getMessage(), "", fsObj, smbShare, storageObj); } } else { if ((fsObj != null) && (storageObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE, false, e.getMessage(), "", snapshotObj, fsObj, smbShare, storageObj); } } } } private void deleteShareACLsFromDB(FileDeviceInputOutput args) { List<CifsShareACL> existingDBAclList = queryDBShareAcls(args); List<CifsShareACL> deleteAclList = new ArrayList<CifsShareACL>(); _log.debug("Inside deleteShareACLsFromDB() to delete ACL of share {} from DB", args.getShareName()); for (Iterator<CifsShareACL> iterator = existingDBAclList.iterator(); iterator.hasNext();) { CifsShareACL cifsShareACL = iterator.next(); if (args.getShareName().equals(cifsShareACL.getShareName())) { cifsShareACL.setInactive(true); deleteAclList.add(cifsShareACL); } } if (!deleteAclList.isEmpty()) { _log.info("Deleting ACL of share {}", args.getShareName()); _dbClient.updateObject(deleteAclList); } } /** * Gets the list of SMB share names to be recorded as an extension in the * event for filesystem/snapshot share/deleteShare operations. The extension * is specified in the format: * * ExtensionName=name1, name2, ...,name3 * * @param smbFileShares * The list of file system SMB shares. * * @return extension names in the format as above */ private String getShareNameExtensions(List<SMBFileShare> smbFileShares) { StringBuilder strBuilder = new StringBuilder(); strBuilder.append(RecordableBourneEvent.FS_SHARE_EXTENSION_NAME); strBuilder.append("="); int i = smbFileShares.size(); for (SMBFileShare fileShare : smbFileShares) { strBuilder.append(fileShare.getName()); i--; if (i > 0) { strBuilder.append(","); } } return strBuilder.toString(); } @Override public void modifyFS(URI storage, URI pooluri, URI fsuri, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(fsuri, opId); FileShare fs = null; try { StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); FileDeviceInputOutput args = new FileDeviceInputOutput(); fs = _dbClient.queryObject(FileShare.class, fsuri); args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, pooluri); args.addStoragePool(pool); args.setFileOperation(true); args.setOpId(opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doModifyFS(storageObj, args); if (result.getCommandPending()) { // async operation return; } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); _log.info("FileSystem updated " + " with Soft Limit: " + args.getFsSoftLimit() + ", Notification Limit: " + args.getFsNotificationLimit() + ", Soft Grace: " + args.getFsSoftGracePeriod()); } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Set status fs.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(fs); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.UPDATE_FILE_SYSTEM, result.isCommandSuccess(), eventMsg, "", fs); } catch (Exception e) { _log.error("Unable to update file system: FS URI {}", fs.getId()); ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); updateTaskStatus(opId, fs, e); if (fs != null) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UPDATE_FILE_SYSTEM, false, e.getMessage(), "", fs); } } } @Override public void snapshotFS(URI storage, URI snapshot, URI fs, String task) throws ControllerException { ControllerUtils.setThreadLocalLogData(fs, task); FileShare fsObj = null; Snapshot snapshotObj = null; try { String[] params = { storage.toString(), snapshot.toString(), fs.toString() }; _log.info("Snapshot FS: storage : {}, snapshot : {}, fs : {}", params); FileDeviceInputOutput args = new FileDeviceInputOutput(); StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); fsObj = _dbClient.queryObject(FileShare.class, fs); snapshotObj = _dbClient.queryObject(Snapshot.class, snapshot); args.addFileShare(fsObj); args.addSnapshot(snapshotObj); StoragePool storagePool = _dbClient.queryObject(StoragePool.class, fsObj.getPool()); args.addStoragePool(storagePool); args.setOpId(task); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, task); WorkflowStepCompleter.stepExecuting(task); BiosCommandResult result = getDevice(storageObj.getSystemType()).doSnapshotFS(storageObj, args); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(task, result.getServiceCoded()); } snapshotObj.setCreationTime(Calendar.getInstance()); fsObj.getOpStatus().updateTaskStatus(task, result.toOperation()); snapshotObj.getOpStatus().updateTaskStatus(task, result.toOperation()); snapshotObj.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(_dbClient, snapshotObj)); // Incase error, set the snapshot to inactive state. if (!result.isCommandSuccess()) { _log.error("Snapshot create command is not successfull, so making object to inactive"); snapshotObj.setInactive(true); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(task); } _dbClient.updateObject(snapshotObj); _dbClient.updateObject(fsObj); fsObj = _dbClient.queryObject(FileShare.class, fs); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_SNAPSHOT, result.isCommandSuccess(), eventMsg, "", snapshotObj, fsObj); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(task, serviceError); String[] params = { storage.toString(), fs.toString(), snapshot.toString(), e.getMessage() }; _log.error("Unable to create file system snapshot: storage {}, FS {}, snapshot {}: {}", params); updateTaskStatus(task, fsObj, e); updateTaskStatus(task, snapshotObj, e); if ((fsObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_SNAPSHOT, false, e.getMessage(), "", snapshotObj, fsObj); } } } @Override public void restoreFS(URI storage, URI fs, URI snapshot, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(fs, opId); StorageSystem storageObj = null; FileShare fsObj = null; Snapshot snapshotObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); Operation op = null; try { String[] params = { storage.toString(), snapshot.toString(), fs.toString() }; _log.info("Restore FS: {} {} {}", params); storageObj = _dbClient.queryObject(StorageSystem.class, storage); fsObj = _dbClient.queryObject(FileShare.class, fs); snapshotObj = _dbClient.queryObject(Snapshot.class, snapshot); args.addFileShare(fsObj); args.addSnapshot(snapshotObj); args.setOpId(opId); WorkflowStepCompleter.stepExecuting(opId); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doRestoreFS(storageObj, args); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } op = result.toOperation(); snapshotObj.getOpStatus().updateTaskStatus(opId, op); fsObj.getOpStatus().updateTaskStatus(opId, op); _dbClient.updateObject(fsObj); _dbClient.updateObject(snapshotObj); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.RESTORE_FILE_SNAPSHOT, result.isCommandSuccess(), eventMsg, "", fsObj, snapshot); } catch (Exception e) { String[] params = { storage.toString(), fs.toString(), snapshot.toString(), e.getMessage() }; _log.error("Unable to restore file system from snapshot: storage {}, FS {}, snapshot {}: {}", params); ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); updateTaskStatus(opId, snapshotObj, e); if ((fsObj != null) && (snapshotObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.RESTORE_FILE_SNAPSHOT, false, e.getMessage(), "", fsObj, snapshotObj); } } if ((op != null) && (!(op.getStatus().equalsIgnoreCase(Operation.Status.error.name())))) { try { // Synchronize snapshot list in DB with the list on the device syncSnapshotList(storageObj, fsObj, args); } catch (Exception ex) { String[] params = { storage.toString(), fs.toString(), snapshot.toString() }; _log.warn( "Restore succeeded but failed to sync snapshot list in DB with list on the device: storage {}, FS {}, snapshot {}", params); } } } private void syncSnapshotList(StorageSystem storageObj, FileShare fsObj, FileDeviceInputOutput args) { // Retrieve all snapshots from DB that belong to this file system URIQueryResultList results = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(fsObj.getId()), results); // Setup snapshot name-object map Map<String, Snapshot> snapshotsInDB = new ConcurrentHashMap<String, Snapshot>(); while (results.iterator().hasNext()) { URI uri = results.iterator().next(); Snapshot snapObj = _dbClient.queryObject(Snapshot.class, uri); snapshotsInDB.put(snapObj.getName(), snapObj); } // Retrieve list of valid snapshot names from the device List<String> snapshotsOnDevice = new ArrayList<String>(); BiosCommandResult result = getDevice(storageObj.getSystemType()).getFSSnapshotList(storageObj, args, snapshotsOnDevice); Operation op = result.toOperation(); if (!op.getStatus().equalsIgnoreCase(Operation.Status.ready.name())) { _log.warn("The list of snapshots could not be retrieved from the device {}.", storageObj.getId()); } else { // Iterate through the snapshots in the DB and if name not found in // the list returned by the device, mark snapshot in DB as inactive Set<String> snapshotNames = snapshotsInDB.keySet(); for (String snapshotName : snapshotNames) { if (!snapshotsOnDevice.contains(snapshotName)) { snapshotsInDB.get(snapshotName).setInactive(true); _dbClient.updateObject(snapshotsInDB.get(snapshotName)); } } // Iterate through the snapshot list from device and if a // snapshot is found on the device but not in the DB, add the // newly discovered snapshot to the DB. } } private void updateTaskStatus(String opId, DataObject fsObj, Exception e) { final ServiceCoded serviceCoded; if ((opId == null) || (fsObj == null)) { return; } if (e instanceof ServiceCoded) { serviceCoded = (ServiceCoded) e; } else { serviceCoded = DeviceControllerException.errors.jobFailed(e); } final BiosCommandResult result = BiosCommandResult.createErrorResult(serviceCoded); fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); _dbClient.updateObject(fsObj); _log.debug("updateTaskStatus:afterUpdate:" + fsObj.getOpStatus().get(opId).toString()); } /** * Creates a connection to monitor events generated by the storage * identified by the passed URI. * * @param storage * A database client URI that identifies the storage to be * monitored. * * @throws ControllerException * When errors occur connecting the storage for * event monitoring. */ @Override public void connectStorage(URI storage) throws ControllerException { // Retrieve the storage device info from the database. StorageSystem storageObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); } catch (Exception e) { throw DeviceControllerException.exceptions.unableToConnectToStorageDeviceForMonitoringDbException( storage.toString(), e); } // Verify non-null storage device returned from the database client. if (storageObj == null) { throw DeviceControllerException.exceptions.unableToConnectToStorageDeviceForMonitoringDbNullRef( storage.toString()); } // Get the file device reference for the type of file device managed // by the controller. FileStorageDevice storageDevice = getDevice(storageObj.getSystemType()); if (storageDevice == null) { String devType = String.format("%1$s", storageDevice); throw DeviceControllerException.exceptions.unableToConnectToStorageDeviceForMonitoringNoDevice( storage.toString(), devType); } storageDevice.doConnect(storageObj); _log.info("Adding to storage device to work pool: {}", storageObj.getId()); } /** * Removes a connection that was previously established for monitoring * events from the storage identified by the passed URI. * * @param storage * A database client URI that identifies the storage to be * disconnected. * * @throws ControllerException * When errors occur disconnecting the storage * for event monitoring. */ @Override public void disconnectStorage(URI storage) throws ControllerException { // Retrieve the storage device info from the database. StorageSystem storageObj = null; try { storageObj = _dbClient.queryObject(StorageSystem.class, storage); } catch (Exception e) { throw DeviceControllerException.exceptions.unableToDisconnectStorageDeviceMonitoringDbException( storage.toString(), e); } // Verify non-null storage device returned from the database client. if (storageObj == null) { String msg = String.format("Failed disconnecting %1$s for monitoring. Database returned a null reference.", storage); _log.error(msg); throw DeviceControllerException.exceptions.unableToDisconnectStorageDeviceMonitoringDbNullRef( storage.toString()); } // Get the file device reference for the type of file device managed // by the controller. FileStorageDevice storageDevice = getDevice(storageObj.getSystemType()); if (storageDevice == null) { String devType = String.format("%1$s", getDevice(storageObj.getSystemType())); String msg = String.format("Failed disconnecting %1$s for monitoring. No device for type %2$s.", storage, devType); _log.error(msg); throw DeviceControllerException.exceptions.unableToDisconnectStorageDeviceMonitoringNoDevice( storage.toString(), devType); } storageDevice.doDisconnect(storageObj); _log.info("Removing storage device from work pool: {}", storageObj.getId()); } /** * Fail the task * * @param clazz * @param id * @param opId * @param serviceCoded */ private void doFailTask(Class<? extends DataObject> clazz, URI id, String opId, ServiceCoded serviceCoded) { try { _dbClient.error(clazz, id, opId, serviceCoded); } catch (DatabaseException ioe) { _log.error(ioe.getMessage()); } } @Override public void discoverStorageSystem(AsyncTask[] tasks) throws ControllerException { } @Override public void scanStorageProviders(AsyncTask[] tasks) throws ControllerException { } public static void recordFileDeviceOperation(DbClient dbClient, OperationTypeEnum opType, boolean opStatus, String evDesc, String extensions, Object... extParam) { String evType; if (evDesc == null || evDesc.isEmpty()) { evDesc = opType.getDescription(); } evType = opType.getEvType(opStatus); String opStage = AuditLogManager.AUDITOP_END; _log.info("opType: {} detail: {}", opType.toString(), evType + ':' + evDesc); FileShare fs = null; Snapshot snapshotObj = null; QuotaDirectory quotaDirObj = null; if (extParam[0] instanceof Snapshot) { snapshotObj = (Snapshot) extParam[0]; fs = (FileShare) extParam[1]; recordSnapshotEvent(dbClient, snapshotObj, fs, evType, evDesc, extensions); } else if (extParam[0] instanceof QuotaDirectory) { quotaDirObj = (QuotaDirectory) extParam[0]; fs = (FileShare) extParam[1]; recordQuotaDirectoryEvent(dbClient, quotaDirObj, fs, evType, evDesc, extensions); } else if (extParam[0] instanceof FileShare) { fs = (FileShare) extParam[0]; recordFsEvent(dbClient, fs, evType, evDesc, extensions); } else { _log.error("unrecognized param list"); } FileSMBShare smbShare = null; switch (opType) { case CREATE_FILE_SYSTEM: auditFile(dbClient, opType, opStatus, opStage, fs.getLabel(), fs.getVirtualArray().toString(), (fs.getProject() != null) ? fs.getProject().toString() : null); break; case DELETE_FILE_SYSTEM: auditFile(dbClient, opType, opStatus, opStage, fs.getId().toString(), ((StorageSystem) extParam[1]).getId().toString()); break; case DELETE_FILE_SNAPSHOT: auditFile(dbClient, opType, opStatus, opStage, snapshotObj.getId().toString(), ((StorageSystem) extParam[2]).getId().toString()); break; case EXPORT_FILE_SYSTEM: case UPDATE_EXPORT_RULES_FILE_SYSTEM: case UPDATE_FILE_SYSTEM_SHARE_ACL: case UNEXPORT_FILE_SYSTEM: auditFile(dbClient, opType, opStatus, opStage, fs.getId().toString(), ((StorageSystem) extParam[1]).getId().toString(), extensions); break; case EXPAND_FILE_SYSTEM: auditFile(dbClient, opType, opStatus, opStage, fs.getId().toString(), extParam[1]); break; case CREATE_FILE_SYSTEM_SHARE: case DELETE_FILE_SYSTEM_SHARE: smbShare = (FileSMBShare) extParam[1]; auditFile(dbClient, opType, opStatus, opStage, smbShare.getName(), smbShare.getPermissionType(), smbShare.getPermission(), smbShare.getMaxUsers(), smbShare.getDescription(), fs.getId().toString()); break; case RESTORE_FILE_SNAPSHOT: URI snapshot = (URI) extParam[1]; auditFile(dbClient, opType, opStatus, opStage, snapshot, fs.getId().toString()); break; case CREATE_FILE_SYSTEM_SNAPSHOT: auditFile(dbClient, opType, opStatus, opStage, snapshotObj.getLabel(), snapshotObj.getId(), fs.getId().toString()); break; case EXPORT_FILE_SNAPSHOT: case UPDATE_EXPORT_RULES_FILE_SNAPSHOT: case UPDATE_FILE_SNAPSHOT_SHARE_ACL: case UNEXPORT_FILE_SNAPSHOT: auditFile(dbClient, opType, opStatus, opStage, snapshotObj.getId().toString(), ((StorageSystem) extParam[2]).getId().toString(), extensions); break; case CREATE_FILE_SNAPSHOT_SHARE: case DELETE_FILE_SNAPSHOT_SHARE: smbShare = (FileSMBShare) extParam[2]; auditFile(dbClient, opType, opStatus, opStage, smbShare.getName(), smbShare.getPermissionType(), smbShare.getPermission(), smbShare.getMaxUsers(), smbShare.getDescription(), snapshotObj.getId().toString()); break; case CREATE_FILE_SYSTEM_QUOTA_DIR: case DELETE_FILE_SYSTEM_QUOTA_DIR: case UPDATE_FILE_SYSTEM_QUOTA_DIR: auditFile(dbClient, opType, opStatus, opStage, quotaDirObj.getLabel(), quotaDirObj.getId(), fs.getId().toString()); break; case DELETE_FILE_SYSTEM_SHARE_ACL: auditFile(dbClient, opType, opStatus, opStage, fs.getId().toString(), ((StorageSystem) extParam[1]).getId().toString(), extensions); break; case DELETE_FILE_SNAPSHOT_SHARE_ACL: auditFile(dbClient, opType, opStatus, opStage, snapshotObj.getId().toString(), ((StorageSystem) extParam[2]).getId().toString(), extensions); break; case ASSIGN_FILE_SYSTEM_SNAPSHOT_SCHEDULE: case UNASSIGN_FILE_SYSTEM_SNAPSHOT_SCHEDULE: auditFile(dbClient, opType, opStatus, opStage, fs.getId().toString(), ((SchedulePolicy) extParam[1]).getId().toString(), extensions); break; default: _log.error("unrecognized fileshare operation type"); } } @Override public void startMonitoring(AsyncTask task, Type deviceType) throws ControllerException { } @Override public void createQuotaDirectory(URI storage, FileShareQuotaDirectory quotaDir, URI fs, String task) throws ControllerException { ControllerUtils.setThreadLocalLogData(fs, task); FileShare fsObj = null; QuotaDirectory quotaDirObj = null; try { String[] params = { storage.toString(), fs.toString(), quotaDir.toString() }; _log.info("FileDeviceController::createQtree: create QuotaDirectory: storage : {}, quotaDir : {}, fs : {}", params); StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); fsObj = _dbClient.queryObject(FileShare.class, fs); URI qtreeURI = quotaDir.getId(); quotaDirObj = _dbClient.queryObject(QuotaDirectory.class, qtreeURI); FileDeviceInputOutput args = new FileDeviceInputOutput(); // Set up args args.addFileShare(fsObj); args.addQuotaDirectory(quotaDirObj); args.setOpId(task); FileStorageDevice nasDevice = getDevice(storageObj.getSystemType()); BiosCommandResult result = nasDevice.doCreateQuotaDirectory(storageObj, args, quotaDirObj); if (result.getCommandPending()) { return; } fsObj.getOpStatus().updateTaskStatus(task, result.toOperation()); quotaDirObj.getOpStatus().updateTaskStatus(task, result.toOperation()); String fsName = fsObj.getName(); quotaDirObj.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(_dbClient, quotaDirObj, fsName)); // In case of an error, set the quotaDir to an 'inactive' state. if (!result.isCommandSuccess()) { quotaDirObj.setInactive(true); _log.error("FileDeviceController::createQtree: QuotaDirectory create command is not successfull"); } _dbClient.updateObject(quotaDirObj); _dbClient.updateObject(fsObj); fsObj = _dbClient.queryObject(FileShare.class, fs); _log.debug( "FileDeviceController::createQtree: After QuotaDirectory created and fs persisted, Task Stauts {} -- Operation Details : {}", fsObj.getOpStatus().get(task).getStatus(), result.toOperation()); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_QUOTA_DIR, result.isCommandSuccess(), eventMsg, "", quotaDirObj, fsObj); } catch (Exception e) { String[] params = { storage.toString(), fs.toString(), quotaDir.toString(), e.getMessage() }; _log.error("FileDeviceController::createQtree: Unable to create file system quotaDir: storage {}, FS {}, snapshot {}: {}", params); updateTaskStatus(task, fsObj, e); updateTaskStatus(task, quotaDirObj, e); if ((fsObj != null) && (quotaDirObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_QUOTA_DIR, false, e.getMessage(), "", quotaDirObj, fsObj); } } } @Override public void updateQuotaDirectory(URI storage, FileShareQuotaDirectory quotaDir, URI fs, String task) throws ControllerException { ControllerUtils.setThreadLocalLogData(fs, task); FileShare fsObj = null; QuotaDirectory quotaDirObj = null; try { String[] params = { storage.toString(), fs.toString(), quotaDir.toString() }; _log.info("FileDeviceController::updateQtree: storage : {}, fs : {}, quotaDir : {}", params); StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); fsObj = _dbClient.queryObject(FileShare.class, fs); URI qtreeURI = quotaDir.getId(); quotaDirObj = _dbClient.queryObject(QuotaDirectory.class, qtreeURI); quotaDirObj.setSoftLimit(quotaDir.getSoftLimit()); quotaDirObj.setSoftGrace(quotaDir.getSoftGrace()); quotaDirObj.setNotificationLimit(quotaDir.getNotificationLimit()); FileDeviceInputOutput args = new FileDeviceInputOutput(); // Set up args args.addFileShare(fsObj); args.addQuotaDirectory(quotaDirObj); args.setOpId(task); FileStorageDevice nasDevice = getDevice(storageObj.getSystemType()); BiosCommandResult result = nasDevice.doUpdateQuotaDirectory(storageObj, args, quotaDirObj); if (result.getCommandPending()) { return; } fsObj.getOpStatus().updateTaskStatus(task, result.toOperation()); quotaDirObj.getOpStatus().updateTaskStatus(task, result.toOperation()); String fsName = fsObj.getName(); quotaDirObj.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(_dbClient, quotaDirObj, fsName)); if (!result.isCommandSuccess()) { _log.error("FileDeviceController::updateQtree: QuotaDirectory update command is not successfull"); } // save the task status into db _dbClient.updateObject(quotaDirObj); _dbClient.updateObject(fsObj); fsObj = _dbClient.queryObject(FileShare.class, fs); _log.debug( "FileDeviceController::updateQtree: After QuotaDirectory updated and fs persisted, Task Stauts {} -- Operation Details : {}", fsObj.getOpStatus().get(task).getStatus(), result.toOperation()); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.UPDATE_FILE_SYSTEM_QUOTA_DIR, result.isCommandSuccess(), eventMsg, "", quotaDirObj, fsObj); } catch (Exception e) { String[] params = { storage.toString(), fs.toString(), quotaDir.toString(), e.getMessage() }; _log.error("FileDeviceController::updateQtree: Unable to update file system quotaDir: storage {}, FS {}, snapshot {}: {}", params); updateTaskStatus(task, fsObj, e); updateTaskStatus(task, quotaDirObj, e); if ((fsObj != null) && (quotaDirObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.CREATE_FILE_SYSTEM_QUOTA_DIR, false, e.getMessage(), "", quotaDirObj, fsObj); } } } @Override public void deleteQuotaDirectory(URI storage, URI quotaDir, URI fs, String task) throws ControllerException { FileShare fsObj = null; QuotaDirectory quotaDirObj = null; try { String[] params = { storage.toString(), quotaDir.toString(), fs.toString() }; _log.info("FileDeviceController::deleteQuotaDirectory: storage : {}, quotadir : {}, fs : {}", params); StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); fsObj = _dbClient.queryObject(FileShare.class, fs); quotaDirObj = _dbClient.queryObject(QuotaDirectory.class, quotaDir); FileDeviceInputOutput args = new FileDeviceInputOutput(); String quotaName = quotaDirObj.getName(); args.addFSFileObject(fsObj); FSExportMap fsExportMap = fsObj.getFsExports(); boolean isExported = false; // delete export if (fsExportMap != null && !fsExportMap.isEmpty()) { // check the quota directory is exported for (FileExport fileExport : fsExportMap.values()) { if (quotaName.equals(fileExport.getSubDirectory()) && fileExport.getPath().endsWith(quotaName)) { isExported = true; _log.info("Delete the nfs sub directory export path {} and key {}", fileExport.getPath(), fileExport.getFileExportKey()); } } if (true == isExported) { // delete the export of quota directory this.deleteExportRules(storage, fs, false, quotaName, task); fsObj = _dbClient.queryObject(FileShare.class, fs); } } // delete fileshare of quota directory SMBShareMap smbShareMap = fsObj.getSMBFileShares(); if (smbShareMap != null && !smbShareMap.isEmpty()) { FileSMBShare fileSMBShare = null; List<FileSMBShare> fileSMBShares = new ArrayList<FileSMBShare>(); for (SMBFileShare smbFileShare : smbShareMap.values()) { // check for quotaname in native fs path if (true == (smbFileShare.getPath().endsWith(quotaName))) { fileSMBShare = new FileSMBShare(smbFileShare); _log.info("Delete the cifs sub directory path of quota directory {}", smbFileShare.getPath()); fileSMBShares.add(fileSMBShare); } } if (fileSMBShares != null && !fileSMBShares.isEmpty()) { // delete shares for (FileSMBShare tempFileSMBShare : fileSMBShares) { this.deleteShare(storage, fs, tempFileSMBShare, task); _log.info("Delete SMB Share Name{} for quota ", tempFileSMBShare.getName()); } } } fsObj = _dbClient.queryObject(FileShare.class, fs); // Set up args args.addFSFileObject(fsObj); args.addQuotaDirectory(quotaDirObj); args.setOpId(task); FileStorageDevice nasDevice = getDevice(storageObj.getSystemType()); BiosCommandResult result = nasDevice.doDeleteQuotaDirectory(storageObj, args); if (result.getCommandPending()) { return; } fsObj.getOpStatus().updateTaskStatus(task, result.toOperation()); quotaDirObj.getOpStatus().updateTaskStatus(task, result.toOperation()); String fsName = fsObj.getName(); quotaDirObj.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(_dbClient, quotaDirObj, fsName)); if (!result.isCommandSuccess()) { _log.error("FileDeviceController::deleteQuotaDirectory: command is not successfull"); } // save the task status in db _dbClient.updateObject(quotaDirObj); _dbClient.updateObject(fsObj); fsObj = _dbClient.queryObject(FileShare.class, fs); _log.debug( "FileDeviceController::deleteQuotaDirectory: After deleteQuotaDirectory created and fs persisted, Task Stauts {} -- Operation Details : {}", fsObj.getOpStatus().get(task).getStatus(), result.toOperation()); String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM_QUOTA_DIR, result.isCommandSuccess(), eventMsg, "", quotaDirObj, fsObj); } catch (Exception e) { String[] params = { storage.toString(), fs.toString(), quotaDir.toString(), e.getMessage() }; _log.error( "FileDeviceController::deleteQuotaDirectory: Unable to create file system quota dir: storage {}, FS {}, quotadir {}: {}", params); updateTaskStatus(task, fsObj, e); updateTaskStatus(task, quotaDirObj, e); if ((fsObj != null) && (quotaDirObj != null)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.DELETE_FILE_SYSTEM_QUOTA_DIR, false, e.getMessage(), "", quotaDirObj, fsObj); } } } @Override public void updateExportRules(URI storage, URI fsURI, FileExportUpdateParams param, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileObject fsObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; Snapshot snapshotObj = null; boolean isFile = false; try { StorageSystem storageObj = _dbClient.queryObject( StorageSystem.class, storage); args.setSubDirectory(param.getSubDir()); args.setAllExportRules(param); args.setBypassDnsCheck(param.getBypassDnsCheck()); _log.info("Controller Recieved FileExportUpdateParams {}", param); // File if (URIUtil.isType(fsURI, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fsURI); setVirtualNASinArgs(fs.getVirtualNAS(), args); fsObj = fs; args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } else { // Snapshot snapshotObj = _dbClient.queryObject(Snapshot.class, fsURI); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fs.getVirtualNAS(), args); args.addFileShare(fs); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } args.setFileOperation(isFile); args.setOpId(opId); // Query & Pass all Existing Exports args.setExistingDBExportRules(queryExports(args)); // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()).updateExportRules(storageObj, args); if (result.isCommandSuccess()) { // Update Database doCRUDExports(param, fs, args); // Delete the Export Map, if there are no exports. if ((args.getFileObjExports() != null) && (queryExports(args).isEmpty())) { args.getFileObjExports().clear(); _dbClient.updateObject(args.getFileObj()); } WorkflowStepCompleter.stepSucceded(opId); } if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = (isFile) ? OperationTypeEnum.EXPORT_FILE_SYSTEM : OperationTypeEnum.EXPORT_FILE_SNAPSHOT; fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getExportNewClientExtensions(param.retrieveAllExports()), fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getExportNewClientExtensions(param.retrieveAllExports()), snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] params = { storage.toString(), fsURI.toString() }; _log.error("Unable to export file system or snapshot: storage {}, FS/snapshot URI {}", params, e); _log.error("{}, {} ", e.getMessage(), e); updateTaskStatus(opId, fsObj, e); } } private FileExportRule getAvailableExportRule(FileExportRule exportRule, FileDeviceInputOutput args) throws URISyntaxException { String exportIndex = exportRule.getFsExportIndex(); if (!args.getFileOperation()) { exportIndex = exportRule.getSnapshotExportIndex(); } _log.info("Retriving DB Model using its index {}", exportIndex); FileExportRule rule = null; URIQueryResultList result = new URIQueryResultList(); if (!args.getFileOperation()) { _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getSnapshotExportRuleConstraint(exportIndex), result); } else { _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getFileExportRuleConstraint(exportIndex), result); } Iterator<URI> it = result.iterator(); while (it.hasNext()) { if (result.iterator().hasNext()) { rule = _dbClient.queryObject(FileExportRule.class, it.next()); if (rule != null && !rule.getInactive()) { _log.info("Existing DB Model found {}", rule); break; } } } return rule; } private List<ExportRule> queryExports(FileDeviceInputOutput args) { List<ExportRule> rules = null; try { ContainmentConstraint containmentConstraint; if (args.getFileOperation()) { FileShare fs = args.getFs(); _log.info("Querying all ExportRules Using FsId {}", fs.getId()); containmentConstraint = ContainmentConstraint.Factory.getFileExportRulesConstraint(fs.getId()); } else { URI snapshotId = args.getSnapshotId(); _log.info("Querying all ExportRules Using Snapshot Id {}", snapshotId); containmentConstraint = ContainmentConstraint.Factory.getSnapshotExportRulesConstraint(snapshotId); } List<FileExportRule> fileExportRules = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileExportRule.class, containmentConstraint); rules = new ArrayList<>(); for (FileExportRule fileExportRule : fileExportRules) { ExportRule rule = new ExportRule(); getExportRule(fileExportRule, rule); rules.add(rule); } } catch (Exception e) { _log.error("Error while querying {}", e); } return rules; } private List<FileExportRule> queryFileExports(FileDeviceInputOutput args) { List<FileExportRule> fileExportRules = null; try { ContainmentConstraint containmentConstraint; if (args.getFileOperation()) { FileShare fs = args.getFs(); _log.info("Querying all ExportRules Using FsId {}", fs.getId()); containmentConstraint = ContainmentConstraint.Factory.getFileExportRulesConstraint(fs.getId()); } else { URI snapshotId = args.getSnapshotId(); _log.info("Querying all ExportRules Using Snapshot Id {}", snapshotId); containmentConstraint = ContainmentConstraint.Factory.getSnapshotExportRulesConstraint(snapshotId); } fileExportRules = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileExportRule.class, containmentConstraint); } catch (Exception e) { _log.error("Error while querying {}", e); } return fileExportRules; } /* * private List<FileExportRule> queryFSDBExports(FileShare fs) * { * List<URI> exportIds = _dbClient.queryByConstraint(ContainmentConstraint. * Factory.getFileExportRulesConstraint(fs.getId())); * return _dbClient.queryObject(FileExportRule.class, exportIds); * * } */ private void getExportRule(FileExportRule orig, ExportRule dest) { dest.setFsID(orig.getFileSystemId()); dest.setSnapShotID(orig.getSnapshotId()); dest.setExportPath(orig.getExportPath()); dest.setSecFlavor(orig.getSecFlavor()); dest.setAnon(orig.getAnon()); dest.setReadOnlyHosts(orig.getReadOnlyHosts()); dest.setReadWriteHosts(orig.getReadWriteHosts()); dest.setRootHosts(orig.getRootHosts()); dest.setMountPoint(orig.getMountPoint()); dest.setDeviceExportId(orig.getDeviceExportId()); _log.info("Original FileExportRule {}", orig.toString()); _log.info("Destination ExportRule {}", dest.toString()); } private void copyPropertiesToSave(FileExportRule dest, ExportRule orig, FileShare fs, FileDeviceInputOutput args) { _log.info("Origin {}", orig.toString()); String exportPath = args.getExportPath(); // This export path is the one that is figured out at the device. // Make sure you set the path on args object while doing the operation. Check for // <Device>FileStorageDeviceXXX.java dest.setExportPath(exportPath); dest.setSecFlavor(orig.getSecFlavor()); dest.setAnon(orig.getAnon()); if (orig.getReadOnlyHosts() != null && !orig.getReadOnlyHosts().isEmpty()) { dest.setReadOnlyHosts(new StringSet(orig.getReadOnlyHosts())); _log.info("Read Only Hosts {}", dest.getReadOnlyHosts()); } if (orig.getReadWriteHosts() != null && !orig.getReadWriteHosts().isEmpty()) { dest.setReadWriteHosts(new StringSet(orig.getReadWriteHosts())); _log.info("Read Write Hosts {}", dest.getReadWriteHosts()); } if (orig.getRootHosts() != null && !orig.getRootHosts().isEmpty()) { dest.setRootHosts(new StringSet(orig.getRootHosts())); _log.info("Root hosts {}", dest.getRootHosts()); } // Set this always at the end -- Thats how the model is defined. if (!args.getFileOperation()) { dest.setSnapshotId(args.getSnapshotId()); } else { dest.setFileSystemId(fs.getId()); } // Figure out Storage Port Network id to build the mount point. StoragePort storagePort = _dbClient.queryObject(StoragePort.class, fs.getStoragePort()); String mountPoint = ExportUtils.getFileMountPoint(storagePort.getPortNetworkId(), exportPath); dest.setMountPoint(mountPoint); // dest.calculateExportRuleIndex(); if ((orig.getDeviceExportId() != null) && (!orig.getDeviceExportId().isEmpty())) { dest.setDeviceExportId(orig.getDeviceExportId()); } else if ((args.getObjIdOnDevice() != null) && (!args.getObjIdOnDevice().isEmpty())) { dest.setDeviceExportId(args.getObjIdOnDevice()); } // _log.info("New File Export Rule Object {}", dest); _log.info("Dest After {}", dest.toString()); } private void doDeleteExportRulesFromDB(boolean allDirs, String subDir, FileDeviceInputOutput args) throws Exception { // Query All Export Rules Specific to a File System. // queryExports List<FileExportRule> exports = queryFileExports(args); if (exports != null && !exports.isEmpty()) { if (allDirs) { // ALl EXPORTS _log.info("Doing CRUD Operations on all DB FileExportRules for requested fs"); for (FileExportRule rule : exports) { _log.info("Deleting export rule from DB having path {} - Rule :{}", rule.getExportPath(), rule); rule.setInactive(true); _dbClient.updateObject(rule); } } else if (subDir != null && !subDir.isEmpty()) { // Filter for a specific Sub Directory export _log.info("Doing CRUD Operations on DB FileExportRules Specific to SubDirectory {}", subDir); for (FileExportRule rule : exports) { if (rule.getExportPath().endsWith("/" + subDir)) { _log.info("Deleting Subdiretcory export rule from DB having path {} - Rule :{}", rule.getExportPath(), rule); rule.setInactive(true); _dbClient.updateObject(rule); } } } else { // Filter for No SUBDIR - main export rules with no sub dirs for (FileExportRule rule : exports) { if (args.getFileOperation() && rule.getExportPath().equalsIgnoreCase(args.getFsPath())) { _log.info("Deleting export rule from DB having path {} - Rule :{}", rule.getExportPath(), rule); rule.setInactive(true); _dbClient.updateObject(rule); } else if (args.getFileOperation() == false && rule.getExportPath().equalsIgnoreCase(args.getSnapshotPath())) { _log.info("Deleting snapshot export rule from DB having path {} - Rule :{}", rule.getExportPath(), rule); rule.setInactive(true); _dbClient.updateObject(rule); } } } } } /** * Delete the reference of FileShare from SchedulePolicy * * @param fs */ private void doDeletePolicyReferenceFromDB(FileShare fs) { _log.info("Removing policy reference for file system " + fs.getName()); for (String policy : fs.getFilePolicies()) { SchedulePolicy fp = _dbClient.queryObject(SchedulePolicy.class, URI.create(policy)); StringSet fsURIs = fp.getAssignedResources(); fsURIs.remove(fs.getId().toString()); fp.setAssignedResources(fsURIs); _dbClient.updateObject(fp); } } private void doDeleteSnapshotsFromDB(FileShare fs, boolean allDirs, String subDir, FileDeviceInputOutput args) throws Exception { _log.info(" Setting Snapshots to InActive with Force Delete "); URIQueryResultList snapIDList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(fs.getId()), snapIDList); _log.info("getSnapshots: FS {}: {} ", fs.getId().toString(), snapIDList.toString()); List<Snapshot> snapList = _dbClient.queryObject(Snapshot.class, snapIDList); args.setFileOperation(false);// Set this as snapshot operation to delete only snapshots. if (snapList != null && !snapList.isEmpty()) { for (Snapshot snapshot : snapList) { _log.info("Marking Snapshot as InActive Snapshot Id {} Fs Id : {}", snapshot.getId(), snapshot.getParent()); snapshot.setInactive(true); args.addSnapshot(snapshot); doDeleteExportRulesFromDB(true, null, args); deleteShareACLsFromDB(args); _dbClient.updateObject(snapshot); } } args.setFileOperation(true); // restoring back } private void doCRUDExports(FileExportUpdateParams param, FileShare fs, FileDeviceInputOutput args) throws Exception { try { // create new exports ExportRules exportRules = param.getExportRulesToAdd(); List<ExportRule> rules; if (exportRules != null) { rules = exportRules.getExportRules(); if (rules != null && !rules.isEmpty()) { for (ExportRule exportRule : rules) { FileExportRule rule = new FileExportRule(); rule.setId(URIUtil.createId(FileExportRule.class)); copyPropertiesToSave(rule, exportRule, fs, args); _log.info("Storing New DB Export Rule {}", rule); _dbClient.createObject(rule); } } } // Modify Existing Exports exportRules = param.getExportRulesToModify(); if (exportRules != null) { rules = exportRules.getExportRules(); if (rules != null && !rules.isEmpty()) { for (ExportRule exportRule : rules) { FileExportRule rule = new FileExportRule(); // Copy the properties to build the index id to query DB for existing Export Rule copyPropertiesToSave(rule, exportRule, fs, args); rule = getAvailableExportRule(rule, args); // Remove the existing and create the new one. // Don't Update the existing one as persist object will create a new StringSet rather // it updates the existing one with new information and upon keeping/appending to old one. rule.setInactive(true); _log.info("Removing Existing DB Export Rule {}", rule); _dbClient.updateObject(rule); FileExportRule newRule = new FileExportRule(); newRule.setId(URIUtil.createId(FileExportRule.class)); // Now, Copy the properties again into the rule came out of DB, before updating. copyPropertiesToSave(newRule, exportRule, fs, args); _log.info("Storing New DB Export Rule {}", newRule); _dbClient.createObject(newRule); } } } // Delete Existing Exports exportRules = param.getExportRulesToDelete(); if (exportRules != null) { rules = exportRules.getExportRules(); if (rules != null && !rules.isEmpty()) { for (ExportRule exportRule : rules) { FileExportRule rule = new FileExportRule(); copyPropertiesToSave(rule, exportRule, fs, args); rule = getAvailableExportRule(rule, args); rule.setInactive(true); _log.info("Marking DB Export Rule Inactive {}", rule); _dbClient.updateObject(rule); } } // Delete the ExportMap entry if there are no export rules for this file system or sub directory FSExportMap fsNFSExportMap = fs.getFsExports(); ContainmentConstraint containmentConstraint = ContainmentConstraint.Factory.getFileExportRulesConstraint(fs.getId()); List<FileExportRule> fileExportRules = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileExportRule.class, containmentConstraint); Set<String> fileExportMapKeys = fsNFSExportMap.keySet(); Iterator<String> keySetIterator = fileExportMapKeys.iterator(); HashSet<String> keystoRemove = new HashSet<String>(); while (keySetIterator.hasNext()) { String fileExportMapKey = keySetIterator.next(); FileExport fileExport = fsNFSExportMap.get(fileExportMapKey); boolean exportRuleExists = false; for (FileExportRule fileExportRule : fileExportRules) { if (fileExportRule.getExportPath().equals(fileExport.getMountPath())) { exportRuleExists = true; break; } } if (!exportRuleExists) { keystoRemove.add(fileExportMapKey); } } for (String key : keystoRemove) { _log.info("Deleting file export map entry : {} for key : {}", fsNFSExportMap.get(key), key); fsNFSExportMap.remove(key); } _dbClient.updateObject(fs); } } catch (Exception e) { _log.info("Error While executing CRUD Operations {}", e); } } /** * Gets the list of export clients to be recorded as an extension in the * event for FileSystem/snapshot export/unexport operations. The extension * is specified in the format: * * ExtensionName=client1, client2, ..., client3 * * @param fExports * The list of FileSystem export maps. * * @return A string specifying export/unexport clients. */ private String getExportNewClientExtensions(List<ExportRule> fExports) { if (fExports == null || fExports.isEmpty()) { return ""; } StringBuilder strBuilder = new StringBuilder(); int exportSize = fExports.size(); if (exportSize > 0) { strBuilder.append(RecordableBourneEvent.FS_CLIENT_EXTENSION_NAME); strBuilder.append("="); // List<String> clients = new ArrayList<String>(); List<String> ro = new ArrayList<String>(); List<String> rw = new ArrayList<String>(); List<String> root = new ArrayList<String>(); for (int i = 0; i < exportSize; i++) { if (fExports.get(i) != null && fExports.get(i).getReadOnlyHosts() != null) { ro.addAll(fExports.get(i).getReadOnlyHosts()); // clients.addAll(fExports.get(i).getReadOnlyHosts()); } if (fExports.get(i) != null && fExports.get(i).getReadWriteHosts() != null) { rw.addAll(fExports.get(i).getReadWriteHosts()); // clients.addAll(fExports.get(i).getReadWriteHosts()); } if (fExports.get(i) != null && fExports.get(i).getRootHosts() != null) { root.addAll(fExports.get(i).getRootHosts()); // clients.addAll(fExports.get(i).getRootHosts()); } } StringBuilder allROhosts = new StringBuilder("ReadOnly Hosts : ["); for (String roClient : ro) { allROhosts.append(roClient).append(","); } allROhosts.append(" ]"); StringBuilder allRWhosts = new StringBuilder("ReadWrite Hosts : ["); for (String rwClient : rw) { allRWhosts.append(rwClient).append(","); } allRWhosts.append(" ]"); StringBuilder allROOThosts = new StringBuilder("Root Hosts : ["); for (String rootClient : root) { allROOThosts.append(rootClient).append(","); } allROOThosts.append(" ]"); strBuilder.append(allROhosts).append(allRWhosts).append(allROOThosts); } return strBuilder.toString(); } private String getNewACLExtensions(List<ShareACL> acls) { if (acls == null || acls.isEmpty()) { return ""; } StringBuilder strBuilder = new StringBuilder(); int aclSize = acls.size(); if (aclSize > 0) { strBuilder.append(RecordableBourneEvent.FS_ACL_EXTENSION_NAME); strBuilder.append("="); strBuilder.append(acls); } return strBuilder.toString(); } @Override public void deleteExportRules(URI storage, URI fileUri, boolean allDirs, String subDir, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(fileUri, opId); FileObject fsObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; Snapshot snapshotObj = null; StorageSystem storageObj = null; boolean isFile = false; try { storageObj = _dbClient.queryObject( StorageSystem.class, storage); // File if (URIUtil.isType(fileUri, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fileUri); setVirtualNASinArgs(fs.getVirtualNAS(), args); fsObj = fs; args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); args.setAllDir(allDirs); args.setSubDirectory(subDir); } else { // Snapshot snapshotObj = _dbClient.queryObject(Snapshot.class, fileUri); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fs.getVirtualNAS(), args); args.addFileShare(fs); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); args.setAllDir(true); args.setSubDirectory(null); } args.setFileOperation(isFile); args.setOpId(opId); List<ExportRule> existingExportRules = queryExports(args); args.setExistingDBExportRules(existingExportRules); // Do the Operation on device. _log.info("Delete Export Rules : request received for {}, with allDirs : {}, subDir : {}", new Object[] { fs.getId(), allDirs, subDir }); acquireStepLock(storageObj, opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()) .deleteExportRules(storageObj, args); if (result.isCommandSuccess()) { // Update Database doDeleteExportRulesFromDB(allDirs, subDir, args); doDeleteExportsFromFSObjMap(allDirs, subDir, args); WorkflowStepCompleter.stepSucceded(opId); } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Audit & Update the task status String eventMsg = result.isCommandSuccess() ? "" : result.getMessage(); fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); if (isFile) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UNEXPORT_FILE_SYSTEM, result.isCommandSuccess(), eventMsg, "", fs, storageObj); } else { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, result.isCommandSuccess(), eventMsg, "", snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] params = { storage.toString(), fileUri.toString() }; _log.error("Unable to export file system or snapshot: storage {}, FS/snapshot URI {}", params); if ((fsObj != null) && (storageObj != null)) { if (URIUtil.isType(fileUri, FileShare.class)) { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UNEXPORT_FILE_SYSTEM, false, e.getMessage(), "", fs, storageObj); } else { recordFileDeviceOperation(_dbClient, OperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, false, e.getMessage(), "", snapshotObj, fs, storageObj); } } updateTaskStatus(opId, fsObj, e); } } private void doDeleteExportsFromFSObjMap(boolean allDirs, String subDir, FileDeviceInputOutput args) throws Exception { // Query All Export Rules Specific to a File System. // Update the FS ExportMap // Remove Export FileObject fsObj = null; if (args.getFileOperation()) { fsObj = args.getFs(); } else { fsObj = args.getFileSnapshot(); } FSExportMap map = args.getFileObjExports(); if ((map == null) || (map.isEmpty())) { return; } Collection<FileExport> fileExports = map.values(); List<String> filexportKeys = new ArrayList<>(); if (allDirs) { // ALl EXPORTS // to avoid current exception, prepare seperate delete list for (FileExport fileExport : fileExports) { filexportKeys.add(fileExport.getFileExportKey()); } // then remove keys _log.info("Removing all exports from the export map"); for (String filexportKey : filexportKeys) { fsObj.getFsExports().remove(filexportKey); _log.info("FileShareExport removed : " + filexportKey); } _dbClient.updateObject(fsObj); } else if (subDir != null && !subDir.isEmpty()) { _log.info("Removing FileExport Specific to SubDirectory from Export Map {}", subDir); // Filter for a specific Sub Directory export // to avoid current exception, prepare seperate delete list for (FileExport fileExport : fileExports) { if (fileExport.getSubDirectory().equalsIgnoreCase(subDir)) { filexportKeys.add(fileExport.getFileExportKey()); } } for (String filexportKey : filexportKeys) { fsObj.getFsExports().remove(filexportKey); _log.info("FileShareExport removed : " + filexportKey); } _dbClient.updateObject(fsObj); } else { // Filter for No SUBDIR - main export rules with no sub dirs _log.info("Removing All FileExports other than SubDirectory exports from Export Map"); // to avoid current exception, prepare seperate delete list for (FileExport fileExport : fileExports) { if (fileExport.getSubDirectory() == null || (fileExport.getSubDirectory() != null && fileExport.getSubDirectory().isEmpty())) { filexportKeys.add(fileExport.getFileExportKey()); } } // remove the filesystem keys for (String filexportKey : filexportKeys) { fsObj.getFsExports().remove(filexportKey); _log.info("FileShareExport removed : " + filexportKey); } _dbClient.updateObject(fsObj); } } private FileExportRule getFileExportRule(URI uri, FileExport fileExport, FileDeviceInputOutput args) { FileExportRule rule = new FileExportRule(); rule.setAnon(fileExport.getRootUserMapping()); rule.setExportPath(fileExport.getPath()); if (!args.getFileOperation()) { rule.setSnapshotId(uri); } else { rule.setFileSystemId(uri); } rule.setSecFlavor(fileExport.getSecurityType()); if (fileExport.getPermissions().equals(FileShareExport.Permissions.ro.name()) && fileExport.getClients() != null && !fileExport.getClients().isEmpty()) { rule.setReadOnlyHosts(new StringSet(fileExport.getClients())); } if (fileExport.getPermissions().equals(FileShareExport.Permissions.rw.name()) && fileExport.getClients() != null && !fileExport.getClients().isEmpty()) { rule.setReadWriteHosts(new StringSet(fileExport.getClients())); } if (fileExport.getPermissions().equals(FileShareExport.Permissions.root.name()) && fileExport.getClients() != null && !fileExport.getClients().isEmpty()) { rule.setRootHosts(new StringSet(fileExport.getClients())); } rule.setMountPoint(fileExport.getMountPoint()); // _log.info("Generating FileExportRule IsilonId ? {}", fileExport.getIsilonId()); if (fileExport.getIsilonId() != null) { rule.setDeviceExportId(fileExport.getIsilonId()); } if (fileExport.getNativeId() != null) { rule.setDeviceExportId(fileExport.getNativeId()); } return rule; } @Override public void updateShareACLs(URI storage, URI fsURI, String shareName, CifsShareACLUpdateParams param, String opId) throws ControllerException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileObject fsObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; Snapshot snapshotObj = null; boolean isFile = false; _log.info("Controller recieved request to update ACL of share {}: cifsShareACLUpdateParams {}", shareName, param); try { StorageSystem storageObj = _dbClient.queryObject( StorageSystem.class, storage); args.setAllShareAcls(param); args.setShareName(shareName); // File if (URIUtil.isType(fsURI, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fsURI); setVirtualNASinArgs(fs.getVirtualNAS(), args); fsObj = fs; args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } else { // Snapshot snapshotObj = _dbClient.queryObject(Snapshot.class, fsURI); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fs.getVirtualNAS(), args); args.addFileShare(fs); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } args.setFileOperation(isFile); args.setOpId(opId); // Query for existing ACLs args.setExistingShareAcls(queryExistingShareAcls(args)); // Do the Operation on device. // Acquire lock for VNXFILE Storage System acquireStepLock(storageObj, opId); WorkflowStepCompleter.stepExecuting(opId); BiosCommandResult result = getDevice(storageObj.getSystemType()) .updateShareACLs(storageObj, args); if (result.isCommandSuccess()) { // Update database updateShareACLsInDB(param, fs, args); WorkflowStepCompleter.stepSucceded(opId); } if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = (isFile) ? OperationTypeEnum.UPDATE_FILE_SYSTEM_SHARE_ACL : OperationTypeEnum.UPDATE_FILE_SNAPSHOT_SHARE_ACL; fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result .getMessage(); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getNewACLExtensions(param.retrieveAllACLs()), fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, getNewACLExtensions(param.retrieveAllACLs()), snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] logParams = { storage.toString(), fsURI.toString() }; _log.error("Unable to update share ACL for file system or snapshot: storage {}, FS/snapshot URI {}", logParams, e); _log.error("{}, {} ", e.getMessage(), e); updateTaskStatus(opId, fsObj, e); } } private void updateShareACLsInDB(CifsShareACLUpdateParams param, FileShare fs, FileDeviceInputOutput args) { try { // Create new Acls ShareACLs shareAcls = param.getAclsToAdd(); List<ShareACL> shareAclList = null; if (shareAcls != null) { shareAclList = shareAcls.getShareACLs(); if (shareAclList != null && !shareAclList.isEmpty()) { for (ShareACL acl : shareAclList) { CifsShareACL dbShareAcl = new CifsShareACL(); dbShareAcl.setId(URIUtil.createId(CifsShareACL.class)); copyPropertiesToSave(acl, dbShareAcl, fs, args); _log.info("Storing new acl in DB: {}", dbShareAcl); _dbClient.createObject(dbShareAcl); } } } // Modify existing acls shareAcls = param.getAclsToModify(); if (shareAcls != null) { shareAclList = shareAcls.getShareACLs(); if (shareAclList != null && !shareAclList.isEmpty()) { for (ShareACL acl : shareAclList) { CifsShareACL dbShareAcl = new CifsShareACL(); copyPropertiesToSave(acl, dbShareAcl, fs, args); CifsShareACL dbShareAclTemp = getExistingShareAclFromDB(dbShareAcl, args); dbShareAcl.setId(dbShareAclTemp.getId()); _log.info("Updating acl in DB: {}", dbShareAcl); _dbClient.updateObject(dbShareAcl); } } } // Delete existing acls shareAcls = param.getAclsToDelete(); if (shareAcls != null) { shareAclList = shareAcls.getShareACLs(); if (shareAclList != null && !shareAclList.isEmpty()) { for (ShareACL acl : shareAclList) { CifsShareACL dbShareAcl = new CifsShareACL(); copyPropertiesToSave(acl, dbShareAcl, fs, args); CifsShareACL dbShareAclTemp = getExistingShareAclFromDB(dbShareAcl, args); dbShareAcl.setId(dbShareAclTemp.getId()); dbShareAcl.setInactive(true); _log.info("Marking acl inactive in DB: {}", dbShareAcl); _dbClient.updateObject(dbShareAcl); } } } } catch (Exception e) { _log.error("Error While executing CRUD Operations {}", e); } } private CifsShareACL getExistingShareAclFromDB(CifsShareACL dbShareAcl, FileDeviceInputOutput args) { CifsShareACL acl = null; String index = null; URIQueryResultList result = new URIQueryResultList(); if (args.getFileOperation()) { index = dbShareAcl.getFileSystemShareACLIndex(); _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getFileSystemShareACLConstraint(index), result); } else { index = dbShareAcl.getSnapshotShareACLIndex(); _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getSnapshotShareACLConstraint(index), result); } Iterator<URI> it = result.iterator(); while (it.hasNext()) { if (result.iterator().hasNext()) { acl = _dbClient.queryObject(CifsShareACL.class, it.next()); if (acl != null && !acl.getInactive()) { _log.info("Existing ACE found in DB: {}", acl); return acl; } } } return null; } private void copyPropertiesToSave(ShareACL acl, CifsShareACL dbShareAcl, FileShare fs, FileDeviceInputOutput args) { dbShareAcl.setShareName(args.getShareName()); if (acl.getGroup() != null) { dbShareAcl.setGroup(acl.getGroup()); } if (acl.getUser() != null) { dbShareAcl.setUser(acl.getUser()); } if (acl.getPermission() != null) { dbShareAcl.setPermission(acl.getPermission()); } if (acl.getDomain() != null) { dbShareAcl.setDomain(acl.getDomain()); } if (args.getFileOperation()) { dbShareAcl.setFileSystemId(fs.getId()); } else { dbShareAcl.setSnapshotId(args.getSnapshotId()); } } /** * Create the DB object from the NfsACE object * * @param ace * given NfsACE object * @param dbShareAcl * DB object need to be formed * @param fs * FileShare object * @param args * FileDeviceInputOutput object */ private void copyToPersistNfsACL(NfsACE ace, NFSShareACL dbShareAcl, FileShare fs, FileDeviceInputOutput args) { if (args.getFileSystemPath() != null) { String path = args.getFileSystemPath(); if (args.getSubDirectory() != null && !args.getSubDirectory().isEmpty()) { path = path + "/" + args.getSubDirectory(); } dbShareAcl.setFileSystemPath(path); } if (ace.getUser() != null) { dbShareAcl.setUser(ace.getUser()); } if (ace.getType() != null) { dbShareAcl.setType(ace.getType()); } if (ace.getDomain() != null) { dbShareAcl.setDomain(ace.getDomain()); } if (args.getFileOperation()) { dbShareAcl.setFileSystemId(fs.getId()); } else { dbShareAcl.setSnapshotId(args.getSnapshotId()); } if (ace.getPermissions() != null) { dbShareAcl.setPermissions(ace.getPermissions()); } if (ace.getPermissionType() != null) { dbShareAcl.setPermissionType(ace.getPermissionType()); } } /** * Get the DB object to modify it * * @param dbShareAcl * the DB object which need to be searched * @param isFile * it is file or snapshot operation * @return */ private NFSShareACL getExistingNfsAclFromDB(NFSShareACL dbShareAcl, boolean isFile) { NFSShareACL acl = null; String index = null; URIQueryResultList result = new URIQueryResultList(); if (isFile) { index = dbShareAcl.getFileSystemNfsACLIndex(); _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getFileSystemNfsACLConstraint(index), result); } else { index = dbShareAcl.getSnapshotNfsACLIndex(); _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getSnapshotNfsACLConstraint(index), result); } Iterator<URI> it = result.iterator(); while (it.hasNext()) { acl = _dbClient.queryObject(NFSShareACL.class, it.next()); if (acl != null && !acl.getInactive()) { _log.info("Existing ACE found in DB: {}", acl); return acl; } } return null; } private List<CifsShareACL> queryDBShareAcls(FileDeviceInputOutput args) { List<CifsShareACL> acls = new ArrayList<CifsShareACL>(); try { ContainmentConstraint containmentConstraint = null; if (args.getFileOperation()) { FileShare fs = args.getFs(); _log.info("Querying DB for Share ACLs of share {} of filesystemId {} ", args.getShareName(), fs.getId()); containmentConstraint = ContainmentConstraint.Factory.getFileCifsShareAclsConstraint(fs.getId()); } else { URI snapshotId = args.getSnapshotId(); _log.info("Querying DB for Share ACLs of share {} of snapshotId {} ", args.getShareName(), snapshotId); containmentConstraint = ContainmentConstraint.Factory.getSnapshotCifsShareAclsConstraint(snapshotId); } List<CifsShareACL> shareAclList = CustomQueryUtility.queryActiveResourcesByConstraint( _dbClient, CifsShareACL.class, containmentConstraint); Iterator<CifsShareACL> shareAclIter = shareAclList.iterator(); while (shareAclIter.hasNext()) { CifsShareACL shareAcl = shareAclIter.next(); if (shareAcl != null && args.getShareName().equals(shareAcl.getShareName())) { acls.add(shareAcl); } } } catch (Exception e) { _log.error("Error while querying DB for ACL(s) of a share {}", e); } return acls; } private boolean snapshotsExistsOnFS(FileShare fs) { URIQueryResultList snapIDList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory .getFileshareSnapshotConstraint(fs.getId()), snapIDList); _log.info("getSnapshots: FS {}: {} ", fs.getId().toString(), snapIDList.toString()); List<Snapshot> snapList = _dbClient.queryObject( Snapshot.class, snapIDList); if (snapList != null) { _log.info(" No of Snapshots on FS {} ", snapList.size()); for (Snapshot snapshot : snapList) { if (!snapshot.getInactive()) { return true; } } } return false; } private boolean quotaDirectoriesExistsOnFS(FileShare fs) { _log.info(" Setting Snapshots to InActive with Force Delete "); URIQueryResultList qdIDList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory .getQuotaDirectoryConstraint(fs.getId()), qdIDList); _log.info("getQuotaDirectories : FS {}: {} ", fs.getId().toString(), qdIDList.toString()); List<QuotaDirectory> qdList = _dbClient.queryObject( QuotaDirectory.class, qdIDList); if (qdList != null) { for (QuotaDirectory qd : qdList) { if (!qd.getInactive()) { return true; } } } return false; } private List<ShareACL> queryExistingShareAcls(FileDeviceInputOutput args) { _log.info("Querying for Share ACLs of share {}", args.getShareName()); List<ShareACL> acls = new ArrayList<ShareACL>(); try { List<CifsShareACL> dbShareAclList = queryDBShareAcls(args); Iterator<CifsShareACL> dbShareAclIter = dbShareAclList.iterator(); while (dbShareAclIter.hasNext()) { CifsShareACL dbShareAcl = dbShareAclIter.next(); ShareACL shareAcl = new ShareACL(); shareAcl.setDomain(dbShareAcl.getDomain()); if (args.getFileOperation()) { shareAcl.setFileSystemId(dbShareAcl.getFileSystemId()); } else { shareAcl.setSnapshotId(dbShareAcl.getSnapshotId()); } shareAcl.setGroup(dbShareAcl.getGroup()); shareAcl.setPermission(dbShareAcl.getPermission()); shareAcl.setShareName(dbShareAcl.getShareName()); shareAcl.setUser(dbShareAcl.getUser()); acls.add(shareAcl); } } catch (Exception e) { _log.error("Error while querying ACL(s) of a share {}", e); } return acls; } @Override public void deleteShareACLs(URI storage, URI fsURI, String shareName, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileObject fsObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; Snapshot snapshotObj = null; boolean isFile = false; _log.info("Controller recieved request to delete share ACL for share {}", shareName); try { StorageSystem storageObj = _dbClient.queryObject( StorageSystem.class, storage); args.setShareName(shareName); // File if (URIUtil.isType(fsURI, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fsURI); setVirtualNASinArgs(fs.getVirtualNAS(), args); fsObj = fs; args.addFSFileObject(fs); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } else { // Snapshot snapshotObj = _dbClient.queryObject(Snapshot.class, fsURI); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); setVirtualNASinArgs(fs.getVirtualNAS(), args); args.addFileShare(fs); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } args.setFileOperation(isFile); args.setOpId(opId); // query and setExistingShare ACL args.setExistingShareAcls(queryExistingShareAcls(args)); // Acquire lock for VNXFILE Storage System WorkflowStepCompleter.stepExecuting(opId); acquireStepLock(storageObj, opId); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .deleteShareACLs(storageObj, args); if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); // Update database deleteShareACLsFromDB(args); } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.getCommandPending()) { return; } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = (isFile) ? OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE_ACL : OperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE_ACL; fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result .getMessage(); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, shareName, fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, shareName, snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] logParams = { storage.toString(), fsURI.toString() }; _log.error("Unable to delete share ACL for file system or snapshot: storage {}, FS/snapshot URI {}", logParams, e); _log.error("{}, {} ", e.getMessage(), e); updateTaskStatus(opId, fsObj, e); } } /** * Creates default share ACE for fileshares on VNXe, VXFile and Datadomain * * @param id * URI of filesystem or snapshot * @param fileShare * @param storageType */ private void createDefaultACEForSMBShare(URI id, FileSMBShare fileShare, String storageType) { StorageSystem.Type storageSystemType = StorageSystem.Type.valueOf(storageType); if (storageSystemType.equals(Type.vnxe) || storageSystemType.equals(Type.vnxfile) || storageSystemType.equals(Type.datadomain)) { SMBFileShare share = fileShare.getSMBFileShare(); CifsShareACL ace = new CifsShareACL(); ace.setUser(FileControllerConstants.CIFS_SHARE_USER_EVERYONE); String permission = null; switch (share.getPermission()) { case "read": permission = FileControllerConstants.CIFS_SHARE_PERMISSION_READ; break; case "change": permission = FileControllerConstants.CIFS_SHARE_PERMISSION_CHANGE; break; case "full": permission = FileControllerConstants.CIFS_SHARE_PERMISSION_FULLCONTROL; break; } ace.setPermission(permission); ace.setId(URIUtil.createId(CifsShareACL.class)); ace.setShareName(share.getName()); if (URIUtil.isType(id, FileShare.class)) { ace.setFileSystemId(id); } else { ace.setSnapshotId(id); } _log.info("Creating default ACE for the share: {}", ace); _dbClient.createObject(ace); } } @Override public void updateNFSAcl(URI storage, URI fsURI, NfsACLUpdateParams param, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileObject fsObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; Snapshot snapshotObj = null; boolean isFile = false; try { StorageSystem storageObj = _dbClient.queryObject( StorageSystem.class, storage); args.setSubDirectory(param.getSubDir()); args.setAllNfsAcls(param); _log.info("Controller Recieved NfsACLUpdateParams {}", param); // File if (URIUtil.isType(fsURI, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fsURI); fsObj = fs; args.addFSFileObject(fs); args.setFileSystemPath(fs.getPath()); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } else { // Snapshot snapshotObj = _dbClient.queryObject(Snapshot.class, fsURI); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); args.addFileShare(fs); args.setFileSystemPath(fs.getPath()); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } args.setFileOperation(isFile); args.setOpId(opId); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .updateNfsACLs(storageObj, args); if (result.isCommandSuccess()) { // Update Database updateNFSACLsInDB(param, fs, args); WorkflowStepCompleter.stepSucceded(opId); } if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = (isFile) ? OperationTypeEnum.UPDATE_FILE_SYSTEM_NFS_ACL : OperationTypeEnum.UPDATE_FILE_SNAPSHOT_NFS_ACL; fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result .getMessage(); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, args.getFileSystemPath(), fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, args.getFileSystemPath(), snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); String[] params = { storage.toString(), fsURI.toString() }; _log.error("Unable to set ACL on file system or snapshot: storage {}, FS/snapshot URI {}", params, e); _log.error("{}, {} ", e.getMessage(), e); updateTaskStatus(opId, fsObj, e); } } /** * Update the DB object, this method need to be called after the success of * back end command * * @param param * object of NfsACLUpdateParams * @param fs * FileShare object * @param args * FileDeviceInputOutput object */ private void updateNFSACLsInDB(NfsACLUpdateParams param, FileShare fs, FileDeviceInputOutput args) { try { // Create new Acls List<NfsACE> aceAdd = param.getAcesToAdd(); if (aceAdd != null && !aceAdd.isEmpty()) { for (NfsACE ace : aceAdd) { NFSShareACL dbNfsAcl = new NFSShareACL(); dbNfsAcl.setId(URIUtil.createId(NFSShareACL.class)); copyToPersistNfsACL(ace, dbNfsAcl, fs, args); _log.info("Storing new acl in DB: {}", dbNfsAcl); _dbClient.createObject(dbNfsAcl); } } // Modify existing acls List<NfsACE> aceModify = param.getAcesToModify(); if (aceModify != null && !aceModify.isEmpty()) { for (NfsACE ace : aceModify) { NFSShareACL dbNfsAcl = new NFSShareACL(); copyToPersistNfsACL(ace, dbNfsAcl, fs, args); NFSShareACL dbNfsAclTemp = getExistingNfsAclFromDB(dbNfsAcl, args.getFileOperation()); if (dbNfsAclTemp != null) { dbNfsAcl.setId(dbNfsAclTemp.getId()); _log.info("Modifying acl in DB: {}", dbNfsAcl); _dbClient.updateObject(dbNfsAcl); } } } List<NfsACE> aceDelete = param.getAcesToDelete(); if (aceDelete != null && !aceDelete.isEmpty()) { for (NfsACE ace : aceDelete) { NFSShareACL dbNfsAcl = new NFSShareACL(); copyToPersistNfsACL(ace, dbNfsAcl, fs, args); NFSShareACL dbNfsAclTemp = getExistingNfsAclFromDB(dbNfsAcl, args.getFileOperation()); if (dbNfsAclTemp != null) { dbNfsAcl.setId(dbNfsAclTemp.getId()); dbNfsAcl.setInactive(true); _log.info("Marking acl inactive in DB: {}", dbNfsAcl); _dbClient.updateObject(dbNfsAcl); } } } } catch (Exception e) { _log.error("Error While executing CRUD Operations {}", e); } } @Override public void deleteNFSAcls(URI storage, URI fsURI, String subDir, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileObject fsObj = null; FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; Snapshot snapshotObj = null; boolean isFile = false; try { StorageSystem storageObj = _dbClient.queryObject( StorageSystem.class, storage); args.setSubDirectory(subDir); _log.info("FileDeviceController::deleteNFSAcls Recieved Nfs ACL DELETE Operation "); // File if (URIUtil.isType(fsURI, FileShare.class)) { isFile = true; fs = _dbClient.queryObject(FileShare.class, fsURI); fsObj = fs; args.addFSFileObject(fs); args.setFileSystemPath(fs.getPath()); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } else { // Snapshot snapshotObj = _dbClient.queryObject(Snapshot.class, fsURI); fsObj = snapshotObj; fs = _dbClient.queryObject(FileShare.class, snapshotObj.getParent()); args.addFileShare(fs); args.setFileSystemPath(fs.getPath()); args.addSnapshotFileObject(snapshotObj); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); } args.setFileOperation(isFile); args.setOpId(opId); List<NfsACE> aceDeleteList = new ArrayList<NfsACE>(); List<NFSShareACL> dbNfsAclTemp = queryAllNfsACLInDB(fs, subDir, args); makeNfsAceFromDB(aceDeleteList, dbNfsAclTemp); args.setNfsAclsToDelete(aceDeleteList); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .deleteNfsACLs(storageObj, args); if (result.isCommandSuccess()) { // Update Database if (!dbNfsAclTemp.isEmpty()) { for (NFSShareACL nfsShareACL : dbNfsAclTemp) { nfsShareACL.setInactive(true); } _dbClient.updateObject(dbNfsAclTemp); } } if (result.getCommandPending()) { return; } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = (isFile) ? OperationTypeEnum.DELETE_FILE_SYSTEM_NFS_ACL : OperationTypeEnum.DELETE_FILE_SNAPSHOT_NFS_ACL; fsObj.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result .getMessage(); if (isFile) { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, args.getFileSystemPath(), fs, storageObj); } else { recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, args.getFileSystemPath(), snapshotObj, fs, storageObj); } _dbClient.updateObject(fsObj); } catch (Exception e) { String[] params = { storage.toString(), fsURI.toString() }; _log.error("Unable to Delete ACL on file system or snapshot: storage {}, FS/snapshot URI {}", params, e); _log.error("{}, {} ", e.getMessage(), e); updateTaskStatus(opId, fsObj, e); } } /** * To get all the ACLs of File System or a mention subDir. * * @param fs * File System * @param subDir * Sub directory * @return List of NFS ACL present in DB. */ private List<NFSShareACL> queryAllNfsACLInDB(FileShare fs, String subDir, FileDeviceInputOutput args) { List<NFSShareACL> allNfsShareAcl = null; List<NFSShareACL> returnNfsShareAcl = null; List<NFSShareACL> fsNfsShareAcl = new ArrayList<NFSShareACL>(); List<NFSShareACL> subDirNfsShareAcl = new ArrayList<NFSShareACL>(); _log.info("Querying all Nfs File System ACL Using FsId {}", fs.getId()); try { ContainmentConstraint containmentConstraint = null; if (args.getFileOperation()) { containmentConstraint = ContainmentConstraint.Factory .getFileNfsAclsConstraint(fs.getId()); } else { containmentConstraint = ContainmentConstraint.Factory .getSnapshotNfsAclsConstraint(args.getSnapshotId()); } allNfsShareAcl = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, NFSShareACL.class, containmentConstraint); } catch (Exception e) { _log.error("Error while querying {}", e); } returnNfsShareAcl = fsNfsShareAcl; String absolutefsPath = fs.getPath(); String absoluteDirPath = ""; if (subDir != null && !subDir.isEmpty()) { absoluteDirPath = absolutefsPath + "/" + subDir; returnNfsShareAcl = subDirNfsShareAcl; } for (NFSShareACL nfsAcl : allNfsShareAcl) { if (nfsAcl.getFileSystemPath().equals(absoluteDirPath)) { subDirNfsShareAcl.add(nfsAcl); } else if (nfsAcl.getFileSystemPath().equals(absolutefsPath)) { fsNfsShareAcl.add(nfsAcl); } } return returnNfsShareAcl; } /** * Convert list of NfsACE to list of DB object for ACL * * @param nfsAcls * list of the NfsACE object * @param dbNfsAclTemp * converted DB object List */ private void makeNfsAceFromDB(List<NfsACE> nfsAcls, List<NFSShareACL> dbNfsAclTemp) { for (NFSShareACL nfsShareACL : dbNfsAclTemp) { NfsACE nfsAce = new NfsACE(); String permission = nfsShareACL.getPermissions(); if (permission != null && !permission.isEmpty()) { nfsAce.setPermissions(permission); } String domain = nfsShareACL.getDomain(); if (domain != null && !domain.isEmpty()) { nfsAce.setDomain(domain); } String permissionType = nfsShareACL.getPermissionType(); nfsAce.setPermissionType(FileControllerConstants.NFS_FILE_PERMISSION_TYPE_ALLOW); if (permissionType != null && !permissionType.isEmpty()) { nfsAce.setPermissionType(permissionType); } String type = nfsShareACL.getType(); if (type != null && !type.isEmpty()) { nfsAce.setType(type); } String user = nfsShareACL.getUser(); if (user != null && !user.isEmpty()) { nfsAce.setUser(user); } nfsAcls.add(nfsAce); } } /** * Set is the vNAS entity in args only if vNASURI is not null * * @param vNASURI * the URI of VirtualNAS * @param args * instance of FileDeviceInputOutput */ private void setVirtualNASinArgs(URI vNASURI, FileDeviceInputOutput args) { if (vNASURI != null) { VirtualNAS vNAS = _dbClient.queryObject(VirtualNAS.class, vNASURI); args.setvNAS(vNAS); } } /** * Get the deviceType for a StorageSystem. * * @param deviceURI * -- StorageSystem URI * @return deviceType String */ public String getDeviceType(URI deviceURI) throws ControllerException { StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, deviceURI); if (storageSystem == null) { throw DeviceControllerException.exceptions.getDeviceTypeFailed(deviceURI.toString()); } return storageSystem.getSystemType(); } static final String CREATE_FILESYSTEMS_STEP = "FileDeviceCreateFileShares"; static final String MODIFY_FILESYSTEMS_STEP = "FileDeviceModifyFileShares"; static final String DELETE_FILESYSTEMS_STEP = "FileDeviceDeleteFileShares"; static final String CREATE_FS_MIRRORS_STEP = "FileDeviceCreateMirrors"; static final String EXPAND_FILESYSTEMS_STEP = "FileDeviceExpandFileShares"; private static final String ROLLBACK_METHOD_NULL = "rollbackMethodNull"; @Override public String addStepsForCreateFileSystems(Workflow workflow, String waitFor, List<FileDescriptor> filesystems, String taskId) throws InternalException { if (filesystems != null && !filesystems.isEmpty()) { // create source filesystems List<FileDescriptor> sourceDescriptors = FileDescriptor.filterByType(filesystems, FileDescriptor.Type.FILE_DATA, FileDescriptor.Type.FILE_MIRROR_SOURCE); for (FileDescriptor sourceDescriptor : sourceDescriptors) { // create a step waitFor = workflow.createStep(CREATE_FILESYSTEMS_STEP, String.format("Creating File systems:%n%s", taskId), null, sourceDescriptor.getDeviceURI(), getDeviceType(sourceDescriptor.getDeviceURI()), this.getClass(), createFileSharesMethod(sourceDescriptor), rollbackMethodNullMethod(), null); } // create targetFileystems List<FileDescriptor> targetDescriptors = FileDescriptor.filterByType(filesystems, FileDescriptor.Type.FILE_MIRROR_TARGET); if (targetDescriptors != null && !targetDescriptors.isEmpty()) { for (FileDescriptor descriptor : targetDescriptors) { FileShare fileShare = _dbClient.queryObject(FileShare.class, descriptor.getFsURI()); FileShare fileShareSource = _dbClient.queryObject(FileShare.class, fileShare.getParentFileShare().getURI()); if (fileShare.getParentFileShare() != null) { waitFor = workflow.createStep( CREATE_FILESYSTEMS_STEP, String.format("Creating Target File systems:%n%s", taskId), waitFor, descriptor.getDeviceURI(), getDeviceType(descriptor.getDeviceURI()), this.getClass(), createFileSharesMethod(descriptor), rollbackCreateFileSharesMethod(fileShareSource.getStorageDevice(), asList(fileShare.getParentFileShare() .getURI()), sourceDescriptors), null); } } } } // find out which value we should return return waitFor = CREATE_FILESYSTEMS_STEP; } public String addStepsForDeleteFileSystems(Workflow workflow, String waitFor, List<FileDescriptor> filesystems, String taskId) throws InternalException { List<FileDescriptor> sourceDescriptors = FileDescriptor.filterByType(filesystems, FileDescriptor.Type.FILE_DATA, FileDescriptor.Type.FILE_EXISTING_SOURCE, FileDescriptor.Type.FILE_MIRROR_SOURCE); // Segregate by device. Map<URI, List<FileDescriptor>> deviceMap = FileDescriptor.getDeviceMap(sourceDescriptors); // Add a step to delete the fileshares in each device. for (URI deviceURI : deviceMap.keySet()) { filesystems = deviceMap.get(deviceURI); List<URI> fileshareURIs = FileDescriptor.getFileSystemURIs(filesystems); for (URI uriFile : fileshareURIs) { FileShare fsObj = _dbClient.queryObject(FileShare.class, uriFile); // unmount exports only if FULL delete if (FileControllerConstants.DeleteTypeEnum.FULL.toString().equalsIgnoreCase(filesystems.get(0).getDeleteType())) { // get all the mounts and generate steps for unmounting them List<MountInfo> mountList = getAllMountedExports(uriFile, null, true); for (MountInfo mount : mountList) { Object[] args = new Object[] { mount.getHostId(), mount.getFsId(), mount.getMountPath() }; waitFor = createMethod(workflow, waitFor, UNMOUNT_FILESYSTEM_EXPORT_METHOD, null, "Unmounting path:" + mount.getMountPath(), fsObj.getStorageDevice(), args); } } else {// Only remove the mounts from CoPRHD database if Inventory Only delete Object[] args = new Object[] { uriFile }; waitFor = createMethod(workflow, waitFor, CHECK_IF_MOUNT_EXISTS_ON_HOST, null, "Confirming mount dependencies for fs:" + fsObj.getId(), fsObj.getStorageDevice(), args); } if (fsObj != null && fsObj.getMirrorfsTargets() != null) { for (String mirrorTarget : fsObj.getMirrorfsTargets()) { URI targetURI = URI.create(mirrorTarget); FileShare fsTargObj = _dbClient.queryObject(FileShare.class, targetURI); if (fsTargObj != null && !fsTargObj.getInactive()) { _log.info("addStepsForDeleteFileSystems - deleting target fs {} for file system {}", fsTargObj.getId(), fsObj.getId()); workflow.createStep(DELETE_FILESYSTEMS_STEP, String.format("Deleting fileshares:%n%s", asList(targetURI)), waitFor, fsTargObj.getStorageDevice(), getDeviceType(fsTargObj.getStorageDevice()), this.getClass(), deleteFileSharesMethod(fsTargObj.getStorageDevice(), asList(targetURI), filesystems.get(0).isForceDelete(), filesystems.get(0).getDeleteType(), taskId), null, null); } } } // Dont delete the source file system for delete only targets operation!! if (!filesystems.get(0).isDeleteTargetOnly()) { _log.info("addStepsForDeleteFileSystems - deleting source fs {} ", fsObj.getId()); workflow.createStep(DELETE_FILESYSTEMS_STEP, String.format("Deleting fileshares:%n%s", fileshareURIs), waitFor, deviceURI, getDeviceType(deviceURI), this.getClass(), deleteFileSharesMethod(deviceURI, fileshareURIs, filesystems.get(0).isForceDelete(), filesystems.get(0).getDeleteType(), taskId), null, null); } } } return waitFor = DELETE_FILESYSTEMS_STEP; } /* * Expand filesystem * (non-Javadoc) * * @see * com.emc.storageos.fileorchestrationcontroller.FileOrchestrationInterface#addStepsForExpandFileSystems(com.emc. * storageos.workflow. * Workflow, java.lang.String, java.util.List, java.lang.String) */ @Override public String addStepsForExpandFileSystems(Workflow workflow, String waitFor, List<FileDescriptor> fileDescriptors, String taskId) throws InternalException { List<FileDescriptor> sourceDescriptors = FileDescriptor.filterByType(fileDescriptors, FileDescriptor.Type.FILE_MIRROR_SOURCE, FileDescriptor.Type.FILE_EXISTING_SOURCE, FileDescriptor.Type.FILE_DATA, FileDescriptor.Type.FILE_MIRROR_TARGET); if (sourceDescriptors == null || sourceDescriptors.isEmpty()) { return waitFor; } else { createExpandFileshareStep(workflow, waitFor, sourceDescriptors, taskId); } return waitFor; } /** * Return a Workflow.Method for createFileShares. * * @param fileDescriptor * @return */ private Workflow.Method createFileSharesMethod(FileDescriptor fileDescriptor) { return new Workflow.Method("createFS", fileDescriptor.getDeviceURI(), fileDescriptor.getPoolURI(), fileDescriptor.getFsURI(), fileDescriptor.getSuggestedNativeFsId()); } /** * Return a Workflow.Method for rollbackCreateFileSystems * * @param systemURI * @param fileURIs * @return Workflow.Method */ public static Workflow.Method rollbackCreateFileSharesMethod(URI systemURI, List<URI> fileURIs, List<FileDescriptor> sourceDes) { // This case comes when we are creating target FS for existing source, // and if target FS creation fails we should not delete source FS if (sourceDes == null || sourceDes.isEmpty()) { return new Workflow.Method(ROLLBACK_METHOD_NULL); } return new Workflow.Method("rollBackCreateFileShares", systemURI, fileURIs); } /** * Rollback create filesystem */ @Override public void rollBackCreateFileShares(URI systemURI, List<URI> fileURIs, String opId) { try { WorkflowStepCompleter.stepExecuting(opId); for (URI fileshareId : fileURIs) { FileShare fileShare = _dbClient.queryObject(FileShare.class, fileshareId); this.delete(systemURI, fileShare.getPool(), fileShare.getId(), false, FileControllerConstants.DeleteTypeEnum.FULL.toString(), opId); } WorkflowStepCompleter.stepSucceded(opId); } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } /** * Return a Workflow.Method for deleteFileShares. * * @param systemURI * @param fileShareURIs * @return */ private Workflow.Method deleteFileSharesMethod(URI systemURI, List<URI> fileShareURIs, boolean forceDelete, String deleteType, String taskId) { FileShare fsObj = _dbClient.queryObject(FileShare.class, fileShareURIs.get(0)); return new Workflow.Method("delete", fsObj.getStorageDevice(), fsObj.getPool(), fsObj.getId(), forceDelete, deleteType); } /** * Expand File System Step * * @param workflow * @param waitFor * @param fileDescriptors * @param taskId * @return */ private String createExpandFileshareStep(Workflow workflow, String waitFor, List<FileDescriptor> fileDescriptors, String taskId) { _log.info("START Expand file system"); Map<URI, Long> filesharesToExpand = new HashMap<URI, Long>(); for (FileDescriptor descriptor : fileDescriptors) { // Grab the fileshare, let's see if an expand is really needed FileShare fileShare = _dbClient.queryObject(FileShare.class, descriptor.getFsURI()); // Only expand the fileshare if it's an existing fileshare (provisoned capacity is not null and not 0) and // new size > existing fileshare's provisioned capacity, otherwise we can ignore. if (fileShare.getCapacity() != null && fileShare.getCapacity().longValue() != 0 && descriptor.getFileSize() > fileShare.getCapacity().longValue()) { filesharesToExpand.put(fileShare.getId(), descriptor.getFileSize()); } } Workflow.Method expandMethod = null; for (Map.Entry<URI, Long> entry : filesharesToExpand.entrySet()) { _log.info("Creating WF step for Expand FileShare for {}", entry.getKey().toString()); FileShare fileShareToExpand = _dbClient.queryObject(FileShare.class, entry.getKey()); StorageSystem storage = _dbClient.queryObject(StorageSystem.class, fileShareToExpand.getStorageDevice()); Long fileSize = entry.getValue(); expandMethod = expandFileSharesMethod(storage.getId(), fileShareToExpand.getId(), fileSize); waitFor = workflow.createStep( EXPAND_FILESYSTEMS_STEP, String.format("Expand FileShare %s", fileShareToExpand), waitFor, storage.getId(), storage.getSystemType(), getClass(), expandMethod, null, null); _log.info("Creating workflow step {}", EXPAND_FILESYSTEMS_STEP); } return waitFor; } /** * Return a WorkFlow.Method for expandFileShares * * @param uriStorage * @param fileURI * @param size * @return */ Workflow.Method expandFileSharesMethod(URI uriStorage, URI fileURI, long size) { return new Workflow.Method("expandFS", uriStorage, fileURI, size); } @Override public void assignFileSystemSnapshotPolicy(URI storage, URI fsURI, URI policy, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; try { fs = _dbClient.queryObject(FileShare.class, fsURI); SchedulePolicy fp = _dbClient.queryObject(SchedulePolicy.class, policy); if (fs != null && fp != null) { StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); _log.info("Controller Recieved File Policy {}", policy); args.addFSFileObject(fs); args.setFileSystemPath(fs.getPath()); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); args.addFilePolicy(fp); args.setFileOperation(true); args.setOpId(opId); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .assignFilePolicy(storageObj, args); if (result.isCommandSuccess()) { // Update FS database StringSet fpolicies = fs.getFilePolicies(); fpolicies.add(fp.getId().toString()); fs.setFilePolicies(fpolicies); // Update SchedulePolicy database StringSet resources = fp.getAssignedResources(); resources.add(fs.getId().toString()); fp.setAssignedResources(resources); } if (result.getCommandPending()) { return; } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = OperationTypeEnum.ASSIGN_FILE_SYSTEM_SNAPSHOT_SCHEDULE; fs.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result .getMessage(); recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, args.getFileSystemPath(), fs, fp); _dbClient.updateObject(fs); _dbClient.updateObject(fp); } else { throw DeviceControllerException.exceptions.invalidObjectNull(); } } catch (Exception e) { String[] params = { storage.toString(), fsURI.toString(), e.getMessage() }; _log.error("Unable to assign policy : storage {}, FS URI {},: Error {}", params); updateTaskStatus(opId, fs, e); } } @Override public void unassignFileSystemSnapshotPolicy(URI storage, URI fsURI, URI policy, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; try { fs = _dbClient.queryObject(FileShare.class, fsURI); SchedulePolicy fp = _dbClient.queryObject(SchedulePolicy.class, policy); if (fs != null && fp != null) { StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); _log.info("Controller Recieved File Policy {}", policy); args.addFSFileObject(fs); args.setFileSystemPath(fs.getPath()); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); args.addFilePolicy(fp); args.setFileOperation(true); args.setOpId(opId); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .unassignFilePolicy(storageObj, args); if (result.isCommandSuccess()) { // Update FS database StringSet fpolicies = fs.getFilePolicies(); if (fpolicies != null && fpolicies.contains(policy.toString())) { fpolicies.remove(policy.toString()); fs.setFilePolicies(fpolicies); } // Update SchedulePolicy database StringSet resources = fp.getAssignedResources(); if (resources != null && resources.contains(fs.getId().toString())) { resources.remove(fs.getId().toString()); fp.setAssignedResources(resources); } } if (result.getCommandPending()) { return; } // Audit & Update the task status OperationTypeEnum auditType = null; auditType = OperationTypeEnum.UNASSIGN_FILE_SYSTEM_SNAPSHOT_SCHEDULE; fs.getOpStatus().updateTaskStatus(opId, result.toOperation()); // Monitoring - Event Processing String eventMsg = result.isCommandSuccess() ? "" : result .getMessage(); recordFileDeviceOperation(_dbClient, auditType, result.isCommandSuccess(), eventMsg, args.getFileSystemPath(), fs, fp); _dbClient.updateObject(fs); _dbClient.updateObject(fp); } else { throw DeviceControllerException.exceptions.invalidObjectNull(); } } catch (Exception e) { String[] params = { storage.toString(), fsURI.toString(), e.getMessage() }; _log.error("Unable to Unassign policy : storage {}, FS URI {},: Error {}", params); updateTaskStatus(opId, fs, e); } } /** * A rollback workflow method that does nothing, but allows rollback * to continue to prior steps back up the workflow chain. Can be and is * used in workflows in other controllers that invoke operations on this * file controller. If the file operation happens to fail, this no-op * rollback method is invoked. It says the rollback step succeeded, * which will then allow other rollback operations to execute for other * workflow steps executed by the other controller. * * @param stepId * The id of the step being rolled back. * * @throws WorkflowException */ public void rollbackMethodNull(String stepId) throws WorkflowException { WorkflowStepCompleter.stepSucceded(stepId); } /** * Creates a rollback workflow method that does nothing, but allows rollback * to continue to prior steps back up the workflow chain. * * @return A workflow method */ public Workflow.Method rollbackMethodNullMethod() { return new Workflow.Method(ROLLBACK_METHOD_NULL); } @Override public void listSanpshotByPolicy(URI storage, URI fsURI, URI policy, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(fsURI, opId); FileDeviceInputOutput args = new FileDeviceInputOutput(); FileShare fs = null; try { fs = _dbClient.queryObject(FileShare.class, fsURI); FilePolicy fp = _dbClient.queryObject(FilePolicy.class, policy); if (fs != null && fp != null) { StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); _log.info("Controller Recieved File Policy {}", policy); args.addFSFileObject(fs); args.setFileSystemPath(fs.getPath()); StoragePool pool = _dbClient.queryObject(StoragePool.class, fs.getPool()); args.addStoragePool(pool); args.setFileProtectionPolicy(fp); args.setFileOperation(true); args.setOpId(opId); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .listSanpshotByPolicy(storageObj, args); fs.getOpStatus().updateTaskStatus(opId, result.toOperation()); } else { throw DeviceControllerException.exceptions.invalidObjectNull(); } } catch (Exception e) { String[] params = { storage.toString(), fsURI.toString(), e.getMessage() }; _log.error("Unable to get schedule snapshots : storage {}, FS URI {},: Error {}", params); updateTaskStatus(opId, fs, e); } } @Override public void updateStorageSystemFileProtectionPolicy(URI storage, URI policy, URI policyRes, FilePolicyUpdateParam policyUpdateParam, String opId) throws InternalException { ControllerUtils.setThreadLocalLogData(policy, opId); FileDeviceInputOutput args = new FileDeviceInputOutput(); try { FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, policy); PolicyStorageResource policyResource = _dbClient.queryObject(PolicyStorageResource.class, policyRes); if (filePolicy != null && policyResource != null) { StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storage); _log.info("Updating File protection ile Policy {}", policy); args.setFileProtectionPolicy(filePolicy); args.setPolicyStorageResource(policyResource); args.setFileProtectionPolicyUpdateParam(policyUpdateParam); args.setFileOperation(true); args.setOpId(opId); // Do the Operation on device. BiosCommandResult result = getDevice(storageObj.getSystemType()) .updateStorageSystemFileProtectionPolicy(storageObj, args); if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } else { throw DeviceControllerException.exceptions.invalidObjectNull(); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } public void unmountDevice(URI hostId, URI resId, String mountPath, String opId) { try { WorkflowStepCompleter.stepExecuting(opId); _log.info("Unmounting mount dependency:", mountPath); computeSystemOrchestrationDeviceController.unmountDevice(hostId, resId, mountPath, opId); WorkflowStepCompleter.stepSucceded(opId); } catch (ControllerException ex) { WorkflowStepCompleter.stepFailed(opId, ex); _log.error("Failed to unmount:", mountPath); throw ex; } } public void verifyMountDependencies(URI fsId, FileShareExportUpdateParams param, String opId) { try { WorkflowStepCompleter.stepExecuting(opId); _log.info("Verifying mount dependencies:", fsId); List<MountInfo> unmountList = getMountedExports(fsId, param.getSubDir(), param); if (!unmountList.isEmpty()) { WorkflowStepCompleter.stepFailed(opId, APIException.badRequests.cannotDeleteDuetoExistingMounts()); throw APIException.badRequests.cannotDeleteDuetoExistingMounts(); } WorkflowStepCompleter.stepSucceded(opId); } catch (ControllerException ex) { WorkflowStepCompleter.stepFailed(opId, ex); _log.error("Couldn't verify dependencies: ", fsId); throw ex; } } public List<MountInfo> getAllMountedExports(URI id, String subDir, boolean allDirs) { List<MountInfo> mountList = FileOperationUtils.queryDBFSMounts(id, _dbClient); List<MountInfo> unmountList = new ArrayList<MountInfo>(); if (allDirs) { return mountList; } for (MountInfo mount : mountList) { if ((StringUtils.isEmpty(mount.getSubDirectory()) && StringUtils.isEmpty(subDir)) || (!StringUtils.isEmpty(subDir) && subDir.equalsIgnoreCase(mount.getSubDirectory()))) { unmountList.add(mount); } } return unmountList; } public void CheckIfExportIsMounted(URI fsId, String subDir, boolean allDirs, String opId) { WorkflowStepCompleter.stepExecuting(opId); List<MountInfo> mountList = FileOperationUtils.queryDBFSMounts(fsId, _dbClient); if (mountList == null || mountList.isEmpty()) { WorkflowStepCompleter.stepSucceded(opId); } if (allDirs) { WorkflowStepCompleter.stepFailed(opId, APIException.badRequests.cannotDeleteDuetoExistingMounts()); } if (subDir != null) { for (MountInfo mount : mountList) { if (subDir.equalsIgnoreCase(mount.getSubDirectory())) { WorkflowStepCompleter.stepFailed(opId, APIException.badRequests.cannotDeleteDuetoExistingMounts()); } } } else { for (MountInfo mount : mountList) { if (StringUtils.isEmpty(mount.getSubDirectory())) { WorkflowStepCompleter.stepFailed(opId, APIException.badRequests.cannotDeleteDuetoExistingMounts()); } } } WorkflowStepCompleter.stepSucceded(opId); } public List<MountInfo> getMountedExports(URI fsId, String subDir, FileExportUpdateParams param) { List<MountInfo> mountList = FileOperationUtils.queryDBFSMounts(fsId, _dbClient); List<MountInfo> unmountList = new ArrayList<MountInfo>(); if (param.getExportRulesToDelete() != null) { unmountList.addAll(getRulesToUnmount(param.getExportRulesToDelete(), mountList, fsId, subDir)); } if (param.getExportRulesToModify() != null) { unmountList.addAll(getRulesToUnmount(param.getExportRulesToModify(), mountList, fsId, subDir)); } return unmountList; } private List<MountInfo> getRulesToUnmount(ExportRules rules, List<MountInfo> mountList, URI fsId, String subDir) { List<MountInfo> unmountList = new ArrayList<MountInfo>(); List<ExportRule> exportList = new ArrayList<ExportRule>(); exportList.addAll(rules.getExportRules()); Map<ExportRule, List<String>> filteredExports = filterExportRules(exportList, FileOperationUtils.getExportRules(fsId, false, subDir, _dbClient)); for (MountInfo mount : mountList) { String hostname = _dbClient.queryObject(Host.class, mount.getHostId()).getHostName(); if (StringUtils.isEmpty(subDir) && StringUtils.isEmpty(mount.getSubDirectory()) || (!StringUtils.isEmpty(mount.getSubDirectory()) && mount.getSubDirectory().equals(subDir))) { for (Entry<ExportRule, List<String>> rule : filteredExports.entrySet()) { if (rule.getValue().contains(hostname) && rule.getKey().getSecFlavor().equals(mount.getSecurityType())) { unmountList.add(mount); } } } } return unmountList; } private Map<ExportRule, List<String>> filterExportRules(List<ExportRule> newExportList, List<ExportRule> existingExportList) { Map<ExportRule, List<String>> filteredExports = new HashMap<ExportRule, List<String>>(); _log.info("filtering export rules"); for (ExportRule newExport : newExportList) { for (ExportRule oldExport : existingExportList) { if (newExport.getSecFlavor().equalsIgnoreCase(oldExport.getSecFlavor())) { List<String> hosts = new ArrayList<String>(); if (oldExport.getReadOnlyHosts() != null) { hosts.addAll(oldExport.getReadOnlyHosts()); } if (oldExport.getReadWriteHosts() != null) { hosts.addAll(oldExport.getReadWriteHosts()); } if (oldExport.getRootHosts() != null) { hosts.addAll(oldExport.getRootHosts()); } if (newExport.getReadOnlyHosts() != null) { hosts.removeAll(newExport.getReadOnlyHosts()); } if (newExport.getReadWriteHosts() != null) { hosts.removeAll(newExport.getReadWriteHosts()); } if (newExport.getRootHosts() != null) { hosts.removeAll(newExport.getRootHosts()); } filteredExports.put(oldExport, hosts); } } } return filteredExports; } public void checkIfMountExistsOnHost(URI fsId, String opId) { try { WorkflowStepCompleter.stepExecuting(opId); ContainmentConstraint containmentConstraint = ContainmentConstraint.Factory.getFileMountsConstraint(fsId); List<FileMountInfo> fsDBMounts = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileMountInfo.class, containmentConstraint); FileShare fs = _dbClient.queryObject(FileShare.class, fsId); for (FileMountInfo fsMount : fsDBMounts) { LinuxMountUtils mountUtils = new LinuxMountUtils(_dbClient.queryObject(Host.class, fsMount.getHostId())); ExportRule export = FileOperationUtils.findExport(fs, fsMount.getSubDirectory(), fsMount.getSecurityType(), _dbClient); if (mountUtils.verifyMountPoints(export.getMountPoint(), fsMount.getMountPath())) { String errMsg = new String("delete file system from ViPR database failed because mounts exist for file system " + fs.getLabel() + " and once deleted the mounts cannot be ingested into ViPR"); final ServiceCoded serviceCoded = DeviceControllerException.errors .jobFailedOpMsg(OperationTypeEnum.DELETE_FILE_SYSTEM.toString(), errMsg); WorkflowStepCompleter.stepFailed(opId, serviceCoded); } } for (FileMountInfo fsMount : fsDBMounts) { fsMount.setInactive(true); } _dbClient.updateObject(fsDBMounts); WorkflowStepCompleter.stepSucceded(opId); } catch (ControllerException ex) { WorkflowStepCompleter.stepFailed(opId, ex); _log.error("Couldn't verify dependencies: ", fsId); throw ex; } } /** * Common method used to create Controller methods that would be executed by workflow service * * @param workflow * @param waitFor * @param methodName * - Name of the method to be executed * @param stepId * @param stepDescription * @param storage * @param args * - Parameters of the method that has to be excecuted by workflow * @return waitForStep */ public String createMethod(Workflow workflow, String waitFor, String methodName, String stepId, String stepDescription, URI storage, Object[] args) { StorageSystem system = _dbClient.queryObject(StorageSystem.class, storage); Workflow.Method method = new Workflow.Method(methodName, args); return workflow.createStep(null, stepDescription, waitFor, storage, system.getSystemType(), getClass(), method, null, stepId); } /** * Acquire Work flow Distributed Owner Lock for a Step. * This method is used to acquire lock at a particular work flow step.Currently we are acquiring lock only for * VNXFILE. * This lock would be released after the step completion (either failure or success). * * @param storageObj * -Storage System object's native id is used to generate key for the lock * @param opId */ public void acquireStepLock(StorageSystem storageObj, String opId) { Workflow workflow = _workflowService.getWorkflowFromStepId(opId); if (workflow != null && storageObj.deviceIsType(Type.vnxfile)) { List<String> lockKeys = new ArrayList<String>(); lockKeys.add(storageObj.getNativeGuid()); boolean lockAcquired = _workflowService.acquireWorkflowStepLocks(opId, lockKeys, LockTimeoutValue.get(LockType.FILE_OPERATIONS)); if (!lockAcquired) { throw DeviceControllerException.exceptions.failedToAcquireWorkflowLock(lockKeys.toString(), "Timeout in Acquiring Lock"); } } } @Override public void applyFilePolicy(URI storage, URI sourceFS, URI policyURI, String taskId) throws ControllerException { FileShare fsObj = null; StorageSystem storageObj = null; try { fsObj = _dbClient.queryObject(FileShare.class, sourceFS); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fsObj.getVirtualPool()); Project project = _dbClient.queryObject(Project.class, fsObj.getProject()); TenantOrg tenantOrg = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg()); storageObj = _dbClient.queryObject(StorageSystem.class, storage); FileDeviceInputOutput args = new FileDeviceInputOutput(); FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, policyURI); args.setOpId(taskId); args.addFSFileObject(fsObj); args.setVPool(vpool); args.setTenantOrg(tenantOrg); args.setProject(project); args.setFileProtectionPolicy(filePolicy); setVirtualNASinArgs(fsObj.getVirtualNAS(), args); WorkflowStepCompleter.stepExecuting(taskId); BiosCommandResult result = getDevice(storageObj.getSystemType()).doApplyFilePolicy(storageObj, args); if (result.getCommandPending()) { return; } else if (result.isCommandSuccess()) { _log.info("File policy: {} applied successfully", filePolicy.getFilePolicyName()); WorkflowStepCompleter.stepSucceded(taskId); } else { WorkflowStepCompleter.stepFailed(taskId, result.getServiceCoded()); } } catch (Exception e) { _log.error("Unable to apply file policy: {} to file system: {}", policyURI, fsObj.getId()); ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(taskId, serviceError); updateTaskStatus(taskId, fsObj, e); } } protected void resetReplicationFileSystemsRelation(FilePolicy filePolicy, PolicyStorageResource policyResource) { URI storageSystem = policyResource.getStorageSystem(); String policyPath = policyResource.getResourcePath(); // For replication policy // Remove the source - target relationship if (filePolicy.getFilePolicyType().equalsIgnoreCase(FilePolicyType.file_replication.name())) { ContainmentConstraint containmentConstraint = ContainmentConstraint.Factory.getStorageDeviceFileshareConstraint(storageSystem); List<FileShare> fileshares = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileShare.class, containmentConstraint); List<FileShare> modifiedFileshares = new ArrayList<>(); for (FileShare fileshare : fileshares) { // All the file systems underneath the policy path // should be decoupled!!! if (fileshare.getNativeId().startsWith(policyPath)) { if (fileshare.getPersonality() != null && fileshare.getPersonality().equalsIgnoreCase(PersonalityTypes.SOURCE.toString())) { fileshare.setMirrorStatus(NullColumnValueGetter.getNullStr()); fileshare.setAccessState(NullColumnValueGetter.getNullStr()); fileshare.setPersonality(NullColumnValueGetter.getNullStr()); if (fileshare.getMirrorfsTargets() != null && !fileshare.getMirrorfsTargets().isEmpty()) { StringSet targets = fileshare.getMirrorfsTargets(); for (String strTargetFs : targets) { FileShare targetFs = _dbClient.queryObject(FileShare.class, URI.create(strTargetFs)); targetFs.setMirrorStatus(NullColumnValueGetter.getNullStr()); targetFs.setAccessState(NullColumnValueGetter.getNullStr()); targetFs.setParentFileShare(NullColumnValueGetter.getNullNamedURI()); targetFs.setPersonality(NullColumnValueGetter.getNullStr()); modifiedFileshares.add(targetFs); } targets.clear(); fileshare.setMirrorfsTargets(targets); } } modifiedFileshares.add(fileshare); } } if (!modifiedFileshares.isEmpty()) { _dbClient.updateObject(modifiedFileshares); } } } /** * * @param storage * @param filePolicy * URI of the file policy to be applied * @param policyStorageResource * @param opId * @throws ControllerException */ public void unassignFilePolicy(URI storage, URI policyURI, URI policyStorageResource, String opId) throws ControllerException { StorageSystem storageObj = null; FilePolicy filePolicy = null; PolicyStorageResource policyRes = null; try { FileDeviceInputOutput args = new FileDeviceInputOutput(); storageObj = _dbClient.queryObject(StorageSystem.class, storage); filePolicy = _dbClient.queryObject(FilePolicy.class, policyURI); policyRes = _dbClient.queryObject(PolicyStorageResource.class, policyStorageResource); args.setFileProtectionPolicy(filePolicy); args.setPolicyStorageResource(policyRes); WorkflowStepCompleter.stepExecuting(opId); _log.info("Unassigning file policy: {} from resource: {}", policyURI.toString(), policyRes.getAppliedAt().toString()); BiosCommandResult result = getDevice(storageObj.getSystemType()).doUnassignFilePolicy(storageObj, args); if (result.getCommandPending()) { return; } else if (result.isCommandSuccess()) { // decouple the replication relation for the policy!! resetReplicationFileSystemsRelation(filePolicy, policyRes); filePolicy.removePolicyStorageResources(policyRes.getId()); _dbClient.markForDeletion(policyRes); _dbClient.updateObject(filePolicy); _log.info("Unassigning file policy: {} from resource: {} finished successfully", policyURI.toString(), policyRes.getAppliedAt().toString()); WorkflowStepCompleter.stepSucceded(opId); } else { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } @Override public void assignFileSnapshotPolicyToVirtualPools(URI storageSystemURI, URI vNASURI, URI filePolicyToAssign, URI vpoolURI, String opId) throws ControllerException { StorageSystem storageObj = null; FilePolicy filePolicy = null; VirtualNAS vNAS = null; VirtualPool vpool = null; try { WorkflowStepCompleter.stepExecuting(opId); FileDeviceInputOutput args = new FileDeviceInputOutput(); storageObj = _dbClient.queryObject(StorageSystem.class, storageSystemURI); filePolicy = _dbClient.queryObject(FilePolicy.class, filePolicyToAssign); vpool = _dbClient.queryObject(VirtualPool.class, vpoolURI); if (vNASURI != null) { vNAS = _dbClient.queryObject(VirtualNAS.class, vNASURI); args.setvNAS(vNAS); } args.setFileProtectionPolicy(filePolicy); args.setVPool(vpool); _log.info("Assigning file snapshot policy: {} to vpool: {}", filePolicyToAssign, vpoolURI); BiosCommandResult result = getDevice(storageObj.getSystemType()).checkFilePolicyExistsOrCreate(storageObj, args); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } @Override public void assignFileSnapshotPolicyToProjects(URI storageSystemURI, URI vNASURI, URI filePolicyToAssign, URI vpoolURI, URI projectURI, String opId) throws InternalException { try { WorkflowStepCompleter.stepExecuting(opId); FileDeviceInputOutput args = new FileDeviceInputOutput(); StorageSystem storageObj = _dbClient.queryObject(StorageSystem.class, storageSystemURI); FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, filePolicyToAssign); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, vpoolURI); Project project = _dbClient.queryObject(Project.class, projectURI); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg()); if (vNASURI != null) { VirtualNAS vNAS = _dbClient.queryObject(VirtualNAS.class, vNASURI); args.setvNAS(vNAS); } args.setFileProtectionPolicy(filePolicy); args.setVPool(vpool); args.setProject(project); args.setTenantOrg(tenant); _log.info("Assigning file snapshot policy: {} to vpool {} and project: {}", filePolicyToAssign, vpoolURI, projectURI); BiosCommandResult result = getDevice(storageObj.getSystemType()).checkFilePolicyExistsOrCreate(storageObj, args); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } @Override public void assignFileReplicationPolicyToVirtualPools(URI storageSystemURI, URI targetSystemURI, URI sourceVNasURI, URI targetVArrayURI, URI targetVNasURI, URI filePolicyToAssign, URI vpoolURI, String opId) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(opId); StorageSystem sourceSystem = _dbClient.queryObject(StorageSystem.class, storageSystemURI); StorageSystem targetSystem = _dbClient.queryObject(StorageSystem.class, targetSystemURI); FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, filePolicyToAssign); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, vpoolURI); VirtualArray targetVarray = _dbClient.queryObject(VirtualArray.class, targetVArrayURI); VirtualNAS sourceVNAS = null; VirtualNAS targetVNAS = null; FileDeviceInputOutput sourceArgs = new FileDeviceInputOutput(); FileDeviceInputOutput targetArgs = new FileDeviceInputOutput(); targetArgs.setVarray(targetVarray); sourceArgs.setFileProtectionPolicy(filePolicy); sourceArgs.setVPool(vpool); if (sourceVNasURI != null) { sourceVNAS = _dbClient.queryObject(VirtualNAS.class, sourceVNasURI); sourceArgs.setvNAS(sourceVNAS); targetArgs.setSourceVNAS(sourceVNAS); } targetArgs.setSourceSystem(sourceSystem); targetArgs.setVPool(vpool); targetArgs.setTarget(true); if (targetVNasURI != null) { targetVNAS = _dbClient.queryObject(VirtualNAS.class, targetVNasURI); targetArgs.setvNAS(targetVNAS); } _log.info("Assigning file replication policy: {} to vpool: {}", filePolicyToAssign, vpoolURI); BiosCommandResult result = getDevice(sourceSystem.getSystemType()).checkFileReplicationPolicyExistsOrCreate( sourceSystem, targetSystem, sourceArgs, targetArgs); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } @Override public void assignFileReplicationPolicyToProjects(URI storageSystemURI, URI targetSystemURI, URI sourceVNasURI, URI targetVArrayURI, URI targetVNasURI, URI filePolicyToAssign, URI vpoolURI, URI projectURI, String opId) throws InternalException { try { WorkflowStepCompleter.stepExecuting(opId); StorageSystem sourceSystem = _dbClient.queryObject(StorageSystem.class, storageSystemURI); StorageSystem targetSystem = _dbClient.queryObject(StorageSystem.class, targetSystemURI); FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, filePolicyToAssign); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, vpoolURI); Project project = _dbClient.queryObject(Project.class, projectURI); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg()); VirtualArray targetVarray = _dbClient.queryObject(VirtualArray.class, targetVArrayURI); VirtualNAS sourceVNAS = null; VirtualNAS targetVNAS = null; FileDeviceInputOutput sourceArgs = new FileDeviceInputOutput(); FileDeviceInputOutput targetArgs = new FileDeviceInputOutput(); sourceArgs.setFileProtectionPolicy(filePolicy); sourceArgs.setVPool(vpool); sourceArgs.setProject(project); sourceArgs.setTenantOrg(tenant); targetArgs.setVarray(targetVarray); if (sourceVNasURI != null) { sourceVNAS = _dbClient.queryObject(VirtualNAS.class, sourceVNasURI); sourceArgs.setvNAS(sourceVNAS); targetArgs.setSourceVNAS(sourceVNAS); } targetArgs.setTarget(true); targetArgs.setSourceSystem(sourceSystem); targetArgs.setVPool(vpool); targetArgs.setProject(project); targetArgs.setTenantOrg(tenant); if (targetVNasURI != null) { targetVNAS = _dbClient.queryObject(VirtualNAS.class, targetVNasURI); targetArgs.setvNAS(targetVNAS); } _log.info("Assigning file snapshot policy: {} to vpool {} and project: {}", filePolicyToAssign, vpoolURI, projectURI); BiosCommandResult result = getDevice(sourceSystem.getSystemType()).checkFileReplicationPolicyExistsOrCreate( sourceSystem, targetSystem, sourceArgs, targetArgs); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, serviceError); } } @Override public void performFileReplicationOperation(URI storage, URI sourceFSURI, String opType, String opId) throws ControllerException { StorageSystem system = _dbClient.queryObject(StorageSystem.class, storage); FileShare fileShare = _dbClient.queryObject(FileShare.class, sourceFSURI); TaskCompleter completer = null; BiosCommandResult result = new BiosCommandResult(); WorkflowStepCompleter.stepExecuting(opId); _log.info("file replication operation {} started for file systerm {}", opType, fileShare.getName()); try { if ("pause".equalsIgnoreCase(opType)) { completer = new MirrorFilePauseTaskCompleter(FileShare.class, sourceFSURI, opId); result = getDevice(system.getSystemType()).doPauseLink(system, fileShare); } else if ("resume".equalsIgnoreCase(opType)) { completer = new MirrorFileResumeTaskCompleter(FileShare.class, sourceFSURI, opId); result = getDevice(system.getSystemType()).doResumeLink(system, fileShare, completer); } else if ("start".equalsIgnoreCase(opType)) { completer = new MirrorFileStartTaskCompleter(FileShare.class, sourceFSURI, opId); result = getDevice(system.getSystemType()).doStartMirrorLink(system, fileShare, completer); } else if ("refresh".equalsIgnoreCase(opType)) { completer = new MirrorFileRefreshTaskCompleter(FileShare.class, sourceFSURI, opId); result = getDevice(system.getSystemType()).doRefreshMirrorLink(system, fileShare); } else if ("resync".equalsIgnoreCase(opType)) { completer = new MirrorFileResyncTaskCompleter(FileShare.class, sourceFSURI, opId); result = getDevice(system.getSystemType()).doResyncLink(system, fileShare, completer); } if (result.getCommandSuccess()) { _log.info("file replication operation {} finished successfully for file systerm {}", opType, fileShare.getName()); completer.ready(_dbClient); } else if (result.getCommandPending()) { completer.statusPending(_dbClient, result.getMessage()); } else { completer.error(_dbClient, result.getServiceCoded()); } } catch (Exception e) { _log.error("unable to perform mirror operation {} on file system {} ", opType, sourceFSURI, e); updateTaskStatus(opId, fileShare, e); ServiceError error = DeviceControllerException.errors.jobFailed(e); WorkflowStepCompleter.stepFailed(opId, error); } } /** * Fail over Work flow Method * * @param storage target storage system * @param fileshareURI target file system URI * @param completer * @param opId */ public void failoverFileSystem(URI storage, URI fileshareURI, TaskCompleter completer, String opId) { try { StorageSystem system = _dbClient.queryObject(StorageSystem.class, storage); FileShare fileShare = _dbClient.queryObject(FileShare.class, fileshareURI); WorkflowStepCompleter.stepExecuting(opId); _log.info("Execution of Failover Job Started"); BiosCommandResult cmdResult = getDevice(system.getSystemType()).doFailoverLink(system, fileShare, completer); if (cmdResult.getCommandSuccess()) { completer.ready(_dbClient); } else if (cmdResult.getCommandPending()) { completer.statusPending(_dbClient, cmdResult.getMessage()); } else { completer.error(_dbClient, cmdResult.getServiceCoded()); } } catch (Exception e) { ServiceError error = DeviceControllerException.errors.jobFailed(e); if (null != completer) { completer.error(this._dbClient, error); } WorkflowStepCompleter.stepFailed(opId, error); } } @Override public void checkFilePolicyPathHasResourceLabel(URI storage, URI filePolicyURI, URI nasURI, URI vpoolURI, URI projectURI, String opId) { try { WorkflowStepCompleter.stepExecuting(opId); StorageSystem system = _dbClient.queryObject(StorageSystem.class, storage); FileDeviceInputOutput args = new FileDeviceInputOutput(); FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, filePolicyURI); args.setFileProtectionPolicy(filePolicy); if (vpoolURI != null) { VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, vpoolURI); args.setVPool(vpool); } if (projectURI != null) { Project project = _dbClient.queryObject(Project.class, projectURI); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg()); args.setProject(project); args.setTenantOrg(tenant); } if (nasURI != null) { if (URIUtil.isType(nasURI, VirtualNAS.class)) { VirtualNAS vNAS = _dbClient.queryObject(VirtualNAS.class, nasURI); args.setvNAS(vNAS); } } BiosCommandResult result = getDevice(system.getSystemType()).checkFilePolicyPathHasResourceLabel(system, args); if (result.getCommandPending()) { return; } if (!result.isCommandSuccess() && !result.getCommandPending()) { WorkflowStepCompleter.stepFailed(opId, result.getServiceCoded()); } if (result.isCommandSuccess()) { WorkflowStepCompleter.stepSucceded(opId); } } catch (Exception e) { ServiceError error = DeviceControllerException.errors.jobFailed(e); _log.error("Error occured while checking policy path has resorce label.", e); WorkflowStepCompleter.stepFailed(opId, error); } } }