/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource; import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource; import static com.emc.storageos.api.mapper.FileMapper.map; import static com.emc.storageos.api.mapper.TaskMapper.toTask; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.api.mapper.functions.MapFileShare; import com.emc.storageos.api.service.authorization.PermissionsHelper; import com.emc.storageos.api.service.impl.placement.FilePlacementManager; import com.emc.storageos.api.service.impl.placement.FileRecommendation; import com.emc.storageos.api.service.impl.placement.FileStorageScheduler; import com.emc.storageos.api.service.impl.placement.VirtualPoolUtil; import com.emc.storageos.api.service.impl.resource.utils.CapacityUtils; import com.emc.storageos.api.service.impl.resource.utils.CifsShareUtility; import com.emc.storageos.api.service.impl.resource.utils.ExportVerificationUtility; import com.emc.storageos.api.service.impl.resource.utils.FilePolicyServiceUtils; import com.emc.storageos.api.service.impl.resource.utils.FileSystemReplicationUtils; import com.emc.storageos.api.service.impl.resource.utils.NfsACLUtility; import com.emc.storageos.api.service.impl.resource.utils.VirtualPoolChangeAnalyzer; import com.emc.storageos.api.service.impl.response.BulkList; import com.emc.storageos.api.service.impl.response.ProjOwnedResRepFilter; import com.emc.storageos.api.service.impl.response.ResRepFilter; import com.emc.storageos.api.service.impl.response.RestLinkFactory; import com.emc.storageos.api.service.impl.response.SearchedResRepList; import com.emc.storageos.computesystemorchestrationcontroller.ComputeSystemOrchestrationController; 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.ContainmentPrefixConstraint; import com.emc.storageos.db.client.constraint.PrefixConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus; 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.FilePolicy; import com.emc.storageos.db.client.model.FilePolicy.FilePolicyType; import com.emc.storageos.db.client.model.FilePolicy.FileReplicationType; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.FileShare.MirrorStatus; import com.emc.storageos.db.client.model.FileShare.PersonalityTypes; import com.emc.storageos.db.client.model.IpInterface; import com.emc.storageos.db.client.model.NamedURI; import com.emc.storageos.db.client.model.OpStatusMap; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.model.Project; import com.emc.storageos.db.client.model.QuotaDirectory; import com.emc.storageos.db.client.model.QuotaDirectory.SecurityStyles; 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.StoragePool; import com.emc.storageos.db.client.model.StoragePort; import com.emc.storageos.db.client.model.StorageProtocol; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.Task; import com.emc.storageos.db.client.model.TenantOrg; import com.emc.storageos.db.client.model.VirtualArray; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.db.client.model.VirtualPool.FileReplicationRPOType; import com.emc.storageos.db.client.model.util.TaskUtils; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.FileOperationUtils; import com.emc.storageos.db.client.util.NameGenerator; import com.emc.storageos.db.client.util.SizeUtil; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.fileorchestrationcontroller.FileDescriptor; import com.emc.storageos.fileorchestrationcontroller.FileDescriptor.Type; import com.emc.storageos.fileorchestrationcontroller.FileOrchestrationController; import com.emc.storageos.model.BulkIdParam; import com.emc.storageos.model.BulkRestRep; import com.emc.storageos.model.RelatedResourceRep; import com.emc.storageos.model.ResourceOperationTypeEnum; import com.emc.storageos.model.ResourceTypeEnum; import com.emc.storageos.model.RestLinkRep; import com.emc.storageos.model.SnapshotList; import com.emc.storageos.model.TaskList; import com.emc.storageos.model.TaskResourceRep; import com.emc.storageos.model.block.MirrorList; import com.emc.storageos.model.file.ExportRule; import com.emc.storageos.model.file.ExportRules; import com.emc.storageos.model.file.FileCifsShareACLUpdateParams; import com.emc.storageos.model.file.FileExportUpdateParam; import com.emc.storageos.model.file.FileNfsACLUpdateParams; import com.emc.storageos.model.file.FilePolicyList; import com.emc.storageos.model.file.FilePolicyRestRep; import com.emc.storageos.model.file.FileReplicationCreateParam; import com.emc.storageos.model.file.FileReplicationParam; import com.emc.storageos.model.file.FileShareBulkRep; import com.emc.storageos.model.file.FileShareExportUpdateParams; import com.emc.storageos.model.file.FileShareRestRep; import com.emc.storageos.model.file.FileSystemDeleteParam; import com.emc.storageos.model.file.FileSystemExpandParam; import com.emc.storageos.model.file.FileSystemExportList; import com.emc.storageos.model.file.FileSystemExportParam; import com.emc.storageos.model.file.FileSystemMountParam; import com.emc.storageos.model.file.FileSystemParam; import com.emc.storageos.model.file.FileSystemReplicationSettings; import com.emc.storageos.model.file.FileSystemShareList; import com.emc.storageos.model.file.FileSystemShareParam; import com.emc.storageos.model.file.FileSystemSnapshotParam; import com.emc.storageos.model.file.FileSystemUnmountParam; import com.emc.storageos.model.file.FileSystemUpdateParam; import com.emc.storageos.model.file.FileSystemVirtualPoolChangeParam; import com.emc.storageos.model.file.MountInfo; import com.emc.storageos.model.file.MountInfoList; import com.emc.storageos.model.file.NfsACLs; import com.emc.storageos.model.file.QuotaDirectoryCreateParam; import com.emc.storageos.model.file.QuotaDirectoryList; import com.emc.storageos.model.file.ScheduleSnapshotList; import com.emc.storageos.model.file.ScheduleSnapshotRestRep; import com.emc.storageos.model.file.ShareACL; import com.emc.storageos.model.file.ShareACLs; import com.emc.storageos.model.file.SmbShareResponse; import com.emc.storageos.model.file.policy.FilePolicyFileSystemAssignParam; import com.emc.storageos.model.search.SearchResultResourceRep; import com.emc.storageos.model.search.SearchResults; import com.emc.storageos.security.audit.AuditLogManager; import com.emc.storageos.security.authentication.StorageOSUser; import com.emc.storageos.security.authorization.ACL; import com.emc.storageos.security.authorization.CheckPermission; import com.emc.storageos.security.authorization.DefaultPermissions; import com.emc.storageos.security.authorization.Role; import com.emc.storageos.services.OperationTypeEnum; import com.emc.storageos.services.util.TimeUtils; 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.BadRequestException; import com.emc.storageos.svcs.errorhandling.resources.InternalException; import com.emc.storageos.svcs.errorhandling.resources.ServiceCode; import com.emc.storageos.volumecontroller.ControllerException; import com.emc.storageos.volumecontroller.FileController; import com.emc.storageos.volumecontroller.FileControllerConstants; import com.emc.storageos.volumecontroller.FileSMBShare; import com.emc.storageos.volumecontroller.FileShareExport; import com.emc.storageos.volumecontroller.FileShareExport.Permissions; import com.emc.storageos.volumecontroller.FileShareExport.SecurityTypes; import com.emc.storageos.volumecontroller.FileShareQuotaDirectory; import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper; @Path("/file/filesystems") @DefaultPermissions(readRoles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, readAcls = { ACL.OWN, ACL.ALL }, writeRoles = { Role.TENANT_ADMIN }, writeAcls = { ACL.OWN, ACL.ALL }) public class FileService extends TaskResourceService { private static final Logger _log = LoggerFactory.getLogger(FileService.class); public static final String UNLIMITED_USERS = "unlimited"; private static final String EVENT_SERVICE_TYPE = "file"; protected static final String PROTOCOL_NFS = "NFS"; protected static final String PROTOCOL_CIFS = "CIFS"; private static final Long MINUTES_PER_HOUR = 60L; private static final Long HOURS_PER_DAY = 24L; @Override public String getServiceType() { return EVENT_SERVICE_TYPE; } @SuppressWarnings("unchecked") @Override public Class<FileShare> getResourceClass() { return FileShare.class; } @Override public FileShareBulkRep queryBulkResourceReps(List<URI> ids) { Iterator<FileShare> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); return new FileShareBulkRep(BulkList.wrapping(_dbIterator, MapFileShare.getInstance())); } @Override protected BulkRestRep queryFilteredBulkResourceReps( List<URI> ids) { Iterator<FileShare> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); BulkList.ResourceFilter<FileShare> filter = new BulkList.ProjectResourceFilter<FileShare>( getUserFromContext(), _permissionsHelper); return new FileShareBulkRep(BulkList.wrapping(_dbIterator, MapFileShare.getInstance(), filter)); } private FileStorageScheduler _fileScheduler; private NameGenerator _nameGenerator; public NameGenerator getNameGenerator() { return _nameGenerator; } public void setNameGenerator(NameGenerator nameGenerator) { _nameGenerator = nameGenerator; } public void setFileScheduler(FileStorageScheduler fileScheduler) { _fileScheduler = fileScheduler; } FilePlacementManager _filePlacementManager; // File service implementations static volatile private Map<String, FileServiceApi> _fileServiceApis; public static FileServiceApi getFileServiceApis(String Type) { return _fileServiceApis.get(Type); } public static void setFileServiceApis(Map<String, FileServiceApi> _fileServiceApis) { FileService._fileServiceApis = _fileServiceApis; } public void setFilePlacementManager(FilePlacementManager placementManager) { _filePlacementManager = placementManager; } public enum FileTechnologyType { LOCAL_MIRROR, REMOTE_MIRROR, }; public enum FileSystemMountType { AUTO, NFS, NFS4; public static boolean contains(String fsType) { for (FileSystemMountType type : FileSystemMountType.values()) { if (type.name().equalsIgnoreCase(fsType)) { return true; } } return false; } } // Protection operations that are allowed with /file/filesystems/{id}/protection/continuous-copies/ public static enum ProtectionOp { FAILOVER("failover", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_FAILOVER), FAILBACK("failback", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_FAILBACK), START("start", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_START), STOP("stop", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_STOP), PAUSE("pause", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_PAUSE), RESUME("resume", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_RESUME), REFRESH("refresh", ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_REFRESH), UNKNOWN("unknown", ResourceOperationTypeEnum.PERFORM_PROTECTION_ACTION), UPDATE_RPO("update-rpo", ResourceOperationTypeEnum.UPDATE_FILE_SYSTEM_REPLICATION_RPO); private final String op; private final ResourceOperationTypeEnum resourceType; ProtectionOp(String op, ResourceOperationTypeEnum resourceType) { this.op = op; this.resourceType = resourceType; } // The rest URI operation public String getRestOp() { return op; } // The resource type, which contains a good name and description public ResourceOperationTypeEnum getResourceType() { return resourceType; } private static final ProtectionOp[] copyOfValues = values(); public static String getProtectionOpDisplayName(String op) { for (ProtectionOp opValue : copyOfValues) { if (opValue.getRestOp().contains(op)) { return opValue.getResourceType().getName(); } } return ProtectionOp.UNKNOWN.name(); } public static ResourceOperationTypeEnum getResourceOperationTypeEnum(String restOp) { for (ProtectionOp opValue : copyOfValues) { if (opValue.getRestOp().contains(restOp)) { return opValue.getResourceType(); } } return ResourceOperationTypeEnum.FILE_PROTECTION_ACTION; } } /** * Creates file system. * * The VNX File array does not allow 'root' as the beginning of a file system name. If the generated file system * name begins with 'root', then the VNX File array will return an error. * <p> * NOTE: This is an asynchronous operation. * * @param param * File system parameters * @param id * the URN of a ViPR Project * @brief Create file system * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep createFileSystem(FileSystemParam param, @QueryParam("project") URI id) throws InternalException { // check project ArgValidator.checkFieldUriType(id, Project.class, "project"); // Make label as mandatory field ArgValidator.checkFieldNotNull(param.getLabel(), "label"); Project project = _permissionsHelper.getObjectById(id, Project.class); ArgValidator.checkEntity(project, id, isIdEmbeddedInURL(id)); ArgValidator.checkFieldNotNull(project.getTenantOrg(), "project"); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, project.getTenantOrg().getURI()); return createFSInternal(param, project, tenant, null); } /* * all the common code for provisioning fs both in normal public API use case and * the internal object case * NOTE - below method should always work with project being null */ public TaskResourceRep createFSInternal(FileSystemParam param, Project project, TenantOrg tenant, DataObject.Flag[] flags) throws InternalException { ArgValidator.checkFieldUriType(param.getVpool(), VirtualPool.class, "vpool"); ArgValidator.checkFieldUriType(param.getVarray(), VirtualArray.class, "varray"); Long fsSize = SizeUtil.translateSize(param.getSize()); // Convert to MB and check for 20MB min size. Long fsSizeMB = fsSize / (1024 * 1024); // Convert to MB and check for 20MB min size. // VNX file has min 2MB size, NetApp 20MB and Isilon 0 // VNX File 8.1.6 min 1GB size ArgValidator.checkFieldMinimum(fsSizeMB, 1024, "MB", "size"); ArrayList<String> requestedTypes = new ArrayList<String>(); // check varray VirtualArray neighborhood = _dbClient.queryObject(VirtualArray.class, param.getVarray()); ArgValidator.checkEntity(neighborhood, param.getVarray(), false); _permissionsHelper.checkTenantHasAccessToVirtualArray(tenant.getId(), neighborhood); String task = UUID.randomUUID().toString(); // check vpool reference VirtualPool cos = _dbClient.queryObject(VirtualPool.class, param.getVpool()); _permissionsHelper.checkTenantHasAccessToVirtualPool(tenant.getId(), cos); ArgValidator.checkEntity(cos, param.getVpool(), false); if (!VirtualPool.Type.file.name().equals(cos.getType())) { throw APIException.badRequests.virtualPoolNotForFileBlockStorage(VirtualPool.Type.file.name()); } // prepare vpool capability values VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper(); capabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, fsSize); capabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, new Integer(1)); if (VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(cos.getSupportedProvisioningType())) { capabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, Boolean.TRUE); } StringBuilder errorMsg = new StringBuilder(); if (cos.getFileReplicationSupported() && !FilePolicyServiceUtils.updatePolicyCapabilities(_dbClient, neighborhood, cos, project, null, capabilities, errorMsg)) { _log.error("File system can not be created, ", errorMsg.toString()); throw APIException.badRequests.unableToProcessRequest(errorMsg.toString()); } ArgValidator.checkFieldMaximum(param.getSoftLimit(), 100, "softLimit"); ArgValidator.checkFieldMaximum(param.getNotificationLimit(), 100, "notificationLimit"); if (param.getSoftLimit() != 0L) { ArgValidator.checkFieldMinimum(param.getSoftGrace(), 1L, "softGrace"); } if (param.getNotificationLimit() != 0) { capabilities.put(VirtualPoolCapabilityValuesWrapper.SUPPORT_NOTIFICATION_LIMIT, Boolean.TRUE); } if (param.getSoftLimit() != 0) { capabilities.put(VirtualPoolCapabilityValuesWrapper.SUPPORT_SOFT_LIMIT, Boolean.TRUE); } // verify quota CapacityUtils.validateQuotasForProvisioning(_dbClient, cos, project, tenant, fsSize, "filesystem"); String suggestedNativeFsId = param.getFsId() == null ? "" : param.getFsId(); // Find the implementation that services this vpool and fileshare FileServiceApi fileServiceApi = getFileServiceImpl(capabilities, _dbClient); TaskList taskList = createFileTaskList(param, project, tenant, neighborhood, cos, flags, task); // call thread that does the work. CreateFileSystemSchedulingThread.executeApiTask(this, _asyncTaskService.getExecutorService(), _dbClient, neighborhood, project, cos, tenant, flags, capabilities, taskList, task, requestedTypes, param, fileServiceApi, suggestedNativeFsId); auditOp(OperationTypeEnum.CREATE_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, param.getLabel(), param.getSize(), neighborhood.getId().toString(), project == null ? null : project.getId().toString()); // Till we Support multiple file system create // return the file share taskrep return taskList.getTaskList().get(0); } /** * Allocate, initialize and persist state of the fileSystem being created. * * @param param * @param project * @param neighborhood * @param vpool * @param placement * @param token * @return */ private FileShare prepareEmptyFileSystem(FileSystemParam param, Project project, TenantOrg tenantOrg, VirtualArray varray, VirtualPool vpool, DataObject.Flag[] flags, String task) { _log.debug("prepareEmptyFileSystem start..."); StoragePool pool = null; FileShare fs = new FileShare(); fs.setId(URIUtil.createId(FileShare.class)); fs.setLabel(param.getLabel()); // No need to generate any name -- Since the requirement is to use the customizing label we should use the same. // Stripping out the special characters like ; /-+!@#$%^&())";:[]{}\ | but allow underscore character _ String convertedName = param.getLabel().replaceAll("[^\\dA-Za-z\\_]", ""); _log.info("Original name {} and converted name {}", param.getLabel(), convertedName); fs.setName(convertedName); Long fsSize = SizeUtil.translateSize(param.getSize()); fs.setCapacity(fsSize); fs.setNotificationLimit(Long.valueOf(param.getNotificationLimit())); fs.setSoftLimit(Long.valueOf(param.getSoftLimit())); fs.setSoftGracePeriod(param.getSoftGrace()); fs.setVirtualPool(param.getVpool()); if (project != null) { fs.setProject(new NamedURI(project.getId(), fs.getLabel())); } fs.setTenant(new NamedURI(tenantOrg.getId(), param.getLabel())); fs.setVirtualArray(varray.getId()); // When a VPool supports "thin" provisioning if (VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(vpool.getSupportedProvisioningType())) { fs.setThinlyProvisioned(Boolean.TRUE); } fs.setOpStatus(new OpStatusMap()); Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.CREATE_FILE_SYSTEM); fs.getOpStatus().createTaskStatus(task, op); if (flags != null) { fs.addInternalFlags(flags); } _dbClient.createObject(fs); return fs; } private void setProtectionCapWrapper(final VirtualPool vPool, VirtualPoolCapabilityValuesWrapper capabilities) { // validate the vpool for protection and throw error if any other field invalid if (vPool.getFileReplicationType() != null) { // file replication tyep either LOCAL OR REMOTE // TODO: File does not use these fields and this should return an error if any of them are set. // COP-22903 if (vPool.getFrRpoType() != null) { // rpo type can be DAYS or HOURS capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_RPO_TYPE, vPool.getFrRpoType()); } if (vPool.getFrRpoValue() != null) { capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_RPO_VALUE, vPool.getFrRpoValue()); } // async or copy // async - soure changes will mirror target // copy - it kind backup, it is full copy if (vPool.getFileReplicationCopyMode() != null) { capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_COPY_MODE, vPool.getFileReplicationCopyMode()); } } } /** * A method that pre-creates task and FileShare object to return to the caller of the API. * * @param param * @param project * - project of the FileShare * @param tenantOrg * - tenant of the FileShare * @param varray * - varray of the FileShare * @param vpool * - vpool of the Fileshare * @param flags * - * @param task * @return */ private TaskList createFileTaskList(FileSystemParam param, Project project, TenantOrg tenantOrg, VirtualArray varray, VirtualPool vpool, DataObject.Flag[] flags, String task) { TaskList taskList = new TaskList(); FileShare fs = prepareEmptyFileSystem(param, project, tenantOrg, varray, vpool, flags, task); TaskResourceRep fileTask = toTask(fs, task); taskList.getTaskList().add(fileTask); _log.info(String.format("FileShare and Task Pre-creation Objects [Init]-- Source FileSystem: %s, Task: %s, Op: %s", fs.getId(), fileTask.getId(), task)); return taskList; } /** * Get info for file system * * @param id * the URN of a ViPR File system * @brief Show file system * @return File system details */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public FileShareRestRep getFileSystem(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); return map(fs); } /** * * 'mountPath' is not case sensitive. The complete mountPath should be specified. * * If a matching filesystem is not found, an empty list is returned. * * Parameters - mountPath String - mountPath of the filesystem */ @Override protected SearchResults getOtherSearchResults(Map<String, List<String>> parameters, boolean authorized) { SearchResults result = new SearchResults(); // Here we search by mountPath if (!parameters.containsKey("mountPath")) { throw APIException.badRequests.invalidParameterSearchMissingParameter(getResourceClass().getName(), "mountPath"); } String mountPath = parameters.get("mountPath").get(0); List<SearchResultResourceRep> resRepList = new ArrayList<SearchResultResourceRep>(); URIQueryResultList fsUriList = new URIQueryResultList(); _dbClient.queryByConstraint( AlternateIdConstraint.Factory.getFileSystemMountPathConstraint( mountPath), fsUriList); _log.info("After query of the database for {} and result {}", mountPath, fsUriList); Iterator<URI> fsListIterator = fsUriList.iterator(); while (fsListIterator.hasNext()) { URI uri = fsListIterator.next(); FileShare fs = _dbClient.queryObject(FileShare.class, uri); if (!fs.getInactive()) { if (authorized || isAuthorized(fs.getProject().getURI())) { RestLinkRep selfLink = new RestLinkRep("self", RestLinkFactory.newLink(getResourceType(), uri)); SearchResultResourceRep r = new SearchResultResourceRep(uri, selfLink, fs.getMountPath()); resRepList.add(r); _log.info("Mount path match " + fs.getMountPath()); } else { _log.info("Mount path match but not authorized " + fs.getMountPath()); } } } result.setResource(resRepList); return result; } @Override protected FileShare queryResource(URI id) { ArgValidator.checkUri(id); FileShare fs = _permissionsHelper.getObjectById(id, FileShare.class); ArgValidator.checkEntityNotNull(fs, id, isIdEmbeddedInURL(id)); return fs; } @Override protected URI getTenantOwner(URI id) { FileShare fs = queryResource(id); return fs.getTenant().getURI(); } /** * @Deprecated use @Path("/{id}/export") instead. * Get list of file system exports * @param id * the URN of a ViPR File system * @brief List file system exports. * <p> * Use /file/filesystems/{id}/export instead * @return File system exports list. */ @Deprecated @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/exports") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public FileSystemExportList getFileSystemExportList(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fileShare = queryResource(id); FileSystemExportList fileExportListResponse = new FileSystemExportList(); if (fileShare.getInactive()) { return fileExportListResponse; } // Get export map from fileSystem FSExportMap exportMap = fileShare.getFsExports(); Collection<FileExport> fileExports = new ArrayList<FileExport>(); if (exportMap != null) { fileExports = exportMap.values(); } // Process each export from the map and its data to exports in response list. for (FileExport fileExport : fileExports) { FileSystemExportParam fileExportParam = new FileSystemExportParam(); fileExportParam.setEndpoints(fileExport.getClients()); fileExportParam.setSecurityType(fileExport.getSecurityType()); fileExportParam.setPermissions(fileExport.getPermissions()); fileExportParam.setRootUserMapping(fileExport.getRootUserMapping()); fileExportParam.setProtocol(fileExport.getProtocol()); fileExportParam.setMountPoint(fileExport.getMountPoint()); fileExportParam.setSubDirectory(fileExport.getSubDirectory()); fileExportListResponse.getExportList().add(fileExportParam); } return fileExportListResponse; } /** * Since, Modifying an export is not allowed * This method verifies the existing export params with the new one issued to modify. * * @param fs * @param param */ private void verifyExports(FileShare fs, FileExportUpdateParam param, String permissions, String securityType, String rootUserMapping, String path) { // Check to see if th permission passed in is valid Boolean allowedPermission = false; for (Permissions me : Permissions.values()) { if (me.name().equalsIgnoreCase(permissions)) { allowedPermission = true; break; } } if (!allowedPermission) { throw APIException.badRequests.invalidPermissionType(permissions); } // Check to see if the Security Type passed in is valid Boolean allowedsecurityType = false; for (SecurityTypes secType : SecurityTypes.values()) { if (secType.name().equalsIgnoreCase(securityType)) { allowedsecurityType = true; break; } } if (!allowedsecurityType) { throw APIException.badRequests.invalidSecurityType(securityType); } FSExportMap fsExports = fs.getFsExports(); URI id = fs.getId(); // The below logic should satisfy the following test cases // 1. if a fresh new export request received it should go through. // 2. if an export modify found meaning that, the path matched and the request received for same end point: // 2.1 if there is any change in perm, sec, user further processing of request is not allowed. // 2.2 if there is no change in perm, sec, user, end point request should process to override the export. // 3. if an export modify found and path not matched, let the request proceed as it is. // 4. if no export modify found, let the request proceed. if (null != fsExports) { Iterator<FileExport> it = fs.getFsExports().values().iterator(); while (it.hasNext()) { FileExport fileExport = it.next(); // If no key found then it should process as it is. boolean isAlreadyExportedToSameEndpoint = false; if (fileExport.getPath().equals(path)) { List<String> availableEndpoints = fileExport.getClients(); List<String> providedEndpoints = param.getAdd(); for (String providedEndpoint : providedEndpoints) { if (availableEndpoints.contains(providedEndpoint)) { isAlreadyExportedToSameEndpoint = true; break; } } if (isAlreadyExportedToSameEndpoint) { _log.info(String.format( "Existing Export params for FileShare id: %1$s, SecurityType: %2$s, " + "Permissions: %3$s, Root user mapping: %4$s, ", id, fileExport.getSecurityType(), fileExport.getPermissions(), fileExport.getRootUserMapping())); _log.info(String.format( "Recieved Export params for FileShare id: %1$s, SecurityType: %2$s, " + "Permissions: %3$s, Root user mapping: %4$s, ", id, securityType, permissions, rootUserMapping)); if (!fileExport.getPermissions().equals(permissions)) { throw APIException.badRequests.updatingFileSystemExportNotAllowed("permission"); } if (!fileExport.getSecurityType().equals(securityType)) { throw APIException.badRequests.updatingFileSystemExportNotAllowed("security type"); } if (!fileExport.getRootUserMapping().equals(rootUserMapping)) { throw APIException.badRequests.updatingFileSystemExportNotAllowed("root user mapping"); } } } } } } /** * Export file system. * * <p> * NOTE: This is an asynchronous operation. * * @param param * File system export parameters * @param id * the URN of a ViPR File system * @brief Create file export * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/exports") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep export(@PathParam("id") URI id, FileSystemExportParam param) throws InternalException { _log.info("Export request recieved {}", id); // check file System ArgValidator.checkFieldUriType(id, FileShare.class, "id"); ArgValidator.checkFieldValueFromEnum(param.getPermissions(), "permissions", EnumSet.allOf(FileShareExport.Permissions.class)); _log.info("Export security type {}", param.getSecurityType()); for (String sectype : param.getSecurityType().split(",")) { ArgValidator.checkFieldValueFromEnum(sectype.trim(), "type", EnumSet.allOf(FileShareExport.SecurityTypes.class)); } ArgValidator.checkFieldValueFromEnum(param.getProtocol(), "protocol", EnumSet.allOf(StorageProtocol.File.class)); validateIpInterfacesRegistered(param.getEndpoints(), _dbClient); FileShare fs = queryResource(id); String task = UUID.randomUUID().toString(); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // Check for VirtualPool whether it has NFS enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.NFS.name()) && !vpool.getProtocols().contains(StorageProtocol.File.NFSv4.name())) { // Throw an error throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool doesn't support " + StorageProtocol.File.NFS.name() + " or " + StorageProtocol.File.NFSv4 + " protocol"); } // locate storage port for exporting file System StoragePort sport = _fileScheduler.placeFileShareExport(fs, param.getProtocol(), param.getEndpoints()); String path = fs.getPath(); String mountPath = fs.getMountPath(); String subDirectory = param.getSubDirectory(); if (param.getSubDirectory() != null && !param.getSubDirectory().equalsIgnoreCase("null") && param.getSubDirectory().length() > 0) { // Add subdirectory to the path as this is a subdirectory export path += "/" + param.getSubDirectory(); mountPath += "/" + param.getSubDirectory(); } FSExportMap exportMap = fs.getFsExports(); if (exportMap != null) { Iterator it = fs.getFsExports().keySet().iterator(); boolean exportExists = false; while (it.hasNext()) { String fsExpKey = (String) it.next(); FileExport fileExport = fs.getFsExports().get(fsExpKey); if (fileExport.getPath().equalsIgnoreCase(path)) { exportExists = true; break; } } if (exportExists) { throw APIException.badRequests.fileSystemHasExistingExport(); } } String rootUserMapping = param.getRootUserMapping(); if (rootUserMapping != null) { rootUserMapping = rootUserMapping.toLowerCase(); } if (!"nobody".equals(rootUserMapping)) { StorageOSUser user = getUserFromContext(); if (!user.getName().equals(rootUserMapping)) { // throw error throw APIException.forbidden.onlyCurrentUserCanBeSetInRootUserMapping(user.getName()); } } // check for bypassDnsCheck flag. If null then set to false Boolean dnsCheck = param.getBypassDnsCheck(); if (dnsCheck == null) { dnsCheck = false; } FileShareExport export = new FileShareExport(param.getEndpoints(), param.getSecurityType(), param.getPermissions(), rootUserMapping, param.getProtocol(), sport.getPortGroup(), sport.getPortNetworkId(), path, mountPath, subDirectory, param.getComments(), dnsCheck); _log.info(String.format( "FileShareExport --- FileShare id: %1$s, Clients: %2$s, StoragePort: %3$s, SecurityType: %4$s, " + "Permissions: %5$s, Root user mapping: %6$s, Protocol: %7$s, path: %8$s, mountPath: %9$s, SubDirectory: %10$s ,byPassDnsCheck: %11$s", id, export.getClients(), sport.getPortName(), export.getSecurityType(), export.getPermissions(), export.getRootUserMapping(), export.getProtocol(), export.getPath(), export.getMountPath(), export.getSubDirectory(), export.getBypassDnsCheck())); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.EXPORT_FILE_SYSTEM); op.setDescription("Filesystem export"); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.export(device.getId(), fs.getId(), Arrays.asList(export), task); auditOp(OperationTypeEnum.EXPORT_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), export.getClients(), param.getSecurityType(), param.getPermissions(), param.getRootUserMapping(), param.getProtocol()); return toTask(fs, task, op); } /** * @Deprecated use @Path("/{id}/export") instead * * Existing file system exports may have their list of endpoints updated. The permission, security, or * root user * mapping of an existing export may not be changed. In order to change one of these attributes, the * export must be * first deleted and then created with the new value. * * @param id * the URN of a ViPR Project * @param protocol * Protocol valid values - NFS,NFSv4,CIFS * @param securityType * Security type valid values - sys,krb5,krb5i,krb5p * @param permissions * Permissions valid values - ro,rw,root * @param rootUserMapping * Root user mapping * @brief Update file system export. * <p> * Use /file/filesystems/{id}/export instead * @return Task resource representation * @throws InternalException */ @Deprecated @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/exports/{protocol},{secType},{perm},{root_mapping}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep updateExport(@PathParam("id") URI id, @PathParam("protocol") String protocol, @PathParam("secType") String securityType, @PathParam("perm") String permissions, @PathParam("root_mapping") String rootUserMapping, FileExportUpdateParam param) throws InternalException { _log.info("Export update request received {}", id); // Validate the input. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkFieldNotNull(protocol, "protocol"); ArgValidator.checkFieldNotNull(securityType, "secType"); ArgValidator.checkFieldNotNull(permissions, "perm"); ArgValidator.checkFieldNotNull(rootUserMapping, "root_mapping"); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); ArgValidator.checkFieldNotEmpty(fs.getFsExports(), "exports"); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileController controller = getController(FileController.class, device.getSystemType()); String path = fs.getPath(); _log.info("update export for path {} ", path); _log.info(String.format("securityType %1$s, permissions %2$s, rootMapping %3$s, protocol %4$s FileSystem %5$s", securityType, permissions, rootUserMapping, protocol, path)); FileExport fExport = fs.getFsExports().get(FileExport.exportLookupKey(protocol, securityType, permissions, rootUserMapping, path)); if (fExport == null) { throw APIException.badRequests.invalidParameterFileSystemNoSuchExport(); } validateIpInterfacesRegistered(param.getAdd(), _dbClient); verifyExports(fs, param, permissions, securityType, rootUserMapping, path); String task = UUID.randomUUID().toString(); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.EXPORT_FILE_SYSTEM); // Update the list. List<String> clients = fExport.getClients(); if (param.getAdd() != null) { for (String addEndpoint : param.getAdd()) { clients.add(addEndpoint); } } if (param.getRemove() != null) { for (String delEndpoint : param.getRemove()) { clients.remove(delEndpoint); } } FileShareExport export = new FileShareExport(clients, securityType, permissions, rootUserMapping, protocol, fExport.getStoragePortName(), fExport.getStoragePort(), path, fExport.getMountPath(), fExport.getSubDirectory(), param.getComments()); controller.export(device.getId(), fs.getId(), Arrays.asList(export), task); auditOp(OperationTypeEnum.EXPORT_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), export.getClients(), securityType, permissions, rootUserMapping, protocol); return toTask(fs, task, op); } /** * @Deprecated use @Path("/{id}/export") instead * * <p> * NOTE: This is an asynchronous operation. * @param id * the URN of a ViPR Project * @param protocol * Protocol valid values - NFS,NFSv4,CIFS * @param securityType * Security type valid values - sys,krb5,krb5i,krb5p * @param permissions * Permissions valid values - ro,rw,root * @param rootUserMapping * Root user mapping * @brief Delete file system export. * <p> * Use /file/filesystems/{id}/export instead * @return Task resource representation * @throws InternalException */ @Deprecated @DELETE @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/exports/{protocol},{secType},{perm},{root_mapping}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep unexport(@PathParam("id") URI id, @PathParam("protocol") String protocol, @PathParam("secType") String securityType, @PathParam("perm") String permissions, @PathParam("root_mapping") String rootUserMapping, @QueryParam("subDirectory") String subDirectory) throws InternalException { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkFieldNotNull(protocol, "protocol"); ArgValidator.checkFieldNotNull(securityType, "secType"); ArgValidator.checkFieldNotNull(permissions, "perm"); ArgValidator.checkFieldNotNull(rootUserMapping, "root_mapping"); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); String task = UUID.randomUUID().toString(); if (fs.getFsExports() == null) { // No exports present. Return success. return getSuccessResponse(fs, task, ResourceOperationTypeEnum.UNEXPORT_FILE_SYSTEM, "Export does not exist"); } if (fs.getStoragePort() == null) { // port associated with export, fail the operation return getFailureResponse(fs, task, ResourceOperationTypeEnum.UNEXPORT_FILE_SYSTEM, "No storage port associated with " + fs.getLabel()); } StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileController controller = getController(FileController.class, device.getSystemType()); String path = fs.getPath(); String mountPath = fs.getMountPath(); if (subDirectory != null && subDirectory.length() > 0) { // Add subdirectory to the path as this is a subdirectory export path += "/" + subDirectory; mountPath += "/" + subDirectory; } FileExport fExport = null; _log.info("unexport subdirectory passed value is {}", subDirectory); if (subDirectory != null) { _log.info("unexport subdirectory {} with path {} ", subDirectory, path); _log.info(String.format("securityType %1$s, permissions %2$s, rootMapping %3$s, protocol %4$s subDirectory %5$s", securityType, permissions, rootUserMapping, protocol, path)); fExport = fs.getFsExports().get(FileExport.exportLookupKey(protocol, securityType, permissions, rootUserMapping, path)); } else { _log.info("unexport FS {} with path {} ", fs.getName(), path); _log.info(String.format("securityType %1$s, permissions %2$s, rootMapping %3$s, protocol %4$s FileSystem %5$s", securityType, permissions, rootUserMapping, protocol, path)); fExport = fs.getFsExports().get(FileExport.exportLookupKey(protocol, securityType, permissions, rootUserMapping, path)); } if (fExport == null) { // No export to unexport, return success. return getSuccessResponse(fs, task, ResourceOperationTypeEnum.UNEXPORT_FILE_SYSTEM, "Export does not exist"); } fExport.setStoragePort(fs.getStoragePort().toString()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.UNEXPORT_FILE_SYSTEM); op.setDescription("Filesystem unexport"); List<String> endpoints = new ArrayList<String>(); // empty list for unexport FileShareExport export = new FileShareExport(endpoints, securityType, permissions, rootUserMapping, protocol, fExport.getStoragePortName(), fExport.getStoragePort(), fExport.getPath()); export.setIsilonId(fExport.getIsilonId()); controller.unexport(device.getId(), fs.getId(), Arrays.asList(export), task); auditOp(OperationTypeEnum.UNEXPORT_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), securityType, permissions, rootUserMapping, protocol); return toTask(fs, task, op); } private TaskResourceRep getSuccessResponse(FileShare fs, String task, ResourceOperationTypeEnum type, String message) { Operation op = new Operation(); op.setResourceType(type); op.ready(message); _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, op); return toTask(fs, task, op); } private TaskResourceRep getFailureResponse(FileShare fs, String task, ResourceOperationTypeEnum type, String message) { Operation op = new Operation(); op.setResourceType(type); op.setMessage(message); ServiceCoded coded = ServiceError.buildServiceError( ServiceCode.API_BAD_REQUEST, message); op.error(coded); _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, op); return toTask(fs, task, op); } /** * Get list of SMB shares for the specified file system. * * @param id * the URN of a ViPR File system * @brief List file system SMB shares * @return List of file system shares. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/shares") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public FileSystemShareList getFileSystemShareList(@PathParam("id") URI id) { _log.info(String.format("Get list of SMB file shares for file system: %1$s", id)); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fileShare = queryResource(id); FileSystemShareList fileShareListResponse = new FileSystemShareList(); if (fileShare.getInactive()) { return fileShareListResponse; } SMBShareMap smbShareMap = fileShare.getSMBFileShares(); Collection<SMBFileShare> smbShares = new ArrayList<SMBFileShare>(); if (smbShareMap != null) { smbShares = smbShareMap.values(); } // Process each share from the map and add its data to shares in response list. for (SMBFileShare smbShare : smbShares) { SmbShareResponse shareParam = new SmbShareResponse(); shareParam.setShareName(smbShare.getName()); shareParam.setDescription(smbShare.getDescription()); shareParam.setMaxUsers(Integer.toString(smbShare.getMaxUsers())); // Check for "unlimited" if (shareParam.getMaxUsers().equals("-1")) { shareParam.setMaxUsers(UNLIMITED_USERS); } shareParam.setPermissionType(smbShare.getPermissionType()); shareParam.setPermission(smbShare.getPermission()); shareParam.setMountPoint(smbShare.getMountPoint()); shareParam.setPath(smbShare.getPath()); fileShareListResponse.getShareList().add(shareParam); } return fileShareListResponse; } /** * Get the SMB share for the specified file system. * * @param id * the URN of a ViPR File system * @param shareName * file system share name * @brief List file system SMB shares * @return List of file system shares. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/shares/{shareName}") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public SmbShareResponse getFileSystemShare(@PathParam("id") URI id, @PathParam("shareName") String shareName) throws InternalException { _log.info(String.format("Get SMB file share %s for file system: %s", shareName, id.toString())); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); ArgValidator.checkFieldNotNull(shareName, "shareName"); FileShare fileShare = queryResource(id); SMBFileShare smbShare = null; FileSystemShareList fileShareListResponse = new FileSystemShareList(); SmbShareResponse shareParam = null; if (fileShare.getSMBFileShares() != null) { _log.info("Number of SMBShares found {} and looking for share to read {} ", fileShare.getSMBFileShares().size(), shareName); _log.info(String.format("Get file system share: file system id: %1$s, share name %2$s", id, shareName)); smbShare = fileShare.getSMBFileShares().get(shareName); if (smbShare == null) { _log.info("CIFS share does not exist {}", shareName); } else { shareParam = new SmbShareResponse(); shareParam.setShareName(smbShare.getName()); shareParam.setDescription(smbShare.getDescription()); shareParam.setMaxUsers(Integer.toString(smbShare.getMaxUsers())); // Check for "unlimited" if (shareParam.getMaxUsers().equals("-1")) { shareParam.setMaxUsers(UNLIMITED_USERS); } shareParam.setPermissionType(smbShare.getPermissionType()); shareParam.setPermission(smbShare.getPermission()); shareParam.setMountPoint(smbShare.getMountPoint()); shareParam.setPath(smbShare.getPath()); } } return shareParam; } /** * Expand file system. * <p> * NOTE: This is an asynchronous operation. * * @param param * File system expansion parameters * @param id * the URN of a ViPR File system * @brief Expand file system * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/expand") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep expand(@PathParam("id") URI id, FileSystemExpandParam param) throws InternalException { _log.info(String.format( "FileShareExpand --- FileShare id: %1$s, New Size: %2$s", id, param.getNewSize())); // check file System ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); Long newFSsize = SizeUtil.translateSize(param.getNewSize()); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); if (newFSsize <= 0) { throw APIException.badRequests.parameterMustBeGreaterThan("new_size", 0); } // checkQuota long expand = newFSsize - fs.getCapacity(); final long MIN_EXPAND_SIZE = SizeUtil.translateSize("1MB") + 1; if (expand < MIN_EXPAND_SIZE) { throw APIException.badRequests.invalidParameterBelowMinimum("new_size", newFSsize, fs.getCapacity() + MIN_EXPAND_SIZE, "bytes"); } Project project = _dbClient.queryObject(Project.class, fs.getProject().getURI()); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, fs.getTenant().getURI()); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); CapacityUtils.validateQuotasForProvisioning(_dbClient, vpool, project, tenant, expand, "filesystem"); String task = UUID.randomUUID().toString(); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.EXPAND_FILE_SYSTEM); op.setDescription("Filesystem expand"); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); try { fileServiceApi.expandFileShare(fs, newFSsize, task); } catch (InternalException e) { if (_log.isErrorEnabled()) { _log.error("Expand File Size error", e); } FileShare fileShare = _dbClient.queryObject(FileShare.class, fs.getId()); op = fs.getOpStatus().get(task); op.error(e); fileShare.getOpStatus().updateTaskStatus(task, op); _dbClient.updateObject(fs); throw e; } return toTask(fs, task, op); } /** * Expand file system. * <p> * NOTE: This is an asynchronous operation. * * @param param * File system expansion parameters * @param id * the URN of a ViPR File system * @brief Expand file system * @return Task resource representation * @throws InternalException */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep update(@PathParam("id") URI id, FileSystemUpdateParam param) throws InternalException { _log.info(String.format("FileShareUpdate --- FileShare id: %1$s", id)); // check file System ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); Boolean deviceSupportsSoftLimit = device.getSupportSoftLimit() != null ? device.getSupportSoftLimit() : false; Boolean deviceSupportsNotificationLimit = device.getSupportNotificationLimit() != null ? device.getSupportNotificationLimit() : false; if (param.getSoftLimit() != 0 && !deviceSupportsSoftLimit) { throw APIException.badRequests.unsupportedParameterForStorageSystem("soft_limit"); } if (param.getNotificationLimit() != 0 && !deviceSupportsNotificationLimit) { throw APIException.badRequests.unsupportedParameterForStorageSystem("notification_limit"); } ArgValidator.checkFieldMaximum(param.getSoftLimit(), 100, "soft_limit"); ArgValidator.checkFieldMaximum(param.getNotificationLimit(), 100, "notification_limit"); if (param.getSoftLimit() > 0L) { ArgValidator.checkFieldMinimum(param.getSoftGrace(), 1L, "soft_grace"); fs.setSoftGracePeriod(param.getSoftGrace()); fs.setSoftLimit(Long.valueOf(param.getSoftLimit())); } if (param.getNotificationLimit() > 0) { fs.setNotificationLimit(Long.valueOf(param.getNotificationLimit())); } _dbClient.updateObject(fs); FileController controller = getController(FileController.class, device.getSystemType()); String task = UUID.randomUUID().toString(); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.UPDATE_FILE_SYSTEM); controller.modifyFS(fs.getStorageDevice(), fs.getPool(), id, task); op.setDescription("Filesystem update"); auditOp(OperationTypeEnum.UPDATE_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), fs.getCapacity(), param.getNotificationLimit(), param.getSoftLimit(), param.getSoftGrace()); return toTask(fs, task, op); } /** * Create SMB file share * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of a ViPR File system * @param param * File system share parameters * @brief Create file system SMB share * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/shares") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep share(@PathParam("id") URI id, FileSystemShareParam param) throws InternalException { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); ArgValidator.checkFieldNotNull(param.getShareName(), "name"); ArgValidator.checkFieldNotEmpty(param.getShareName(), "name"); FileShare fs = queryResource(id); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); String task = UUID.randomUUID().toString(); // Check for VirtualPool whether it has CIFS enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.CIFS.name())) { // Throw an error throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool Doesnt support " + StorageProtocol.File.CIFS.name() + " protocol"); } // locate storage port for sharing file System // Select IP port of the storage array, owning the file system, which belongs to the same varray as the file // system. StoragePort sport = _fileScheduler.placeFileShareExport(fs, StorageProtocol.File.CIFS.name(), null); // Check if maxUsers is "unlimited" and set it to -1 in this case. if (param.getMaxUsers().equalsIgnoreCase(UNLIMITED_USERS)) { param.setMaxUsers("-1"); } ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // If value of permission is not provided, set the value to change if (param.getPermission() == null || param.getPermission().isEmpty()) { param.setPermission(FileSMBShare.Permission.change.name()); } // Let us make sure that a share with the same name does not already exist. String shareName = param.getShareName(); if (CifsShareUtility.doesShareExist(fs, shareName)) { _log.error("CIFS share: {}, already exists", shareName); throw APIException.badRequests.duplicateEntityWithField("CIFS share", "name"); } String path = fs.getPath(); _log.info("Path {}", path); _log.info("Param Share Name : {} SubDirectory : {}", param.getShareName(), param.getSubDirectory()); boolean isSubDirPath = false; if (param.getSubDirectory() != null && param.getSubDirectory().length() > 0) { path += "/" + param.getSubDirectory(); isSubDirPath = true; _log.info("Sub-directory path {}", path); } FileSMBShare smbShare = new FileSMBShare(shareName, param.getDescription(), param.getPermissionType(), param.getPermission(), param.getMaxUsers(), null, path); smbShare.setStoragePortName(sport.getPortName()); smbShare.setStoragePortNetworkId(sport.getPortNetworkId()); smbShare.setStoragePortGroup(sport.getPortGroup()); smbShare.setSubDirPath(isSubDirPath); _log.info(String.format( "Create file system share --- File system id: %1$s, Share name: %2$s, StoragePort: %3$s, PermissionType: %4$s, " + "Permissions: %5$s, Description: %6$s, maxUsers: %7$s", id, smbShare.getName(), sport.getPortName(), smbShare.getPermissionType(), smbShare.getPermission(), smbShare.getDescription(), smbShare.getMaxUsers())); _log.info("SMB share path {}", smbShare.getPath()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.CREATE_FILE_SYSTEM_SHARE); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.share(device.getId(), fs.getId(), smbShare, task); auditOp(OperationTypeEnum.CREATE_FILE_SYSTEM_SHARE, true, AuditLogManager.AUDITOP_BEGIN, smbShare.getName(), smbShare.getPermissionType(), smbShare.getPermission(), smbShare.getMaxUsers(), smbShare.getDescription(), fs.getId().toString()); return toTask(fs, task, op); } /** * Delete specified SMB share. * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of a ViPR File system * @param shareName * file system share name * @brief Delete file system SMB share * @return Task resource representation * @throws InternalException */ @DELETE @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/shares/{shareName}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep deleteShare(@PathParam("id") URI id, @PathParam("shareName") String shareName) throws InternalException { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkFieldNotNull(shareName, "shareName"); ArgValidator.checkFieldNotNull(fs, "filesystem"); String task = UUID.randomUUID().toString(); SMBFileShare smbShare = null; if (!CifsShareUtility.doesShareExist(fs, shareName)) { _log.error("CIFS share does not exist {}", shareName); throw APIException.notFound.invalidParameterObjectHasNoSuchShare(id, shareName); } smbShare = fs.getSMBFileShares().get(shareName); _log.info("Deleteing SMBShare {}", shareName); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.DELETE_FILE_SYSTEM_SHARE); FileSMBShare fileSMBShare = new FileSMBShare(shareName, smbShare.getDescription(), smbShare.getPermissionType(), smbShare.getPermission(), Integer.toString(smbShare.getMaxUsers()), smbShare.getNativeId(), smbShare.getPath()); fileSMBShare.setStoragePortGroup(smbShare.getPortGroup()); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.deleteShare(device.getId(), fs.getId(), fileSMBShare, task); auditOp(OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE, true, AuditLogManager.AUDITOP_BEGIN, smbShare.getName(), smbShare.getPermissionType(), smbShare.getPermission(), smbShare.getMaxUsers(), smbShare.getDescription(), fs.getId().toString()); return toTask(fs, task, op); } /** * Get file system snapshots * * @param id * the URN of a ViPR File system * @brief List file system snapshots * @return List of snapshots */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/snapshots") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public SnapshotList getSnapshots(@PathParam("id") URI id) { List<URI> snapIDList = _dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(id)); _log.debug("getSnapshots: FS {}: {} ", id.toString(), snapIDList.toString()); List<Snapshot> snapList = _dbClient.queryObject(Snapshot.class, snapIDList); SnapshotList list = new SnapshotList(); for (Snapshot snap : snapList) { list.getSnapList().add(toNamedRelatedResource(snap)); } return list; } /** * Create file system snapshot * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of a ViPR File system * @param param * file system snapshot parameters * @brief Create file system snapshot * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/snapshots") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.ANY }) public TaskResourceRep snapshot(@PathParam("id") URI id, FileSystemSnapshotParam param) throws InternalException { String task = UUID.randomUUID().toString(); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (vpool == null) { throw APIException.badRequests.invalidParameterFileSystemHasNoVirtualPool(id); } if (getNumSnapshots(fs) >= vpool.getMaxNativeSnapshots()) { throw APIException.methodNotAllowed.maximumNumberSnapshotsReached(); } String label = TimeUtils.formatDateForCurrent(param.getLabel()); // check duplicate fileshare snapshot names for this fileshare checkForDuplicateName(label, Snapshot.class, id, "parent", _dbClient); Snapshot snap = new Snapshot(); snap.setId(URIUtil.createId(Snapshot.class)); snap.setParent(new NamedURI(id, label)); snap.setLabel(label); snap.setOpStatus(new OpStatusMap()); snap.setProject(new NamedURI(fs.getProject().getURI(), label)); String convertedName = label.replaceAll("[^\\dA-Za-z_]", ""); _log.info("Original name {} and converted name {}", label, convertedName); snap.setName(convertedName); fs.setOpStatus(new OpStatusMap()); Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.CREATE_FILE_SYSTEM_SNAPSHOT); snap.getOpStatus().createTaskStatus(task, op); fs.getOpStatus().createTaskStatus(task, op); _dbClient.createObject(snap); _dbClient.persistObject(fs); // find storageport for fs and based on protocol if (null == fs.getStoragePort()) { StoragePort storagePort; try { // assigned storageport to fs storagePort = _fileScheduler.placeFileShareExport(fs, PROTOCOL_NFS, null); _log.info( "FS is not mounted so we are mounting the FS first and then creating the Snapshot and the returned storage port- {} and supported protocol-{}", storagePort.getPortName(), PROTOCOL_NFS); } catch (APIException e) { // if we don't find port for NFS protocol then // in catch exception we get port for CIFS protocol storagePort = _fileScheduler.placeFileShareExport(fs, PROTOCOL_CIFS, null); _log.info( "FS is not mounted so we are mounting the FS first and then creating the Snapshot and the returned storage port- {} and supported protocol-{}", storagePort.getPortName(), PROTOCOL_NFS); } } // send request to controller try { FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.snapshotFS(device.getId(), snap.getId(), fs.getId(), task); } catch (InternalException e) { snap.setInactive(true); _dbClient.persistObject(snap); // treating all controller exceptions as internal error for now. controller // should discriminate between validation problems vs. internal errors throw e; } auditOp(OperationTypeEnum.CREATE_FILE_SYSTEM_SNAPSHOT, true, AuditLogManager.AUDITOP_BEGIN, snap.getLabel(), snap.getId().toString(), fs.getId().toString()); fs = _dbClient.queryObject(FileShare.class, id); _log.debug("Before sending response, FS ID : {}, Taks : {} ; Status {}", fs.getOpStatus().get(task), fs.getOpStatus().get(task) .getStatus()); return toTask(snap, task, op); } // Counts and returns the number of snapshots on a filesystem Integer getNumSnapshots(FileShare fs) { Integer numSnapshots = 0; URI fsId = fs.getId(); URIQueryResultList snapIDList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(fsId), snapIDList); while (snapIDList.iterator().hasNext()) { URI uri = snapIDList.iterator().next(); Snapshot snap = _dbClient.queryObject(Snapshot.class, uri); if (!snap.getInactive()) { numSnapshots++; } } return numSnapshots; } /** * Deactivate file system, this will move the Filesystem to a "marked-for-delete" state * it will be deleted when all references to this filesystem of type Snapshot are deleted. * The optional forceDelete param will delete snapshots and exports in case of VNXFile when it sets to true. * * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of a ViPR File system * @param param * File system delete param for optional force delete * @brief Delete file system * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/deactivate") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep deactivateFileSystem(@PathParam("id") URI id, FileSystemDeleteParam param) throws InternalException { String task = UUID.randomUUID().toString(); _log.info(String.format( "FileSystemDelete --- FileSystem id: %1$s, Task: %2$s, ForceDelete: %3$s ,DeleteType: %4$s", id, task, param.getForceDelete(), param.getDeleteType())); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); if (!param.getForceDelete()) { ArgValidator.checkReference(FileShare.class, id, checkForDelete(fs)); if (!fs.getFilePolicies().isEmpty()) { throw APIException.badRequests .resourceCannotBeDeleted("Please unassign the policy from file system. " + fs.getLabel()); } } // Verify the higher level replication policies assigned if (param.getForceDelete() && param.getDeleteType() != null && param.getDeleteType().equalsIgnoreCase("FULL")) { if (FilePolicyServiceUtils.vPoolHasReplicationPolicy(_dbClient, fs.getVirtualPool()) || FilePolicyServiceUtils.projectHasReplicationPolicy(_dbClient, fs.getProject().getURI(), fs.getVirtualPool())) { FilePolicyServiceUtils.resetReplicationFileSystemsRelation(_dbClient, fs); } } StringBuffer notSuppReasonBuff = new StringBuffer(); // Verify the file system is having any active replication targets!! if (FileSystemReplicationUtils.filesystemHasActiveReplication(fs, notSuppReasonBuff, param.getDeleteType(), param.getForceDelete())) { throw APIException.badRequests .resourceCannotBeDeleted(notSuppReasonBuff.toString()); } List<URI> fileShareURIs = new ArrayList<URI>(); fileShareURIs.add(id); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.DELETE_FILE_SYSTEM); op.setDescription("Filesystem deactivate"); auditOp(OperationTypeEnum.DELETE_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString()); try { fileServiceApi.deleteFileSystems(device.getId(), fileShareURIs, param.getDeleteType(), param.getForceDelete(), false, task); } catch (InternalException e) { if (_log.isErrorEnabled()) { _log.error("Delete error", e); } FileShare fileShare = _dbClient.queryObject(FileShare.class, fs.getId()); op = fs.getOpStatus().get(task); op.error(e); fileShare.getOpStatus().updateTaskStatus(task, op); _dbClient.persistObject(fs); throw e; } return toTask(fs, task, op); } /** * Retrieve resource representations based on input ids. * * @param param * POST data containing the id list. * @brief List data of file share resources * @return list of representations. * * @throws DatabaseException * When an error occurs querying the database. */ @POST @Path("/bulk") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public FileShareBulkRep getBulkResources(BulkIdParam param) { return (FileShareBulkRep) super.getBulkResources(param); } /** * Validates the clients are registered IP Interfaces if they exist in the database. * * @param clients * list of clients * @param dbClient * DbClient */ public static void validateIpInterfacesRegistered(List<String> clients, DbClient dbClient) { if (clients != null) { for (String client : clients) { List<IpInterface> ipInterfaces = CustomQueryUtility.queryActiveResourcesByAltId( dbClient, IpInterface.class, "ipAddress", client); for (IpInterface ipInterface : ipInterfaces) { if (ipInterface.getRegistrationStatus().equals(RegistrationStatus.UNREGISTERED.toString())) { throw APIException.badRequests.invalidParameterIpInterfaceIsDeregistered(client); } } } } } /** * Allocate, initialize and persist state of the fileSystem being created. * * @param param * @param project * @param tenantOrg * @param neighborhood * @param vpool * @param flags * @param placement * @param token * @return */ private FileShare prepareFileSystem(FileSystemParam param, Project project, TenantOrg tenantOrg, VirtualArray neighborhood, VirtualPool vpool, DataObject.Flag[] flags, FileRecommendation placement, String token) { _log.info("prepareFile System"); StoragePool pool = null; FileShare fs = new FileShare(); fs.setId(URIUtil.createId(FileShare.class)); fs.setLabel(param.getLabel()); // No need to generate any name -- Since the requirement is to use the customizing label we should use the same. // Stripping out the special characters like ; /-+!@#$%^&())";:[]{}\ | but allow underscore character _ String convertedName = param.getLabel().replaceAll("[^\\dA-Za-z\\_]", ""); _log.info("Original name {} and converted name {}", param.getLabel(), convertedName); fs.setName(convertedName); Long fsSize = SizeUtil.translateSize(param.getSize()); fs.setCapacity(fsSize); fs.setVirtualPool(param.getVpool()); if (project != null) { fs.setProject(new NamedURI(project.getId(), fs.getLabel())); } fs.setTenant(new NamedURI(tenantOrg.getId(), param.getLabel())); fs.setVirtualArray(neighborhood.getId()); if (null != placement.getSourceStoragePool()) { pool = _dbClient.queryObject(StoragePool.class, placement.getSourceStoragePool()); if (null != pool) { fs.setProtocol(new StringSet()); fs.getProtocol().addAll(VirtualPoolUtil.getMatchingProtocols(vpool.getProtocols(), pool.getProtocols())); } } fs.setStorageDevice(placement.getSourceStorageSystem()); fs.setPool(placement.getSourceStoragePool()); if (param.getSoftLimit() != 0) { fs.setSoftLimit(new Long(param.getSoftLimit())); } if (param.getNotificationLimit() != 0) { fs.setNotificationLimit(new Long(param.getNotificationLimit())); } if (param.getSoftGrace() > 0) { fs.setSoftGracePeriod(new Integer(param.getSoftGrace())); } if (placement.getStoragePorts() != null && !placement.getStoragePorts().isEmpty()) { fs.setStoragePort(placement.getStoragePorts().get(0)); } // When a VPool supports "thin" provisioning if (VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(vpool.getSupportedProvisioningType())) { fs.setThinlyProvisioned(Boolean.TRUE); } if (placement.getvNAS() != null) { fs.setVirtualNAS(placement.getvNAS()); } fs.setOpStatus(new OpStatusMap()); Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.CREATE_FILE_SYSTEM); fs.getOpStatus().createTaskStatus(token, op); if (flags != null) { fs.addInternalFlags(flags); } _dbClient.createObject(fs); return fs; } /** * Filesystem is not a zone level resource */ @Override protected boolean isZoneLevelResource() { return false; } @Override protected ResourceTypeEnum getResourceType() { return ResourceTypeEnum.FILE; } /** * Get search results by name in zone or project. * * @return SearchedResRepList */ @Override protected SearchedResRepList getNamedSearchResults(String name, URI projectId) { SearchedResRepList resRepList = new SearchedResRepList(getResourceType()); if (projectId == null) { _dbClient.queryByConstraint( PrefixConstraint.Factory.getLabelPrefixConstraint(getResourceClass(), name), resRepList); } else { _dbClient.queryByConstraint( ContainmentPrefixConstraint.Factory.getFileshareUnderProjectConstraint( projectId, name), resRepList); } return resRepList; } /** * Get search results by project alone. * * @return SearchedResRepList */ @Override protected SearchedResRepList getProjectSearchResults(URI projectId) { SearchedResRepList resRepList = new SearchedResRepList(getResourceType()); _dbClient.queryByConstraint( ContainmentConstraint.Factory.getProjectFileshareConstraint(projectId), resRepList); return resRepList; } /** * Get object specific permissions filter * */ @Override public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user, PermissionsHelper permissionsHelper) { return new ProjOwnedResRepFilter(user, permissionsHelper, FileShare.class); } /** * Create Quota directory for a file system * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of a ViPR File system * @param param * File system Quota directory parameters * @brief Create file system Quota directory * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/quota-directories") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep createQuotaDirectory(@PathParam("id") URI id, QuotaDirectoryCreateParam param) throws InternalException { _log.info("FileService::createQtree Request recieved {}", id); String origQtreeName = param.getQuotaDirName(); ArgValidator.checkQuotaDirName(origQtreeName, "name"); ArgValidator.checkFieldMaximum(param.getSoftLimit(), 100, "softLimit"); ArgValidator.checkFieldMaximum(param.getNotificationLimit(), 100, "notificationLimit"); if (param.getSoftLimit() != 0L) { ArgValidator.checkFieldMinimum(param.getSoftGrace(), 1L, "softGrace"); } // check duplicate QuotaDirectory names for this fileshare checkForDuplicateName(origQtreeName, QuotaDirectory.class, id, "parent", _dbClient); String task = UUID.randomUUID().toString(); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); if (param.getSecurityStyle() != null) { ArgValidator.checkFieldValueFromEnum(param.getSecurityStyle(), "security_style", EnumSet.allOf(QuotaDirectory.SecurityStyles.class)); } // Get the FileSystem object from the URN FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // Create the QuotaDirectory object for the DB QuotaDirectory quotaDirectory = new QuotaDirectory(); quotaDirectory.setId(URIUtil.createId(QuotaDirectory.class)); quotaDirectory.setParent(new NamedURI(id, origQtreeName)); // ICICIC - Curious ! quotaDirectory.setLabel(origQtreeName); quotaDirectory.setOpStatus(new OpStatusMap()); quotaDirectory.setProject(new NamedURI(fs.getProject().getURI(), origQtreeName)); quotaDirectory.setTenant(new NamedURI(fs.getTenant().getURI(), origQtreeName)); quotaDirectory.setSoftLimit( param.getSoftLimit() > 0 ? param.getSoftLimit() : fs.getSoftLimit().intValue() > 0 ? fs.getSoftLimit().intValue() : 0); quotaDirectory.setSoftGrace( param.getSoftGrace() > 0 ? param.getSoftGrace() : fs.getSoftGracePeriod() > 0 ? fs.getSoftGracePeriod() : 0); quotaDirectory.setNotificationLimit(param.getNotificationLimit() > 0 ? param.getNotificationLimit() : fs.getNotificationLimit().intValue() > 0 ? fs.getNotificationLimit().intValue() : 0); String convertedName = origQtreeName.replaceAll("[^\\dA-Za-z_]", ""); _log.info("FileService::QuotaDirectory Original name {} and converted name {}", origQtreeName, convertedName); quotaDirectory.setName(convertedName); if (param.getOpLock() != null) { quotaDirectory.setOpLock(param.getOpLock()); } else { quotaDirectory.setOpLock(true); } if (param.getSecurityStyle() != null) { quotaDirectory.setSecurityStyle(param.getSecurityStyle()); } else { quotaDirectory.setSecurityStyle(SecurityStyles.parent.toString()); } if (param.getSize() != null) { Long quotaSize = SizeUtil.translateSize(param.getSize()); // converts the input string in format "<value>GB" // to bytes ArgValidator.checkFieldMaximum(quotaSize, fs.getCapacity(), SizeUtil.SIZE_B, "size", true); quotaDirectory.setSize(quotaSize); } else { quotaDirectory.setSize((long) 0); } fs.setOpStatus(new OpStatusMap()); Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.CREATE_FILE_SYSTEM_QUOTA_DIR); quotaDirectory.getOpStatus().createTaskStatus(task, op); fs.getOpStatus().createTaskStatus(task, op); _dbClient.createObject(quotaDirectory); _dbClient.persistObject(fs); // Create an object of type "FileShareQuotaDirectory" to be passed into the south-bound layers. FileShareQuotaDirectory qt = new FileShareQuotaDirectory(quotaDirectory); // Now get ready to make calls into the controller StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileController controller = getController(FileController.class, device.getSystemType()); try { controller.createQuotaDirectory(device.getId(), qt, fs.getId(), task); } catch (InternalException e) { quotaDirectory.setInactive(true); _dbClient.persistObject(quotaDirectory); // treating all controller exceptions as internal error for now. controller // should discriminate between validation problems vs. internal errors throw e; } auditOp(OperationTypeEnum.CREATE_FILE_SYSTEM_QUOTA_DIR, true, AuditLogManager.AUDITOP_BEGIN, quotaDirectory.getLabel(), quotaDirectory.getId().toString(), fs.getId().toString()); fs = _dbClient.queryObject(FileShare.class, id); _log.debug("FileService::QuotaDirectory Before sending response, FS ID : {}, Taks : {} ; Status {}", fs.getOpStatus().get(task), fs .getOpStatus().get(task).getStatus()); return toTask(quotaDirectory, task, op); } /** * Get list of quota directories for the specified file system. * * @param id * the URN of a ViPR File system * @brief List file system quota directories * @return List of file system quota directories. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/quota-directories") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public QuotaDirectoryList getQuotaDirectoryList(@PathParam("id") URI id) { _log.info(String.format("Get list of quota directories for file system: %1$s", id)); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fileShare = queryResource(id); QuotaDirectoryList quotaDirList = new QuotaDirectoryList(); if (fileShare.getInactive()) { return quotaDirList; } // Get SMB share map from file system List<QuotaDirectory> quotaDirs = queryDBQuotaDirectories(fileShare); // Process each share from the map and add its data to shares in response list. for (QuotaDirectory quotaDir : quotaDirs) { quotaDirList.getQuotaDirs().add(toNamedRelatedResource(quotaDir)); } return quotaDirList; } private List<QuotaDirectory> queryDBQuotaDirectories(FileShare fs) { _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; } /** * * Existing file system exports may have their list of export rules updated. * * @param id * the URN of a ViPR fileSystem * @param subDir * sub-directory within a filesystem * @param unmountExport * Whether to unmount an export when deleting or modifying a rule * @brief Update file system export * @return Task resource representation * @throws InternalException */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/export") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep updateFSExportRules(@PathParam("id") URI id, @QueryParam("subDir") String subDir, @QueryParam("unmountExport") boolean unmountExport, FileShareExportUpdateParams param) throws InternalException { // log input received. _log.info("Update FS Export Rules : request received for {} with {}", id, param); String task = UUID.randomUUID().toString(); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // check for bypassDnsCheck flag. If null then set to false if (param.getBypassDnsCheck() == null) { param.setBypassDnsCheck(false); } // Check for VirtualPool whether it has NFS enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.NFS.name()) && !vpool.getProtocols().contains(StorageProtocol.File.NFSv4.name())) { // Throw an error throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool Doesnt support " + StorageProtocol.File.NFS.name() + " or " + StorageProtocol.File.NFSv4 + " protocol"); } StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); String path = fs.getPath(); _log.info("Export path found {} ", path); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.UPDATE_EXPORT_RULES_FILE_SYSTEM); op.setDescription("Filesystem export rules update"); try { _log.info("Sub Dir Provided {}", subDir); // Set Sub Directory param.setSubDir(subDir); // Validate the input ExportVerificationUtility exportVerificationUtility = new ExportVerificationUtility(_dbClient, getUserFromContext()); exportVerificationUtility.verifyExports(fs, null, param); _log.info("No Errors found proceeding further {}, {}, {}", new Object[] { _dbClient, fs, param }); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.updateExportRules(device.getId(), fs.getId(), param, unmountExport, task); auditOp(OperationTypeEnum.UPDATE_EXPORT_RULES_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), param); } catch (URISyntaxException e) { _log.error("Error Processing Export Updates {}, {}", e.getMessage(), e); } catch (BadRequestException e) { op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error Processing Export Updates {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { // _log.error("Error Processing Export Updates {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return toTask(fs, task, op); } /** * * Existing file system exports may have their list of export rules deleted. * * @param id * the URN of a ViPR fileSystem * @param subDir * sub-directory within a filesystem * @param allDirs * All Dirs within a filesystem * @param unmountExport * Whether to unmount an export when deleting the rule * @return Task resource representation * @throws InternalException */ @DELETE @Path("/{id}/export") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public TaskResourceRep deleteFSExportRules(@PathParam("id") URI id, @QueryParam("allDirs") boolean allDirs, @QueryParam("subDir") String subDir, @QueryParam("unmountExport") boolean unmountExport) { // log input received. _log.info("Delete Export Rules : request received for {}, with allDirs : {}, subDir : {}", new Object[] { id, allDirs, subDir }); String task = UUID.randomUUID().toString(); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); String path = fs.getPath(); _log.info("Export path found {} ", path); // Before running operation check if subdirectory exists List<FileExportRule> exportFileRulesTemp = queryDBFSExports(fs); boolean subDirFound = false; if (subDir != null && !subDir.isEmpty()) { for (FileExportRule rule : exportFileRulesTemp) { if (rule.getExportPath().endsWith("/" + subDir)) { subDirFound = true; } } if (!subDirFound) { _log.info("Sub-Directory {} doesnot exists, so deletion of Sub-Directory export rule from DB failed ", subDir); throw APIException.badRequests.subDirNotFound(subDir); } } Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.UNEXPORT_FILE_SYSTEM); op.setDescription("Filesystem unexport"); try { FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.deleteExportRules(device.getId(), fs.getId(), allDirs, subDir, unmountExport, task); auditOp(OperationTypeEnum.UNEXPORT_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), allDirs, subDir); } catch (BadRequestException e) { op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error Processing Export Updates {}", e.getMessage(), e); } catch (Exception e) { _log.error("Error Processing Export Updates {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return toTask(fs, task, op); } @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/export") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public ExportRules getFSExportRules(@PathParam("id") URI id, @QueryParam("allDirs") boolean allDirs, @QueryParam("subDir") String subDir) { _log.info("Request recieved for Exports with Id : {} allDirs : {} subDir : {}", new Object[] { id, allDirs, subDir }); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); List<ExportRule> exportRule = FileOperationUtils.getExportRules(id, allDirs, subDir, _dbClient); ExportRules rules = new ExportRules(); if (!exportRule.isEmpty()) { rules.setExportRules(exportRule); } return rules; } /** * API to update ACLs of an existing share * * @param id * the file system URI * @param shareName * name of the share * @param param * request payload object of type <code>com.emc.storageos.model.file.CifsShareACLUpdateParams</code> * @return TaskResponse * @throws InternalException */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/shares/{shareName}/acl") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep updateShareACL(@PathParam("id") URI id, @PathParam("shareName") String shareName, FileCifsShareACLUpdateParams param) throws InternalException { _log.info("Update file share acl request received. Filesystem: {}, Share: {}", id.toString(), shareName); _log.info("Request body: {}", param.toString()); ArgValidator.checkFieldNotNull(shareName, "shareName"); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); CifsShareUtility.checkForUpdateShareACLOperationOnStorage( device.getSystemType(), OperationTypeEnum.UPDATE_FILE_SYSTEM_SHARE_ACL.name()); if (!CifsShareUtility.doesShareExist(fs, shareName)) { _log.error("CIFS share does not exist {}", shareName); throw APIException.notFound.invalidParameterObjectHasNoSuchShare(fs.getId(), shareName); } String task = UUID.randomUUID().toString(); // Check for VirtualPool whether it has CIFS enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.CIFS.name())) { throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool doesn't support " + StorageProtocol.File.CIFS.name() + " protocol"); } // Validate the input CifsShareUtility util = new CifsShareUtility(_dbClient, fs, null, shareName); util.verifyShareACLs(param); _log.info("Request payload verified. No errors found."); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.UPDATE_FILE_SYSTEM_SHARE_ACL); op.setDescription("Update file system share ACLs"); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.updateShareACLs(device.getId(), fs.getId(), shareName, param, task); auditOp(OperationTypeEnum.UPDATE_FILE_SYSTEM_SHARE_ACL, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), param); return toTask(fs, task, op); } @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/shares/{shareName}/acl") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public ShareACLs getShareACLs(@PathParam("id") URI id, @PathParam("shareName") String shareName) { _log.info("Request recieved to get ACLs with Id: {} shareName: {}", id, shareName); // Validate the FS id ArgValidator.checkFieldUriType(id, FileShare.class, "id"); ArgValidator.checkFieldNotNull(shareName, "shareName"); FileShare fs = queryResource(id); if (!CifsShareUtility.doesShareExist(fs, shareName)) { _log.error("CIFS share does not exist {}", shareName); throw APIException.notFound.invalidParameterObjectHasNoSuchShare(fs.getId(), shareName); } ShareACLs acls = new ShareACLs(); CifsShareUtility util = new CifsShareUtility(_dbClient, fs, null, shareName); List<ShareACL> shareAclList = util.queryExistingShareACLs(); _log.info("Number of existing ACLs found : {} ", shareAclList.size()); if (!shareAclList.isEmpty()) { acls.setShareACLs(shareAclList); } return acls; } @DELETE @Path("/{id}/shares/{shareName}/acl") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public TaskResourceRep deleteFileShareACL(@PathParam("id") URI id, @PathParam("shareName") String shareName) { // log input received. _log.info("Delete ACL of share: Request received for share: {}, of filesystem: {}", shareName, id); String taskId = UUID.randomUUID().toString(); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); ArgValidator.checkFieldNotNull(shareName, "shareName"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); CifsShareUtility.checkForUpdateShareACLOperationOnStorage( device.getSystemType(), OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE_ACL.name()); if (!CifsShareUtility.doesShareExist(fs, shareName)) { _log.error("CIFS share does not exist {}", shareName); throw APIException.notFound.invalidParameterObjectHasNoSuchShare(fs.getId(), shareName); } Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), taskId, ResourceOperationTypeEnum.DELETE_FILE_SYSTEM_SHARE_ACL); op.setDescription("Delete ACL of Cifs share"); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); fileServiceApi.deleteShareACLs(device.getId(), fs.getId(), shareName, taskId); auditOp(OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE_ACL, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), shareName); return toTask(fs, taskId, op); } /** * GET all ACLs for a fileSystem * * @param id * the URN of a ViPR fileSystem * @param allDirs * all directory within a fileSystem * @param subDir * sub-directory within a fileSystem * @return list of ACLs for file system. * @throws InternalException */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/acl") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public NfsACLs getFileShareACLs(@PathParam("id") URI id, @QueryParam("allDirs") boolean allDirs, @QueryParam("subDir") String subDir) { _log.info("Request recieved for Acl with Id : {} allDirs : {} subDir : {}", new Object[] { id, allDirs, subDir }); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); // Check for VirtualPool whether it has NFS v4 enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.NFSv4.name())) { // Throw an error throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool does not support " + StorageProtocol.File.NFSv4.name() + " protocol"); } // Get All ACLs of FS from data base and group them based on path!! NfsACLUtility util = new NfsACLUtility(_dbClient, fs, null, subDir); NfsACLs acls = util.getNfsAclFromDB(allDirs); if (acls.getNfsACLs() != null && !acls.getNfsACLs().isEmpty()) { _log.info("Found {} Acl rules for filesystem {}", acls.getNfsACLs().size(), fs.getId()); } else { _log.info("No Acl rules found for filesystem {}", fs.getId()); } return acls; } /** * * Update existing file system ACL * * @param id * the URN of a ViPR fileSystem * @param param * FileNfsACLUpdateParams * @brief Update file system ACL * @return Task resource representation * @throws InternalException */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/acl") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep updateFileSystemAcls(@PathParam("id") URI id, FileNfsACLUpdateParams param) throws InternalException { // log input received. _log.info("Update FS ACL : request received for {} with {}", id, param); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // Check for VirtualPool whether it has NFS v4 enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.NFSv4.name())) { // Throw an error throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool does not support " + StorageProtocol.File.NFSv4.name() + " protocol"); } StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileController controller = getController(FileController.class, device.getSystemType()); String task = UUID.randomUUID().toString(); String path = fs.getPath(); _log.info("fileSystem path {} ", path); Operation op = new Operation(); try { _log.info("Sub Dir Provided {}", param.getSubDir()); // Validate the input NfsACLUtility util = new NfsACLUtility(_dbClient, fs, null, param.getSubDir()); util.verifyNfsACLs(param); _log.info("No Errors found proceeding further {}, {}, {}", new Object[] { _dbClient, fs, param }); op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.UPDATE_FILE_SYSTEM_NFS_ACL); op.setDescription("Filesystem NFS ACL update"); controller.updateNFSAcl(device.getId(), fs.getId(), param, task); auditOp(OperationTypeEnum.UPDATE_FILE_SYSTEM_NFS_ACL, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), param); } catch (BadRequestException e) { op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error Processing File System ACL Updates {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Error Processing File System ACL Updates {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return toTask(fs, task, op); } /** * Delete all the existing ACLs of a fileSystem or subDirectory * * @param id * the URN of a ViPR fileSystem * @param subDir * sub-directory within a fileSystem * @return Task resource representation */ @DELETE @Path("/{id}/acl") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public TaskResourceRep deleteFileSystemACL(@PathParam("id") URI id, @QueryParam("subDir") String subDir) { // log input received. _log.info("Delete ACL of fileSystem: Request received for filesystem: {} with subDir {} ", id, subDir); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); String task = UUID.randomUUID().toString(); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // Check for VirtualPool whether it has NFS v4 enabled VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); if (!vpool.getProtocols().contains(StorageProtocol.File.NFSv4.name())) { // Throw an error throw APIException.methodNotAllowed.vPoolDoesntSupportProtocol("Vpool does not support " + StorageProtocol.File.NFSv4.name() + " protocol"); } StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileController controller = getController(FileController.class, device.getSystemType()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.DELETE_FILE_SYSTEM_NFS_ACL); op.setDescription("Delete ACL of file system "); try { controller.deleteNFSAcls(device.getId(), fs.getId(), subDir, task); auditOp(OperationTypeEnum.DELETE_FILE_SYSTEM_SHARE_ACL, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), subDir); } catch (BadRequestException e) { op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error Processing File System ACL Delete {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Error Processing File System ACL Delete {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return toTask(fs, task, op); } @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/vpool-change") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep changeFileSystemVirtualPool(@PathParam("id") URI id, FileSystemVirtualPoolChangeParam param) { _log.info("Request to change VirtualPool for filesystem {}", id); StringBuilder errorMsg = new StringBuilder(); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); String task = UUID.randomUUID().toString(); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // Make sure that we don't have some pending // operation against the file system!!! checkForPendingTasks(Arrays.asList(fs.getTenant().getURI()), Arrays.asList(fs)); // Get the project. URI projectURI = fs.getProject().getURI(); Project project = _permissionsHelper.getObjectById(projectURI, Project.class); ArgValidator.checkEntity(project, projectURI, false); _log.info("Found filesystem project {}", projectURI); // Get the VirtualPool for the request and verify that the // project's tenant has access to the VirtualPool. VirtualPool newVpool = getVirtualPoolForRequest(project, param.getVirtualPool(), _dbClient, _permissionsHelper); _log.info("Found new VirtualPool {}", newVpool.getId()); VirtualPool currentVpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); StringBuffer notSuppReasonBuff = new StringBuffer(); // Verify the vPool change is supported!!! if (!VirtualPoolChangeAnalyzer.isSupportedFileReplicationChange(currentVpool, newVpool, notSuppReasonBuff)) { _log.error("Virtual Pool change is not supported due to {}", notSuppReasonBuff.toString()); throw APIException.badRequests.invalidVirtualPoolForVirtualPoolChange( newVpool.getLabel(), notSuppReasonBuff.toString()); } ArgValidator.checkFieldUriType(param.getFilePolicy(), FilePolicy.class, "file_policy"); FilePolicy filePolicy = _dbClient.queryObject(FilePolicy.class, param.getFilePolicy()); ArgValidator.checkEntity(filePolicy, param.getFilePolicy(), true); StringSet existingFSPolicies = fs.getFilePolicies(); if (existingFSPolicies != null && existingFSPolicies.contains(param.getFilePolicy().toString())) { errorMsg.append("Provided file policy:" + filePolicy.getId() + " is already is applied to the file system:" + fs.getId()); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidVirtualPoolForVirtualPoolChange(newVpool.getLabel(), errorMsg.toString()); } // check if same TYPE of policy already applied to file system if (filePolicy.getFilePolicyType().equals(FilePolicy.FilePolicyType.file_replication.name()) && existingFSPolicies != null && !existingFSPolicies.isEmpty()) { checkForDuplicatePolicyApplied(filePolicy, existingFSPolicies); } // Check if the target vpool supports provided policy type.. FilePolicyServiceUtils.validateVpoolSupportPolicyType(filePolicy, newVpool); // Check if the vpool supports policy at file system level.. if (!newVpool.getAllowFilePolicyAtFSLevel()) { errorMsg.append("Provided vpool :" + newVpool.getLabel() + " doesn't support policy at file system level"); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidVirtualPoolForVirtualPoolChange( newVpool.getLabel(), errorMsg.toString()); } // Verify the vpool/project/fs has any replication policy!!! // only single replication policy per vpool/project/fs. if (filePolicy.getFilePolicyType().equalsIgnoreCase(FilePolicyType.file_replication.name()) && FilePolicyServiceUtils.fsHasReplicationPolicy(_dbClient, newVpool.getId(), fs.getProject().getURI(), fs.getId())) { errorMsg.append("Provided vpool/project/fs has already assigned with replication policy."); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidVirtualPoolForVirtualPoolChange( newVpool.getLabel(), errorMsg.toString()); } if (FilePolicyServiceUtils.fsHasSnapshotPolicyWithSameSchedule(_dbClient, fs.getId(), filePolicy)) { errorMsg.append("Snapshot policy with similar schedule is already present on fs " + fs.getLabel()); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidVirtualPoolForVirtualPoolChange( newVpool.getLabel(), errorMsg.toString()); } Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.CHANGE_FILE_SYSTEM_VPOOL); op.setDescription("Change vpool operation"); op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, op); TaskResourceRep fileSystemTask = toTask(fs, task, op); try { // Change the virtual pool of source file system!! fs.setVirtualPool(newVpool.getId()); _dbClient.updateObject(fs); FilePolicyFileSystemAssignParam policyAssignParam = new FilePolicyFileSystemAssignParam(); policyAssignParam.setTargetVArrays(param.getTargetVArrays()); if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_replication.name())) { return assignFileReplicationPolicyToFS(fs, filePolicy, policyAssignParam, task); } else if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_snapshot.name())) { return assignFilePolicyToFS(fs, filePolicy, task); } } catch (BadRequestException e) { op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Change vpool operation failed {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Change vpool operation failed {}, {}", e.getMessage(), e); // revert the virtual pool of source file system!! fs.setVirtualPool(currentVpool.getId()); _dbClient.updateObject(fs); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return fileSystemTask; } @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/create") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep createContinuousCopies(@PathParam("id") URI id, FileReplicationCreateParam param) throws InternalException, APIException { _log.info("Request to create replication copies for filesystem {}", id); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); FileShare orgFs = queryResource(id); String task = UUID.randomUUID().toString(); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); TaskList taskList = new TaskList(); // Make sure that we don't have some pending // operation against the file system!!! checkForPendingTasks(Arrays.asList(fs.getTenant().getURI()), Arrays.asList(fs)); // Get the project. URI projectURI = fs.getProject().getURI(); Project project = _permissionsHelper.getObjectById(projectURI, Project.class); ArgValidator.checkEntity(project, projectURI, false); _log.info("Found filesystem project {}", projectURI); VirtualPool currentVpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); StringBuffer notSuppReasonBuff = new StringBuffer(); // Verify the file system and its vPool are capable of doing replication!!! if (!FileSystemReplicationUtils.isSupportedFileReplicationCreate(fs, currentVpool, notSuppReasonBuff)) { _log.error("create mirror copies is not supported for file system {} due to {}", fs.getId().toString(), notSuppReasonBuff.toString()); throw APIException.badRequests.unableToCreateMirrorCopies( fs.getId(), notSuppReasonBuff.toString()); } // Get the virtual array!!! VirtualArray varray = _dbClient.queryObject(VirtualArray.class, fs.getVirtualArray()); // New operation Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.CREATE_FILE_SYSTEM_MIRROR_COPIES); op.setDescription("Create file system mirror operation"); op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, op); TaskResourceRep fileSystemTask = toTask(fs, task, op); taskList.getTaskList().add(fileSystemTask); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); // prepare vpool capability values VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper(); capabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, fs.getCapacity()); capabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, new Integer(1)); if (VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(currentVpool.getSupportedProvisioningType())) { capabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, Boolean.TRUE); } // Set the source file system details // source fs details used in finding recommendations for target fs!! capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_SYSTEM_CREATE_MIRROR_COPY, Boolean.TRUE); capabilities.put(VirtualPoolCapabilityValuesWrapper.EXISTING_SOURCE_FILE_SYSTEM, fs); capabilities.put(VirtualPoolCapabilityValuesWrapper.SOURCE_STORAGE_SYSTEM, device); StringBuilder errorMsg = new StringBuilder(); if (!FilePolicyServiceUtils.updatePolicyCapabilities(_dbClient, varray, currentVpool, project, null, capabilities, errorMsg)) { _log.error("File system can not be created, ", errorMsg.toString()); throw APIException.badRequests.unableToProcessRequest(errorMsg.toString()); } if (param.getCopyName() != null && !param.getCopyName().isEmpty()) { // No need to generate any name -- Since the requirement is to use the customizing label we should use the // same. // Stripping out the special characters like ; /-+!@#$%^&())";:[]{}\ | but allow underscore character _ String convertedName = param.getCopyName().replaceAll("[^\\dA-Za-z\\_]", ""); _log.info("Original copy name {} and converted copy name {}", param.getCopyName(), convertedName); capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_TARGET_COPY_NAME, convertedName); } FileServiceApi fileServiceApi = getFileShareServiceImpl(capabilities, _dbClient); try { // Call out placementManager to get the recommendation for placement. List recommendations = _filePlacementManager.getRecommendationsForFileCreateRequest( varray, project, currentVpool, capabilities); // Verify the source virtual pool recommendations meets source fs storage!!! fileServiceApi.createTargetsForExistingSource(fs, project, currentVpool, varray, taskList, task, recommendations, capabilities); } catch (BadRequestException e) { // Revert the file system to original state!!! restoreFromOriginalFs(orgFs, fs); _dbClient.updateObject(fs); op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Create file system mirror copy failed {}, {}", e.getMessage(), e); throw e; } catch (InternalException e) { // Revert the file system to original state!!! restoreFromOriginalFs(orgFs, fs); _dbClient.updateObject(fs); op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Create file system mirror copy failed {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Create file system mirror copy failed {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } auditOp(OperationTypeEnum.CREATE_MIRROR_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getLabel(), currentVpool.getLabel(), fs.getLabel(), project == null ? null : project.getId().toString()); return taskList.getTaskList().get(0); } @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/deactivate") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep deactivateContinuousCopies(@PathParam("id") URI id, FileSystemDeleteParam param) throws InternalException, APIException { _log.info("Request to deactivate replication copies for filesystem {}", id); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); FileShare orgFs = queryResource(id); String task = UUID.randomUUID().toString(); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); TaskList taskList = new TaskList(); // Make sure that we don't have some pending // operation against the file system!!! checkForPendingTasks(Arrays.asList(fs.getTenant().getURI()), Arrays.asList(fs)); // Get the project. URI projectURI = fs.getProject().getURI(); Project project = _permissionsHelper.getObjectById(projectURI, Project.class); ArgValidator.checkEntity(project, projectURI, false); _log.info("Found filesystem project {}", projectURI); VirtualPool currentVpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); StringBuffer notSuppReasonBuff = new StringBuffer(); // Verify the file system and its vPool are capable of doing replication!!! if (!FileSystemReplicationUtils.validateDeleteMirrorCopies(fs, currentVpool, notSuppReasonBuff)) { _log.error("delete mirror copies is not supported for file system {} due to {}", fs.getId().toString(), notSuppReasonBuff.toString()); throw APIException.badRequests.unableToDeleteMirrorCopies( fs.getId(), notSuppReasonBuff.toString()); } // Get the virtual array!!! VirtualArray varray = _dbClient.queryObject(VirtualArray.class, fs.getVirtualArray()); // New operation Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.DELETE_MIRROR_FILE_SYSTEMS); op.setDescription("Deactivate file system mirror operation"); op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, op); TaskResourceRep fileSystemTask = toTask(fs, task, op); taskList.getTaskList().add(fileSystemTask); List<URI> fileShareURIs = new ArrayList<URI>(); fileShareURIs.add(id); boolean deleteMirrorCopies = true; StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); try { fileServiceApi.deleteFileSystems(device.getId(), fileShareURIs, param.getDeleteType(), param.getForceDelete(), deleteMirrorCopies, task); } catch (InternalException e) { if (_log.isErrorEnabled()) { _log.error("deactivate continuous copies error ", e); } FileShare fileShare = _dbClient.queryObject(FileShare.class, fs.getId()); op = fs.getOpStatus().get(task); op.error(e); fileShare.getOpStatus().updateTaskStatus(task, op); // Revert the file system to original state!!! restoreFromOriginalFs(orgFs, fs); _dbClient.updateObject(fs); throw e; } auditOp(OperationTypeEnum.DELETE_MIRROR_FILE_SYSTEM, true, AuditLogManager.AUDITOP_BEGIN, fs.getLabel(), currentVpool.getLabel(), fs.getLabel(), project == null ? null : project.getId().toString()); return taskList.getTaskList().get(0); } /** * * @Deprecated use @Path("/{id}/assign-file-policy/{filePolicyUri}") instead * Assign file policy API will enable the policy and policy will run * based on the schedule. * * Start continuous copies. * * @prereq none * @param id the URN of a ViPR Source file share * @brief Start the replication session between source and target file system. * @return TaskList * @throws ControllerException * */ @Deprecated @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/start") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList startContinuousCopies(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.START.toString()); String task = UUID.randomUUID().toString(); FileShare sourceFileShare = queryResource(id); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_START); op.setDescription("start the replication link between source and target"); StorageSystem system = _dbClient.queryObject(StorageSystem.class, sourceFileShare.getStorageDevice()); FileController controller = getController(FileController.class, system.getSystemType()); controller.performFileReplicationOperation(system.getId(), id, ProtectionOp.START.toString().toLowerCase(), task); TaskList taskList = new TaskList(); TaskResourceRep taskResp = toTask(sourceFileShare, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * * Refresh continuous copies. * * @prereq none * @param id the URN of a ViPR Source file share * @brief Refresh the replication session between source and target file system. * @return TaskList * @throws ControllerException * */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/refresh") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList refreshContinuousCopies(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.REFRESH.toString()); String task = UUID.randomUUID().toString(); FileShare sourceFileShare = queryResource(id); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_REFRESH); op.setDescription("refresh the replication link between source and target"); StorageSystem system = _dbClient.queryObject(StorageSystem.class, sourceFileShare.getStorageDevice()); FileController controller = getController(FileController.class, system.getSystemType()); controller.performFileReplicationOperation(system.getId(), id, ProtectionOp.REFRESH.toString().toLowerCase(), task); TaskList taskList = new TaskList(); TaskResourceRep taskResp = toTask(sourceFileShare, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * * Stop continuous copies. * * @prereq none * @param id the URN of a ViPR Source file share * @brief Stop the replication session between source and target file system. * @return TaskList * @throws ControllerException * */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/stop") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList stopContinuousCopies(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.STOP.toString()); String task = UUID.randomUUID().toString(); FileShare sourceFileShare = queryResource(id); Set<URI> unassignFrom = new HashSet<>(); unassignFrom.add(id); FilePolicy filepolicy = FileSystemReplicationUtils.getReplicationPolicyAppliedOnFS(sourceFileShare, _dbClient); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_STOP); op.setDescription("stop the replication link between source and target"); FileOrchestrationController controller = getController(FileOrchestrationController.class, FileOrchestrationController.FILE_ORCHESTRATION_DEVICE); controller.unassignFilePolicy(filepolicy.getId(), unassignFrom, task); auditOp(OperationTypeEnum.STOP_FILE_MIRROR, true, "BEGIN", sourceFileShare.getId().toString()); TaskList taskList = new TaskList(); TaskResourceRep taskResp = toTask(sourceFileShare, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * * Pause continuous copies. * * @prereq none * @param id the URN of a ViPR Source file share * @brief Pause the replication session between source and target file system. * @return TaskResourceRep * @throws ControllerException * */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/pause") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList pauseContinuousCopies(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.PAUSE.toString()); String task = UUID.randomUUID().toString(); FileShare sourceFileShare = queryResource(id); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_PAUSE); op.setDescription("pause the replication link between source and target"); StorageSystem system = _dbClient.queryObject(StorageSystem.class, sourceFileShare.getStorageDevice()); FileController controller = getController(FileController.class, system.getSystemType()); controller.performFileReplicationOperation(system.getId(), id, ProtectionOp.PAUSE.toString().toLowerCase(), task); TaskList taskList = new TaskList(); TaskResourceRep taskResp = toTask(sourceFileShare, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * * Resume continuous copies. * * @prereq none * @param id the URN of a ViPR Source file share * @brief Resume the replication session between source and target file system. * @return TaskList * @throws ControllerException * */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/resume") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList resumeContinuousCopies(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.RESUME.toString()); String task = UUID.randomUUID().toString(); FileShare sourceFileShare = queryResource(id); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_RESUME); op.setDescription("resume the replication link between source and target"); StorageSystem system = _dbClient.queryObject(StorageSystem.class, sourceFileShare.getStorageDevice()); FileController controller = getController(FileController.class, system.getSystemType()); controller.performFileReplicationOperation(system.getId(), id, ProtectionOp.RESUME.toString().toLowerCase(), task); TaskList taskList = new TaskList(); TaskResourceRep taskResp = toTask(sourceFileShare, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * Update file system RPO. * <p> * NOTE: This is an asynchronous operation. * * @param param * File system RPO update parameters * @param id * the URN of a ViPR File system * @brief update file system replication RPO * @return Task resource representation * @throws InternalException */ @Deprecated @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/update-rpo") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep updateFileSystemReplicationRPO(@PathParam("id") URI id, FileReplicationParam param) throws InternalException { throw APIException.badRequests.unableToPerformMirrorOperation(ProtectionOp.UPDATE_RPO.toString(), id, "api is deprecated!!"); } /** * * Request to failover the protection link associated with the param.copyID. * * NOTE: This is an asynchronous operation. * * @prereq none * * @param id * the URN of a ViPR Source fileshare * @param param * FileReplicationParam to failover to * * @brief Failover the fileShare protection link * @return TaskList * * @throws ControllerException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/failover") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList failoverProtection(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.FAILOVER.toString()); TaskResourceRep taskResp = null; StoragePort storageportNFS = null; StoragePort storageportCIFS = null; TaskList taskList = new TaskList(); String task = UUID.randomUUID().toString(); FileShare fs = queryResource(id); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_FAILOVER); op.setDescription("failover source file system to target system"); boolean replicateConfiguration = param.isReplicateConfiguration(); if (replicateConfiguration) { List<String> targetfileUris = new ArrayList<String>(); targetfileUris.addAll(fs.getMirrorfsTargets()); FileShare targetFileShare = _dbClient.queryObject(FileShare.class, URI.create(targetfileUris.get(0))); SMBShareMap smbShareMap = fs.getSMBFileShares(); if (smbShareMap != null) { storageportCIFS = _fileScheduler.placeFileShareExport(targetFileShare, StorageProtocol.File.CIFS.name(), null); } FSExportMap nfsExportMap = fs.getFsExports(); if (nfsExportMap != null) { storageportNFS = _fileScheduler.placeFileShareExport(targetFileShare, StorageProtocol.File.NFS.name(), null); } } FileServiceApi fileServiceApi = getFileShareServiceImpl(fs, _dbClient); try { fileServiceApi.failoverFileShare(id, storageportNFS, storageportCIFS, replicateConfiguration, task); } catch (InternalException e) { if (_log.isErrorEnabled()) { _log.error("", e); } FileShare fileShare = _dbClient.queryObject(FileShare.class, fs.getId()); op = fs.getOpStatus().get(task); op.error(e); fileShare.getOpStatus().updateTaskStatus(task, op); _dbClient.updateObject(fs); throw e; } taskResp = toTask(fs, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * * Request to fail Back the protection link associated with the param.copyID. * * NOTE: This is an asynchronous operation. * * @prereq none * * @param id * the URN of a ViPR Source files hare * @param param * FileReplicationParam to fail Back to * * @brief Fail Back the fileShare protection link * @return TaskList * * @throws ControllerException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies/failback") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskList failbackProtection(@PathParam("id") URI id, FileReplicationParam param) throws ControllerException { doMirrorOperationValidation(id, ProtectionOp.FAILBACK.toString()); TaskResourceRep taskResp = null; StoragePort storageportNFS = null; StoragePort storageportCIFS = null; TaskList taskList = new TaskList(); String task = UUID.randomUUID().toString(); FileShare sourceFileShare = queryResource(id); Operation op = _dbClient.createTaskOpStatus(FileShare.class, id, task, ResourceOperationTypeEnum.FILE_PROTECTION_ACTION_FAILBACK); op.setDescription("failback to source file system from target system"); boolean replicateConfiguration = param.isReplicateConfiguration(); if (replicateConfiguration) { List<String> targetfileUris = new ArrayList<String>(); targetfileUris.addAll(sourceFileShare.getMirrorfsTargets()); FileShare targetFileShare = _dbClient.queryObject(FileShare.class, URI.create(targetfileUris.get(0))); SMBShareMap smbShareMap = targetFileShare.getSMBFileShares(); if (smbShareMap != null) { storageportCIFS = _fileScheduler.placeFileShareExport(sourceFileShare, StorageProtocol.File.CIFS.name(), null); } FSExportMap nfsExportMap = targetFileShare.getFsExports(); if (nfsExportMap != null) { storageportNFS = _fileScheduler.placeFileShareExport(sourceFileShare, StorageProtocol.File.NFS.name(), null); } } FileServiceApi fileServiceApi = getFileShareServiceImpl(sourceFileShare, _dbClient); try { fileServiceApi.failbackFileShare(sourceFileShare.getId(), storageportNFS, storageportCIFS, replicateConfiguration, task); } catch (InternalException e) { if (_log.isErrorEnabled()) { _log.error("", e); } op = sourceFileShare.getOpStatus().get(task); op.error(e); sourceFileShare.getOpStatus().updateTaskStatus(task, op); _dbClient.updateObject(sourceFileShare); throw e; } taskResp = toTask(sourceFileShare, task, op); taskList.getTaskList().add(taskResp); return taskList; } /** * List FileShare mirrors * * * @prereq none * * @param id * the URN of a ViPR FileShare to list mirrors * * @brief List fileShare mirrors * @return FileShare mirror response containing a list of mirror identifiers */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/protection/continuous-copies") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public MirrorList getNativeContinuousCopies(@PathParam("id") URI id) { MirrorList list = new MirrorList(); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare sourceFileShare = _dbClient.queryObject(FileShare.class, id); StringSet sourceFileShareMirrors = sourceFileShare.getMirrorfsTargets(); if (sourceFileShareMirrors == null || sourceFileShareMirrors.isEmpty()) { return list; } for (String uriStr : sourceFileShareMirrors) { FileShare fileMirror = _dbClient.queryObject(FileShare.class, URI.create(uriStr)); if (fileMirror == null || fileMirror.getInactive()) { _log.warn("Stale mirror {} found for fileShare {}", uriStr, sourceFileShare.getId()); continue; } list.getMirrorList().add(toNamedRelatedResource(fileMirror)); } return list; } private void doMirrorOperationValidation(URI id, String op) { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare sourceFileShare = queryResource(id); ArgValidator.checkEntity(sourceFileShare, id, true); // Make sure that we don't have some pending // operation against the file share checkForPendingTasks(Arrays.asList(sourceFileShare.getTenant().getURI()), Arrays.asList(sourceFileShare)); StringBuffer notSuppReasonBuff = new StringBuffer(); // Verify the file system is capable of replication.. if (!FileSystemReplicationUtils.validateMirrorOperationSupported(sourceFileShare, notSuppReasonBuff, op.toLowerCase())) { _log.error("Mirror Operation {} is not supported for the file system {} as : {}", op, sourceFileShare.getLabel(), notSuppReasonBuff.toString()); throw APIException.badRequests.unableToPerformMirrorOperation(op, sourceFileShare.getId(), notSuppReasonBuff.toString()); } // Check for replication policy existence on file system.. if (FileSystemReplicationUtils.getReplicationPolicyAppliedOnFS(sourceFileShare, _dbClient) == null) { notSuppReasonBuff .append(String .format( "Mirror Operation {} is not supported for the file system {} as file system doesn't have any replication policy assigned/applied", op, sourceFileShare.getLabel())); _log.error(notSuppReasonBuff.toString()); throw APIException.badRequests.unableToPerformMirrorOperation(op, sourceFileShare.getId(), notSuppReasonBuff.toString()); } } /** * copy exports rules * * @param orig * @param dest * @param fs */ private void copyPropertiesToSave(FileExportRule orig, ExportRule dest, FileShare fs) { dest.setFsID(fs.getId()); 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()); // Test _log.info("Expor Rule : {} - {}", orig, dest); } private List<FileExportRule> queryDBFSExports(FileShare fs) { _log.info("Querying all ExportRules Using FsId {}", fs.getId()); try { ContainmentConstraint containmentConstraint = ContainmentConstraint.Factory.getFileExportRulesConstraint(fs.getId()); List<FileExportRule> fileExportRules = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileExportRule.class, containmentConstraint); return fileExportRules; } catch (Exception e) { _log.error("Error while querying {}", e); } return null; } /** * Returns the bean responsible for servicing the request * * @param fileShare * fileshare * @param dbClient * db client * @return file service implementation object */ public static FileServiceApi getFileShareServiceImpl(VirtualPoolCapabilityValuesWrapper capabilities, DbClient dbClient) { return getFileServiceImpl(capabilities, dbClient); } /** * Returns the bean responsible for servicing the request * * @param fileShare * fileshare * @param dbClient * db client * @return file service implementation object */ public static FileServiceApi getFileShareServiceImpl(FileShare fileShare, DbClient dbClient) { VirtualPool vPool = dbClient.queryObject(VirtualPool.class, fileShare.getVirtualPool()); Project project = dbClient.queryObject(Project.class, fileShare.getProject().getURI()); VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper(); capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_TYPE, VirtualPool.FileReplicationType.NONE.name()); StringBuilder errorMsg = new StringBuilder(); if (vPool.getFileReplicationSupported()) { FilePolicyServiceUtils.updateReplicationTypeCapabilities(dbClient, vPool, project, fileShare, capabilities, errorMsg); } return getFileServiceImpl(capabilities, dbClient); } /** * Returns the bean responsible for servicing the request * * @param vpool * Virtual Pool * @param dbClient * db client * @return file service implementation object */ private static FileServiceApi getFileServiceImpl(VirtualPoolCapabilityValuesWrapper capabilities, DbClient dbClient) { // Mutually exclusive logic that selects an implementation of the file service if (FilePolicyServiceUtils.vPoolSpecifiesFileReplication(capabilities)) { if (capabilities.getFileReplicationType().equals(VirtualPool.FileReplicationType.LOCAL.name())) { return getFileServiceApis("localmirror"); } else if (capabilities.getFileReplicationType().equals(VirtualPool.FileReplicationType.REMOTE.name())) { return getFileServiceApis("remotemirror"); } } return getFileServiceApis("default"); } /** * Returns the bean responsible for servicing the request * * @param vpool * Virtual Pool * @param dbClient * db client * @return file service implementation object */ private static FileServiceApi getFileServiceImpl(VirtualPoolCapabilityValuesWrapper capabilities, FilePolicy filePolicy) { // Mutually exclusive logic that selects an implementation of the file service if (FilePolicyServiceUtils.vPoolSpecifiesFileReplication(capabilities)) { if (filePolicy.getFileReplicationType().equals(FilePolicy.FileReplicationType.LOCAL.name())) { return getFileServiceApis("localmirror"); } else if (filePolicy.getFileReplicationType().equals(FilePolicy.FileReplicationType.REMOTE.name())) { return getFileServiceApis("remotemirror"); } } return getFileServiceApis("default"); } /** * * Assign existing file system to file policy. * * @param id * the URN of a ViPR fileSystem * @param filePolicyUri * the URN of a Policy * @brief Update file system with Policy detail * @return Task resource representation * @throws InternalException */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/assign-file-policy/{filePolicyUri}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep assignFilePolicy(@PathParam("id") URI id, @PathParam("filePolicyUri") URI filePolicyUri, FilePolicyFileSystemAssignParam param) throws InternalException { TaskResourceRep resp = new TaskResourceRep(); StringBuilder errorMsg = new StringBuilder(); _log.info("Assigning file policy {} to file system {}", filePolicyUri, id); String task = UUID.randomUUID().toString(); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); ArgValidator.checkFieldUriType(filePolicyUri, FilePolicy.class, "filePolicyUri"); ArgValidator.checkUri(filePolicyUri); FilePolicy filePolicy = _permissionsHelper.getObjectById(filePolicyUri, FilePolicy.class); ArgValidator.checkEntityNotNull(filePolicy, filePolicyUri, isIdEmbeddedInURL(filePolicyUri)); StringSet existingFSPolicies = fs.getFilePolicies(); if (existingFSPolicies != null && existingFSPolicies.contains(filePolicyUri.toString())) { _log.info("Provided file policy {} is already is applied to the file sytem {}", filePolicy.getId(), fs.getId()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.ASSIGN_FILE_POLICY_TO_FILE_SYSTEM); op.setDescription("assign file policy to file system"); _dbClient.ready(FileShare.class, fs.getId(), task); return toTask(fs, task, op); } // check if same TYPE of policy already applied to file system if (filePolicy.getFilePolicyType().equals(FilePolicy.FilePolicyType.file_replication.name()) && existingFSPolicies != null && !existingFSPolicies.isEmpty()) { checkForDuplicatePolicyApplied(filePolicy, existingFSPolicies); } // Check if the vpool supports provided policy type.. VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); FilePolicyServiceUtils.validateVpoolSupportPolicyType(filePolicy, vpool); // Check if the vpool supports policy at file system level.. if (!vpool.getAllowFilePolicyAtFSLevel()) { errorMsg.append("Provided vpool :" + vpool.getLabel() + " doesn't support policy at file system level"); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidFilePolicyAssignParam(filePolicy.getFilePolicyName(), errorMsg.toString()); } // Verify the vpool/project/fs has any replication policy!!! // only single replication policy per vpool/project/fs. if (filePolicy.getFilePolicyType().equalsIgnoreCase(FilePolicyType.file_replication.name()) && FilePolicyServiceUtils.fsHasReplicationPolicy(_dbClient, vpool.getId(), fs.getProject().getURI(), fs.getId())) { errorMsg.append("Provided vpool/project/fs has already assigned with replication policy."); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidFilePolicyAssignParam(filePolicy.getFilePolicyName(), errorMsg.toString()); } if (filePolicy.getFilePolicyType().equalsIgnoreCase(FilePolicyType.file_snapshot.name()) && FilePolicyServiceUtils.fsHasSnapshotPolicyWithSameSchedule(_dbClient, fs.getId(), filePolicy)) { errorMsg.append("Snapshot policy with similar schedule is already present on fs " + fs.getLabel()); _log.error(errorMsg.toString()); throw APIException.badRequests.invalidFilePolicyAssignParam(filePolicy.getFilePolicyName(), errorMsg.toString()); } if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_replication.name())) { return assignFileReplicationPolicyToFS(fs, filePolicy, param, task); } else if (filePolicy.getFilePolicyType().equals(FilePolicyType.file_snapshot.name())) { return assignFilePolicyToFS(fs, filePolicy, task); } return resp; } /** * * Unassign existing file system to file policy. * * @param id * the URN of a ViPR fileSystem * @param filePolicyUri * the URN of a Policy * @brief Update file system with Policy detail * @return Task resource representation * @throws InternalException */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/unassign-file-policy/{filePolicyUri}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep unAssignFilePolicy(@PathParam("id") URI id, @PathParam("filePolicyUri") URI filePolicyUri) throws InternalException { // log input received. _log.info("Unassign Policy on File System : request received for {} with {}", id, filePolicyUri); String task = UUID.randomUUID().toString(); // Validate the FS id. ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); ArgValidator.checkFieldUriType(filePolicyUri, FilePolicy.class, "filePolicyUri"); ArgValidator.checkUri(filePolicyUri); FilePolicy fp = _permissionsHelper.getObjectById(filePolicyUri, FilePolicy.class); ArgValidator.checkEntityNotNull(fp, filePolicyUri, isIdEmbeddedInURL(filePolicyUri)); // verify the schedule policy is associated with file system or not. if (!fs.getFilePolicies().isEmpty() && !fs.getFilePolicies().contains(filePolicyUri.toString())) { throw APIException.badRequests.cannotFindAssociatedPolicy(filePolicyUri); } StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileOrchestrationController controller = getController(FileOrchestrationController.class, FileOrchestrationController.FILE_ORCHESTRATION_DEVICE); Operation op = _dbClient.createTaskOpStatus(FilePolicy.class, fp.getId(), task, ResourceOperationTypeEnum.UNASSIGN_FILE_POLICY); op.setDescription("Filesystem unassign policy"); // As the action done by tenant admin // Set current tenant as task's tenant!!! Task taskObj = op.getTask(fp.getId()); FilePolicyServiceUtils.updateTaskTenant(_dbClient, fp, "unassign", taskObj, fs.getTenant().getURI()); try { Set<URI> unassignFrom = new HashSet<URI>(); unassignFrom.add(id); _log.info("No Errors found proceeding further {}, {}, {}", new Object[] { _dbClient, fs, fp }); controller.unassignFilePolicy(filePolicyUri, unassignFrom, task); auditOp(OperationTypeEnum.UNASSIGN_FILE_POLICY, true, "BEGIN", fp.getId().toString(), fp.getFilePolicyName()); } catch (BadRequestException e) { op = _dbClient.error(FilePolicy.class, fp.getId(), task, e); _log.error("Error Unassigning File policy {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Error Unassigning Filesystem policy {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return toTask(fp, task, op); } /** * Get Policy for file system * * @param id * the URN of a ViPR File system * @brief Show file system * @return File system Policy details */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/file-policies") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public FilePolicyList getFileSystemPolicy(@PathParam("id") URI id) { FilePolicyList fpList = new FilePolicyList(); List<FilePolicyRestRep> fpRestList = new ArrayList<FilePolicyRestRep>(); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); StringSet fpolicies = fs.getFilePolicies(); for (String fpolicy : fpolicies) { FilePolicyRestRep fpRest = new FilePolicyRestRep(); URI fpURI = URI.create(fpolicy); if (fpURI != null) { SchedulePolicy fp = _permissionsHelper.getObjectById(fpURI, SchedulePolicy.class); if (fp != null) { ArgValidator.checkEntityNotNull(fp, fpURI, isIdEmbeddedInURL(fpURI)); getFilePolicyRestRep(fpRest, fp, fs); } } fpRestList.add(fpRest); } fpList.setFilePolicies(fpRestList); return fpList; } /** * Get file system Snapshot created by policy * * @param id * The URN of a ViPR file system * @param filePolicyUri * The URN of a file policy schedule * @param timeout * Time limit in seconds to get the output .Default is 30 seconds * @return List of snapshots created by a file policy */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/file-policies/{filePolicyUri}/snapshots") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public ScheduleSnapshotList getFileSystemSchedulePolicySnapshots(@PathParam("id") URI id, @PathParam("filePolicyUri") URI filePolicyUri, @QueryParam("timeout") int timeout) { // valid value of timeout is 10 sec to 10 min if (timeout < 10 || timeout > 600) { timeout = 30;// default timeout value. } ScheduleSnapshotList list = new ScheduleSnapshotList(); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); ArgValidator.checkFieldUriType(filePolicyUri, FilePolicy.class, "filePolicyUri"); ArgValidator.checkUri(filePolicyUri); FilePolicy sp = _permissionsHelper.getObjectById(filePolicyUri, FilePolicy.class); ArgValidator.checkEntityNotNull(sp, filePolicyUri, isIdEmbeddedInURL(filePolicyUri)); // verify the schedule policy is associated with file system or not. if (!fs.getFilePolicies().contains(filePolicyUri.toString())) { throw APIException.badRequests.cannotFindAssociatedPolicy(filePolicyUri); } String task = UUID.randomUUID().toString(); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileController controller = getController(FileController.class, device.getSystemType()); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.GET_FILE_SYSTEM_SNAPSHOT_BY_SCHEDULE); op.setDescription("list snapshots created by a policy"); try { _log.info("No Errors found. Proceeding further {}, {}, {}", new Object[] { _dbClient, fs, sp }); controller.listSanpshotByPolicy(device.getId(), fs.getId(), sp.getId(), task); Task taskObject = null; auditOp(OperationTypeEnum.GET_FILE_SYSTEM_SNAPSHOT_BY_SCHEDULE, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), sp.getId()); int timeoutCounter = 0; // wait till timeout or result from controller service ,whichever is earlier do { TimeUnit.SECONDS.sleep(1); taskObject = TaskUtils.findTaskForRequestId(_dbClient, fs.getId(), task); timeoutCounter++; // exit the loop if task is completed with error/success or timeout } while ((taskObject != null && !(taskObject.isReady() || taskObject.isError())) && timeoutCounter < timeout); if (taskObject == null) { throw APIException.badRequests .unableToProcessRequest("Error occured while getting Filesystem policy Snapshots task information"); } else if (taskObject.isReady()) { URIQueryResultList snapshotsURIs = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory.getFileshareSnapshotConstraint(id), snapshotsURIs); List<Snapshot> snapList = _dbClient.queryObject(Snapshot.class, snapshotsURIs); for (Snapshot snap : snapList) { if (!snap.getInactive() && snap.getExtensions().containsKey("schedule")) { ScheduleSnapshotRestRep snapRest = new ScheduleSnapshotRestRep(); getScheduleSnapshotRestRep(snapRest, snap); list.getScheduleSnapList().add(snapRest); snap.setInactive(true); _dbClient.updateObject(snap); } } } else if (taskObject.isError()) { throw APIException.badRequests .unableToProcessRequest("Error occured while getting Filesystem policy Snapshots due to" + taskObject.getMessage()); } else { throw APIException.badRequests .unableToProcessRequest("Error occured while getting Filesystem policy Snapshots due to timeout"); } } catch (BadRequestException e) { op = _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error while getting Filesystem policy Snapshots {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } catch (Exception e) { _log.error("Error while getting Filesystem policy Snapshots {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return list; } private void getScheduleSnapshotRestRep(ScheduleSnapshotRestRep target, Snapshot source) { if (source.getExtensions().containsKey("created")) { target.setCreated(source.getExtensions().get("created")); } if (source.getExtensions().containsKey("expires")) { target.setExpires(source.getExtensions().get("expires")); } target.setId(source.getId()); target.setMountPath(source.getMountPath()); target.setName(source.getName()); } /** * Create FilePolicyRestRep object from the SchedulePolicy object * * @param fpRest * FilePolicyRestRep object * @param fp * SchedulePolicy object * @param fs * FileShare object */ private void getFilePolicyRestRep(FilePolicyRestRep fpRest, SchedulePolicy fp, FileShare fs) { String snapshotScheduleName = fp.getPolicyName() + "_" + fs.getName(); String pattern = snapshotScheduleName + "_YYYY-MM-DD_HH-MM"; fpRest.setPolicyId(fp.getId()); fpRest.setPolicyName(fp.getPolicyName()); fpRest.setScheduleDayOfMonth(fp.getScheduleDayOfMonth()); fpRest.setScheduleDayOfWeek(fp.getScheduleDayOfWeek()); fpRest.setScheduleFrequency(fp.getScheduleFrequency()); fpRest.setScheduleRepeat(fp.getScheduleRepeat()); fpRest.setScheduleTime(fp.getScheduleTime()); fpRest.setSnapshotExpireTime(fp.getSnapshotExpireTime()); fpRest.setSnapshotExpireType(fp.getSnapshotExpireType()); fpRest.setSnapshotPattern(pattern); } /** * Gets and verifies the VirtualPool passed in the request. * * @param project * A reference to the project. * @param cosURI * The URI of the VirtualPool. * @param dbClient * Reference to a database client. * @param permissionsHelper * Reference to a permissions helper. * * @return A reference to the VirtualPool. */ public static VirtualPool getVirtualPoolForRequest(Project project, URI cosURI, DbClient dbClient, PermissionsHelper permissionsHelper) { ArgValidator.checkUri(cosURI); VirtualPool cos = dbClient.queryObject(VirtualPool.class, cosURI); ArgValidator.checkEntity(cos, cosURI, false); if (!VirtualPool.Type.file.name().equals(cos.getType())) { throw APIException.badRequests.virtualPoolNotForFileBlockStorage(VirtualPool.Type.file.name()); } permissionsHelper.checkTenantHasAccessToVirtualPool(project.getTenantOrg().getURI(), cos); return cos; } private void restoreFromOriginalFs(FileShare orgFs, FileShare fs) { // Vpool fs.setVirtualPool(orgFs.getVirtualPool()); // Replication file attributes!! fs.setAccessState(orgFs.getAccessState()); fs.setMirrorfsTargets(orgFs.getMirrorfsTargets()); fs.setParentFileShare(orgFs.getParentFileShare()); } /** * Checks to see if the file replication change is supported. * * @param currentVpool * the source virtual pool * @param newVpool * the target virtual pool * @param notSuppReasonBuff * the not supported reason string buffer * @return */ private boolean isSupportedFileReplicationCreate(FileShare fs, VirtualPool currentVpool, StringBuffer notSuppReasonBuff) { _log.info(String.format("Checking isSupportedFileReplicationCreate for Fs [%s] with vpool [%s]...", fs.getLabel(), currentVpool.getLabel())); if (!doBasicMirrorValidation(fs, currentVpool, notSuppReasonBuff)) { return false; } // File system should not be the active source file system!! if (fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.SOURCE.name()) && !MirrorStatus.DETACHED.name().equalsIgnoreCase(fs.getMirrorStatus())) { notSuppReasonBuff .append(String .format("File system given in request is an active source file system %s.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } // File system should not have any active mirror copies!! if (fs.getMirrorfsTargets() != null && !fs.getMirrorfsTargets().isEmpty()) { notSuppReasonBuff .append(String .format("File system given in request has active target file system %s.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } return true; } /** * Checks to see if the file replication change is supported. * * @param currentVpool * the source virtual pool * @param newVpool * the target virtual pool * @param notSuppReasonBuff * the not supported reason string buffer * @return */ private boolean validateDeleteMirrorCopies(FileShare fs, VirtualPool currentVpool, StringBuffer notSuppReasonBuff) { _log.info(String.format("Checking validateDeleteMirrorCopies for Fs [%s] ", fs.getLabel())); if (!doBasicMirrorValidation(fs, currentVpool, notSuppReasonBuff)) { return false; } // File system should not be the failover state // Failover state, the mirror copy would be in production!!! if (fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.SOURCE.name()) && (MirrorStatus.FAILED_OVER.name().equalsIgnoreCase(fs.getMirrorStatus()) || MirrorStatus.SUSPENDED.name().equalsIgnoreCase(fs.getMirrorStatus()))) { notSuppReasonBuff .append(String .format("File system given in request is in active or failover state %s.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } // File system should not have any active mirror copies!! if (fs.getMirrorfsTargets() == null || fs.getMirrorfsTargets().isEmpty()) { notSuppReasonBuff .append(String .format("File system given in request has no active target file system %s.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } return true; } /** * Checks to see if the file replication operation is supported. * * @param fs * file share object * @param currentVpool * source virtual pool * @param notSuppReasonBuff * the not supported reason string buffer * @param operation * mirror operation to be checked */ private boolean validateMirrorOperationSupported(FileShare fs, VirtualPool currentVpool, StringBuffer notSuppReasonBuff, String operation) { _log.info("Checking if mirror operation {} is supported for file system {} ", operation, fs.getLabel()); if (!doBasicMirrorValidation(fs, currentVpool, notSuppReasonBuff)) { return false; } String currentMirrorStatus = fs.getMirrorStatus(); boolean isSupported = false; // This validation is required after stop operation if (fs.getPersonality() == null || !fs.getPersonality().equals(PersonalityTypes.SOURCE.name())) { notSuppReasonBuff.append(String.format("File system - %s given in request is not having any active replication.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } switch (operation) { // Refresh operation can be performed without any check. case "refresh": isSupported = true; break; // START operation can be performed only if Mirror status is UNKNOWN case "start": if (currentMirrorStatus.equalsIgnoreCase(MirrorStatus.UNKNOWN.toString())) { isSupported = true; } break; // STOP operation can be performed only if Mirror status is SYNCHRONIZED or IN_SYNC case "stop": if (currentMirrorStatus.equalsIgnoreCase(MirrorStatus.SYNCHRONIZED.toString()) || currentMirrorStatus.equalsIgnoreCase(MirrorStatus.IN_SYNC.toString())) { isSupported = true; } break; // PAUSE operation can be performed only if Mirror status is SYNCHRONIZED or IN_SYNC case "pause": if (currentMirrorStatus.equalsIgnoreCase(MirrorStatus.SYNCHRONIZED.toString()) || currentMirrorStatus.equalsIgnoreCase(MirrorStatus.IN_SYNC.toString())) { isSupported = true; } break; // RESUME operation can be performed only if Mirror status is PAUSED. case "resume": if (currentMirrorStatus.equalsIgnoreCase(MirrorStatus.PAUSED.toString())) { isSupported = true; } break; // Fail over can be performed if Mirror status is NOT UNKNOWN or FAILED_OVER. case "failover": if (!(currentMirrorStatus.equalsIgnoreCase(MirrorStatus.UNKNOWN.toString()) || currentMirrorStatus.equalsIgnoreCase(MirrorStatus.FAILED_OVER.toString()))) { isSupported = true; } break; // Fail back can be performed only if Mirror status is FAILED_OVER. case "failback": if (currentMirrorStatus.equalsIgnoreCase(MirrorStatus.FAILED_OVER.toString())) { isSupported = true; } break; } notSuppReasonBuff.append(String.format(" : file system %s is in %s state", fs.getLabel(), currentMirrorStatus.toUpperCase())); return isSupported; } /** * Checks to see if the file replication change is supported. * * @param fs * @param currentVpool * the source virtual pool * @param notSuppReasonBuff * the not supported reason string buffer * @return */ private boolean doBasicMirrorValidation(FileShare fs, VirtualPool currentVpool, StringBuffer notSuppReasonBuff) { // file system virtual pool must be enabled with replication.. if (!FilePolicyServiceUtils.vPoolSpecifiesFileReplication(fs, currentVpool, _dbClient)) { notSuppReasonBuff.append(String.format("File replication is not enabled in virtual pool - %s" + " of the requested file system -%s ", currentVpool.getLabel(), fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } // File system should not be the target file system.. if (fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.TARGET.name())) { notSuppReasonBuff.append(String.format("File system - %s given in request is an active Target file system.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return false; } return true; } /** * Checks to see if the file replication change is supported. * * @param fs * @param notSuppReasonBuff * the not supported reason string buffer * @return */ private boolean filesystemHasActiveReplication(FileShare fs, StringBuffer notSuppReasonBuff, String deleteType, boolean forceDelete) { // File system should not be the target file system.. if (fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.TARGET.name())) { notSuppReasonBuff.append(String.format("File system - %s given in request is an active Target file system.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return true; } // File system should not have active replication targets!! // For resource delete (forceDelete=false) // For VIPR_ONLY type, till we support ingestion of replication file systems // avoid deleting file systems if it has active mirrors!! if (forceDelete == false || FileControllerConstants.DeleteTypeEnum.VIPR_ONLY.toString().equalsIgnoreCase(deleteType)) { if (fs.getMirrorfsTargets() != null && !fs.getMirrorfsTargets().isEmpty()) { notSuppReasonBuff .append(String .format("File system %s given in request has active target file systems.", fs.getLabel())); _log.info(notSuppReasonBuff.toString()); return true; } } return false; } private Long getMinutRpoValue(String rpoType, Long rpoValue) { Long multiplier = 1L; switch (rpoType.toUpperCase()) { case "MINUTES": multiplier = 1L; break; case "HOURS": multiplier = MINUTES_PER_HOUR; break; case "DAYS": multiplier = HOURS_PER_DAY * MINUTES_PER_HOUR; break; } Long rpoInMinuts = rpoValue * multiplier; return rpoInMinuts; } private boolean validateProtectionSettings(VirtualPool vpool, FileReplicationParam param) { if (param.getCopies() != null && !param.getCopies().isEmpty()) { if (param.getCopies().get(0).getReplicationSettingParam() != null) { FileSystemReplicationSettings rpoParam = param.getCopies().get(0).getReplicationSettingParam(); if (rpoParam.getRpoType() == null || FileReplicationRPOType.lookup(rpoParam.getRpoType()) == null) { throw APIException.badRequests .invalidReplicationRPOType(rpoParam.getRpoType()); } if (rpoParam.getRpoValue() == null || rpoParam.getRpoValue() <= 0) { throw APIException.badRequests.invalidReplicationRPOValue(); } // Validate the RPO values!! switch (rpoParam.getRpoType().toUpperCase()) { case "MINUTES": if (rpoParam.getRpoValue() > MINUTES_PER_HOUR) { throw APIException.badRequests.invalidReplicationRPOValueForType( rpoParam.getRpoValue().toString(), rpoParam.getRpoType()); } break; case "HOURS": if (rpoParam.getRpoValue() > HOURS_PER_DAY) { throw APIException.badRequests.invalidReplicationRPOValueForType( rpoParam.getRpoValue().toString(), rpoParam.getRpoType()); } break; case "DAYS": // No validation required for Days. break; default: throw APIException.badRequests.invalidReplicationRPOType(rpoParam.getRpoType()); } Long rpoInMinuts = getMinutRpoValue(rpoParam.getRpoType(), rpoParam.getRpoValue()); Long vpoolRpoInMinuts = getMinutRpoValue(vpool.getFrRpoType(), vpool.getFrRpoValue()); if (rpoInMinuts < vpoolRpoInMinuts) { throw APIException.badRequests.lessRPOThanVpoolRpo(); } return true; } else { throw APIException.badRequests.noProtectionSettingsProvided(); } } return false; } /** * Perform a mount operation for a file system * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of a ViPR File system * @param param * File system mount parameters * @brief mount a FS * @return Task resource representation * @throws InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/mount") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep mountExport(@PathParam("id") URI id, FileSystemMountParam param) throws InternalException { _log.info("FileService::mount Request recieved {}", id); String task = UUID.randomUUID().toString(); ArgValidator.checkFieldUriType(id, FileShare.class, "id"); // Get the FileSystem object from the URN FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // validations if (!isSubDirValid(fs, param.getSubDir())) { throw APIException.badRequests.invalidParameter("sub_directory", param.getSubDir()); } if (!isFSTypeValid(param)) { throw APIException.badRequests.invalidParameter("fs_type", param.getFsType()); } if (!isSecurityValid(fs, param)) { throw APIException.badRequests.invalidParameter("security", param.getSecurity()); } fs.setOpStatus(new OpStatusMap()); Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.MOUNT_NFS_EXPORT); fs.getOpStatus().createTaskStatus(task, op); _dbClient.updateObject(fs); // Now get ready to make calls into the controller ComputeSystemOrchestrationController controller = getController(ComputeSystemOrchestrationController.class, null); try { controller.mountDevice(param.getHost(), id, param.getSubDir(), param.getSecurity(), param.getPath(), param.getFsType(), task); } catch (Exception e) { // treating all controller exceptions as internal error for now. controller // should discriminate between validation problems vs. internal errors throw e; } auditOp(OperationTypeEnum.MOUNT_NFS_EXPORT, true, AuditLogManager.AUDITOP_BEGIN, fs.getName(), fs.getId().toString(), param.getHost().toString(), param.getSubDir(), param.getPath()); fs = _dbClient.queryObject(FileShare.class, id); _log.debug("FileService::Mount Before sending response, FS ID : {}, Taks : {} ; Status {}", fs.getOpStatus().get(task), fs .getOpStatus().get(task).getStatus()); return toTask(fs, task, op); } /** * Get list of mounts for the specified file system. * * @param id * the URN of a ViPR File system * @brief List file system mounts * @return List of file system mounts. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/mount") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public MountInfoList getMountListForFS(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, FileShare.class, "id"); _log.info(String.format("Get list of file system mounts: %1$s", id)); MountInfoList mountList = new MountInfoList(); mountList.setMountList(FileOperationUtils.queryDBFSMounts(id, _dbClient)); return mountList; } /** * unmount an exported filesystem * <p> * NOTE: This is an asynchronous operation. * * @param id * the URN of the fs * @param param * FileSystemUnmountParam * @brief unmount fs * @return Task resource representation * @throws com.emc.storageos.svcs.errorhandling.resources.InternalException */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/unmount") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL }) public TaskResourceRep unmountExport(@PathParam("id") URI id, FileSystemUnmountParam param) throws InternalException { FileShare fs = queryResource(id); ArgValidator.checkEntity(fs, id, isIdEmbeddedInURL(id)); // validations if (!isMountPathValid(param.getHostId(), param.getMountPath())) { throw APIException.badRequests.invalidParameter("mount_path", param.getMountPath()); } _log.info("FileService::unmount export Request recieved {}", id); String task = UUID.randomUUID().toString(); Operation op = new Operation(); op.setResourceType(ResourceOperationTypeEnum.UNMOUNT_NFS_EXPORT); fs.setOpStatus(new OpStatusMap()); fs.getOpStatus().createTaskStatus(task, op); _dbClient.updateObject(fs); // Now get ready to make calls into the controller ComputeSystemOrchestrationController controller = getController(ComputeSystemOrchestrationController.class, null); try { controller.unmountDevice(param.getHostId(), id, param.getMountPath(), task); } catch (InternalException e) { // treating all controller exceptions as internal error for now. controller // should discriminate between validation problems vs. internal errors throw e; } auditOp(OperationTypeEnum.UNMOUNT_NFS_EXPORT, true, AuditLogManager.AUDITOP_BEGIN, param.getHostId(), param.getMountPath()); fs = _dbClient.queryObject(FileShare.class, fs.getId()); _log.debug("FileService::unmount Before sending response, FS ID : {}, Task : {} ; Status {}", fs.getOpStatus().get(task), fs.getOpStatus().get(task).getStatus()); return toTask(fs, task, op); } private boolean isSecurityValid(FileShare fs, FileSystemMountParam param) { List<String> allowedSecurities = new ArrayList<String>(); String subDirectory = param.getSubDir(); if (StringUtils.isEmpty(param.getSubDir())) { subDirectory = null; } List<ExportRule> exports = FileOperationUtils.getExportRules(fs.getId(), false, subDirectory, _dbClient); for (ExportRule rule : exports) { List<String> securityTypes = Arrays.asList(rule.getSecFlavor().split("\\s*,\\s*")); allowedSecurities.addAll(securityTypes); } if (allowedSecurities.contains(param.getSecurity())) { return true; } return false; } private boolean isFSTypeValid(FileSystemMountParam param) { if (FileSystemMountType.contains(param.getFsType())) { return true; } return false; } private boolean isSubDirValid(FileShare fs, String subDir) { List<ExportRule> exportFileRulesTemp = FileOperationUtils.getExportRules(fs.getId(), false, subDir, _dbClient); if (!exportFileRulesTemp.isEmpty()) { return true; } return false; } private boolean isMountPathValid(URI hostId, String mountPath) { List<MountInfo> mountList = FileOperationUtils.queryDBHostMounts(hostId, _dbClient); for (MountInfo mount : mountList) { if (mount.getMountPath().equalsIgnoreCase(mountPath)) { return true; } } return false; } private void checkForDuplicatePolicyApplied(FilePolicy filePolicy, StringSet existingFSPolicies) { List<URI> existingFSPolicyURIs = new ArrayList<>(); for (String filePolicyURI : existingFSPolicies) { existingFSPolicyURIs.add(URI.create(filePolicyURI)); } Iterator<FilePolicy> iterator = _dbClient.queryIterativeObjects(FilePolicy.class, existingFSPolicyURIs, true); while (iterator.hasNext()) { FilePolicy fp = iterator.next(); if (filePolicy.getFilePolicyType().equals(fp.getFilePolicyType())) { _log.error("File policy of same type is already applied to the file system {}.", filePolicy.getFilePolicyType()); throw APIException.badRequests.duplicateFilePolicyTypeAssociation(filePolicy.getFilePolicyType()); } } } private TaskResourceRep assignFilePolicyToFS(FileShare fs, FilePolicy filePolicy, String task) { StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); FileOrchestrationController controller = getController(FileOrchestrationController.class, FileOrchestrationController.FILE_ORCHESTRATION_DEVICE); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.ASSIGN_FILE_POLICY_TO_FILE_SYSTEM); op.setDescription("assign file policy to file system"); // As the action done by tenant admin // Set current tenant as task's tenant!!! Task taskObj = op.getTask(fs.getId()); FilePolicyServiceUtils.updateTaskTenant(_dbClient, filePolicy, "assign", taskObj, fs.getTenant().getURI()); try { _log.info("No Errors found proceeding further {}, {}, {}", new Object[] { _dbClient, fs, filePolicy }); List<FileDescriptor> fileDescriptors = new ArrayList<>(); FileDescriptor desc = new FileDescriptor(Type.FILE_EXISTING_SOURCE, fs.getId()); fileDescriptors.add(desc); controller.assignFilePolicyToFileSystem(filePolicy, fileDescriptors, task); auditOp(OperationTypeEnum.ASSIGN_FILE_POLICY, true, AuditLogManager.AUDITOP_BEGIN, fs.getId().toString(), device.getId().toString(), filePolicy.getId()); } catch (BadRequestException e) { _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error Assigning Filesystem policy {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Error Assigning Filesystem policy {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return toTask(fs, task, op); } private TaskResourceRep assignFileReplicationPolicyToFS(FileShare fs, FilePolicy filePolicy, FilePolicyFileSystemAssignParam param, String task) { StringBuffer notSuppReasonBuff = new StringBuffer(); // Verify the fs has replication attributes!!! if (fs.getPersonality() != null && PersonalityTypes.SOURCE.name().equalsIgnoreCase(fs.getPersonality()) && fs.getMirrorfsTargets() != null && !fs.getMirrorfsTargets().isEmpty()) { notSuppReasonBuff.append(String.format("File system %s has active target file systems", fs.getLabel())); _log.error(notSuppReasonBuff.toString()); throw APIException.badRequests.unableToProcessRequest(notSuppReasonBuff.toString()); } // File system should not be the target file system.. if (fs.getPersonality() != null && fs.getPersonality().equalsIgnoreCase(PersonalityTypes.TARGET.name())) { notSuppReasonBuff.append(String.format("File system - %s given in request is an active Target file system.", fs.getLabel())); _log.error(notSuppReasonBuff.toString()); throw APIException.badRequests.unableToProcessRequest(notSuppReasonBuff.toString()); } ArgValidator.checkFieldNotNull(param.getTargetVArrays(), "target_varrays"); Set<URI> targertVarrayURIs = param.getTargetVArrays(); for (URI targertVarrayURI : targertVarrayURIs) { ArgValidator.checkFieldUriType(targertVarrayURI, VirtualArray.class, "target_varray"); VirtualArray targetVarray = _permissionsHelper.getObjectById(targertVarrayURI, VirtualArray.class); ArgValidator.checkEntity(targetVarray, targertVarrayURI, false); } VirtualArray sourceVarray = _dbClient.queryObject(VirtualArray.class, fs.getVirtualArray()); // Get the project. URI projectURI = fs.getProject().getURI(); Project project = _permissionsHelper.getObjectById(projectURI, Project.class); VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, fs.getVirtualPool()); // New operation TaskList taskList = new TaskList(); Operation op = _dbClient.createTaskOpStatus(FileShare.class, fs.getId(), task, ResourceOperationTypeEnum.ASSIGN_FILE_POLICY_TO_FILE_SYSTEM); op.setDescription("assign file policy to file system"); // As the action done by tenant admin // Set current tenant as task's tenant!!! Task taskObj = op.getTask(fs.getId()); FilePolicyServiceUtils.updateTaskTenant(_dbClient, filePolicy, "assign", taskObj, fs.getTenant().getURI()); TaskResourceRep fileShareTask = toTask(fs, task, op); taskList.getTaskList().add(fileShareTask); StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice()); // prepare vpool capability values VirtualPoolCapabilityValuesWrapper capabilities = new VirtualPoolCapabilityValuesWrapper(); capabilities.put(VirtualPoolCapabilityValuesWrapper.SIZE, fs.getCapacity()); capabilities.put(VirtualPoolCapabilityValuesWrapper.RESOURCE_COUNT, new Integer(1)); if (VirtualPool.ProvisioningType.Thin.toString().equalsIgnoreCase(vpool.getSupportedProvisioningType())) { capabilities.put(VirtualPoolCapabilityValuesWrapper.THIN_PROVISIONING, Boolean.TRUE); } // Set the source file system details // source fs details used in finding recommendations for target fs!! capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_SYSTEM_CREATE_MIRROR_COPY, Boolean.TRUE); capabilities.put(VirtualPoolCapabilityValuesWrapper.EXISTING_SOURCE_FILE_SYSTEM, fs); capabilities.put(VirtualPoolCapabilityValuesWrapper.SOURCE_STORAGE_SYSTEM, device); capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_TYPE, filePolicy.getFileReplicationType()); capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_COPY_MODE, filePolicy.getFileReplicationCopyMode()); Set<String> targetVArrys = new HashSet<String>(); if (filePolicy.getFileReplicationType().equalsIgnoreCase(FileReplicationType.REMOTE.name())) { for (URI targertVarrayURI : targertVarrayURIs) { targetVArrys.add(targertVarrayURI.toString()); } } else { targetVArrys.add(sourceVarray.getId().toString()); } capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_TARGET_VARRAYS, targetVArrys); capabilities.put(VirtualPoolCapabilityValuesWrapper.FILE_REPLICATION_TARGET_VPOOL, vpool.getId()); FileServiceApi fileServiceApi = getFileShareServiceImpl(capabilities, _dbClient); try { // Call out placementManager to get the recommendation for placement. List recommendations = _filePlacementManager.getRecommendationsForFileCreateRequest(sourceVarray, project, vpool, capabilities); fileServiceApi.assignFilePolicyToFileSystem(fs, filePolicy, project, vpool, sourceVarray, taskList, task, recommendations, capabilities); } catch (BadRequestException e) { _dbClient.error(FileShare.class, fs.getId(), task, e); _log.error("Error Assigning Filesystem policy {}, {}", e.getMessage(), e); throw e; } catch (Exception e) { _log.error("Error Assigning Filesystem policy {}, {}", e.getMessage(), e); throw APIException.badRequests.unableToProcessRequest(e.getMessage()); } return fileShareTask; } }