/* * Copyright (c) 2012-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; import com.emc.storageos.db.client.model.Bucket; import com.emc.storageos.db.client.model.FileShare; import com.emc.storageos.db.client.model.PropertyListDataObject; import com.emc.storageos.db.client.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.joiner.Joiner; import com.emc.storageos.model.vpool.ManagedResourcesCapacity; import com.emc.storageos.model.vpool.ManagedResourcesCapacity.ManagedResourceCapacity; import static com.emc.storageos.db.client.model.mapper.PropertyListDataObjectMapper.map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; import java.util.Calendar; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class ManagedCapacityImpl implements Runnable { private static final Logger log = LoggerFactory.getLogger(ManagedCapacityImpl.class); public static final long KB = 1024L; private DbClient dbClient; public void setDbClient(DbClient dbClient) { this.dbClient = dbClient; } public DbClient getDbClient() { return this.dbClient; } public void run() { if (Thread.currentThread().isInterrupted()) { return; } else { try { List<ManagedResourceCapacity> capList = getManagedCapacity().getResourceCapacityList(); for (ManagedResourceCapacity cap : capList) { CapacityPropertyListTypes type = mapCapacityType(cap.getType()); PropertyListDataObject resource = map(cap, type.toString()); List<URI> dataResourcesURI = dbClient.queryByConstraint( AlternateIdConstraint.Factory.getConstraint(PropertyListDataObject.class, "resourceType", type.toString())); if (!dataResourcesURI.isEmpty()) { resource.setId(dataResourcesURI.get(0)); resource.setCreationTime(Calendar.getInstance()); dbClient.updateAndReindexObject(resource); } else { resource.setId(URIUtil.createId(PropertyListDataObject.class)); dbClient.createObject(resource); } } } catch (InterruptedException ie) { Thread.currentThread().interrupt(); } } } public ManagedResourcesCapacity getManagedCapacity() throws InterruptedException { log.info("Getting provisioning managed capacity"); double total = 0; StringBuilder logMessage = new StringBuilder(""); logMessage.append('\n'); logMessage.append("------------------------------------------------------------------------\n"); logMessage.append("| | | |\n"); logMessage.append("| RESOURCE | MANAGED_QTY | TOTAL CAPACITY |\n"); logMessage.append("| | | |\n"); logMessage.append("------------------------------------------------------------------------\n"); ManagedResourcesCapacity resources = getManagedCapacity(dbClient); List<ManagedResourceCapacity> capacities = resources.getResourceCapacityList(); for (ManagedResourcesCapacity.ManagedResourceCapacity cap : capacities) { total += cap.getResourceCapacity(); logMessage.append("| | | |\n"); logMessage.append( String.format("| %13s | %10d | %30s |%n", cap.getType(), cap.getNumResources(), Double.toString(cap.getResourceCapacity()) )); logMessage.append("| | | |\n"); } logMessage.append("| | | |\n"); logMessage.append("------------------------------------------------------------------------\n"); logMessage.append("| | | |\n"); logMessage.append( String.format("| TOTAL | | %30s |%n", Double.toString(total))); logMessage.append("| | | |\n"); logMessage.append("------------------------------------------------------------------------\n"); logMessage.append('\n'); log.info(logMessage.toString()); return resources; } static public ManagedResourcesCapacity getManagedCapacity(DbClient dbClient) throws InterruptedException { ManagedResourcesCapacity resourcesCapacity = new ManagedResourcesCapacity(); ManagedResourcesCapacity.ManagedResourceCapacity manCap; CustomQueryUtility.AggregatedValue aggr = null; if (Thread.currentThread().interrupted()) { throw new InterruptedException(); } manCap = new ManagedResourcesCapacity.ManagedResourceCapacity(); manCap.setType(ManagedResourcesCapacity.CapacityResourceType.VOLUME); aggr = CustomQueryUtility.aggregatedPrimitiveField(dbClient, Volume.class, "allocatedCapacity"); manCap.setNumResources(aggr.getCount()); manCap.setResourceCapacity(aggr.getValue()); resourcesCapacity.getResourceCapacityList().add(manCap); if (Thread.currentThread().interrupted()) { throw new InterruptedException(); } manCap = new ManagedResourcesCapacity.ManagedResourceCapacity(); manCap.setType(ManagedResourcesCapacity.CapacityResourceType.FILESHARE); aggr = CustomQueryUtility.aggregatedPrimitiveField(dbClient, FileShare.class, "usedCapacity"); manCap.setNumResources(aggr.getCount()); manCap.setResourceCapacity(aggr.getValue()); resourcesCapacity.getResourceCapacityList().add(manCap); if (Thread.currentThread().interrupted()) { throw new InterruptedException(); } manCap = new ManagedResourcesCapacity.ManagedResourceCapacity(); manCap.setType(ManagedResourcesCapacity.CapacityResourceType.POOL); aggr = CustomQueryUtility.aggregatedPrimitiveField(dbClient, StoragePool.class, "freeCapacity"); manCap.setNumResources(aggr.getCount()); double capacity = aggr.getValue(); // We must consider storage systems with sharedStorageCapacity == true (e.g. Ceph), // because each their pool reports total storage free capacity. // We get all such systems and subtract its pool size multiplied by (pools count - 1) from total capacity. // Get all StoragePools where storageDevice is a StorageSystem where sharedStorageCapacity is true Joiner j = new Joiner(dbClient).join(StorageSystem.class, "ss").match("sharedStorageCapacity", true) .join("ss", StoragePool.class, "sp", "storageDevice").go(); Map<StorageSystem, Collection<URI>> ssToPoolMap = j.pushList("ss").pushUris("sp").map(); // From the joiner, get the StorageSystems (which is a small amount of objects) and the SPs (which is large, so get URIs and use query) for (Entry<StorageSystem, Collection<URI>> ssToPoolEntry : ssToPoolMap.entrySet()) { Collection<URI> poolURIs = ssToPoolEntry.getValue(); int extraPoolCount = poolURIs.size() - 1; if (extraPoolCount <= 0) { // Do nothing if none of the only pool belongs to Storage System continue; } StoragePool pool = dbClient.queryObject(StoragePool.class, poolURIs.iterator().next()); capacity -= extraPoolCount * pool.getFreeCapacity(); } manCap.setResourceCapacity(capacity * KB); resourcesCapacity.getResourceCapacityList().add(manCap); if (Thread.currentThread().interrupted()) { throw new InterruptedException(); } manCap = new ManagedResourcesCapacity.ManagedResourceCapacity(); manCap.setType(ManagedResourcesCapacity.CapacityResourceType.BUCKET); aggr = CustomQueryUtility.aggregatedPrimitiveField(dbClient, Bucket.class, "hardQuota"); manCap.setNumResources(aggr.getCount()); manCap.setResourceCapacity(aggr.getValue()); resourcesCapacity.getResourceCapacityList().add(manCap); if (Thread.currentThread().interrupted()) { throw new InterruptedException(); } return resourcesCapacity; } public static enum CapacityPropertyListTypes { POOL_MANAGED_CAPACITY, VOLUME_MANAGED_CAPACITY, FILE_MANAGED_CAPACITY, OBJECT_MANAGED_CAPACITY, } public static ManagedResourcesCapacity.CapacityResourceType mapCapacityType(CapacityPropertyListTypes resourceType) { ManagedResourcesCapacity.CapacityResourceType type = ManagedResourcesCapacity.CapacityResourceType.POOL; switch (resourceType) { case POOL_MANAGED_CAPACITY: type = ManagedResourcesCapacity.CapacityResourceType.POOL; break; case VOLUME_MANAGED_CAPACITY: type = ManagedResourcesCapacity.CapacityResourceType.VOLUME; break; case FILE_MANAGED_CAPACITY: type = ManagedResourcesCapacity.CapacityResourceType.FILESHARE; break; case OBJECT_MANAGED_CAPACITY: type = ManagedResourcesCapacity.CapacityResourceType.BUCKET; break; } return type; } public static CapacityPropertyListTypes mapCapacityType(ManagedResourcesCapacity.CapacityResourceType resourceType) { CapacityPropertyListTypes type = CapacityPropertyListTypes.POOL_MANAGED_CAPACITY; switch (resourceType) { case POOL: type = CapacityPropertyListTypes.POOL_MANAGED_CAPACITY; break; case VOLUME: type = CapacityPropertyListTypes.VOLUME_MANAGED_CAPACITY; break; case FILESHARE: type = CapacityPropertyListTypes.FILE_MANAGED_CAPACITY; break; case BUCKET: type = CapacityPropertyListTypes.OBJECT_MANAGED_CAPACITY; break; } return type; } }