/*
* Copyright (c) 2012-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.VirtualPoolMapper.toFileVirtualPool;
import java.net.URI;
import java.util.Iterator;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
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 javax.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.api.mapper.VirtualPoolMapper;
import com.emc.storageos.api.mapper.functions.MapFileVirtualPool;
import com.emc.storageos.api.service.impl.placement.VirtualPoolUtil;
import com.emc.storageos.api.service.impl.response.BulkList;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.FilePolicy;
import com.emc.storageos.db.client.model.FilePolicy.FilePolicyApplyLevel;
import com.emc.storageos.db.client.model.FilePolicy.FilePolicyType;
import com.emc.storageos.db.client.model.FileShare;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StringMap;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.StringSetMap;
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.VirtualPool.FileReplicationType;
import com.emc.storageos.db.client.model.VirtualPool.Type;
import com.emc.storageos.db.client.model.VpoolRemoteCopyProtectionSettings;
import com.emc.storageos.db.common.VdcUtil;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.model.BulkIdParam;
import com.emc.storageos.model.ResourceTypeEnum;
import com.emc.storageos.model.auth.ACLAssignmentChanges;
import com.emc.storageos.model.auth.ACLAssignments;
import com.emc.storageos.model.pools.StoragePoolList;
import com.emc.storageos.model.quota.QuotaInfo;
import com.emc.storageos.model.quota.QuotaUpdateParam;
import com.emc.storageos.model.vpool.CapacityResponse;
import com.emc.storageos.model.vpool.FileVirtualPoolBulkRep;
import com.emc.storageos.model.vpool.FileVirtualPoolParam;
import com.emc.storageos.model.vpool.FileVirtualPoolProtectionParam;
import com.emc.storageos.model.vpool.FileVirtualPoolProtectionUpdateParam;
import com.emc.storageos.model.vpool.FileVirtualPoolRestRep;
import com.emc.storageos.model.vpool.FileVirtualPoolUpdateParam;
import com.emc.storageos.model.vpool.VirtualPoolList;
import com.emc.storageos.model.vpool.VirtualPoolPoolUpdateParam;
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.security.geo.GeoServiceClient;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.volumecontroller.AttributeMatcher;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitUnManagedObjectsMatcher;
import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper;
import com.google.common.base.Function;
@Path("/file/vpools")
@DefaultPermissions(readRoles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, readAcls = { ACL.USE }, writeRoles = { Role.SYSTEM_ADMIN,
Role.RESTRICTED_SYSTEM_ADMIN })
public class FileVirtualPoolService extends VirtualPoolService {
private static final Logger _log = LoggerFactory.getLogger(FileVirtualPoolService.class);
private static final Long MINUTES_PER_HOUR = 60L;
private static final Long HOURS_PER_DAY = 24L;
/**
* Create File Store VirtualPool
*
* @param param VirtualPool parameters
* @brief Create VirtualPool for a file store
* @return VirtualPool details
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public FileVirtualPoolRestRep createFileVirtualPool(FileVirtualPoolParam param) {
ArgValidator.checkFieldNotEmpty(param.getName(), VPOOL_NAME);
checkForDuplicateName(param.getName(), VirtualPool.class);
ArgValidator.checkFieldNotEmpty(param.getDescription(), VPOOL_DESCRIPTION);
VirtualPoolUtil.validateFileVirtualPoolCreateParams(param, _dbClient);
VirtualPool cos = prepareVirtualPool(param, true);
if (null != param.getLongTermRetention()) {
cos.setLongTermRetention(param.getLongTermRetention());
}
StringBuffer errorMessage = new StringBuffer();
// update the implicit pools matching with this VirtualPool.
ImplicitPoolMatcher.matchVirtualPoolWithAllStoragePools(cos, _dbClient, _coordinator, errorMessage);
if (null != cos.getMatchedStoragePools() || null != cos.getInvalidMatchedPools()) {
ImplicitUnManagedObjectsMatcher.matchVirtualPoolsWithUnManagedFileSystems(cos,
_dbClient);
}
_dbClient.createObject(cos);
recordOperation(OperationTypeEnum.CREATE_VPOOL, VPOOL_CREATED_DESCRIPTION, cos);
return toFileVirtualPool(cos);
}
/**
* List VirtualPool for File Store
*
* @brief List classes of service for a file store
* @return Returns the VirtualPool user is authorized to see
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public VirtualPoolList listFileVirtualPool(
@DefaultValue("") @QueryParam(TENANT_ID_QUERY_PARAM) String tenantId,
@DefaultValue("") @QueryParam(VDC_ID_QUERY_PARAM) String shortVdcId) {
_geoHelper.verifyVdcId(shortVdcId);
return getVirtualPoolList(VirtualPool.Type.file, shortVdcId, tenantId);
}
/**
* Get info for File Store VirtualPool
*
* @param id the URN of a ViPR VirtualPool
* @brief Show file store VirtualPool
* @return VirtualPool details
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public FileVirtualPoolRestRep getFileVirtualPool(@PathParam("id") URI id) {
VirtualPool vpool = getVirtualPool(VirtualPool.Type.file, id);
FileVirtualPoolRestRep restRep = toFileVirtualPool(vpool);
restRep.setNumResources(getNumResources(vpool, _dbClient));
return restRep;
}
/**
* Deactivate File Store VirtualPool, this will move the Cos to a "marked-for-deletion" state,
* and no more resource may be created using it.
* The VirtualPool will be deleted when all references to this VirtualPool of type FileShare are deleted
*
* @param id the URN of a ViPR VirtualPool
* @brief Delete file store VirtualPool
* @return VirtualPool details
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/deactivate")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public Response deleteFileVirtualPool(@PathParam("id") URI id) {
return deleteVirtualPool(VirtualPool.Type.file, id);
}
/**
* Return the matching pools for a given set of VirtualPool attributes.
* This API is useful for user to find the matching pools before creating a VirtualPool.
*
* @param param : VirtualPoolAttributeParam
* @brief List pools matching specified properties in file store VirtualPool
* @return : matching pools.
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/matching-pools")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public StoragePoolList getMatchingPoolsForVirtualPoolAttributes(FileVirtualPoolParam param) {
StoragePoolList poolList = new StoragePoolList();
VirtualPool vpool = prepareVirtualPool(param, false);
List<URI> poolURIs = _dbClient.queryByType(StoragePool.class, true);
List<StoragePool> allPools = _dbClient.queryObject(StoragePool.class, poolURIs);
StringBuffer errorMessage = new StringBuffer();
List<StoragePool> matchedPools = ImplicitPoolMatcher.getMatchedPoolWithStoragePools(vpool,
allPools,
null,
null,
null,
_dbClient,
_coordinator, AttributeMatcher.VPOOL_MATCHERS, errorMessage);
for (StoragePool pool : matchedPools) {
poolList.getPools().add(toNamedRelatedResource(pool, pool.getNativeGuid()));
}
return poolList;
}
/**
* Get File Store VirtualPool ACL
*
* @param id the URN of a ViPR VirtualPool
* @brief Show ACL entries for file store VirtualPool
* @return ACL Assignment details
*/
@GET
@Path("/{id}/acl")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public ACLAssignments getAcls(@PathParam("id") URI id) {
return getAclsOnVirtualPool(VirtualPool.Type.file, id);
}
/**
* Add or remove individual File Store VirtualPool ACL entry(s). Request body must include at least one add or remove operation.
*
* @param id the URN of a ViPR VirtualPool
* @param changes ACL assignment changes
* @brief Add or remove ACL entries from file store VirtualPool
* @return No data returned in response body
*/
@PUT
@Path("/{id}/acl")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN, Role.RESTRICTED_SECURITY_ADMIN }, blockProxies = true)
public ACLAssignments updateAcls(@PathParam("id") URI id,
ACLAssignmentChanges changes) {
return updateAclsOnVirtualPool(VirtualPool.Type.file, id, changes);
}
/**
* Returns list of computed id's for all storage pools matching with the VirtualPool.
* This list of pools will be used to do create Fileshares.
*
* @param id the URN of a ViPR VirtualPool.
*
* @brief List storage pools in file store VirtualPool
* @return The ids for all storage pools that satisfy the VirtualPool.
*/
@GET
@Path("/{id}/storage-pools")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StoragePoolList getStoragePools(@PathParam("id") URI id) {
return getStoragePoolsForVirtualPool(id);
}
/**
* This method re-computes the matched pools for this VirtualPool and returns this information.
*
* Where as getStoragePools {id}/storage-pools returns whatever is already computed, for matched pools.
*
* @param id : the URN of a ViPR Block VirtualPool.
* @brief Refresh list of storage pools in file store VirtualPool
* @return : List of Pool Ids matching with this VirtualPool.
*/
@GET
@Path("/{id}/refresh-matched-pools")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public StoragePoolList refreshMatchedStoragePools(@PathParam("id") URI id) {
return refreshMatchedPools(VirtualPool.Type.file, id);
}
/**
* Update File VirtualPool only allows if there are no resources associated and
* list of attributes changed not changed.
*
* List of attributes can updated if it satisfies above constraint:
* assignedStoragePools & useMatchedStoragePools flag.
*
* @param param
* VirtualPool parameters
* @brief Update description of file store VirtualPool
* @return VirtualPool details
*/
@PUT
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public FileVirtualPoolRestRep updateFileVirtualPool(@PathParam("id") URI id, FileVirtualPoolUpdateParam param) {
VirtualPool cos = null;
ArgValidator.checkFieldUriType(id, VirtualPool.class, "id");
cos = _dbClient.queryObject(VirtualPool.class, id);
ArgValidator.checkEntity(cos, id, isIdEmbeddedInURL(id));
if (!cos.getType().equals(VirtualPool.Type.file.name())) {
throw APIException.badRequests.unexpectedValueForProperty("VPool type", VirtualPool.Type.file.name(), cos.getType());
}
VirtualPoolUtil.validateFileVirtualPoolUpdateParams(cos, param, _dbClient);
URIQueryResultList resultList = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getVirtualPoolFileshareConstraint(id), resultList);
for (Iterator<URI> fileShareItr = resultList.iterator(); fileShareItr.hasNext();) {
FileShare fileShare = _dbClient.queryObject(FileShare.class, fileShareItr.next());
if (!fileShare.getInactive() && checkAttributeValuesChanged(param, cos)) {
throw APIException.badRequests.vPoolUpdateNotAllowed("FileShares");
}
}
if (param.getProtection() != null && checkProtectionChanged(cos, param.getProtection())) {
// need to iterate over all the policy and see if policy is associated with vpool .
// if policy is associated with vpool we can not modify the protection attribute
List<URI> filePolicyList = _dbClient.queryByType(FilePolicy.class, true);
for (URI filePolicy : filePolicyList) {
FilePolicy policyObj = _dbClient.queryObject(FilePolicy.class, filePolicy);
if (policyObj.getAssignedResources() != null) {
if(policyObj.getApplyAt().equalsIgnoreCase(FilePolicyApplyLevel.project.name()) && (policyObj.getFilePolicyVpool() != null)){
if (policyObj.getFilePolicyVpool().toString().equalsIgnoreCase(id.toString())) {
checkProtectAttributeAginstPolicy(param.getProtection(), policyObj);
}
} else if (policyObj.getApplyAt().equalsIgnoreCase(FilePolicyApplyLevel.vpool.name())) {
StringSet assignedResources = policyObj.getAssignedResources();
if (assignedResources.contains(id.toString())) {
checkProtectAttributeAginstPolicy(param.getProtection(), policyObj);
}
}
}
}
}
// set common update VirtualPool Params here.
populateCommonVirtualPoolUpdateParams(cos, param);
if (null != param.getSystemType()) {
if (cos.getArrayInfo() != null && cos.getArrayInfo().containsKey(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE)) {
for (String systemType : cos.getArrayInfo().get(
VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE)) {
cos.getArrayInfo().remove(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE,
systemType);
}
}
if (!(VirtualPool.SystemType.NONE.name().equalsIgnoreCase(param.getSystemType())
|| VirtualPool.SystemType.isFileTypeSystem(param.getSystemType()))) {
throw APIException.badRequests.invalidSystemType("File");
}
if (cos.getArrayInfo() == null) {
cos.setArrayInfo(new StringSetMap());
}
cos.getArrayInfo().put(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE, param.getSystemType());
}
// Update file protection parameters!!!
if (null != param.getProtection()) {
updateFileProtectionParamsForVirtualPool(cos, param.getProtection());
}
if (null != param.getLongTermRetention()) {
cos.setLongTermRetention(param.getLongTermRetention());
}
StringBuffer errorMessage = new StringBuffer();
// invokes implicit pool matching algorithm.
ImplicitPoolMatcher.matchVirtualPoolWithAllStoragePools(cos, _dbClient, _coordinator, errorMessage);
// adding supported coses to unmanaged volumes
if (null != cos.getMatchedStoragePools() || null != cos.getInvalidMatchedPools()) {
ImplicitUnManagedObjectsMatcher.matchVirtualPoolsWithUnManagedFileSystems(cos,
_dbClient);
}
_dbClient.updateObject(cos);
recordOperation(OperationTypeEnum.UPDATE_VPOOL, VPOOL_UPDATED_DESCRIPTION, cos);
return toFileVirtualPool(cos);
}
/**
* Update File VirtualPool only allows user to assign matching storage pools.
*
* @param param
* VirtualPool parameters
* @brief Update storage pools in file store VirtualPool
* @return VirtualPool details
*/
@PUT
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/assign-matched-pools")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public FileVirtualPoolRestRep updateFileVirtualPoolWithAssignedPools(@PathParam("id") URI id,
VirtualPoolPoolUpdateParam param) {
VirtualPool vPool = updateVirtualPoolWithAssignedStoragePools(id, param);
return toFileVirtualPool(vPool);
}
/**
* Gets storage capacity information for specified VirtualPool and Neighborhood instances.
*
* The method returns set of metrics for capacity available for file storage provisioning:
* - usable_gb : total storage capacity
* - free_gb : free storage capacity
* - used_gb : used storage capacity
* - percent_used : percent of usable capacity which is used
*
* @param id the URN of a ViPR VirtualPool.
* @param varrayId The id of varray.
* @brief Show storage capacity for a VirtualPool and varray
* @return Capacity metrics in GB and percent indicator for used capacity.
*/
@GET
@Path("/{id}/varrays/{varrayId}/capacity")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public CapacityResponse getCapacity(@PathParam("id") URI id,
@PathParam("varrayId") URI varrayId) {
return getCapacityForVirtualPoolAndVirtualArray(getVirtualPool(Type.file, id), varrayId);
}
@Override
protected URI getTenantOwner(URI id) {
return null;
}
@Override
protected Type getVirtualPoolType() {
return Type.file;
}
/**
* @brief List all instances of File VirtualPools
*
*/
@POST
@Path("/bulk")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public FileVirtualPoolBulkRep getBulkResources(BulkIdParam param) {
return (FileVirtualPoolBulkRep) super.getBulkResources(param);
}
/**
*
* @param id the URN of a ViPR VirtualPool.
* @brief Show quota and available capacity before quota is exhausted
* @return QuotaInfo Quota metrics.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN })
@Path("/{id}/quota")
public QuotaInfo getQuota(@PathParam("id") URI id) throws DatabaseException {
return getQuota(getVirtualPool(Type.file, id));
}
/**
*
* @param id the URN of a ViPR VirtualPool.
* @param param new values for the quota
* @brief Updates quota and available capacity before quota is exhausted
* @return QuotaInfo Quota metrics.
*/
@PUT
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
@Path("/{id}/quota")
public QuotaInfo updateQuota(@PathParam("id") URI id,
QuotaUpdateParam param) throws DatabaseException {
return updateQuota(getVirtualPool(Type.file, id), param);
}
private class mapFileVirtualPoolWithResources implements Function<VirtualPool, FileVirtualPoolRestRep> {
@Override
public FileVirtualPoolRestRep apply(VirtualPool vpool) {
FileVirtualPoolRestRep to = VirtualPoolMapper.toFileVirtualPool(vpool);
to.setNumResources(getNumResources(vpool, _dbClient));
return to;
}
}
@Override
public FileVirtualPoolBulkRep queryBulkResourceReps(List<URI> ids) {
if (!ids.iterator().hasNext()) {
return new FileVirtualPoolBulkRep();
}
// get vdc id from the first id; assume all id's are from the same vdc
String shortVdcId = VdcUtil.getVdcId(VirtualArray.class, ids.iterator().next()).toString();
Iterator<VirtualPool> dbIterator;
if (shortVdcId.equals(VdcUtil.getLocalShortVdcId())) {
dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids);
} else {
GeoServiceClient geoClient = _geoHelper.getClient(shortVdcId);
try {
dbIterator = geoClient.queryObjects(getResourceClass(), ids);
} catch (Exception ex) {
// TODO: revisit this exception
_log.error("error retrieving bulk virtual pools from vdc " + shortVdcId, ex);
throw APIException.internalServerErrors.genericApisvcError("error retrieving remote virtual pool", ex);
}
}
return new FileVirtualPoolBulkRep(BulkList.wrapping(dbIterator, new mapFileVirtualPoolWithResources(),
new BulkList.VirtualPoolFilter(Type.file)));
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected FileVirtualPoolBulkRep queryFilteredBulkResourceReps(
List<URI> ids) {
if (isSystemOrRestrictedSystemAdmin()) {
return queryBulkResourceReps(ids);
}
if (!ids.iterator().hasNext()) {
return new FileVirtualPoolBulkRep();
}
// get vdc id from the first id; assume all id's are from the same vdc
String shortVdcId = VdcUtil.getVdcId(VirtualArray.class, ids.iterator().next()).toString();
Iterator<VirtualPool> dbIterator;
if (shortVdcId.equals(VdcUtil.getLocalShortVdcId())) {
dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids);
} else {
GeoServiceClient geoClient = _geoHelper.getClient(shortVdcId);
try {
dbIterator = geoClient.queryObjects(getResourceClass(), ids);
} catch (Exception ex) {
// TODO: revisit this exception
_log.error("error retrieving bulk virtual pools from vdc " + shortVdcId, ex);
throw APIException.internalServerErrors.genericApisvcError("error retrieving remote virtual pool", ex);
}
}
BulkList.ResourceFilter filter = new BulkList.VirtualPoolFilter(Type.file, getUserFromContext(), _permissionsHelper);
return new FileVirtualPoolBulkRep(BulkList.wrapping(dbIterator, MapFileVirtualPool.getInstance(), filter));
}
@Override
protected ResourceTypeEnum getResourceType() {
return ResourceTypeEnum.FILE_VPOOL;
}
static Integer getNumResources(VirtualPool vpool, DbClient dbClient) {
return dbClient.countObjects(FileShare.class, "virtualPool", vpool.getId());
}
// this method must not persist anything to the DB.
private VirtualPool prepareVirtualPool(FileVirtualPoolParam param, boolean validateReplArgs) {
VirtualPool vPool = new VirtualPool();
vPool.setType(VirtualPool.Type.file.name());
// set common VirtualPool parameters.
populateCommonVirtualPoolCreateParams(vPool, param);
StringSetMap arrayInfo = new StringSetMap();
if (null != param.getSystemType()) {
if (!VirtualPool.SystemType.NONE.toString().equals(param.getSystemType())
&& !VirtualPool.SystemType.isFileTypeSystem(param.getSystemType())) {
throw APIException.badRequests.invalidParameter("system_type", param.getSystemType());
}
arrayInfo.put(VirtualPoolCapabilityValuesWrapper.SYSTEM_TYPE, param.getSystemType());
vPool.addArrayInfoDetails(arrayInfo);
}
vPool.setMaxNativeSnapshots(VirtualPool.MAX_DISABLED);
if (null != param.getProtection()) {
FileVirtualPoolProtectionParam protectionParam = param.getProtection();
if ((protectionParam.getSnapshots() != null)
&& (protectionParam.getSnapshots().getMaxSnapshots() != null)) {
vPool.setMaxNativeSnapshots(protectionParam.getSnapshots().getMaxSnapshots());
}
vPool.setScheduleSnapshots(false);
if (protectionParam.getScheduleSnapshots() != null) {
vPool.setScheduleSnapshots(protectionParam.getScheduleSnapshots());
}
vPool.setFileReplicationSupported(false);
if (protectionParam.getReplicationSupported() != null) {
vPool.setFileReplicationSupported(protectionParam.getReplicationSupported());
}
vPool.setAllowFilePolicyAtProjectLevel(false);
if (protectionParam.getAllowFilePolicyAtProjectLevel() != null) {
vPool.setAllowFilePolicyAtProjectLevel(protectionParam.getAllowFilePolicyAtProjectLevel());
}
vPool.setAllowFilePolicyAtFSLevel(false);
if (protectionParam.getAllowFilePolicyAtFSLevel() != null) {
vPool.setAllowFilePolicyAtFSLevel(protectionParam.getAllowFilePolicyAtFSLevel());
}
}
if (null != param.getLongTermRetention()) {
vPool.setLongTermRetention(param.getLongTermRetention());
}
return vPool;
}
/**
*
* Check if any VirtualPool attribute values (including long term retention) have changed.
*
* @param param
* @param vpool : VirtualPool in DB.
* @return : flag to check whether to update VirtualPool or not.
*/
private boolean checkAttributeValuesChanged(FileVirtualPoolUpdateParam param, VirtualPool vpool) {
return super.checkAttributeValuesChanged(param, vpool)
|| checkLongTermRetentionChanged(param.getLongTermRetention(), vpool.getLongTermRetention()
|| checkProtectionChanged(vpool, param.getProtection()));
}
/**
* If vpool is associated with policy then the respective vpool attribute can not be modified.
*
* @param protectParam
* @param policyObj
*/
private void checkProtectAttributeAginstPolicy(FileVirtualPoolProtectionUpdateParam protectParam, FilePolicy policyObj) {
// now check the policy attribute against modified vpool attribute.
if (!protectParam.getReplicationSupported()
&& policyObj.getFilePolicyType().equalsIgnoreCase(FilePolicyType.file_replication.name())) {
throw APIException.badRequests.vPoolUpdateNotAllowed("FileReplication");
} else if (!protectParam.getScheduleSnapshots()
&& policyObj.getFilePolicyType().equalsIgnoreCase(FilePolicyType.file_snapshot.name())) {
throw APIException.badRequests.vPoolUpdateNotAllowed("ScheduleSnapshot");
} else if (!protectParam.getAllowFilePolicyAtProjectLevel()
&& policyObj.getApplyAt().equalsIgnoreCase(FilePolicyApplyLevel.project.name())) {
throw APIException.badRequests.vPoolUpdateNotAllowed("FilePolicyAtProjectLevel");
} else if (!protectParam.getAllowFilePolicyAtFSLevel()
&& policyObj.getApplyAt().equalsIgnoreCase(FilePolicyApplyLevel.file_system.name())) {
throw APIException.badRequests.vPoolUpdateNotAllowed("FilePolicyAtFSLevel");
}
}
/**
* check for any change in LongTermRetention
*
* @param paramValue
* @param vpoolValue
*/
private boolean checkLongTermRetentionChanged(Boolean paramValue, Boolean vpoolValue) {
boolean isModified = false;
if (null != vpoolValue) {
if (paramValue == null) {
isModified = false;
} else if (paramValue != vpoolValue) {
isModified = true;
}
} else {
if (null != paramValue) {
isModified = true;
}
}
return isModified;
}
/**
* Check whether the file replication attributes have changed.
*
* @param from the source virtual pool without updates
* @param to the updated virtual pool
* @return true if the virtual pool has changed, false otherwise
*/
public static boolean checkProtectionChanged(VirtualPool from, FileVirtualPoolProtectionUpdateParam to) {
// If the update object is null there are no updates
if (to == null) {
_log.info("No virtual pool replication settings changes have been made");
return false;
}
// Check the protection parameters changed!!!
if (to.getScheduleSnapshots() != from.getScheduleSnapshots()
|| to.getReplicationSupported() != from.getFileReplicationSupported()
|| to.getAllowFilePolicyAtProjectLevel() != from.getAllowFilePolicyAtProjectLevel()
|| to.getAllowFilePolicyAtFSLevel() != from.getAllowFilePolicyAtFSLevel()) {
_log.info("Protection parameters cannot be modified to a vpool with provisioned filessystems ",
from.getId());
return true;
}
// Check the RPO/Type changed!!!
if (to.getMinRpoType() != from.getFrRpoType() || to.getMinRpoValue() != from.getFrRpoValue()) {
_log.info("RPO parameters cannot be modified to a vpool with provisioned filessystems ",
from.getId());
return true;
}
_log.info("No protection changes");
return false;
}
/**
* Performs the protection updates on VirtualPool.
*
* @param virtualPool Reference to the virtual pool to update.
* @param param The updates that need to be applied to the virtual pool.
*/
private void updateFileProtectionParamsForVirtualPool(VirtualPool virtualPool,
FileVirtualPoolProtectionUpdateParam param) {
// If the update specifies replication protection, we need to process the update.
if (param != null) {
if (param.getScheduleSnapshots() != null) {
virtualPool.setScheduleSnapshots(param.getScheduleSnapshots());
}
// Handle the protection snapshot updates
if (param.getSnapshots() != null) {
// By default the maxSnapshots value should be 0 so this should never be null
// but good to have just in case...
if (param.getSnapshots().getMaxSnapshots() != null) {
// Keep in mind that if an empty or 0 value is specified snapshots
// will be removed from the virtual pool.
virtualPool.setMaxNativeSnapshots(param.getSnapshots().getMaxSnapshots());
} else {
// Remove snapshots by setting the disabled value
virtualPool.setMaxNativeSnapshots(VirtualPool.MAX_DISABLED);
}
}
if (param.getReplicationSupported() != null) {
virtualPool.setFileReplicationSupported(param.getReplicationSupported());
}
if (param.getAllowFilePolicyAtProjectLevel() != null) {
virtualPool.setAllowFilePolicyAtProjectLevel(param.getAllowFilePolicyAtProjectLevel());
}
if (param.getAllowFilePolicyAtFSLevel() != null) {
virtualPool.setAllowFilePolicyAtFSLevel(param.getAllowFilePolicyAtFSLevel());
}
}
}
private void deleteRemoteCopies(VirtualPool virtualPool,
FileVirtualPoolProtectionUpdateParam param) {
// Remove all remote copy setttings, if any!!!
StringMap remoteCopySettingsMap = virtualPool.getFileRemoteCopySettings();
if (remoteCopySettingsMap != null && !remoteCopySettingsMap.isEmpty()) {
for (String varray : remoteCopySettingsMap.keySet()) {
String remoteCopySettingsUri = remoteCopySettingsMap.get(varray);
remoteCopySettingsMap.remove(varray);
VpoolRemoteCopyProtectionSettings remoteSettingsObj = _dbClient.queryObject(
VpoolRemoteCopyProtectionSettings.class, URI.create(remoteCopySettingsUri));
remoteSettingsObj.setInactive(true);
_dbClient.updateObject(remoteSettingsObj);
}
}
}
private void deleteReplicationParams(VirtualPool virtualPool,
FileVirtualPoolProtectionUpdateParam param) {
// Remove replication settings from virtual pool
// 1. Reset the policy settings
// 2. Reset the remote copies!!!
virtualPool.setFrRpoType(null);
virtualPool.setFrRpoValue(null);
virtualPool.setFileReplicationType(FileReplicationType.NONE.name());
// Clear the remote copies!!
deleteRemoteCopies(virtualPool, param);
_log.info("File Replication setting removed from virtual pool {} ", virtualPool.getLabel());
}
private boolean validateReplicationRpoParams(Long rpoValue, String rpoType) {
if (rpoValue != null || rpoType != null) {
if (rpoType == null
|| FileReplicationRPOType.lookup(rpoType) == null) {
throw APIException.badRequests.invalidReplicationRPOType(rpoType);
}
if (rpoValue == null || rpoValue <= 0) {
throw APIException.badRequests.invalidReplicationRPOValue();
}
switch (rpoType.toUpperCase()) {
case "MINUTES":
if (rpoValue > MINUTES_PER_HOUR) {
throw APIException.badRequests.invalidReplicationRPOValueForType(
rpoValue.toString(), rpoType);
}
break;
case "HOURS":
if (rpoValue > HOURS_PER_DAY) {
throw APIException.badRequests.invalidReplicationRPOValueForType(
rpoValue.toString(), rpoType);
}
break;
case "DAYS":
// No validation required for Days.
break;
default:
throw APIException.badRequests.invalidReplicationRPOType(rpoType);
}
return true;
}
return false;
}
}