/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.blockorchestrationcontroller; import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.volumecontroller.impl.utils.VirtualPoolCapabilityValuesWrapper; @SuppressWarnings("serial") public class VolumeDescriptor implements Serializable { public enum Type { /* * ****************************** * The ordering of these are important for the sortByType() method, * be mindful when adding/removing/changing the list. * Especially the RP Values, keep them in sequential order. * ****************************** */ BLOCK_DATA(1), // user's data volume BLOCK_MIRROR(2), // array level mirror BLOCK_SNAPSHOT(3), // array level snapshot RP_EXISTING_PROTECTED_SOURCE(4), // RecoverPoint existing source volume that has protection already RP_EXISTING_SOURCE(5), // RecoverPoint existing source volume RP_VPLEX_VIRT_SOURCE(6), // RecoverPoint + VPLEX Virtual source RP_SOURCE(7), // RecoverPoint source RP_TARGET(8), // RecoverPoint target RP_VPLEX_VIRT_TARGET(9), // RecoverPoint + VPLEX Virtual target RP_VPLEX_VIRT_JOURNAL(10), // RecoverPoint + VPLEX Virtual journal RP_JOURNAL(11), // RecoverPoint journal VPLEX_VIRT_VOLUME(12), // VPLEX Virtual Volume VPLEX_LOCAL_MIRROR(13), // VPLEX local mirror VPLEX_IMPORT_VOLUME(14), // VPLEX existing Volume to be imported SRDF_SOURCE(15), // SRDF remote mirror source SRDF_TARGET(16), // SRDF remote mirror target SRDF_EXISTING_SOURCE(17), // SRDF existing source volume VPLEX_MIGRATE_VOLUME(18), BLOCK_SNAPSHOT_SESSION(19), // snapshot session DUMMY_MIGRATE(20); // Used to pass through without migrating private final int order; private Type(int order) { this.order = order; } public int getOrder() { return order; } }; private Type type; // The type of this volume private URI deviceURI; // Device this volume will be created on private URI volumeURI; // The volume id or BlockObject id to be created private URI poolURI; // The pool id to be used for creation private VirtualPoolCapabilityValuesWrapper capabilitiesValues; // Non-volume-specific RP policy is stored in here private URI consistencyGroup; // The consistency group this volume belongs to private Long volumeSize; // Used to separate multi-volume create requests private URI migrationId; // Reference to the migration object for this volume private URI computeResource; // Host/Cluster to which the volume will be exported to, as part of the provisioning. private List<List<URI>> snapSessionSnapshotURIs; // list of snapshot id's to link sessions to // Layer/device specific parameters (key/value) for this volume (serializable!) private Map<String, Object> parameters = new HashMap<String, Object>(); public static final String PARAM_VARRAY_CHANGE_NEW_VAARAY_ID = "varrayChangeNewVArrayId"; public static final String PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID = "vpoolChangeExistingVolumeId"; public static final String PARAM_VPOOL_CHANGE_NEW_VPOOL_ID = "vpoolChangeNewVpoolId"; public static final String PARAM_VPOOL_CHANGE_OLD_VPOOL_ID = "vpoolChangeOldVpoolId"; public static final String PARAM_IS_COPY_SOURCE_ID = "isCopySourceId"; public static final String PARAM_DO_NOT_DELETE_VOLUME = "doNotDeleteVolume"; public static final String PARAM_MIGRATION_SUSPEND_BEFORE_COMMIT = "migrationSuspendBeforeCommit"; public static final String PARAM_MIGRATION_SUSPEND_BEFORE_DELETE_SOURCE = "migrationSuspendBeforeDeleteSource"; public VolumeDescriptor(Type type, URI deviceURI, URI volumeURI, URI poolURI, URI consistencyGroupURI, VirtualPoolCapabilityValuesWrapper capabilities, Long volumeSize) { this(type, deviceURI, volumeURI, poolURI, consistencyGroupURI, capabilities); this.volumeSize = volumeSize; } public VolumeDescriptor(Type type, URI deviceURI, URI volumeURI, URI poolURI, URI consistencyGroupURI, URI migrationId, VirtualPoolCapabilityValuesWrapper capabilities) { this(type, deviceURI, volumeURI, poolURI, consistencyGroupURI, capabilities); setMigrationId(migrationId); } public VolumeDescriptor(Type type, URI deviceURI, URI volumeURI, URI poolURI, URI consistencyGroupURI, VirtualPoolCapabilityValuesWrapper capabilities) { this.type = type; this.deviceURI = deviceURI; this.volumeURI = volumeURI; this.poolURI = poolURI; this.capabilitiesValues = capabilities; this.consistencyGroup = consistencyGroupURI; } public VolumeDescriptor(Type type, URI deviceURI, URI volumeURI, URI poolURI, VirtualPoolCapabilityValuesWrapper capabilities) { this(type, deviceURI, volumeURI, poolURI, null, capabilities); } /** * constructor for snapshot session volume descriptor * * @param type type of volume desccriptor (snapshot session) * @param deviceURI storage controller id * @param volumeURI BlockSnapshotSession id * @param poolURI virtual pool id * @param consistencyGroupURI consistency group id * @param capabilities capabilities object * @param snapSessionSnapshotURIs list of snapshot ids for create and link to snapshot */ public VolumeDescriptor(Type type, URI deviceURI, URI volumeURI, URI poolURI, URI consistencyGroupURI, VirtualPoolCapabilityValuesWrapper capabilities, List<List<URI>> snapSessionSnapshotURIs) { this(type, deviceURI, volumeURI, poolURI, consistencyGroupURI, capabilities); this.setSnapSessionSnapshotURIs(snapSessionSnapshotURIs); } /** * Returns all the descriptors of a given type. * * @param descriptors * List<VolumeDescriptor> input list * @param type * enum Type * @return returns list elements matching given type */ static public List<VolumeDescriptor> getDescriptors(List<VolumeDescriptor> descriptors, Type type) { List<VolumeDescriptor> list = new ArrayList<VolumeDescriptor>(); for (VolumeDescriptor descriptor : descriptors) { if (descriptor.getType() == type) { list.add(descriptor); } } return list; } /** * Return a map of device URI to a list of descriptors in that device. * * @param descriptors * List<VolumeDescriptors> * @return Map of device URI to List<VolumeDescriptors> in that device */ static public Map<URI, List<VolumeDescriptor>> getDeviceMap(List<VolumeDescriptor> descriptors) { HashMap<URI, List<VolumeDescriptor>> poolMap = new HashMap<URI, List<VolumeDescriptor>>(); for (VolumeDescriptor desc : descriptors) { if (poolMap.get(desc.getDeviceURI()) == null) { poolMap.put(desc.getDeviceURI(), new ArrayList<VolumeDescriptor>()); } poolMap.get(desc.getDeviceURI()).add(desc); } return poolMap; } /** * Return a map of pool URI to a list of descriptors in that pool. * * @param descriptors * List<VolumeDescriptors> * @return Map of pool URI to List<VolumeDescriptors> in that pool */ static public Map<URI, List<VolumeDescriptor>> getPoolMap(List<VolumeDescriptor> descriptors) { HashMap<URI, List<VolumeDescriptor>> poolMap = new HashMap<URI, List<VolumeDescriptor>>(); for (VolumeDescriptor desc : descriptors) { if (poolMap.get(desc.getPoolURI()) == null) { poolMap.put(desc.getPoolURI(), new ArrayList<VolumeDescriptor>()); } poolMap.get(desc.getPoolURI()).add(desc); } return poolMap; } /** * Return a map of pool URI to a list of descriptors in that pool of each size. * * @param descriptors * List<VolumeDescriptors> * @return Map of pool URI to a map of identical sized volumes to List<VolumeDescriptors> in that pool of that size */ static public Map<URI, Map<Long, List<VolumeDescriptor>>> getPoolSizeMap(List<VolumeDescriptor> descriptors) { Map<URI, Map<Long, List<VolumeDescriptor>>> poolSizeMap = new HashMap<URI, Map<Long, List<VolumeDescriptor>>>(); for (VolumeDescriptor desc : descriptors) { // If the outside pool map doesn't exist, create it. if (poolSizeMap.get(desc.getPoolURI()) == null) { poolSizeMap.put(desc.getPoolURI(), new HashMap<Long, List<VolumeDescriptor>>()); } // If the inside size map doesn't exist, create it. if (poolSizeMap.get(desc.getPoolURI()).get(desc.getVolumeSize()) == null) { poolSizeMap.get(desc.getPoolURI()).put(desc.getVolumeSize(), new ArrayList<VolumeDescriptor>()); } // Add volume to the list poolSizeMap.get(desc.getPoolURI()).get(desc.getVolumeSize()).add(desc); } return poolSizeMap; } /** * Return a List of URIs for the volumes. * * @param descriptors * List<VolumeDescriptors> * @return List<URI> of volumes in the input list */ public static List<URI> getVolumeURIs(List<VolumeDescriptor> descriptors) { Set<URI> volumeURIs = new HashSet<>(); for (VolumeDescriptor desc : descriptors) { volumeURIs.add(desc.getVolumeURI()); } List<URI> volumeList = new ArrayList<>(); volumeList.addAll(volumeURIs); return volumeList; } /** * Filter a list of VolumeDescriptors by type(s). * * @param descriptors * -- Original list. * @param inclusive * -- Types to be included (or null if not used). * @param exclusive * -- Types to be excluded (or null if not used). * @return List<VolumeDescriptor> */ public static List<VolumeDescriptor> filterByType( List<VolumeDescriptor> descriptors, Type[] inclusive, Type[] exclusive) { List<VolumeDescriptor> result = new ArrayList<VolumeDescriptor>(); if (descriptors == null) { return result; } HashSet<Type> included = new HashSet<Type>(); if (inclusive != null) { included.addAll(Arrays.asList(inclusive)); } HashSet<Type> excluded = new HashSet<Type>(); if (exclusive != null) { excluded.addAll(Arrays.asList(exclusive)); } for (VolumeDescriptor desc : descriptors) { if (excluded.contains(desc.getType())) { continue; } if (included.isEmpty() || included.contains(desc.getType())) { result.add(desc); } } return result; } public static List<VolumeDescriptor> filterByType( List<VolumeDescriptor> descriptors, Type... inclusive) { return filterByType(descriptors, inclusive, null); } /** * Helper method to retrieve the vpool change volume hiding in the volume descriptors * * @param descriptors * list of volumes * @return URI of the vpool change volume */ public static URI getVirtualPoolChangeVolume(List<VolumeDescriptor> descriptors) { if (descriptors != null) { for (VolumeDescriptor volumeDescriptor : descriptors) { if (volumeDescriptor.getParameters() != null) { if ((URI) volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID) != null) { return (URI) volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID); } } } } return null; } /** * Helper method to find the change vpool using a single descriptor * * @param descriptor * Volume descriptor to use * @return URI of the change vpool */ public static URI getVirtualPoolChangeVolume(VolumeDescriptor descriptor) { if (descriptor != null) { List<VolumeDescriptor> descriptors = new ArrayList<VolumeDescriptor>(); descriptors.add(descriptor); return getVirtualPoolChangeVolume(descriptors); } return null; } /** * Helper method to retrieve the change vpool volume hiding in the volume descriptors and * to find the old vpool. * * @param descriptors * list of volumes * @return Map<URI,URI> of the vpool change volume and the old vpool associated to it. */ public static Map<URI, URI> createVolumeToOldVpoolMap(List<VolumeDescriptor> descriptors) { Map<URI, URI> volumesToOldVpoolMap = new HashMap<URI, URI>(); if (descriptors != null) { for (VolumeDescriptor volumeDescriptor : descriptors) { if (volumeDescriptor.getParameters() != null) { if (volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID) != null) { URI volumeURI = (URI) volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID); URI oldVpoolURI = (URI) volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_OLD_VPOOL_ID); volumesToOldVpoolMap.put(volumeURI, oldVpoolURI); } } } } return volumesToOldVpoolMap; } /** * Helper method to retrieve the change vpool volume hiding in the volume descriptors and * to find the new vpool. * * @param descriptors list of volumes * @return Map<URI,URI> of the vpool change volume and the old vpool associated to it. */ public static Map<URI, URI> createVolumeToNewVpoolMap(List<VolumeDescriptor> descriptors) { Map<URI, URI> volumesToNewVpoolMap = new HashMap<URI, URI>(); if (descriptors != null) { for (VolumeDescriptor volumeDescriptor : descriptors) { if (volumeDescriptor.getParameters() != null) { if (volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID) != null) { URI volumeURI = (URI) volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_EXISTING_VOLUME_ID); URI newVpoolURI = (URI) volumeDescriptor.getParameters().get(VolumeDescriptor.PARAM_VPOOL_CHANGE_NEW_VPOOL_ID); volumesToNewVpoolMap.put(volumeURI, newVpoolURI); } } } } return volumesToNewVpoolMap; } /** * Helper method to retrieve the suspension setting hiding in the volume descriptors. * * @param descriptors * list of volumes * @return boolean if we should suspend before commit */ public static boolean getMigrationSuspendBeforeCommit(List<VolumeDescriptor> descriptors) { return isPropertyEnabled(descriptors, VolumeDescriptor.PARAM_MIGRATION_SUSPEND_BEFORE_COMMIT); } /** * Helper method to retrieve the suspension setting hiding in the volume descriptors. * * @param descriptors * list of volumes * @return boolean if we should suspend before deleting the source volumes */ public static boolean getMigrationSuspendBeforeDeleteSource(List<VolumeDescriptor> descriptors) { return isPropertyEnabled(descriptors, VolumeDescriptor.PARAM_MIGRATION_SUSPEND_BEFORE_DELETE_SOURCE); } /** * Helper that checks any boolean property in the volume descriptor. False is default response. * * @param descriptors * descriptor list * @param param * string of parameter to check * @return true if the property is set and true, false otherwise */ private static boolean isPropertyEnabled(List<VolumeDescriptor> descriptors, String param) { if (descriptors != null) { for (VolumeDescriptor volumeDescriptor : descriptors) { if (volumeDescriptor.getParameters() != null) { if (volumeDescriptor.getParameters().get(param) != null) { return (Boolean) volumeDescriptor.getParameters().get(param); } } } } return false; } /** * Sorts the descriptors using the natural order of the enum type * defined at the top of the class. * * @param descriptors * VolumeDescriptors to sort */ public static void sortByType(List<VolumeDescriptor> descriptors) { Collections.sort(descriptors, new Comparator<VolumeDescriptor>() { @Override public int compare(VolumeDescriptor vd1, VolumeDescriptor vd2) { return vd1.getType().getOrder() - vd2.getType().getOrder(); } }); } /** * Returns all descriptors that have the PARAM_DO_NOT_DELETE_VOLUME flag set to true. * * @param descriptors * List of descriptors to check * @return all descriptors that have the PARAM_DO_NOT_DELETE_VOLUME flag set to true */ public static List<VolumeDescriptor> getDoNotDeleteDescriptors(List<VolumeDescriptor> descriptors) { List<VolumeDescriptor> doNotDeleteDescriptors = new ArrayList<VolumeDescriptor>(); if (descriptors != null && !descriptors.isEmpty()) { for (VolumeDescriptor descriptor : descriptors) { if (descriptor.getParameters() != null && descriptor.getParameters().get(VolumeDescriptor.PARAM_DO_NOT_DELETE_VOLUME) != null && descriptor.getParameters().get(VolumeDescriptor.PARAM_DO_NOT_DELETE_VOLUME).equals(Boolean.TRUE)) { doNotDeleteDescriptors.add(descriptor); } } } return doNotDeleteDescriptors; } @Override public String toString() { return "VolumeDescriptor [_type=" + getType() + ", _deviceURI=" + getDeviceURI() + ", _volumeURI=" + getVolumeURI() + ", _poolURI=" + getPoolURI() + ", _consistencyGroup=" + getConsistencyGroupURI() + ", _capabilitiesValues=" + getCapabilitiesValues() + ", parameters=" + parameters + ", size=" + getVolumeSize() + "]"; } public String toString(Volume volume) { return "VolumeDescriptor [_type=" + getType() + ", _deviceURI=" + getDeviceURI() + ", _poolURI=" + getPoolURI() + ", _consistencyGroup=" + getConsistencyGroupURI() + ", _capabilitiesValues=" + getCapabilitiesValues() + ", parameters=" + parameters + ", volume=" + volume.toString() + ", size=" + getVolumeSize() + "]"; } public Type getType() { return type; } public void setType(Type type) { this.type = type; } public URI getDeviceURI() { return deviceURI; } public void setDeviceURI(URI deviceURI) { this.deviceURI = deviceURI; } public URI getVolumeURI() { return volumeURI; } public void setVolumeURI(URI volumeURI) { this.volumeURI = volumeURI; } public URI getPoolURI() { return poolURI; } public void setPoolURI(URI poolURI) { this.poolURI = poolURI; } public VirtualPoolCapabilityValuesWrapper getCapabilitiesValues() { return capabilitiesValues; } public void setCapabilitiesValues(VirtualPoolCapabilityValuesWrapper capabilitiesValues) { this.capabilitiesValues = capabilitiesValues; } public Map<String, Object> getParameters() { return parameters; } public void setParameters(Map<String, Object> parameters) { this.parameters = parameters; } public URI getConsistencyGroupURI() { return consistencyGroup; } public void setConsistencyGroupURI(URI consistencyGroupURI) { this.consistencyGroup = consistencyGroupURI; } public Long getVolumeSize() { return volumeSize; } public void setVolumeSize(Long _volumeSize) { this.volumeSize = _volumeSize; } public URI getMigrationId() { return migrationId; } public void setMigrationId(URI _migrationId) { this.migrationId = _migrationId; } public URI getComputeResource() { return computeResource; } public void setComputeResource(URI _computeResource) { this.computeResource = _computeResource; } /** * @return the snapSessionSnapshotURIs */ public List<List<URI>> getSnapSessionSnapshotURIs() { return snapSessionSnapshotURIs; } /** * @param snapSessionSnapshotURIs the snapSessionSnapshotURIs to set */ public void setSnapSessionSnapshotURIs(List<List<URI>> snapSessionSnapshotURIs) { this.snapSessionSnapshotURIs = snapSessionSnapshotURIs; } }