/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis.job; import java.net.URI; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.cim.CIMProperty; import javax.wbem.CloseableIterator; import javax.wbem.WBEMException; import javax.wbem.client.WBEMClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringMap; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.Volume.ReplicationState; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.smis.CIMPropertyFactory; import com.emc.storageos.volumecontroller.impl.smis.SmisCommandHelper; import com.emc.storageos.volumecontroller.impl.smis.SmisConstants; import com.emc.storageos.volumecontroller.impl.smis.SmisUtils; import com.google.common.base.Joiner; public class SmisReplicaCreationJobs extends SmisJob { private static final Logger _log = LoggerFactory.getLogger(SmisReplicaCreationJobs.class); protected static final String[] _volumeProps = { SmisConstants.CP_DEVICE_ID, SmisConstants.CP_ELEMENT_NAME, SmisConstants.CP_WWN_NAME, SmisConstants.CP_NAME, SmisConstants.CP_CONSUMABLE_BLOCKS, SmisConstants.CP_BLOCK_SIZE }; public SmisReplicaCreationJobs(CIMObjectPath cimJob, URI storageSystem, TaskCompleter taskCompleter, String jobName) { super(cimJob, storageSystem, taskCompleter, jobName); // TODO Auto-generated constructor stub } protected long getProvisionedCapacityInformation(WBEMClient client, CIMInstance syncVolumeInstance) { Long provisionedCapacity = 0L; try { if (syncVolumeInstance != null) { CIMProperty consumableBlocks = syncVolumeInstance .getProperty(SmisConstants.CP_CONSUMABLE_BLOCKS); CIMProperty blockSize = syncVolumeInstance.getProperty(SmisConstants.CP_BLOCK_SIZE); // calculate provisionedCapacity = consumableBlocks * block size provisionedCapacity = Long.valueOf(consumableBlocks.getValue().toString()) * Long.valueOf(blockSize.getValue().toString()); } } catch (Exception e) { _log.error("Updating ProvisionedCapacity failed for Volume {}", syncVolumeInstance.getObjectPath(), e); } return provisionedCapacity; } protected long getAllocatedCapacityInformation(WBEMClient client, CIMInstance syncVolumeInstance) { Long allocatedCapacity = 0L; try { if (syncVolumeInstance != null) { CloseableIterator<CIMInstance> iterator = client.referenceInstances( syncVolumeInstance.getObjectPath(), SmisConstants.CIM_ALLOCATED_FROM_STORAGEPOOL, null, false, SmisConstants.PS_SPACE_CONSUMED); if (iterator.hasNext()) { CIMInstance allocatedFromStoragePoolPath = iterator.next(); CIMProperty spaceConsumed = allocatedFromStoragePoolPath .getProperty(SmisConstants.CP_SPACE_CONSUMED); allocatedCapacity = Long.valueOf(spaceConsumed.getValue().toString()); } } } catch (Exception e) { _log.error("Updating Allocated Capacity failed for Volume {}", syncVolumeInstance.getObjectPath(), e); } return allocatedCapacity; } /** * It will iterate through all created sync volumes, match up with ViPR created clones, and update them in ViPR. * * @param syncVolumeIter * @param client * @param dbClient * @param clones * @param replicationGroupId * @throws Exception */ protected void processCGClones(CloseableIterator<CIMInstance> syncVolumeIter, WBEMClient client, DbClient dbClient, List<Volume> clones, String replicationGroupId, boolean isSyncActive) throws Exception { Map<String, Volume> srcNativeIdToCloneMap = new HashMap<String, Volume>(); Set<URI> pools = new HashSet<URI>(); for (Volume clone : clones) { Volume volume = dbClient.queryObject(Volume.class, clone.getAssociatedSourceVolume()); srcNativeIdToCloneMap.put(volume.getNativeId(), clone); pools.add(clone.getPool()); } for (URI pool : pools) { SmisUtils.updateStoragePoolCapacity(dbClient, client, pool); StoragePool thePool = dbClient.queryObject(StoragePool.class, pool); StringMap reservationMap = thePool.getReservedCapacityMap(); for (URI volumeId : getTaskCompleter().getIds()) { // remove from reservation map reservationMap.remove(volumeId.toString()); } dbClient.persistObject(thePool); } // Iterate through the clone elements that were created by the // Job and try to match them up with the appropriate ViPR clone Calendar now = Calendar.getInstance(); while (syncVolumeIter.hasNext()) { // Get the sync volume native device id CIMInstance syncVolume = syncVolumeIter.next(); CIMObjectPath syncVolumePath = syncVolume.getObjectPath(); String syncDeviceID = syncVolumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString(); String elementName = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_ELEMENT_NAME); // Get the associated source volume for this sync volume CIMObjectPath volumePath = null; CloseableIterator<CIMObjectPath> volumeIter = client.associatorNames(syncVolumePath, null, SmisConstants.CIM_STORAGE_VOLUME, null, null); volumePath = volumeIter.next(); volumeIter.close(); String volumeDeviceID = volumePath.getKey(SmisConstants.CP_DEVICE_ID).getValue().toString(); String wwn = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_WWN_NAME); String alternativeName = CIMPropertyFactory.getPropertyValue(syncVolume, SmisConstants.CP_NAME); // Lookup the associated clone based on the source volume's ID. Volume theClone = srcNativeIdToCloneMap.get(volumeDeviceID); theClone.setNativeId(syncDeviceID); theClone.setNativeGuid(NativeGUIDGenerator.generateNativeGuid(dbClient, theClone)); theClone.setReplicationGroupInstance(replicationGroupId); theClone.setDeviceLabel(elementName); theClone.setInactive(false); theClone.setSyncActive(isSyncActive); theClone.setCreationTime(now); theClone.setWWN(wwn.toUpperCase()); theClone.setAlternateName(alternativeName); theClone.setProvisionedCapacity(getProvisionedCapacityInformation(client, syncVolume)); theClone.setAllocatedCapacity(getAllocatedCapacityInformation(client, syncVolume)); if (isSyncActive) { theClone.setReplicaState(ReplicationState.CREATED.name()); } else { theClone.setReplicaState(ReplicationState.INACTIVE.name()); } dbClient.persistObject(theClone); } } /** * Update storage pool capacity and remove reservation for mirror capacities from pool's reserved capacity map. * * @param client * @param dbClient * @param replicas * @throws Exception */ protected void updatePools(WBEMClient client, DbClient dbClient, List<? extends Volume> replicas) throws Exception { Set<URI> poolURIs = new HashSet<URI>(); for (Volume replica : replicas) { poolURIs.add(replica.getPool()); } for (URI poolURI : poolURIs) { SmisUtils.updateStoragePoolCapacity(dbClient, client, poolURI); StoragePool pool = dbClient.queryObject(StoragePool.class, poolURI); StringMap reservationMap = pool.getReservedCapacityMap(); for (URI volumeId : getTaskCompleter().getIds()) { // remove from reservation map reservationMap.remove(volumeId.toString()); } dbClient.persistObject(pool); } } /* * Construct target native ID to source native ID mapping using getReplicationRelationships SMI-S call. * * @param dbClient DBClient * @param helper SmisCommandHelper * @param storage StorageSystem * @param srcDevIds Collection of source native IDs * @param syncType integer value of sync type to query (clone, mirror, snapshot) * @return the target native ID to source native ID mapping */ protected Map<String, String> getConsistencyGroupSyncPairs(DbClient dbClient, SmisCommandHelper helper, StorageSystem storage, Collection<String> srcDevIds, int syncType) throws WBEMException { Map<String, String> tgtToSrcMap = new HashMap<String, String>(); List<CIMObjectPath> syncPairs = helper.getReplicationRelationships( storage, SmisConstants.LOCAL_LOCALITY_VALUE, syncType, SmisConstants.SYNCHRONOUS_MODE_VALUE, SmisConstants.STORAGE_SYNCHRONIZED_VALUE); if (_log.isDebugEnabled()) { _log.debug("Found {} relationships", syncPairs.size()); _log.debug("Looking for System elements on {} with IDs {}", storage.getNativeGuid(), Joiner.on(',').join(srcDevIds)); } for (CIMObjectPath syncPair : syncPairs) { _log.info("Checking {}", syncPair); String srcProp = syncPair.getKeyValue(SmisConstants.CP_SYSTEM_ELEMENT).toString(); CIMObjectPath srcPath = new CIMObjectPath(srcProp); String srcId = srcPath.getKeyValue(SmisConstants.CP_DEVICE_ID).toString(); if (srcDevIds.contains(srcId)) { String tgtProp = syncPair.getKeyValue(SmisConstants.CP_SYNCED_ELEMENT).toString(); CIMObjectPath tgtPath = new CIMObjectPath(tgtProp); String tgtId = tgtPath.getKeyValue(SmisConstants.CP_DEVICE_ID).toString(); tgtToSrcMap.put(tgtId, srcId); } } return tgtToSrcMap; } }