/*
* Copyright (c) 2008-2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource;
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.Iterator;
import java.util.List;
import java.util.UUID;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.api.mapper.functions.MapFileSnapshot;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.api.service.impl.placement.FileStorageScheduler;
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.response.BulkList;
import com.emc.storageos.api.service.impl.response.BulkList.PermissionsEnforcingResourceFilter;
import com.emc.storageos.api.service.impl.response.BulkList.ResourceFilter;
import com.emc.storageos.api.service.impl.response.ProjOwnedSnapResRepFilter;
import com.emc.storageos.api.service.impl.response.ResRepFilter;
import com.emc.storageos.api.service.impl.response.SearchedResRepList;
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.model.DiscoveredDataObject;
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.FileShare;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.Operation;
import com.emc.storageos.db.client.model.Project;
import com.emc.storageos.db.client.model.SMBFileShare;
import com.emc.storageos.db.client.model.SMBShareMap;
import com.emc.storageos.db.client.model.Snapshot;
import com.emc.storageos.db.client.model.StoragePort;
import com.emc.storageos.db.client.model.StorageProtocol;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.exceptions.DatabaseException;
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.TaskResourceRep;
import com.emc.storageos.model.file.ExportRule;
import com.emc.storageos.model.file.ExportRules;
import com.emc.storageos.model.file.FileSnapshotBulkRep;
import com.emc.storageos.model.file.FileSnapshotRestRep;
import com.emc.storageos.model.file.FileSystemExportList;
import com.emc.storageos.model.file.FileSystemExportParam;
import com.emc.storageos.model.file.FileSystemShareList;
import com.emc.storageos.model.file.FileSystemShareParam;
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.SnapshotCifsShareACLUpdateParams;
import com.emc.storageos.model.file.SnapshotExportUpdateParams;
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.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.FileController;
import com.emc.storageos.volumecontroller.FileControllerConstants;
import com.emc.storageos.volumecontroller.FileSMBShare;
import com.emc.storageos.volumecontroller.FileShareExport;
@Path("/file/snapshots")
@DefaultPermissions(readRoles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, readAcls = { ACL.ANY }, writeRoles = {
Role.TENANT_ADMIN }, writeAcls = { ACL.ANY })
public class FileSnapshotService extends TaskResourceService {
private static final Logger _log = LoggerFactory.getLogger(FileService.class);
private static final String EVENT_SERVICE_TYPE = "fileSnapshot";
@Override
public String getServiceType() {
return EVENT_SERVICE_TYPE;
}
private FileStorageScheduler _fileScheduler;
public void setFileScheduler(FileStorageScheduler fileScheduler) {
_fileScheduler = fileScheduler;
}
/**
* Get info for file share snapshot
*
* @param id
* the URN of a ViPR Snapshot
* @brief Show file snapshot
* @return File snapshot details
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY })
public FileSnapshotRestRep getSnapshot(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
return map(snap);
}
/**
* Get all Snapshots matching the path
*
* @QueryParam mountpath
* @brief Show Snapshots
* @return Snapshot details
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.OWN, ACL.ALL })
public List<FileSnapshotRestRep> getSnapshots(@QueryParam("mountpath") String mountPath) {
List<FileSnapshotRestRep> snapRepList = new ArrayList<FileSnapshotRestRep>();
List<URI> ids = _dbClient.queryByType(Snapshot.class, true);
Iterator<Snapshot> iter = _dbClient.queryIterativeObjects(Snapshot.class, ids);
_log.info("getSnapshots call ... with mountpath {}", mountPath);
while (iter.hasNext()) {
Snapshot snap = iter.next();
if (snap != null) {
if (mountPath != null) {
if (snap.getMountPath().equalsIgnoreCase(mountPath)) {
snapRepList.add(map(snap));
} else {
_log.info("Skip this Snapshot Mount Path doesnt match {} {}", snap.getMountPath(), mountPath);
}
} else {
_log.info("Mountpath query param is null");
snapRepList.add(map(snap));
}
}
}
return snapRepList;
}
@Override
protected Snapshot queryResource(URI id) {
ArgValidator.checkUri(id);
Snapshot snap = _permissionsHelper.getObjectById(id, Snapshot.class);
ArgValidator.checkEntityNotNull(snap, id, isIdEmbeddedInURL(id));
return snap;
}
@Override
protected URI getTenantOwner(URI id) {
Snapshot snapshot = queryResource(id);
URI projectUri = snapshot.getProject().getURI();
ArgValidator.checkUri(projectUri);
Project project = _permissionsHelper.getObjectById(projectUri, Project.class);
ArgValidator.checkEntityNotNull(project, projectUri, isIdEmbeddedInURL(projectUri));
return project.getTenantOrg().getURI();
}
private void verifyFileSnapshotExports(Snapshot snap, FileSystemExportParam param, String path) {
FSExportMap snapExports = snap.getFsExports();
URI id = snap.getId();
if (null != snapExports) {
Iterator<FileExport> it = snapExports.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.getEndpoints();
for (String providedEndpoint : providedEndpoints) {
if (availableEndpoints.contains(providedEndpoint)) {
isAlreadyExportedToSameEndpoint = true;
break;
}
}
if (isAlreadyExportedToSameEndpoint) {
_log.info(String.format(
"Existing Export params for Snapshot 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 Snapshot id: %1$s, SecurityType: %2$s, " +
"Permissions: %3$s, Root user mapping: %4$s, ",
id, param.getSecurityType(), param.getPermissions(), param.getRootUserMapping()));
if (!fileExport.getPermissions().equals(param.getPermissions())) {
throw APIException.badRequests.updatingSnapshotExportNotAllowed("permissions");
}
if (!fileExport.getSecurityType().equals(param.getSecurityType())) {
throw APIException.badRequests.updatingSnapshotExportNotAllowed("type");
}
if (!fileExport.getRootUserMapping().equals(param.getRootUserMapping())) {
throw APIException.badRequests.updatingSnapshotExportNotAllowed("root_user");
}
}
String rootUserMapping = param.getRootUserMapping();
if (rootUserMapping != null) {
rootUserMapping = rootUserMapping.toLowerCase();
}
String currentlyLoggedInUsername = getUserFromContext().getName();
if (!"nobody".equals(rootUserMapping) && !currentlyLoggedInUsername.equals(rootUserMapping)) {
throw APIException.forbidden.onlyCurrentUserCanBeSetInRootUserMapping(currentlyLoggedInUsername);
}
}
}
}
}
/**
* Add file share snapshot export.
* <p>
* NOTE: This is an asynchronous operation.
*
* @param id
* the URN of a ViPR Snapshot
* @param param
* File system export parameters
* @brief Create file snapshot 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.ANY })
public TaskResourceRep export(@PathParam("id") URI id, FileSystemExportParam param)
throws InternalException {
_log.info("Snapshot Export request recieved {}", id);
String task = UUID.randomUUID().toString();
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
ArgValidator.checkEntity(snap, id, true);
if (!param.getPermissions().equals(FileShareExport.Permissions.ro.name())) {
throw APIException.badRequests.snapshotExportPermissionReadOnly();
}
ArgValidator.checkFieldValueFromEnum(param.getSecurityType(), "type",
EnumSet.allOf(FileShareExport.SecurityTypes.class));
ArgValidator.checkFieldValueFromEnum(param.getProtocol(), "protocol",
EnumSet.allOf(StorageProtocol.File.class));
FileService.validateIpInterfacesRegistered(param.getEndpoints(), _dbClient);
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(), FileShare.class);
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
// Locate storage port for exporting file snap
// We use file system in the call since file snap belongs to the same neighbourhood as its parent file system
StoragePort sport = _fileScheduler.placeFileShareExport(fs, param.getProtocol(), param.getEndpoints());
String path = snap.getPath();
String mountPath = snap.getMountPath();
_log.info("Check whether there is a NFS Export already for the path {}", path);
FSExportMap exportMap = snap.getFsExports();
if (exportMap != null) {
Iterator it = snap.getFsExports().keySet().iterator();
boolean exportExists = false;
while (it.hasNext()) {
String fsExpKey = (String) it.next();
FileExport fileExport = snap.getFsExports().get(fsExpKey);
_log.info("Snap export key {} does it exist ? {}", fsExpKey + ":" + fileExport.getPath(), exportExists);
if (fileExport.getPath().equalsIgnoreCase(path)) {
exportExists = true;
_log.info("Snap export key {} exist {}", fsExpKey + ":" + fileExport.getPath(), exportExists);
break;
}
}
if (exportExists) {
throw APIException.badRequests.snapshotHasExistingExport();
}
}
verifyFileSnapshotExports(snap, param, path);
FileShareExport export = new FileShareExport(param.getEndpoints(), param.getSecurityType(), param.getPermissions(),
param.getRootUserMapping(), param.getProtocol(), sport.getPortGroup(), sport.getPortNetworkId(), path, mountPath,
param.getSubDirectory(), param.getComments());
_log.info("FileSnapExport --- FileSnap id: " + id + ", Clients: " + export.getClients() + ", StoragePort:" + sport.getPortName()
+ ", StoragePort :" + export.getStoragePort() + ", SecurityType: " + export.getSecurityType() +
", Permissions: " + export.getPermissions() + ", Root user mapping: " + export.getRootUserMapping() + ",Protocol: "
+ export.getProtocol() +
",path:" + export.getPath() + ",mountPath:" + export.getMountPath());
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snap.getId(),
task, ResourceOperationTypeEnum.EXPORT_FILE_SNAPSHOT);
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.export(device.getId(), snap.getId(), Arrays.asList(export), task);
auditOp(OperationTypeEnum.EXPORT_FILE_SNAPSHOT, true, AuditLogManager.AUDITOP_BEGIN,
snap.getId().toString(), device.getId().toString(), export.getClients(), param.getSecurityType(),
param.getPermissions(), param.getRootUserMapping(), param.getProtocol());
return toTask(snap, task, op);
}
/**
* @Deprecated use {id}/export instead
* Get file share snapshots exports
* @param id
* the URN of a ViPR Snapshot
* @brief List file snapshot exports.This method is deprecated.
* <p>
* Use /file/snapshots/{id}/export instead.
* @return List of file share snapshot exports
*/
@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 getFileSystemSnapshotExportList(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snapshot = queryResource(id);
FileSystemExportList fileExportListResponse = new FileSystemExportList();
if (snapshot.getInactive()) {
return fileExportListResponse;
}
// Get export map from snapshot
FSExportMap exportMap = snapshot.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());
fileExportListResponse.getExportList().add(fileExportParam);
}
return fileExportListResponse;
}
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/export")
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY })
public ExportRules getSnapshotExportRules(@PathParam("id") URI id,
@QueryParam("allDirs") boolean allDirs,
@QueryParam("subDir") String subDir) {
_log.info("Request recieved to list snapshotExports with Id : {}",
new Object[] { id });
// Validate the FS id.
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snapshot = queryResource(id);
ExportRules exportRules = new ExportRules();
List<ExportRule> exportRule = new ArrayList<>();
// Query All Export Rules Specific to a File System.
List<FileExportRule> exports = queryDBSnapshotExports(snapshot);
_log.info("Number of existing snapshot exports found : {} ", exports.size());
// All EXPORTS
for (FileExportRule rule : exports) {
ExportRule expRule = new ExportRule();
// Copy Props
copyPropertiesToSave(rule, expRule, snapshot);
exportRule.add(expRule);
}
_log.info("Number of snapshot export rules returning {}", exportRule.size());
exportRules.setExportRules(exportRule);
return exportRules;
}
private List<FileExportRule> queryDBSnapshotExports(Snapshot snapshot) {
_log.info("Querying all ExportRules Using Snapshot Id {}", snapshot.getId());
try {
ContainmentConstraint containmentConstraint = ContainmentConstraint.Factory.getSnapshotExportRulesConstraint(snapshot.getId());
List<FileExportRule> fileExportRules = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, FileExportRule.class,
containmentConstraint);
return fileExportRules;
} catch (Exception e) {
_log.error("Error while querying {}", e);
}
return null;
}
private void copyPropertiesToSave(FileExportRule orig, ExportRule dest, Snapshot snapshot) {
dest.setSnapShotID(snapshot.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());
}
/**
* Remove file share snapshot export.
* <p>
* NOTE: This is an asynchronous operation.
*
* @param id
* the URN of a ViPR Snapshot
* @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 snapshot export
* @return Task resource representation
* @throws InternalException
*/
@DELETE
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/exports/{protocol},{secType},{perm},{rootMapping}")
@CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.ANY })
public TaskResourceRep unexport(@PathParam("id") URI id,
@PathParam("protocol") String protocol, @PathParam("secType") String securityType,
@PathParam("perm") String permissions,
@PathParam("rootMapping") String rootUserMapping) throws InternalException {
String task = UUID.randomUUID().toString();
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(), FileShare.class);
ArgValidator.checkFieldNotNull(protocol, "protocol");
ArgValidator.checkFieldNotNull(securityType, "secType");
ArgValidator.checkFieldNotNull(permissions, "perm");
ArgValidator.checkFieldNotNull(rootUserMapping, "rootMapping");
if (snap.getFsExports() == null || snap.getFsExports().isEmpty()) {
// No export to unexport, return success.
String message = "Export does not exist";
return getSuccessResponse(snap, task, ResourceOperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, message);
}
ArgValidator.checkEntity(snap, id, isIdEmbeddedInURL(id));
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
FileController controller = getController(FileController.class,
device.getSystemType());
String path = snap.getPath();
_log.info(String.format("securityType %1$s, permissions %2$s, rootMapping %3$s %4$s", securityType, permissions, rootUserMapping,
path));
FileExport fileSnapExport = snap.getFsExports().get(
FileExport.exportLookupKey(protocol, securityType, permissions, rootUserMapping, path));
if (fileSnapExport == null) {
// No export to unexport, return success.
String message = "Export does not exist";
return getSuccessResponse(snap, task, ResourceOperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, message);
}
List<String> endpoints = new ArrayList<String>(); // empty list for unexport
FileShareExport export = new FileShareExport(endpoints, securityType, permissions, rootUserMapping, protocol,
fileSnapExport.getStoragePortName(), fileSnapExport.getStoragePort(), fileSnapExport.getPath());
export.setIsilonId(fileSnapExport.getIsilonId());
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snap.getId(), task, ResourceOperationTypeEnum.UNEXPORT_FILE_SNAPSHOT);
controller.unexport(device.getId(), snap.getId(), Arrays.asList(export), task);
auditOp(OperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, true, AuditLogManager.AUDITOP_BEGIN,
snap.getId().toString(), device.getId().toString(), securityType, permissions, rootUserMapping, protocol);
return toTask(snap, task, op);
}
@DELETE
@Path("/{id}/export")
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.TENANT_ADMIN }, acls = { ACL.ANY })
public TaskResourceRep deleteSnapshotExportRules(@PathParam("id") URI id) {
// log input received.
_log.info("Delete Snapshot Export Rules : request received for {}", new Object[] { id });
String task = UUID.randomUUID().toString();
// Validate the FS id.
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snapshot = queryResource(id);
FileShare fileShare = _permissionsHelper.getObjectById(snapshot.getParent(), FileShare.class);
ArgValidator.checkEntity(snapshot, id, isIdEmbeddedInURL(id));
/* check if the Snapshot has any export rules on it */
List<FileExportRule> exports = queryDBSnapshotExports(snapshot);
if (exports == null || exports.isEmpty()) {
_log.error("Error Processing Export Updates for snapshot {} doesnot have exports", snapshot.getName());
throw APIException.badRequests.snapshotHasNoExport(snapshot.getId());
}
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fileShare.getStorageDevice());
String path = snapshot.getPath();
_log.info("Export path found {} ", path);
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snapshot.getId(), task,
ResourceOperationTypeEnum.UNEXPORT_FILE_SNAPSHOT);
try {
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fileShare, _dbClient);
fileServiceApi.deleteExportRules(device.getId(), snapshot.getId(), false, null, false, task);
auditOp(OperationTypeEnum.UNEXPORT_FILE_SNAPSHOT, true, AuditLogManager.AUDITOP_BEGIN,
snapshot.getId().toString(), device.getId().toString(), false, null);
return toTask(snapshot, task, op);
}
catch (BadRequestException 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());
}
}
/**
* Returns a task when there is no export to unexport
*
* @param snap
* Snapshot whose export has to be deleted
* @param task
* @return Task resource representation
*/
private TaskResourceRep getSuccessResponse(Snapshot snap, String task, ResourceOperationTypeEnum type, String message) {
Operation op = new Operation();
op.setResourceType(type);
op.ready(message);
_dbClient.createTaskOpStatus(Snapshot.class, snap.getId(), task, op);
return toTask(snap, task, op);
}
/**
* Lists all SMB shares for the specified snapshot.
*
* @param id
* the URN of a ViPR Snapshot
* @brief List file snapshot SMB shares
* @return List of SMB 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 snapshot: %1$s", id));
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
FileSystemShareList fileShareListResponse = new FileSystemShareList();
if (snap.getInactive()) {
return fileShareListResponse;
}
// Get SMB share map from snapshot
SMBShareMap smbShareMap = snap.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(FileService.UNLIMITED_USERS);
}
shareParam.setPermissionType(smbShare.getPermissionType());
shareParam.setPermission(smbShare.getPermission());
shareParam.setMountPoint(smbShare.getMountPoint());
shareParam.setPath(smbShare.getPath());
fileShareListResponse.getShareList().add(shareParam);
}
return fileShareListResponse;
}
/**
* Creates SMB file share.
* <p>
* Note: This is an asynchronous operation.
*
* @param id
* the URN of a ViPR Snapshot
* @param param
* File system share parameters
* @brief Create file snapshot 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.ANY })
public TaskResourceRep share(@PathParam("id") URI id, FileSystemShareParam param)
throws InternalException {
String task = UUID.randomUUID().toString();
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
ArgValidator.checkFieldNotNull(param.getShareName(), "name");
ArgValidator.checkFieldNotEmpty(param.getShareName(), "name");
Snapshot snap = queryResource(id);
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(), FileShare.class);
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
FileController controller = getController(FileController.class,
device.getSystemType());
ArgValidator.checkEntity(snap, id, isIdEmbeddedInURL(id));
// Let us make sure that a share with the same name does not already exist.
String shareName = param.getShareName();
if (CifsShareUtility.doesShareExist(snap, shareName)) {
_log.error("CIFS share: {}, already exists", shareName);
throw APIException.badRequests.duplicateEntityWithField("CIFS share", "name");
}
// If value of permission is not provided, set the value to read-only
if (param.getPermission() == null || param.getPermission().isEmpty()) {
param.setPermission(FileSMBShare.Permission.read.name());
}
if (!param.getPermission().equals(FileSMBShare.Permission.read.name())) {
throw APIException.badRequests.snapshotSMBSharePermissionReadOnly();
}
// Locate storage port for sharing snapshot
// Select IP port of the storage array, owning the parent file system, which belongs to the same varray as the
// file system.
// We use file system in the call since file snap belongs to the same neighbourhood as its parent 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(FileService.UNLIMITED_USERS)) {
param.setMaxUsers("-1");
}
String path = snap.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(param.getShareName(), 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 snapshot share --- Snap 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(Snapshot.class, snap.getId(), task,
ResourceOperationTypeEnum.CREATE_FILE_SNAPSHOT_SHARE);
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.share(device.getId(), snap.getId(), smbShare, task);
auditOp(OperationTypeEnum.CREATE_FILE_SNAPSHOT_SHARE, true, AuditLogManager.AUDITOP_BEGIN,
smbShare.getName(), smbShare.getPermissionType(), smbShare.getPermission(),
smbShare.getMaxUsers(), smbShare.getDescription(), snap.getId().toString());
return toTask(snap, task, op);
}
/**
* Deletes SMB share.
* <p>
* Note: This is an asynchronous operation.
*
* @param id
* the URN of a ViPR Snapshot
* @param shareName
* SMB share name
* @brief Delete file snapshot 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.ANY })
public TaskResourceRep deleteShare(@PathParam("id") URI id,
@PathParam("shareName") String shareName) throws InternalException {
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(), FileShare.class);
ArgValidator.checkFieldNotNull(shareName, "shareName");
ArgValidator.checkEntity(snap, id, isIdEmbeddedInURL(id));
String task = UUID.randomUUID().toString();
if (!CifsShareUtility.doesShareExist(snap, shareName)) {
_log.error("CIFS share does not exist", shareName);
throw APIException.notFound.invalidParameterObjectHasNoSuchShare(id, shareName);
}
SMBFileShare smbShare = snap.getSMBFileShares().get(shareName);
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snap.getId(),
task, ResourceOperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE);
FileSMBShare fileSMBShare = new FileSMBShare(shareName, smbShare.getDescription(),
smbShare.getPermissionType(), smbShare.getPermission(), Integer.toString(smbShare
.getMaxUsers()),
smbShare.getNativeId(), smbShare.getPath());
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.deleteShare(device.getId(), snap.getId(), fileSMBShare, task);
auditOp(OperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE, true, AuditLogManager.AUDITOP_BEGIN,
smbShare.getName(), smbShare.getPermissionType(), smbShare.getPermission(),
smbShare.getMaxUsers(), smbShare.getDescription(), snap.getId().toString());
return toTask(snap, task, op);
}
/**
* 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 updateSnapshotShareACL(@PathParam("id") URI id,
@PathParam("shareName") String shareName,
SnapshotCifsShareACLUpdateParams param) throws InternalException {
_log.info("Update snapshot share acl request received. Snapshot: {}, Share: {}",
id.toString(), shareName);
_log.info("Request body: {}", param.toString());
ArgValidator.checkFieldNotNull(shareName, "shareName");
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snapshot = queryResource(id);
ArgValidator.checkEntity(snapshot, id, isIdEmbeddedInURL(id));
if (!CifsShareUtility.doesShareExist(snapshot, shareName)) {
_log.error("CIFS share does not exist {}", shareName);
throw APIException.notFound.invalidParameterObjectHasNoSuchShare(snapshot.getId(), shareName);
}
FileShare fs = _permissionsHelper.getObjectById(snapshot.getParent(), FileShare.class);
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
CifsShareUtility.checkForUpdateShareACLOperationOnStorage(
device.getSystemType(), OperationTypeEnum.UPDATE_FILE_SNAPSHOT_SHARE_ACL.name());
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, null, snapshot, shareName);
util.verifyShareACLs(param);
_log.info("Request payload verified. No errors found.");
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snapshot.getId(),
task, ResourceOperationTypeEnum.UPDATE_FILE_SNAPSHOT_SHARE_ACL);
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.updateShareACLs(device.getId(), snapshot.getId(), shareName, param, task);
auditOp(OperationTypeEnum.UPDATE_FILE_SNAPSHOT_SHARE_ACL, true, AuditLogManager.AUDITOP_BEGIN,
snapshot.getId().toString(), device.getId().toString(), param);
return toTask(snapshot, 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 getSnapshotShareACLs(@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, Snapshot.class, "id");
ArgValidator.checkFieldNotNull(shareName, "shareName");
Snapshot snapshot = queryResource(id);
ArgValidator.checkEntity(snapshot, id, isIdEmbeddedInURL(id));
if (!CifsShareUtility.doesShareExist(snapshot, shareName)) {
_log.error("CIFS share does not exist {}", shareName);
throw APIException.notFound.invalidParameterObjectHasNoSuchShare(snapshot.getId(), shareName);
}
ShareACLs acls = new ShareACLs();
CifsShareUtility util = new CifsShareUtility(_dbClient, null, snapshot, 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 deleteSnapshotShareACL(@PathParam("id") URI id,
@PathParam("shareName") String shareName) {
// log input received.
_log.info("Delete ACL of share: Request received for {}, of file snapshot {}",
shareName, id);
String taskId = UUID.randomUUID().toString();
// Validate the snapshot id.
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
ArgValidator.checkFieldNotNull(shareName, "shareName");
Snapshot snapshot = queryResource(id);
ArgValidator.checkEntity(snapshot, id, isIdEmbeddedInURL(id));
if (!CifsShareUtility.doesShareExist(snapshot, shareName)) {
_log.error("CIFS share does not exist {}", shareName);
throw APIException.notFound.invalidParameterObjectHasNoSuchShare(snapshot.getId(), shareName);
}
FileShare fs = _permissionsHelper.getObjectById(snapshot.getParent(), FileShare.class);
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
CifsShareUtility.checkForUpdateShareACLOperationOnStorage(
device.getSystemType(), OperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE_ACL.name());
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snapshot.getId(),
taskId, ResourceOperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE_ACL);
op.setDescription("Delete ACL of Snapshot Cifs share");
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.deleteShareACLs(device.getId(), snapshot.getId(), shareName, taskId);
auditOp(OperationTypeEnum.DELETE_FILE_SNAPSHOT_SHARE_ACL,
true, AuditLogManager.AUDITOP_BEGIN,
snapshot.getId().toString(), device.getId().toString(), shareName);
return toTask(snapshot, taskId, op);
}
/**
* Call will restore this snapshot to the File system that it is associated with.
*
* @param id
* [required] - the URN of a ViPR file snapshot to restore from
* @brief Restore file snapshot
* @return TaskResourceRep - Task resource object for tracking this operation
* @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 })
@Path("/{id}/restore")
public TaskResourceRep restore(@PathParam("id") URI id)
throws InternalException {
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(), FileShare.class);
String task = UUID.randomUUID().toString();
Operation op = null;
if ((snap != null) && (!(snap.getInactive()))) {
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
StorageSystem.Type storageSystemType = StorageSystem.Type.valueOf(device.getSystemType());
if (storageSystemType.equals(DiscoveredDataObject.Type.isilon)) {
_log.error("Invalid Operation. Restore snapshot is not supported by ISILON");
throw APIException.badRequests.isilonSnapshotRestoreNotSupported();
}
_log.info(String.format(
"Snapshot restore --- Snapshot id: %1$s, FileShare: %2$s, task %3$s", id, fs.getId(), task));
_dbClient.createTaskOpStatus(FileShare.class, fs.getId(),
task, ResourceOperationTypeEnum.RESTORE_FILE_SNAPSHOT);
op = _dbClient.createTaskOpStatus(Snapshot.class, snap.getId(),
task, ResourceOperationTypeEnum.RESTORE_FILE_SNAPSHOT);
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.restoreFS(device.getId(), fs.getId(), snap.getId(), task);
auditOp(OperationTypeEnum.RESTORE_FILE_SNAPSHOT, true, AuditLogManager.AUDITOP_BEGIN,
snap.getId().toString(), fs.getId().toString());
} else {
StringBuilder msg = new StringBuilder("Attempt to use deleted snapshot: " + snap.getName());
msg.append(" to restore File: " + fs.getName());
op = new Operation();
ServiceCoded coded = ServiceError.buildServiceError(
ServiceCode.API_BAD_REQUEST, msg.toString());
op.error(coded);
op.setMessage(msg.toString());
op = _dbClient.createTaskOpStatus(Snapshot.class, snap.getId(), task, op);
_log.error(msg.toString());
}
return toTask(snap, task, op);
}
/**
* Deactivate filesystem snapshot, this will move the snapshot to a "marked-for-delete" state.
* This will be deleted by the garbage collector on a subsequent iteration
* <p>
* NOTE: This is an asynchronous operation.
*
* @param id
* the URN of a ViPR Snapshot
* @brief Delete file snapshot
* @return Task resource representation
* @throws InternalException
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/deactivate")
@CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.ANY })
public TaskResourceRep deleteSnapshot(@PathParam("id") URI id)
throws InternalException {
String task = UUID.randomUUID().toString();
_log.info(String.format(
"FileSnapshotDelete --- Snapshot id: %1$s, Task: %2$s", id,
task));
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
Operation op = null;
if (snap != null) {
ArgValidator.checkReference(Snapshot.class, id,
checkForDelete(snap));
if (snap.getInactive()) {
op = new Operation();
op.setResourceType(ResourceOperationTypeEnum.DELETE_FILE_SNAPSHOT);
op.ready();
_dbClient.createTaskOpStatus(Snapshot.class, snap.getId(), task, op);
} else {
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(),
FileShare.class);
if (null != fs) {
StorageSystem device = _dbClient.queryObject(
StorageSystem.class, fs.getStorageDevice());
op = _dbClient.createTaskOpStatus(Snapshot.class, snap
.getId(), task, ResourceOperationTypeEnum.DELETE_FILE_SNAPSHOT);
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.deleteSnapshot(device.getId(), null, snap.getId(),
false, FileControllerConstants.DeleteTypeEnum.FULL.toString(), task);
auditOp(OperationTypeEnum.DELETE_FILE_SNAPSHOT, true,
AuditLogManager.AUDITOP_BEGIN, snap.getId()
.toString(),
device.getId().toString());
}
}
}
return toTask(snap, task, op);
}
/*
* Generate export path
*
* @param fsName
*
* @param mountpath
*
* @param deviceType
*
* @return
*/
private String getExportPath(String snapshotName, String mountPath, String deviceType) {
String path = snapshotName;
if (deviceType.equals(DiscoveredDataObject.Type.isilon.toString())) {
path = mountPath;
}
return path;
}
/**
* Retrieve resource representations based on input ids.
*
* @param param
* POST data containing the id list.
* @brief List data of file snapshot resources
* @return list of representations.
*/
@POST
@Path("/bulk")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public FileSnapshotBulkRep getBulkResources(BulkIdParam param) {
return (FileSnapshotBulkRep) super.getBulkResources(param);
}
@SuppressWarnings("unchecked")
@Override
public Class<Snapshot> getResourceClass() {
return Snapshot.class;
}
/**
* Retrieve FileSnapshot representations based on input ids.
*
* @param ids
* the URN of a ViPR FileSnapshot list.
* @return list of FileSnapshot representations.
*
* @throws DatabaseException
* When an error occurs querying the database.
*/
@Override
public FileSnapshotBulkRep queryBulkResourceReps(List<URI> ids) {
Iterator<Snapshot> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids);
return new FileSnapshotBulkRep(BulkList.wrapping(_dbIterator, MapFileSnapshot.getInstance()));
}
@Override
protected BulkRestRep queryFilteredBulkResourceReps(
List<URI> ids) {
Iterator<Snapshot> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids);
ResourceFilter<Snapshot> filter = new FileSnapshotFilter(getUserFromContext(), _permissionsHelper);
return new FileSnapshotBulkRep(BulkList.wrapping(_dbIterator, MapFileSnapshot.getInstance(), filter));
}
private class FileSnapshotFilter extends PermissionsEnforcingResourceFilter<Snapshot> {
protected FileSnapshotFilter(StorageOSUser user,
PermissionsHelper permissionsHelper) {
super(user, permissionsHelper);
}
@Override
public boolean isAccessible(Snapshot resource) {
boolean ret = false;
ret = isTenantAccessible(getTenantOwner(resource.getId()));
if (!ret) {
NamedURI proj = resource.getProject();
if (proj != null) {
ret = isProjectAccessible(proj.getURI());
}
}
return ret;
}
}
/**
* File snapshot is not a zone level resource
*/
@Override
protected boolean isZoneLevelResource() {
return false;
}
@Override
protected ResourceTypeEnum getResourceType() {
return ResourceTypeEnum.FILE_SNAPSHOT;
}
/**
* 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.getSnapshotUnderProjectConstraint(
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.getProjectFileSnapshotConstraint(projectId),
resRepList);
return resRepList;
}
/**
* Get object specific permissions filter
*
*/
@Override
public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user,
PermissionsHelper permissionsHelper) {
return new ProjOwnedSnapResRepFilter(user, permissionsHelper, Snapshot.class);
}
/**
*
* 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
* @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 updateSnapshotExportRules(@PathParam("id") URI id,
SnapshotExportUpdateParams param) throws InternalException {
// log input received.
_log.info("Update Snapshot Export Rules : request received for {} with {}", id, param);
String task = UUID.randomUUID().toString();
// Validate the FS id.
ArgValidator.checkFieldUriType(id, Snapshot.class, "id");
Snapshot snap = queryResource(id);
ArgValidator.checkEntity(snap, id, true);
FileShare fs = _permissionsHelper.getObjectById(snap.getParent(), FileShare.class);
StorageSystem device = _dbClient.queryObject(StorageSystem.class, fs.getStorageDevice());
String path = snap.getPath();
_log.info("Snapshot Export path found {} ", path);
Operation op = _dbClient.createTaskOpStatus(Snapshot.class, snap.getId(), task,
ResourceOperationTypeEnum.UPDATE_EXPORT_RULES_FILE_SNAPSHOT);
try {
// Validate the input
ExportVerificationUtility exportVerificationUtility = new ExportVerificationUtility(_dbClient, getUserFromContext());
exportVerificationUtility.verifyExports(fs, snap, param);
_log.info("No Errors found proceeding further {}, {}, {}", new Object[] { _dbClient, fs, param });
FileServiceApi fileServiceApi = FileService.getFileShareServiceImpl(fs, _dbClient);
fileServiceApi.updateExportRules(device.getId(), snap.getId(), param, false, task);
auditOp(OperationTypeEnum.UPDATE_EXPORT_RULES_FILE_SNAPSHOT, true, AuditLogManager.AUDITOP_BEGIN,
fs.getId().toString(), device.getId().toString(), param);
} catch (URISyntaxException e) {
op.setStatus(Operation.Status.error.name());
_log.error("Error Processing Export Updates {}, {}", e.getMessage(), e);
return toTask(snap, task, op);
} catch (BadRequestException e) {
op = _dbClient.error(Snapshot.class, snap.getId(), task, e);
_log.error("Error Processing Export Updates {}, {}", e.getMessage(), e);
// throw e;
} catch (Exception e) {
op.setStatus(Operation.Status.error.name());
toTask(snap, task, op);
// _log.error("Error Processing Export Updates {}, {}", e.getMessage(), e);
throw APIException.badRequests.unableToProcessRequest(e.getMessage());
}
return toTask(snap, task, op);
}
}