/* * Copyright (c) 2012 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.smis; import static java.util.Arrays.asList; import static javax.cim.CIMDataType.STRING_T; import static javax.cim.CIMDataType.UINT16_T; import java.io.IOException; import java.lang.reflect.Array; import java.net.URI; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import javax.cim.CIMArgument; import javax.cim.CIMDataType; import javax.cim.CIMInstance; import javax.cim.CIMObjectPath; import javax.cim.CIMProperty; import javax.cim.UnsignedInteger16; import javax.cim.UnsignedInteger32; import javax.cim.UnsignedInteger64; import javax.wbem.CloseableIterator; import javax.wbem.WBEMException; import javax.wbem.client.WBEMClient; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.cimadapter.connections.cim.CimConnection; import com.emc.storageos.cimadapter.connections.cim.CimConstants; import com.emc.storageos.cimadapter.connections.cim.CimObjectPathCreator; import com.emc.storageos.customconfigcontroller.CustomConfigConstants; import com.emc.storageos.customconfigcontroller.DataSource; import com.emc.storageos.customconfigcontroller.impl.CustomConfigHandler; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.URIUtil; import com.emc.storageos.db.client.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.constraint.URIQueryResultList; import com.emc.storageos.db.client.model.AutoTieringPolicy; import com.emc.storageos.db.client.model.BlockConsistencyGroup; import com.emc.storageos.db.client.model.BlockMirror; import com.emc.storageos.db.client.model.BlockObject; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.BlockSnapshotSession; import com.emc.storageos.db.client.model.DiscoveredDataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject.Type; import com.emc.storageos.db.client.model.ExportGroup; import com.emc.storageos.db.client.model.ExportMask; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.Initiator; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.model.StoragePool; import com.emc.storageos.db.client.model.StorageProvider; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.SynchronizationState; import com.emc.storageos.db.client.model.VirtualPool; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.Volume.LinkStatus; import com.emc.storageos.db.client.util.CustomQueryUtility; import com.emc.storageos.db.client.util.ExportMaskNameGenerator; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.db.client.util.WWNUtility; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.svcs.errorhandling.model.ServiceCoded; import com.emc.storageos.svcs.errorhandling.resources.ServiceCode; import com.emc.storageos.svcs.errorhandling.resources.ServiceCodeException; import com.emc.storageos.util.ExportUtils; import com.emc.storageos.util.InvokeTestFailure; import com.emc.storageos.volumecontroller.ControllerLockingService; import com.emc.storageos.volumecontroller.JobContext; import com.emc.storageos.volumecontroller.TaskCompleter; import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl; import com.emc.storageos.volumecontroller.impl.ControllerUtils; import com.emc.storageos.volumecontroller.impl.JobPollResult; import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator; import com.emc.storageos.volumecontroller.impl.StorageGroupPolicyLimitsParam; import com.emc.storageos.volumecontroller.impl.VolumeURIHLU; import com.emc.storageos.volumecontroller.impl.block.ExportMaskPolicy; import com.emc.storageos.volumecontroller.impl.block.ExportMaskPolicy.IG_TYPE; import com.emc.storageos.volumecontroller.impl.smis.job.SmisJob; import com.emc.storageos.volumecontroller.impl.utils.ConsistencyGroupUtils; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.ListMultimap; import com.google.common.collect.Sets; import sun.net.util.IPAddressUtil; /** * Helper for Smis commands */ public class SmisCommandHelper implements SmisConstants { private static final int GET_VOLUMES_BAD_HLU_RETRY_SLEEP_MSEC = 10000; private static final int GET_VOLUMES_BAD_HLU_RETRIES = 20; private static final Logger _log = LoggerFactory.getLogger(SmisCommandHelper.class); public static final ConcurrentHashMap<String, CIMObjectPath> CIM_OBJECT_PATH_HASH_MAP = new ConcurrentHashMap<String, CIMObjectPath>(); public static final String VMAX_PREFIX = "vmax"; public static final String VNX_PREFIX = "vnx"; private static final int SYNC_WRAPPER_WAIT = 5000; private static final int SYNC_WRAPPER_TIME_OUT = 12000000; // set to 200 minutes to handle striped meta volumes with // BCV helper // expansion (it may take long time) private static final String EMC_IS_BOUND = "EMCIsBound"; private static final int MAX_REFRESH_LOCK_WAIT_TIME = 300; private static final long REFRESH_THRESHOLD = 120000; private static final CIMObjectPath _cop = CimObjectPathCreator.createInstance( Constants.PROFILECLASS, CimConstants.DFLT_CIM_CONNECTION_INTEROP_NS); public static final int PARKING_SLO_SG_LOCK_WAIT_SECS = 3600; public static final UnsignedInteger32 SINGLE_DEVICE_FOR_EACH_CONFIG = new UnsignedInteger32(1); CIMArgumentFactory _cimArgument = null; CIMPropertyFactory _cimProperty = null; CIMObjectPathFactory _cimPath = null; CIMConnectionFactory _cimConnection = null; DbClient _dbClient = null; ControllerLockingService _locker; private ExportMaskNameGenerator _nameGenerator; public void setCimArgumentFactory(CIMArgumentFactory cimArgumentFactory) { _cimArgument = cimArgumentFactory; } public void setCimPropertyFactory(CIMPropertyFactory cimPropertyFactory) { _cimProperty = cimPropertyFactory; } public void setCimConnectionFactory(CIMConnectionFactory connectionFactory) { _cimConnection = connectionFactory; } public void setCimObjectPathFactory(CIMObjectPathFactory cimObjectPathFactory) { _cimPath = cimObjectPathFactory; } public void setDbClient(DbClient dbClient) { _dbClient = dbClient; } public void setLocker(ControllerLockingService locker) { _locker = locker; } public void setNameGenerator(ExportMaskNameGenerator nameGenerator) { _nameGenerator = nameGenerator; } public boolean checkConnectionliveness(StorageSystem storageDevice) { boolean isLive = false; try { CimConnection connection = getConnection(storageDevice); WBEMClient client = connection.getCimClient(); // Call the provider to get computer systems. client.enumerateInstanceNames(_cop); isLive = true; } catch (Exception wbemEx) { _log.error("Invalid connection found for Provider: {}", storageDevice.getActiveProviderURI()); } return isLive; } public Object invokeMethod(StorageSystem storageDevice, CIMObjectPath objectPath, String methodName, CIMArgument[] inArgs, CIMArgument[] outArgs) throws WBEMException { CimConnection connection = getConnection(storageDevice); WBEMClient client = connection.getCimClient(); int index = 0; StringBuilder inputInfoBuffer = new StringBuilder(); inputInfoBuffer.append("\nSMI-S Provider: ").append(connection.getHost()).append(" -- Attempting invokeMethod ").append(methodName) .append(" on\n").append(" objectPath=").append(objectPath.toString()).append(" with arguments: \n"); if (inArgs != null) { for (CIMArgument arg : inArgs) { if (arg != null) { inputInfoBuffer.append(" inArg[").append(index++).append("]=").append(arg.toString()).append('\n'); } } } InvokeTestFailure.internalOnlyInvokeSmisTestFailure(methodName, InvokeTestFailure.ARTIFICIAL_FAILURE_015); _log.info(inputInfoBuffer.toString()); long start = System.nanoTime(); Object obj = client.invokeMethod(objectPath, methodName, inArgs, outArgs); String total = String.format("%2.6f", ((System.nanoTime() - start) / 1000000000.0)); String str = protectedToString(obj); StringBuilder outputInfoBuffer = new StringBuilder(); outputInfoBuffer.append("\nSMI-S Provider: ").append(connection.getHost()).append(" -- Completed invokeMethod ").append(methodName) .append(" on\n").append(" objectPath=").append(objectPath.toString()).append("\n Returned: ").append(str) .append(" with output arguments: \n"); for (CIMArgument arg : outArgs) { if (arg != null) { str = protectedToString(arg); outputInfoBuffer.append(" outArg=").append(str).append('\n'); } } outputInfoBuffer.append(" Execution time: ").append(total).append(" seconds.\n"); _log.info(outputInfoBuffer.toString()); return obj; } public void deleteMaskingGroup(StorageSystem storage, String groupName, SmisCommandHelper.MASKING_GROUP_TYPE groupType) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, groupType); deleteMaskingGroup(storage, maskingGroupPath, groupType, groupName); } public void deleteMaskingGroup( StorageSystem storage, CIMObjectPath maskingGroupPath, SmisCommandHelper.MASKING_GROUP_TYPE groupType, String groupName) throws Exception { _log.debug("{} Delete {} Masking Group START...", storage.getSerialNumber(), groupType.name()); _log.info("{} Deleting Masking Group {}", maskingGroupPath, groupName); CIMInstance maskingGroupInstance = null; try { maskingGroupInstance = getInstance(storage, maskingGroupPath, false, false, new String[] {}); } catch (WBEMException we) { _log.debug("{} Problem when trying to get masking group...", storage.getSerialNumber(), we); if (we.getID() != WBEMException.CIM_ERR_NOT_FOUND) { throw we; } } if (maskingGroupInstance == null) { _log.info("{} Masking group already deleted ...", storage.getSerialNumber()); return; } CIMArgument[] inArgs = getDeleteMaskingGroupInputArguments(storage, groupName, groupType); CIMArgument[] outArgs = new CIMArgument[5]; try { invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "DeleteGroup", inArgs, outArgs, null); _log.debug("{} Delete {} Masking Group END...", storage.getSystemType(), groupType.name()); } catch (WBEMException we) { _log.debug("{} Problem when trying to delete masking group ...", storage.getSerialNumber(), we); if (we.getID() != WBEMException.CIM_ERR_NOT_FOUND) { throw we; } else { _log.debug("{} Masking group already deleted ...", storage.getSerialNumber()); } } } /** * Makes a call to SMIS provider and returns the response back to the caller. If the SMIS call * is a asynchronous, it waits for the SMIS job to complete before returning. This is done to * allow callers to make consecutive asynchronous calls without the need for a workflow. * <em>This function should be used for asynchronous SMIS calls only and will throw an exception * if the call did not return a job path.</em> * * @param inArgs * input arguments * @param outArgs * output arguments * @param job * for handling special cases of intermediate and final cim job results. Null should * be used when no special handling is needed. * @return the return value of the method invocation * @throws WBEMException * when a error occurs in the SMIS provider * @throws SmisException * when an error occurs while waiting for the asyn job to complete or if the smis * call did not return a job. */ public Object invokeMethodSynchronously(StorageSystem storageDevice, CIMObjectPath objectPath, String methodName, CIMArgument[] inArgs, CIMArgument[] outArgs, SmisJob job) throws WBEMException, SmisException { Object obj = invokeMethod(storageDevice, objectPath, methodName, inArgs, outArgs); CIMObjectPath cimJobPath = _cimPath .getCimObjectPathFromOutputArgs(outArgs, "Job"); // if this is an async call, wait for the job to complete if (cimJobPath != null) { try { waitForAsyncSmisJob(storageDevice, cimJobPath, job); } catch (Exception ex) { _log.error( "Exception occurred while waiting on async job {} to complete", cimJobPath); if (ex instanceof SmisException) { throw (SmisException) ex; } else { throw new SmisException( "Exception occurred while waiting on async " + "job to complete.", ex); } } } else { throw new SmisException(MessageFormat.format( "No job was created for method {0}, object {1}, on storage device {2}", methodName, objectPath.getObjectName(), storageDevice.getLabel())); } return obj; } private void waitForAsyncSmisJob(StorageSystem storageDevice, CIMObjectPath cimJobPath, SmisJob job) throws SmisException { if (job == null) { TaskCompleter taskCompleter = new TaskCompleter() { @Override public void ready(DbClient dbClient) throws DeviceControllerException { } @Override public void error(DbClient dbClient, ServiceCoded serviceCoded) throws DeviceControllerException { } @Override protected void complete(DbClient dbClient, Operation.Status status, ServiceCoded coded) throws DeviceControllerException { } }; job = new SmisJob(cimJobPath, storageDevice.getId(), taskCompleter, ""); } else { job.setCimJob(cimJobPath); } JobContext jobContext = new JobContext(_dbClient, _cimConnection, null, null, null, null, this); long startTime = System.currentTimeMillis(); int sync_wrapper_time_out = InvokeTestFailure.internalOnlyOverrideSyncWrapperTimeOut(SYNC_WRAPPER_TIME_OUT); while (true) { JobPollResult result = job.poll(jobContext, SYNC_WRAPPER_WAIT); if (!result.isJobInTerminalState()) { if (System.currentTimeMillis() - startTime > sync_wrapper_time_out) { throw new SmisException( "Timed out waiting on smis job to complete after " + (System.currentTimeMillis() - startTime) + " milliseconds"); } else { try { Thread.sleep(SYNC_WRAPPER_WAIT); } catch (InterruptedException e) { _log.error("Thread waiting for smis job to complete was interrupted and " + "will be resumed"); } } } else { if (result.isJobInTerminalFailedState()) { throw new SmisException( "Smis job failed: " + result.getErrorDescription()); } break; } } } /** * Executes query for component of a given storage system (volume, pool, etc...) * * @param storageSystem * @param query * @param queryLanguage * @return * @throws WBEMException */ public List<CIMInstance> executeQuery(StorageSystem storageSystem, String query, String queryLanguage) throws WBEMException { CloseableIterator<CIMInstance> iterator = null; CimConnection connection = _cimConnection.getConnection(storageSystem); WBEMClient client = connection.getCimClient(); CIMObjectPath objectPath = _cimPath.getStorageSystem(storageSystem); _log.info(String.format("Executing query: %s, objectPath: %s, query language: %s", query, objectPath, queryLanguage)); List<CIMInstance> instanceList = new ArrayList<CIMInstance>(); try { iterator = client.execQuery(objectPath, query, queryLanguage); while (iterator.hasNext()) { CIMInstance instance = iterator.next(); instanceList.add(instance); } } catch (WBEMException we) { _log.error("Caught an error will attempting to execute query and process query result. Query: " + query, we); } finally { closeCIMIterator(iterator); } return instanceList; } /** * remove Volumes from Storage Group. * * @param storage * the storage * @param groupName * the group name * @param volumeURIList * the volume uri list * @param forceFlag * the force flag * @throws Exception */ public void removeVolumesFromStorageGroup( StorageSystem storage, String groupName, List<URI> volumeURIList, boolean forceFlag) throws Exception { _log.info( "{} removeVolume from Storage group {} START...", storage.getSerialNumber(), groupName); CIMArgument[] inArgs = getRemoveVolumesFromMaskingGroupInputArguments( storage, groupName, volumeURIList, forceFlag); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, null); _log.info( "{} removeVolume from Storage group {} END...", storage.getSerialNumber(), groupName); } /** * Removes the volume from storage groups if the volume is not in any Masking View. * This will be called just before deleting the volume (for VMAX2). * * @param storageSystem * the storage system * @param volume * the volume */ public void removeVolumeFromStorageGroupsIfVolumeIsNotInAnyMV(StorageSystem storage, BlockObject bo) { /** * If Volume is not associated with any MV, then remove the volume from its associated SGs. */ CloseableIterator<CIMObjectPath> mvPathItr = null; CloseableIterator<CIMInstance> sgInstancesItr = null; boolean isSGInAnyMV = true; try { _log.info("Checking if device {} needs to be removed from Storage Groups which is not in any Masking View", bo.getNativeGuid()); CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storage, bo); // See if Volume is associated with MV mvPathItr = getAssociatorNames(storage, volumePath, null, SYMM_LUN_MASKING_VIEW, null, null); if (!mvPathItr.hasNext()) { isSGInAnyMV = false; } if (!isSGInAnyMV) { _log.info("Device {} is not in any Masking View, hence removing it from Storage Groups if any", bo.getNativeGuid()); boolean forceFlag = ExportUtils.useEMCForceFlag(_dbClient, bo.getId()); // Get all the storage groups associated with this volume sgInstancesItr = getAssociatorInstances(storage, volumePath, null, SmisConstants.SE_DEVICE_MASKING_GROUP, null, null, PS_ELEMENT_NAME); while (sgInstancesItr.hasNext()) { CIMInstance sgPath = sgInstancesItr.next(); String storageGroupName = CIMPropertyFactory.getPropertyValue(sgPath, SmisConstants.CP_ELEMENT_NAME); // Double check: check if SG is part of MV if (!checkStorageGroupInAnyMaskingView(storage, sgPath.getObjectPath())) { // if last volume, dis-associate FAST int sgVolumeCount = getVMAXStorageGroupVolumeCount(storage, storageGroupName); if (sgVolumeCount == 1) { WBEMClient client = getConnection(storage).getCimClient(); removeVolumeGroupFromPolicyAndLimitsAssociation(client, storage, sgPath.getObjectPath()); } removeVolumesFromStorageGroup(storage, storageGroupName, Collections.singletonList(bo.getId()), forceFlag); // If there was only one volume in the SG, it would be empty after removing that last volume. if (sgVolumeCount == 1) { _log.info("Deleting Empty Storage Group {}", storageGroupName); deleteMaskingGroup(storage, storageGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); } } } } else { _log.info("Found that Device {} is part of Masking View {}", bo.getNativeGuid(), mvPathItr.next()); } } catch (Exception e) { _log.warn("Exception while trying to remove device {} from Storage Groups which is not in any Masking View", bo.getNativeGuid(), e); } finally { closeCIMIterator(mvPathItr); closeCIMIterator(sgInstancesItr); } } public void removeVolumeGroupFromAutoTieringPolicy( StorageSystem storage, CIMObjectPath volumeGroupPath) throws Exception { _log.debug("{} removeVolumeGroupFromAutoTierPolicy START...", storage.getSerialNumber()); String policyName = getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, volumeGroupPath); if (isFastPolicy(policyName)) { _log.debug("disassociate {} from fast policy: {}", volumeGroupPath, policyName); CIMObjectPath[] volumeGroupPaths = new CIMObjectPath[] { volumeGroupPath }; CIMArgument[] inArgs = getRemoveVolumeGroupFromTierInputArguments( storage, policyName, volumeGroupPaths); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(storage, _cimPath.getTierPolicySvcPath(storage), "ModifyStorageTierPolicyRule", inArgs, outArgs); } _log.debug("{} removeVolumeGroupFromAutoTierPolicy END...", storage.getSerialNumber()); } public CimConnection getConnection(StorageSystem storageDevice) { return _cimConnection.getConnection(storageDevice); } public CIMArgument[] getCreateElementReplicaSnapInputArguments( StorageSystem storageDevice, Volume volume, boolean createInactive, String label) { return getCreateElementReplicaInputArguments(storageDevice, volume, null, createInactive, label, SNAPSHOT_VALUE); } public CIMArgument[] getCreateElementReplicaVPSnapInputArguments(StorageSystem storageDevice, Volume volume, boolean createInactive, String label, CIMInstance replicationSetting) { CIMArgument[] baseArgs = getCreateElementReplicaInputArguments(storageDevice, volume, null, createInactive, label, SNAPSHOT_VALUE); List<CIMArgument> args = new ArrayList<>(Arrays.asList(baseArgs)); args.add(_cimArgument.object(CP_REPLICATION_SETTING_DATA, replicationSetting)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getCreateElementReplicaSnapInputArgumentsWithTargetAndSetting( StorageSystem storageDevice, Volume volume, String targetId, CIMInstance replicaSettingData, boolean createInactive, String label) { CIMArgument[] baseArguments = getCreateElementReplicaInputArguments(storageDevice, volume, null, createInactive, label, SNAPSHOT_VALUE); List<CIMArgument> args = new ArrayList<CIMArgument>(); args.addAll(Arrays.asList(baseArguments)); args.add(_cimArgument.reference(CP_TARGET_ELEMENT, _cimPath.getVolumePath(storageDevice, targetId))); args.add(_cimArgument.object(CP_REPLICATION_SETTING_DATA, replicaSettingData)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getCreateElementReplicaMirrorInputArguments(StorageSystem storageDevice, Volume volume, StoragePool pool, boolean createInactive, String label, CIMObjectPath volumeGroupPath, CIMInstance replicaSettingData) { CIMArgument[] baseArguments = getCreateElementReplicaInputArguments(storageDevice, volume, pool, createInactive, label, MIRROR_VALUE); List<CIMArgument> args = new ArrayList<CIMArgument>(); args.addAll(Arrays.asList(baseArguments)); args.add(_cimArgument.referenceArray(CP_COLLECTIONS, new CIMObjectPath[] { volumeGroupPath })); args.add(_cimArgument.object(CP_REPLICATION_SETTING_DATA, replicaSettingData)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getCreateElementReplicaMirrorInputArguments(StorageSystem storageDevice, BlockObject volume, StoragePool pool, boolean createInactive, String label) { return getCreateElementReplicaInputArguments(storageDevice, volume, pool, createInactive, label, MIRROR_VALUE); } public CIMArgument[] getCreateElementReplicaInputArguments( StorageSystem storageDevice, BlockObject volume, StoragePool pool, boolean createInactive, String label, int syncType) { int waitForCopyState = (createInactive) ? INACTIVE_VALUE : ACTIVATE_VALUE; CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageDevice, volume); List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.string(CP_ELEMENT_NAME, label)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, syncType)); args.add(_cimArgument.reference(CP_SOURCE_ELEMENT, volumePath)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, waitForCopyState)); if (pool != null) { addTargetPoolToArgs(storageDevice, pool, args); } return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getFractureMirrorInputArgumentsWithCopyState(CIMObjectPath storageSync, Boolean sync) { int operation = (sync != null && sync) ? SPLIT_VALUE : FRACTURE_VALUE; int copyState = (operation == SPLIT_VALUE) ? SPLIT : FRACTURED; return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, operation), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, copyState), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getFractureMirrorInputArguments(CIMObjectPath storageSync, Boolean sync) { int FRACTURE_OR_SPLIT = (sync != null && sync) ? SPLIT_VALUE : FRACTURE_VALUE; return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FRACTURE_OR_SPLIT), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getFailoverSyncPairInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FAILOVER_SYNC_PAIR), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getFailoverSyncPairInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FAILOVER_SYNC_PAIR), _cimArgument.bool(CP_FORCE, true), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getFractureInputArguments(Collection<CIMObjectPath> syncPaths, Boolean sync) { int FRACTURE_OR_SPLIT = (sync != null && sync) ? SPLIT_VALUE : FRACTURE_VALUE; return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FRACTURE_OR_SPLIT), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getDetachSRDFInputArguments(CIMObjectPath syncPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DETACH_VALUE), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, syncPath) }; } public CIMArgument[] getDetachSRDFInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DETACH_VALUE), _cimArgument.bool(CP_FORCE, true), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getAddSyncPairInputArguments(CIMObjectPath groupSync, Object settings, CIMObjectPath... syncPairs) { List<CIMArgument> args = new ArrayList<>(); args.add(_cimArgument.object(CP_REPLICATION_SETTING_DATA, settings)); args.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); args.add(_cimArgument.uint16(CP_OPERATION, ADD_SYNC_PAIR)); args.add(_cimArgument.bool(CP_FORCE, true)); args.add(_cimArgument.reference(CP_SYNCHRONIZATION, groupSync)); args.add(_cimArgument.referenceArray(CP_SYNCPAIR, syncPairs)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getRemoveSyncPairInputArguments(CIMObjectPath storageSync, CIMObjectPath syncPair, Object repSettingInstance) { CIMObjectPath[] paths = new CIMObjectPath[] { syncPair }; return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, REMOVE_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync), _cimArgument.referenceArray(CP_SYNCPAIR, paths), _cimArgument.bool(CP_FORCE, true), _cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance) }; } public CIMArgument[] getSyncPairFailBackInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FAILBACK_SYNC_PAIR), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getSRDFPauseLinkInputArguments(Collection<CIMObjectPath> syncPaths, Object repSettingInstance, boolean sync) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); args.add(_cimArgument.uint16(CP_OPERATION, (sync ? FRACTURE_VALUE : SUSPEND_SYNC_PAIR))); args.add(_cimArgument.bool(CP_FORCE, true)); args.add(_cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {}))); args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getSRDFActivePauseLinkInputArguments(Collection<CIMObjectPath> syncPaths, Object repSettingInstance, boolean sync) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SUSPENDED)); args.add(_cimArgument.uint16(CP_OPERATION, (sync ? FRACTURE_VALUE : SUSPEND_SYNC_PAIR))); args.add(_cimArgument.bool(CP_FORCE, true)); args.add(_cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {}))); args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getSRDFSplitInputArguments(Collection<CIMObjectPath> syncPaths, Object repSettingInstance) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FRACTURE_VALUE), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})), _cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance) }; } public CIMArgument[] getSRDFPauseGroupInputArguments(CIMObjectPath storageSync, Object repSettingInstance, boolean sync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, (sync ? SPLIT_VALUE : SUSPEND_SYNC_PAIR)), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync), _cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance) }; } public CIMArgument[] getSwapPairSuspendInputArguments(Collection<CIMObjectPath> syncPaths, Object repSettingInstance) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, SWAP_SYNC_PAIR), _cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getASyncPairFailBackInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FAILBACK_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getSwapPairSuspendInputArguments(CIMObjectPath storageSync, Object repSettingInstance) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, SWAP_SYNC_PAIR), _cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getSyncPairResumeInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getASyncPairFailBackInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, FAILBACK_SYNC_PAIR), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getASyncPairSuspendInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, SUSPEND_SYNC_PAIR), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getActivePairSuspendInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, SUSPEND_SYNC_PAIR), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SUSPENDED), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getASyncSwapInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, SWAP_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getSyncPairResumeInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getASyncPairResumeInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getActivePairResumeInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getSRDFProtectionInputArguments(CIMObjectPath volume) { return new CIMArgument[] { _cimArgument.uint16(CP_ACCESS, READ_WRITE_DISABLED), _cimArgument.uint16(CP_ELEMENTTYPE, ELEMENT_TYPE), _cimArgument.reference(CP_ELEMENT, volume) }; } public CIMArgument[] getReSyncASyncPairResumeInputArguments(CIMObjectPath groupSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESYNC_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, groupSync) }; } public CIMArgument[] getDetachMirrorInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.bool(CP_FORCE, true), _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DETACH_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getResumeSynchronizationInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESYNC_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getResetToAdaptiveCopyModeInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESET_TO_ADAPTIVE_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getResetToSyncCopyModeInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESET_TO_SYNC_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getResetToAsyncCopyModeInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESET_TO_ASYNC_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getActivateConsistencyInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, ACTIVATE_CONSISTENCY_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getResumeSnapshotSynchronizationInputArguments(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getResumeSyncListInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getResumeActiveListInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED), _cimArgument.uint16(CP_OPERATION, RESUME_SYNC_PAIR), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getResumeSynchronizationInputArgumentsWithCopyState(CIMObjectPath storageSync) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESYNC_VALUE), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED), _cimArgument.reference(CP_SYNCHRONIZATION, storageSync) }; } public CIMArgument[] getDetachSynchronizationInputArguments(StorageSystem storage, Volume volume) { CIMObjectPath syncObject; try { syncObject = _cimPath.getSyncObject(storage, volume); } catch (Exception e) { throw new IllegalArgumentException("Problem getting input arguments"); } return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DETACH_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObject) }; } public CIMArgument[] getDetachSynchronizationInputArguments(CIMObjectPath syncObject) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DETACH_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObject) }; } public CIMArgument[] getDeleteMirrorInputArguments(StorageSystem storage, CIMObjectPath mirrorPath) { return new CIMArgument[] { _cimArgument.reference(CP_THE_ELEMENT, mirrorPath) }; } /** * Create input arguments for ReturnElementsToStoragePool operation * * @param theElements * Array of path to be returned to the storage pool * @param options * Additional options: 2 (Continue on nonexistent element), 3 (Return error on * nonexistent element) * @return An array of CIMArgument based on the given parameters */ public CIMArgument[] getReturnElementsToStoragePoolArguments(CIMObjectPath[] theElements, int options) { return new CIMArgument[] { _cimArgument.referenceArray(CP_THE_ELEMENTS, theElements), _cimArgument.uint16(CP_OPTIONS, options) }; } public CIMArgument[] getReturnElementsToStoragePoolArguments(CIMObjectPath[] theElements) { return new CIMArgument[] { _cimArgument.referenceArray(CP_THE_ELEMENTS, theElements) }; } public CIMArgument[] getVNXCopyToTargetGroupInputArguments(CIMObjectPath settingsState, CIMObjectPath targetGroup) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, COPY_TO_TARGET_VALUE), _cimArgument.reference(CP_SETTINGS_STATE, settingsState), _cimArgument.reference(CP_TARGET_GROUP, targetGroup) }; } public CIMArgument[] getVNXCopyToTargetInputArguments(CIMObjectPath settingsState, CIMObjectPath target) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, COPY_TO_TARGET_VALUE), _cimArgument.reference(CP_SETTINGS_STATE, settingsState), _cimArgument.reference(CP_TARGET_ELEMENT, target) }; } public CIMArgument[] getActivateSnapshotInputArguments(StorageSystem storageSystem, BlockSnapshot snapshot) { CIMObjectPath syncObject; try { syncObject = _cimPath.getSyncObject(storageSystem, snapshot); } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments: "); } List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); argsList.add(_cimArgument.uint16(CP_OPERATION, ACTIVATE_VALUE)); argsList.add(_cimArgument.reference(CP_SYNCHRONIZATION, syncObject)); // Set a flag that will allow the database synchronization set to be skipped, so // that the activate runs faster, to meet our 10 second window. argsList.add(_cimArgument.bool(CP_EMC_SKIP_REFRESH, true)); CIMArgument[] result = {}; return argsList.toArray(result); } public CIMArgument[] getActivateGroupSnapshotInputArguments(StorageSystem storageSystem, CIMObjectPath cgPath) { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); argsList.add(_cimArgument.uint16(CP_OPERATION, ACTIVATE_VALUE)); argsList.add(_cimArgument.reference(CP_SYNCHRONIZATION, cgPath)); argsList.add(_cimArgument.bool(CP_EMC_SKIP_REFRESH, true)); CIMArgument[] result = {}; return argsList.toArray(result); } public CIMArgument[] getCreateSynchronizationAspectInput(CIMObjectPath cgPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SKIP_REFRESH, true), _cimArgument.uint16(CP_SYNC_TYPE, SNAPSHOT_VALUE), _cimArgument.reference(CP_SOURCE_ELEMENT, cgPath) }; } public CIMArgument[] getCreateGroupSynchronizationAspectInput(CIMObjectPath cgPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SKIP_REFRESH, true), _cimArgument.uint16(CP_SYNC_TYPE, SNAPSHOT_VALUE), _cimArgument.reference(CP_SOURCE_GROUP, cgPath) }; } public CIMArgument[] getCreateMetaVolumesInputArguments(StorageSystem storageDevice, StoragePool pool, String label, Long capacity, int count, boolean isThinlyProvisioned, String metaType, Integer metaMemberCount, CIMInstance poolSetting) { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageDevice, pool.getNativeId())) }; CIMObjectPath inPoolPath = CimObjectPathCreator.createInstance(pool.getPoolClassName(), _cimConnection.getNamespace(storageDevice), inPoolPropKeys); CIMObjectPath[] inPoolPaths = new CIMObjectPath[] { inPoolPath }; // Use thick/thin volume type int volumeType = isThinlyProvisioned ? THIN_STORAGE_VOLUME : STORAGE_VOLUME_VALUE; list.add(_cimArgument.uint16(CP_ELEMENT_TYPE, volumeType)); list.add(_cimArgument.referenceArray(CP_EMC_IN_POOLS, inPoolPaths)); list.add(_cimArgument.uint64(CP_SIZE, capacity)); if (count > 1) { list.add(_cimArgument.uint32(CP_EMC_NUMBER_OF_DEVICES, count)); } if (label != null) { list.add(_cimArgument.string(CP_ELEMENT_NAME, label)); } // Set composite type int compositeType = metaType.equalsIgnoreCase(Volume.CompositionType.STRIPED.toString()) ? STRIPED_META_VOLUME_TYPE : CONCATENATED_META_VOLUME_TYPE; list.add(_cimArgument.uint16(CP_COMPOSITE_TYPE, compositeType)); // Set number of members list.add(_cimArgument.uint32(CP_EMCNUMBEROFMEMBERS, metaMemberCount)); if (poolSetting != null) { list.add(_cimArgument.reference(CP_GOAL, poolSetting.getObjectPath())); } } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments: " + storageDevice.getSerialNumber()); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public List<CIMArgument> getCreateVolumesInputArgumentsasList(StorageSystem storageDevice, StoragePool pool, List<String> labels, Long capacity, int count, boolean isThinlyProvisioned) { if (storageDevice.getUsingSmis80()) { return getCreateVolumesInputArgumentsasList80(storageDevice, pool, labels, capacity, count, isThinlyProvisioned); } else { return getCreateVolumesInputArgumentsasList40(storageDevice, pool, labels.get(0), capacity, count, isThinlyProvisioned); } } public List<CIMArgument> getCreateVolumesInputArgumentsasList40(StorageSystem storageDevice, StoragePool pool, String label, Long capacity, int count, boolean isThinlyProvisioned) { ArrayList<CIMArgument> list = new ArrayList<>(); try { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageDevice, pool.getNativeId())) }; CIMObjectPath inPoolPath = CimObjectPathCreator.createInstance(pool.getPoolClassName(), _cimConnection.getNamespace(storageDevice), inPoolPropKeys); if (!storageDevice.checkIfVmax3()) { // Use thick/thin volume type int volumeType = isThinlyProvisioned ? STORAGE_VOLUME_TYPE_THIN : STORAGE_VOLUME_VALUE; list.add(_cimArgument.uint16(CP_ELEMENT_TYPE, volumeType)); } // Adding Goal parameter if volumes need to be FAST Enabled list.add(_cimArgument.reference(CP_IN_POOL, inPoolPath)); list.add(_cimArgument.uint64(CP_SIZE, capacity)); list.add(_cimArgument.uint32(CP_EMC_NUMBER_OF_DEVICES, count)); if (label != null) { list.add(_cimArgument.string(CP_ELEMENT_NAME, label)); } } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments: " + storageDevice.getSerialNumber()); } return list; } public List<CIMArgument> getCreateVolumesInputArgumentsasList80(StorageSystem storageDevice, StoragePool pool, List<String> labels, Long capacity, int count, boolean isThinlyProvisioned) { ArrayList<CIMArgument> list = new ArrayList<>(); try { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageDevice, pool.getNativeId())) }; CIMObjectPath inPoolPath = CimObjectPathCreator.createInstance(pool.getPoolClassName(), _cimConnection.getNamespace(storageDevice), inPoolPropKeys); // Use thick/thin volume type Integer volumeType = isThinlyProvisioned ? STORAGE_VOLUME_TYPE_THIN : STORAGE_VOLUME_VALUE; // Create array values // Adding Goal parameter if volumes need to be FAST Enabled list.add(_cimArgument.referenceArray(CP_IN_POOL, toMultiElementArray(count, inPoolPath))); list.add(_cimArgument.uint64Array(CP_SIZE, toMultiElementArray(count, new UnsignedInteger64(Long.toString(capacity))))); list.add(_cimArgument.uint32Array(CP_EMC_NUMBER_OF_DEVICE_FOR_EACH_CONFIG, toMultiElementArray(count, SINGLE_DEVICE_FOR_EACH_CONFIG))); if (labels != null) { String[] labelsArray = labels.toArray(new String[] {}); // Convert labels to array list.add(_cimArgument.stringArray(CP_ELEMENT_NAMES, labelsArray)); } // Add CIMArgument instances to the list if (!storageDevice.checkIfVmax3()) { list.add(_cimArgument.uint16Array(CP_ELEMENT_TYPE, toMultiElementArray(count, new UnsignedInteger16(volumeType)))); } } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments: " + storageDevice.getSerialNumber()); } return list; } public CIMArgument[] getCreateVolumesBasedOnSettingInputArguments( StorageSystem storage, CIMObjectPath poolPath, CIMInstance storageSetting, String label, int count, long capacity) { if (storage.getUsingSmis80()) { return getCreateVolumesBasedOnSettingInputArguments80(storage, poolPath, storageSetting, label, count, capacity); } else { return getCreateVolumesBasedOnSettingInputArguments40(storage, poolPath, storageSetting, label, count, capacity); } } public CIMArgument[] getCreateVolumesBasedOnSettingInputArguments40( StorageSystem storage, CIMObjectPath poolPath, CIMInstance storageSetting, String label, int count, long capacity) { return new CIMArgument[] { _cimArgument.uint16(CP_ELEMENT_TYPE, STORAGE_VOLUME_VALUE), _cimArgument.uint32(CP_EMC_NUMBER_OF_DEVICES, count), _cimArgument.uint64(CP_SIZE, capacity), _cimArgument.reference(CP_IN_POOL, poolPath), _cimArgument.reference(CP_GOAL, storageSetting.getObjectPath()) }; } public CIMArgument[] getCreateVolumesBasedOnSettingInputArguments80( StorageSystem storage, CIMObjectPath poolPath, CIMInstance storageSetting, String label, int count, long capacity) { return new CIMArgument[] { _cimArgument.uint16Array(CP_ELEMENT_TYPE, toMultiElementArray(count, new UnsignedInteger16(STORAGE_VOLUME_VALUE))), _cimArgument.uint32Array(CP_EMC_NUMBER_OF_DEVICE_FOR_EACH_CONFIG, toMultiElementArray(count, SINGLE_DEVICE_FOR_EACH_CONFIG)), _cimArgument.uint64Array(CP_SIZE, toMultiElementArray(count, new UnsignedInteger64(Long.toString(capacity)))), _cimArgument.referenceArray(CP_IN_POOL, toMultiElementArray(count, poolPath)), _cimArgument.referenceArray(CP_GOAL, toMultiElementArray(count, storageSetting.getObjectPath())) }; } public CIMArgument[] getCreateVolumesBasedOnVolumeGroupInputArguments( StorageSystem storage, CIMObjectPath poolPath, CIMObjectPath volumeGroupPath, String label, int count, long capacity) { if (storage.getUsingSmis80() != null && storage.getUsingSmis80()) { return getCreateVolumesBasedOnVolumeGroupInputArguments80(storage, poolPath, volumeGroupPath, label, count, capacity); } else { return getCreateVolumesBasedOnVolumeGroupInputArguments40(storage, poolPath, volumeGroupPath, label, count, capacity); } } public CIMArgument[] getCreateVolumesBasedOnVolumeGroupInputArguments40( StorageSystem storage, CIMObjectPath poolPath, CIMObjectPath volumeGroupPath, String label, int count, long capacity) { if (label != null) { return new CIMArgument[] { _cimArgument.uint16(CP_ELEMENT_TYPE, STORAGE_VOLUME_VALUE), _cimArgument.string(CP_ELEMENT_NAME, label), _cimArgument.uint32(CP_EMC_NUMBER_OF_DEVICES, count), _cimArgument.uint64(CP_SIZE, capacity), _cimArgument.reference(CP_IN_POOL, poolPath), _cimArgument.referenceArray(CP_EMC_COLLECTIONS, toMultiElementArray(count, volumeGroupPath)) }; } return new CIMArgument[] { _cimArgument.uint16(CP_ELEMENT_TYPE, STORAGE_VOLUME_VALUE), _cimArgument.uint32(CP_EMC_NUMBER_OF_DEVICES, count), _cimArgument.uint64(CP_SIZE, capacity), _cimArgument.reference(CP_IN_POOL, poolPath), _cimArgument.referenceArray(CP_EMC_COLLECTIONS, toMultiElementArray(count, volumeGroupPath)) }; } public CIMArgument[] getCreateVolumesBasedOnVolumeGroupInputArguments80( StorageSystem storage, CIMObjectPath poolPath, CIMObjectPath volumeGroupPath, String label, int count, long capacity) { List<CIMArgument> list = new ArrayList<>(); list.add(_cimArgument.uint16Array(CP_ELEMENT_TYPE, toMultiElementArray(count, new UnsignedInteger16(STORAGE_VOLUME_VALUE)))); list.add(_cimArgument.uint32Array(CP_EMC_NUMBER_OF_DEVICE_FOR_EACH_CONFIG, toMultiElementArray(count, SINGLE_DEVICE_FOR_EACH_CONFIG))); list.add(_cimArgument.uint64Array(CP_SIZE, toMultiElementArray(count, new UnsignedInteger64(Long.toString(capacity))))); list.add(_cimArgument.referenceArray(CP_IN_POOL, toMultiElementArray(count, poolPath))); list.add(_cimArgument.referenceArray(CP_EMC_COLLECTIONS, toMultiElementArray(count, volumeGroupPath))); if (label != null) { list.add(_cimArgument.stringArray(CP_ELEMENT_NAMES, toMultiElementArray(count, label))); } return list.toArray(new CIMArgument[list.size()]); } public CIMArgument[] getCreateVolumesInputArguments(StorageSystem storageDevice, StoragePool pool, String label, Long capacity, int count, boolean isThinlyProvisioned, CIMInstance poolSetting, boolean isBoundToPool) { List<String> labels = new ArrayList<>(asList(toMultiElementArray(count, label))); return getCreateVolumesInputArguments(storageDevice, pool, labels, capacity, count, isThinlyProvisioned, poolSetting, isBoundToPool); } public CIMArgument[] getCreateVolumesInputArguments(StorageSystem storageDevice, StoragePool pool, List<String> labels, Long capacity, int count, boolean isThinlyProvisioned, CIMInstance poolSetting, boolean isBoundToPool) { List<CIMArgument> list = getCreateVolumesInputArgumentsasList(storageDevice, pool, labels, capacity, count, isThinlyProvisioned); if (!isBoundToPool) { if (storageDevice.getUsingSmis80()) { list.add(_cimArgument.boolArray(CP_EMC_BIND_ELEMENTS, toMultiElementArray(count, false))); } else { list.add(_cimArgument.bool(CP_EMC_BIND_ELEMENTS, false)); } } if (poolSetting != null) { if (storageDevice.getUsingSmis80()) { list.add(_cimArgument.referenceArray(CP_GOAL, toMultiElementArray(count, poolSetting.getObjectPath()))); } else { list.add(_cimArgument.reference(CP_GOAL, poolSetting.getObjectPath())); } } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreateVolumesInputArguments(StorageSystem storageDevice, StoragePool pool, List<String> labels, Long capacity, int count, boolean isThinlyProvisioned, boolean isBoundToPool, CIMObjectPath volumeGroupPath, boolean fullyAllocated) { List<CIMArgument> list = getCreateVolumesInputArgumentsasList(storageDevice, pool, labels, capacity, count, isThinlyProvisioned); if (!isBoundToPool) { if (storageDevice.getUsingSmis80()) { list.add(_cimArgument.boolArray(CP_EMC_BIND_ELEMENTS, toMultiElementArray(count, false))); } else { list.add(_cimArgument.bool(CP_EMC_BIND_ELEMENTS, false)); } } if (storageDevice.checkIfVmax3()) { list.add(_cimArgument.referenceArray(CP_EMC_COLLECTIONS, toMultiElementArray(count, volumeGroupPath))); // set volumeType for fully-thin or fully-allocated int volumeType = fullyAllocated ? STORAGE_VOLUME_FULLY_ALLOCATED : STORAGE_VOLUME_TYPE_THIN; if (storageDevice.getUsingSmis80()) { list.add(_cimArgument.uint16Array(CP_ELEMENT_TYPE, toMultiElementArray(count, new UnsignedInteger16(volumeType)))); } else { list.add(_cimArgument.uint16(CP_ELEMENT_TYPE, volumeType)); } } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreateVolumesInputArgumentsOnFastEnabledPool(StorageSystem storageDevice, StoragePool pool, String label, Long capacity, int count, boolean isThinlyProvisioned, String fastPolicyName) throws IOException { if (storageDevice.getUsingSmis80()) { List<String> labels = new ArrayList<>(asList(toMultiElementArray(count, label))); return getCreateVolumesInputArgumentsOnFastEnabledPool(storageDevice, pool, labels, capacity, count, isThinlyProvisioned, fastPolicyName); } else { return getCreateVolumesInputArgumentsOnFastEnabledPool(storageDevice, pool, asList(label), capacity, count, isThinlyProvisioned, fastPolicyName); } } public CIMArgument[] getCreateVolumesInputArgumentsOnFastEnabledPool(StorageSystem storageDevice, StoragePool pool, List<String> labels, Long capacity, int count, boolean isThinlyProvisioned, String fastPolicyName) throws IOException { List<CIMArgument> list = getCreateVolumesInputArgumentsasList(storageDevice, pool, labels, capacity, count, isThinlyProvisioned); CIMArgument[] result = {}; if (!storageDevice.getAutoTieringEnabled()) { return list.toArray(result); } String poolSettingId = null; if (null == fastPolicyName) { poolSettingId = pool.getStartHighThenAutoTierId(); } else if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_NO_MOVEMENT.toString().equalsIgnoreCase( fastPolicyName)) { poolSettingId = pool.getNoDataMovementId(); } else if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_AUTOTIER.toString().equalsIgnoreCase( fastPolicyName)) { poolSettingId = pool.getAutoTierSettingId(); } else if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_HIGHEST_AVAILABLE.toString() .equalsIgnoreCase(fastPolicyName)) { poolSettingId = pool.getHighAvailableTierId(); } else if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_LOWEST_AVAILABLE.toString() .equalsIgnoreCase(fastPolicyName)) { poolSettingId = pool.getLowAvailableTierId(); } else if (AutoTieringPolicy.VnxFastPolicy.DEFAULT_START_HIGH_THEN_AUTOTIER.toString() .equalsIgnoreCase(fastPolicyName)) { poolSettingId = pool.getStartHighThenAutoTierId(); } if (null != poolSettingId) { if (storageDevice.getUsingSmis80()) { list.add(_cimArgument.referenceArray(CP_GOAL, toMultiElementArray(count, _cimPath.getPoolSettingPath(storageDevice, poolSettingId)))); } else { list.add(_cimArgument.reference(CP_GOAL, _cimPath.getPoolSettingPath(storageDevice, poolSettingId))); } } result = list.toArray(result); return result; } public CIMArgument[] getBindVolumeInputArguments(StorageSystem storageDevice, StoragePool pool, Volume volume, long thinVolumePreAllocateSize) throws IOException { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageDevice, pool.getNativeId())) }; CIMObjectPath inPoolPath = CimObjectPathCreator.createInstance(pool.getPoolClassName(), _cimConnection.getNamespace(storageDevice), inPoolPropKeys); list.add(_cimArgument.reference(CP_IN_POOL, inPoolPath)); CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageDevice, volume); list.add(_cimArgument.reference(CP_THE_ELEMENT, volumePath)); if (thinVolumePreAllocateSize > 0) { list.add(_cimArgument.uint64(CP_SIZE, thinVolumePreAllocateSize)); } } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments for volume bind: " + storageDevice.getSerialNumber()); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreatePoolSettingArguments() { return new CIMArgument[] { _cimArgument.uint16(CP_SETTING_TYPE, DEFAULT_SETTING_TYPE) }; } public CIMProperty[] getModifyPoolSettingArguments(Long size) { return new CIMProperty[] { _cimProperty.uint64(CP_THIN_VOLUME_INITIAL_RESERVE, size) }; } public CIMProperty[] getModifyStorageTierMethodologyIdInputArguments(int storageTierMethodology) { return new CIMProperty[] { _cimProperty.uint16(EMC_STORAGE_TIER_METHODOLOGY, storageTierMethodology) }; } public int getVolumeStorageTierMethodologyId(StorageSystem storage, CIMObjectPath volumePath) throws Exception { CIMInstance cimInstance = this.getInstance(storage, volumePath, false, false, PS_EMC_STORAGE_TIER_METHODOLOGY); String tierMethodologyId = cimInstance.getPropertyValue(EMC_STORAGE_TIER_METHODOLOGY).toString(); return Integer.parseInt(tierMethodologyId); } public CIMArgument[] getExpandVolumeInputArguments(StorageSystem storageDevice, StoragePool pool, Volume volume, Long size) { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageDevice, volume); CIMInstance volumeInstance = getInstance(storageDevice, volumePath, false, false, new String[] { CP_THINLY_PROVISIONED }); String isThinVolume = CIMPropertyFactory.getPropertyValue(volumeInstance, CP_THINLY_PROVISIONED); list.add(_cimArgument.reference(CP_THE_ELEMENT, volumePath)); list.add(_cimArgument.uint64(CP_SIZE, size)); // Check volume type and use thick/thin element type based on the type of the volume int volumeType = STORAGE_VOLUME_VALUE; if (isThinVolume != null && isThinVolume.equals("true")) { volumeType = STORAGE_VOLUME_TYPE_THIN; } list.add(_cimArgument.uint16(CP_ELEMENT_TYPE, volumeType)); } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments: " + storageDevice.getSerialNumber()); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreateMetaVolumeMembersInputArguments(StorageSystem storageDevice, StoragePool pool, int count, Long capacity, boolean isThinlyProvisioned) { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageDevice, pool.getNativeId())) }; CIMObjectPath inPoolPath = CimObjectPathCreator.createInstance(pool.getPoolClassName(), _cimConnection.getNamespace(storageDevice), inPoolPropKeys); // Use thick/thin volume type int volumeType = isThinlyProvisioned ? STORAGE_VOLUME_TYPE_THIN : STORAGE_VOLUME_VALUE; list.add(_cimArgument.uint16(CP_ELEMENT_TYPE, volumeType)); // do not bind thin members (SMI-S requires thin members to be unbound) if (volumeType == STORAGE_VOLUME_TYPE_THIN) { list.add(_cimArgument.bool(CP_EMC_BIND_ELEMENTS, false)); } list.add(_cimArgument.reference(CP_IN_POOL, inPoolPath)); list.add(_cimArgument.uint64(CP_SIZE, capacity)); list.add(_cimArgument.uint32(CP_EMC_NUMBER_OF_DEVICES, count)); } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments: " + storageDevice.getSerialNumber()); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreateMetaVolumeInputArguments(StorageSystem storageDevice, String label, Volume metaHead, List<String> metaMembers, String metaType, boolean isExpand) { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { // Set InElements ArrayList<String> volumeNamesList = new ArrayList<String>(); volumeNamesList.add(metaHead.getNativeId()); // meta head should be first volumeNamesList.addAll(metaMembers); String[] stringArray = {}; CIMObjectPath[] volumePaths = _cimPath.getVolumePaths(storageDevice, volumeNamesList.toArray(stringArray)); list.add(_cimArgument.referenceArray(CP_IN_ELEMENTS, volumePaths)); // Set composite type int compositeType = metaType.equalsIgnoreCase(Volume.CompositionType.STRIPED.toString()) ? STRIPED_META_VOLUME_TYPE : CONCATENATED_META_VOLUME_TYPE; list.add(_cimArgument.uint16(CP_COMPOSITE_TYPE, compositeType)); // Get information about if meta head is bound to pool. CIMInstance cimVolume = null; CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageDevice, metaHead); cimVolume = getInstance(storageDevice, volumePath, false, false, new String[] { EMC_IS_BOUND }); String isBoundStr = cimVolume.getPropertyValue(EMC_IS_BOUND).toString(); Boolean isBound = Boolean.parseBoolean(isBoundStr); // For vnx stripe meta volume create: to preserve data on the base lun should set // EMCPreserveData to true. // Is needed only for expand operation. Also do this only if meta head is bound to pool. if (storageDevice.getSystemType().equals(StorageSystem.Type.vnxblock.toString()) && compositeType == STRIPED_META_VOLUME_TYPE && isExpand) { // Check that meta head is bound to pool (have data) if (isBound) { list.add(_cimArgument.bool(CP_EMC_PRESERVE_DATA, true)); } } // ER: We do not unconditionally bind volume here because this code is also used for // expand use cases which should not change binding // state of volumes. // list.add(_cimArgument.bool(CP_EMC_BIND_ELEMENTS, true)); // Should preserve original binding state of device to pool in this call. Details, see // OPT: 431394 . // Other reason is that we need to set thin meta pre-allocate size when we bind thin vmax meta to pool. list.add(_cimArgument.bool(CP_EMC_BIND_ELEMENTS, isBound)); } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments for meta volume create: " + storageDevice.getSerialNumber()); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getExpandMetaVolumeInputArguments(StorageSystem storageDevice, Volume metaHead, List<String> newMetaMembers) { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { // Set meta head. CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageDevice, metaHead); list.add(_cimArgument.reference(CP_THE_ELEMENT, volumePath)); // Set InElements ArrayList<String> volumeNamesList = new ArrayList<String>(); volumeNamesList.addAll(newMetaMembers); String[] stringArray = {}; CIMObjectPath[] volumePaths = _cimPath.getVolumePaths(storageDevice, volumeNamesList.toArray(stringArray)); list.add(_cimArgument.referenceArray(CP_IN_ELEMENTS, volumePaths)); // Get information about if meta head is bound to pool. CIMInstance cimVolume = null; cimVolume = getInstance(storageDevice, volumePath, false, false, new String[] { EMC_IS_BOUND }); String isBoundStr = cimVolume.getPropertyValue(EMC_IS_BOUND).toString(); Boolean isBound = Boolean.parseBoolean(isBoundStr); // For vmax striped meta volume expand: to preserve data on the source volume set // EMCPreserveData to true. For vnx striped mate volume expand, data is preserved automatically and // EMCPreserveData // is not required. // Also do this only if meta head is bound to pool. String metaType = metaHead.getCompositionType(); int compositeType = metaType.equalsIgnoreCase(Volume.CompositionType.STRIPED.toString()) ? STRIPED_META_VOLUME_TYPE : CONCATENATED_META_VOLUME_TYPE; list.add(_cimArgument.uint16(CP_COMPOSITE_TYPE, compositeType)); if (storageDevice.getSystemType().equals(StorageSystem.Type.vmax.toString()) && compositeType == STRIPED_META_VOLUME_TYPE) { // Check that meta head is bound to pool (have data) if (isBound) { list.add(_cimArgument.bool(CP_EMC_PRESERVE_DATA, true)); } } } catch (Exception e) { throw new IllegalStateException("Problem getting input arguments for meta volume expand: " + storageDevice.getSerialNumber()); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getDeleteVolumesInputArguments(StorageSystem storageDevice, String[] volumeNames) { CIMObjectPath[] volumePaths; ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { volumePaths = _cimPath.getVolumePaths(storageDevice, volumeNames); } catch (Exception e) { throw new IllegalStateException("Problem deleting volumes: " + volumeNames.toString() + "on array: " + storageDevice.getSerialNumber()); } list.add(_cimArgument.referenceArray(CP_THE_ELEMENTS, volumePaths)); if (storageDevice.checkIfVmax3()) { // Additional options: 2 (Continue on nonexistent element), // 3 (Return error on nonexistent element) list.add(_cimArgument.uint16(CP_OPTIONS, 2)); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreateVolumeGroupInputArguments(StorageSystem storageDevice, String groupName, String[] volumeNames) { ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); CIMObjectPath[] volumePaths; try { if (volumeNames != null) { volumePaths = _cimPath.getVolumePaths(storageDevice, volumeNames); list.add(_cimArgument.referenceArray(CP_MEMBERS, volumePaths)); } } catch (Exception e) { throw new IllegalStateException("Problem creating volume group: " + groupName + "on array: " + storageDevice.getSerialNumber()); } list.add(_cimArgument.string(CP_GROUP_NAME, groupName)); list.add(_cimArgument.uint16(CP_TYPE, VOLUME_GROUP_TYPE)); list.add(_cimArgument.bool(CP_DELETE_WHEN_BECOMES_UNASSOCIATED, Boolean.TRUE)); CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMArgument[] getCreateVolumeGroupInputArguments(StorageSystem storageDevice, String groupName, String slo, String srp, String workload, String[] volumeNames, boolean disableCompression) { CIMObjectPath[] volumePaths; ArrayList<CIMArgument> list = new ArrayList<CIMArgument>(); try { if (volumeNames != null) { volumePaths = _cimPath.getVolumePaths(storageDevice, volumeNames); list.add(_cimArgument.referenceArray(CP_MEMBERS, volumePaths)); } } catch (Exception e) { throw new IllegalStateException("Problem creating volume group: " + groupName + "on array: " + storageDevice.getSerialNumber()); } list.add(_cimArgument.string(CP_GROUP_NAME, groupName)); list.add(_cimArgument.uint16(CP_TYPE, VOLUME_GROUP_TYPE)); list.add(_cimArgument.string(CP_EMC_SLO, slo)); list.add(_cimArgument.string(CP_EMC_SRP, srp)); list.add(_cimArgument.string(CP_EMC_WORKLOAD, workload)); if (disableCompression) { list.add(_cimArgument.bool(CP_EMC_DISABLE_COMPRESSION, Boolean.TRUE)); } CIMArgument[] result = {}; result = list.toArray(result); return result; } public CIMProperty[] getV3FastSettingProperties(String fastSetting) { return new CIMProperty[] { _cimProperty.string(CP_FAST_SETTING, fastSetting) }; } public CIMProperty[] getV3CompressionProperties(boolean compression) { return new CIMProperty[] { _cimProperty.bool(CP_EMC_COMPRESSION, compression) }; } public CIMArgument[] getCascadedStorageGroupInputArguments(StorageSystem storageDevice, String groupName, CIMObjectPath[] storageGroupPaths) { return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.uint16(CP_TYPE, VOLUME_GROUP_TYPE), _cimArgument.referenceArray(CP_MEMBERS, storageGroupPaths), _cimArgument.bool(CP_DELETE_WHEN_BECOMES_UNASSOCIATED, Boolean.TRUE) }; } public CIMArgument[] getVolumeGroupToTierInputArguments(StorageSystem storageDevice, String policyName, CIMObjectPath[] storageGroupPaths) { CIMObjectPath tierPolicyRulePath; try { tierPolicyRulePath = _cimPath.getTierPolicyRulePath(storageDevice, policyName); } catch (Exception e) { throw new IllegalStateException("Problem creating tier policy Rule group: " + policyName + "on array: " + storageDevice.getSerialNumber()); } return new CIMArgument[] { _cimArgument.reference(CP_POLICY_RULE, tierPolicyRulePath), _cimArgument.uint16(CP_OPERATION, TIERING_GROUP_TYPE), _cimArgument.referenceArray(CP_IN_ELEMENTS, storageGroupPaths), }; } /** * Get the fast policies associated with the storage group * * @param storage * storage system * @param storageGroup * storage group name * @return the fast policies associated with the storage group * @throws Exception */ private StringSet findTierPoliciesForSingleStorageGroup(StorageSystem storage, String storageGroup) throws Exception { CloseableIterator<CIMObjectPath> tierPolicyRuleItr = null; StringSet policies = new StringSet(); try { CIMObjectPath storageGroupPath = _cimPath.getStorageGroupObjectPath(storageGroup, storage); if (storage.checkIfVmax3()) { CIMInstance instance = getInstance(storage, storageGroupPath, false, true, SmisConstants.PS_HOST_IO); String policyName = SmisUtils.getSLOPolicyName(instance); if (policyName != null) { policies.add(policyName); } } else { tierPolicyRuleItr = getAssociatorNames(storage, storageGroupPath, null, CIM_TIER_POLICY_RULE, null, null); while (tierPolicyRuleItr.hasNext()) { CIMObjectPath tierPolicyRulePath = tierPolicyRuleItr.next(); String policyRuleName = tierPolicyRulePath.getKey(Constants.POLICYRULENAME) .getValue().toString(); if (policyRuleName != null) { policies.add(policyRuleName); } } } } finally { closeCIMIterator(tierPolicyRuleItr); } return policies; } /** * Get the fast policies associated with the storage group * * @param storage * storage system * @param storageGroup * storage group name * @return the fast policies associated with the storage group * @throws Exception */ public StringSet findTierPoliciesForStorageGroup(StorageSystem storage, String storageGroup) throws Exception { CloseableIterator<CIMInstance> cimInstanceItr; StringSet policies = new StringSet(); CIMObjectPath storageGroupPath = _cimPath.getStorageGroupObjectPath(storageGroup, storage); if (this.isCascadedSG(storage, storageGroupPath)) { cimInstanceItr = getAssociatorInstances(storage, storageGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_ELEMENT_NAME); while (cimInstanceItr.hasNext()) { CIMInstance childGroupInstance = cimInstanceItr.next(); String returnedgroupName = CIMPropertyFactory.getPropertyValue(childGroupInstance, CP_ELEMENT_NAME); policies.addAll(findTierPoliciesForSingleStorageGroup(storage, returnedgroupName)); } } else { policies.addAll(findTierPoliciesForSingleStorageGroup(storage, storageGroup)); } return policies; } /** * Utility method to see if the storage group is used in a masking view. * Will not look past its own SG. (for instance, it will not look at the parent's SG) * * @param storage * storage system * @param storageGroupPath * storage group * @return true if this SG is directly assigned to a masking view * @throws Exception */ private boolean checkStorageGroupInAnyMaskingView(StorageSystem storage, CIMObjectPath storageGroupPath) throws Exception { CloseableIterator<CIMObjectPath> cimPathItr = null; try { _log.info("Verifying SG is already part of masking view"); cimPathItr = getAssociatorNames(storage, storageGroupPath, null, SYMM_LUN_MASKING_VIEW, null, null); if (cimPathItr != null && cimPathItr.hasNext()) { _log.info("SG already part of masking view found"); return true; } } catch (Exception e) { _log.error("Failed trying to check if storage group is in a parent storage group", storageGroupPath.getObjectName(), e); throw e; } finally { closeCIMIterator(cimPathItr); } return false; } public Map<String, Set<String>> findAnyStorageGroupsCanBeReUsed(StorageSystem storage, ListMultimap<String, VolumeURIHLU> expectedVolumeNativeGuids, StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam) throws WBEMException { CloseableIterator<CIMInstance> groupInstanceItr = null; CloseableIterator<CIMObjectPath> tierPolicyRuleItr = null; CloseableIterator<CIMObjectPath> volumePathItr = null; // concurrent hash map used to avoid concurrent modification exception // only Map<String, Set<String>> groupPaths = new ConcurrentHashMap<String, Set<String>>(); try { boolean isVmax3 = storage.checkIfVmax3(); CIMObjectPath deviceMaskingGroupPath = CimObjectPathCreator.createInstance( SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), ROOT_EMC_NAMESPACE); _log.info("Trying to get all Storage Groups"); if (isVmax3) { CIMObjectPath controllerConfigSvcPath = _cimPath.getControllerConfigSvcPath(storage); groupInstanceItr = getAssociatorInstances(storage, controllerConfigSvcPath, null, SE_DEVICE_MASKING_GROUP, null, null, PS_V3_STORAGE_GROUP_PROPERTIES); } else { groupInstanceItr = getEnumerateInstances(storage, deviceMaskingGroupPath, PS_ELEMENT_NAME); } /** * used in finding out whether any volume already exists in a Storage Group, but this * storage Group not part of the selected list.i.e. in case of fast , then these volumes * cannot be part of a different storage group. hence, we cannot proceed with creating * export group. **/ Set<String> volumesInExistingGroups = new HashSet<String>(); while (groupInstanceItr.hasNext()) { CIMInstance groupInstance = groupInstanceItr.next(); CIMObjectPath groupPath = groupInstance.getObjectPath(); // skipping device masking groups other than belong to expected // storage system if (!groupPath.toString().contains(storage.getSerialNumber())) { continue; } _log.debug("Trying to find group {} belongs to expected policy {}", groupPath, storageGroupPolicyLimitsParam.getAutoTierPolicyName()); String fastSetting = null; if (isVmax3) { fastSetting = CIMPropertyFactory.getPropertyValue(groupInstance, CP_FAST_SETTING); } else { tierPolicyRuleItr = getAssociatorNames(storage, groupPath, null, CIM_TIER_POLICY_RULE, null, null); } String groupName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); /** * if storage group does not math with desired the properties (policyName, Bandwidth,IOPS), skip */ StorageGroupPolicyLimitsParam existStorageGroupPolicyLimitsParam = createStorageGroupPolicyLimitsParam(storage, groupInstance); if (!existStorageGroupPolicyLimitsParam.equals(storageGroupPolicyLimitsParam)) { continue; } Set<String> returnedNativeGuids = new HashSet<String>(); // loop through all the volumes of this storage group _log.debug("Looping through all volumes in storage group {}", groupName); volumePathItr = getAssociatorNames(storage, groupPath, null, CIM_STORAGE_VOLUME, null, null); while (volumePathItr.hasNext()) { returnedNativeGuids.add(getVolumeNativeGuid(volumePathItr.next())); } if (returnedNativeGuids.isEmpty()) { continue; } // these volumes are at least part of a storage group volumesInExistingGroups.addAll(returnedNativeGuids); if (isVmax3) { if (!fastSetting.equals(storageGroupPolicyLimitsParam.getAutoTierPolicyName())) { continue; } if (fastSetting.equals(storageGroupPolicyLimitsParam.getAutoTierPolicyName()) && groupName.startsWith(Constants.STORAGE_GROUP_PREFIX)) { continue; } } // Flag will be true if the group is non-FAST boolean isNonFastGroup = (tierPolicyRuleItr != null) ? !tierPolicyRuleItr.hasNext() : false; // if the storage group is associated with fast policies, then // if the given policy name is not // present in that associated policies list, then ignore this // storage group. if (!isVmax3 && !checkPolicyExistsInReturnedList(groupName, tierPolicyRuleItr, storageGroupPolicyLimitsParam.getAutoTierPolicyName())) { if (isNonFastGroup) { // Ignore volumes that are in non FAST groups (we only care about volumes that could be in // multiple FAST groups). volumesInExistingGroups.removeAll(returnedNativeGuids); } continue; } Set<String> diff = Sets.difference(returnedNativeGuids, expectedVolumeNativeGuids .asMap().keySet()); /** * If diff is 0, it means the same set of volumes reside in one of the Storage * Groups associated with this Policy, hence, this storage Group can be reused * during this export operation to different initiator set. */ if (diff.isEmpty()) { // check whether this storage group is part of any existing parent group // if its not part of any group, then select this // even though this group is part of existing expected parent group, we need to // skip // as there is no action needed.This scenario is possible,only if the same value // is exported using the same export group again. // if thats the case, we throw Error // "Volumes already part of existing storage groups" _log.info("Trying to find parent cascaded groups any of reusable storage group {} ", groupName); if (checkStorageGroupAlreadyPartOfExistingParentGroups(storage, groupPath)) { _log.info( "Even though this group {} contains subset of given volumes {}, it cannot be reused, as it is part of another cascading group", groupPath, Joiner.on("\t").join(returnedNativeGuids)); continue; } _log.info("Found Group {} with subset of expected volumes {}", groupName, Joiner.on("\t").join(returnedNativeGuids)); runStorageGroupSelectionProcess(groupPaths, returnedNativeGuids, groupName); // add the new group } } /** * In case of fast policy, if we find a volume which is part of Storage Group, but this * volume is not in the list of final selected Storage Groups volumes, then it means, we * cannot proceed with creating an Export Group. */ if (groupPaths.size() > 0) { Set<String> volumesPartOfSelectedStorageGroups = constructVolumeNativeGuids(groupPaths .values()); Set<String> remainingVolumes = new HashSet<String>(); Sets.difference(expectedVolumeNativeGuids.asMap().keySet(), volumesPartOfSelectedStorageGroups).copyInto(remainingVolumes); _log.debug("Remaining volumes which doesn't fit into existing storage groups {}", Joiner.on("\t").join(remainingVolumes)); // volumes which are not part of selected Storage Groups from // expected list if (!remainingVolumes.isEmpty()) { // volumes which are already part of storage group. _log.debug("Trying to find , if any of the remaining volumes is present in existing storage groups"); remainingVolumes.retainAll(volumesInExistingGroups); // there are volumes which are present in existing storage // groups. if (!remainingVolumes.isEmpty()) { throw DeviceControllerException.exceptions .volumesAlreadyPartOfStorageGroups(Joiner.on("\t").join(remainingVolumes)); } } } } finally { closeCIMIterator(groupInstanceItr); closeCIMIterator(volumePathItr); closeCIMIterator(tierPolicyRuleItr); } return groupPaths; } /** * This method is used for VMAX3 storage system to find exiting storage group with a * specified SLO for parking volumes. * * @param forProvider * The storage provider where the query executes * @param storage * The reference to storage system * @param policyName * The EMCFastSetting name with which storage group is associated * @param associatedToView * Boolean which specifies whether storage group should be associated with masking view or not * * @return returns map of storage group and volumes nativeguids in a storage group * @throws WBEMException */ public Map<CIMObjectPath, Set<String>> findAnySLOStorageGroupsCanBeReUsed(StorageSystem forProvider, StorageSystem storage, String policyName, boolean associatedToView) throws WBEMException { CloseableIterator<CIMInstance> groupInstanceItr = null; CloseableIterator<CIMObjectPath> volumePathItr = null; Map<CIMObjectPath, Set<String>> groupPaths = new ConcurrentHashMap<CIMObjectPath, Set<String>>(); try { CIMObjectPath controllerConfigSvcPath = _cimPath.getControllerConfigSvcPath(storage); _log.info("Trying to get all Storage Groups"); groupInstanceItr = getAssociatorInstances(forProvider, controllerConfigSvcPath, null, SE_DEVICE_MASKING_GROUP, null, null, PS_V3_STORAGE_GROUP_PROPERTIES); while (groupInstanceItr.hasNext()) { CIMInstance groupInstance = groupInstanceItr.next(); CIMObjectPath groupPath = groupInstance.getObjectPath(); String groupName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); String fastSetting = CIMPropertyFactory.getPropertyValue(groupInstance, CP_FAST_SETTING); String groupAssociatedToView = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ASSOCIATED_TO_VIEW); Set<String> returnedNativeGuids = new HashSet<String>(); if (fastSetting.equals(policyName) && associatedToView == Boolean.parseBoolean(groupAssociatedToView) && groupName.startsWith(Constants.STORAGE_GROUP_PREFIX)) { // loop through all the volumes of this storage group _log.debug("Looping through all volumes in storage group {}", groupName); volumePathItr = getAssociatorNames(forProvider, groupPath, null, CIM_STORAGE_VOLUME, null, null); while (volumePathItr.hasNext()) { returnedNativeGuids.add(getVolumeNativeGuid(volumePathItr.next())); } groupPaths.put(groupPath, returnedNativeGuids); } } } finally { closeCIMIterator(groupInstanceItr); closeCIMIterator(volumePathItr); } return groupPaths; } private boolean checkStorageGroupAlreadyPartOfExistingParentGroups(StorageSystem storage, CIMObjectPath groupPath) throws WBEMException { CloseableIterator<CIMObjectPath> cimPathItr = getAssociatorNames(storage, groupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null); // even if storage group is part of expected parent storage group already, there is no // action needed // as its already part of parent group. boolean result = cimPathItr != null && cimPathItr.hasNext(); closeCIMIterator(cimPathItr); return result; } private <E> void closeCIMIterator(CloseableIterator<E> itr) { if (null != itr) { itr.close(); } } private boolean checkPolicyExistsInReturnedList(String groupName, CloseableIterator<CIMObjectPath> tierPolicyRuleItr, String policyName) { if (!tierPolicyRuleItr.hasNext()) { _log.info("Group is not associated with any Fast Policy"); return false; } try { while (tierPolicyRuleItr.hasNext()) { CIMObjectPath tierPolicyRulePath = tierPolicyRuleItr.next(); String policyRuleName = tierPolicyRulePath.getKey(Constants.POLICYRULENAME) .getValue().toString(); _log.info("Found Storage Group " + groupName + " is associated with policy " + policyRuleName); if (policyName.equalsIgnoreCase(policyRuleName)) { _log.info("Storage Group " + groupName + " is associated with expected policy " + policyRuleName); return true; } } } finally { closeCIMIterator(tierPolicyRuleItr); } return false; } /** * Algorithm used in wisely choosing the right storage Groups. UseCase 1 : 1. V1, V2 belongs to * Storage Group S1 2. V1,V3,V4 from SG2 comes up, the algorithm removes the old entry and * updates the new SG2. UseCase 2: 1. V1,V2 from SG1 2. V3,V4 from SG2, algorithm adds this * entry. Use Case 3: 1. V1.V2 from SG1 2. V1,V3 from SG2, algorithm replaces the old with new * group. Use case 4: 1.V1,V2 from SG1 2. V1 from SG2, no action * * @param groupPaths * @param returnedNativeGuids */ private void runStorageGroupSelectionProcess( Map<String, Set<String>> groupPaths, Set<String> returnedNativeGuids, String groupName) { _log.info("Running Storage Group selection process"); if (groupPaths.size() == 0) { _log.info("Adding volumes to given group as its first time in loop"); groupPaths.put(groupName, returnedNativeGuids); return; } Iterator<Entry<String, Set<String>>> groupPathItr = groupPaths.entrySet() .iterator(); while (groupPathItr.hasNext()) { Entry<String, Set<String>> entry = groupPathItr.next(); Set<String> diff = Sets.difference(returnedNativeGuids, entry.getValue()); _log.debug("diff between returned volumes {} against existing {}", Joiner.on("\t").join(returnedNativeGuids), Joiner.on("\t").join(entry.getValue())); _log.info("Diff {}", Joiner.on("\t").join(diff)); if (returnedNativeGuids.size() == diff.size()) { _log.debug("Adding volumes to given group {}", groupName); groupPaths.put(groupName, returnedNativeGuids); } else if (returnedNativeGuids.size() >= entry.getValue().size()) { // remove existing group _log.info("Removing Storage Group {} and adding {} from existing map", entry.getKey(), groupName); groupPaths.remove(entry.getKey()); groupPaths.put(groupName, returnedNativeGuids); } } } public CIMArgument[] getRemoveVolumeGroupFromTierInputArguments(StorageSystem storageDevice, String policyName, CIMObjectPath[] storageGroupPaths) { CIMObjectPath tierPolicyRulePath; try { tierPolicyRulePath = _cimPath.getTierPolicyRulePath(storageDevice, policyName); } catch (Exception e) { throw new IllegalStateException("Problem creating tier policy Rule group: " + policyName + "on array: " + storageDevice.getSerialNumber()); } return new CIMArgument[] { _cimArgument.reference(CP_POLICY_RULE, tierPolicyRulePath), _cimArgument.uint16(CP_OPERATION, TIERING_POLICY_REMOVE_TYPE), _cimArgument.referenceArray(CP_IN_ELEMENTS, storageGroupPaths), }; } public CIMArgument[] getCreateTargetPortGroupInputArguments(StorageSystem storageDevice, String groupName, List<URI> targetURIList) { CIMObjectPath[] targetPortPaths; try { targetPortPaths = _cimPath.getTargetPortPaths(storageDevice, targetURIList); } catch (Exception e) { _log.error(String.format("Problem creating target port group: %s on array %s", groupName, storageDevice.getSerialNumber()), e); throw new IllegalStateException("Problem creating target port group: " + groupName + "on array: " + storageDevice.getSerialNumber()); } return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.uint16(CP_TYPE, TARGET_PORT_GROUP_TYPE), _cimArgument.referenceArray(CP_MEMBERS, targetPortPaths), _cimArgument.bool(CP_DELETE_WHEN_BECOMES_UNASSOCIATED, Boolean.TRUE) }; } public CIMArgument[] getCreateInitiatorGroupInputArguments(StorageSystem storageDevice, String groupName, String[] initiatorNames, boolean consistentLUNs) { CIMObjectPath[] initiatorPaths; try { initiatorPaths = _cimPath.getInitiatorPaths(storageDevice, initiatorNames); } catch (Exception e) { throw new IllegalStateException("Problem creating initiator group: " + groupName + "on array: " + storageDevice.getSerialNumber()); } return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.uint16(CP_TYPE, INITIATOR_GROUP_TYPE), _cimArgument.referenceArray(CP_MEMBERS, initiatorPaths), _cimArgument.bool(CP_DELETE_WHEN_BECOMES_UNASSOCIATED, Boolean.TRUE), _cimArgument.bool(CP_CONSISTENT_LUNS, consistentLUNs) }; } public CIMArgument getConsistenLUNsArgument(boolean value) { CIMArgument arg = new CIMArgument(CP_CONSISTENT_LUNS, CIMDataType.BOOLEAN_T, new Boolean(value)); return arg; } public CIMArgument[] getCreateEmptyIGWithInitiatorGroupsInputArguments(String groupName) { return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.uint16(CP_TYPE, INITIATOR_GROUP_TYPE), _cimArgument.bool(CP_DELETE_WHEN_BECOMES_UNASSOCIATED, Boolean.TRUE) }; } public CIMArgument[] getCreateInitiatorGroupWithInitiatorGroupsInputArguments(String groupName, List<CIMObjectPath> igPaths, boolean consistentLUNs) { CIMObjectPath[] initiatorGroupPaths = igPaths.toArray(new CIMObjectPath[igPaths.size()]); return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.uint16(CP_TYPE, INITIATOR_GROUP_TYPE), _cimArgument.referenceArray(CP_MEMBERS, initiatorGroupPaths), _cimArgument.bool(CP_DELETE_WHEN_BECOMES_UNASSOCIATED, Boolean.TRUE), _cimArgument.bool(CP_CONSISTENT_LUNS, consistentLUNs) }; } public CIMArgument[] getCreateMaskingViewInputArguments(CIMObjectPath volumeGroup, CIMObjectPath targetPortGroup, CIMObjectPath initiatorGroup, String[] deviceNumbers, String maskingViewName, boolean forceFlag) { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.string(CP_ELEMENT_NAME, maskingViewName)); argsList.add(_cimArgument.reference(CP_DEVICE_MASKING_GROUP, volumeGroup)); argsList.add(_cimArgument.reference(CP_TARGET_MASKING_GROUP, targetPortGroup)); argsList.add(_cimArgument.reference(CP_INITIATOR_MASKING_GROUP, initiatorGroup)); if (deviceNumbers != null && deviceNumbers.length > 0) { argsList.add(_cimArgument.stringArray(CP_DEVICE_NUMBERS, deviceNumbers)); } if (forceFlag) { argsList.add(_cimArgument.bool(CP_EMC_FORCE, Boolean.TRUE)); } CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getDeleteMaskingViewInputArguments(StorageSystem storage, URI exportMaskURI, boolean forceFlag) throws Exception { String groupName = getExportMaskName(exportMaskURI); return getDeleteMaskingViewInputArguments(storage, groupName, forceFlag); } public CIMArgument[] getDeleteMaskingViewInputArguments(StorageSystem storage, String maskName, boolean forceFlag) throws Exception { CIMObjectPath protocolControllerPath = _cimPath.getMaskingViewPath(storage, maskName); List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.reference(CP_PROTOCOL_CONTROLLER, protocolControllerPath)); if (forceFlag) { argsList.add(_cimArgument.bool(CP_EMC_FORCE, Boolean.TRUE)); } if (storage.getUsingSmis80()) { // see COP-13573 argsList.add(_cimArgument.bool(CP_EMC_UNMAP_ELEMENTS, Boolean.TRUE)); } CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getDeleteMaskingGroupInputArguments(StorageSystem storage, String groupName, MASKING_GROUP_TYPE groupType) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, groupType); return new CIMArgument[] { _cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath), _cimArgument.bool(CP_FORCE, Boolean.TRUE) }; } public CIMArgument[] getDeleteInitiatorMaskingGroup(StorageSystem storage, CIMObjectPath igPath) throws Exception { return new CIMArgument[] { _cimArgument.reference(CP_MASKING_GROUP, igPath), _cimArgument.bool(CP_FORCE, Boolean.TRUE) }; } public CIMArgument[] getRemoveVolumesFromMaskingGroupInputArguments(StorageSystem storage, String groupName, List<URI> volumeURIList, boolean forceFlag) throws Exception { String[] members = getBlockObjectAlternateNames(volumeURIList); CIMObjectPath[] memberPaths = _cimPath.getVolumePaths(storage, members); CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); return getRemoveAndUnmapMaskingGroupMembersInputArguments(maskingGroupPath, memberPaths, storage, forceFlag); } public CIMArgument[] getRemoveTargetPortsFromMaskingGroupInputArguments(StorageSystem storage, String groupName, List<URI> targetURIList) throws Exception { CIMObjectPath[] memberPaths = _cimPath.getTargetPortPaths(storage, targetURIList); CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_TargetMaskingGroup); return getAddOrRemoveMaskingGroupMembersInputArguments(maskingGroupPath, memberPaths, false); } public CIMArgument[] getRemoveInitiatorsFromMaskingGroupInputArguments(StorageSystem storage, String groupName, List<Initiator> initiatorList) throws Exception { String[] memberNames = getInitiatorNames(initiatorList, storage); CIMObjectPath[] memberPaths = _cimPath.getInitiatorPaths(storage, memberNames); CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_InitiatorMaskingGroup); return getAddOrRemoveMaskingGroupMembersInputArguments(maskingGroupPath, memberPaths, false); } public CIMArgument[] getRemoveInitiatorsFromMaskingGroupInputArguments(StorageSystem storage, CIMObjectPath igPath, List<Initiator> initiatorList) throws Exception { String[] memberNames = getInitiatorNames(initiatorList, storage); CIMObjectPath[] memberPaths = _cimPath.getInitiatorPaths(storage, memberNames); return getAddOrRemoveMaskingGroupMembersInputArguments(igPath, memberPaths, false); } public CIMArgument[] getRemoveIGFromCIG(CIMObjectPath igPath, CIMObjectPath cigPath) { CIMObjectPath[] igPaths = new CIMObjectPath[] { igPath }; return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, igPaths), _cimArgument.reference(CP_MASKING_GROUP, cigPath) }; } public CIMArgument[] getRemoveAndUnmapMaskingGroupMembersInputArguments(CIMObjectPath maskingGroupPath, CIMObjectPath[] memberPaths, StorageSystem storage, boolean forceFlag) { CIMArgument[] args = getAddOrRemoveMaskingGroupMembersInputArguments(maskingGroupPath, memberPaths, forceFlag); // Only for 8.0.3 and up. !!! (see COP-13573) if (storage.getUsingSmis80()) { args = addElement(args, _cimArgument.bool(CP_EMC_UNMAP_ELEMENTS, Boolean.TRUE)); } return args; } public CIMArgument[] getAddOrRemoveMaskingGroupMembersInputArguments(CIMObjectPath maskingGroupPath, CIMObjectPath[] members, boolean forceFlag) { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.referenceArray(CP_MEMBERS, members)); argsList.add(_cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath)); if (forceFlag) { argsList.add(_cimArgument.bool(CP_EMC_FORCE, Boolean.TRUE)); } CIMArgument[] args = {}; return argsList.toArray(args); } public String getStorageGroupName(URI exportMaskURI) throws Exception { return getExportMaskName(exportMaskURI); } public void addVolumesToStorageGroup( VolumeURIHLU[] volumeURIHLUs, StorageSystem storage, String storageGroupName, SmisJob job, boolean forceFlag) throws Exception { // The 'DeviceNumbers' parameter that's used in the AddMembers call // needs to match up with the list of volumes in the 'Members' // parameter. The containers here are used to make sure that happens. List<URI> uriList = new ArrayList<>(); List<String> deviceNumberList = new ArrayList<>(); for (VolumeURIHLU volURIHlu : volumeURIHLUs) { String hlu = volURIHlu.getHLU(); // Add the HLU to the list only if it is non-null and not the // LUN_UNASSIGNED value (as a hex string). if (hlu != null && !hlu.equalsIgnoreCase(ExportGroup.LUN_UNASSIGNED_STR)) { deviceNumberList.add(hlu); } uriList.add(volURIHlu.getVolumeURI()); } String[] HLUs = (!deviceNumberList.isEmpty()) ? deviceNumberList.toArray(new String[deviceNumberList.size()]) : null; CIMArgument[] inArgs = getAddVolumesToMaskingGroupInputArguments(storage, storageGroupName, uriList, HLUs, forceFlag); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "AddMembers", inArgs, outArgs, job); } /** * Move volumes from one storage group to another. * Provider from v8.0.3 supports moveMembers for V3 array. It is a non-disruptive IO call. * * without disrupting the host's ability to view the volumes, at least one of the following conditions must be met: * - Each storage group must be a child of the same parent storage group, and the parent group must be associated * with a masking view. * - Each storage group must be associated with a masking view, and both masking views must contain a common * initiator group and a * common port group. * In this must both contain the same set of ports, or the target port group can contain a superset of the ports in * the source port * group. * - The source storage group is not in a masking view. */ public void moveVolumesFromOneStorageGroupToAnother(StorageSystem storage, CIMObjectPath sourceMaskingGroup, CIMObjectPath targetMaskingGroup, List<URI> volumeURIs, SmisJob job) throws Exception { Set<String> volumeDeviceIds = new HashSet<String>(); for (URI volURI : volumeURIs) { Volume volume = _dbClient.queryObject(Volume.class, volURI); volumeDeviceIds.add(volume.getNativeId()); } CIMArgument[] inArgs = getMoveVolumesBetweenMaskingGroupInputArguments(storage, sourceMaskingGroup, targetMaskingGroup, volumeDeviceIds); CIMArgument[] outArgs = new CIMArgument[1]; invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "EMCMoveMembers", inArgs, outArgs, job); } /** * Get the Volume CIM path, given a Volume object * * @param storage * storage system * @param volume * volume persisted * @return CIMObjectPath corresponding to that volume * @throws Exception */ public CIMObjectPath getVolumeMember(StorageSystem storage, Volume volume) throws Exception { List<URI> volumeURIList = new ArrayList<URI>(); volumeURIList.add(volume.getId()); String[] volumeNames = getBlockObjectAlternateNames(volumeURIList); CIMObjectPath[] members = _cimPath.getVolumePaths(storage, volumeNames); return members[0]; } /** * Get List of Volume CIM Paths * * @param storage * @param boUris * @return List<CIMObjectPath> * @throws Exception */ public List<CIMObjectPath> getVolumeMembers(StorageSystem storage, List<URI> boUris) throws Exception { String[] volumeNames = getBlockObjectAlternateNames(boUris); CIMObjectPath[] members = _cimPath.getVolumePaths(storage, volumeNames); return Arrays.asList(members); } /** * Helper method to set/unset the volume with the "RecoverPoint" tag. * The boolean parameter flag determines if the operation is to set or unset the flag on the volume. * * @param storageSystem * @param volume * @param flag * @return tagSet - boolean indicating whether the recoverpoint tag was successfully enabled or disabled * @throws Exception */ public boolean doApplyRecoverPointTag(final StorageSystem storageSystem, Volume volume, boolean flag) throws Exception { boolean tagSet = false; // Set/Unset the RP tag (if applicable) if (volume != null && storageSystem != null && volume.checkForRp() && storageSystem.getSystemType() != null && storageSystem.getSystemType().equalsIgnoreCase(DiscoveredDataObject.Type.vmax.toString()) && !storageSystem.checkIfVmax3()) { List<CIMObjectPath> volumePathList = new ArrayList<CIMObjectPath>(); volumePathList.add(_cimPath.getBlockObjectPath(storageSystem, volume)); _log.info(String.format("Volume [%s](%s) will be %s for RP", volume.getLabel(), volume.getId(), (flag ? "tagged" : "untagged"))); tagSet = setRecoverPointTag(storageSystem, volumePathList, flag); } else { _log.info(String.format("Volume [%s](%s) is not valid for RP tagging operation", volume.getLabel(), volume.getId())); tagSet = true; } return tagSet; } /** * Method will add or remove the EMCRecoverPointEnabled flag from the device masking group for * VMAX. * * @param deviceGroupPath * [in] - CIMObjectPath referencing the volume */ private boolean setRecoverPointTagInternal(StorageSystem storage, List<CIMObjectPath> volumeMemberList, boolean tag) throws Exception { boolean tagSet = false; try { _log.info("Attempting to {} RecoverPoint tag on Volume: {}", tag ? "enable" : "disable", Joiner.on(",").join(volumeMemberList)); CimConnection connection = _cimConnection.getConnection(storage); WBEMClient client = connection.getCimClient(); if (storage.getUsingSmis80()) { CIMObjectPath configSvcPath = _cimPath.getConfigSvcPath(storage); CIMArgument[] inArgs = getRecoverPointInputArguments(storage, volumeMemberList, tag); CIMArgument[] outArgs = new CIMArgument[5]; SmisJob job = null; invokeMethodSynchronously(storage, configSvcPath, EMC_SETUNSET_RECOVERPOINT, inArgs, outArgs, job); } else { for (CIMObjectPath volumeMember : volumeMemberList) { CIMInstance toUpdate = new CIMInstance(volumeMember, new CIMProperty[] { _cimProperty.bool(EMC_RECOVERPOINT_ENABLED, tag) }); _log.debug("Params: " + toUpdate.toString()); client.modifyInstance(toUpdate, CP_EMC_RECOVERPOINT_ENABLED); } } _log.info(String.format("RecoverPoint tag has been successfully %s Volume", tag ? "applied to" : "removed from")); tagSet = true; } catch (WBEMException e) { if (e.getMessage().contains("is already set to the requested state")) { _log.info("Found the volume was already in the proper RecoverPoint tag state"); tagSet = true; } else { _log.error(String.format("Encountered an error while trying to %s the RecoverPoint tag", tag ? "enable" : "disable"), e); } } return tagSet; } /** * Method will attempt to add or remove the EMCRecoverPointEnabled tag on VMAX volumes for up to 1 minute * * @param storage * - VMAX storage system under consideration * @param volumeMemberList * - volumes to add or remove EMCRecoverPointEnabled tag on * @param tag * - enable or disable the tag * @return whether the tag was successfully enabled or disabled * @throws Exception */ public boolean setRecoverPointTag(StorageSystem storage, List<CIMObjectPath> volumeMemberList, boolean tag) throws Exception { final int MAX_WAIT_TOTAL_TRIES = 120; final int MAX_WAIT_RETRY_MILLISECONDS = 5000; int setTagTries = MAX_WAIT_TOTAL_TRIES; boolean tagSet = false; // set to true to stay in the loop if (storage.checkIfVmax3()) { _log.error("Unable to set RecoverPoint Tag for VMAX V3 and beyond"); return tagSet; } while (!tagSet && setTagTries-- > 0) { if ((MAX_WAIT_TOTAL_TRIES - setTagTries) != 1) { _log.info("Briefly sleeping before attempting to set RecoverPoint tag (Attempt #{} / {})", MAX_WAIT_TOTAL_TRIES - setTagTries, MAX_WAIT_TOTAL_TRIES); try { Thread.sleep(MAX_WAIT_RETRY_MILLISECONDS); } catch (InterruptedException e1) { Thread.currentThread().interrupt(); } } tagSet = setRecoverPointTagInternal(storage, volumeMemberList, tag); } if (!tagSet) { _log.info("Unable to set RecoverPoint tag after {} attempts)", MAX_WAIT_TOTAL_TRIES); } return tagSet; } public CIMArgument[] getRecoverPointInputArguments(StorageSystem storageDevice, List<CIMObjectPath> volumeMemberList, boolean tag) throws Exception { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); if (tag) { argsList.add(_cimArgument.uint16(CP_OPERATION, 1)); } else { argsList.add(_cimArgument.uint16(CP_OPERATION, 2)); } CIMObjectPath[] volumeMemberPaths = {}; volumeMemberPaths = volumeMemberList.toArray(volumeMemberPaths); argsList.add(_cimArgument.referenceArray(CP_THE_ELEMENTS, volumeMemberPaths)); CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getAddVolumesToMaskingGroupInputArguments(StorageSystem storageDevice, String storageGroupName, List<URI> volumeURIList, String[] deviceNumbers, boolean forceFlag) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storageDevice, ControllerUtils.extractGroupName(storageGroupName), MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); String[] volumeNames = getBlockObjectAlternateNames(volumeURIList); CIMObjectPath[] members = _cimPath.getVolumePaths(storageDevice, volumeNames); List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.referenceArray(CP_MEMBERS, members)); argsList.add(_cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath)); if (deviceNumbers != null && deviceNumbers.length > 0) { argsList.add(_cimArgument.stringArray(CP_DEVICE_NUMBERS, deviceNumbers)); } if (forceFlag) { argsList.add(_cimArgument.bool(CP_EMC_FORCE, Boolean.TRUE)); } CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getAddVolumesToMaskingGroupInputArguments(StorageSystem storageDevice, CIMObjectPath groupPath, Set<String> volumeDeviceIds) throws Exception { String[] volumeNames = volumeDeviceIds.toArray(new String[volumeDeviceIds.size()]); CIMObjectPath[] members = _cimPath.getVolumePaths(storageDevice, volumeNames); List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.referenceArray(CP_MEMBERS, members)); argsList.add(_cimArgument.reference(CP_MASKING_GROUP, groupPath)); CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getMoveVolumesBetweenMaskingGroupInputArguments(StorageSystem storageDevice, CIMObjectPath sourceGroupPath, CIMObjectPath targetGroupPath, Set<String> volumeDeviceIds) throws Exception { String[] volumeNames = volumeDeviceIds.toArray(new String[volumeDeviceIds.size()]); CIMObjectPath[] members = _cimPath.getVolumePaths(storageDevice, volumeNames); List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.referenceArray(CP_MEMBERS, members)); argsList.add(_cimArgument.reference(CP_SOURCE_MASKING_GROUP, sourceGroupPath)); argsList.add(_cimArgument.reference(CP_TARGET_MASKING_GROUP, targetGroupPath)); CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] modifyCascadedStorageGroupInputArguments( StorageSystem storageDevice, String storageGroupName, CIMObjectPath[] childGroupPaths, boolean forceFlag) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storageDevice, storageGroupName, MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.referenceArray(CP_MEMBERS, childGroupPaths)); argsList.add(_cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath)); if (forceFlag) { argsList.add(_cimArgument.bool(CP_EMC_FORCE, Boolean.TRUE)); } CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getRemoveGroupsFromMaskingViewInputArguments( StorageSystem storage, String groupName, CIMObjectPath groupPath) throws Exception { CIMObjectPath protocolControllerPath = _cimPath.getMaskingViewPath(storage, groupName); List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.reference(CP_PROTOCOL_CONTROLLER, protocolControllerPath)); argsList.add(_cimArgument.reference(CP_MASKING_GROUP, groupPath)); argsList.add(_cimArgument.uint16(CP_OPERATION, REMOVE_GROUP_TYPE)); CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getAddInitiatorsToMaskingGroupInputArguments(StorageSystem storageDevice, CIMObjectPath maskingGroupPath, List<Initiator> initiatorList) throws Exception { String[] initiatorNames = getInitiatorNames(initiatorList, storageDevice); CIMObjectPath[] members = _cimPath.getInitiatorPaths(storageDevice, initiatorNames); return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, members), _cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath) }; } public CIMArgument[] getAddTargetsToMaskingGroupInputArguments(StorageSystem storageDevice, CIMObjectPath maskingGroupPath, String exportMaskName, List<URI> targetURIList) throws Exception { try { CIMObjectPath[] targetPortPaths = _cimPath.getTargetPortPaths(storageDevice, targetURIList); return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, targetPortPaths), _cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath) }; } catch (Exception e) { throw new IllegalStateException("Problem adding target ports to export mask : " + exportMaskName + "on array: " + storageDevice.getSerialNumber()); } } public CIMArgument[] getCreateStorageHardwareIDArgs(Initiator initiator) throws Exception { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); String storageID = null; String nodeID = null; argsList.add(_cimArgument.string(CP_EMC_HOST_NAME, initiator.getHostName())); if (initiator.getProtocol().equals("FC")) { storageID = WWNUtility.getUpperWWNWithNoColons(initiator.getInitiatorPort()); nodeID = WWNUtility.getUpperWWNWithNoColons(initiator.getInitiatorNode()); argsList.add(_cimArgument.string(CP_EMC_NODE_ID, nodeID)); argsList.add(_cimArgument.string(CP_STORAGE_ID, storageID)); argsList.add(_cimArgument.uint16(CP_ID_TYPE, PORT_WWN_ID_TYPE_VALUE)); } else { storageID = initiator.getInitiatorPort(); argsList.add(_cimArgument.string(CP_STORAGE_ID, storageID)); argsList.add(_cimArgument.uint16(CP_ID_TYPE, PORT_ISCSI_ID_TYPE_VALUE)); } CIMArgument[] args = {}; return argsList.toArray(args); } public CIMArgument[] getCreateOrGrowStorageGroupInputArguments(StorageSystem storage, URI exportMask, VolumeURIHLU[] volumeURIHLUs, List<Initiator> initiatorList, List<URI> targetURIList) throws Exception { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); if (volumeURIHLUs != null && volumeURIHLUs.length > 0) { String[] lunNames = new String[volumeURIHLUs.length]; List<String> deviceNumbers = new ArrayList<String>(); UnsignedInteger16[] deviceAccesses = new UnsignedInteger16[volumeURIHLUs.length]; String elementName = getExportMaskName(exportMask); argsList.add(_cimArgument.string(CP_EMC_ELEMENT_NAME, elementName)); for (int i = 0; i < volumeURIHLUs.length; i++) { lunNames[i] = getBlockObjectAlternateName(volumeURIHLUs[i].getVolumeURI()); String hlu = volumeURIHLUs[i].getHLU(); // Add the HLU to the list only if it is non-null and not the // LUN_UNASSIGNED value (as a hex string). if (hlu != null && !hlu.equalsIgnoreCase(ExportGroup.LUN_UNASSIGNED_STR)) { deviceNumbers.add(hlu); } deviceAccesses[i] = READ_WRITE_UINT16; } argsList.add(_cimArgument.uint16Array(CP_DEVICE_ACCESSES, deviceAccesses)); argsList.add(_cimArgument.stringArray(CP_LU_NAMES, lunNames)); if (!deviceNumbers.isEmpty()) { String[] numbers = {}; argsList.add(_cimArgument.stringArray(CP_DEVICE_NUMBERS, deviceNumbers.toArray(numbers))); } } if (initiatorList != null && !initiatorList.isEmpty()) { String[] initiatorPortIDs = getInitiatorNamesForClariion(initiatorList); argsList.add(_cimArgument.stringArray(CP_INITIATOR_PORT_IDS, initiatorPortIDs)); } if (targetURIList != null && !targetURIList.isEmpty()) { CIMObjectPath[] targetEndpoints = _cimPath.getTargetPortPaths(storage, targetURIList); Set<String> uniqueTargetPortIDs = new HashSet<String>(); for (CIMObjectPath path : targetEndpoints) { uniqueTargetPortIDs.add(path.getKey(CP_NAME).getValue().toString()); } argsList.add(_cimArgument.stringArray(CP_TARGET_PORT_IDS, uniqueTargetPortIDs.toArray(new String[] {}))); } CIMObjectPath[] protocolControllers = _cimPath.getClarProtocolControllers(storage, getExportMaskNativeId(exportMask)); if (protocolControllers != null && protocolControllers.length > 0) { argsList.add(_cimArgument.referenceArray(CP_PROTOCOL_CONTROLLERS, protocolControllers)); } CIMArgument[] retArgs = {}; return argsList.toArray(retArgs); } public CIMArgument[] getDeleteOrShrinkStorageGroupInputArguments(StorageSystem storage, URI exportMask, List<URI> volumeURIList, List<Initiator> initiatorList, boolean bDeleteStorageGroup) throws Exception { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); String[] volumeNames = null; String[] initiatorPortIDs = null; if (volumeURIList != null && !volumeURIList.isEmpty()) { volumeNames = getBlockObjectAlternateNames(volumeURIList); argsList.add(_cimArgument.stringArray(CP_LU_NAMES, volumeNames)); } if (initiatorList != null && !initiatorList.isEmpty()) { initiatorPortIDs = getInitiatorNamesForClariion(initiatorList); argsList.add(_cimArgument.stringArray(CP_INITIATOR_PORT_IDS, initiatorPortIDs)); } CIMObjectPath[] protocolControllers = _cimPath.getClarProtocolControllers(storage, getExportMaskNativeId(exportMask)); if (protocolControllers != null && protocolControllers.length > 0) { if (bDeleteStorageGroup) { argsList.add(_cimArgument.reference(CP_PROTOCOL_CONTROLLER, protocolControllers[0])); } else { argsList.add(_cimArgument.referenceArray(CP_PROTOCOL_CONTROLLERS, protocolControllers)); } } CIMArgument[] retArgs = {}; return argsList.toArray(retArgs); } public CIMArgument[] getCreateReplicationGroupCreateInputArguments(StorageSystem storage, String groupName, CIMObjectPath[] volumePaths) throws Exception { if (storage.getUsingSmis80()) { // DeleteOnEmptyElement property set to true is not allowed if (groupName != null) { return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.referenceArray(CP_MEMBERS, volumePaths) }; } else { return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, volumePaths) }; } } return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.bool(CP_DELETE_ON_EMPTY_ELEMENT, true), _cimArgument.referenceArray(CP_MEMBERS, volumePaths) }; } public CIMArgument[] getCreateReplicationGroupWithMembersInputArguments(StorageSystem storage, String groupName, CIMObjectPath[] volumePaths) throws Exception { if (storage.checkIfVmax3()) { return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, volumePaths) }; } return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName), _cimArgument.referenceArray(CP_MEMBERS, volumePaths) }; } public CIMArgument[] getCreateReplicationGroupInputArguments(String groupName) throws Exception { return new CIMArgument[] { _cimArgument.string(CP_GROUP_NAME, groupName) }; } public CIMArgument[] getDeactivateSnapshotSynchronousInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DEACTIVATE_SNAPSHOT), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath) }; } public CIMArgument[] getDeleteSnapshotSynchronousInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DELETE_SNAPSHOT), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath) }; } public CIMArgument[] getReturnGroupSyncToPoolInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RETURN_TO_RESOURCE_POOL), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath) }; } public CIMArgument[] getRestoreFromReplicaInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, RESTORED_COPY_STATE), _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_REPLICA), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath), _cimArgument.bool(CP_FORCE, true) }; } public CIMArgument[] getRestoreFromReplicaInputArgumentsWithForce(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_REPLICA), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath), _cimArgument.bool(CP_FORCE, true) }; } public CIMArgument[] getRestoreFromSettingsStateInputArguments(CIMObjectPath settingsStatePath, boolean waitForCopyState) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.uint16(CP_OPERATION, RESTORE_FROM_SYNC_SETTINGS)); args.add(_cimArgument.reference(CP_SETTINGS_STATE, settingsStatePath)); if (waitForCopyState) { args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, RESTORED_COPY_STATE)); } return args.toArray(new CIMArgument[args.size()]); } public CIMArgument[] getDeleteReplicationGroupInputArguments(StorageSystem storage, String groupName) { CIMObjectPath groupPath = _cimPath.getReplicationGroupPath(storage, groupName); return getDeleteReplicationGroupInputArguments(storage, groupPath, true); } public CIMArgument[] getDeleteReplicationGroupInputArguments(StorageSystem storage, CIMObjectPath groupPath, boolean removeElements) { return new CIMArgument[] { _cimArgument.reference(CP_REPLICATION_GROUP, groupPath), _cimArgument.bool(CP_REMOVE_ELEMENTS, removeElements) }; } public CIMArgument[] getRestoreFromSnapshotInputArguments(StorageSystem storage, Volume to, BlockSnapshot from) throws Exception { CIMObjectPath volumePath = _cimPath.getVolumePath(storage, to.getNativeId()); if (from.getSettingsInstance() == null) { throw DeviceControllerException.exceptions.snapSettingsInstanceNull(from.getSnapsetLabel(), from.getId().toString()); } CIMObjectPath syncSettingsPath = _cimPath.getSyncSettingsPath(storage, volumePath, from.getSettingsInstance()); return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_SYNC_SETTINGS), _cimArgument.reference(CP_SETTINGS_STATE, syncSettingsPath) }; } public CIMArgument[] getDeleteSettingsForSnapshotInputArguments(StorageSystem storage, Volume to, BlockSnapshot from) throws Exception { String[] deviceIds = getBlockObjectNativeIds(Arrays.asList(to.getId())); CIMObjectPath[] volumePaths = _cimPath.getVolumePaths(storage, deviceIds); CIMObjectPath volumePath = volumePaths[0]; CIMObjectPath syncSettingsPath = _cimPath.getSyncSettingsPath(storage, volumePath, from.getSettingsInstance()); return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, DELETE_FROM_SYNC_SETTINGS), _cimArgument.reference(CP_SETTINGS_STATE, syncSettingsPath) }; } public CIMArgument[] getDeleteSettingsForSnapshotInputArguments(CIMObjectPath settingsPath, boolean synchronous) throws Exception { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, synchronous), _cimArgument.uint16(CP_OPERATION, DELETE_FROM_SYNC_SETTINGS), _cimArgument.reference(CP_SETTINGS_STATE, settingsPath) }; } public CIMArgument[] getCreateGroupReplicaInputArgumentsForVNX(StorageSystem storage, CIMObjectPath cgPath, boolean createInactive, String label, int syncType) { final int waitForCopyState = createInactive ? INACTIVE_VALUE : ACTIVATE_VALUE; final CIMArgument[] basicArgs = new CIMArgument[] { _cimArgument.uint16(CP_SYNC_TYPE, syncType), _cimArgument.reference(CP_SOURCE_GROUP, cgPath), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, waitForCopyState) }; final List<CIMArgument> args = new ArrayList<CIMArgument>(asList(basicArgs)); // If active, add the RelationshipName if (!createInactive) { args.add(_cimArgument.string(RELATIONSHIP_NAME, label)); } return args.toArray(new CIMArgument[args.size()]); } public CIMArgument[] getCreateGroupReplicaInputArgumentsForVMAX( StorageSystem storage, CIMObjectPath cgPath, boolean createInactive, String label, CIMObjectPath targetGroupPath, CIMObjectPath targetVPSnapPoolPath, CIMInstance replicaSettingConsistentPointInTime, SYNC_TYPE syncType) { final CIMArgument[] basicArgs = new CIMArgument[] { _cimArgument.uint16(CP_SYNC_TYPE, syncType.getValue()), _cimArgument.reference(CP_SOURCE_GROUP, cgPath) }; final List<CIMArgument> args = new ArrayList<CIMArgument>(asList(basicArgs)); if (null != targetGroupPath) { args.add(_cimArgument.reference(CP_TARGET_GROUP, targetGroupPath)); } if (null != targetVPSnapPoolPath) { args.add(_cimArgument.reference(CP_TARGET_POOL, targetVPSnapPoolPath)); } // If active, add the RelationshipName if (!createInactive) { // Ensure that it does not exceed MAX_VMAX_RELATIONSHIP_NAME int maxRelNameLength = storage.getUsingSmis80() ? MAX_SMI80_RELATIONSHIP_NAME : MAX_VMAX_RELATIONSHIP_NAME; final String relationshipName = (label.length() > maxRelNameLength) ? label.substring(0, maxRelNameLength) : label; args.add(_cimArgument.string(RELATIONSHIP_NAME, relationshipName)); if (syncType == SYNC_TYPE.CLONE || syncType == SYNC_TYPE.SNAPSHOT || syncType == SYNC_TYPE.MIRROR) { args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, ACTIVATE_VALUE)); } } // If inactive, add the WaitForCopyState else { int waitForCopyState = -1; if (syncType == SYNC_TYPE.SNAPSHOT) { waitForCopyState = INACTIVE_VALUE; } else if (syncType == SYNC_TYPE.CLONE) { waitForCopyState = PREPARED_VALUE; } args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, waitForCopyState)); } if (replicaSettingConsistentPointInTime != null) { args.add(_cimArgument.object(CP_REPLICATION_SETTING_DATA, replicaSettingConsistentPointInTime)); } return args.toArray(new CIMArgument[args.size()]); } public CIMArgument[] getAddMembersInputArguments(CIMObjectPath cgPath, CIMObjectPath[] volumePaths) { return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, volumePaths), _cimArgument.reference(CP_REPLICATION_GROUP, cgPath) }; } public CIMArgument[] getRemoveMembersInputArguments(CIMObjectPath cgPath, CIMObjectPath[] volumePaths) { return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, volumePaths), _cimArgument.reference(CP_REPLICATION_GROUP, cgPath) }; } public CIMArgument[] getCreateDefaultStoragePoolSettingsArguments() { return new CIMArgument[] { _cimArgument.uint16(CP_SETTING_TYPE, DEFAULT_SETTING_TYPE_VALUE) }; } /** * Convenience method that wraps SMI-S ModifyReplicatSynchronization operation * * @param storage * [required] - StorageSystem object representing array * @param inArgs * [required] - CIMArgument array containing operation's arguments * @return CIM_Job CIMObjectPath will be returned representing the job associated with the * operation. * @throws WBEMException */ public CIMObjectPath callModifyReplica(StorageSystem storage, CIMArgument[] inArgs) throws WBEMException { CIMObjectPath replicationSvcPath = _cimPath.getControllerReplicationSvcPath(storage); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(storage, replicationSvcPath, MODIFY_REPLICA_SYNCHRONIZATION, inArgs, outArgs); return _cimPath.getCimObjectPathFromOutputArgs(outArgs, JOB); } public void callModifyReplicaSynchronously(StorageSystem storage, CIMArgument[] inArgs, SmisJob job) throws WBEMException { CIMObjectPath replicationSvcPath = _cimPath .getControllerReplicationSvcPath(storage); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethodSynchronously(storage, replicationSvcPath, MODIFY_REPLICA_SYNCHRONIZATION, inArgs, outArgs, job); } public CIMObjectPath callModifyListReplica(StorageSystem storage, CIMArgument[] inArgs) throws WBEMException { CIMObjectPath replicationSvcPath = _cimPath.getControllerReplicationSvcPath(storage); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(storage, replicationSvcPath, SmisConstants.MODIFY_LIST_REPLICA_SYNCHRONIZATION, inArgs, outArgs); return _cimPath.getCimObjectPathFromOutputArgs(outArgs, SmisConstants.JOB); } public CIMObjectPath protect(StorageSystem storage, CIMArgument[] inArgs) throws WBEMException { CIMObjectPath protectionSvcPath = _cimPath.getStorageProtectionSvcPath(storage); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethodSynchronously(storage, protectionSvcPath, PROTECT, inArgs, outArgs, null); return _cimPath.getCimObjectPathFromOutputArgs(outArgs, JOB); } /** * Convenience method that wraps SMI-S ModifyReplicatSynchronization operation * * @param storage * [required] - StorageSystem object representing array * @param inArgs * [required] - CIMArgument array containing operation's arguments * @param outArgs * [required] - output arguments to be filled in by the operation * @return Object - return result object * @throws WBEMException */ public Object callModifyReplica(StorageSystem storage, CIMArgument[] inArgs, CIMArgument[] outArgs) throws WBEMException { CIMObjectPath replicationSvcPath = _cimPath.getControllerReplicationSvcPath(storage); return invokeMethod(storage, replicationSvcPath, MODIFY_REPLICA_SYNCHRONIZATION, inArgs, outArgs); } /** * Convenience method that wraps SMI-S ModifySettingsDefineState operation * * @param storage * [required] - StorageSystem object referencing the array * @param inArgs * [required] - input arugments for the ModifySettingsDefineState operation * @return Object - return result object * @throws WBEMException */ public CIMObjectPath callModifySettingsDefineState(StorageSystem storage, CIMArgument[] inArgs) throws WBEMException { CIMObjectPath replicationSvcPath = _cimPath.getControllerReplicationSvcPath(storage); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(storage, replicationSvcPath, MODIFY_SETTINGS_DEFINE_STATE, inArgs, outArgs); return _cimPath.getCimObjectPathFromOutputArgs(outArgs, JOB); } /** * Convenience method that wraps SMI-S ModifySettingsDefineState operation * * @param storage * [required] - StorageSystem object referencing the array * @param inArgs * [required] - input arugments for the ModifySettingsDefineState operation * @param outArgs * [required] - output arguments to be filled in by the operation * @return Object - return result object * @throws WBEMException */ public Object callModifySettingsDefineState(StorageSystem storage, CIMArgument[] inArgs, CIMArgument[] outArgs) throws WBEMException { CIMObjectPath replicationSvcPath = _cimPath.getControllerReplicationSvcPath(storage); return invokeMethod(storage, replicationSvcPath, MODIFY_SETTINGS_DEFINE_STATE, inArgs, outArgs); } /** * This method will take a URI and return a nativeId for the BlockObject object to which the URI * applies. * * @param uri * - URI * @return Returns a nativeId String value * @throws DeviceControllerException.exceptions.notAVolumeOrBlocksnapshotUri * if URI is not a Volume/BlockSnapshot URI */ public String getBlockObjectNativeId(URI uri) throws Exception { String nativeId; if (URIUtil.isType(uri, Volume.class)) { Volume volume = _dbClient.queryObject(Volume.class, uri); nativeId = volume.getNativeId(); } else if (URIUtil.isType(uri, BlockSnapshot.class)) { BlockSnapshot blockSnapshot = _dbClient.queryObject(BlockSnapshot.class, uri); nativeId = blockSnapshot.getNativeId(); } else if (URIUtil.isType(uri, BlockMirror.class)) { BlockMirror blockMirror = _dbClient.queryObject(BlockMirror.class, uri); nativeId = blockMirror.getNativeId(); } else { throw DeviceControllerException.exceptions.notAVolumeOrBlocksnapshotUri(uri); } return nativeId; } /** * This method will take a URI and return alternateName for the BlockObject object to which the * URI applies. * * @param uri * - URI * @return Returns a nativeId String value * @throws DeviceControllerException.exceptions.notAVolumeOrBlocksnapshotUri * if URI is not a Volume/BlockSnapshot URI */ public String getBlockObjectAlternateName(URI uri) throws Exception { String nativeId; if (URIUtil.isType(uri, Volume.class)) { Volume volume = _dbClient.queryObject(Volume.class, uri); nativeId = volume.getAlternateName(); } else if (URIUtil.isType(uri, BlockSnapshot.class)) { BlockSnapshot blockSnapshot = _dbClient.queryObject(BlockSnapshot.class, uri); nativeId = blockSnapshot.getAlternateName(); } else if (URIUtil.isType(uri, BlockMirror.class)) { BlockMirror blockMirror = _dbClient.queryObject(BlockMirror.class, uri); nativeId = blockMirror.getAlternateName(); } else { throw DeviceControllerException.exceptions.notAVolumeOrBlocksnapshotUri(uri); } return nativeId; } /** * This method will loop through the URI list and return a list of nativeIds for each of the * BlockObject objects to which the URI applies. * * @param uris * - Collection of URIs * @return Returns a list of nativeId String values * @throws DeviceControllerException.exceptions.notAVolumeOrBlocksnapshotUri * f URI is not a Volume/BlockSnapshot URI */ public String[] getBlockObjectNativeIds(Collection<URI> uris) throws Exception { String[] results = {}; Set<String> nativeIds = new HashSet<String>(); for (URI uri : uris) { String nativeId; if (URIUtil.isType(uri, Volume.class)) { Volume volume = _dbClient.queryObject(Volume.class, uri); nativeId = volume.getNativeId(); } else if (URIUtil.isType(uri, BlockSnapshot.class)) { BlockSnapshot blockSnapshot = _dbClient.queryObject(BlockSnapshot.class, uri); nativeId = blockSnapshot.getNativeId(); } else if (URIUtil.isType(uri, BlockMirror.class)) { BlockMirror blockMirror = _dbClient.queryObject(BlockMirror.class, uri); nativeId = blockMirror.getAlternateName(); } else { throw DeviceControllerException.exceptions.notAVolumeOrBlocksnapshotUri(uri); } nativeIds.add(nativeId); } return nativeIds.toArray(results); } /** * This method will loop through the URI list and return a list of nativeIds for each of the * BlockObject objects to which the URI applies. * * @param uris * - Collection of URIs * @return Returns a list of nativeId String values * @throws Exception */ public String[] getBlockObjectAlternateNames(Collection<URI> uris) throws Exception { String[] results = {}; List<String> names = new ArrayList<String>(); for (URI uri : uris) { String alternateName = getBlockObjectAlternateName(uri); if (NullColumnValueGetter.isNotNullValue(alternateName) && !names.contains(alternateName)) { names.add(alternateName); } } return names.toArray(results); } public String[] getInitiatorNames(List<Initiator> initiatorList, StorageSystem storageDevice) throws Exception { List<String> initiatorNameList = new ArrayList<String>(); String[] initiatorNames = {}; for (Initiator initiator : initiatorList) { String initiatorName = null; if (initiator.getProtocol().equals("FC")) { if (storageDevice.getUsingSmis80()) { initiatorName = "W+".concat(WWNUtility.getUpperWWNWithNoColons(initiator.getInitiatorPort())); } else { initiatorName = "W+" .concat(WWNUtility.getUpperWWNWithNoColons(initiator.getInitiatorNode().concat(initiator.getInitiatorPort()))); } } else { initiatorName = "I+".concat(initiator.getInitiatorPort()); } initiatorNameList.add(SmisUtils.translate(storageDevice, initiatorName)); } initiatorNames = initiatorNameList.toArray(initiatorNames); return initiatorNames; } public String getExportMaskName(URI exportMaskURI) throws Exception { ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); return exportMask.getMaskName(); } public String getExportMaskResource(URI exportMaskURI) throws Exception { ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); return exportMask.getResource(); } public StringSet getExportMaskDeviceDataMapParameter(URI exportMaskURI, String parameter) throws Exception { ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); if (exportMask.getDeviceDataMap() == null) { return new StringSet(); } return exportMask.getDeviceDataMap().get(parameter); } public String getTieringPolicyName(String autoTierPolicyUri) throws Exception { if (NONE.equalsIgnoreCase(autoTierPolicyUri)) { return NONE; } AutoTieringPolicy policy = _dbClient.queryObject(AutoTieringPolicy.class, URI.create(autoTierPolicyUri)); return policy.getPolicyName(); } public void setProtocolControllerNativeId(URI exportMaskURI, CIMObjectPath protocolController) throws Exception { ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); if (protocolController != null) { CIMProperty<String> storageGroupID = (CIMProperty<String>) protocolController.getKey(CP_DEVICE_ID); exportMask.setNativeId(storageGroupID.getValue()); } else { exportMask.setNativeId(null); } _dbClient.persistObject(exportMask); } public CIMInstance getInstance(StorageSystem storage, CIMObjectPath objectPath, boolean propagated, boolean includeClassOrigin, String[] propertyList) throws Exception { CIMInstance cimInstance = null; CimConnection connection = _cimConnection.getConnection(storage); WBEMClient client = connection.getCimClient(); try { cimInstance = client.getInstance(objectPath, propagated, includeClassOrigin, propertyList); } catch (Exception e) { throw e; } return cimInstance; } /** * This is a wrapper for the WBEMClient enumerateInstances method. * * @param storage * - StorageArray reference, will be used to lookup SMI-S connection * @param namespace * - Namespace to use * @param className * - Name of the class on the provider to query * @param deep * - If true, this specifies that, for each returned Instance of the Class, all * properties of the Instance must be present (subject to constraints imposed by the * other parameters), including any which were added by subclassing the specified * Class. If false, each returned Instance includes only properties defined for the * specified Class in path. * @param localOnly * - If true, only elements values that were instantiated in the instance is * returned. * @param includeClassOrigin * - The class origin attribute is the name of the class that first defined the * property. If true, the class origin attribute will be present for each property on * all returned CIMInstances. If false, the class origin will not be present. * @param propertyList * - An array of property names used to filter what is contained in the instances * returned. Each instance returned only contains elements for the properties of the * names specified. Duplicate and invalid property names are ignored and the request * is otherwise processed normally. An empty array indicates that no properties * should be returned. A null value indicates that all properties should be returned. * @return - CloseableIterator of CIMInstance values representing the instances of the specified * class. * @throws Exception */ public CloseableIterator<CIMInstance> getInstances(StorageSystem storage, String namespace, String className, boolean deep, boolean localOnly, boolean includeClassOrigin, String[] propertyList) throws Exception { CloseableIterator<CIMInstance> cimInstances; CimConnection connection = _cimConnection.getConnection(storage); WBEMClient client = connection.getCimClient(); String classKey = namespace + className; CIMObjectPath cimObjectPath = CIM_OBJECT_PATH_HASH_MAP.get(classKey); if (cimObjectPath == null) { cimObjectPath = CimObjectPathCreator.createInstance(className, namespace); CIM_OBJECT_PATH_HASH_MAP.putIfAbsent(classKey, cimObjectPath); } cimInstances = client.enumerateInstances(cimObjectPath, deep, localOnly, includeClassOrigin, propertyList); return cimInstances; } private String getExportMaskNativeId(URI exportMaskURI) throws Exception { ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); return exportMask.getNativeId(); } private String[] getInitiatorNamesForClariion(List<Initiator> initiatorList) throws Exception { List<String> initiatorNameList = new ArrayList<String>(); String[] initiatorNames = {}; for (Initiator initiator : initiatorList) { String initiatorName = null; if (initiator.getProtocol().equals("FC")) { initiatorName = WWNUtility.getUpperWWNWithNoColons(initiator.getInitiatorNode()).concat(":") .concat(WWNUtility.getUpperWWNWithNoColons(initiator.getInitiatorPort())); } else { initiatorName = initiator.getInitiatorPort(); } initiatorNameList.add(initiatorName); } return initiatorNameList.toArray(initiatorNames); } /** * This method is a wrapper for the getInstance. If the object is not found, it returns a null * value instead of throwing an exception. * * @param storage * [required] - StorageSystem object to which an SMI-S connection would be made * @param objectPath * [required] * @param propagated * [required] * @param includeClassOrigin * [required] * @return CIMInstance object that represents the existing object * @throws Exception */ public CIMInstance checkExists(StorageSystem storage, CIMObjectPath objectPath, boolean propagated, boolean includeClassOrigin) throws Exception { CIMInstance instance = null; try { if (objectPath != null && !objectPath.equals(NULL_CIM_OBJECT_PATH)) { _log.debug(String.format("checkExists(storage=%s, objectPath=%s, propagated=%s, includeClassOrigin=%s)", storage.getSerialNumber(), objectPath.toString(), String.valueOf(propagated), String.valueOf(includeClassOrigin))); instance = getInstance(storage, objectPath, propagated, includeClassOrigin, null); } } catch (WBEMException e) { // If we get an error indicating the object is not found, then // it's okay, we want to return null for this method if (e.getID() != WBEMException.CIM_ERR_NOT_FOUND) { throw e; } } catch (Exception e) { _log.error("checkExists call encountered an exception", e); throw e; } return instance; } public boolean checkVolumeGroupAssociatedWithPolicy(StorageSystem storage, CIMObjectPath volumechildGroupPath, String expectedPolicyName) throws WBEMException { return expectedPolicyName.equalsIgnoreCase(getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, volumechildGroupPath)); } public String getAutoTieringPolicyNameAssociatedWithVolumeGroup(StorageSystem storage, CIMObjectPath volumechildGroupPath) throws WBEMException { String policyName = Constants.NONE; CloseableIterator<CIMObjectPath> tierPolicyPathItr = null; _log.debug("Finding out Fast Policy Associated with Storage Group {}", volumechildGroupPath); try { tierPolicyPathItr = getReference(storage, volumechildGroupPath, CP_TIERPOLICY_APPLIES_TO_ELEMENT, null); while (tierPolicyPathItr.hasNext()) { CIMObjectPath tierPolicySetAppliesToElementPath = tierPolicyPathItr.next(); CIMObjectPath tierPolicyPath = (CIMObjectPath) tierPolicySetAppliesToElementPath .getKey(CP_POLICY_SET).getValue(); policyName = tierPolicyPath.getKey(CP_POLICY_NAME).getValue().toString(); _log.debug("Found Policy Name {} associated with Storage Group {}", policyName, volumechildGroupPath); break; } } finally { closeCIMIterator(tierPolicyPathItr); } return policyName; } /** * Returns whether this object is a cascaded object or not. * * @param storage * storage device * @param path * path of IG, SG, or PG * @return true if the object has child references * @throws WBEMException */ public boolean isCascadedSG(StorageSystem storage, CIMObjectPath path) throws WBEMException { String policyName = Constants.NONE; CloseableIterator<CIMObjectPath> pathItr = null; try { if (checkExists(storage, path, false, false) != null) { pathItr = getReference(storage, path, SE_MEMBER_OF_COLLECTION_DMG_DMG, null); if (!pathItr.hasNext()) { // There are no references in this SG, it is a standalone. return false; } while (pathItr.hasNext()) { CIMObjectPath objPath = pathItr.next(); if (objPath != null) { CIMProperty prop = objPath.getKey(MEMBER); if (prop != null) { CIMObjectPath comparePath = (CIMObjectPath) prop.getValue(); // comparePath tends to have the IP address prepended, path does not. // comparePath: // //10.247.99.71/root/emc:SE_DeviceMaskingGroup.InstanceID="SYMMETRIX+000195701573+ingcl-12_GOLD_SG" // path: // /root/emc:SE_DeviceMaskingGroup.InstanceID="SYMMETRIX+000195701573+ingcl-12_GOLD_SG" if (comparePath != null && comparePath.toString().endsWith(path.toString())) { // There is a cascaded storage group out there that we're the child of. // But we're still a child. return false; } } } } } else { _log.info("Instance not found for path {}. Assuming cascaded.", path); } } catch (Exception e) { _log.info("Got exception trying to retrieve cascade status of SG. Assuming cascaded: ", e); } finally { closeCIMIterator(pathItr); } return true; } /** * Find if IG is cascaded * * @param storage * @param path * @return * @throws WBEMException */ public boolean isCascadedIG(StorageSystem storage, CIMObjectPath path) throws WBEMException { CloseableIterator<CIMObjectPath> pathItr = null; try { if (checkExists(storage, path, false, false) != null) { pathItr = getReference(storage, path, SE_MEMBER_OF_COLLECTION_IMG_IMG, null); if (!pathItr.hasNext()) { // There are no references in this IG, it is a standalone. return false; } while (pathItr.hasNext()) { CIMObjectPath objPath = pathItr.next(); if (objPath != null) { CIMProperty prop = objPath.getKey(MEMBER); if (prop != null) { CIMObjectPath comparePath = (CIMObjectPath) prop.getValue(); if (comparePath != null && comparePath.toString().endsWith(path.toString())) { return false; } } } } } else { _log.info("Instance not found for path {}. Assuming non-cascaded.", path); return false; } } catch (Exception e) { _log.info("Got exception trying to retrieve cascade status of IG. Assuming cascaded: ", e); } finally { closeCIMIterator(pathItr); } return true; } /** * Wrapper for WBEM.referenceNames routine * * @param storageDevice * [required] - StorageSystem object to which an SMI-S connection would be made * @param path * [required] - CIMObjectPath defining the source CIM Object whose referring Objects * are to be returned. This argument may contain either a Class name or the modelpath * of an Instance. * @param resultClass * [optional] - This string MUST either contain a valid CIM Class name or be null. It * filters the Objects returned to contain only the Objects of this Class name or one * of its subclasses. * @param role * [optional] - This string MUST either contain a valid Property name or be null. It * filters the Objects returned to contain only Objects referring to the source * Object via a Property with the specified name. If "Antecedent" is specified, then * only Associations in which the source Object is the "Antecedent" reference are * returned * @return - If successful, a CloseableIterator referencing zero or more CIMObjectPaths of * CIMClasses or CIMInstances meeting the specified criteria. * @throws WBEMException */ public CloseableIterator<CIMObjectPath> getReference(StorageSystem storageDevice, CIMObjectPath path, String resultClass, String role) throws WBEMException { return getConnection(storageDevice).getCimClient().referenceNames(path, resultClass, role); } /** * Wrapper for WBEM.associatorNames routine * * @param storageDevice * [required] * @param path * [required] * @param assocClass * [optional] - assocClass - This string MUST either contain a valid CIM Association * class name or be null. It filters the Objects returned to contain only Objects * associated to the source Object via this CIM Association class or one of its * subclasses. * @param resultClass * [optional] - This string MUST either contain a valid CIM Class name or be null. It * filters the Objects returned to contain only the Objects of this Class name or one * of its subclasses. * @param role * [optional] - role - This string MUST either contain a valid Property name or be * null. It filters the Objects returned to contain only Objects associated to the * source Object via an Association class in which the source Object plays the * specified role. (i.e. the Property name in the Association class that refers to * the source Object matches this value) If "Antecedent" is specified, then only * Associations in which the source Object is the "Antecedent" reference are * examined. * @param resultRole * [optional] - This string MUST either contain a valid Property name or be null. It * filters the Objects returned to contain only Objects associated to the source * Object via an Association class in which the Object returned plays the specified * role. (i.e. the Property name in the Association class that refers to the Object * returned matches this value) If "Dependent" is specified, then only Associations * in which the Object returned is the "Dependent" reference are examined. * @return CloseableIterator - iterator that can be used to enumerate the associatorNames * @throws WBEMException */ public CloseableIterator<CIMObjectPath> getAssociatorNames(StorageSystem storageDevice, CIMObjectPath path, String assocClass, String resultClass, String role, String resultRole) throws WBEMException { return getConnection(storageDevice).getCimClient().associatorNames(path, assocClass, resultClass, role, resultRole); } public CloseableIterator<CIMInstance> getAssociatorInstances(StorageSystem storageDevice, CIMObjectPath path, String assocClass, String resultClass, String role, String resultRole, String[] prop) throws WBEMException { return getConnection(storageDevice).getCimClient().associatorInstances(path, null, resultClass, null, null, false, prop); } public CloseableIterator<CIMObjectPath> getEnumerateInstanceNames( StorageSystem storageDevice, CIMObjectPath path) throws WBEMException { return getConnection(storageDevice).getCimClient().enumerateInstanceNames(path); } public CloseableIterator<CIMInstance> getEnumerateInstances( StorageSystem storageDevice, CIMObjectPath path, String[] prop) throws WBEMException { return getConnection(storageDevice).getCimClient().enumerateInstances(path, true, false, false, prop); } public boolean isStorageGroupSizeGreaterThanGivenVolumes(String groupName, StorageSystem storage, int size) throws Exception { return (getVMAXStorageGroupVolumeCount(storage, groupName) > size); } public int getVMAXStorageGroupVolumeCount(StorageSystem storage, String groupName) throws Exception { int count = 0; CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); CloseableIterator<CIMObjectPath> volumeItr = null; try { volumeItr = getAssociatorNames(storage, maskingGroupPath, null, CIM_STORAGE_VOLUME, null, null); while (volumeItr.hasNext()) { volumeItr.next(); count++; } } finally { closeCIMIterator(volumeItr); } return count; } public boolean findStorageGroupsAssociatedWithMultipleParents( StorageSystem storage, String groupName) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); CloseableIterator<CIMObjectPath> cimPathItr = null; try { _log.debug("Trying to find the parent Storage Groups, on which this group {} resides", groupName); cimPathItr = getAssociatorNames(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null); while (cimPathItr.hasNext()) { // actual parent Group is already deleted in previous step , hence if you find a parent then return // true,which // skips deleting this child group. _log.debug("At least 1 parent Group other than expected parent exists for given child Group {}", groupName); return true; } } finally { closeCIMIterator(cimPathItr); } return false; } public boolean findStorageGroupAChildOfParent( StorageSystem storage, String childgroupName, String parentGroupName) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, parentGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); CloseableIterator<CIMInstance> cimInstanceItr = null; try { cimInstanceItr = getAssociatorInstances(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_ELEMENT_NAME); while (cimInstanceItr.hasNext()) { CIMInstance childGroupInstance = cimInstanceItr.next(); String returnedgroupName = CIMPropertyFactory.getPropertyValue(childGroupInstance, CP_ELEMENT_NAME); if (childgroupName.equalsIgnoreCase(returnedgroupName)) { return true; } } } finally { closeCIMIterator(cimInstanceItr); } return false; } public boolean findStorageGroupsAssociatedWithOtherMaskingViews( StorageSystem storage, String groupName) throws Exception { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); CloseableIterator<CIMObjectPath> cimPathItr = null; try { _log.debug("Trying to find the masking views, on which this group {} resides", groupName); cimPathItr = getAssociatorNames(storage, maskingGroupPath, null, SYMM_LUN_MASKING_VIEW, null, null); while (cimPathItr.hasNext()) { _log.debug("Storage Group {} is part of existing masking view", groupName); return true; } } finally { closeCIMIterator(cimPathItr); } return false; } /** * Use case : Group volumes based on existing child Storage Groups they belong to Algo : Loop * through each Child Storage Group { Loop through each Volume in child Group ,if given volume * found, then the volume gets landed in child Group bucket } Result : Volumes gets landed in * proper child Storage Group buckets. * * @param storage * @param groupName * @param volumeUris * @return * @throws Exception */ public Map<String, List<URI>> groupVolumesBasedOnExistingGroups(StorageSystem storage, String groupName, List<URI> volumeUris) throws Exception { CloseableIterator<CIMInstance> cimInstanceItr = null; CloseableIterator<CIMObjectPath> volumeItr = null; Map<String, List<URI>> volumeGroup = new HashMap<String, List<URI>>(); try { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); /** if no child groups found, then group all volumes to parent Group */ if (!this.isCascadedSG(storage, maskingGroupPath)) { Map<String, URI> volumePaths = getNativeGuidToVolumeUriMap(volumeUris, storage); volumeItr = groupVolumeBasedOnStorageGroup(storage, volumeGroup, volumePaths, maskingGroupPath); return volumeGroup; } /** Generate given Volume NativeGuids to Volume Uri map */ Map<String, URI> volumePaths = getNativeGuidToVolumeUriMap(volumeUris, storage); cimInstanceItr = getAssociatorInstances(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_ELEMENT_NAME); while (cimInstanceItr.hasNext()) { CIMInstance instance = cimInstanceItr.next(); volumeItr = groupVolumeBasedOnStorageGroup(storage, volumeGroup, volumePaths, instance.getObjectPath()); } } finally { closeCIMIterator(cimInstanceItr); closeCIMIterator(volumeItr); } return volumeGroup; } private CloseableIterator<CIMObjectPath> groupVolumeBasedOnStorageGroup( StorageSystem storage, Map<String, List<URI>> volumeGroup, Map<String, URI> volumePaths, CIMObjectPath storageGroupPath) throws Exception { String groupName; CloseableIterator<CIMObjectPath> volumeItr; CIMInstance storageGroupInstance = getInstance(storage, storageGroupPath, false, false, PS_ELEMENT_NAME); groupName = CIMPropertyFactory.getPropertyValue(storageGroupInstance, CP_ELEMENT_NAME); /** Loop through volumes of storage groups */ volumeItr = getAssociatorNames(storage, storageGroupPath, null, CIM_STORAGE_VOLUME, null, null); while (volumeItr.hasNext()) { CIMObjectPath volumePath = volumeItr.next(); String nativeGuid = getVolumeNativeGuid(volumePath); /** * if given volume is found, then it lands in this child Group bucket */ if (volumePaths.containsKey(nativeGuid)) { if (volumeGroup.get(groupName) == null) { volumeGroup.put(groupName, new ArrayList<URI>()); } volumeGroup.get(groupName).add(volumePaths.get(nativeGuid)); } } return volumeItr; } public Map<StorageGroupPolicyLimitsParam, List<String>> groupStorageGroupsByAssociation( StorageSystem storage, String groupName) throws Exception { Map<StorageGroupPolicyLimitsParam, List<String>> groupNames = new HashMap<StorageGroupPolicyLimitsParam, List<String>>(); CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); CloseableIterator<CIMInstance> cimInstanceItr = null; try { _log.info("Trying to find child Storage Groups for given Parent Group {}", groupName); if (storage.checkIfVmax3()) { cimInstanceItr = getAssociatorInstances(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_V3_STORAGE_GROUP_PROPERTIES); if (!cimInstanceItr.hasNext()) { _log.info("Non-Cascaded Storage Group found {}", groupName); CIMInstance maskingGroupInstance = getInstance(storage, maskingGroupPath, false, false, PS_V3_STORAGE_GROUP_PROPERTIES); String policyName = CIMPropertyFactory.getPropertyValue(maskingGroupInstance, CP_FAST_SETTING); if (policyName == null || policyName.isEmpty()) { policyName = Constants.NONE; } StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(policyName); groupNames.put(storageGroupPolicyLimitsParam, new ArrayList<String>()); groupNames.get(storageGroupPolicyLimitsParam).add(groupName); } else { StorageGroupPolicyLimitsParam storageGroupNonePolicyLimitsParam = new StorageGroupPolicyLimitsParam(Constants.NONE); // add cascaded parent Group as well, for deletion groupNames.put(storageGroupNonePolicyLimitsParam, new ArrayList<String>()); groupNames.get(storageGroupNonePolicyLimitsParam).add(groupName); } while (cimInstanceItr.hasNext()) { CIMInstance groupInstance = cimInstanceItr.next(); groupName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); String policyName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_FAST_SETTING); StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = createStorageGroupPolicyLimitsParam(storage, groupInstance); if (null == groupNames.get(storageGroupPolicyLimitsParam)) { groupNames.put(storageGroupPolicyLimitsParam, new ArrayList<String>()); } groupNames.get(storageGroupPolicyLimitsParam).add(groupName); } } else { cimInstanceItr = getAssociatorInstances(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_HOST_IO); if (!cimInstanceItr.hasNext()) { _log.info("Non-Cascaded Storage Group found {}", groupName); CIMInstance groupInstance = getInstance(storage, maskingGroupPath, false, false, PS_HOST_IO); StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = createStorageGroupPolicyLimitsParam(storage, groupInstance); groupNames.put(storageGroupPolicyLimitsParam, new ArrayList<String>()); groupNames.get(storageGroupPolicyLimitsParam).add(groupName); } else { StorageGroupPolicyLimitsParam storageGroupNonePolicyLimitsParam = new StorageGroupPolicyLimitsParam(Constants.NONE); // add cascaded parent Group as well, for deletion groupNames.put(storageGroupNonePolicyLimitsParam, new ArrayList<String>()); // No need to include CSG, as its already handled } while (cimInstanceItr.hasNext()) { CIMInstance groupInstance = cimInstanceItr.next(); String storageGroupName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = createStorageGroupPolicyLimitsParam(storage, groupInstance); if (null == groupNames.get(storageGroupPolicyLimitsParam)) { groupNames.put(storageGroupPolicyLimitsParam, new ArrayList<String>()); } groupNames.get(storageGroupPolicyLimitsParam).add(storageGroupName); } } } finally { closeCIMIterator(cimInstanceItr); } _log.info("Constructed Groups : {}", Joiner.on('\n').withKeyValueSeparator(" -> ").join(groupNames)); return groupNames; } /** * Group volumes based on policy, bandwidth, and IOPs as dictated by the ViPR database objects. * * @param storage * storage device * @param volumeUris * volume URIs * @return a map of storage groups to volumes using that policy, bandwidth, and IOPs * @throws Exception */ public Map<StorageGroupPolicyLimitsParam, List<URI>> groupVolumesBasedOnFastPolicy(StorageSystem storage, List<URI> volumeUris) throws Exception { Map<StorageGroupPolicyLimitsParam, List<URI>> volumeGroup = new HashMap<StorageGroupPolicyLimitsParam, List<URI>>(); Map<URI, VirtualPool> uriVirtualPoolMap = new HashMap<URI, VirtualPool>(); for (URI volumeURI : volumeUris) { String policyName = Constants.NONE; Integer hostIOLimitBandwidth = null; Integer hostIOLimitIOPs = null; if (URIUtil.isType(volumeURI, Volume.class)) { Volume volume = _dbClient.queryObject(Volume.class, volumeURI); VirtualPool virtualPool = uriVirtualPoolMap.get(volume.getVirtualPool()); if (virtualPool == null) { virtualPool = _dbClient.queryObject(VirtualPool.class, volume.getVirtualPool()); uriVirtualPoolMap.put(volume.getVirtualPool(), virtualPool); } String volumePolicyName = ControllerUtils.getAutoTieringPolicyName(volume.getId(), _dbClient); if (volumePolicyName != null) { policyName = volumePolicyName; } hostIOLimitBandwidth = virtualPool.getHostIOLimitBandwidth(); hostIOLimitIOPs = virtualPool.getHostIOLimitIOPs(); } StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(policyName, hostIOLimitBandwidth, hostIOLimitIOPs, storage); if (volumeGroup.get(storageGroupPolicyLimitsParam) == null) { volumeGroup.put(storageGroupPolicyLimitsParam, new ArrayList<URI>()); } volumeGroup.get(storageGroupPolicyLimitsParam).add(volumeURI); _log.info("Adding volumeURI {} to policy {}", volumeURI, storageGroupPolicyLimitsParam); } return volumeGroup; } public Map<String, List<URI>> groupVolumesBasedOnFastPolicy(StorageSystem storage, String policyName, List<URI> volumeUris) throws Exception { Map<String, List<URI>> volumeGroup = new HashMap<String, List<URI>>(); CloseableIterator<CIMInstance> cimInstanceItr = null; CloseableIterator<CIMObjectPath> volumeItr = null; try { CIMObjectPath policyRulepath = _cimPath.getTierPolicyRulePath(storage, policyName); if (Constants.NONE.equalsIgnoreCase(policyName)) { volumeGroup.put(Constants.NONE, volumeUris); return volumeGroup; } cimInstanceItr = getAssociatorInstances(storage, policyRulepath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_ELEMENT_NAME); /** if no child groups found, then group all volumes to parent Group */ if (!cimInstanceItr.hasNext()) { volumeGroup.put(Constants.NONE, volumeUris); return volumeGroup; } /** Generate given Volume NativeGuids to Volume Uri map */ Map<String, URI> volumePaths = getNativeGuidToVolumeUriMap(volumeUris, storage); while (cimInstanceItr.hasNext()) { CIMInstance groupInstance = cimInstanceItr.next(); String groupName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); /** Loop through volumes of storage groups */ volumeItr = getAssociatorNames(storage, groupInstance.getObjectPath(), null, CIM_STORAGE_VOLUME, null, null); while (volumeItr.hasNext()) { CIMObjectPath volumePath = volumeItr.next(); String nativeGuid = getVolumeNativeGuid(volumePath); /** * if given volume is found, then it lands in thhis child Group bucket */ if (volumePaths.containsKey(nativeGuid)) { if (!volumeGroup.containsKey(groupName)) { volumeGroup.put(groupName, new ArrayList<URI>()); } volumeGroup.get(groupName).add(volumePaths.get(nativeGuid)); } } } } finally { closeCIMIterator(volumeItr); closeCIMIterator(cimInstanceItr); } return volumeGroup; } /** * Generate NativeGuid-->Volume uri mapping using volume uris list. * * @param volumeUris * @param storage * @return * @throws IOException */ private Map<String, URI> getNativeGuidToVolumeUriMap( List<URI> volumeUris, StorageSystem storage) throws IOException { Map<String, URI> volumePaths = new HashMap<String, URI>(); for (URI volumeUri : volumeUris) { String nativeGuid = null; if (URIUtil.isType(volumeUri, Volume.class)) { Volume volume = _dbClient.queryObject(Volume.class, volumeUri); nativeGuid = NativeGUIDGenerator.generateNativeGuid(_dbClient, volume); } else if (URIUtil.isType(volumeUri, BlockSnapshot.class)) { BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, volumeUri); nativeGuid = NativeGUIDGenerator.generateNativeGuid(storage, snapshot); } else if (URIUtil.isType(volumeUri, BlockMirror.class)) { BlockMirror mirror = _dbClient.queryObject(BlockMirror.class, volumeUri); nativeGuid = NativeGUIDGenerator.generateNativeGuid(storage, mirror); } volumePaths.put(nativeGuid, volumeUri); } return volumePaths; } /** * Algo : FastPolicy F1 ---> V1, V2 FastPolicy F2 ---> V3, V4 Use case : Add these volumes to * existing Storage Group S1. 1. Find out the child Groups for given parent Group S1. 2. For * each child Group, if its associated with Fast, get its policy name. CH1 --->F1 Now the * resultant group would be CH1--->V1,V2 3. After looping through all child Storage Groups, if * you still didn't encounter F2, then it means we need to create a new Storage Group CH2 and * associate with F2. 4. Final result would be Volumes get grouped by child Storage Group Names. * * @param storage * storage system * @param parentGroupName * parent storage group name * @param policyToVolumeMap * map of FAST policy to volume objects * @return group of storage group to volume objects * @throws Exception */ public Map<String, Collection<VolumeURIHLU>> groupVolumesByStorageGroup(StorageSystem storage, String parentGroupName, DataSource sgDataSource, String sgCustomTemplateName, ListMultimap<StorageGroupPolicyLimitsParam, VolumeURIHLU> policyLimitsParamToVolumeGroup, CustomConfigHandler customConfigHandler) throws Exception { Map<String, Collection<VolumeURIHLU>> volumeGroup = new HashMap<String, Collection<VolumeURIHLU>>(); CloseableIterator<CIMInstance> cimInstanceItr = null; try { boolean isVmax3 = storage.checkIfVmax3(); CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, parentGroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); // If we were sent a single non-cascading storage group, keep the algorithm simple. // Make sure the policy matches ours, if so grab the volumes. if (!isCascadedSG(storage, maskingGroupPath)) { // TODO: Add VMAX3 check and get fast policy for VMAX3 volume. String policyName = getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, maskingGroupPath); volumeGroup.put(parentGroupName, new ArrayList<VolumeURIHLU>()); for (Entry<StorageGroupPolicyLimitsParam, Collection<VolumeURIHLU>> policyToVolumeEntry : policyLimitsParamToVolumeGroup .asMap().entrySet()) { if (policyName != null && policyName.equalsIgnoreCase(Constants.NONE.toString())) { policyName = null; } String volumePolicy = policyToVolumeEntry.getKey().getAutoTierPolicyName(); if (volumePolicy != null && volumePolicy.equalsIgnoreCase(Constants.NONE.toString())) { volumePolicy = null; } if ((policyName == null && volumePolicy == null) || (policyName != null && policyName.equalsIgnoreCase(volumePolicy))) { volumeGroup.get(parentGroupName).addAll(policyToVolumeEntry.getValue()); } // Exception to the rule: If we are looking to place a FAST volume, and we have a flat // (non-cascaded) SG, // We want to be in the map as well. if (volumePolicy != null && policyName == null) { volumeGroup.get(parentGroupName).addAll(policyToVolumeEntry.getValue()); } } if (!volumeGroup.get(parentGroupName).isEmpty()) { _log.info("Storage Group {} is not a cascading group, hence grouping all volumes under parent group.", parentGroupName); return volumeGroup; } } _log.info("Trying to find child Storage Groups for given Parent Group {}", parentGroupName); /** get list of child storage groups */ if (isVmax3) { cimInstanceItr = getAssociatorInstances(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_V3_STORAGE_GROUP_PROPERTIES); } else { cimInstanceItr = getAssociatorInstances(storage, maskingGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, new String[] { CP_ELEMENT_NAME, EMC_MAX_BANDWIDTH, EMC_MAX_IO }); } Set<StorageGroupPolicyLimitsParam> storageGroupPolicyLimitsParamSet = new HashSet<StorageGroupPolicyLimitsParam>(); /** * Loop through each Storage Group, find if its associated with fast Policy, limit bandwidth, and limit IO. * Try to look * up the given policyToVolumeMap data, to find out the right storage group bucket for * these volumes */ Map<String, Integer> preferedChildGroupMap = new HashMap<String, Integer>(); Map<StorageGroupPolicyLimitsParam, String> preferedPolicyLimitsParamToChildGroup = new HashMap<StorageGroupPolicyLimitsParam, String>(); while (cimInstanceItr.hasNext()) { CIMInstance childGroupInstance = cimInstanceItr.next(); String groupName = CIMPropertyFactory.getPropertyValue(childGroupInstance, CP_ELEMENT_NAME); /** * Get the properties (policyName, Bandwidth,IOPS) associated with this Storage Group */ StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = createStorageGroupPolicyLimitsParam(storage, childGroupInstance); _log.info("Group Name {} is associated with Fast Policy : {}", groupName, storageGroupPolicyLimitsParam.getAutoTierPolicyName()); // Count the number of volumes in this group. Lowest number of volumes in the storage // group for that child storage group wins. Integer numVolumes = getVMAXStorageGroupVolumeCount(storage, groupName); String policyLimitAttribute = storageGroupPolicyLimitsParam.toString(); // This will identify the storage group with the lowest number of volumes and store the group name and // policy limit params // for that group name. if ((preferedChildGroupMap.get(policyLimitAttribute) == null) || ((preferedChildGroupMap.get(policyLimitAttribute) != null) && (numVolumes < preferedChildGroupMap.get(policyLimitAttribute)))) { preferedChildGroupMap.put(policyLimitAttribute, numVolumes); preferedPolicyLimitsParamToChildGroup.put(storageGroupPolicyLimitsParam, groupName); } } // Now place the volumes in the respective storage group. for (StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam : preferedPolicyLimitsParamToChildGroup.keySet()) { if (policyLimitsParamToVolumeGroup.containsKey(storageGroupPolicyLimitsParam) && !storageGroupPolicyLimitsParamSet.contains(storageGroupPolicyLimitsParam)) { volumeGroup.put(preferedPolicyLimitsParamToChildGroup.get(storageGroupPolicyLimitsParam), policyLimitsParamToVolumeGroup.get(storageGroupPolicyLimitsParam)); storageGroupPolicyLimitsParamSet.add(storageGroupPolicyLimitsParam); } } _log.info("Storage Group exists already for given volume's fast Policies -->{}", Joiner.on("\t").join(storageGroupPolicyLimitsParamSet)); Set<String> existingGroupNames = getExistingStorageGroupsFromArray(storage); /** * At this point, volumes with expected fast policies might have been already grouped. A * new group needs to be created, for each remaining volumes, if non-fast. If fast * enabled, then run Storage Group Selection Process to find any existing Storage Groups * can be reused, if not, create a new storage group. */ /** * At this point, we have the list of the volume groups (FP + bandwidth+IOPS), which has a Storage Group. * For the remaining volume groups, we need to create a new Storage Group. * * No changes needed */ for (Entry<StorageGroupPolicyLimitsParam, Collection<VolumeURIHLU>> policyToVolumeEntry : policyLimitsParamToVolumeGroup .asMap().entrySet()) { StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = policyToVolumeEntry.getKey(); if (!storageGroupPolicyLimitsParamSet.contains(storageGroupPolicyLimitsParam)) { _log.debug("Policy {} to which new Storage Group needs to be created", storageGroupPolicyLimitsParam); ListMultimap<String, VolumeURIHLU> expectedVolumeHluMap = ControllerUtils .getVolumeNativeGuids(policyToVolumeEntry.getValue(), _dbClient); if (!StringUtils.equalsIgnoreCase(storageGroupPolicyLimitsParam.getAutoTierPolicyName(), Constants.NONE)) { _log.info("Running Storage Group Selection Process to find out if any groups can be reused"); Map<String, Set<String>> existingReusableGroups = findAnyStorageGroupsCanBeReUsed(storage, expectedVolumeHluMap, storageGroupPolicyLimitsParam); // add existing group names, use later to add these // groups to parent Cascaded Group. _log.info("Existing Reusable Storage Groups Found {}", Joiner.on("\t").join(existingReusableGroups.keySet())); for (String group : existingReusableGroups.keySet()) { volumeGroup.put(group, null); } // find out remaining volumes which doesn't have any // groups to fit into Set<String> volumesInReusableStorageGroups = constructVolumeNativeGuids(existingReusableGroups .values()); Set<String> volumesNotPartOfAnyGroup = Sets.difference(expectedVolumeHluMap .asMap().keySet(), volumesInReusableStorageGroups); _log.debug("Volumes not part of any Existing Storage Groups {}", Joiner.on("\t").join(volumesNotPartOfAnyGroup)); // create a new group for volumes, which doesn't have // right storage groups if (!volumesNotPartOfAnyGroup.isEmpty()) { _log.info("Creating an new Volume Group for these Volumes"); VolumeURIHLU[] volumeURIHLU = ControllerUtils.constructVolumeUriHLUs( volumesNotPartOfAnyGroup, expectedVolumeHluMap); sgDataSource.addProperty(CustomConfigConstants.AUTO_TIERING_POLICY_NAME, storageGroupPolicyLimitsParam.toString()); String storageGroupName = customConfigHandler.getComputedCustomConfigValue(sgCustomTemplateName, storage.getSystemType(), sgDataSource); String generatedGroupName = generateGroupName(existingGroupNames, storageGroupName); volumeGroup.put( generatedGroupName, Arrays.asList(volumeURIHLU)); } } else { // TODO check if this need to taken care off for VMAX3 as volumes will have policy name _log.info("Creating a new Storage Group always, as non fast"); sgDataSource.addProperty(CustomConfigConstants.AUTO_TIERING_POLICY_NAME, StorageGroupPolicyLimitsParam.NON_FAST_POLICY); String storageGroupName = customConfigHandler.getComputedCustomConfigValue(sgCustomTemplateName, storage.getSystemType(), sgDataSource); String generatedGroupName = generateGroupName(existingGroupNames, storageGroupName); volumeGroup.put(generatedGroupName, policyToVolumeEntry.getValue()); } } } } finally { closeCIMIterator(cimInstanceItr); } return volumeGroup; } /** * generate Group Name based on policy and host settings, which doesn't exist in array already. * * @param storageGroupPolicyLimitsParam * @param existingGroupNames * @param parentGroupName * @return */ public String generateGroupName(Set<String> existingGroupNames, String storageGroupName) { // replace "+" in the group name with "-" to make sure that we do not hit limitation on vmax3 for group names with // "+" and do not return false positive here for such a mask. For example, mask with "+"s does not exist on array, but // when we replace "+"s bu "_"s we hit the existing mask on device. We will also convert them to lower case to avoid // hitting case sensitive issue during the search String storageGroupNameTemp = storageGroupName.replaceAll(Constants.SMIS_PLUS_REGEX, Constants.HYPHEN); _log.info("Converted storage group name from {} to {} .", storageGroupName, storageGroupNameTemp); String result = storageGroupNameTemp; // Is 'storageGroupName' already in the list of existing names? if (existingGroupNames.contains(storageGroupNameTemp.toLowerCase())) { // Yes -- name is already in the existing group name list. We're going to have to generate a unique name by // using an appended // numeric index. The format will be storageGroupName_<[N]>, where N is a number between 1 and the size of // existingGroupNames. int size = existingGroupNames.size(); for (int index = 1; index <= size; index++) { // Generate an indexed name ... result = String.format("%s_%d", storageGroupNameTemp, index); // If the indexed name does not exist, then exit the loop and return 'result' if (!existingGroupNames.contains(result.toLowerCase())) { break; } } } _log.info(String.format("generateGroupName(existingGroupNames.size = %d, %s), returning %s", existingGroupNames.size(), storageGroupNameTemp, result)); return result; } /** * TODO: VMAX3 Customized names * generate Group Names which doesn't exist in array already. * * @param count * @param existingGroupNames * @param parentGroupName * @return */ public String generateGroupName(String policyName, Set<String> existingGroupNames, String parentGroupName) { int count = 0; String format = null; while (count <= existingGroupNames.size()) { if (0 == count) { format = String.format("SG_%s", policyName); } else { format = String.format("SG_%s_%d", policyName, count); } String generatedGroupName = generate(parentGroupName, format, SmisConstants.MASK_NAME_DELIMITER, SmisConstants.MAX_STORAGE_GROUP_NAME_LENGTH); if (!existingGroupNames.contains(generatedGroupName)) { return generatedGroupName; } count++; } // we will not hit this scenario any time in a real case. return generate(parentGroupName, String.format("SG1_%s", policyName), SmisConstants.MASK_NAME_DELIMITER, SmisConstants.MAX_STORAGE_GROUP_NAME_LENGTH); } /** * get SGs from Array. I hit a failure in this query off and on during my testing, * so I am using this method for a small retry method. * * @param storage * storage system * @return set of storage group names */ public Map<StorageGroupPolicyLimitsParam, Set<String>> getExistingSGNamesFromArray(StorageSystem storage) { CloseableIterator<CIMInstance> groupInstanceItr = null; Map<StorageGroupPolicyLimitsParam, Set<String>> storageGroups = new HashMap<StorageGroupPolicyLimitsParam, Set<String>>(); final int RETRY_COUNT = 5; final int RETRY_SLEEP_MS = 5000; int retry = 0; while (retry < RETRY_COUNT) { try { CIMObjectPath deviceMaskingGroupPath = CimObjectPathCreator.createInstance( SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), ROOT_EMC_NAMESPACE); groupInstanceItr = getEnumerateInstances(storage, deviceMaskingGroupPath, new String[] { CP_ELEMENT_NAME, EMC_MAX_BANDWIDTH, EMC_MAX_IO }); while (groupInstanceItr.hasNext()) { CIMInstance groupInstance = groupInstanceItr.next(); CIMObjectPath groupPath = groupInstance.getObjectPath(); // skipping device masking groups other than belong to expected // storage system if (!groupPath.toString().contains(storage.getSerialNumber())) { continue; } String policyName = getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, groupPath); String groupName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); String hostIOLimitBandwidth = CIMPropertyFactory.getPropertyValue(groupInstance, EMC_MAX_BANDWIDTH); String hostIOLimitIOPs = CIMPropertyFactory.getPropertyValue(groupInstance, EMC_MAX_IO); StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(policyName, hostIOLimitBandwidth, hostIOLimitIOPs, storage); Set<String> storageGroupNames = storageGroups.get(storageGroupPolicyLimitsParam); if (storageGroupNames == null) { storageGroupNames = new HashSet<String>(); storageGroups.put(storageGroupPolicyLimitsParam, storageGroupNames); } storageGroupNames.add(groupName); } _log.debug("Existing Group Names on Array : {}", Joiner.on("\t").join(storageGroups.values())); return storageGroups; } catch (Exception e) { _log.warn("Get Existing SG Names failed", e); if (retry <= RETRY_COUNT) { _log.warn(String.format("Going to retry (%d out of %d tries) SG name query in %s milliseconds", retry + 1, RETRY_COUNT, RETRY_SLEEP_MS)); try { Thread.sleep(RETRY_SLEEP_MS); } catch (InterruptedException e1) { // ignore } } } finally { closeCIMIterator(groupInstanceItr); } retry++; } _log.debug("Existing Group Names on Array : {}", Joiner.on("\t").join(storageGroups.values())); return storageGroups; } /** * Get Existing Storage Group Names * * @param storage * @return */ public Set<String> getExistingStorageGroupsFromArray(StorageSystem storage) { CloseableIterator<CIMInstance> groupInstanceItr = null; Set<String> storageGroupNames = new HashSet<String>(); try { CIMObjectPath storageGroupPath = CimObjectPathCreator.createInstance( SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), ROOT_EMC_NAMESPACE); groupInstanceItr = getEnumerateInstances(storage, storageGroupPath, SmisConstants.PS_ELEMENT_NAME); while (groupInstanceItr.hasNext()) { CIMInstance groupInstance = groupInstanceItr.next(); storageGroupNames.add((groupInstance.getPropertyValue(CP_ELEMENT_NAME).toString()).toLowerCase()); } } catch (Exception e) { _log.warn("Get Existing port Group Names failed", e); } finally { closeCIMIterator(groupInstanceItr); } return storageGroupNames; } /** * Determines which of the passed volumes is in a storage group that is not a * parking storage group. * * @param storage A reference to the storage system. * @param volumeURIs The URIs of the volumes to check. * * @return The URIs of the volumes in non parking storage groups mapped by storage group name. */ public Map<String, List<URI>> getVolumesInNonParkingStorageGroup(StorageSystem storage, List<URI> volumeURIs) { CloseableIterator<CIMInstance> storageGroupInstanceItr = null; Map<String, List<URI>> storageGroupMap = new HashMap<>(); try { CIMObjectPath storageGroupPath = CimObjectPathCreator.createInstance( SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), ROOT_EMC_NAMESPACE); storageGroupInstanceItr = getEnumerateInstances(storage, storageGroupPath, SmisConstants.PS_ELEMENT_NAME); while (storageGroupInstanceItr.hasNext()) { CIMInstance storageGroupInstance = storageGroupInstanceItr.next(); String storageGroupName = storageGroupInstance.getPropertyValue(CP_ELEMENT_NAME).toString(); // Parking storage groups starts with "ViPR_". if (storageGroupName.startsWith(Constants.STORAGE_GROUP_PREFIX)) { continue; } List<URI> volumesInStorageGroup = findVolumesInStorageGroup(storage, storageGroupName, volumeURIs); if (volumesInStorageGroup != null && !volumesInStorageGroup.isEmpty()) { storageGroupMap.put(storageGroupName, volumesInStorageGroup); } } } catch (Exception e) { _log.warn("Get export mask volumes in non parking storage groups failed", e); } finally { closeCIMIterator(storageGroupInstanceItr); } return storageGroupMap; } /** * Get Existing Port Group Names * * @param storage * @return */ public Set<String> getExistingPortGroupsFromArray(StorageSystem storage) { CloseableIterator<CIMInstance> groupInstanceItr = null; Set<String> portGroupNames = new HashSet<String>(); try { CIMObjectPath portMaskingGroupPath = CimObjectPathCreator.createInstance( SmisCommandHelper.MASKING_GROUP_TYPE.SE_TargetMaskingGroup.name(), ROOT_EMC_NAMESPACE); groupInstanceItr = getEnumerateInstances(storage, portMaskingGroupPath, SmisConstants.PS_ELEMENT_NAME); while (groupInstanceItr.hasNext()) { CIMInstance groupInstance = groupInstanceItr.next(); portGroupNames.add((groupInstance.getPropertyValue(CP_ELEMENT_NAME).toString()).toLowerCase()); } } catch (Exception e) { _log.warn("Get Existing port Group Names failed", e); } finally { closeCIMIterator(groupInstanceItr); } return portGroupNames; } /** * Get Existing Initiator Group Names from Array * * @param storage * @return */ public Set<String> getExistingInitiatorGroupsFromArray(StorageSystem storage) { CloseableIterator<CIMInstance> groupInstanceItr = null; Set<String> initiatorGroupNames = new HashSet<String>(); try { CIMObjectPath portMaskingGroupPath = CimObjectPathCreator.createInstance( SmisCommandHelper.MASKING_GROUP_TYPE.SE_InitiatorMaskingGroup.name(), ROOT_EMC_NAMESPACE); groupInstanceItr = getEnumerateInstances(storage, portMaskingGroupPath, SmisConstants.PS_ELEMENT_NAME); while (groupInstanceItr.hasNext()) { CIMInstance groupInstance = groupInstanceItr.next(); initiatorGroupNames.add((groupInstance.getPropertyValue(CP_ELEMENT_NAME).toString()).toLowerCase()); } } catch (Exception e) { _log.warn("Get Existing initiator Group Names failed", e); } finally { closeCIMIterator(groupInstanceItr); } return initiatorGroupNames; } /** * Giver 2 strings: str1 and str2, this method concatenates them by using the delimeter * and restricting the size of the resulting string to maxLength. * * Did not want to use NameGenerator._generate as that takes three inputs and if the third input * is null it appends a random UUID - which we do not want in the users of this method. */ public String generate(String str1, String str2, char delimiter, int maxLength) { return _nameGenerator.generate(str1, str2, null, delimiter, maxLength); } public String getVolumeNativeGuid(CIMObjectPath path) { String systemName = path.getKey(CP_SYSTEM_NAME).getValue().toString(); systemName = systemName.replaceAll(Constants.SMIS80_DELIMITER_REGEX, Constants.PLUS); String id = path.getKey(CP_DEVICE_ID).getValue().toString(); return NativeGUIDGenerator.generateNativeGuidForVolumeOrBlockSnapShot( systemName.toUpperCase(), id); } public String getVolumeDeviceId(CIMObjectPath path) { String id = path.getKey(CP_DEVICE_ID).getValue().toString(); return id; } public String getConsistencyGroupName(final BlockConsistencyGroup group, final StorageSystem storageSystem) { String groupName = null; if (group != null && storageSystem != null) { groupName = group.getCgNameOnStorageSystem(storageSystem.getId()); } return groupName; } public boolean findReplicationGroupPartOfSRDFRelationShip(final CIMObjectPath replicationGroupPath, final StorageSystem forProvider, final StorageSystem system) { CloseableIterator<CIMObjectPath> names = null; try { names = getAssociatorNames(forProvider, replicationGroupPath, null, SE_GROUP_SYNCHRONIZED_RG_RG, null, null); if (names.hasNext()) { return true; } } catch (WBEMException e) { _log.error("findReplicationGroupPartOfSRDFRelationShip -- WBEMException: ", e); } finally { closeCIMIterator(names); } return false; } /** * This is wrapper of the WBEM modifyIstance interface * * @param storage * [required] - StorageSystem object representing the array * @param instance * [required] - CIMInstance * @param properties * [required] - Names of properties to update their values * @throws WBEMException */ public void modifyInstance(StorageSystem storage, CIMInstance instance, String[] properties) throws WBEMException { getConnection(storage).getCimClient().modifyInstance(instance, properties); } public static String getPrefix(StorageSystem storage) { String prefix = ""; if (storage.getSystemType().equals(StorageSystem.Type.vmax.name())) { prefix = VMAX_PREFIX; } else if (storage.getSystemType().equals(StorageSystem.Type.vnxblock.name())) { prefix = VNX_PREFIX; } return prefix; } private static int getArrayType(StorageSystem storage) { int type; if (storage.getSystemType().equals(StorageSystem.Type.vnxblock.name())) { type = 1; } else if (storage.getSystemType().equals(StorageSystem.Type.vmax.name())) { type = 2; } else { type = 0; } return type; } public static String getSmisStorageDeviceName(StorageSystem storage) { return getPrefix(storage) + "SmisDevice"; } /** * Simple puts the thread to sleep for the passed duration. * * @param duration * How long to pause in milliseconds. */ static void pauseThread(long duration) { try { Thread.sleep(duration); } catch (Exception e) { _log.warn("Exception while trying to sleep", e); } } /** * FIXME * This method is a temporary alternative to the one below and * removes the initial waiting time (~3 minutes) before refreshing. * * The wait time is deemed unnecessary because the Provider will attempt * to consolidate its sync requests. * * Still, there appears to be a requirement for waiting an arbitrary amount of * time *after* the refresh call in order for subsequent associator calls to * get correct data. * * @param storage * @return * @throws WBEMException */ public Object callRefreshSystem(StorageSystem storage) throws WBEMException { Object result = null; String lockKey = String.format("callRefreshSystem-%s", storage.getId().toString()); try { if (_locker.acquireLock(lockKey, MAX_REFRESH_LOCK_WAIT_TIME)) { CIMObjectPath seSystemRegistrationSvc = getRegistrationService(storage); UnsignedInteger32[] syncType = new UnsignedInteger32[] { new UnsignedInteger32(REPLICATION_DATA_SYNC_TYPE), new UnsignedInteger32(DEVICES_SYNC_TYPE), new UnsignedInteger32(MASKING_SYNC_TYPE) }; CIMObjectPath[] systems = new CIMObjectPath[] { _cimPath.getStorageSystem(storage) }; CIMArgument[] refreshArgs = new CIMArgument[] { _cimArgument.uint32Array(CP_SYNC_TYPE, syncType), _cimArgument.referenceArray(CP_SYSTEMS, systems) }; CIMArgument[] outArgs = new CIMArgument[5]; result = invokeMethod(storage, seSystemRegistrationSvc, EMC_REFRESH_SYSTEM, refreshArgs, outArgs); long currentMillis = Calendar.getInstance().getTimeInMillis(); storage.setLastRefresh(currentMillis); _dbClient.updateObject(storage); _log.info(String.format("Did EMCRefresh against StorageSystem %s. " + "Last refresh set to %d", storage.getNativeGuid(), currentMillis)); } } finally { _locker.releaseLock(lockKey); } return result; } public Object callRefreshSystem(StorageSystem storage, SimpleFunction toCallAfterRefresh) throws WBEMException { return callRefreshSystem(storage, toCallAfterRefresh, false); } public Object callRefreshSystem(StorageSystem storage, SimpleFunction toCallAfterRefresh, boolean force) throws WBEMException { Object result = null; String lockKey = String.format("callRefreshSystem-%s", storage.getId().toString()); try { if (_locker.acquireLock(lockKey, MAX_REFRESH_LOCK_WAIT_TIME)) { storage = _dbClient.queryObject(StorageSystem.class, storage.getId()); long currentMillis = Calendar.getInstance().getTimeInMillis(); long deltaLastRefreshValue = currentMillis - storage.getLastRefresh(); if (deltaLastRefreshValue < REFRESH_THRESHOLD && force) { // In case of SRDF Active mode resume operation, its possible that second call // to refreshSystem might be done where REFRESH_THRESHOLD value might not be met so we // will pause thread for the remainder of the time as we need to make sure refresh // system is executed to be able to get correct access state for the target volumes. long sleepDuration = REFRESH_THRESHOLD - deltaLastRefreshValue; _log.info(String.format("Sleep for %d msecs before calling refresh because last " + "refresh was done %d msecs ago", sleepDuration, deltaLastRefreshValue)); pauseThread(sleepDuration); currentMillis = Calendar.getInstance().getTimeInMillis(); deltaLastRefreshValue = currentMillis - storage.getLastRefresh(); } // Do a basic calculation of how long we had to wait for the // acquireLock to finish. If were waiting for a long time, then // presumably the deltaLastRefreshValue would be non-zero and much // more than a few milliseconds. If it is beyond our threshold, // then we will assume that the refresh needs to be done. Otherwise, // there were multiple threads (possibly on different nodes) attempting // the refresh at the same time and hence it is not necessary to run it // again so soon. if (deltaLastRefreshValue >= REFRESH_THRESHOLD) { _log.info(String.format("Difference between current time %d and " + "lastRefresh %d is %d, greater than or equal to threshold %d - will " + "attempt EMCRefresh", currentMillis, storage.getLastRefresh(), deltaLastRefreshValue, REFRESH_THRESHOLD)); CIMObjectPath seSystemRegistrationSvc = getRegistrationService(storage); UnsignedInteger32[] syncType = new UnsignedInteger32[] { new UnsignedInteger32(REPLICATION_DATA_SYNC_TYPE), new UnsignedInteger32(DEVICES_SYNC_TYPE) }; CIMObjectPath[] systems = new CIMObjectPath[] { _cimPath.getStorageSystem(storage) }; CIMArgument[] refreshArgs = new CIMArgument[] { _cimArgument.uint32Array(CP_SYNC_TYPE, syncType), _cimArgument.referenceArray(CP_SYSTEMS, systems) }; CIMArgument[] outArgs = new CIMArgument[5]; result = invokeMethod(storage, seSystemRegistrationSvc, EMC_REFRESH_SYSTEM, refreshArgs, outArgs); currentMillis = Calendar.getInstance().getTimeInMillis(); storage.setLastRefresh(currentMillis); _dbClient.persistObject(storage); _log.info(String.format("Did EMCRefresh against StorageSystem %s. " + "Last refresh set to %d", storage.getNativeGuid(), currentMillis)); if (toCallAfterRefresh != null) { toCallAfterRefresh.call(); } } else { _log.info(String.format("Did not run EMCRefresh against " + "StorageSystem %s because it was done %d msecs ago, " + "which is within in the refresh threshold %d", storage.getNativeGuid(), deltaLastRefreshValue, REFRESH_THRESHOLD)); } } else { _log.info(String.format("Could not get the EMCRefresh lock after %d seconds.", MAX_REFRESH_LOCK_WAIT_TIME)); } } finally { _locker.releaseLock(lockKey); } return result; } public CIMObjectPath getRegistrationService(StorageSystem storage) throws WBEMException { return _cimPath.getSeSystemRegistrationService(storage); } public CIMArgument[] getAddStorageCIMArguments(StorageSystem storage) throws WBEMException { String[] ips; UnsignedInteger16[] types; if (storage.getSecondaryIPs() == null) { ips = new String[] { storage.getIpAddress() }; types = new UnsignedInteger16[] { new UnsignedInteger16(2) }; } else { ips = new String[storage.getSecondaryIPs().size() + 1]; types = new UnsignedInteger16[ips.length]; ips[0] = storage.getIpAddress(); types[0] = new UnsignedInteger16(2); int idx = 1; for (String ip : storage.getSecondaryIPs()) { ips[idx] = ip; types[idx] = new UnsignedInteger16(2); idx++; } } CIMArgument[] addSysArgs = new CIMArgument[] { _cimArgument.uint16("ArrayType", getArrayType(storage)), _cimArgument.stringArray("Addresses", ips), _cimArgument.uint16Array("Types", types), _cimArgument.string("User", storage.getUsername()), _cimArgument.string("Password", storage.getPassword()) }; return addSysArgs; } public CIMArgument[] getRemStorageCIMArguments(StorageSystem storage) throws WBEMException { return new CIMArgument[] { _cimArgument.reference("System", _cimPath.getStorageSystem(storage)) }; } public CIMArgument[] getCreateSynchronizationAspectForGroupInput(CIMObjectPath replicationGroup, boolean skipRefresh, String name, Integer mode) { return getCreateSynchronizationAspectInput(replicationGroup, skipRefresh, name, mode, CP_SOURCE_GROUP); } public CIMArgument[] getCreateSynchronizationAspectInput(CIMObjectPath sourcePath, boolean skipRefresh, String name, Integer mode) { return getCreateSynchronizationAspectInput(sourcePath, skipRefresh, name, mode, CP_SOURCE_ELEMENT); } /** * Get the SMI-S input arguments when creating a CIM_SynchronizedAspectForSource, i.e, * an array snapshot point-in-time copy, for the source with the passed path. * * @param sourcePath * The CIM object path for the array snapshot source. * @param skipRefresh * true if the skipRefresh argument should be included. * @param name * The name for the array snapshot, or null for no name. * @param mode * The update mode, or null. * @param sourceParameter * Parameter specifying either SourceElement or SourceGroup * * @return An array of CIMArgument */ public CIMArgument[] getCreateSynchronizationAspectInput(CIMObjectPath sourcePath, boolean skipRefresh, String name, Integer mode, String sourceParameter) { List<CIMArgument> argList = new ArrayList<CIMArgument>(); argList.add(_cimArgument.uint16(CP_SYNC_TYPE, SNAPSHOT_VALUE)); argList.add(_cimArgument.reference(sourceParameter, sourcePath)); // If skip refresh, add argument. if (skipRefresh) { argList.add(_cimArgument.bool(CP_EMC_SKIP_REFRESH, true)); } // Add argument if name is specified. if (name != null) { argList.add(_cimArgument.string(CP_NAME, name)); } // Add argument if mode is specified. if (mode != null) { argList.add(_cimArgument.uint16(CP_MODE, mode.intValue())); } return argList.toArray(new CIMArgument[argList.size()]); } public CIMArgument[] getDeleteStorageHardwareIDArgs(StorageSystem storage, Initiator initiator) throws Exception { String[] initiatorNames = getInitiatorNames(Arrays.asList(initiator), storage); CIMObjectPath[] initiators = _cimPath.getInitiatorPaths(storage, initiatorNames); return new CIMArgument[] { _cimArgument.reference(CP_HARDWARE_ID, initiators[0]) }; } public CloseableIterator<CIMInstance> getSymmLunMaskingViews(StorageSystem storage) throws Exception { return getLunMaskingProtocolControllers(storage, SYMM_LUN_MASKING_VIEW); } public CIMInstance getSymmLunMaskingView(StorageSystem storage, ExportMask mask) throws Exception { return getInstance(storage, _cimPath.getMaskingViewPath(storage, mask.getMaskName()), false, true, null); } /** * Returns a CloseableIterator for ClarLunMaskingProtocolController CIMInstance objects. NOTE: * This will return all instances from all arrays that the SMISProvider upon which the 'storage' * system is managed. * * @param storage * [in] - StorageSystem object. Used to look up SMIS connection. * @return CloseableIterator of CIMInstance objects * @throws Exception */ public CloseableIterator<CIMInstance> getClarLunMaskingProtocolControllers(StorageSystem storage) throws Exception { return getLunMaskingProtocolControllers(storage, CLAR_LUN_MASKING_SCSI_PROTOCOL_CONTROLLER); } /** * Returns a CloseableIterator for protocol controller CIMInstance objects. NOTE: This will * return all instances from all arrays that the SMISProvider upon which the 'storage' system is * managed. * * @param storage * [in] - StorageSystem object. Used to look up SMIS connection. * @param className * [in] - Name of CIM class to enumerate * @return CloseableIterator of CIMInstance objects * @throws Exception */ public CloseableIterator<CIMInstance> getLunMaskingProtocolControllers(StorageSystem storage, String className) throws Exception { CIMObjectPath controllerConfigSvcPath = _cimPath.getControllerConfigSvcPath(storage); return getAssociatorInstances(storage, controllerConfigSvcPath, null, className, null, null, PS_LUN_MASKING_CNTRL_NAME_AND_ROLE); } public CloseableIterator<CIMInstance> getClarPrivileges(StorageSystem storage) throws Exception { return getPrivileges(storage, EMC_CLAR_PRIVILEGE); } public CloseableIterator<CIMInstance> getPrivileges(StorageSystem storage, String className) throws Exception { CIMObjectPath privilegeMgmtSvcPath = _cimPath.getPrivilegeManagementService(storage); return getAssociatorInstances(storage, privilegeMgmtSvcPath, null, className, null, null, PS_EMC_CLAR_PRIVILEGE); } public CIMInstance getLunMaskingProtocolController(StorageSystem storage, ExportMask exportMask) throws Exception { return getInstance(storage, _cimPath.getLunMaskingProtocolControllerPath(storage, exportMask), false, true, null); } /** * Will return a map of the volume WWNs to their HLU values for an instance of LunMasking * container on the array. * * @param client * [in] - WBEM client used to read data from SMI-S * @param instance * [in] - Instance of CIM_LunMaskingSCSIProtocolController, holding a representation * of an array masking container. * @return - Will return a map of the volume WWNs to their HLU values for an instance of * LunMasking container on the array. * @throws WBEMException */ public Map<String, Integer> getVolumesFromLunMaskingInstance(WBEMClient client, CIMInstance instance) throws WBEMException { Map<String, Integer> wwnToHLU = new HashMap<String, Integer>(); CloseableIterator<CIMInstance> iterator = null; CloseableIterator<CIMInstance> protocolControllerForUnitIter = null; try { int retry = 0; boolean failures = true; Map<String, Integer> deviceIdToHLU = new HashMap<String, Integer>(); while (failures) { failures = false; deviceIdToHLU.clear(); protocolControllerForUnitIter = client.referenceInstances(instance.getObjectPath(), CIM_PROTOCOL_CONTROLLER_FOR_UNIT, null, false, PS_DEVICE_NUMBER); while (protocolControllerForUnitIter.hasNext()) { CIMInstance pcu = protocolControllerForUnitIter.next(); CIMObjectPath pcuPath = pcu.getObjectPath(); CIMProperty<CIMObjectPath> dependentVolumePropery = (CIMProperty<CIMObjectPath>) pcuPath.getKey(CP_DEPENDENT); CIMObjectPath dependentVolumePath = dependentVolumePropery.getValue(); String deviceId = dependentVolumePath.getKey(CP_DEVICE_ID).getValue() .toString(); String deviceNumber = CIMPropertyFactory.getPropertyValue(pcu, CP_DEVICE_NUMBER); try { Integer decimalHLU = (int) Long.parseLong(deviceNumber, 16); deviceIdToHLU.put(deviceId, decimalHLU); } catch (NumberFormatException nfe) { // We've found in testing when users remove volumes from masks, the volume will still be in the // provider, but the HLU will get returned as an empty string, causing the overall operation to // fail. This retry loop will ensure that we wait until the provider is returning only volumes // with valid HLUs, thus removing any volumes from the mask that are in-flight outside of the // controller. _log.error(String.format( "deviceId: %s returned an invalid HLU. It may be currently getting removed from the mask.", deviceId)); failures = true; if (retry++ > GET_VOLUMES_BAD_HLU_RETRIES) { // rethrow throw nfe; } try { _log.warn("Retrying query operation for volumes and HLU after 10 seconds"); Thread.sleep(GET_VOLUMES_BAD_HLU_RETRY_SLEEP_MSEC); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } } _log.debug(String.format("getVolumesFromLunMaskingInstance(%s) - deviceIdToHLU map = %s", instance.getObjectPath().toString(), Joiner.on(',').join(deviceIdToHLU.entrySet()))); iterator = client.associatorInstances(instance.getObjectPath(), null, CIM_STORAGE_VOLUME, null, null, false, PS_EMCWWN); while (iterator.hasNext()) { CIMInstance cimInstance = iterator.next(); String deviceId = cimInstance.getObjectPath().getKey(CP_DEVICE_ID) .getValue().toString(); String wwn = CIMPropertyFactory.getPropertyValue(cimInstance, CP_WWN_NAME); wwnToHLU.put(wwn.toUpperCase(), deviceIdToHLU.get(deviceId)); } _log.debug(String.format("getVolumesFromLunMaskingInstance(%s) - wwnToHLU map = %s", instance.getObjectPath().toString(), Joiner.on(',').join(wwnToHLU.entrySet()))); } catch (WBEMException we) { _log.error("Caught an error will attempting to get volume list from " + "masking instance", we); throw we; } finally { closeCIMIterator(iterator); closeCIMIterator(protocolControllerForUnitIter); } return wwnToHLU; } /** * Will return a list of port names for the LunMasking container 'instance'. * * @param client * [in] - WBEM client used to read data from SMI-S * @param instance * [in] - Instance of CIM_LunMaskingSCSIProtocolController, holding a representation * of an array masking container. * @return - Will return a list of port names for the LunMasking container. * @throws WBEMException */ public List<String> getInitiatorsFromLunMaskingInstance(WBEMClient client, CIMInstance instance) throws WBEMException { List<String> initiatorPorts = new ArrayList<String>(); CloseableIterator<CIMInstance> iterator = null; try { iterator = client.associatorInstances(instance.getObjectPath(), null, CP_SE_STORAGE_HARDWARE_ID, null, null, false, PS_STORAGE_ID); while (iterator.hasNext()) { CIMInstance cimInstance = iterator.next(); String initiator = CIMPropertyFactory.getPropertyValue(cimInstance, CP_STORAGE_ID); // initiator could be iSCSI or a WWN. We need to normalize if it is a // WWN, so that we can compare appropriately. String it = Initiator.normalizePort(initiator); initiatorPorts.add(it); } } catch (WBEMException we) { _log.error("Caught an error while attempting to get initiator list from " + "masking instance", we); throw we; } finally { closeCIMIterator(iterator); } return initiatorPorts; } /** * Given a CIMInstance of a ClarLunMaskingProtocolController return a list of storage ports that * it references. * * @param client * [in] - WBEMClient to be used to talk to SMIS provider * @param instance * [in] - CIMInstance object pointing to a ClarLunMaskingProtocolController * @return List of port name String values. The WWNs will have colons separating the hex digits. */ public List<String> getStoragePortsFromLunMaskingInstance(WBEMClient client, CIMInstance instance) { List<String> storagePorts = new ArrayList<String>(); CloseableIterator<CIMInstance> iterator = null; try { iterator = client.associatorInstances(instance.getObjectPath(), null, CIM_PROTOCOL_ENDPOINT, null, null, false, PS_NAME); while (iterator.hasNext()) { CIMInstance cimInstance = iterator.next(); String portName = CIMPropertyFactory.getPropertyValue(cimInstance, CP_NAME); String fixedName = Initiator.toPortNetworkId(portName); storagePorts.add(fixedName); } } catch (WBEMException we) { _log.error("Caught an error while attempting to get storage ports from " + "masking instance", we); } finally { closeCIMIterator(iterator); } return storagePorts; } public void removeGroupsFromCascadedVolumeGroup( StorageSystem storage, String groupName, CIMObjectPath volumeGroupPath, SmisJob job, boolean forceFlag) throws Exception { _log.debug("{} RemoveGroupsFromCascadedVolumeGroup START...", storage.getSerialNumber()); CIMObjectPath[] volumeGroupPaths = new CIMObjectPath[] { volumeGroupPath }; CIMArgument[] inArgs = modifyCascadedStorageGroupInputArguments( storage, groupName, volumeGroupPaths, forceFlag); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), "RemoveMembers", inArgs, outArgs, job); _log.debug("{} RemoveGroupsFromCascadedVolumeGroup END...", storage.getSerialNumber()); } public CIMObjectPath getInitiatorGroupPath(StorageSystem storageDevice, String initiatorGroupName) throws Exception { return _cimPath.getMaskingGroupPath(storageDevice, initiatorGroupName, MASKING_GROUP_TYPE.SE_InitiatorMaskingGroup); } public CIMArgument[] getAddInitiatorGroupToMaskingGroupInputArguments(CIMObjectPath maskingGroupPath, CIMObjectPath initiatorGroupPath) throws Exception { CIMObjectPath[] members = {}; ArrayList<CIMObjectPath> initiatorGroupPaths = new ArrayList<CIMObjectPath>(); initiatorGroupPaths.add(initiatorGroupPath); members = initiatorGroupPaths.toArray(members); return new CIMArgument[] { _cimArgument.referenceArray(CP_MEMBERS, members), _cimArgument.reference(CP_MASKING_GROUP, maskingGroupPath) }; } public CIMArgument[] getCloneInputArguments(String label, CIMObjectPath sourceVolumePath, CIMObjectPath volumeGroupPath, StorageSystem storageDevice, StoragePool pool, boolean createInactive, CIMInstance replicationSettingData) { int waitForCopyState = (createInactive) ? PREPARED_VALUE : ACTIVATE_VALUE; List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.string(CP_ELEMENT_NAME, label)); args.add(_cimArgument.reference(CP_SOURCE_ELEMENT, sourceVolumePath)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, CLONE_VALUE)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, waitForCopyState)); if (pool != null) { addTargetPoolToArgs(storageDevice, pool, args); } if (storageDevice.checkIfVmax3()) { args.add(_cimArgument.referenceArray(SmisConstants.CP_COLLECTIONS, new CIMObjectPath[] { volumeGroupPath })); } if (replicationSettingData != null) { args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, replicationSettingData)); } return args.toArray(new CIMArgument[args.size()]); } private void addTargetPoolToArgs(StorageSystem storageSystem, StoragePool pool, List<CIMArgument> args) { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageSystem, pool.getNativeId())) }; CIMObjectPath inPoolPath = CimObjectPathCreator.createInstance(pool.getPoolClassName(), _cimConnection.getNamespace(storageSystem), inPoolPropKeys); args.add(_cimArgument.reference(CP_TARGET_POOL, inPoolPath)); } /** * Retrieve the Clar_SettingsDefineState_RG_SAFS instance represented by the given * Clar_SynchronizationAspectForSourceGroup instance ID * * @param storageSystem * - StorageArray reference, will be used to lookup SMI-S connection * @param synchAspectinstanceID * - Clar_SynchronizationAspectForSourceGroup instance ID to look for * @return * @throws Exception * - If it is not able to find the given id */ public CIMObjectPath getSettingsDefineStateForSource(StorageSystem storageSystem, String synchAspectinstanceID) throws Exception { boolean isVmax = (storageSystem.getSystemType().equals(DiscoveredDataObject.Type.vmax.name())); String className = (isVmax) ? SYMM_SETTINGS_DEFINE_STATE_SV_SAFS : CLAR_SETTINGS_DEFINE_STATE_SV_SAFS; CloseableIterator<CIMInstance> instances = getInstances(storageSystem, ROOT_EMC_NAMESPACE, className, true, false, false, new String[] { CP_INSTANCE_ID }); try { while (instances.hasNext()) { CIMInstance instance = instances.next(); CIMObjectPath settingsPath = instance.getObjectPath(); CIMObjectPath syncPath = (CIMObjectPath) settingsPath.getKey( CP_SETTING_DATA).getValue(); String instanceID = (String) syncPath.getKey(CP_INSTANCE_ID).getValue(); if (instanceID.equals(synchAspectinstanceID)) { return settingsPath; } } } finally { closeCIMIterator(instances); } throw new ServiceCodeException(ServiceCode.CONTROLLER_ERROR, "Unable to find instance of Clar_SettingsDefineState_SV_SAFS with " + "Clar_SynchronizationAspectForSource={0}", new Object[] { synchAspectinstanceID }); } /** * Retrieve the Clar_SettingsDefineState_RG_SAFS instance represented by the given * Clar_SynchronizationAspectForSourceGroup instance ID * * @param storageSystem * - StorageArray reference, will be used to lookup SMI-S connection * @param synchAspectinstanceID * - Clar_SynchronizationAspectForSourceGroup instance ID to look for * @return * @throws Exception * - If it is not able to find the given id */ public CIMObjectPath getSettingsDefineStateForSourceGroup(StorageSystem storageSystem, String synchAspectinstanceID) throws Exception { CloseableIterator<CIMInstance> instances = getInstances(storageSystem, ROOT_EMC_NAMESPACE, CLAR_SETTINGS_DEFINE_STATE_RG_SAFS, true, false, false, new String[] { CP_INSTANCE_ID }); try { while (instances.hasNext()) { CIMInstance instance = instances.next(); CIMObjectPath settingsPath = instance.getObjectPath(); CIMObjectPath syncPath = (CIMObjectPath) settingsPath.getKey( CP_SETTING_DATA).getValue(); String instanceID = (String) syncPath.getKey(CP_INSTANCE_ID) .getValue(); if (instanceID.equals(synchAspectinstanceID)) { return settingsPath; } } } finally { closeCIMIterator(instances); } throw new ServiceCodeException(ServiceCode.CONTROLLER_ERROR, "Unable to find instance of Clar_SettingsDefineState_RG_SAFS with Clar_SynchronizationAspectForSourceGroup={0}", new Object[] { synchAspectinstanceID }); } public Collection<? extends CIMObjectPath> constructMaskingGroupPathsFromNames( Set<String> groupNames, StorageSystem storage) throws Exception { List<CIMObjectPath> maskingGroupPaths = new ArrayList<CIMObjectPath>(); for (String groupName : groupNames) { CIMObjectPath maskingGroupPath = _cimPath .getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); maskingGroupPaths.add(maskingGroupPath); } return maskingGroupPaths; } public Set<String> constructVolumeNativeGuids(Collection<Set<String>> nativeGuidCollection) { Set<String> nativeGuids = new HashSet<String>(); for (Set<String> nativeGuidSet : nativeGuidCollection) { nativeGuids.addAll(nativeGuidSet); } return nativeGuids; } public CIMArgument[] getActivateFullCopyArguments(StorageSystem storageSystem, Volume volume) { CIMObjectPath syncObject; try { syncObject = _cimPath.getSyncObject(storageSystem, volume); } catch (Exception e) { throw new IllegalArgumentException("Problem getting input arguments"); } List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); argsList.add(_cimArgument.uint16(CP_OPERATION, ACTIVATE_VALUE)); argsList.add(_cimArgument.reference(CP_SYNCHRONIZATION, syncObject)); // For the case of VNX, we are going to set a flag that will // allow the database synchronization set to be skipped, so // that the activate runs faster, to meet our 10 second window. if (storageSystem.getSystemType().equals(StorageSystem.Type.vnxblock.name())) { argsList.add(_cimArgument.bool(CP_EMC_SKIP_REFRESH, true)); } CIMArgument[] result = {}; return argsList.toArray(result); } public CIMArgument[] getActivateGroupFullCopyInputArguments(StorageSystem storageSystem, CIMObjectPath groupSync) { List<CIMArgument> argsList = new ArrayList<CIMArgument>(); argsList.add(_cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true)); argsList.add(_cimArgument.uint16(CP_OPERATION, ACTIVATE_VALUE)); argsList.add(_cimArgument.reference(CP_SYNCHRONIZATION, groupSync)); // For the case of VNX, we are going to set a flag that will // allow the database synchronization set to be skipped, so // that the activate runs faster, to meet our 10 second window. if (storageSystem.getSystemType().equals(StorageSystem.Type.vnxblock.name())) { argsList.add(_cimArgument.bool(CP_EMC_SKIP_REFRESH, true)); } CIMArgument[] result = {}; return argsList.toArray(result); } public CIMArgument[] getCreateGroupReplicaForSRDFInputArguments(StorageSystem storage, String replicaName, CIMObjectPath srcCG, CIMObjectPath tgtCG, CIMObjectPath collection, int mode, Object repSettingInstance) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.reference(CP_CONNECTIVITY_COLLECTION, collection)); // By default CG's are consistency enabled for 8.0.3 & 4.6.2.25 provider versions. Hence commenting the below // line // args.add(_cimArgument.uint16(CP_CONSISTENCY, NO_CONSISTENCY)); args.add(_cimArgument.uint16(CP_MODE, mode)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, MIRROR_VALUE)); args.add(_cimArgument.reference(CP_SOURCE_GROUP, srcCG)); args.add(_cimArgument.reference(CP_TARGET_GROUP, tgtCG)); int maxRelNameLength = storage.getUsingSmis80() ? MAX_SMI80_RELATIONSHIP_NAME : MAX_VMAX_RELATIONSHIP_NAME; final String relationshipName = (replicaName.length() > maxRelNameLength) ? replicaName.substring(0, maxRelNameLength) : replicaName; args.add(_cimArgument.string(RELATIONSHIP_NAME, relationshipName)); // args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance)); // WaitForCopyState only valid for Active mode. if (SRDFOperations.Mode.ACTIVE.getMode() == mode) { args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED)); } return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getCreateGroupReplicaFromElementSynchronizationsForSRDFInputArguments( CIMObjectPath srcCG, CIMObjectPath tgtCG, Collection<CIMObjectPath> elementSynchronizations) { return getCreateGroupReplicaFromElementSynchronizationsForSRDFInputArguments(srcCG, tgtCG, elementSynchronizations, null); } public CIMArgument[] getCreateGroupReplicaFromElementSynchronizationsForSRDFInputArguments( CIMObjectPath srcCG, CIMObjectPath tgtCG, Collection<CIMObjectPath> elementSynchronizations, String relationshipName) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.reference(CP_SOURCE_GROUP, srcCG)); args.add(_cimArgument.reference(CP_TARGET_GROUP, tgtCG)); args.add(_cimArgument.referenceArray(CP_ELEMENT_SYNCHRONIZATIONS, elementSynchronizations.toArray(new CIMObjectPath[] {}))); if (relationshipName != null) { args.add(_cimArgument.string(CP_RELATIONSHIP_NAME, relationshipName)); } return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getCreateElementReplicaForSRDFInputArguments(CIMObjectPath srcVolume, CIMObjectPath tgtVolume, CIMObjectPath collection, int mode, Object repSettingInstance) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.reference(CP_CONNECTIVITY_COLLECTION, collection)); args.add(_cimArgument.uint16(CP_MODE, mode)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, MIRROR_VALUE)); args.add(_cimArgument.reference(CP_SOURCE_VOLUME, srcVolume)); args.add(_cimArgument.reference(CP_TARGET_VOLUME, tgtVolume)); args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingInstance)); return args.toArray(new CIMArgument[] {}); } public CIMArgument[] getDissolveSnapshotInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, DISSOLVE_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath), _cimArgument.bool(CP_FORCE, true) }; } public CIMArgument[] getResyncSnapshotInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESYNC_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath), _cimArgument.bool(CP_FORCE, true) }; } public CIMArgument[] getResyncReplicaInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESYNC_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath) }; } public CIMArgument[] getSupportedOperationsForSnapshot() { return new CIMArgument[] { _cimArgument.uint16(CP_REPLICATION_TYPE, SNAPSHOT_REPLICATION_TYPE) }; } public CIMArgument[] getReplicationSettingDataInstance() { return new CIMArgument[] { _cimArgument.uint16(CP_REPLICATION_TYPE, SNAPSHOT_REPLICATION_TYPE) }; } public CIMArgument[] getReplicationSettingDataInstance(int replicationType) { return new CIMArgument[] { _cimArgument.uint16(CP_REPLICATION_TYPE, replicationType) }; } public CIMArgument[] getSupportedFeatures() { return new CIMArgument[] { _cimArgument.uint16(CP_REPLICATION_TYPE, EMULATION_VALUE) }; } public StorageSystem getStorageSystemForProvider(final StorageSystem storageSystem, final Volume volume) { // wisely choose the right Storage System, so that right Provider is used in invoking calls if (LinkStatus.FAILED_OVER.toString().equalsIgnoreCase(volume.getLinkStatus())) { StringSet targets = volume.getSrdfTargets(); if (null == targets) { return _dbClient.queryObject(StorageSystem.class, volume.getStorageController()); } for (String targetURi : targets) { Volume target = _dbClient.queryObject(Volume.class, URI.create(targetURi)); if (null == target) { return storageSystem; } return _dbClient.queryObject(StorageSystem.class, target.getStorageController()); } } if (null == volume.getSrdfParent()) { return storageSystem; } Volume parent = _dbClient.queryObject(Volume.class, volume.getSrdfParent().getURI()); if (null == parent) { return storageSystem; } return _dbClient.queryObject(StorageSystem.class, parent.getStorageController()); } public boolean arraySupports(StorageSystem storage, int operation) { boolean result = false; CIMArgument[] out = new CIMArgument[5]; try { invokeMethod(storage, _cimPath.getReplicationServiceCapabilitiesPath(storage), GET_SUPPORTED_OPERATIONS, getSupportedOperationsForSnapshot(), out); Object value = _cimPath.getFromOutputArgs(out, SUPPORTED_OPERATIONS); if (value != null) { UnsignedInteger16[] supported = (UnsignedInteger16[]) value; for (UnsignedInteger16 it : supported) { if (it.intValue() == operation) { result = true; break; } } } } catch (WBEMException e) { _log.error("arraySupportsDissolve exception: ", e); } return result; } public boolean arraySupportsDissolve(StorageSystem storage) { return arraySupports(storage, DISSOLVE_VALUE); } public boolean arraySupportsResync(StorageSystem storage) { return arraySupports(storage, RESYNC_VALUE); } public boolean isThinlyProvisioned(StorageSystem storage, BlockObject to) throws Exception { CIMObjectPath path = _cimPath.getBlockObjectPath(storage, to); CIMInstance instance = getInstance(storage, path, false, false, PS_THINLY_PROVISIONED); String thinlyProvisionedString = CIMPropertyFactory.getPropertyValue(instance, CP_THINLY_PROVISIONED); return (thinlyProvisionedString != null) ? thinlyProvisionedString.equalsIgnoreCase(Boolean.TRUE.toString()) : false; } public boolean validateStorageProviderConnection(String ipAddress, Integer portNumber) { boolean isConnectionValid = false; try { CimConnection connection = _cimConnection.getConnection(ipAddress, portNumber.toString()); isConnectionValid = (connection != null && _cimConnection.checkConnectionliveness(connection)); } catch (IllegalStateException ise) { _log.error(ise.getMessage()); } return isConnectionValid; } /** * Method to generate the input arguments for EMCManuallyRegisterHostInitiators * * @param storage * [in] - StorageSystem object. * @param initiators * [in] - List of Initiator objects to process for input generation * @param storagePortURI * [in] - StoragePort URI reference * @return CIMArgument[] representing the generate arguments for the SMI-S method call. * @throws Exception */ public CIMArgument[] getEMCManuallyRegisterHostInitiators(StorageSystem storage, Collection<Initiator> initiators, URI storagePortURI) throws Exception { List<CIMArgument> args = new ArrayList<CIMArgument>(); int type = 2; // Fibre-Channel type String hostname = EMPTY_STRING; List<String> unRegisteredNodeIDs = new ArrayList<String>(); String[] unRegisteredStorageIDs = new String[initiators.size()]; CIMObjectPath[] targetEndpoints = _cimPath.getTargetPortPaths(storage, Collections.singletonList(storagePortURI)); int it = 0; for (Initiator initiator : initiators) { if (WWNUtility.isValidWWN(initiator.getInitiatorPort())) { // This is an FC initiator, add the node part unRegisteredNodeIDs.add(Initiator.normalizePort(initiator.getInitiatorNode())); } else { type = 5; // iSCSI type } // The order matters to platforms like VNX. VNX requires to use the initiator hostname // field in order to keep consistent with peer initiators. if (initiator.getHostName() != null && !initiator.getHostName().equals(EMPTY_STRING)) { hostname = initiator.getHostName(); } else if (hostname.equals(EMPTY_STRING) && initiator.getHost() != null) { Host host = _dbClient.queryObject(Host.class, initiator.getHost()); if (host != null) { hostname = host.getHostName(); } } // VNX does not like registering initiators with IP addresses if ((hostname != null) && (IPAddressUtil.isIPv4LiteralAddress(hostname) || IPAddressUtil.isIPv6LiteralAddress(hostname))) { hostname = "HOST-" + hostname; } // Regardless of the initiator type, we should always have the initiatorPort value for it unRegisteredStorageIDs[it++] = Initiator.normalizePort(initiator.getInitiatorPort()); } args.add(_cimArgument.string(CP_HOSTNAME, hostname)); args.add(_cimArgument.referenceArray(CP_TARGET_ENDPOINTS, targetEndpoints)); args.add(_cimArgument.uint16(CP_UNREGISTERED_STORAGE_TYPE, type)); args.add(_cimArgument.stringArray(CP_UNREGISTERED_STORAGE_IDS, unRegisteredStorageIDs)); if (!unRegisteredNodeIDs.isEmpty()) { String[] nodeIDs = unRegisteredNodeIDs.toArray(new String[unRegisteredNodeIDs.size()]); args.add(_cimArgument.stringArray(CP_UNREGISTERED_NODE_IDS, nodeIDs)); } return args.toArray(new CIMArgument[args.size()]); } /** * This function will generate the input arguments for the EMCGetConnectedTargetEndpoints * SMI-S method call. * * @param initiator * [in] - CIMObjectPath that references an initiator on the provider * @return CIMArgument array containing arguments for the method call */ public CIMArgument[] getEMCGetConnectedTargetEndpoints(CIMObjectPath initiator) { return new CIMArgument[] { _cimArgument.reference(CP_HARDWARE_ID, initiator), _cimArgument.uint16(CP_FILTER, FILTER_CONNECTED_VALUE) }; } /** * This function will prevent calls to obj.toString() from generating a * runtime Exception. * * Note: this function is here because there seem to be strange cases where * the result of an SMI-S invokeMethod returns a non-null Object, but calling * toString() on the Object results in a NPE deep within the toString() call. * This function is used as a countermeasure for this behavior. * * @param obj * [in] - Object to call toString() against. * @return String (obj.toString() or "", if it could not be obtained) */ private String protectedToString(Object obj) { String out = EMPTY_STRING; if (obj != null) { try { out = obj.toString(); } catch (RuntimeException runtime) { String message = "Caught an exception while trying to call obj.toString()"; if (_log.isDebugEnabled()) { // If debugging is enabled, dump the stacktrace _log.error(message, runtime); } else { _log.info(message); } } } return out; } public CIMArgument[] getDefaultReplicationSettingDataInputArgumentsForSnapshot() { return new CIMArgument[] { _cimArgument.uint16(SmisConstants.CP_REPLICATION_TYPE, 6) // 6 -> Synchronous Snapshot Local }; } public CIMArgument[] getDefaultReplicationSettingDataInputArgumentsForLocalMirror() { return new CIMArgument[] { _cimArgument.uint16(SmisConstants.CP_REPLICATION_TYPE, 2) // 2 -> Synchronous Mirror Local }; } /* * find/create storage group for VMAX V3 */ public CIMObjectPath getVolumeGroupPath(StorageSystem forProvider, StorageSystem storageSystem, Volume volume, StoragePool storagePool) { CIMObjectPath volumeGrouptPath = null; if (storageSystem.checkIfVmax3()) { if (storagePool == null) { storagePool = _dbClient.queryObject(StoragePool.class, volume.getPool()); } String srp = storagePool.getPoolName(); // default values in case autoTierPolicy is not set then use NONE SLO for V3 AFA and Optimized SLO for V3 String slo = storageSystem.isV3AllFlashArray() ? Constants.NONE.toUpperCase() : Constants.OPTIMIZED_SLO; String workload = Constants.NONE.toUpperCase(); URI policyURI = volume.getAutoTieringPolicyUri(); if (!NullColumnValueGetter.isNullURI(policyURI)) { AutoTieringPolicy policy = _dbClient.queryObject(AutoTieringPolicy.class, policyURI); slo = policy.getVmaxSLO(); workload = policy.getVmaxWorkload().toUpperCase(); } // Try to find existing storage group. volumeGrouptPath = getVolumeGroupBasedOnSLO(forProvider, storageSystem, slo, workload, srp); if (volumeGrouptPath == null) { // Create new storage group. volumeGrouptPath = createVolumeGroupBasedOnSLO(forProvider, storageSystem, slo, workload, srp); } } return volumeGrouptPath; } /** * Removes volume from storage group * * @param storage * The reference to storage system * @param nativeId * The volume nativeId * @param forceFlag * @throws Exception */ public CIMInstance removeVolumeFromParkingSLOStorageGroup(StorageSystem storage, String nativeId, boolean forceFlag) throws Exception { CIMInstance parkingSLOStorageGroup = null; CIMObjectPath volumePath = _cimPath.getVolumePath(storage, nativeId); CloseableIterator<CIMInstance> cimInstanceItr = null; String returnedgroupName = null; try { cimInstanceItr = getAssociatorInstances(storage, volumePath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, PS_ELEMENT_NAME); while (cimInstanceItr.hasNext()) { CIMInstance groupInstance = cimInstanceItr.next(); String elementName = CIMPropertyFactory.getPropertyValue(groupInstance, CP_ELEMENT_NAME); _log.debug("Found associated masking group {}", groupInstance.getObjectPath().toString()); if (elementName.startsWith(Constants.STORAGE_GROUP_PREFIX)) { returnedgroupName = elementName; parkingSLOStorageGroup = groupInstance; } } } catch (WBEMException ex) { _log.debug("Failed to find storage group for a volume from SMI-S Provider : " + ex.getMessage()); throw new DeviceControllerException(ex); } finally { if (cimInstanceItr != null) { cimInstanceItr.close(); } } if (returnedgroupName != null) { CIMObjectPath maskingGroupPath = _cimPath.getMaskingGroupPath(storage, returnedgroupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); CIMObjectPath[] memberPaths = {}; ArrayList<CIMObjectPath> volumePaths = new ArrayList<CIMObjectPath>(); volumePaths.add(volumePath); memberPaths = volumePaths.toArray(memberPaths); CIMArgument[] inArgs = getAddOrRemoveMaskingGroupMembersInputArguments(maskingGroupPath, memberPaths, forceFlag); CIMArgument[] outArgs = new CIMArgument[5]; _log.info("Invoking remove volume:" + nativeId + " from storage group:" + returnedgroupName); invokeMethodSynchronously(storage, _cimPath.getControllerConfigSvcPath(storage), SmisConstants.REMOVE_MEMBERS, inArgs, outArgs, null); } else { _log.info("Looks like volume is already removed from the storage group," + " could not find storage group for the volume {} on the storage system {}", nativeId, storage.getNativeGuid()); } return parkingSLOStorageGroup; } /** * Finds the storage group based on SLO * * @param forProvider * The storage provider where the query executes * @param storageSystem * The reference to storage system * @param slo * The slo name for the fast setting * @param workload * The workload name for the fast setting * @param srp * The srp name for the fast setting * * @return returns volumeGroupPath if found else null */ public CIMObjectPath getVolumeGroupBasedOnSLO(StorageSystem forProvider, StorageSystem storageSystem, String slo, String workload, String srp) { CIMObjectPath volumeGroupObjectPath = null; StringBuffer fastSettingName = new StringBuffer(); fastSettingName = fastSettingName.append(slo).append(Constants._plusDelimiter) .append(workload).append(Constants._plusDelimiter).append(srp); try { Map<CIMObjectPath, Set<String>> groupPaths = findAnySLOStorageGroupsCanBeReUsed(forProvider, storageSystem, fastSettingName.toString(), false); for (CIMObjectPath groupPath : groupPaths.keySet()) { Set<String> groupVolumes = groupPaths.get(groupPath); if (groupVolumes == null || (groupVolumes != null && groupVolumes.size() < 4000)) { volumeGroupObjectPath = groupPath; break; } } } catch (WBEMException e) { _log.info(storageSystem.getSystemType() + " Problem when trying to look for existing storage group for SLO " + fastSettingName.toString(), e); throw new DeviceControllerException(e); } return volumeGroupObjectPath; } /** * Creates storage group based on fast setting. * * @param forProvider * The storage provider where the query executes * @param storageSystem * The reference to the storage system * @param slo * The slo name for the fast setting * @param workload * The workload name for the fast setting * @param srp * The srp name for the fast setting * * @return returns the storage group path for the storage group created */ public CIMObjectPath createVolumeGroupBasedOnSLO(StorageSystem forProvider, StorageSystem storageSystem, String slo, String workload, String srp) { String groupName = generateGroupName(slo, workload, srp); String lockName = generateParkingSLOSGLockName(storageSystem, groupName); boolean gotLock = false; CIMObjectPath volumeGroupObjectPath = null; try { // The parking SLO StorageGroup's lifecycle will be maintained by ViPR. // It will create it and it will delete it. It is a shared resource, so // this call to create the SG needs distributed process protection if (_locker.acquireLock(lockName, PARKING_SLO_SG_LOCK_WAIT_SECS)) { gotLock = true; // Since we locked this operation, we need to make sure that some other system // did not already create the StorageGroup. So, check for it here. volumeGroupObjectPath = _cimPath.getStorageGroupObjectPath(groupName, storageSystem); CIMInstance instance = checkExists(forProvider, volumeGroupObjectPath, false, false); if (instance == null) { // Nothing created yet and we have the lock, so let's create it ... CIMArgument[] inArgs = getCreateVolumeGroupInputArguments(storageSystem, groupName, slo, srp, workload, null, false); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(forProvider, _cimPath.getControllerConfigSvcPath(storageSystem), "CreateGroup", inArgs, outArgs); volumeGroupObjectPath = _cimPath.getCimObjectPathFromOutputArgs(outArgs, "MaskingGroup"); } } else { _log.warn(String.format("Could not get lock %s while trying to createVolumeGroupBasedOnSLO", lockName)); throw DeviceControllerException.exceptions.failedToAcquireLock(lockName, "createVolumeGroupBasedOnSLO"); } } catch (WBEMException we) { _log.info(storageSystem.getSystemType() + " Problem when trying to create volume group for SLO: " + slo + " SRP: " + srp + " Workload: " + workload, we); throw new DeviceControllerException(we); } catch (Exception e) { _log.error("An exception while processing createVolumeGroupBasedOnSLO", e); } finally { if (gotLock) { _locker.releaseLock(lockName); } } return volumeGroupObjectPath; } private String generateGroupName(String slo, String workload, String srp) { String groupName = null; StringBuffer groupNameSB = new StringBuffer(Constants.STORAGE_GROUP_PREFIX); groupNameSB = groupNameSB.append(slo).append(Constants.UNDERSCORE_DELIMITER) .append(workload).append(Constants.UNDERSCORE_DELIMITER) .append(srp).append(Constants.UNDERSCORE_DELIMITER) .append(UUID.randomUUID()); groupName = groupNameSB.toString(); if (groupName.length() > Constants.STOARGE_GROUP_MAX_LENGTH) { groupName = groupName.substring(0, Constants.STOARGE_GROUP_MAX_LENGTH); } return groupName; } /** * This method return volumes deviceId present in the passed in storage group. * * @param storage * The reference to storage system * @param groupName * The storage group name * @return set of deviceIds of volumes in the passed in storage group * @throws Exception */ public Set<String> getVolumeDeviceIdsFromStorageGroup(StorageSystem storage, String groupName) throws Exception { CIMObjectPath groupPath = _cimPath.getMaskingGroupPath(storage, groupName, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); return getVolumeDeviceIdsFromStorageGroup(storage, groupPath); } /** * This method returns volume device IDs present in the passed-in storage group. * * @param storage * storage system * @param sgPath * storage group object path * @return set of device IDs of volumes in the storage group * @throws Exception */ public Set<String> getVolumeDeviceIdsFromStorageGroup(StorageSystem storage, CIMObjectPath sgPath) throws Exception { CloseableIterator<CIMObjectPath> volumePathItr = null; try { Set<String> deviceIds = new HashSet<String>(); // loop through all the volumes of this storage group _log.debug("Looping through all volumes in storage group {}", sgPath.getObjectName()); volumePathItr = getAssociatorNames(storage, sgPath, null, CIM_STORAGE_VOLUME, null, null); while (volumePathItr.hasNext()) { deviceIds.add(getVolumeDeviceId(volumePathItr.next())); } return deviceIds; } finally { closeCIMIterator(volumePathItr); } } /** * This method is used to get fast setting value for the volume based on autoTierPolicyName. * fastSetting is combination of SLO+WORKLOAD+SRP. If no policy name is specified then * fastSetting is OPTIMIZED+NONE+SRP_1. * Other example name is BRONZE+DSS+SRP_1 when autoTierPolicy is specified for a volume. * * @param blockObjectURI * BlockObjectURI * @param autoTierPolicyName * AutoTier Policy name * * @return VMAX3 fast setting */ public String getVMAX3FastSettingForVolume(URI blockObjectURI, String autoTierPolicyName) { StringBuffer policyName = new StringBuffer(); Volume volume = null; if (URIUtil.isType(blockObjectURI, Volume.class)) { volume = _dbClient.queryObject(Volume.class, blockObjectURI); // If the there is a BlockSnapshot with the same native GUID as the volume, then // this is a backend volume representing the snapshot for the purpose of importing // the snapshot into VPLEX as a VPLEX volume. Therefore, treat it like a block snapshot // and use the parent volume. List<BlockSnapshot> snapshots = CustomQueryUtility.getActiveBlockSnapshotByNativeGuid(_dbClient, volume.getNativeGuid()); if (!snapshots.isEmpty()) { volume = _dbClient.queryObject(Volume.class, snapshots.get(0).getParent()); } } else if (URIUtil.isType(blockObjectURI, BlockSnapshot.class)) { BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, blockObjectURI); volume = _dbClient.queryObject(Volume.class, snapshot.getParent()); } else if (URIUtil.isType(blockObjectURI, BlockMirror.class)) { BlockMirror mirror = _dbClient.queryObject(BlockMirror.class, blockObjectURI); policyName = getPolicyByBlockObject(mirror.getPool(), autoTierPolicyName, mirror.getAutoTieringPolicyUri()); } if (volume != null) { policyName = getPolicyByBlockObject(volume.getPool(), autoTierPolicyName, volume.getAutoTieringPolicyUri()); } return policyName.toString(); } /** * This method is will check if the Storage Pool associated with the Volume supports compression. * If it does support compression, it will check if the associated virtual Pool has compression enabled. * It will recommend the user to disable compression if the virtual pool has compression disabled and * the storage pool enables compression by default. * * @param blockObjectURI BlockObjectURI * @param storage - StorageSystem object * @return boolean to report if compression needs to be disabled. */ public boolean disableVMAX3Compression(URI blockObjectURI, StorageSystem storageSystem) { VirtualPool virtualPool = null; StoragePool storagePool = null; Volume volume = null; if (URIUtil.isType(blockObjectURI, Volume.class)) { volume = _dbClient.queryObject(Volume.class, blockObjectURI); // Using the same logic that is in the above getVMAX3FastSettingForVolume method. // If the there is a BlockSnapshot with the same native GUID as the volume, then // this is a backend volume representing the snapshot for the purpose of importing // the snapshot into VPLEX as a VPLEX volume. Therefore, treat it like a block snapshot // and use the parent volume. List<BlockSnapshot> snapshots = CustomQueryUtility.getActiveBlockSnapshotByNativeGuid(_dbClient, volume.getNativeGuid()); if (!snapshots.isEmpty()) { volume = _dbClient.queryObject(Volume.class, snapshots.get(0).getParent()); } } else if (URIUtil.isType(blockObjectURI, BlockSnapshot.class)) { BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, blockObjectURI); volume = _dbClient.queryObject(Volume.class, snapshot.getParent()); } else if (URIUtil.isType(blockObjectURI, BlockMirror.class)) { BlockMirror mirror = _dbClient.queryObject(BlockMirror.class, blockObjectURI); if (NullColumnValueGetter.isNullURI(mirror.getVirtualPool()) || NullColumnValueGetter.isNullURI(mirror.getPool())) { _log.info("The given BlockMirror {} does not have an associated Virtual pool or Storage Pool ", blockObjectURI); return false; // This should never happen but we need this additional check. } virtualPool = _dbClient.queryObject(VirtualPool.class, mirror.getVirtualPool()); storagePool = _dbClient.queryObject(StoragePool.class, mirror.getPool()); } if (volume != null) { if (NullColumnValueGetter.isNullURI(volume.getVirtualPool()) || NullColumnValueGetter.isNullURI(volume.getPool())) { _log.info("The given Volume {} does not have an associated Virtual pool or Storage Pool ", blockObjectURI); return false; // This should never happen but we need this additional check. } virtualPool = _dbClient.queryObject(VirtualPool.class, volume.getVirtualPool()); storagePool = _dbClient.queryObject(StoragePool.class, volume.getPool()); } return (checkIfProviderSupportsCompressionOperations(storageSystem) && !virtualPool.getCompressionEnabled() && storagePool.getCompressionEnabled()); } /** * This method is will check if the volume associated with virtual Pool has compression enabled. * * @param blockObjectURI BlockObjectURI * @return boolean to report if compression is enabled on the vpool. */ public boolean isVMAX3VolumeCompressionEnabled(URI blockObjectURI) { VirtualPool virtualPool = null; Volume volume = null; if (URIUtil.isType(blockObjectURI, Volume.class)) { volume = _dbClient.queryObject(Volume.class, blockObjectURI); } else if (URIUtil.isType(blockObjectURI, BlockSnapshot.class)) { BlockSnapshot snapshot = _dbClient.queryObject(BlockSnapshot.class, blockObjectURI); volume = _dbClient.queryObject(Volume.class, snapshot.getParent()); } else if (URIUtil.isType(blockObjectURI, BlockMirror.class)) { BlockMirror mirror = _dbClient.queryObject(BlockMirror.class, blockObjectURI); virtualPool = _dbClient.queryObject(VirtualPool.class, mirror.getVirtualPool()); } if (volume != null) { virtualPool = _dbClient.queryObject(VirtualPool.class, volume.getVirtualPool()); } return ((virtualPool != null) && virtualPool.getCompressionEnabled()); } /** * This method return true if the SMI-S provider supports compression operations. * If not, it will throw an exception * * @param storage - StorageSystem object * @param boolean to report if SMI-S provider supports compression */ public Boolean checkIfProviderSupportsCompressionOperations(StorageSystem storageSystem) { String versionSubstring = null; if (storageSystem.checkIfVmax3() && storageSystem.getUsingSmis80()) { try { StorageProvider storageProvider = _dbClient.queryObject(StorageProvider.class, storageSystem.getActiveProviderURI()); String providerVersion = storageProvider.getVersionString(); versionSubstring = providerVersion.split("\\.")[1]; } catch (Exception e) { _log.error("Exception get provider version for the storage system {} {}.", storageSystem.getLabel(), storageSystem.getId()); return false; } } if (NullColumnValueGetter.isNullValue(versionSubstring) || !(Integer.parseInt(versionSubstring) > 2)) { String errMsg = String.format( "SMI-S Provider associated with Storage System %s does not support compression operations", storageSystem.getSerialNumber()); _log.error(errMsg); return false; } return true; } /** * Get the policy by BlockObject autoTieringPolicy URI. * * @param pool * @param autoTierPolicyName * @param policyURI * @return */ private StringBuffer getPolicyByBlockObject(URI pool, String autoTierPolicyName, URI policyURI) { StoragePool storagePool = _dbClient.queryObject(StoragePool.class, pool); StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, storagePool.getStorageDevice()); StringBuffer policyName = new StringBuffer(); if ((null != autoTierPolicyName && Constants.NONE.equalsIgnoreCase(autoTierPolicyName)) || (NullColumnValueGetter.isNullURI(policyURI))) { String defaultSLO = storageSystem.isV3AllFlashArray() ? Constants.NONE.toUpperCase() : Constants.OPTIMIZED_SLO; policyName = policyName.append(defaultSLO).append(Constants._plusDelimiter) .append(Constants.NONE.toUpperCase()).append(Constants._plusDelimiter).append(storagePool.getPoolName()); } else { AutoTieringPolicy autoTierPolicy = _dbClient.queryObject(AutoTieringPolicy.class, policyURI); policyName = policyName.append(autoTierPolicy.getVmaxSLO()).append(Constants._plusDelimiter) .append(autoTierPolicy.getVmaxWorkload().toUpperCase()).append(Constants._plusDelimiter) .append(storagePool.getPoolName()); } return policyName; } /** * Convenient method to update storage group host IO limits attributes (bandwidth and iops, using setting from * volumes * * @param client * @param storageGroupPath * @param volumeURIHLUs * @throws WBEMException */ public void setHostIOLimits(WBEMClient client, CIMObjectPath storageGroupPath, VolumeURIHLU[] volumeURIHLUs) throws WBEMException { if (volumeURIHLUs == null || volumeURIHLUs.length <= 0) { return; } if (volumeURIHLUs[0].isHostIOLimitIOPsSet()) { updateHostIOLimitIOPs(client, storageGroupPath, volumeURIHLUs[0].getHostIOLimitIOPs()); } if (volumeURIHLUs[0].isHostIOLimitBandwidthSet()) { updateHostIOLimitBandwidth(client, storageGroupPath, volumeURIHLUs[0].getHostIOLimitBandwidth()); } } /** * Reset storage group host IO limits to 0 * * @param client * @param storage * @param storageGroupPath * @throws Exception */ public void resetHostIOLimits(WBEMClient client, StorageSystem storage, CIMObjectPath storageGroupPath) throws Exception { CIMInstance storageGroupInstance = checkExists(storage, storageGroupPath, false, false); String hostIOLimitBandwidth = CIMPropertyFactory.getPropertyValue(storageGroupInstance, EMC_MAX_BANDWIDTH); String hostIOLimitIOPs = CIMPropertyFactory.getPropertyValue(storageGroupInstance, EMC_MAX_IO); // TODO : reset Bandwidth and IOPs for VMAX3 is not working, need to follow up with SMIS team boolean resetBandwidth = !StringUtils.isEmpty(hostIOLimitBandwidth) && Integer.parseInt(hostIOLimitBandwidth) > 0; if (resetBandwidth) { updateHostIOLimitBandwidth(client, storageGroupPath, 0); } boolean resetIOPs = !StringUtils.isEmpty(hostIOLimitIOPs) && Integer.parseInt(hostIOLimitIOPs) > 0; if (resetIOPs) { updateHostIOLimitIOPs(client, storageGroupPath, 0); } } /** * Set storage group host io limit bandwidth * * @param client * @param storageGroupPath * @param hostIOLimitBandwidth * @throws WBEMException */ public void updateHostIOLimitBandwidth(WBEMClient client, CIMObjectPath storageGroupPath, Integer hostIOLimitBandwidth) throws WBEMException { if (hostIOLimitBandwidth == null) { return; } _log.info("Attempting to update Host IO Limit Bandwidth for Storage Group : {} to {}", storageGroupPath.toString(), hostIOLimitBandwidth); CIMPropertyFactory factoryRef = (CIMPropertyFactory) ControllerServiceImpl.getBean("CIMPropertyFactory"); CIMInstance toUpdate = new CIMInstance(storageGroupPath, new CIMProperty[] { factoryRef.uint32(EMC_MAX_BANDWIDTH, hostIOLimitBandwidth) }); _log.debug("Params: " + toUpdate.toString()); client.modifyInstance(toUpdate, new String[] { EMC_MAX_BANDWIDTH }); } /** * Set storage group host io limit iops * * @param client * @param storageGroupPath * @param hostIOLimitIOPs * @throws WBEMException */ public void updateHostIOLimitIOPs(WBEMClient client, CIMObjectPath storageGroupPath, Integer hostIOLimitIOPs) throws WBEMException { if (hostIOLimitIOPs == null) { return; } _log.info("Attempting to update Host IO Limit IOPs for Storage Group : {} to {}", storageGroupPath.toString(), hostIOLimitIOPs); CIMPropertyFactory factoryRef = (CIMPropertyFactory) ControllerServiceImpl.getBean("CIMPropertyFactory"); CIMInstance toUpdate = new CIMInstance(storageGroupPath, new CIMProperty[] { factoryRef.uint32(EMC_MAX_IO, hostIOLimitIOPs) }); _log.debug("Params: " + toUpdate.toString()); client.modifyInstance(toUpdate, new String[] { EMC_MAX_IO }); } /** * Set storage group host io limit iops * * @param client * @param storageGroupPath * @param hostIOLimitIOPs * @throws WBEMException */ public void updateStorageGroupName(WBEMClient client, CIMObjectPath storageGroupPath, String storageGroupName) throws WBEMException { if (StringUtils.isEmpty(storageGroupName)) { return; } _log.info("Attempting to update storage group name to: " + storageGroupName); CIMPropertyFactory factoryRef = (CIMPropertyFactory) ControllerServiceImpl.getBean("CIMPropertyFactory"); CIMInstance toUpdate = new CIMInstance(storageGroupPath, new CIMProperty[] { factoryRef.string(CP_ELEMENT_NAME, storageGroupName) }); _log.debug("Params: " + toUpdate.toString()); client.modifyInstance(toUpdate, PS_ELEMENT_NAME); } /** * Get policy and host limits information about the export mask that is specific to VMAX. * * @param storage * storage system * @param exportMask * export mask * @return export mask policy */ public ExportMaskPolicy getExportMaskPolicy(StorageSystem storage, ExportMask exportMask) { ExportMaskPolicy policy = new ExportMaskPolicy(); policy.simpleMask = false; CloseableIterator<CIMInstance> cimInstanceItr = null; String storageGroupName; try { CIMObjectPath maskingViewPath = _cimPath.getMaskingViewPath(storage, exportMask.getMaskName()); CIMInstance maskingViewInstance = checkExists(storage, maskingViewPath, false, false); String maxUnitsControlled = CIMPropertyFactory.getPropertyValue(maskingViewInstance, CP_MAX_UNITS_CONTROLLED); if (!Strings.isNullOrEmpty(maxUnitsControlled)) { int maxVolumesAllowed = Integer.valueOf(maxUnitsControlled); policy.setMaxVolumesAllowed(maxVolumesAllowed); } storageGroupName = getStorageGroupForGivenMaskingView(maskingViewInstance, exportMask.getMaskName(), storage); CIMObjectPath storageGroupPath = _cimPath.getStorageGroupObjectPath(storageGroupName, storage); CIMObjectPath igPath = getInitiatorGroupForGivenMaskingView(exportMask.getMaskName(), storage); if (isCascadedIG(storage, igPath)) { policy.setIgType(IG_TYPE.CASCADED.name()); } else { policy.setIgType(IG_TYPE.SIMPLE.name()); } CIMInstance storageGroupInstance = checkExists(storage, storageGroupPath, false, false); String hostIOLimitBandwidth = CIMPropertyFactory.getPropertyValue(storageGroupInstance, EMC_MAX_BANDWIDTH); String hostIOLimitIOPs = CIMPropertyFactory.getPropertyValue(storageGroupInstance, EMC_MAX_IO); policy.tierPolicies = findTierPoliciesForStorageGroup(storage, storageGroupName); policy.sgName = storageGroupName; policy.setHostIOLimitBandwidth(StringUtils.isEmpty(hostIOLimitBandwidth) ? null : Integer.parseInt(hostIOLimitBandwidth)); policy.setHostIOLimitIOPs(StringUtils.isEmpty(hostIOLimitIOPs) ? null : Integer.parseInt(hostIOLimitIOPs)); boolean childSG = !this.isCascadedSG(storage, storageGroupPath); // It is expected there would be only one fast policy, grab the first or set null policy.localTierPolicy = null; if (childSG && policy.tierPolicies != null && !policy.tierPolicies.isEmpty()) { for (String tier : policy.tierPolicies) { policy.localTierPolicy = tier; } } Set<String> storageGroupNames = null; // If this is a non-cascaded, non-fast policy, check for additional phantom storage groups if (childSG && policy.tierPolicies.isEmpty()) { storageGroupNames = this.getPhantomStorageGroupsForGivenMaskingView(exportMask.getMaskName(), storage); StringSet policyNames = new StringSet(); for (String sgName : storageGroupNames) { policyNames.addAll(findTierPoliciesForStorageGroup(storage, sgName)); } policy.tierPolicies.addAll(policyNames); } // If this is non-cascaded, and we found no phantoms either, it's a simple mask. if (childSG && (storageGroupNames == null || storageGroupNames.isEmpty())) { policy.simpleMask = true; } // if Non-cascaded SG and Phantom SGs found, then its Phantom Type if (childSG && (storageGroupNames != null && !storageGroupNames.isEmpty())) { policy.setExportType(ExportMaskPolicy.EXPORT_TYPE.PHANTOM.name()); } } catch (Exception e) { String msg = "Error when attempting to query LUN masking information: " + e.getMessage(); _log.error(MessageFormat.format("Encountered an SMIS error when attempting to query existing exports policy: {0}", msg), e); throw SmisException.exceptions.queryExistingMasksFailure(msg, e); } finally { closeCIMIterator(cimInstanceItr); } return policy; } /** * Find any "phantom" storage groups that may be associated with a masking view. A phantom storage group is defined * as * a volume in the specified masking view that is contained in a storage group that is NOT in a masking view. This * is * a trick used by folks to be able to use a single non-cascaded storage group to contain volumes with different * fast-policies, * which is a policy that is attached to the storage group. * * In order to find a phantom storage group, starting from the masking view, we must: * 1. Find the volumes associated with the masking view * 2. Find the storage groups associated the volume that is not in a masking view * 3. Verify the storage group has a FAST policy and it is not child SG type (in case of CSG attached to MV) * * @param maskingViewName * the name of the masking view * @param storage * storage device * @return a set of phantom storage group names * @throws Exception */ public Set<String> getPhantomStorageGroupsForGivenMaskingView(String maskingViewName, StorageSystem storage) throws Exception { Set<String> discoveredGroupNames = new HashSet<String>(); CloseableIterator<CIMInstance> volumePathItr = null; CloseableIterator<CIMInstance> sgPaths = null; try { CIMObjectPath maskingViewPath = _cimPath.getMaskingViewPath(storage, maskingViewName); CIMInstance maskingViewInstance = checkExists(storage, maskingViewPath, false, false); _log.debug("Trying to find if any masking view by the same name {} exists", maskingViewName); if (null == maskingViewInstance) { _log.error( "Masking View {} not available in Provider, either its deleted or provider might take some time to sync with Array. Try again if group is available on Array", maskingViewName); } else { _log.info("Running phantom SG check for Masking View {}", maskingViewName); volumePathItr = getAssociatorInstances(storage, maskingViewPath, null, CIM_STORAGE_VOLUME, null, null, PS_EMCWWN); // COP-18172 - Use a cache for holding StorageGroup information. There could be many volumes in the // MaskingView, which // could be associated with the same StorageGroup(s). It could be more efficient to cache the // StorageGroup information, so // that we don't hit the provider over and over again for the same StorageGroup information. class StorageGroupInfo { Set<String> policyNames; String storageGroupName; Boolean isPartOfExistingParentGroups; } Map<String, StorageGroupInfo> storageGroupInfoCache = new HashMap<>(); while (volumePathItr.hasNext()) { CIMInstance cimInstance = volumePathItr.next(); String deviceName = cimInstance.getObjectPath().getKey(CP_SYSTEM_NAME).getValue().toString() + ":" + cimInstance.getObjectPath().getKey(CP_DEVICE_ID).getValue().toString(); _log.debug("phantom checker: looking at volume to see what storage groups it's part of: {}", deviceName); // Get all of the storage groups associated with this volume sgPaths = getAssociatorInstances(storage, cimInstance.getObjectPath(), null, SmisConstants.SE_DEVICE_MASKING_GROUP, null, null, null); while (sgPaths.hasNext()) { CIMInstance sgPath = sgPaths.next(); String cacheKey = sgPath.toString(); StorageGroupInfo sgInfo = storageGroupInfoCache.get(cacheKey); if (sgInfo == null) { sgInfo = new StorageGroupInfo(); sgInfo.storageGroupName = CIMPropertyFactory.getPropertyValue(sgPath, SmisConstants.CP_ELEMENT_NAME); sgInfo.policyNames = this.findTierPoliciesForStorageGroup(storage, sgInfo.storageGroupName); sgInfo.isPartOfExistingParentGroups = checkStorageGroupAlreadyPartOfExistingParentGroups(storage, sgPath.getObjectPath()); storageGroupInfoCache.put(cacheKey, sgInfo); } if (sgInfo.policyNames != null && !sgInfo.policyNames.isEmpty() && !sgInfo.isPartOfExistingParentGroups) { discoveredGroupNames.add(sgInfo.storageGroupName); } } } // remove storage groups that are directly attached to the masking view discoveredGroupNames.remove(getStorageGroupForGivenMaskingView(maskingViewName, storage)); } } catch (Exception e) { _log.error("Failed trying to find existing Storage Groups under Masking View {}", maskingViewName, e); throw e; } finally { closeCIMIterator(sgPaths); } _log.info("Phantom SG check for Masking View {} found: {}", maskingViewName, discoveredGroupNames); return discoveredGroupNames; } /** * Finds the storage group attached to the masking view. * * @param maskingViewName * name of masking view * @param storage * storage system * @return name of storage group * @throws Exception */ public String getStorageGroupForGivenMaskingView(String maskingViewName, StorageSystem storage) throws Exception { CIMObjectPath maskingViewPath = _cimPath.getMaskingViewPath(storage, maskingViewName); CIMInstance maskingViewInstance = checkExists(storage, maskingViewPath, false, false); return getStorageGroupForGivenMaskingView(maskingViewInstance, maskingViewName, storage); } /** * Finds the storage group attached to the masking view. * * @param maskingViewInstance * CIMInstance that points to the Symm_LunMaskingView * @param maskingViewName * name of masking view * @param storage * storage system * @return name of storage group * @throws Exception */ public String getStorageGroupForGivenMaskingView(CIMInstance maskingViewInstance, String maskingViewName, StorageSystem storage) throws Exception { String discoveredGroupName = null; CloseableIterator<CIMInstance> deviceMaskingGroupPathItr = null; try { if (null == maskingViewInstance) { _log.error( "Masking View {} not available in Provider, either its deleted or provider might take some time to sync with Array. Try again if group is available on Array", maskingViewName); } else { _log.debug("Masking View {} found", maskingViewName); deviceMaskingGroupPathItr = getAssociatorInstances(storage, maskingViewInstance.getObjectPath(), null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.toString(), null, null, PS_ELEMENT_NAME); _log.info("Trying to find existing Storage Groups under Masking view {}", maskingViewName); while (deviceMaskingGroupPathItr.hasNext()) { discoveredGroupName = CIMPropertyFactory.getPropertyValue( deviceMaskingGroupPathItr.next(), SmisConstants.CP_ELEMENT_NAME); _log.info("Storage Group Name {} found", discoveredGroupName); } } } catch (Exception e) { _log.error("Failed trying to find existing Storage Groups under Masking View {}", maskingViewName, e); throw e; } finally { closeCIMIterator(deviceMaskingGroupPathItr); } return discoveredGroupName; } /** * Get IG associated with masking view * * @param maskingViewName * @param storage * @return * @throws Exception */ public CIMObjectPath getInitiatorGroupForGivenMaskingView(CIMObjectPath maskingViewPath, StorageSystem storage) throws Exception { CIMObjectPath iniGroup = null; CloseableIterator<CIMObjectPath> iniMaskingGroupPathItr = null; try { iniMaskingGroupPathItr = getAssociatorNames(storage, maskingViewPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_InitiatorMaskingGroup.toString(), null, null); if (iniMaskingGroupPathItr.hasNext()) { iniGroup = iniMaskingGroupPathItr.next(); } } catch (Exception e) { _log.error("Failed trying to find existing Storage Groups under Masking View {}", maskingViewPath, e); throw e; } finally { closeCIMIterator(iniMaskingGroupPathItr); } return iniGroup; } /** * Get IG associated with given masking view * * @param maskName * @param storage * @return * @throws Exception */ public CIMObjectPath getInitiatorGroupForGivenMaskingView(String maskName, StorageSystem storage) throws Exception { CIMObjectPath maskingViewPath = _cimPath.getMaskingViewPath(storage, maskName); return getInitiatorGroupForGivenMaskingView(maskingViewPath, storage); } /** * Gets the initiator names for initiator group. * * @param storage the storage * @param igPath the ig path * @return the initiators for initiator group * @throws WBEMException the WBEM exception */ public List<String> getInitiatorNamesForInitiatorGroup(StorageSystem storage, CIMObjectPath igPath) throws WBEMException { List<String> initiatorNames = new ArrayList<String>(); CloseableIterator<CIMInstance> initiatorsForIg = getAssociatorInstances(storage, igPath, null, SmisConstants.CP_SE_STORAGE_HARDWARE_ID, null, null, SmisConstants.PS_STORAGE_ID); if (initiatorsForIg != null) { while (initiatorsForIg.hasNext()) { CIMInstance initiatorInstance = initiatorsForIg.next(); String initiatorPort = CIMPropertyFactory.getPropertyValue(initiatorInstance, SmisConstants.CP_STORAGE_ID); initiatorNames.add(Initiator.normalizePort(initiatorPort)); } initiatorsForIg.close(); } return initiatorNames; } /** * Find a phantom (not belonging to any masking view) with matches the FAST (auto-tiering) policy name and limits * setting * * @param storage * storage device * @param storageGroupPolicyLimitsParam * policy name and limits setting * @return name of storage group that is a phantom SG with that policy, otherwise null * @throws Exception */ public List<String> findPhantomStorageGroupAssociatedWithFastPolicy(StorageSystem storage, StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam) throws Exception { CloseableIterator<CIMObjectPath> cimPathItr = null; List<String> sgNames = new ArrayList<String>(); try { // Get all storage groups _log.info("findPhantomStorageGroupAssociatedWithFastPolicy START: " + storageGroupPolicyLimitsParam); Map<StorageGroupPolicyLimitsParam, Set<String>> allStorageGroups = getExistingSGNamesFromArray(storage); Set<String> storageGroupsOfPolicy = allStorageGroups.get(storageGroupPolicyLimitsParam); if (storageGroupsOfPolicy == null || storageGroupsOfPolicy.isEmpty()) { return null; } for (String storageGroupName : storageGroupsOfPolicy) { StringSet policyNames = findTierPoliciesForStorageGroup(storage, storageGroupName); CIMObjectPath storageGroupPath = _cimPath.getStorageGroupObjectPath(storageGroupName, storage); if (this.isCascadedSG(storage, storageGroupPath)) { _log.info("findPhantomStorageGroupAssociatedWithFastPolicy avoiding storage group: " + storageGroupName + " because it is a parent storage group."); continue; } _log.debug("findPhantomStorageGroupAssociatedWithFastPolicy found policies: " + Joiner.on("\t").join(policyNames) + " on storage group: " + storageGroupName); // See if this storage group is associated with the policy we sent in. if (policyNames != null && policyNames.contains(storageGroupPolicyLimitsParam.getAutoTierPolicyName())) { _log.info("findPhantomStorageGroupAssociatedWithFastPolicy found policy on storage group: " + storageGroupName); // Now check to see if this storage group is associated with any masking views if (!checkStorageGroupInAnyMaskingView(storage, storageGroupPath)) { // Make sure this isn't a child storage group and its the parent(s) are not in masking views // to qualify as phantom storage group boolean inMaskView = false; cimPathItr = getAssociatorNames(storage, storageGroupPath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null); if (cimPathItr != null) { while (cimPathItr.hasNext() && !inMaskView) { CIMObjectPath parentObjectPath = cimPathItr.next(); if (checkStorageGroupInAnyMaskingView(storage, parentObjectPath)) { inMaskView = true; } } } if (!inMaskView) { _log.info("findPhantomStorageGroupAssociatedWithFastPolicy found policy on storage group: " + storageGroupName + " and it's not associated with a masking view, so it's a container for FAST volumes"); _log.info("findPhantomStorageGroupAssociatedWithFastPolicy END: " + storageGroupPolicyLimitsParam); sgNames.add(storageGroupName); } else { _log.info("findPhantomStorageGroupAssociatedWithFastPolicy found policy on storage group: " + storageGroupName + ", but it's associated indirectly with a masking view"); } } else { _log.info("findPhantomStorageGroupAssociatedWithFastPolicy found policy on storage group: " + storageGroupName + ", but it's associated with a masking view"); } closeCIMIterator(cimPathItr); } } } catch (Exception e) { _log.error("Failed trying to find existing Storage Groups with policy name", storageGroupPolicyLimitsParam, e); throw e; } finally { closeCIMIterator(cimPathItr); } _log.info("findPhantomStorageGroupAssociatedWithFastPolicy END: " + storageGroupPolicyLimitsParam); return sgNames; } /** * Determines which of the provided volumes URIs are already in the storage group * provided. Allows us to only remove the volumes that haven't been removed yet, * and assume success for the others. * * @param storage * storage system * @param storageGroupName * storage group name * @param volumeURIList * list of volumes * @return list of volumes from the volumeURIList that are in the storage group * @throws Exception */ public List<URI> findVolumesInStorageGroup(StorageSystem storage, String storageGroupName, List<URI> volumeURIList) throws Exception { List<URI> returnVolumes = new ArrayList<URI>(); CloseableIterator<CIMObjectPath> volumePathItr = null; try { List<BlockObject> bos = new ArrayList<>(); for (URI boURI : volumeURIList) { bos.add(Volume.fetchExportMaskBlockObject(_dbClient, boURI)); } volumePathItr = getAssociatorNames(storage, _cimPath.getStorageGroupObjectPath(storageGroupName, storage), null, SmisConstants.CIM_STORAGE_VOLUME, null, null); while (volumePathItr.hasNext()) { CIMObjectPath volumePath = volumePathItr.next(); for (BlockObject bo : bos) { String nativeGuid = getNativeGuid(bo); if (nativeGuid != null && nativeGuid.equalsIgnoreCase(getVolumeNativeGuid(volumePath))) { _log.info("Found object " + bo.getLabel() + " is in storage group " + storageGroupName); returnVolumes.add(bo.getId()); } } } return returnVolumes; } catch (Exception e) { throw e; } finally { closeCIMIterator(volumePathItr); } } /** * Gets the native GUID corresponding to the block object. If the BlockObject is a RP BlockSnapshot, the native GUID will reference the * RecoverPoint protection system. Obtain the BlockSnapshot's associated volume to get the correct native GUID. The associated volume is * referenced using the BlockSnapshot's sourceNativeId field. * * @param bo the BlockObject * @return the native GUID */ private String getNativeGuid(BlockObject bo) { String nativeGuid = ""; if (bo != null) { // Set the native GUID to its default nativeGuid = bo.getNativeGuid(); // If this is an RP BlockSnapshot, the native GUID will reference the RecoverPoint protection system. Obtain the // BlockSnapshot's associated volume to get the correct native GUID. The associated volume is referenced using // the BlockSnapshot's sourceNativeId field. if (URIUtil.isType(bo.getId(), BlockSnapshot.class) && BlockObject.checkForRP(_dbClient, bo.getId())) { URIQueryResultList result = new URIQueryResultList(); _dbClient.queryByConstraint(AlternateIdConstraint.Factory .getVolumeNativeGuidConstraint(bo.getNativeId()), result); Iterator<URI> volumeIterator = result.iterator(); while (volumeIterator.hasNext()) { Volume vol = _dbClient.queryObject(Volume.class, volumeIterator.next()); // Make sure the storage system of the volume matches that of the RP BlockSnapshot // to confirm a match. if (vol.getStorageController().equals(bo.getStorageController())) { nativeGuid = vol.getNativeGuid(); break; } } } } return nativeGuid; } /** * Filter volumes that are already part of the Replication Group. * * @param storage * the storage * @param replicationGroupPath * the replication group path * @param deviceIds * the volumes * @return new list with volumes to add * @throws Exception * the exception */ public Set<String> filterVolumesAlreadyPartOfReplicationGroup(StorageSystem storage, CIMObjectPath replicationGroupPath, String[] deviceIds) throws Exception { Set<String> volumes = new HashSet<String>(Arrays.asList(deviceIds)); Set<String> volumesInRG = getVolumeDeviceIdsFromStorageGroup( storage, replicationGroupPath); volumes.removeAll(volumesInRG); return volumes; } /** * Filter replicas that are already part of the Replication Group. * * @param storage * the storage * @param replicationGroupPath * the replication group path * @param deviceIds * the volumes * @return new list with volumes to add * @throws Exception * the exception */ public List<URI> filterReplicasAlreadyPartOfReplicationGroup(StorageSystem storage, String replicationGroupName, List<URI> replicas) throws Exception { List<URI> replicasToAdd = new ArrayList<URI>(); replicasToAdd.addAll(replicas); CIMObjectPath replicationGroupPath = _cimPath.getReplicationGroupPath(storage, ControllerUtils.extractGroupName(replicationGroupName)); List<URI> volumesInRG = findVolumesInReplicationGroup( storage, replicationGroupPath, replicas); replicasToAdd.removeAll(volumesInRG); return replicasToAdd; } /** * Determines which of the provided volumes URIs are already in the replication group * provided. * * @param storage * storage system * @param replicationGroupPath * the replication group path * @param volumeURIList * list of volumes * @return list of volumes from the volumeURIList that are in the storage group * @throws Exception * the exception */ public List<URI> findVolumesInReplicationGroup(StorageSystem storage, CIMObjectPath replicationGroupPath, List<URI> volumeURIList) throws Exception { List<URI> returnVolumes = new ArrayList<URI>(); CloseableIterator<CIMObjectPath> volumePathItr = null; try { List<BlockObject> bos = new ArrayList<>(); for (URI boURI : volumeURIList) { bos.add(BlockObject.fetch(_dbClient, boURI)); } volumePathItr = getAssociatorNames(storage, replicationGroupPath, null, SmisConstants.CIM_STORAGE_VOLUME, null, null); while (volumePathItr.hasNext()) { CIMObjectPath volumePath = volumePathItr.next(); for (BlockObject bo : bos) { if (bo.getNativeGuid().equalsIgnoreCase(getVolumeNativeGuid(volumePath))) { returnVolumes.add(bo.getId()); } } } return returnVolumes; } finally { closeCIMIterator(volumePathItr); } } /** * Check to see if this volume is in a masking view other than the one that was sent in. * If it is, it is likely a volume that is in a view that requires the volume to remain in * its phantom storage group * * @param storage * storage system * @param volumeId * volume ID * @param knownStorageGroupName * masking view name we already know about * @return true if the volume is in multiple masking views * @throws Exception */ public boolean isPhantomVolumeInMultipleMaskingViews(StorageSystem storage, URI volumeId, String knownStorageGroupName) throws Exception { CloseableIterator<CIMInstance> sgPaths = null; try { Volume volume = _dbClient.queryObject(Volume.class, volumeId); CIMObjectPath volumePath = this.getVolumeMember(storage, volume); if (volumePath != null) { CIMInstance cimInstance = this.getInstance(storage, volumePath, true, false, PS_ELEMENT_NAME); _log.info("phantom checker: looking at volume to see what storage groups it's part of: " + volume.getLabel()); // Get all of the storage groups associated with this volume sgPaths = getAssociatorInstances(storage, cimInstance.getObjectPath(), null, SmisConstants.SE_DEVICE_MASKING_GROUP, null, null, null); while (sgPaths.hasNext()) { CIMInstance sgPath = sgPaths.next(); String storageGroupName = CIMPropertyFactory.getPropertyValue(sgPath, SmisConstants.CP_ELEMENT_NAME); Set<String> policyNames = this.findTierPoliciesForStorageGroup(storage, storageGroupName); if ((policyNames == null || policyNames.isEmpty() || policyNames.contains(Constants.NONE.toString())) && !storageGroupName.equalsIgnoreCase(knownStorageGroupName)) { _log.info("Found that the volume is in storage group " + storageGroupName + " which has no FAST policy"); return true; } } } } catch (Exception e) { _log.error("Failed trying to find existing Storage Groups for volume {}", volumeId, e); throw e; } finally { closeCIMIterator(sgPaths); } return false; } public void removeVolumeGroupFromPolicyAndLimitsAssociation(WBEMClient client, StorageSystem storage, CIMObjectPath volumeGroupPath) throws Exception { _log.debug("{} removeVolumeGroupFromPolicyAndLimitsAssociation START...", storage.getSerialNumber()); if (!storage.checkIfVmax3()) { removeVolumeGroupFromAutoTieringPolicy(storage, volumeGroupPath); } resetHostIOLimits(client, storage, volumeGroupPath); _log.debug("{} removeVolumeGroupFromPolicyAndLimitsAssociation END...", storage.getSerialNumber()); } public boolean isFastPolicy(String policyName) { return !StringUtils.isEmpty(policyName) && !StringUtils.equalsIgnoreCase(Constants.NONE, policyName); } /** * Construct a storage group policy limits object from a volumeURIHLU object. * * @param volumeUriHLUs * @param dbClient * @return */ public StorageGroupPolicyLimitsParam createStorageGroupPolicyLimitsParam( Collection<VolumeURIHLU> volumeUriHLUs, StorageSystem storage, DbClient dbClient) { StorageGroupPolicyLimitsParam policyQuota = new StorageGroupPolicyLimitsParam(Constants.NONE); for (VolumeURIHLU volumeUriHLU : volumeUriHLUs) { String policyName = null; if (storage.checkIfVmax3()) { policyName = getVMAX3FastSettingForVolume(volumeUriHLU.getVolumeURI(), volumeUriHLU.getAutoTierPolicyName()); } else { policyName = volumeUriHLU.getAutoTierPolicyName(); } policyQuota = new StorageGroupPolicyLimitsParam(policyName, volumeUriHLU.getHostIOLimitBandwidth(), volumeUriHLU.getHostIOLimitIOPs(), storage); break; } return policyQuota; } /** * Construct a storage group policy limits based on info extracted from SMIS storage group object * * @param storage * storage system * @param groupInstance * SMIS storage group instance * @return */ public StorageGroupPolicyLimitsParam createStorageGroupPolicyLimitsParam(StorageSystem storage, CIMInstance groupInstance) throws WBEMException { StorageGroupPolicyLimitsParam storageGroupPolicyLimitsParam = null; String hostIOLimitBandwidth = CIMPropertyFactory.getPropertyValue(groupInstance, EMC_MAX_BANDWIDTH); String hostIOLimitIOPs = CIMPropertyFactory.getPropertyValue(groupInstance, EMC_MAX_IO); if (storage.checkIfVmax3()) { storageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(CIMPropertyFactory.getPropertyValue(groupInstance, CP_FAST_SETTING), hostIOLimitBandwidth, hostIOLimitIOPs, storage); storageGroupPolicyLimitsParam .setCompression(SmisUtils.getEMCCompressionForStorageGroup(groupInstance)); } else { storageGroupPolicyLimitsParam = new StorageGroupPolicyLimitsParam(getAutoTieringPolicyNameAssociatedWithVolumeGroup(storage, groupInstance.getObjectPath()), hostIOLimitBandwidth, hostIOLimitIOPs, storage); } return storageGroupPolicyLimitsParam; } /** * Get Port Groups within the masking View. * * @param system * @param mvName * @return * @throws Exception */ public CIMInstance getPortGroupInstance(StorageSystem system, String mvName) throws Exception { CIMObjectPath maskingViewPathPath = _cimPath.getMaskingViewPath(system, mvName); CloseableIterator<CIMInstance> cimPathItr = null; try { _log.info("Trying to find the port groups within masking view {}", mvName); cimPathItr = getAssociatorInstances(system, maskingViewPathPath, null, MASKING_GROUP_TYPE.SE_TargetMaskingGroup.name(), null, null, PS_ELEMENT_NAME); while (cimPathItr.hasNext()) { return cimPathItr.next(); } } finally { closeCIMIterator(cimPathItr); } return null; } /** * Check volume is already added to any phantom sg with expected fast * * @param volNativeId * @param groupName * @param storage * @param policy * @return */ public boolean checkVolumeAssociatedWithAnyPhantomSG(String volNativeId, String groupName, StorageSystem storage, String policy) { CloseableIterator<CIMInstance> sgInstanceIr = null; try { _log.info("Trying to find volume {} is associated with any phantom SG with expected FAST {}", volNativeId, policy); CIMObjectPath volumePath = _cimPath.getVolumePath(storage, volNativeId); sgInstanceIr = getAssociatorInstances(storage, volumePath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, SmisConstants.PS_ELEMENT_NAME); while (sgInstanceIr.hasNext()) { CIMInstance sgInstance = sgInstanceIr.next(); String gpNameFound = (String) sgInstance.getPropertyValue(SmisConstants.CP_ELEMENT_NAME); if (groupName.equalsIgnoreCase(gpNameFound)) { continue; } _log.info("Volume {} available in other SG {}", volNativeId, gpNameFound); if (!checkStorageGroupInAnyMaskingView(storage, sgInstance.getObjectPath()) && checkVolumeGroupAssociatedWithPolicy(storage, sgInstance.getObjectPath(), policy)) { return true; } } } catch (Exception e) { _log.warn("Find volume associated with any phantom SG with right policy failed", e); } finally { if (null != sgInstanceIr) { sgInstanceIr.close(); } } _log.info("No Phantom SGs found for volume {}", volNativeId); return false; } /** * Check volume associated with any SG with fast policy applied, irrespective of MVs. * * @param volNativeId * @param storage * @param policy * @return */ public boolean checkVolumeAssociatedWithAnySGWithPolicy(String volNativeId, StorageSystem storage, String policy) { CloseableIterator<CIMInstance> sgInstanceIr = null; try { _log.info("Trying to find volume {} is associated with any phantom SG with expected FAST {}", volNativeId, policy); CIMObjectPath volumePath = _cimPath.getVolumePath(storage, volNativeId); sgInstanceIr = getAssociatorInstances(storage, volumePath, null, SmisCommandHelper.MASKING_GROUP_TYPE.SE_DeviceMaskingGroup.name(), null, null, SmisConstants.PS_ELEMENT_NAME); while (sgInstanceIr.hasNext()) { CIMInstance sgInstance = sgInstanceIr.next(); String gpNameFound = (String) sgInstance.getPropertyValue(SmisConstants.CP_ELEMENT_NAME); _log.info("Volume {} available in other SG {}", volNativeId, gpNameFound); if (checkVolumeGroupAssociatedWithPolicy(storage, sgInstance.getObjectPath(), policy)) { return true; } } } catch (Exception e) { _log.warn("Find volume associated with any phantom SG with right policy failed", e); } finally { if (null != sgInstanceIr) { sgInstanceIr.close(); } } _log.info("No Phantom SGs found for volume {}", volNativeId); return false; } /** * Verify atleast 1 volume in SG is already associated with Fast through phantom sgs. * * @param sgPath * @param storage * @param policy * @return * @throws Exception */ public boolean checkVolumeAssociatedWithPhantomSG(CIMObjectPath sgPath, StorageSystem storage, String policy) throws Exception { String groupName = null; try { groupName = (String) sgPath.getKey(SmisConstants.CP_INSTANCE_ID).getValue(); Set<String> volIds = getVolumeDeviceIdsFromStorageGroup(storage, sgPath); for (String id : volIds) { return checkVolumeAssociatedWithAnyPhantomSG(id, groupName, storage, policy); } } catch (Exception e) { // TODO till SMI-s OPT gets resolved, will have this fix.The impact // would be seen only in a single Node cluster with Phantom SG // adding a new Node will fail. _log.warn("Storage Group {} is not refreshed in DB yet", groupName, e); } return false; } public List<CIMObjectPath> getReplicationRelationships(StorageSystem sourceSystem, int localityValue, int syncType, int mode, int synchronizationType) throws WBEMException { CIMArgument[] inArgs = new CIMArgument[] { _cimArgument.uint16(CP_LOCALITY, localityValue), _cimArgument.uint16(CP_MODE, mode), _cimArgument.uint16(CP_SYNC_TYPE, syncType), _cimArgument.uint16(CP_TYPE, synchronizationType) }; CIMArgument[] outArgs = new CIMArgument[5]; CIMObjectPath repSvcPath = _cimPath.getControllerReplicationSvcPath(sourceSystem); invokeMethod(sourceSystem, repSvcPath, GET_REPLICATION_RELATIONSHIPS, inArgs, outArgs); for (CIMArgument arg : outArgs) { if (arg != null && arg.getName().equalsIgnoreCase(SYNCHRONIZATIONS)) { CIMObjectPath[] synchronizations = (CIMObjectPath[]) arg.getValue(); return asList(synchronizations); } } return Collections.EMPTY_LIST; } public CIMArgument[] getSRDFRestoreInputArguments(CIMObjectPath syncPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_REPLICA), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, syncPath) }; } public CIMArgument[] getSRDFRestoreInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_REPLICA), _cimArgument.bool(CP_FORCE, true), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMArgument[] getActiveSRDFRestoreInputArguments(CIMObjectPath syncPath) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_REPLICA), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED), _cimArgument.bool(CP_FORCE, true), _cimArgument.reference(CP_SYNCHRONIZATION, syncPath) }; } public CIMArgument[] getActiveSRDFRestoreInputArguments(Collection<CIMObjectPath> syncPaths) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, RESTORE_FROM_REPLICA), _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED), _cimArgument.bool(CP_FORCE, true), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncPaths.toArray(new CIMObjectPath[] {})) }; } public CIMObjectPath getDeviceGroup(final StorageSystem system, final StorageSystem forProvider, final BlockObject volume, final DbClient dbClient) throws Exception { URI cgUri = volume.getConsistencyGroup(); BlockConsistencyGroup cgObj = dbClient.queryObject(BlockConsistencyGroup.class, cgUri); String cgName = cgObj.getAlternateLabel(); if (null == cgName) { cgName = cgObj.getLabel(); } CIMObjectPath groupPath = checkDeviceGroupExists(cgName, forProvider, system); return groupPath; } public CIMObjectPath checkDeviceGroupExists(final String cgName, final StorageSystem forProvider, final StorageSystem system) { CloseableIterator<CIMObjectPath> names = null; try { CIMObjectPath path = _cimPath.getStorageSystem(system); names = getAssociatorNames(forProvider, path, null, SE_REPLICATION_GROUP, null, null); while (names.hasNext()) { CIMObjectPath replicationGroupPath = names.next(); String instanceId = replicationGroupPath.getKey(CP_INSTANCE_ID).getValue() .toString(); // Format // VMAX2: SE_ReplicationGroup.InstanceID="SynchCG+1+SYMMETRIX+000195701505" // VMAX3: SE_ReplicationGroup.InstanceID="000196700572+testRG" String repName = null; if (forProvider.getUsingSmis80()) { repName = instanceId.split(Constants.PATH_DELIMITER_REGEX)[1]; } else { repName = instanceId.split(Constants.PATH_DELIMITER_REGEX)[0]; } if (repName.equalsIgnoreCase(cgName)) { return replicationGroupPath; } } } catch (WBEMException e) { _log.warn("Failed to get Device Group {}", cgName, e); } finally { if (null != names) { names.close(); } } return null; } public CIMInstance getReplicationSettingDataInstance(final StorageSystem sourceSystem) { CIMInstance modifiedInstance = null; try { CIMObjectPath replicationSettingCapabilities = _cimPath .getReplicationServiceCapabilitiesPath(sourceSystem); CIMArgument[] inArgs = getReplicationSettingDataInstance(); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(sourceSystem, replicationSettingCapabilities, "GetDefaultReplicationSettingData", inArgs, outArgs); for (CIMArgument<?> outArg : outArgs) { if (null == outArg) { continue; } if (outArg.getName().equalsIgnoreCase(DEFAULT_INSTANCE)) { CIMInstance repInstance = (CIMInstance) outArg.getValue(); if (null != repInstance) { CIMProperty<?> existingProp = repInstance.getProperty(EMC_CONSISTENCY_EXEMPT); CIMProperty<?> prop = null; if (existingProp == null) { // ConsistencyExempt property is now part of the smi-s standard. Available in providers 8.0+ // (VMAX3 arrays) // EMCConsistencyExempt property in ReplicationSettingData is removed existingProp = repInstance.getProperty(CONSISTENCY_EXEMPT); prop = new CIMProperty<Object>(CONSISTENCY_EXEMPT, existingProp.getDataType(), true); } else { prop = new CIMProperty<Object>(EMC_CONSISTENCY_EXEMPT, existingProp.getDataType(), true); } CIMProperty<?>[] propArray = new CIMProperty<?>[] { prop }; modifiedInstance = repInstance.deriveInstance(propArray); break; } } } } catch (Exception e) { _log.error("Error retrieving Replication Setting Data Instance ", e); } return modifiedInstance; } /** * This is a distributed process protected operation that checks each CIMInstance in * the 'parkingSLOStorageGroups' set to see if it has no volumes associated it. * If so, it will be deleted. * * @param storage * [in] - StorageSystem object against which the StorageGroups belong * @param _locker * [in] - Locking service to protect access across * @param parkingSLOStorageGroups * [in] - Set of SE_DeviceMaskingGroup CIMInstance objects * @throws Exception if there is a issue in deleting ParikingSLOStorageGroup */ public void deleteParkingSLOStorageGroupsIfEmpty(StorageSystem storage, Set<CIMInstance> parkingSLOStorageGroups) throws Exception { String currentHeldLockName = null; CloseableIterator<CIMObjectPath> volumeIterator = null; try { for (CIMInstance seDeviceMaskingInstance : parkingSLOStorageGroups) { CIMProperty elementNameProperty = seDeviceMaskingInstance.getProperty(SmisConstants.CP_ELEMENT_NAME); String groupName = elementNameProperty.getValue().toString(); String lockName = generateParkingSLOSGLockName(storage, groupName); // Get the lock for this StorageGroup and process it if (_locker.acquireLock(lockName, PARKING_SLO_SG_LOCK_WAIT_SECS)) { currentHeldLockName = lockName; volumeIterator = getAssociatorNames(storage, seDeviceMaskingInstance.getObjectPath(), null, CIM_STORAGE_VOLUME, null, null); if (volumeIterator != null && !volumeIterator.hasNext()) { // There are no volume paths associated to this DeviceMaskingGroup, so we can delete it now. deleteMaskingGroup(storage, groupName, MASKING_GROUP_TYPE.SE_DeviceMaskingGroup); volumeIterator.close(); volumeIterator = null; } _locker.releaseLock(lockName); currentHeldLockName = null; } else { currentHeldLockName = null; _log.warn(String.format("Could not get lock %s while trying to deleteParkingSLOStorageGroupsIfEmpty", lockName)); throw DeviceControllerException.exceptions.failedToAcquireLock(lockName, "deleteParkingSLOStorageGroupsIfEmpty"); } } // Refresh the SMI-S provider to make sure that any other clients of SMI-S have the current // state of the changes on the array after we've processed all the StorageGroups. callRefreshSystem(storage, null); } catch (Exception e) { _log.error("An exception while processing deleteParkingSLOStorageGroupsIfEmpty", e); throw e; } finally { // Cleanup any iterator that may have been open but not yet closed if (volumeIterator != null) { volumeIterator.close(); } // In case of some failure, release any lock that might have been acquired if (currentHeldLockName != null) { _locker.releaseLock(currentHeldLockName); } } } private String generateParkingSLOSGLockName(StorageSystem storageSystem, String groupName) { return String.format("%s-%s-lock", storageSystem.getSerialNumber(), groupName); } public CIMArgument[] getCreateListReplicaInputArguments(StorageSystem storageDevice, CIMObjectPath[] sourceVolumePath, CIMObjectPath[] targetVolumePath) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.referenceArray(CP_SOURCE_ELEMENTS, sourceVolumePath)); args.add(_cimArgument.referenceArray(CP_TARGET_ELEMENTS, targetVolumePath)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, MIRROR_VALUE)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, ACTIVATE_VALUE)); return args.toArray(new CIMArgument[args.size()]); } /** * Construct input arguments for calling CreateListReplica. * * @param storageDevice * @param sourceVolumePath * @param targetVolumePath * @param labels * @param syncType * @param replicaName * @param sessionName * @param createInactive * @return */ public CIMArgument[] getCreateListReplicaInputArguments(StorageSystem storageDevice, CIMObjectPath[] sourceVolumePath, CIMObjectPath[] targetVolumePath, List<String> labels, int syncType, String replicaName, String sessionName, boolean createInactive, CIMObjectPath targetVPSnapPoolPath) { List<CIMArgument> args = new ArrayList<CIMArgument>(); int inactiveValue = (syncType == SmisConstants.CLONE_VALUE) ? PREPARED_VALUE : INACTIVE_VALUE; int waitForCopyState = (createInactive) ? inactiveValue : ACTIVATE_VALUE; args.add(_cimArgument.referenceArray(CP_SOURCE_ELEMENTS, sourceVolumePath)); if (targetVolumePath != null && targetVolumePath.length > 0) { args.add(_cimArgument.referenceArray(CP_TARGET_ELEMENTS, targetVolumePath)); } else if (labels != null) { args.add(_cimArgument.stringArray(CP_ELEMENT_NAMES, labels.toArray(new String[] {}))); } args.add(_cimArgument.uint16(CP_SYNC_TYPE, syncType)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, waitForCopyState)); if (storageDevice.deviceIsType(Type.vmax)) { CIMInstance repSettingData = null; if (syncType == SmisConstants.CLONE_VALUE) { if (createInactive && storageDevice.getUsingSmis80()) { repSettingData = getReplicationSettingDataInstanceForDesiredCopyMethod(storageDevice, replicaName, COPY_BEFORE_ACTIVATE, true); } else if (storageDevice.checkIfVmax3() && ControllerUtils.isVmaxUsing81SMIS(storageDevice, _dbClient)) { /** * VMAX3 using SMI 8.1 provider needs to send DesiredCopyMethodology=32770 * to create TimeFinder differential clone. */ repSettingData = getReplicationSettingDataInstanceForDesiredCopyMethod(storageDevice, replicaName, SMIS810_TF_DIFFERENTIAL_CLONE_VALUE, true); } else { repSettingData = getReplicationSettingDataInstanceForDesiredCopyMethod(storageDevice, replicaName, DIFFERENTIAL_CLONE_VALUE, true); } } else if (syncType == SmisConstants.SNAPSHOT_VALUE) { // For VMAX2 arrays use the VPSNAPS during createListReplica. if (!storageDevice.checkIfVmax3()) { repSettingData = getReplicationSettingDataInstanceForDesiredCopyMethod(storageDevice, replicaName, VP_SNAP_VALUE, true); if (targetVPSnapPoolPath != null) { // set the target pool path args.add(_cimArgument.reference(CP_TARGET_POOL, targetVPSnapPoolPath)); } } else { // For VMAX3, we always create snapvx snapshots repSettingData = getReplicationSettingDataInstanceForDesiredCopyMethod(storageDevice, sessionName, INSTRUMENTATION_DECIDES_VALUE, true); } } args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, repSettingData)); } return args.toArray(new CIMArgument[args.size()]); } public CIMArgument[] getCreateListReplicaInputArguments(StorageSystem storageDevice, CIMObjectPath[] sourceVolumePath, CIMObjectPath[] targetVolumePath, int mode, CIMObjectPath repCollection, CIMInstance repSetting, boolean addWaitForCopyState) { List<CIMArgument> args = new ArrayList<>(); args.add(_cimArgument.referenceArray(CP_SOURCE_ELEMENTS, sourceVolumePath)); args.add(_cimArgument.referenceArray(CP_TARGET_ELEMENTS, targetVolumePath)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, MIRROR_VALUE)); args.add(_cimArgument.uint16(CP_MODE, mode)); args.add(_cimArgument.reference(CP_CONNECTIVITY_COLLECTION, repCollection)); // WaitForCopyState only valid for Synchronous mode // Or Active Mode when adding pairs to an empty RDF group. if (SRDFOperations.Mode.SYNCHRONOUS.getMode() == mode || addWaitForCopyState) { args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED)); } if (repSetting != null) { args.add(_cimArgument.object(CP_REPLICATION_SETTING_DATA, repSetting)); } return args.toArray(new CIMArgument[args.size()]); } public CIMArgument[] getModifyListReplicaInputArguments(CIMObjectPath[] syncObjectPaths, int operationValue) { return new CIMArgument[] { _cimArgument.bool(CP_EMC_SYNCHRONOUS_ACTION, true), _cimArgument.uint16(CP_OPERATION, operationValue), _cimArgument.referenceArray(CP_SYNCHRONIZATION, syncObjectPaths) }; } public CIMArgument[] getModifyListReplicaInputArguments(CIMObjectPath[] syncObjectPaths, int operation, int copyState) { CIMArgument[] baseArgs = getModifyListReplicaInputArguments(syncObjectPaths, operation); List<CIMArgument> args = new ArrayList<>(Arrays.asList(baseArgs)); if (copyState != NON_COPY_STATE) { args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, copyState)); } return args.toArray(new CIMArgument[] {}); } public CIMObjectPath getPoolPath(StorageSystem storageSystem, StoragePool storagePool) { CIMProperty[] inPoolPropKeys = { _cimProperty.string(CP_INSTANCE_ID, _cimPath.getPoolName(storageSystem, storagePool.getNativeId())) }; return CimObjectPathCreator.createInstance(storagePool.getPoolClassName(), _cimConnection.getNamespace(storageSystem), inPoolPropKeys); } public CIMArgument[] getCreateElementReplicaMirrorInputArgumentsWithReplicationSettingData(StorageSystem storageDevice, BlockObject volume, StoragePool pool, boolean createInactive, CIMInstance replicationSettingData, String label) { return getCreateElementReplicaInputArgumentsWithReplicationSettingData(storageDevice, volume, pool, createInactive, label, replicationSettingData, MIRROR_VALUE); } public CIMArgument[] getCreateElementReplicaInputArgumentsWithReplicationSettingData( StorageSystem storageDevice, BlockObject volume, StoragePool pool, boolean createInactive, String label, CIMInstance replicationSettingData, int syncType) { int waitForCopyState = (createInactive) ? INACTIVE_VALUE : ACTIVATE_VALUE; CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageDevice, volume); List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.string(CP_ELEMENT_NAME, label)); args.add(_cimArgument.uint16(CP_SYNC_TYPE, syncType)); args.add(_cimArgument.reference(CP_SOURCE_ELEMENT, volumePath)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, waitForCopyState)); if (pool != null) { addTargetPoolToArgs(storageDevice, pool, args); } if (replicationSettingData != null) { args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, replicationSettingData)); } return args.toArray(new CIMArgument[] {}); } /** * Get SettingsDefineState instances based on source or source group * * @param storage * StorageSystem that holds the SettingsDefineState instances * @param blockObject * BlockObject representing the source of replication * @param snapshot * BlockSnapshot of the source blockObject * @return A List of CIMObjectPaths for SettingsDefineState instances * @throws WBEMException */ public List<CIMObjectPath> getSettingsDefineStatePaths( StorageSystem storage, BlockObject blockObject, BlockSnapshot snapshot) throws WBEMException { if (blockObject.hasConsistencyGroup() && NullColumnValueGetter.isNotNullValue(blockObject.getReplicationGroupInstance())) { return getSettingsDefineStateFromSourceGroup(storage, blockObject); } return getSettingsDefineStateFromSource(storage, blockObject); } /** * Get Synchronization aspects associated with the source block object, then * constructs SettingsDefineState instances based on the source and aspects. * * @param storage * StorageSystem that holds the SettingsDefineState instances * @param blockObject * BlockObject representing the source of replication * @return A List of CIMObjectPaths for SettingsDefineState instances * @throws WBEMException */ private List<CIMObjectPath> getSettingsDefineStateFromSource( StorageSystem storage, BlockObject blockObject) throws WBEMException { List<CIMObjectPath> settingsDefineStatePaths = new ArrayList<>(); CIMObjectPath blockObjectPath = _cimPath.getBlockObjectPath(storage, blockObject); CloseableIterator<CIMInstance> aspectInstancesItr = null; CloseableIterator<CIMObjectPath> groupSyncRefs = null; try { aspectInstancesItr = getAssociatorInstances(storage, blockObjectPath, null, SYMM_SYNCHRONIZATION_ASPECT_FOR_SOURCE, null, null, new String[] { CP_SYNC_TYPE, CP_SYNC_STATE }); while (aspectInstancesItr.hasNext()) { CIMInstance aspectInstance = aspectInstancesItr.next(); CIMObjectPath aspectPath = aspectInstance.getObjectPath(); String syncType = CIMPropertyFactory.getPropertyValue( aspectInstance, CP_SYNC_TYPE); String syncState = CIMPropertyFactory.getPropertyValue( aspectInstance, CP_SYNC_STATE); if (SNAPSHOT_SYNC_TYPE_STR.equals(syncType) && RESTORED_SYNC_STATE_STR.equals(syncState)) { CIMProperty[] settingsKeys = { _cimProperty.reference(CP_MANAGED_ELEMENT, blockObjectPath), _cimProperty.reference(CP_SETTING_DATA, aspectPath) }; settingsDefineStatePaths.add(CimObjectPathCreator .createInstance(SYMM_SETTINGS_DEFINE_STATE_SV_SAFS, ROOT_EMC_NAMESPACE, settingsKeys)); } } } finally { closeCIMIterator(aspectInstancesItr); } return settingsDefineStatePaths; } /** * Get SettingsDefineState instances related to the consistency group that * the source of the BlockSnapshot object belongs to. * * There is no association between source group and Synchronization aspects * (unlike source volume). * Steps - * 1. get consistency group from block snapshot * 2. get the CIMObjectPath of the consistency group * 3. query aspect instances with desired SyncType, SyncState, and array serial number in SourceElement * 4. check if SourceElement is the consistency group * 5. if yes, construct SettingsDefineState based on the source group and aspect * * @param storage * StorageSystem that holds the SettingsDefineState instances * @param groupMember * BlockObject that is part of a snapshot group * @return A List of CIMObjectPaths for SettingsDefineState instances * @throws WBEMException */ public List<CIMObjectPath> getSettingsDefineStateFromSourceGroup( StorageSystem storage, BlockObject groupMember) throws WBEMException { List<CIMObjectPath> settingsDefineStatePaths = new ArrayList<>(); String groupName = ConsistencyGroupUtils.getSourceConsistencyGroupName(groupMember, _dbClient); CIMObjectPath groupPath = _cimPath.getReplicationGroupPath(storage, groupName); /* * Query SourceElement name with groupPath string doesn't work as it is * actually an object path. Since there are special chars in the * InstanceID of groupPath (e.g, "+", "_"), avoid using the InstanceID * string in the LIKE operator. */ String query = String.format( "SELECT %s FROM %s WHERE %s='%s' AND %s='%s' AND %s LIKE '%s'", CP_SOURCE_ELEMENT, SYMM_SYNCHRONIZATION_ASPECT_FOR_SOURCE_GROUP, CP_SYNC_TYPE, SNAPSHOT_SYNC_TYPE_STR, CP_SYNC_STATE, RESTORED_SYNC_STATE_STR, CP_SOURCE_ELEMENT, storage.getSerialNumber()); List<CIMInstance> aspectList = executeQuery(storage, query, "wql"); if (aspectList != null && !aspectList.isEmpty()) { for (CIMInstance aspectInstance : aspectList) { String sourceElement = CIMPropertyFactory.getPropertyValue( aspectInstance, CP_SOURCE_ELEMENT); if (sourceElement.equalsIgnoreCase(groupPath.toString())) { // class name is lower case in SourceElement CIMProperty[] settingsKeys = { _cimProperty.reference(CP_MANAGED_ELEMENT, groupPath), _cimProperty.reference(CP_SETTING_DATA, aspectInstance.getObjectPath()) }; settingsDefineStatePaths.add(CimObjectPathCreator .createInstance(SYMM_SETTINGS_DEFINE_STATE_RG_SAFS, ROOT_EMC_NAMESPACE, settingsKeys)); } } } return settingsDefineStatePaths; } public CIMArgument[] getEMCResumeInputArguments( CIMObjectPath settingsStatePath) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, RESUME_FROM_SYNC_SETTINGS), _cimArgument.reference(CP_SETTINGS_STATE, settingsStatePath) }; } /* * Create ReplicationSettingData for single volume/group snapshot */ public CIMInstance getReplicationSettingData(StorageSystem storage, String snapSettingName, boolean isGroupConsistency) throws WBEMException { CIMInstance modifiedInstance = null; CloseableIterator<CIMInstance> repSvcCapIter = null; try { repSvcCapIter = getAssociatorInstances(storage, _cimPath.getControllerReplicationSvcPath(storage), null, _cimPath.prefixWithParamName(SmisConstants.REPLICATION_SERVICE_CAPABILTIES), null, null, null); if (repSvcCapIter != null && repSvcCapIter.hasNext()) { CIMInstance instance = repSvcCapIter.next(); CIMArgument[] in = getDefaultReplicationSettingDataInputArgumentsForSnapshot(); CIMArgument[] out = new CIMArgument[5]; invokeMethod(storage, instance.getObjectPath(), SmisConstants.GET_DEFAULT_REPLICATION_SETTING_DATA, in, out); CIMInstance defaultInstance = (CIMInstance) _cimPath.getFromOutputArgs(out, SmisConstants.DEFAULT_INSTANCE); // populate properties List<CIMProperty> propList = new ArrayList<CIMProperty>(); propList.add(new CIMProperty<Object>(SmisConstants.CP_ELEMENT_NAME, CIMDataType.STRING_T, snapSettingName)); for (CIMProperty prop : defaultInstance.getProperties()) { if (isGroupConsistency && prop.getName().equals(SmisConstants.CP_CONSISTENT_POINT_IN_TIME)) { propList.add(new CIMProperty<Object>(prop.getName(), prop.getDataType(), true)); } else if (!prop.getName().equals(SmisConstants.CP_ELEMENT_NAME)) { propList.add(prop); } } // ElementName is not in the defaultInstance, hence cannot be modified via // defaultInstance.deriveInstance // construct a new path, then create a new instance modifiedInstance = new CIMInstance(_cimPath.getReplicationSettingObjectPathFromDefault(defaultInstance), propList.toArray(new CIMProperty[] {})); } } finally { if (repSvcCapIter != null) { repSvcCapIter.close(); } } return modifiedInstance; } public boolean checkGroupEmpty(StorageSystem system, CIMObjectPath groupPath) throws WBEMException { CloseableIterator<CIMObjectPath> volumeIter = getAssociatorNames(system, groupPath, null, SmisConstants.CIM_STORAGE_VOLUME, null, null); boolean result = true; if (volumeIter != null && volumeIter.hasNext()) { result = false; } if (volumeIter != null) { volumeIter.close(); } return result; } public CIMArgument[] getResyncSnapshotWithWaitInputArguments(CIMObjectPath syncObjectPath) { return new CIMArgument[] { _cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, ACTIVATE_VALUE), _cimArgument.uint16(CP_OPERATION, RESYNC_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObjectPath), _cimArgument.bool(CP_FORCE, true) }; } /** * Verifies whether the group has replicas in split state. * When new replicas are added to the group, they can be in Sync state & old mirrors could be in SPLIT state. * Hence to make the group consistent, we should check for the syncState of all replicas in the group. * if there is any replica in split state, then resume the complete group. * * @param storage * @param replicaList * @param clazz * @return */ public <T extends BlockObject> boolean groupHasReplicasInSplitState(StorageSystem storage, List<URI> replicaList, Class<T> clazz) { Iterator<T> replicaObjsItr = _dbClient.queryIterativeObjects(clazz, replicaList, true); while (replicaObjsItr.hasNext()) { T replicaObj = replicaObjsItr.next(); CIMObjectPath syncObjCoP = _cimPath.getSyncObject(storage, replicaObj); _log.debug("Verifying replica {} sync state.", replicaObj.getId()); try { CIMInstance instance = getInstance(storage, syncObjCoP, false, false, new String[] { SmisConstants.CP_SYNC_STATE }); if (null == instance) { continue; } String syncState = CIMPropertyFactory.getPropertyValue(instance, SmisConstants.CP_SYNC_STATE); if (SynchronizationState.FRACTURED.toString().equals(syncState)) { _log.info("Found a replica {} in Split state", replicaObj.getId()); return true; } } catch (Exception e) { String msg = String.format("Failed to acquire sync instance %s. continuing with next.. ", syncObjCoP); _log.warn(msg, e); } } _log.info("All replicas in the group are in SYNC state. No resume required"); return false; } /** * Creates an explicitly sized array of generic type T, containing the given value for all its elements. * * Example: * toMultiElementArray(2, true); => boolean[] array = new boolean[2] { true, true}; * * @param count * size of the array * @param value * value for each element * @param <T> * type of array * * @return Array of T, containing the same value for each element. */ public static <T> T[] toMultiElementArray(int count, T value) { T[] array = (T[]) Array.newInstance(value.getClass(), count); for (int i = 0; i < count; i++) { array[i] = value; } return array; } public String createVolumesMethodName(StorageSystem storageSystem) { return storageSystem.getUsingSmis80() ? EMC_CREATE_MULTIPLE_TYPE_ELEMENTS_FROM_STORAGE_POOL : CREATE_OR_MODIFY_ELEMENT_FROM_STORAGE_POOL; } /** * Get source object for a replica. * * @param dbClient * @param replica * * @return source object */ public BlockObject getSource(BlockObject replica) { URI sourceURI; if (replica instanceof BlockSnapshot) { sourceURI = ((BlockSnapshot) replica).getParent().getURI(); } else if (replica instanceof BlockMirror) { sourceURI = ((BlockMirror) replica).getSource().getURI(); } else { sourceURI = ((Volume) replica).getAssociatedSourceVolume(); } return BlockObject.fetch(_dbClient, sourceURI); } /** * Add CIMArgument to CIMArgument[] * * @param args * @param element * @return new CIMArgument[] */ public CIMArgument[] addElement(CIMArgument[] args, CIMArgument element) { List<CIMArgument> argsList = new ArrayList<CIMArgument>(Arrays.asList(args)); argsList.add(element); CIMArgument[] argsNew = {}; return argsList.toArray(argsNew); } public CIMInstance getReplicationSettingDataInstanceForDesiredCopyMethod(final StorageSystem storageSystem, int desiredValue, Boolean setTargetSupplier) { return this.getReplicationSettingDataInstanceForDesiredCopyMethod(storageSystem, null, desiredValue, setTargetSupplier); } /* * Get ReplicationSettingData instance. * * @param storageSystem A reference to the storage system * * @param elementName An optional name for the instance * * @param desiredValue DesiredCopyMethodology value * * @param steTargetSupplier Whether or not the TargetElementSupplier should also be specified. */ @SuppressWarnings("rawtypes") public CIMInstance getReplicationSettingDataInstanceForDesiredCopyMethod(final StorageSystem storageSystem, String elementName, int desiredValue, Boolean setTargetSupplier) { CIMInstance modifiedInstance = null; // only for vmax, otherwise, return null if (!storageSystem.deviceIsType(Type.vmax)) { return modifiedInstance; } try { CIMObjectPath replicationSettingCapabilities = _cimPath .getReplicationServiceCapabilitiesPath(storageSystem); CIMArgument[] inArgs = getReplicationSettingDataInstance(); CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(storageSystem, replicationSettingCapabilities, GET_DEFAULT_REPLICATION_SETTING_DATA, inArgs, outArgs); for (CIMArgument<?> outArg : outArgs) { if (null == outArg) { continue; } ArrayList<CIMProperty> list = new ArrayList<>(); if (outArg.getName().equalsIgnoreCase(SmisConstants.DEFAULT_INSTANCE)) { CIMInstance repInstance = (CIMInstance) outArg.getValue(); if (null != repInstance) { CIMProperty<?> desiredMethod = new CIMProperty<Object>(SmisConstants.DESIRED_COPY_METHODOLOGY, UINT16_T, new UnsignedInteger16(desiredValue)); list.add(desiredMethod); if (setTargetSupplier) { CIMProperty<?> targetElementSupplier = new CIMProperty<Object>(TARGET_ELEMENT_SUPPLIER, UINT16_T, new UnsignedInteger16(CREATE_NEW_TARGET_VALUE)); list.add(targetElementSupplier); } /** * To create SNAPVX snapshot smis uses the ElementName attribute in replicationSettingsInstance. * By default Element Name of replicationSettingsInstance is "Default ReplicationSettingData". * Element Name should not be having white space as it accept only alphanumeric value. * To avoid SNAPVX creation failure i just removed white space as a workaround. */ if (null == elementName) { elementName = SmisConstants.DEFAULT_REPLICATION_SETTING_DATA_ELEMENT_NAME; } CIMProperty<?> elementNameProp = new CIMProperty<Object>(SmisConstants.CP_ELEMENT_NAME, STRING_T, elementName); list.add(elementNameProp); modifiedInstance = repInstance.deriveInstance(list.toArray(new CIMProperty[] {})); break; } } } } catch (Exception e) { _log.error("Error retrieving Replication Setting Data Instance ", e); } return modifiedInstance; } /** * Return the CIMObjectPath representing the StoragePool to which 'volume belongs * * @param storage * [IN] - StorageSystem object where 'volume' resides * @param volume * [IN] - Volume object * @return CIMObjectPath of StoragePool where 'volume' belongs */ public CIMObjectPath getVolumeStoragePoolPath(StorageSystem storage, Volume volume) { CIMObjectPath poolPath = null; if (volume != null && volume.getPool() != null) { StoragePool storagePool = _dbClient.queryObject(StoragePool.class, volume.getPool()); if (storagePool != null) { poolPath = getPoolPath(storage, storagePool); } } return poolPath; } /** * Get the SMI-S input arguments when linking a target to an array snapshot. * * @param system * A reference to the storage system. * @param settingsStatePath * The CIM object path of the CIM_SettingsDefineState for the array snapshot. * @param targetDevicePath * The CIM object path of the target volume. * @param copyMode * Specifies if the array snapshot should simply be attached to the target * (i.e., no data copy), or the array snapshot should actually be copied to the target. * * @return An array of CIMArgument */ public CIMArgument[] getModifySettingsDefinedStateForLinkTargets(StorageSystem system, CIMObjectPath settingsStatePath, CIMObjectPath targetDevicePath, String copyMode) { return getModifySettingsDefinedStateForLinking(system, settingsStatePath, targetDevicePath, copyMode, CP_TARGET_ELEMENT); } public CIMArgument[] getModifySettingsDefinedStateForLinkTargetGroup(StorageSystem system, CIMObjectPath settingsStatePath, CIMObjectPath targetDevicePath, String copyMode) { return getModifySettingsDefinedStateForLinking(system, settingsStatePath, targetDevicePath, copyMode, CP_TARGET_GROUP); } public CIMArgument[] getModifySettingsDefinedStateForLinking(StorageSystem system, CIMObjectPath settingsStatePath, CIMObjectPath targetPath, String copyMode, String targetKey) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.reference(CP_SETTINGS_STATE, settingsStatePath)); args.add(_cimArgument.reference(targetKey, targetPath)); if (copyMode.equals(BlockSnapshotSession.CopyMode.copy.name())) { CIMInstance replicationsettingDataInstance = getReplicationSettingDataInstanceForDesiredCopyMethod(system, COPY_METHODOLOGY_FULL_COPY, false); args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, replicationsettingDataInstance)); args.add(_cimArgument.uint16(CP_OPERATION, COPY_TO_TARGET_VALUE)); args.add(_cimArgument.uint16(CP_WAIT_FOR_COPY_STATE, SYNCHRONIZED)); } else { args.add(_cimArgument.uint16(CP_OPERATION, ATTACH_TO_TARGET_VALUE)); } return args.toArray(new CIMArgument[args.size()]); } /** * Get the SMI-S input arguments when re-linking a target to an array snapshot. * * @param system * A reference to the storage system. * @param settingsStatePath * The CIM object path of the CIM_SettingsDefineState for the target array snapshot. * @param targetDevicePath * The CIM object path of the target volume. * @param isCopyMode * true if the target is currently linked in "copy" mode, false otherwise. * * @return An array of CIMArgument */ public CIMArgument[] getModifySettingsDefinedStateForRelinkTargets(StorageSystem system, CIMObjectPath settingsStatePath, CIMObjectPath targetDevicePath, boolean isCopyMode) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.uint16(CP_OPERATION, RELINK_TARGET_VALUE)); args.add(_cimArgument.reference(CP_TARGET_ELEMENT, targetDevicePath)); args.add(_cimArgument.reference(CP_SETTINGS_STATE, settingsStatePath)); if (isCopyMode) { CIMInstance replicationsettingDataInstance = getReplicationSettingDataInstanceForDesiredCopyMethod(system, COPY_METHODOLOGY_FULL_COPY, false); args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, replicationsettingDataInstance)); } return args.toArray(new CIMArgument[args.size()]); } /** * Get the SMI-S input arguments when re-linking a target group to an array snapshot. * * @param system * A reference to the storage system. * @param settingsStatePath * The CIM object path of the CIM_SettingsDefineState for the target array snapshot. * @param targetDevicePath * The CIM object path of the target volume. * @param isCopyMode * true if the target group is currently linked in "copy" mode, false otherwise. * * @return An array of CIMArgument */ public CIMArgument[] getModifySettingsDefinedStateForRelinkTargetGroups(StorageSystem system, CIMObjectPath settingsStatePath, CIMObjectPath replicationGroupPath, boolean isCopyMode) { List<CIMArgument> args = new ArrayList<CIMArgument>(); args.add(_cimArgument.uint16(CP_OPERATION, RELINK_TARGET_VALUE)); args.add(_cimArgument.reference(CP_TARGET_GROUP, replicationGroupPath)); args.add(_cimArgument.reference(CP_SETTINGS_STATE, settingsStatePath)); if (isCopyMode) { CIMInstance replicationsettingDataInstance = getReplicationSettingDataInstanceForDesiredCopyMethod(system, COPY_METHODOLOGY_FULL_COPY, false); args.add(_cimArgument.object(CP_REPLICATIONSETTING_DATA, replicationsettingDataInstance)); } return args.toArray(new CIMArgument[args.size()]); } /** * Get the SMI-S input arguments when unlinking a target from an array snapshot. * * @param syncObject * The path for the CIM_StorageSynchronized instance for the linked target. * * @return An array of CIMArgument */ public CIMArgument[] getUnlinkBlockSnapshotSessionTargetInputArguments(CIMObjectPath syncObject) { return new CIMArgument[] { _cimArgument.uint16(CP_OPERATION, DETACH_VALUE), _cimArgument.reference(CP_SYNCHRONIZATION, syncObject) }; } public CIMArgument[] fabricateSourceGroupSynchronizationAspectInputArguments(StorageSystem system, String repGrpName, String sessionLabel) { List<String> addSFSEntries = new ArrayList<>(); addSFSEntries.add(ADD_SFS_ENTRIES); addSFSEntries.add(formatSessionLabelForFabrication(system.getSerialNumber(), repGrpName, sessionLabel)); return new CIMArgument[] { _cimArgument.stringArray(SFSENTRIES, addSFSEntries.toArray(new String[addSFSEntries.size()])) }; } private String formatSessionLabelForFabrication(String systemSerial, String replicationGroupName, String sessionLabel) { return String.format("%s+%s##SSNAME+%s", systemSerial, replicationGroupName, sessionLabel); } private String formatSessionLabelForFabrication(String systemSerial, String replicationGroupName) { return String.format("%s+%s##SSNAME", systemSerial, replicationGroupName); } /** * Remove EMCSFSEntry containing the groupSynchronizedAspect information. It would find the entry using the snap * session * source replication group name, then remove it. This operation is necessary before deleting an attached snaphost * session replication * group. * * @param system * @param replicationSvc * @param sourceReplicationGroupName */ public void removeSFSEntryForReplicaReplicationGroup(StorageSystem system, CIMObjectPath replicationSvc, String sourceReplicationGroupName) throws WBEMException { List<String> sfsEntries = getEMCSFSEntries(system, replicationSvc); String groupSynchronizedAspectLabel = formatSessionLabelForFabrication(system.getSerialNumber(), sourceReplicationGroupName); List<String> removeEntryList = new ArrayList<String>(); if (sfsEntries != null && !sfsEntries.isEmpty()) { for (String entry : sfsEntries) { if (entry.contains(groupSynchronizedAspectLabel)) { removeEntryList.add(entry); } } } if (removeEntryList.isEmpty()) { _log.info(String.format("The expected SFS entry %s is not found for the source group %s", groupSynchronizedAspectLabel, sourceReplicationGroupName)); return; } try { String[] removeEntries = new String[removeEntryList.size()]; removeEntries = removeEntryList.toArray(removeEntries); CIMArgument[] inArgs = new CIMArgument[] { _cimArgument.stringArray("SFSEntries", removeEntries) }; CIMArgument[] outArgs = new CIMArgument[5]; invokeMethod(system, replicationSvc, SmisConstants.EMC_REMOVE_SFSENTRIES, inArgs, outArgs); } catch (WBEMException e) { _log.error("EMCRemoveSFSEntries -- WBEMException: ", e); throw e; } } /** * Get EMCSFSEntries * * @param storage * @param replicationSvc * @return the list of EMCSFSEntries */ public List<String> getEMCSFSEntries(StorageSystem storage, CIMObjectPath replicationSvc) throws WBEMException { CIMArgument[] outArgs = new CIMArgument[5]; try { invokeMethod(storage, replicationSvc, SmisConstants.EMC_LIST_SFSENTRIES, null, outArgs); for (CIMArgument arg : outArgs) { if (arg != null && arg.getName().equalsIgnoreCase(SmisConstants.SFSENTRIES)) { String[] entries = (String[]) arg.getValue(); return asList(entries); } } } catch (WBEMException e) { _log.error("get EMCSFSEntries -- WBEMException: ", e); throw e; } return null; } /** * Rename a volume on the SMIS storage device. Used by SRDF. * * @param dbClient - database reference (volume deviceLabel is updated) * @param storageSystem - StorageSystem * @param volume - Volume * @param name - new name String */ public void renameVolume(DbClient dbClient, StorageSystem storageSystem, Volume volume, String name) { try { CIMObjectPath volumePath = _cimPath.getBlockObjectPath(storageSystem, volume); _log.info(String.format("Attempting to modify volume %s to %s", volumePath.toString(), name)); CIMInstance toUpdate = new CIMInstance(volumePath, new CIMProperty[] { new CIMPropertyFactory().string(SmisConstants.CP_ELEMENT_NAME, name) } ); modifyInstance(storageSystem, toUpdate, SmisConstants.PS_ELEMENT_NAME); volume.setDeviceLabel(name); dbClient.updateAndReindexObject(volume); _log.info(String.format("Volume name has been modified to %s", name)); } catch (WBEMException e) { _log.error("Encountered an error while trying to set the volume name", e); } catch (DatabaseException e) { _log.error("Encountered an error while trying to set the volume name", e); } catch (Exception e) { _log.error("Encountered an error while trying to set the volume name", e); } } /** * Get the SMI-S input arguments for setting the Initiator Alias. * * @param shidPath A reference to the HardwareID. * @param initiatorAlias The alias that needs to be set * @return An array of CIMArgument */ public CIMArgument[] getEMCInitiatorAliasSetArgs(CIMObjectPath shidPath, String initiatorAlias) throws Exception { return new CIMArgument[] { _cimArgument.reference(CP_EXISTING_STORAGEID, shidPath), _cimArgument.string(CP_ALIAS_STORAGEID, initiatorAlias) }; } /** * Get the SMI-S input arguments for getting the Initiator Alias. * * @param shidPath A reference to the existing HardwareID. * @return An array of CIMArgument */ public CIMArgument[] getEMCInitiatorAliasGetArgs(CIMObjectPath shidPath) throws Exception { return new CIMArgument[] { _cimArgument.reference(CP_EXISTING_STORAGEID, shidPath) }; } /** * Check if Port Groups is shared with other masking view than the passed in masking view name. * If masking view name is null, then it is to check if the port group has any masking view associated * * @param system - Storage system * @param portGroupName - port group name * @param mvName - masking view name to check with * @return true or false * @throws Exception */ public boolean checkPortGroupShared(StorageSystem system, String portGroupName, String mvName) throws Exception { CIMObjectPath portGroupPath = _cimPath.getMaskingGroupPath(system, portGroupName, SmisConstants.MASKING_GROUP_TYPE.SE_TargetMaskingGroup); CloseableIterator<CIMInstance> cimPathItr = null; boolean result = false; try { _log.info("Trying to find the masking view associated with port group {}", portGroupName); cimPathItr = getAssociatorInstances(system, portGroupPath, null, SYMM_LUNMASKINGVIEW, null, null, PS_ELEMENT_NAME); while (cimPathItr.hasNext()) { if (mvName == null) { // Just to check if there is any masking view associated to the port group result = true; break; } else { String maskingName = CIMPropertyFactory.getPropertyValue(cimPathItr.next(), SmisConstants.CP_ELEMENT_NAME); _log.info("The port group {} has lun masking view {} associated", portGroupName, maskingName); if (maskingName != null && !maskingName.equals(mvName)) { result = true; break; } } } } catch (Exception e) { _log.error("Could not get associated masking view:", e); } finally { if (cimPathItr != null) { cimPathItr.close(); } } return result; } }