/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource; import static com.emc.storageos.api.mapper.BlockMapper.toVirtualPoolResource; import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource; import static com.emc.storageos.api.mapper.DbObjectMapper.toTypedRelatedResource; import static com.emc.storageos.api.mapper.SystemsMapper.map; import static com.emc.storageos.api.mapper.TaskMapper.toTask; import java.math.BigInteger; import java.net.URI; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import javax.ws.rs.Consumes; 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.core.MediaType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.api.service.impl.resource.utils.CapacityUtils; import com.emc.storageos.api.service.impl.resource.utils.PurgeRunnable; import com.emc.storageos.api.service.impl.response.BulkList; import com.emc.storageos.coordinator.client.service.CoordinatorClient; 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.DiscoveredDataObject.DiscoveryStatus; import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageTier; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.db.client.model.Volume; 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.ResourceOperationTypeEnum; import com.emc.storageos.model.ResourceTypeEnum; import com.emc.storageos.model.TaskResourceRep; import com.emc.storageos.model.TypedRelatedResourceRep; import com.emc.storageos.model.block.tier.StorageTierList; import com.emc.storageos.model.pools.StoragePoolBulkRep; import com.emc.storageos.model.pools.StoragePoolList; import com.emc.storageos.model.pools.StoragePoolResources; import com.emc.storageos.model.pools.StoragePoolRestRep; import com.emc.storageos.model.pools.StoragePoolUpdate; import com.emc.storageos.model.pools.VirtualArrayAssignments; import com.emc.storageos.model.vpool.VirtualPoolList; 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.resources.APIException; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableBourneEvent; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager; import com.emc.storageos.volumecontroller.impl.monitoring.cim.enums.RecordType; import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher; import com.google.common.base.Function; /** * StoragePool resource implementation */ @Path("/vdc/storage-pools") @DefaultPermissions(readRoles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, writeRoles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public class StoragePoolService extends TaggedResource { private Logger _logger = LoggerFactory.getLogger(StoragePoolService.class); private static final String EVENT_SERVICE_TYPE = "StoragePool"; protected static final String EVENT_SERVICE_SOURCE = "StoragePoolService"; protected static final String STORAGEPOOL_UPDATED_DESCRIPTION = "Storage pool Updated"; protected static final String STORAGEPOOL_DEREGISTERED_DESCRIPTION = "Storage Pool Unregistered"; @Autowired private RecordableEventManager _evtMgr; @Override public String getServiceType() { return EVENT_SERVICE_TYPE; } // how many times to retry a procedure before returning failure to the user. // Is used with "system delete" operation. private int _retry_attempts; private static final Logger _log = LoggerFactory.getLogger(StoragePoolService.class); @Override protected URI getTenantOwner(URI id) { return null; } public void setRetryAttempts(int retries) { _retry_attempts = retries; } /** * Gets the storage pool with the passed id from the database. * * @param id the URN of a ViPR storage pool. * * @return A reference to the registered StoragePool. * * @throws BadRequestException When the storage pool is not registered. */ protected StoragePool queryRegisteredResource(URI id) { ArgValidator.checkUri(id); StoragePool pool = _dbClient.queryObject(StoragePool.class, id); ArgValidator.checkEntityNotNull(pool, id, isIdEmbeddedInURL(id)); if (!RegistrationStatus.REGISTERED.toString().equalsIgnoreCase( pool.getRegistrationStatus())) { throw APIException.badRequests.resourceNotRegistered(StoragePool.class.getSimpleName(), id); } return pool; } @Override protected StoragePool queryResource(URI id) { ArgValidator.checkUri(id); StoragePool pool = _dbClient.queryObject(StoragePool.class, id); ArgValidator.checkEntity(pool, id, isIdEmbeddedInURL(id)); return pool; } /** * Gets the ids and self links for all storage pools. * * @brief List storage pools * @return A StoragePoolList reference specifying the ids and self links for * the storage pools. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }) public StoragePoolList getStoragePools() { StoragePoolList storagePools = new StoragePoolList(); List<URI> ids = _dbClient.queryByType(StoragePool.class, true); for (URI id : ids) { StoragePool storagePool = _dbClient.queryObject(StoragePool.class, id); if (storagePool != null) { storagePools.getPools().add(toNamedRelatedResource(storagePool, storagePool.getNativeGuid())); } } return storagePools; } /** * Gets the ids and self links for all matched VirtualPools for a given storage pool. * * @brief List matching VirtualPools for specified storage pool * @return A VirtualPoolList reference specifying the ids and self links for * the matched VirtualPool. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/matched-vpools") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }) public VirtualPoolList getMatchedVirtualPoolForPool(@PathParam("id") URI id) { VirtualPoolList vpools = new VirtualPoolList(); ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); StoragePool storagePool = queryRegisteredResource(id); ArgValidator.checkEntity(storagePool, id, isIdEmbeddedInURL(id)); URIQueryResultList cosResultList = new URIQueryResultList(); _dbClient.queryByConstraint(ContainmentConstraint.Factory .getMatchedPoolVirtualPoolConstraint(id), cosResultList); Iterator<URI> cosListItr = cosResultList.iterator(); while (cosListItr.hasNext()) { VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, cosListItr.next()); vpools.getVirtualPool().add(toVirtualPoolResource(vpool)); } return vpools; } /** * Gets the data for a storage pool. * * @param id the URN of a ViPR storage pool. * * @brief Show storage pool * @return A StoragePoolRestRep reference specifying the data for the * storage pool with the passed id. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }) public StoragePoolRestRep getStoragePool(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); StoragePool storagePool = queryResource(id); ArgValidator.checkEntity(storagePool, id, isIdEmbeddedInURL(id)); StoragePoolRestRep restRep = toStoragePoolRep(storagePool, _dbClient, _coordinator); restRep.setNumResources(getNumResources(storagePool, _dbClient)); return restRep; } /** * Get Storage tiers associated with given Pool * Vmax pools, only one tier will be present always * Vnx pools can have multiple tiers. * * @param id the URN of a ViPR storage pool. * * @brief List storage pool storage tiers * @return A StorageTierList reference specifying the data for the * storage tier with the passed id. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/storage-tiers") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }) public StorageTierList getStorageTiers(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); StoragePool storagePool = queryRegisteredResource(id); ArgValidator.checkEntity(storagePool, id, isIdEmbeddedInURL(id)); if (storagePool.getTiers() == null) { throw APIException.badRequests.invalidParameterStoragePoolHasNoTiers(id); } StorageTierList storageTierList = new StorageTierList(); for (String tierUri : storagePool.getTiers()) { StorageTier tier = _dbClient.queryObject(StorageTier.class, URI.create(tierUri)); if (null != tier) { storageTierList.getStorageTiers().add(toNamedRelatedResource(tier, tier.getNativeGuid())); } } return storageTierList; } /** * Allows the user to deregister a registered storage pool so that it is no * longer used by the system. This simply sets the registration_status of * the storage pool to UNREGISTERED. * * @param id the URN of a ViPR storage pool to deregister. * * @brief Unregister storage pool * @return Status indicating success or failure. */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/deregister") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public StoragePoolRestRep deregisterStoragePool(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); StoragePool pool = queryResource(id); StringBuffer errorMessage = new StringBuffer(); if (RegistrationStatus.REGISTERED.toString().equalsIgnoreCase( pool.getRegistrationStatus())) { pool.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString()); // run implicit pool matcher algorithm to update the matched pools in VirtualPool. if (null == pool.getConnectedVirtualArrays() || pool.getConnectedVirtualArrays().isEmpty()) { ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(Arrays.asList(pool), _dbClient, _coordinator,errorMessage); } _dbClient.persistObject(pool); // Record the storage pool deregister event. recordStoragePoolEvent(OperationTypeEnum.STORAGE_POOL_DEREGISTER, STORAGEPOOL_DEREGISTERED_DESCRIPTION, pool.getId()); auditOp(OperationTypeEnum.DEREGISTER_STORAGE_POOL, true, null, id.toString()); } return toStoragePoolRep(pool, _dbClient, _coordinator); } /** * This API call only allows user to update virtual array & virtual pool * assignments for the registered storage pool. * <p> * A pool can be associated with a virtual array either implicitly or explicitly. A pool is implicitly associated with a virtual array * when the pool's storage system has one or more ports in the virtual array (see {@link StoragePool#getConnectedVirtualArrays()}). the * pool's implicit virtual arrays are the union of all the tagged virtual arrays of the storage array ports. This implicit association * cannot be changed or removed, it can only be overridden by an explicit assignment (see {@link StoragePool#getAssignedVirtualArrays()} * ). A pool's effective virtual array association is {@link StoragePool#getTaggedVirtualArrays()}) * <p> * Managing pools associated virtual arrays requires planning. In general, pools should be assigned to virtual arrays only when it is * desired to limit the virtual arrays where they can be used. * * @param id the URN of a ViPR storage pool. * @param storagePoolUpdates Specifies the updates to be made to the storage * pool. * * @brief Update storage pool * @return A StoragePoolRestRep specifying the updated storage pool info. */ @PUT @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public StoragePoolRestRep updateStoragePool(@PathParam("id") URI id, StoragePoolUpdate storagePoolUpdates) { // Get the storage pool with the passed id. ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); StoragePool storagePool = queryRegisteredResource(id); ArgValidator.checkEntity(storagePool, id, isIdEmbeddedInURL(id)); boolean neighborhoodChange = false; // Validate that the neighborhoods to be assigned to the storage pool // reference existing neighborhoods in the database and add them to // the storage pool. if (storagePoolUpdates.getVarrayChanges() != null) { VirtualArrayAssignments addedNH = storagePoolUpdates.getVarrayChanges().getAdd(); if ((addedNH != null) && (!addedNH.getVarrays().isEmpty())) { VirtualArrayService.checkVirtualArrayURIs(addedNH.getVarrays(), _dbClient); storagePool.addAssignedVirtualArrays(addedNH.getVarrays()); } // Validate that the neighborhoods to be unassigned from the storage // pool reference existing neighborhoods in the database and remove // them from the storage pool. VirtualArrayAssignments removedNH = storagePoolUpdates.getVarrayChanges().getRemove(); if ((removedNH != null) && (!removedNH.getVarrays().isEmpty())) { VirtualArrayService.checkVirtualArrayURIs(removedNH.getVarrays(), _dbClient); storagePool.removeAssignedVirtualArrays(removedNH.getVarrays()); } verifyPoolNoInUseInVarrays(storagePool); neighborhoodChange = true; } // If there is change in varray, then update new matched pools // for all VirtualPool. if (neighborhoodChange) { StringBuffer errorMessage = new StringBuffer(); ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(Arrays.asList(storagePool), _dbClient, _coordinator, errorMessage); } Integer currentMaxSubscriptionPercentFromArray = storagePool.getMaxThinPoolSubscriptionPercentageFromArray(); _logger.info(String.format("Current maximum subscription percent in storage pool from array : %s ", currentMaxSubscriptionPercentFromArray)); if (null != storagePoolUpdates.getMaxPoolUtilizationPercentage()) { if (storagePoolUpdates.getMaxPoolUtilizationPercentage() < 0 || storagePoolUpdates.getMaxPoolUtilizationPercentage() > 100) { throw APIException.badRequests.invalidParameterPercentageExpected("max_pool_utilization_percentage", storagePoolUpdates.getMaxPoolUtilizationPercentage()); } // check that a new value does not exceed array limit if (currentMaxSubscriptionPercentFromArray != null && storagePoolUpdates.getMaxPoolUtilizationPercentage() > currentMaxSubscriptionPercentFromArray) { throw APIException.badRequests.invalidParameterValueExceedsArrayLimit("max_pool_utilization_percentage", storagePoolUpdates.getMaxPoolUtilizationPercentage(), currentMaxSubscriptionPercentFromArray); } storagePool .setMaxPoolUtilizationPercentage(storagePoolUpdates.getMaxPoolUtilizationPercentage()); } if (null != storagePoolUpdates.getMaxThinPoolSubscriptionPercentage()) { ArgValidator.checkFieldMinimum(storagePoolUpdates.getMaxThinPoolSubscriptionPercentage(), 0, "max_thin_pool_subscription_percentage"); if (!validateMaxThinPoolSubscriptionInput(storagePool, storagePoolUpdates.getMaxThinPoolSubscriptionPercentage())) { throw APIException.badRequests.parameterIsOnlyApplicableTo("max_thin_pool_subscription_percentage", "Thin Pool"); } // check that a new value does not exceed array limit if (currentMaxSubscriptionPercentFromArray != null && storagePoolUpdates.getMaxThinPoolSubscriptionPercentage() > currentMaxSubscriptionPercentFromArray) { throw APIException.badRequests.invalidParameterValueExceedsArrayLimit("max_thin_pool_subscription_percentage", storagePoolUpdates.getMaxThinPoolSubscriptionPercentage(), currentMaxSubscriptionPercentFromArray); } storagePool .setMaxThinPoolSubscriptionPercentage(storagePoolUpdates.getMaxThinPoolSubscriptionPercentage()); } // If unlimited resources is specified and set to true, then no need to look at max resources // If unlimited resources is set to false, then max resources should also be specified. If not specified, throw error if (null != storagePoolUpdates.getIsUnlimitedResourcesSet()) { if (storagePoolUpdates.getIsUnlimitedResourcesSet()) { storagePool.setIsResourceLimitSet(false); } else { if (null != storagePoolUpdates.getMaxResources()) { storagePool.setIsResourceLimitSet(true); storagePool.setMaxResources(storagePoolUpdates.getMaxResources()); } else { throw APIException.badRequests.parameterMaxResourcesMissing(); } } } else if (null != storagePoolUpdates.getMaxResources()) { storagePool.setMaxResources(storagePoolUpdates.getMaxResources()); storagePool.setIsResourceLimitSet(true); } // Persist the changes and return a successful response. _dbClient.updateAndReindexObject(storagePool); // Record the storage pool update event. recordStoragePoolEvent(OperationTypeEnum.STORAGE_POOL_UPDATE, STORAGEPOOL_UPDATED_DESCRIPTION, storagePool.getId()); auditOp(OperationTypeEnum.UPDATE_STORAGE_POOL, true, null, id.toString()); return toStoragePoolRep(storagePool, _dbClient, _coordinator); } /** * Remove a storage pool. The method would remove the deregistered storage pool and all resources * associated with the storage pool from the database. * Note they are not removed from the storage system physically, * but become unavailable for the user. * * @param id the URN of a ViPR storage pool to be removed. * * @brief remove storage pool from ViPR * @return Status indicating success or failure. */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/deactivate") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }) public TaskResourceRep deleteStoragePool(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); StoragePool pool = queryResource(id); if (!RegistrationStatus.UNREGISTERED.toString().equalsIgnoreCase( pool.getRegistrationStatus()) || DiscoveryStatus.VISIBLE.name().equalsIgnoreCase( pool.getDiscoveryStatus())) { throw APIException.badRequests.cannotDeactivateStoragePool(); } String taskId = UUID.randomUUID().toString(); Operation op = _dbClient.createTaskOpStatus(StoragePool.class, id, taskId, ResourceOperationTypeEnum.DELETE_STORAGE_POOL); PurgeRunnable.executePurging(_dbClient, _dbPurger, _asynchJobService.getExecutorService(), pool, _retry_attempts, taskId, 60); return toTask(pool, taskId, op); } /** * Record Bourne Event for the completed operations * * @param type * @param type * @param description * @param storagePort */ private void recordStoragePoolEvent(OperationTypeEnum opType, String description, URI storagePool) { String evType; evType = opType.getEvType(true); RecordableBourneEvent event = new RecordableBourneEvent( /* String */evType, /* tenant id */null, /* user id ?? */URI.create("ViPR-User"), /* project ID */null, /* VirtualPool */null, /* service */EVENT_SERVICE_TYPE, /* resource id */storagePool, /* description */description, /* timestamp */System.currentTimeMillis(), /* extensions */"", /* native guid */null, /* record type */RecordType.Event.name(), /* Event Source */EVENT_SERVICE_SOURCE, /* Operational Status codes */"", /* Operational Status Descriptions */""); try { _evtMgr.recordEvents(event); } catch (Exception ex) { _log.error("Failed to record event. Event description: {}. Error: {}.", description, ex); } } /** * Verify whether thinPoolSubscriptionPercentageLimit is applicable to this pool or not. * * @param pool * @param thinPoolSubscriptionPercentageLimit * @return */ private boolean validateMaxThinPoolSubscriptionInput(StoragePool pool, Integer thinPoolSubscriptionPercentageLimit) { if (null != thinPoolSubscriptionPercentageLimit) { String resType = pool.getSupportedResourceTypes(); if (null == resType) { _log.error("Supported reousrce type for the storage pool was not set."); return false; } _log.debug("validate pool of type {} for limit of {}.", resType, thinPoolSubscriptionPercentageLimit); if (resType.equals(StoragePool.SupportedResourceTypes.THICK_ONLY.name())) { return false; } } return true; } /** * Retrieves the id, name, and type of the resources in the registered * storage pool. with the passed id. * * @param id the URN of a ViPR storage pool. * * @brief List storage pool resources * @return A list of the resources in the storage pool. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/resources") @CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }) public StoragePoolResources getStoragePoolResources(@PathParam("id") URI id) { // Make sure the storage pool is registered. ArgValidator.checkFieldUriType(id, StoragePool.class, "id"); queryRegisteredResource(id); // Create the storage pools resources to be returned. StoragePoolResources resources = new StoragePoolResources(); // Get the active volumes in the storage pool and add them to // the storage pool resources URIQueryResultList volumeURIList = new URIQueryResultList(); _dbClient.queryByConstraint( ContainmentConstraint.Factory.getStoragePoolVolumeConstraint(id), volumeURIList); Iterator<URI> volumeURIIter = volumeURIList.iterator(); while (volumeURIIter.hasNext()) { URI volumeURI = volumeURIIter.next(); Volume volume = _dbClient.queryObject(Volume.class, volumeURI); if ((volume != null) && (!volume.getInactive())) { TypedRelatedResourceRep resource = toTypedRelatedResource(volume); resources.getResources().add(resource); } } // Get the active file shares in the storage pool and add them to the // storage pools resources. URIQueryResultList fsURIList = new URIQueryResultList(); _dbClient.queryByConstraint( ContainmentConstraint.Factory.getStoragePoolFileshareConstraint(id), fsURIList); Iterator<URI> fsURIIter = fsURIList.iterator(); while (fsURIIter.hasNext()) { URI fsURI = fsURIIter.next(); FileShare fs = _dbClient.queryObject(FileShare.class, fsURI); if ((fs != null) && (!fs.getInactive())) { TypedRelatedResourceRep resource = toTypedRelatedResource(fs); resources.getResources().add(resource); } } return resources; } /** * Retrieve resource representations based on input ids. * * @param param POST data containing the id list. * @brief List data of storage pool 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 StoragePoolBulkRep getBulkResources(BulkIdParam param) { return (StoragePoolBulkRep) super.getBulkResources(param); } @SuppressWarnings("unchecked") @Override public Class<StoragePool> getResourceClass() { return StoragePool.class; } @Override public StoragePoolBulkRep queryBulkResourceReps(List<URI> ids) { Iterator<StoragePool> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); return new StoragePoolBulkRep(BulkList.wrapping(_dbIterator, new Function<StoragePool, StoragePoolRestRep>() { @Override public StoragePoolRestRep apply(StoragePool storagePool) { StoragePoolRestRep restRep = toStoragePoolRep(storagePool, _dbClient, _coordinator); restRep.setNumResources(getNumResources(storagePool, _dbClient)); return restRep; } })); } @Override public StoragePoolBulkRep queryFilteredBulkResourceReps(List<URI> ids) { verifySystemAdmin(); return queryBulkResourceReps(ids); } public static StoragePoolRestRep toStoragePoolRep(StoragePool pool, DbClient dbClient, CoordinatorClient coordinator) { boolean isBlockStoragePool = StoragePool.PoolServiceType.block.name(). equalsIgnoreCase(pool.getPoolServiceType()); Map<String, BigInteger> rawCapacityMetrics = CapacityUtils.getPoolCapacityMetrics(pool); Map<String, Long> capacityMetrics = CapacityUtils.preparePoolCapacityMetrics(rawCapacityMetrics); return map(pool, capacityMetrics, isBlockStoragePool, coordinator); } @Override protected ResourceTypeEnum getResourceType() { return ResourceTypeEnum.STORAGE_POOL; } // Counts and returns the number of resources in a pool public static Integer getNumResources(StoragePool pool, DbClient dbClient) { String serviceType = pool.getPoolServiceType(); if (StoragePool.PoolServiceType.file.name().equals(serviceType)) { return dbClient.countObjects(FileShare.class, "pool", pool.getId()); } if (StoragePool.PoolServiceType.block.name().equals(serviceType)) { return dbClient.countObjects(Volume.class, "pool", pool.getId()); } // We don't do anything if it's of type object return 0; } /** * Checks that the pool does not have any volumes in the varrays from which it is being removed * * @param storagePool */ private void verifyPoolNoInUseInVarrays(StoragePool storagePool) { _log.debug("Checking virtual array changes allowed for pool {}.", storagePool.getNativeGuid()); List<Volume> volumes = CustomQueryUtility.queryActiveResourcesByRelation(_dbClient, storagePool.getId(), Volume.class, "pool"); for (Volume volume : volumes) { // only error if the pool ends up in a state where it can no longer be used in the varray // if removing the varrays reverts the pool to using implicit varrays which contains the // volumes, then it is all good. if (!storagePool.getTaggedVirtualArrays().contains(volume.getVirtualArray().toString())) { _log.debug("The pool is in use by volume {} in varray {} which will no longer in the pool's tagged varray", volume.getLabel(), volume.getVirtualArray().toString()); throw APIException.badRequests.cannotChangePoolVarraysVolumeExists( storagePool.getNativeGuid(), volume.getVirtualArray().toString(), volume.getLabel()); } } } }