/* * Copyright (c) 2012-2015 iWave Software LLC * All Rights Reserved */ package com.emc.sa.asset.providers; import static com.emc.sa.asset.providers.BlockProviderUtils.isLocalMirrorSupported; import static com.emc.sa.asset.providers.BlockProviderUtils.isLocalSnapshotSupported; import static com.emc.sa.asset.providers.BlockProviderUtils.isRPSourceVolume; import static com.emc.sa.asset.providers.BlockProviderUtils.isRPTargetVolume; import static com.emc.sa.asset.providers.BlockProviderUtils.isRemoteSnapshotSupported; import static com.emc.sa.asset.providers.BlockProviderUtils.isSnapshotRPBookmark; import static com.emc.sa.asset.providers.BlockProviderUtils.isSnapshotSessionSupportedForCG; import static com.emc.sa.asset.providers.BlockProviderUtils.isSnapshotSessionSupportedForVolume; import static com.emc.sa.asset.providers.BlockProviderUtils.isVpoolProtectedByVarray; import static com.emc.vipr.client.core.util.ResourceUtils.name; import static com.emc.vipr.client.core.util.ResourceUtils.stringId; import java.net.URI; import java.util.ArrayList; 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 org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.emc.sa.asset.AssetOptionsContext; import com.emc.sa.asset.AssetOptionsUtils; import com.emc.sa.asset.BaseAssetOptionsProvider; import com.emc.sa.asset.annotation.Asset; import com.emc.sa.asset.annotation.AssetDependencies; import com.emc.sa.asset.annotation.AssetNamespace; import com.emc.sa.machinetags.KnownMachineTags; import com.emc.sa.machinetags.MachineTagUtils; import com.emc.sa.service.vipr.block.BlockStorageUtils; import com.emc.sa.util.CatalogSerializationUtils; import com.emc.sa.util.ResourceType; import com.emc.sa.util.StringComparator; import com.emc.sa.util.TextUtils; import com.emc.storageos.db.client.model.BlockConsistencyGroup; import com.emc.storageos.db.client.model.BlockConsistencyGroup.Types; import com.emc.storageos.db.client.model.DiscoveredDataObject.Type; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.model.Volume.ReplicationState; import com.emc.storageos.db.client.model.VolumeGroup; import com.emc.storageos.model.BulkIdParam; import com.emc.storageos.model.NamedRelatedResourceRep; import com.emc.storageos.model.RelatedResourceRep; import com.emc.storageos.model.SnapshotList; import com.emc.storageos.model.StringHashMapEntry; import com.emc.storageos.model.VirtualArrayRelatedResourceRep; import com.emc.storageos.model.application.VolumeGroupCopySetParam; import com.emc.storageos.model.application.VolumeGroupList; import com.emc.storageos.model.application.VolumeGroupRestRep; import com.emc.storageos.model.block.BlockConsistencyGroupRestRep; import com.emc.storageos.model.block.BlockMirrorRestRep; import com.emc.storageos.model.block.BlockObjectRestRep; import com.emc.storageos.model.block.BlockSnapshotRestRep; import com.emc.storageos.model.block.BlockSnapshotSessionList; import com.emc.storageos.model.block.BlockSnapshotSessionRestRep; import com.emc.storageos.model.block.NamedVolumesList; import com.emc.storageos.model.block.VolumeDeleteTypeEnum; import com.emc.storageos.model.block.VolumeRestRep; import com.emc.storageos.model.block.VolumeRestRep.MirrorRestRep; import com.emc.storageos.model.block.VolumeRestRep.ProtectionRestRep; import com.emc.storageos.model.block.VolumeRestRep.SRDFRestRep; import com.emc.storageos.model.block.export.ExportBlockParam; import com.emc.storageos.model.block.export.ExportGroupRestRep; import com.emc.storageos.model.block.export.ExportPathParameters; import com.emc.storageos.model.block.export.ExportPathsAdjustmentPreviewParam; import com.emc.storageos.model.block.export.ExportPathsAdjustmentPreviewRestRep; import com.emc.storageos.model.block.export.ITLRestRep; import com.emc.storageos.model.block.export.InitiatorPortMapRestRep; import com.emc.storageos.model.host.HostRestRep; import com.emc.storageos.model.host.InitiatorRestRep; import com.emc.storageos.model.host.cluster.ClusterRestRep; import com.emc.storageos.model.ports.StoragePortRestRep; import com.emc.storageos.model.project.ProjectRestRep; import com.emc.storageos.model.protection.ProtectionSetRestRep; import com.emc.storageos.model.search.SearchResultResourceRep; import com.emc.storageos.model.systems.StorageSystemRestRep; import com.emc.storageos.model.varray.VirtualArrayRestRep; import com.emc.storageos.model.vpool.BlockVirtualPoolRestRep; import com.emc.storageos.model.vpool.VirtualPoolChangeOperationEnum; import com.emc.storageos.model.vpool.VirtualPoolChangeRep; import com.emc.storageos.model.vpool.VirtualPoolCommonRestRep; import com.emc.storageos.storagedriver.model.StoragePort; import com.emc.vipr.client.ViPRCoreClient; import com.emc.vipr.client.core.filters.BlockVolumeBootVolumeFilter; import com.emc.vipr.client.core.filters.BlockVolumeConsistencyGroupFilter; import com.emc.vipr.client.core.filters.ConsistencyGroupFilter; import com.emc.vipr.client.core.filters.DefaultResourceFilter; import com.emc.vipr.client.core.filters.ExportHostOrClusterFilter; import com.emc.vipr.client.core.filters.ExportVirtualArrayFilter; import com.emc.vipr.client.core.filters.FilterChain; import com.emc.vipr.client.core.filters.RecoverPointPersonalityFilter; import com.emc.vipr.client.core.filters.ResourceFilter; import com.emc.vipr.client.core.filters.SRDFSourceFilter; import com.emc.vipr.client.core.filters.SRDFTargetFilter; import com.emc.vipr.client.core.filters.SourceTargetVolumesFilter; import com.emc.vipr.client.core.filters.VplexVolumeFilter; import com.emc.vipr.client.core.filters.VplexVolumeVirtualPoolFilter; import com.emc.vipr.client.core.impl.SearchConstants; import com.emc.vipr.client.core.util.CachedResources; import com.emc.vipr.client.core.util.ResourceUtils; import com.emc.vipr.model.catalog.AssetOption; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @Component @AssetNamespace("vipr") public class BlockProvider extends BaseAssetOptionsProvider { private static final Logger log = LoggerFactory.getLogger(BlockProvider.class); public static final String EXCLUSIVE_STORAGE = "exclusive"; public static final String SHARED_STORAGE = "shared"; public static final String RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_VALUE = "rp"; public static final String LOCAL_ARRAY_SNAPSHOT_TYPE_VALUE = "local"; public static final String SNAPSHOT_SESSION_TYPE_VALUE = "session"; public static final String SNAPSHOT_TARGET_TYPE_VALUE = "target"; public static final String CG_SNAPSHOT_TYPE_VALUE = "cg"; public static final String CG_SNAPSHOT_SESSION_TYPE_VALUE = "cgsession"; public static final String VOLUME_OPTION_KEY = "volume"; public static final String CONSISTENCY_GROUP_OPTION_KEY = "consistencygroup"; public static final String LINKED_SNAPSHOT_COPYMODE_VALUE = "copy"; public static final String LINKED_SNAPSHOT_NOCOPYMODE_VALUE = "nocopy"; public static final String YES_VALUE = "yes"; public static final String NO_VALUE = "no"; public static final String MIGRATE_ONLY_OPTION_KEY = "migrate_only"; public static final String INGEST_AND_MIGRATE_OPTION_KEY = "ingest_and_migrate"; private static final AssetOption MIGRATE_ONLY_OPTION = newAssetOption(MIGRATE_ONLY_OPTION_KEY, "Migrate Only"); private static final AssetOption INGEST_AND_MIGRATE_OPTION = newAssetOption(INGEST_AND_MIGRATE_OPTION_KEY, "Ingest and Migrate"); private static final AssetOption VOLUME_OPTION = newAssetOption(VOLUME_OPTION_KEY, "block.storage.type.volume"); private static final AssetOption CONSISTENCY_GROUP_OPTION = newAssetOption(CONSISTENCY_GROUP_OPTION_KEY, "block.storage.type.consistencygroup"); // Failover option keys public static final String LATEST_IMAGE_OPTION_KEY = "latest"; public static final String PIT_IMAGE_OPTION_KEY = "pit"; // SRDF METRO filter public static final String ACTIVE = "ACTIVE"; private static final AssetOption LATEST_IMAGE_OPTION = newAssetOption(LATEST_IMAGE_OPTION_KEY, "failover.image.type.latest"); private static final AssetOption PIT_IMAGE_OPTION = newAssetOption(PIT_IMAGE_OPTION_KEY, "failover.image.type.pit"); private static final AssetOption EXCLUSIVE_STORAGE_OPTION = newAssetOption(EXCLUSIVE_STORAGE, "block.storage.type.exclusive"); private static final AssetOption SHARED_STORAGE_OPTION = newAssetOption(SHARED_STORAGE, "block.storage.type.shared"); private static final AssetOption RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_OPTION = newAssetOption(RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_VALUE, "block.snapshot.type.rp_bookmark"); private static final AssetOption LOCAL_ARRAY_SNAPSHOT_TYPE_OPTION = newAssetOption(LOCAL_ARRAY_SNAPSHOT_TYPE_VALUE, "block.snapshot.type.local"); private static final AssetOption SNAPSHOT_SESSION_TYPE_OPTION = newAssetOption(SNAPSHOT_SESSION_TYPE_VALUE, "block.snapshot.type.session"); private static final AssetOption SNAPSHOT_TARGET_TYPE_OPTION = newAssetOption(SNAPSHOT_TARGET_TYPE_VALUE, "block.snapshot.type.target"); private static final AssetOption CG_SNAPSHOT_TYPE_OPTION = newAssetOption(CG_SNAPSHOT_TYPE_VALUE, "block.snapshot.type.cg"); private static final AssetOption CG_SNAPSHOT_SESSION_TYPE_OPTION = newAssetOption(CG_SNAPSHOT_SESSION_TYPE_VALUE, "block.snapshot.type.cg.session"); private static final AssetOption LINKED_SNAPSHOT_COPYMODE_OPTION = newAssetOption(LINKED_SNAPSHOT_COPYMODE_VALUE, "block.snapshot.linked.copymode"); private static final AssetOption LINKED_SNAPSHOT_NOCOPYMODE_OPTION = newAssetOption(LINKED_SNAPSHOT_NOCOPYMODE_VALUE, "block.snapshot.linked.nocopymode"); private static final AssetOption DISPLAY_JOURNALS_TRUE_OPTION = newAssetOption(YES_VALUE, "choice.yes"); private static final AssetOption DISPLAY_JOURNALS_FALSE_OPTION = newAssetOption(NO_VALUE, "choice.no"); private static List<AssetOption> NTFS_OPTIONS = Lists.newArrayList(newAssetOption("DEFAULT", "Default"), newAssetOption("512", "512"), newAssetOption("1024", "1k"), newAssetOption("2048", "2k"), newAssetOption("4096", "4k"), newAssetOption("8192", "8k"), newAssetOption("16k", "16k"), newAssetOption("32k", "32k"), newAssetOption("64k", "64k")); private static List<AssetOption> FAT32_OPTIONS = Lists.newArrayList(newAssetOption("DEFAULT", "Default"), newAssetOption("512", "512"), newAssetOption("1024", "1k"), newAssetOption("2048", "2k"), newAssetOption("4096", "4k"), newAssetOption("8192", "8k")); private static List<AssetOption> ALL_BLOCKSIZE_OPTIONS = Lists.newArrayList(NTFS_OPTIONS); private static List<AssetOption> WINDOWS_FILESYSTEM_TYPES = Lists.newArrayList( newAssetOption("ntfs", "ntfs"), newAssetOption("fat32", "fat32")); private static final String BLOCK_CONSISTENCY_GROUP_TYPE = "BlockConsistencyGroup"; private static final String VOLUME_TYPE = "Volume"; private static final String NONE_TYPE = "None"; private static final String IBMXIV_SYSTEM_TYPE = "ibmxiv"; private static final int EXPORT_PATH_MIN = 1; private static final int EXPORT_PATH_MAX = 32; public static boolean isExclusiveStorage(String storageType) { return EXCLUSIVE_STORAGE.equals(storageType); } public static boolean isSharedStorage(String storageType) { return SHARED_STORAGE.equals(storageType); } public static boolean isVolumeType(String type) { return VOLUME_OPTION_KEY.equals(type); } public static boolean isConsistencyGroupType(String type) { return CONSISTENCY_GROUP_OPTION_KEY.equals(type); } public static boolean checkTypeConsistency(URI volumeId, String volumeOrConsistencyType) { if (volumeId == null || volumeOrConsistencyType == null) { return false; } else if (isVolumeType(volumeOrConsistencyType) && !BlockProviderUtils.isType(volumeId, VOLUME_TYPE)) { return false; } else if (isConsistencyGroupType(volumeOrConsistencyType) && !BlockProviderUtils.isType(volumeId, BLOCK_CONSISTENCY_GROUP_TYPE)) { return false; } return true; } static boolean isConsistencyGroupType(URI urlId) { return BlockProviderUtils.isType(urlId, BLOCK_CONSISTENCY_GROUP_TYPE); } protected static boolean isInConsistencyGroup(BlockObjectRestRep volume) { return volume.getConsistencyGroup() != null; } @Asset("blockVolumeOrConsistencyType") @AssetDependencies("project") public List<AssetOption> getblockVolumeOrConsistencyType(AssetOptionsContext ctx, URI project) { return Lists.newArrayList(VOLUME_OPTION, CONSISTENCY_GROUP_OPTION); } @Asset("imageToAccess") @AssetDependencies("protectedBlockVolume") public List<AssetOption> getImageToAccess(AssetOptionsContext ctx, URI protectedBlockVolume) { List<AssetOption> options = Lists.newArrayList(); options = Lists.newArrayList(LATEST_IMAGE_OPTION, PIT_IMAGE_OPTION); return options; } @Asset("blockStorageType") public List<AssetOption> getStorageTypes(AssetOptionsContext ctx) { return Lists.newArrayList(EXCLUSIVE_STORAGE_OPTION, SHARED_STORAGE_OPTION); } @Asset("sourceBlockVolume") @AssetDependencies("project") public List<AssetOption> getSourceVolumes(AssetOptionsContext ctx, URI project) { debug("getting source block volumes (project=%s)", project); return createVolumeOptions(null, listSourceVolumes(api(ctx), project)); } @Asset("sourceBlockVolumeForAddToApplication") @AssetDependencies({ "consistencyGroupAll" }) public List<AssetOption> getApplicationSourceVolumes(AssetOptionsContext ctx, URI cg) { final ViPRCoreClient client = api(ctx); VolumeGroupList applications = client.application().getApplications(); List<URI> applicationIds = new ArrayList<URI>(); for (NamedRelatedResourceRep volumeGroup : applications.getVolumeGroups()) { VolumeGroupRestRep vg = client.application().getApplication(volumeGroup.getId()); if (vg.getRoles().contains("COPY")) { applicationIds.add(volumeGroup.getId()); } } ResourceFilter<VolumeRestRep> cgFilter = new BlockVolumeConsistencyGroupFilter(cg, false); List<ProjectRestRep> projects = api(ctx).projects().getByTenant(ctx.getTenant()); List<VolumeRestRep> volumes = new ArrayList<VolumeRestRep>(); for (ProjectRestRep project : projects) { volumes.addAll(listSourceVolumes(api(ctx), project.getId(), cgFilter)); } List<VolumeRestRep> volumesNotInApplication = new ArrayList<VolumeRestRep>(); for (VolumeRestRep volume : volumes) { if (volume.getVolumeGroups() != null && !volume.getVolumeGroups().isEmpty()) { boolean volumeIsInApplication = false; for (RelatedResourceRep rep : volume.getVolumeGroups()) { if (applicationIds.contains(rep.getId())) { volumeIsInApplication = true; break; } } if (!volumeIsInApplication) { volumesNotInApplication.add(volume); } } else { volumesNotInApplication.add(volume); } } return createVolumeOptions(null, volumesNotInApplication); } @Asset("sourceBlockVolumeInConsistencyGroup") @AssetDependencies({ "project", "consistencyGroup" }) public List<AssetOption> getSourceVolumesWithoutConsistencyGroup(AssetOptionsContext ctx, URI project, URI consistencyGroup) { debug("getting source block volumes in consistency group or no consistency group (project=%s, consistency group=%s)", project, consistencyGroup); return createVolumeOptions(null, listSourceVolumes(api(ctx), project, new BlockVolumeConsistencyGroupFilter(consistencyGroup, true))); } /** * Get source volumes for a specific project. If the deletionType is VIPR_ONLY, create * a filter that only retrieves Volumes with Host Exports * * @param ctx * @param project * @param deletionType * @return */ @Asset("sourceBlockVolumeWithDeletion") @AssetDependencies({ "project", "deletionType" }) public List<AssetOption> getSourceVolumesWithDeletion(final AssetOptionsContext ctx, URI project, String deletionType) { debug("getting source block volumes (project=%s)", project); FilterChain<VolumeRestRep> filters = new BlockVolumeMountPointFilter().not(); filters.and(new BlockVolumeVMFSDatastoreFilter().not()); List<VolumeRestRep> volumes = listSourceVolumes(api(ctx), project, filters); return createVolumeOptions(null, volumes); } @Asset("unexportedSourceBlockVolumeWithDeletion") @AssetDependencies({ "project", "deletionType" }) public List<AssetOption> getUnexportedSourceVolumesWithDeletion(final AssetOptionsContext ctx, URI project, String deletionType) { debug("getting unexported source block volumes (project=%s)", project); final ViPRCoreClient client = api(ctx); Set<URI> volumeIds = new HashSet<URI>(getExportedVolumeIds(ctx, project)); UnexportedBlockResourceFilter<VolumeRestRep> unexportedFilter = new UnexportedBlockResourceFilter<VolumeRestRep>( volumeIds); List<VolumeRestRep> volumes = listSourceVolumes(client, project, unexportedFilter); return createVolumeOptions(null, volumes); } @Asset("exportedBlockVolume") @AssetDependencies("project") public List<AssetOption> getExportedVolumes(AssetOptionsContext ctx, URI project) { debug("getting source block volumes (project=%s)", project); final ViPRCoreClient client = api(ctx); // Filter volumes that are not RP Metadata List<URI> volumeIds = getExportedVolumeIds(ctx, project); FilterChain<VolumeRestRep> filter = new FilterChain<VolumeRestRep>(RecoverPointPersonalityFilter.METADATA.not()); filter.and(new BlockVolumeVMFSDatastoreFilter().not()); filter.and(new BlockVolumeBootVolumeFilter().not()); filter.and(new BlockVolumeMountPointFilter().not()); List<VolumeRestRep> volumes = client.blockVolumes().getByIds(volumeIds, filter); return createVolumeWithVarrayOptions(client, volumes); } /** * Return a list of all exported volume ids for a given project id. * * @param ctx asset option content * @param project id * @return list of exported volume ids */ private List<URI> getExportedVolumeIds(AssetOptionsContext ctx, URI project) { final ViPRCoreClient client = api(ctx); List<URI> volumeIds = Lists.newArrayList(); for (ExportGroupRestRep export : client.blockExports().findByProject(project)) { for (ExportBlockParam resource : export.getVolumes()) { if (ResourceType.isType(ResourceType.VOLUME, resource.getId())) { volumeIds.add(resource.getId()); } } } return volumeIds; } @Asset("deletionType") public List<AssetOption> getDeletionType(AssetOptionsContext ctx) { List<AssetOption> options = new ArrayList<>(); options.add(newAssetOption(VolumeDeleteTypeEnum.FULL.toString(), "block.deletion.type.full")); options.add(newAssetOption(VolumeDeleteTypeEnum.VIPR_ONLY.toString(), "block.deletion.type.vipr_only")); return options; } @Asset("fullOnlyDeletionType") public List<AssetOption> getFullOnlyDeletionType(AssetOptionsContext ctx) { List<AssetOption> options = new ArrayList<>(); options.add(newAssetOption(VolumeDeleteTypeEnum.FULL.toString(), "block.deletion.type.full")); return options; } @Asset("vplexMigrationChangeOperation") public List<AssetOption> getVplexMigrationChangeOperations(AssetOptionsContext ctx) { List<AssetOption> options = Lists.newArrayList(); options.add(newAssetOption(VirtualPoolChangeOperationEnum.VPLEX_DATA_MIGRATION.name(), "virtualPoolChange.operation." + VirtualPoolChangeOperationEnum.VPLEX_DATA_MIGRATION.name())); options.add(newAssetOption(VirtualPoolChangeOperationEnum.VPLEX_LOCAL_TO_DISTRIBUTED.name(), "virtualPoolChange.operation." + VirtualPoolChangeOperationEnum.VPLEX_LOCAL_TO_DISTRIBUTED.name())); return options; } @Asset("virtualPoolChangeOperation") public List<AssetOption> getVirtualPoolchangeOperations(AssetOptionsContext ctx) { List<AssetOption> options = Lists.newArrayList(); for (VirtualPoolChangeOperationEnum operation : VirtualPoolChangeOperationEnum.values()) { options.add(newAssetOption(operation.name(), "virtualPoolChange.operation." + operation.name())); } return options; } @Asset("virtualPoolChangeVolumeWithSource") @AssetDependencies({ "project", "blockVirtualPool" }) public List<AssetOption> getVpoolChangeVolumes(AssetOptionsContext ctx, URI projectId, URI virtualPoolId) { return createVolumeOptions(api(ctx), listSourceVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId))); } @Asset("virtualPoolChangeVolumeWithSource") @AssetDependencies({ "project", "blockVirtualPool", "displayJournals" }) public List<AssetOption> getVpoolChangeVolumes(AssetOptionsContext ctx, URI projectId, URI virtualPoolId, String displayJournals) { if (YES_VALUE.equals(displayJournals)) { return createVolumeOptions(api(ctx), listJournalVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId))); } return createVolumeOptions(api(ctx), listSourceVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId))); } @Asset("virtualPoolChangeVolumeWithSourceFilter") @AssetDependencies({ "project", "blockVirtualPool", "sourceVolumeFilter" }) public List<AssetOption> getVpoolChangeVolumes(AssetOptionsContext ctx, URI projectId, URI virtualPoolId, int volumePage) { List<AssetOption> options = createVolumeOptions(api(ctx), listSourceVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId))); return VirtualDataCenterProvider.getVolumeSublist(volumePage, options); } @Asset("sourceVolumeFilter") @AssetDependencies({ "project", "blockVirtualPool" }) public List<AssetOption> getVolumeFilter(AssetOptionsContext ctx, URI projectId, URI virtualPoolId) { List<String> volumeNames = Lists.newArrayList(); for (VolumeRestRep volume : listSourceVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId))) { volumeNames.add(volume.getName()); } Collections.sort(volumeNames, new StringComparator(false)); return VirtualDataCenterProvider.getVolumeFilterOptions(volumeNames); } @Asset("virtualArrayChangeVolume") @AssetDependencies({ "project", "targetVirtualArray" }) public List<AssetOption> getVirtualArrayChangeCandidateVolumes(AssetOptionsContext ctx, URI projectId, URI varrayId) { ViPRCoreClient client = api(ctx); NamedVolumesList volumeList = client.blockVolumes().listVirtualArrayChangeCandidates(projectId, varrayId); List<VolumeRestRep> volumes = client.blockVolumes().getByRefs(volumeList.getVolumes()); return createVolumeOptions(client, volumes); } @Asset("targetVirtualArray") @AssetDependencies("project") public List<AssetOption> getTargetVplexVolumeVirtualArrays(AssetOptionsContext ctx, URI projectId) { ViPRCoreClient client = api(ctx); List<AssetOption> targets = Lists.newArrayList(); for (VirtualArrayRestRep varray : client.varrays().getByTenant(ctx.getTenant())) { targets.add(createBaseResourceOption(varray)); } return targets; } @Asset("migrationTargetVirtualPool") @AssetDependencies({ "project", "blockVirtualPool", "vplexMigrationChangeOperation", "displayJournals" }) public List<AssetOption> getMigrationTargetVirtualPools(AssetOptionsContext ctx, URI projectId, URI virtualPoolId, String vpoolChangeOperation, String displayJournals) { return getTargetVirtualPoolsForVpool(ctx, projectId, virtualPoolId, vpoolChangeOperation, null, displayJournals); } @Asset("mobilityMigrationTargetVirtualPool") public List<AssetOption> getMobilityMigrationTargetVirtualPools(AssetOptionsContext ctx) { return this.createBaseResourceOptions(api(ctx).blockVpools().getByTenant(ctx.getTenant())); } @Asset("journalCopyName") @AssetDependencies("rpConsistencyGroupByProject") public List<AssetOption> getCopyNameByConsistencyGroup(AssetOptionsContext ctx, URI consistencyGroupId) { ViPRCoreClient client = api(ctx); List<RelatedResourceRep> volumes = client.blockConsistencyGroups().get(consistencyGroupId).getVolumes(); Set<String> copyNames = Sets.newHashSet(); for (RelatedResourceRep volume : volumes) { VolumeRestRep volumeRep = client.blockVolumes().get(volume); if (volumeRep.getProtection() != null && volumeRep.getProtection().getRpRep() != null) { if (volumeRep.getProtection().getRpRep().getCopyName() != null) { String copyName = volumeRep.getProtection().getRpRep().getCopyName(); copyNames.add(copyName); } if (volumeRep.getHaVolumes() != null) { List<RelatedResourceRep> haVolumes = volumeRep.getHaVolumes(); for (RelatedResourceRep haVolume : haVolumes) { VolumeRestRep haVolumeRep = client.blockVolumes().get(haVolume); if (haVolumeRep.getProtection() != null && haVolumeRep.getProtection().getRpRep() != null && haVolumeRep.getProtection().getRpRep().getCopyName() != null) { String copyName = haVolumeRep.getProtection().getRpRep().getCopyName(); copyNames.add(copyName); } } } if (volumeRep.getProtection().getRpRep().getRpTargets() != null) { List<VirtualArrayRelatedResourceRep> targetVolumes = volumeRep.getProtection().getRpRep().getRpTargets(); for (VirtualArrayRelatedResourceRep target : targetVolumes) { VolumeRestRep targetVolume = client.blockVolumes().get(target.getId()); String copyName = targetVolume.getProtection().getRpRep().getCopyName(); copyNames.add(copyName); } } } } List<AssetOption> copyNameAssets = Lists.newArrayList(); for (String copyName : copyNames) { copyNameAssets.add(newAssetOption(copyName, copyName)); } AssetOptionsUtils.sortOptionsByLabel(copyNameAssets); return copyNameAssets; } @Asset("virtualArrayByConsistencyGroup") @AssetDependencies("rpConsistencyGroupByProject") public List<AssetOption> getVirtualArrayByConsistencyGroup(AssetOptionsContext ctx, URI consistencyGroupId) { ViPRCoreClient client = api(ctx); List<RelatedResourceRep> volumes = client.blockConsistencyGroups().get(consistencyGroupId).getVolumes(); List<AssetOption> targets = Lists.newArrayList(); if (!volumes.isEmpty()) { RelatedResourceRep varrayId = client.blockVolumes().get(volumes.get(0)).getVirtualArray(); VirtualArrayRestRep virtualArray = client.varrays().get(varrayId); targets.add(createBaseResourceOption(virtualArray)); } return targets; } @Asset("targetVirtualPool") @AssetDependencies({ "sourceBlockVolume", "virtualPoolChangeOperation" }) public List<AssetOption> getTargetVirtualPools(AssetOptionsContext ctx, URI volumeId, String vpoolChangeOperation) { List<VirtualPoolChangeRep> vpoolChanges = api(ctx).blockVolumes().listVirtualPoolChangeCandidates(volumeId); return createVpoolChangeOptions(vpoolChangeOperation, vpoolChanges); } @Asset("targetVirtualPool") @AssetDependencies({ "project", "blockVirtualPool", "virtualPoolChangeOperation" }) public List<AssetOption> getTargetVirtualPoolsForVpool(AssetOptionsContext ctx, URI projectId, URI virtualPoolId, String vpoolChangeOperation) { // This is an intermediate asset that is evaluated while waiting for the "virtualPoolChangeVolumeWithSourceFilter" // asset dependency to be filled in by the user. The desired behaviour is that the below "targetVirtualPool" // asset with the dependency on "virtualPoolChangeVolumeWithSourceFilter" will be fired instead. // // The "virtualPoolChangeVolumeWithSourceFilter" asset is a select-many component. When there // are NO values selected, the asset is not sent down at all and this "targetVirtualPool" asset will // be evaluated instead and return an empty list. // // Once the user selects at least 1 volume in the "virtualPoolChangeVolumeWithSourceFilter" asset then the below // "targetVirtualPool" asset will be evaluated and the drop down will be populated. info("No filtered volumes selected, returning empty list."); return Collections.emptyList(); } @Asset("targetVirtualPool") @AssetDependencies({ "project", "blockVirtualPool", "virtualPoolChangeOperation", "virtualPoolChangeVolumeWithSourceFilter" }) public List<AssetOption> getTargetVirtualPoolsForVpool(AssetOptionsContext ctx, URI projectId, URI virtualPoolId, String vpoolChangeOperation, String filteredVolumes) { return getTargetVirtualPoolsForVpool(ctx, projectId, virtualPoolId, vpoolChangeOperation, filteredVolumes, null); } @Asset("targetVirtualPool") @AssetDependencies({ "project", "blockVirtualPool", "virtualPoolChangeOperation", "virtualPoolChangeVolumeWithSourceFilter", "displayJournals" }) public List<AssetOption> getTargetVirtualPoolsForVpool(AssetOptionsContext ctx, URI projectId, URI virtualPoolId, String vpoolChangeOperation, String filteredVolumes, String displayJournals) { List<URI> volumeIds = Lists.newArrayList(); if (filteredVolumes != null && !filteredVolumes.isEmpty()) { // Best case we are passed in the volumes selected by the user // as comma delimited string so we do not have to load them from // the API. info("Filtered volumes selected by user: %s", filteredVolumes); List<String> parsedVolumeIds = TextUtils.parseCSV(filteredVolumes); for (String id : parsedVolumeIds) { volumeIds.add(uri(id)); } } else { // Worst case we need to get the volumes from the API. info("Loading all volumes for vpool: %s", virtualPoolId.toString()); List<VolumeRestRep> volumes = null; if (YES_VALUE.equals(displayJournals)) { volumes = listJournalVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId)); } else { volumes = listSourceVolumes(api(ctx), projectId, new VirtualPoolFilter(virtualPoolId)); } for (VolumeRestRep volume : volumes) { volumeIds.add(volume.getId()); } } if (CollectionUtils.isNotEmpty(volumeIds)) { BulkIdParam input = new BulkIdParam(); input.setIds(volumeIds); List<VirtualPoolChangeRep> vpoolChanges = api(ctx).blockVpools().listVirtualPoolChangeCandidates(virtualPoolId, input); return createVpoolChangeOptions(vpoolChangeOperation, vpoolChanges); } return Collections.emptyList(); } @Asset("volumeExport") @AssetDependencies("blockVolume") public List<AssetOption> getExportsForVolume(AssetOptionsContext ctx, URI volumeId) { Set<NamedRelatedResourceRep> exports = getUniqueExportsForVolume(ctx, volumeId); return createNamedResourceOptions(exports); } @Asset("snapshotExport") @AssetDependencies("exportedBlockSnapshot") public List<AssetOption> getExportsForSnapshot(AssetOptionsContext ctx, URI snapshotId) { Set<NamedRelatedResourceRep> exports = getUniqueExportsForSnapshot(ctx, snapshotId); return createNamedResourceOptions(exports); } @Asset("continuousCopyExport") @AssetDependencies("exportedBlockContinuousCopy") public List<AssetOption> getExportsForContinuousCopy(AssetOptionsContext ctx, URI copyId) { Set<NamedRelatedResourceRep> exports = getUniqueExportsForVolume(ctx, copyId); return createNamedResourceOptions(exports); } @Asset("volumeExport") @AssetDependencies("sourceBlockVolume") public List<AssetOption> getExportsForSourceVolume(AssetOptionsContext ctx, URI volumeId) { Set<NamedRelatedResourceRep> exports = getUniqueExportsForVolume(ctx, volumeId); return createNamedResourceOptions(exports); } @Asset("volumeExport") @AssetDependencies("exportedBlockVolume") public List<AssetOption> getExportsForExportedVolume(AssetOptionsContext ctx, URI volumeId) { final ViPRCoreClient client = api(ctx); Set<NamedRelatedResourceRep> exports = getUniqueExportsForVolume(ctx, volumeId); return createExportWithVarrayOptions(client, client.blockExports().getByRefs(exports)); } /** * Gets the set of unique exports for a given volume. * * @param ctx * the asset options context * @param volumeId * the volume id. * @return the export resource IDs. */ protected Set<NamedRelatedResourceRep> getUniqueExportsForVolume(AssetOptionsContext ctx, URI volumeId) { return convertITLListToRelatedResourceRestReps(api(ctx).blockVolumes().getExports(volumeId)); } /** Gets the set of unique exports for a given snapshot */ protected Set<NamedRelatedResourceRep> getUniqueExportsForSnapshot(AssetOptionsContext ctx, URI snapshotId) { return convertITLListToRelatedResourceRestReps(api(ctx).blockSnapshots().listExports(snapshotId)); } /** Find the unique exports for the given */ protected Set<NamedRelatedResourceRep> convertITLListToRelatedResourceRestReps(List<ITLRestRep> exports) { Set<NamedRelatedResourceRep> relatedRestReps = Sets.newHashSet(); for (ITLRestRep export : exports) { relatedRestReps.add(export.getExport()); } return relatedRestReps; } protected static List<AssetOption> createExportWithVarrayOptions(ViPRCoreClient client, Collection<? extends ExportGroupRestRep> exportObjects) { List<URI> varrayIds = getExportVirtualArrayIds(exportObjects); Map<URI, VirtualArrayRestRep> varrayNames = getVirutalArrayNames(client, varrayIds); List<AssetOption> options = Lists.newArrayList(); for (ExportGroupRestRep export : exportObjects) { options.add(createExportWithVarrayOption(export, varrayNames)); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected static AssetOption createExportWithVarrayOption(ExportGroupRestRep export, Map<URI, VirtualArrayRestRep> varrayNames) { String varrayName = varrayNames.get(export.getVirtualArray().getId()).getName(); String label = getMessage("block.unexport.export", export.getName(), varrayName); return new AssetOption(export.getId(), label); } private static List<URI> getExportVirtualArrayIds(Collection<? extends ExportGroupRestRep> exportObjects) { List<URI> varrayIds = Lists.newArrayList(); for (ExportGroupRestRep export : exportObjects) { varrayIds.add(export.getVirtualArray().getId()); } return varrayIds; } @Asset("exportPathVirtualArray") public List<AssetOption> getExportPathVirtualArray(AssetOptionsContext ctx) { ViPRCoreClient client = api(ctx); return createBaseResourceOptions(client.varrays().getByTenant(ctx.getTenant())); } @Asset("exportPathVirtualArray") @AssetDependencies({ "exportPathExport", "exportPathStorageSystem" }) public List<AssetOption> getExportPathVirtualArray(AssetOptionsContext ctx, URI exportId, URI storageSystemId) { ViPRCoreClient client = api(ctx); List<AssetOption> options = Lists.newArrayList(); ExportGroupRestRep export = client.blockExports().get(exportId); List<URI> vArrayIds = new ArrayList<URI>(); vArrayIds.add(export.getVirtualArray().getId()); List<StringHashMapEntry> altArrays = export.getAltVirtualArrays() != null ? export.getAltVirtualArrays() : new ArrayList<StringHashMapEntry>(); for (StringHashMapEntry altArray : altArrays) { if (altArray.getName().equalsIgnoreCase(storageSystemId.toString())) { vArrayIds.add(URI.create(altArray.getValue())); } } List<VirtualArrayRestRep> vArrays = client.varrays().getByIds(vArrayIds); for (VirtualArrayRestRep vArray : vArrays) { options.add(new AssetOption(vArray.getId(), vArray.getName())); } return options; } @Asset("exportPathExport") @AssetDependencies({ "project", "host" }) public List<AssetOption> getExportPathExports(AssetOptionsContext ctx, URI projectId, URI hostOrClusterId) { ViPRCoreClient client = api(ctx); List<ExportGroupRestRep> exports = new ArrayList<ExportGroupRestRep>(); if (BlockStorageUtils.isHost(hostOrClusterId)) { exports = client.blockExports().findByHost(hostOrClusterId, projectId, null); } else if (BlockStorageUtils.isCluster(hostOrClusterId)) { exports = client.blockExports().findByCluster(hostOrClusterId, projectId, null); } return createExportWithVarrayOptions(client, exports); } @Asset("exportPathMinPathsOptions") public List<AssetOption> getExportPathMinOptions(AssetOptionsContext ctx) { return generatePathOptions(EXPORT_PATH_MIN, EXPORT_PATH_MAX); } @Asset("exportPathMaxPathsOptions") public List<AssetOption> getExportPathMaxOptions(AssetOptionsContext ctx) { return generatePathOptions(EXPORT_PATH_MIN, EXPORT_PATH_MAX); } @Asset("exportPathMaxPathsOptions") @AssetDependencies({ "exportPathMinPathsOptions" }) public List<AssetOption> getExportPathMaxOptions(AssetOptionsContext ctx, int min) { return generatePathOptions(min, EXPORT_PATH_MAX); } @Asset("exportPathPathsPerInitiatorOptions") public List<AssetOption> getExportPathPathsPerOptions(AssetOptionsContext ctx) { return generatePathOptions(EXPORT_PATH_MIN, EXPORT_PATH_MAX); } @Asset("exportPathPathsPerInitiatorOptions") @AssetDependencies({ "exportPathMaxPathsOptions" }) public List<AssetOption> getExportPathPathsPerOptions(AssetOptionsContext ctx, int max) { return generatePathOptions(EXPORT_PATH_MIN, max); } private List<AssetOption> generatePathOptions(int min, int max) { List<AssetOption> options = Lists.newArrayList(); for (int i = min; i <= max; ++i) { options.add(new AssetOption(Integer.toString(i), Integer.toString(i))); } return options; } @Asset("exportPathExistingPath") public List<AssetOption> getExportPathExistingPath(AssetOptionsContext ctx ) { List<AssetOption> options = Lists.newArrayList(); options.add(new AssetOption(YES_VALUE, YES_VALUE)); options.add(new AssetOption(NO_VALUE, NO_VALUE)); return options; } @Asset("exportPathStorageSystem") public List<AssetOption> getExportPathStorageSystem(AssetOptionsContext ctx) { ViPRCoreClient client = api(ctx); List<AssetOption> options = Lists.newArrayList(); List<StorageSystemRestRep> storageSystems = client.storageSystems().getAll(); for (StorageSystemRestRep storageSystem : storageSystems) { String systemType = storageSystem.getSystemType(); if (Type.vmax.name().equalsIgnoreCase(systemType) || Type.vplex.name().equalsIgnoreCase(systemType)) { options.add(new AssetOption(storageSystem.getId(), storageSystem.getName())); } } return options; } @SuppressWarnings("incomplete-switch") @Asset("exportPathStorageSystem") @AssetDependencies({ "exportPathExport" }) public List<AssetOption> getExportPathStorageSystem(AssetOptionsContext ctx, URI exportId) { ViPRCoreClient client = api(ctx); List<AssetOption> options = Lists.newArrayList(); List<URI> storageSystemIds = new ArrayList<URI>(); ExportGroupRestRep export = client.blockExports().get(exportId); List<ExportBlockParam> volumes = export.getVolumes(); for (ExportBlockParam volume : volumes) { URI resourceId = volume.getId(); ResourceType volumeType = ResourceType.fromResourceId(resourceId.toString()); switch (volumeType) { case VOLUME: VolumeRestRep v = client.blockVolumes().get(resourceId); if (v != null) { storageSystemIds.add(v.getStorageController()); } break; case BLOCK_SNAPSHOT: BlockSnapshotRestRep s = client.blockSnapshots().get(resourceId); if (s != null) { storageSystemIds.add(s.getStorageController()); } break; } } List<StorageSystemRestRep> storageSystems = client.storageSystems().getByIds(storageSystemIds); for (StorageSystemRestRep storageSystem : storageSystems) { String systemType = storageSystem.getSystemType(); if (Type.vmax.name().equalsIgnoreCase(systemType) || Type.vplex.name().equalsIgnoreCase(systemType)) { options.add(new AssetOption(storageSystem.getId(), storageSystem.getName())); } } return options; } @Asset("exportPathPorts") @AssetDependencies({ "exportPathVirtualArray", "exportPathStorageSystem" }) public List<AssetOption> getExportPathPorts(AssetOptionsContext ctx, URI vArrayId, URI storageSystemId) { ViPRCoreClient client = api(ctx); List<AssetOption> options = Lists.newArrayList(); List<StoragePortRestRep> ports = client.storagePorts().getByVirtualArray(vArrayId); for (StoragePortRestRep port : ports) { if (port.getPortType().equals(StoragePort.PortType.frontend.toString()) && port.getStorageDevice().getId().equals(storageSystemId) && port.getOperationalStatus().equals(StoragePort.OperationalStatus.OK.toString())) { if (port.getNetwork() != null) { String portPercentBusy = (port.getPortPercentBusy() != null) ? String.valueOf(Math.round(port.getPortPercentBusy() * 100 / 100)) + "%" : "N/A"; String networkName = client.networks().get(port.getNetwork().getId()).getName(); String label = getMessage("exportPathAdjustment.ports", port.getPortName(), networkName, port.getPortNetworkId(), portPercentBusy); options.add(new AssetOption(port.getId(), label)); } } } AssetOptionsUtils.sortOptionsByLabel(options); return options; } @Asset("exportPathPreviewStorageSystem") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem"}) public List<AssetOption> getPreviewStorageSystem(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId) { return getPreviewStorageSystem(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, new String("")); } @Asset("exportPathPreviewStorageSystem") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem", "exportPathPorts" }) public List<AssetOption> getPreviewStorageSystem(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId, String ports) { List<AssetOption> options = Lists.newArrayList(); List<URI> exportPathPorts = parseExportPathPorts(ports); ExportPathsAdjustmentPreviewRestRep portPreview = generateExportPathPreview(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, exportPathPorts); options.add(new AssetOption(portPreview.getStorageSystem(), portPreview.getStorageSystem())); return options; } @Asset("exportPathResultingPaths") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem"}) public List<AssetOption> getResultingPaths(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId) { return getResultingPaths(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, new String("")); } @Asset("exportPathResultingPaths") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem", "exportPathPorts" }) public List<AssetOption> getResultingPaths(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId, String ports) { List<URI> exportPathPorts = parseExportPathPorts(ports); ExportPathsAdjustmentPreviewRestRep portPreview = generateExportPathPreview(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, exportPathPorts); List<InitiatorPortMapRestRep> addedList = portPreview.getAdjustedPaths(); return buildPathOptions(ctx, addedList, "exportPathAdjustment.resultingPaths"); } @Asset("exportPathRemovedPaths") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem"}) public List<AssetOption> getRemovedPaths(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId) { return getRemovedPaths(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, new String("")); } @Asset("exportPathRemovedPaths") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem", "exportPathPorts" }) public List<AssetOption> getRemovedPaths(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId, String ports) { List<URI> exportPathPorts = parseExportPathPorts(ports); ExportPathsAdjustmentPreviewRestRep portPreview = generateExportPathPreview(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, exportPathPorts); List<InitiatorPortMapRestRep> removedList = portPreview.getRemovedPaths(); return buildPathOptions(ctx, removedList, "exportPathAdjustment.removedPaths"); } private List<URI> parseExportPathPorts(String input) { List<URI> ports = new ArrayList<URI>(); List<String> parsedIds = TextUtils.parseCSV(input); for (String id : parsedIds) { ports.add(uri(id)); } return ports; } /* helper for building the list of asset option for affected and removed paths */ private List<AssetOption> buildPathOptions(AssetOptionsContext ctx, List<InitiatorPortMapRestRep> list, String message) { ViPRCoreClient client = api(ctx); List<AssetOption> options = Lists.newArrayList(); for (InitiatorPortMapRestRep ipm : list) { InitiatorRestRep initiator = ipm.getInitiator(); List<NamedRelatedResourceRep> ports = ipm.getStoragePorts(); String portList = new String(" "); List<URI> portURIs = new ArrayList<URI>(); for (NamedRelatedResourceRep port : ports) { StoragePortRestRep p = client.storagePorts().get(port.getId()); portList += p.getPortName() + " "; portURIs.add(port.getId()); } Map<URI, List<URI>> key = new HashMap<URI, List<URI>>(); key.put(initiator.getId(), portURIs); String label = getMessage(message, initiator.getHostName(), initiator.getName(), portList); String keyString = new String(""); try { keyString = CatalogSerializationUtils.serializeToString(key); } catch (Exception ex) { } options.add(new AssetOption(keyString, label)); } return options; } @Asset("exportPathAffectedExports") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem" }) public List<AssetOption> getAffectedExports(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId) { return getAffectedExports(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, new String("")); } @Asset("exportPathAffectedExports") @AssetDependencies({ "host", "exportPathVirtualArray", "exportPathExport", "exportPathMinPathsOptions", "exportPathMaxPathsOptions", "exportPathPathsPerInitiatorOptions", "exportPathExistingPath", "exportPathStorageSystem", "exportPathPorts" }) public List<AssetOption> getAffectedExports(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId, String ports) { ViPRCoreClient client = api(ctx); // the asset option list List<AssetOption> options = Lists.newArrayList(); List<URI> exportPathPorts = parseExportPathPorts(ports); ExportPathsAdjustmentPreviewRestRep portPreview = generateExportPathPreview(ctx, hostOrClusterId, vArrayId, exportId, minPaths, maxPaths, pathsPerInitiator, useExisting, storageSystemId, exportPathPorts); List<NamedRelatedResourceRep> affectedList = portPreview.getAffectedExportGroups(); List<URI> exportIds = new ArrayList<URI>(); for (NamedRelatedResourceRep affected : affectedList) { exportIds.add(affected.getId()); } List<ExportGroupRestRep> exports = client.blockExports().getByIds(exportIds); for (ExportGroupRestRep export : exports) { // TODO: need to optimize the way that we retrieve the project name. String projectName = client.projects().get(export.getProject().getId()).getName(); String label = getMessage("exportPathAdjustment.affectedExports", projectName, export.getName()); options.add(new AssetOption(export.getName(), label)); } return options; } private ExportPathsAdjustmentPreviewRestRep generateExportPathPreview(AssetOptionsContext ctx, URI hostOrClusterId, URI vArrayId, URI exportId, Integer minPaths, Integer maxPaths, Integer pathsPerInitiator, String useExisting, URI storageSystemId, List<URI> ports) { ViPRCoreClient client = api(ctx); ExportPathsAdjustmentPreviewParam param = new ExportPathsAdjustmentPreviewParam(); ExportPathParameters exportPathParameters = new ExportPathParameters(); exportPathParameters.setMinPaths(minPaths); exportPathParameters.setMaxPaths(maxPaths); exportPathParameters.setPathsPerInitiator(pathsPerInitiator); exportPathParameters.setStoragePorts(ports); param.setUseExistingPaths(useExisting.equalsIgnoreCase(YES_VALUE) ? true : false); param.setVirtualArray(vArrayId); param.setStorageSystem(storageSystemId); param.setExportPathParameters(exportPathParameters); return client.blockExports().getExportPathAdjustmentPreview(exportId, param); } @Asset("unassignedBlockVolume") @AssetDependencies({ "host", "project" }) public List<AssetOption> getBlockVolumes(AssetOptionsContext ctx, URI hostOrClusterId, final URI projectId) { ViPRCoreClient client = api(ctx); Set<URI> exportedBlockResources = BlockProvider.getExportedVolumes(api(ctx), projectId, hostOrClusterId, null); UnexportedBlockResourceFilter<VolumeRestRep> unexportedFilter = new UnexportedBlockResourceFilter<VolumeRestRep>( exportedBlockResources); SourceTargetVolumesFilter sourceTargetVolumesFilter = new SourceTargetVolumesFilter(); BlockVolumeBootVolumeFilter bootVolumeFilter = new BlockVolumeBootVolumeFilter(); List<VolumeRestRep> volumes = client.blockVolumes().findByProject(projectId, unexportedFilter.and(sourceTargetVolumesFilter).and(bootVolumeFilter.not())); return createVolumeOptions(client, volumes); } @Asset("unassignedVplexBlockVolume") @AssetDependencies({ "project", "host", "virtualArray" }) public List<AssetOption> getBlockVolumes(AssetOptionsContext ctx, final URI projectId, URI hostOrClusterId, URI virtualArrayId) { // get a list of all 'source' volumes that : // - are in this project and not exported to the given host/cluster // - are a 'source' volume // - are vplex volumes ViPRCoreClient client = api(ctx); Set<URI> exportedBlockResources = BlockProvider.getExportedVolumes(client, projectId, hostOrClusterId, virtualArrayId); UnexportedBlockResourceFilter<VolumeRestRep> unexportedFilter = new UnexportedBlockResourceFilter<VolumeRestRep>( exportedBlockResources); SourceTargetVolumesFilter sourceTargetVolumesFilter = new SourceTargetVolumesFilter(); VplexVolumeFilter vplexVolumeFilter = new VplexVolumeFilter(); CachedResources<BlockVirtualPoolRestRep> blockVpools = new CachedResources<>(client.blockVpools()); VplexVolumeVirtualPoolFilter virtualPoolFilter = new VplexVolumeVirtualPoolFilter(blockVpools); BlockVolumeBootVolumeFilter bootVolumeFilter = new BlockVolumeBootVolumeFilter(); FilterChain<VolumeRestRep> filter = sourceTargetVolumesFilter.and(unexportedFilter).and(bootVolumeFilter.not()).and(vplexVolumeFilter.or(virtualPoolFilter)); // perform the query and apply the filter List<VolumeRestRep> volumes = client.blockVolumes().findByProject(projectId, filter); // get a list of all volumes from our list that are in the target VArray, or use the target VArray for protection List<BlockObjectRestRep> acceptedVolumes = getVPlexVolumesInTargetVArray(client, virtualArrayId, volumes); return createVolumeOptions(client, acceptedVolumes); } @Asset("unassignedBlockSnapshot") @AssetDependencies({ "host", "project" }) public List<AssetOption> getBlockSnapshots(AssetOptionsContext ctx, URI hostOrClusterId, URI projectId) { // get a list of all snapshots that are in this project that are not exported to the given host/cluster Set<URI> exportedBlockResources = getExportedVolumes(api(ctx), projectId, hostOrClusterId, null); UnexportedBlockResourceFilter<BlockSnapshotRestRep> unexportedSnapshotFilter = new UnexportedBlockResourceFilter<BlockSnapshotRestRep>(exportedBlockResources); return getSnapshotOptionsForProject(ctx, projectId, unexportedSnapshotFilter); } @Asset("unassignedBlockContinuousCopies") @AssetDependencies({ "host", "project", "volumeWithContinuousCopies"}) public List<AssetOption> getBlockContinuousCopy(AssetOptionsContext ctx, URI hostOrClusterId, URI projectId, URI volume) { // get a list of all continuous copies that are in this project that are not exported to the given host/cluster Set<URI> exportedBlockResources = getExportedVolumes(api(ctx), projectId, hostOrClusterId, null); FilterChain<BlockMirrorRestRep> unexportedCopyFilter = new UnexportedBlockResourceFilter<BlockMirrorRestRep>(exportedBlockResources) .and(new DefaultResourceFilter<BlockMirrorRestRep>() { @Override public boolean acceptId(URI id) { return ResourceType.isType(ResourceType.BLOCK_CONTINUOUS_COPY, id); } }); return getContinuousCopyOptionsForProject(ctx, projectId, volume, unexportedCopyFilter); } @Asset("exportedBlockContinuousCopy") @AssetDependencies({ "project", "volumeWithContinuousCopies" }) public List<AssetOption> getExportedBlockContinuousCopyByVolume(AssetOptionsContext ctx, URI project, URI volume) { debug("getting exported blockContinuousCopy (project=%s) (parent=%s)", project, volume); final ViPRCoreClient client = api(ctx); Set<URI> exportedMirrors = new HashSet<URI>(); for (ExportGroupRestRep export : client.blockExports().findByProject(project)) { for (ExportBlockParam resource : export.getVolumes()) { if (ResourceType.isType(ResourceType.BLOCK_CONTINUOUS_COPY, resource.getId())) { exportedMirrors.add(resource.getId()); } } } ExportedBlockResourceFilter<BlockMirrorRestRep> exportedMirrorFilter = new ExportedBlockResourceFilter<BlockMirrorRestRep>(exportedMirrors); List<BlockMirrorRestRep> mirrors = client.blockVolumes().getContinuousCopies(volume, exportedMirrorFilter); return createVolumeOptions(client, mirrors); } @Asset("vplexVolumeWithSnapshots") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getVplexSnapshotVolumes(AssetOptionsContext ctx, URI project, String volumeOrConsistencyType) { final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { Set<URI> volIdSet = new HashSet<>(); List<BlockSnapshotRestRep> snapshots = findSnapshotsByProject(client, project); for (BlockSnapshotRestRep s : snapshots) { volIdSet.add(s.getParent().getId()); } // Have to get volumes just as it needs vol's mount point which snapshot doesn't have. List<VolumeRestRep> volumes = getVolumesByIds(client, volIdSet); List<VolumeRestRep> filteredVols = new ArrayList<>(); for (VolumeRestRep vol: volumes) { if (vol.getHaVolumes() != null && !vol.getHaVolumes().isEmpty() && !isInConsistencyGroup(vol)) { filteredVols.add(vol); } } return createVolumeOptions(client, filteredVols); } else { List<BlockConsistencyGroupRestRep> consistencyGroups = client.blockConsistencyGroups().findByProject(project, new DefaultResourceFilter<BlockConsistencyGroupRestRep>() { @Override public boolean accept(BlockConsistencyGroupRestRep cg) { if (cg.getTypes() != null && cg.getTypes().contains(Types.VPLEX.name())) { return true; } else { return false; } } }); return createBaseResourceOptions(consistencyGroups); } } private List<VolumeRestRep> getVolumesByIds(ViPRCoreClient client, Set<URI> vols) { log.info("Getting volumes: [{}]", vols.size()); List<VolumeRestRep> volumes = client.blockVolumes().getByIds(vols, null); log.info("Got volumens [{}]", volumes.size()); return volumes; } private List<BlockSnapshotRestRep> findSnapshotsByProject(ViPRCoreClient client, URI project) { log.info("Finding snapshots by project {}", project); List<SearchResultResourceRep> snapshotRefs = client.blockSnapshots().performSearchBy(SearchConstants.PROJECT_PARAM, project); List<URI> ids = new ArrayList<>(); for (SearchResultResourceRep ref: snapshotRefs) { ids.add(ref.getId()); } List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().getByIds(ids, null); log.info("Got snapshots: [{}]", snapshots.size()); return snapshots; } @Asset("vplexBlockSnapshot") @AssetDependencies({ "project", "blockVolumeOrConsistencyType", "vplexVolumeWithSnapshots" }) public List<AssetOption> getVplexBlockSnapshots(AssetOptionsContext ctx, URI projectId, String type, URI volumeOrCGId) { if (isVolumeType(type) && BlockProviderUtils.isType(volumeOrCGId, VOLUME_TYPE)) { List<BlockSnapshotRestRep> snapshots = api(ctx).blockSnapshots().getByVolume(volumeOrCGId); return constructSnapshotOptions(api(ctx), projectId, snapshots); } else if (isConsistencyGroupType(type) && BlockProviderUtils.isType(volumeOrCGId, BLOCK_CONSISTENCY_GROUP_TYPE)) { return getConsistencyGroupSnapshots(ctx, volumeOrCGId); } else { return new ArrayList<AssetOption>(); } } public static class UnexportedBlockResourceFilter<T extends BlockObjectRestRep> extends DefaultResourceFilter<T> { /** The list of block resources ids that have been exported to this host/cluster */ private final Set<URI> exportedBlockResources; public UnexportedBlockResourceFilter(Set<URI> exportedBlockResources) { this.exportedBlockResources = exportedBlockResources; } @Override public boolean acceptId(URI resourceId) { // accept this volume if it hasn't been exported to this host/cluster return !exportedBlockResources.contains(resourceId); } } public static class ExportedBlockResourceFilter<T extends BlockObjectRestRep> extends DefaultResourceFilter<T> { /** The list of block resources ids that have been exported */ private final Set<URI> exportedBlockResources; public ExportedBlockResourceFilter(Set<URI> exportedBlockResources) { this.exportedBlockResources = exportedBlockResources; } @Override public boolean acceptId(URI resourceId) { // accept this volume if it has been exported return exportedBlockResources.contains(resourceId); } } @Asset("blockVirtualPool") public List<AssetOption> getBlockVirtualPools(AssetOptionsContext ctx) { debug("getting blockVirtualPools"); return createBaseResourceOptions(api(ctx).blockVpools().getByTenant(ctx.getTenant())); } @Asset("blockVirtualPoolFilter") public List<AssetOption> getBlockVirtualPoolFilters(AssetOptionsContext ctx) { List<AssetOption> options = createBaseResourceOptions(api(ctx).blockVpools().getAll()); options.add(0, new AssetOption("All", "All")); return options; } /** * Returns the virtual pools for a given virtualArray (initially added for the Create Volume service) * * @param ctx * @param virtualArray * @return */ @Asset("blockVirtualPool") @AssetDependencies({ "virtualArray" }) public List<AssetOption> getVirtualPoolsForVirtualArray(AssetOptionsContext ctx, URI virtualArray) { debug("getting virtualPoolsForVirtualArray(virtualArray=%s)", virtualArray); List<BlockVirtualPoolRestRep> virtualPools = api(ctx).blockVpools().getByVirtualArrayAndTenant(virtualArray,ctx.getTenant()); return createVirtualPoolResourceOptions(virtualPools); } @Asset("blockVirtualPool") @AssetDependencies({ "blockVirtualArray" }) public List<AssetOption> getVirtualPoolsForBlockVirtualArray(AssetOptionsContext ctx, URI virtualArray) { debug("getting getVirtualPoolsForBlockVirtualArray(virtualArray=%s)", virtualArray); return getVirtualPoolsForVirtualArray(ctx, virtualArray); } @Asset("blockVirtualPool") @AssetDependencies({ "virtualArrayByConsistencyGroup" }) public List<AssetOption> getVirtualPoolsForVirtualArrayByCG(AssetOptionsContext ctx, URI virtualArray) { return getVirtualPoolsForVirtualArray(ctx, virtualArray); } @Asset("blockVolume") @AssetDependencies("project") public List<AssetOption> getVolumes(AssetOptionsContext ctx, URI project) { debug("getting volumes (project=%s)", project); ViPRCoreClient client = api(ctx); return createVolumeOptions(client, listVolumes(client, project)); } @Asset("blockVolumeByType") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getVolumesByType(AssetOptionsContext ctx, URI project, String type) { debug("getting volumes (project=%s)", project); final ViPRCoreClient client = api(ctx); if (isVolumeType(type)) { return createVolumeOptions(client, listVolumesWithoutConsistencyGroup(client, project)); } else { List<BlockConsistencyGroupRestRep> consistencyGroups = api(ctx).blockConsistencyGroups() .search() .byProject(project) .run(); return createBaseResourceOptions(consistencyGroups); } } @Asset("protectedBlockVolume") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getProtectedVolumes(AssetOptionsContext ctx, URI project, String volumeOrConsistencyType) { ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { debug("getting protected volumes (project=%s)", project); // Allow recoverpoint or SRDF sources ResourceFilter<VolumeRestRep> filter = RecoverPointPersonalityFilter.SOURCE.or(new SRDFSourceFilter()); List<VolumeRestRep> volumes = client.blockVolumes().findByProject(project, filter); // We need to filter out SRDF Metro volumes as they are not eligible for FAILOVER or SWAP List<VolumeRestRep> filteredVols = new ArrayList<>(); for (VolumeRestRep currentVolume : volumes) { ProtectionRestRep protection = currentVolume.getProtection(); if (protection != null && protection.getSrdfRep() != null && protection.getSrdfRep().getSRDFTargetVolumes() != null && !protection.getSrdfRep().getSRDFTargetVolumes().isEmpty()) { for (VolumeRestRep srdfTarget : client.blockVolumes().getByRefs(protection.getSrdfRep().getSRDFTargetVolumes(), new SRDFTargetFilter())) { SRDFRestRep srdf = (srdfTarget.getProtection() != null) ? srdfTarget.getProtection().getSrdfRep() : null; if (srdf != null && (srdf.getAssociatedSourceVolume() != null) && (srdf.getSrdfCopyMode() != null) && (!ACTIVE.equalsIgnoreCase(srdf.getSrdfCopyMode()))) { filteredVols.add(currentVolume); break; } } } else { // Add the volume as before filteredVols.add(currentVolume); } } return createVolumeOptions(client, filteredVols); } else { debug("getting protected consistency groups (project=%s)", project); // Allow recoverpoint or SRDF sources ResourceFilter<BlockConsistencyGroupRestRep> filter = new ConsistencyGroupFilter(BlockConsistencyGroup.Types.RP.name(), false).or(new ConsistencyGroupFilter(BlockConsistencyGroup.Types.SRDF.name(), false)); List<BlockConsistencyGroupRestRep> consistencyGroups = client.blockConsistencyGroups() .search() .byProject(project) .filter(filter) .run(); // We need to filter out SRDF Metro volumes as they are not eligible for FAILOVER or SWAP List<BlockConsistencyGroupRestRep> filteredCgs = new ArrayList<>(); for (BlockConsistencyGroupRestRep cg : consistencyGroups) { // Get SRDF source volumes if (cg.getTypes().contains(BlockConsistencyGroup.Types.SRDF.name())) { List<VolumeRestRep> srcVolumes = client.blockVolumes().getByRefs(cg.getVolumes(), new SRDFSourceFilter()); if (srcVolumes != null && !srcVolumes.isEmpty()) { // Get the first source volume and obtain its target references VolumeRestRep srcVolume = srcVolumes.get(0); for (VolumeRestRep srdfTarget : client.blockVolumes().getByRefs( srcVolume.getProtection().getSrdfRep().getSRDFTargetVolumes(), new SRDFTargetFilter())) { SRDFRestRep srdf = (srdfTarget.getProtection() != null) ? srdfTarget.getProtection().getSrdfRep() : null; if (srdf != null && (srdf.getAssociatedSourceVolume() != null) && (srdf.getSrdfCopyMode() != null) && (!ACTIVE.equalsIgnoreCase(srdf.getSrdfCopyMode()))) { filteredCgs.add(cg); break; } } } } else { // Add the cg as before filteredCgs.add(cg); } } return createBaseResourceOptions(filteredCgs); } } @Asset("failoverTarget") @AssetDependencies("protectedBlockVolume") public List<AssetOption> getFailoverTarget(AssetOptionsContext ctx, URI protectedBlockVolume) { if (protectedBlockVolume != null) { ViPRCoreClient client = api(ctx); if (BlockProviderUtils.isType(protectedBlockVolume, VOLUME_TYPE)) { debug("getting failoverTargets (protectedBlockVolume=%s)", protectedBlockVolume); VolumeRestRep volume = client.blockVolumes().get(protectedBlockVolume); ProtectionRestRep protection = volume.getProtection(); if (protection != null) { // RecoverPoint protection if (protection.getRpRep() != null && protection.getRpRep().getProtectionSet() != null) { return getRpFailoverTargets(client, volume); } // VMAX SRDF protection if (protection.getSrdfRep() != null && protection.getSrdfRep().getSRDFTargetVolumes() != null && !protection.getSrdfRep().getSRDFTargetVolumes().isEmpty()) { return getSrdfFailoverTargets(client, volume); } } } else if (BlockProviderUtils.isType(protectedBlockVolume, BLOCK_CONSISTENCY_GROUP_TYPE)) { debug("getting failoverTargets for consistency group %s", protectedBlockVolume); BlockConsistencyGroupRestRep cg = client.blockConsistencyGroups().get(protectedBlockVolume); List<VolumeRestRep> srcVolumes = null; // Get RP source volumes if (cg.getTypes().contains(BlockConsistencyGroup.Types.RP.name())) { srcVolumes = client.blockVolumes().getByRefs(cg.getVolumes(), RecoverPointPersonalityFilter.SOURCE); } // Get SRDF source volumes if (cg.getTypes().contains(BlockConsistencyGroup.Types.SRDF.name())) { srcVolumes = client.blockVolumes().getByRefs(cg.getVolumes(), new SRDFSourceFilter()); } if (srcVolumes != null && !srcVolumes.isEmpty()) { // Get the first source volume and obtain its target references VolumeRestRep srcVolume = srcVolumes.get(0); if (cg.getTypes() != null) { Map<String, String> targetVolumes = Maps.newLinkedHashMap(); CachedResources<VirtualArrayRestRep> virtualArrays = new CachedResources<VirtualArrayRestRep>(client.varrays()); List<VirtualArrayRelatedResourceRep> targets = new ArrayList<VirtualArrayRelatedResourceRep>(); // Process the RP targets if (cg.getTypes().contains(BlockConsistencyGroup.Types.RP.name())) { targets = srcVolume.getProtection().getRpRep().getRpTargets(); } // Process the SRDF targets if (cg.getTypes().contains(BlockConsistencyGroup.Types.SRDF.name())) { targets = srcVolume.getProtection().getSrdfRep().getSRDFTargetVolumes(); } for (VolumeRestRep targetVolume : client.blockVolumes().getByRefs(targets)) { VirtualArrayRestRep virtualArray = virtualArrays.get(targetVolume.getVirtualArray()); String label = getMessage(name(virtualArray)); targetVolumes.put(stringId(virtualArray), label); } List<AssetOption> options = Lists.newArrayList(); for (Map.Entry<String, String> entry : targetVolumes.entrySet()) { options.add(new AssetOption(entry.getKey(), entry.getValue())); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } } } } return Lists.newArrayList(); } protected List<AssetOption> getRpFailoverTargets(ViPRCoreClient client, VolumeRestRep volume) { Map<String, String> targetVolumes = Maps.newLinkedHashMap(); URI protectionSetId = volume.getProtection().getRpRep().getProtectionSet().getId(); ProtectionSetRestRep localProtectionSet = client.blockVolumes().getProtectionSet(volume.getId(), protectionSetId); String sourceSiteName = volume.getProtection().getRpRep().getInternalSiteName(); CachedResources<VirtualArrayRestRep> virtualArrays = new CachedResources<VirtualArrayRestRep>(client.varrays()); List<RelatedResourceRep> rpTargets = localProtectionSet.getVolumes(); for (VolumeRestRep protectionSetVolume : client.blockVolumes().getByRefs(rpTargets, RecoverPointPersonalityFilter.TARGET)) { String targetSiteName = protectionSetVolume.getProtection().getRpRep().getInternalSiteName(); boolean isLocal = StringUtils.equals(sourceSiteName, targetSiteName); String rpType = isLocal ? "local" : "remote"; VirtualArrayRestRep virtualArray = virtualArrays.get(protectionSetVolume.getVirtualArray()); String label = getMessage("recoverpoint.target", name(protectionSetVolume), rpType, name(virtualArray)); targetVolumes.put(stringId(protectionSetVolume), label); } List<AssetOption> options = Lists.newArrayList(); for (Map.Entry<String, String> entry : targetVolumes.entrySet()) { options.add(new AssetOption(entry.getKey(), entry.getValue())); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected List<AssetOption> getSrdfFailoverTargets(ViPRCoreClient client, VolumeRestRep volume) { Map<String, String> targetVolumes = Maps.newLinkedHashMap(); CachedResources<VirtualArrayRestRep> virtualArrays = new CachedResources<VirtualArrayRestRep>(client.varrays()); List<VirtualArrayRelatedResourceRep> srdfTargets = volume.getProtection().getSrdfRep().getSRDFTargetVolumes(); for (VolumeRestRep protectionSetVolume : client.blockVolumes().getByRefs(srdfTargets, new SRDFTargetFilter())) { VirtualArrayRestRep virtualArray = virtualArrays.get(protectionSetVolume.getVirtualArray()); String label = getMessage("srdf.target", name(protectionSetVolume), name(virtualArray)); targetVolumes.put(stringId(protectionSetVolume), label); } List<AssetOption> options = Lists.newArrayList(); for (Map.Entry<String, String> entry : targetVolumes.entrySet()) { options.add(new AssetOption(entry.getKey(), entry.getValue())); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } @Asset("blockSnapshot") @AssetDependencies({ "project" }) public List<AssetOption> getBlockSnapshotsByVolume(AssetOptionsContext ctx, URI project) { debug("getting blockSnapshots (project=%s)", project); return getSnapshotOptionsForProject(ctx, project); } @Asset("exportedBlockSnapshot") @AssetDependencies({ "project" }) public List<AssetOption> getExportedBlockSnapshotsByVolume(AssetOptionsContext ctx, URI project) { debug("getting exported blockSnapshots (project=%s)", project); final ViPRCoreClient client = api(ctx); List<URI> snapshotIds = Lists.newArrayList(); for (ExportGroupRestRep export : client.blockExports().findByProject(project)) { for (ExportBlockParam resource : export.getVolumes()) { if (ResourceType.isType(ResourceType.BLOCK_SNAPSHOT, resource.getId())) { snapshotIds.add(resource.getId()); } } } List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().getByIds(snapshotIds); return createVolumeWithVarrayOptions(client, snapshots); } private List<AssetOption> getVolumeSnapshotOptionsForProject(AssetOptionsContext ctx, URI project) { final ViPRCoreClient client = api(ctx); List<BlockSnapshotRestRep> snapshots = findSnapshotsByProject(client, project); List<BlockSnapshotRestRep> filteredSnap = new ArrayList<>(); for (BlockSnapshotRestRep snapshot: snapshots) { if ( !isSnapshotRPBookmark(snapshot) ) { filteredSnap.add(snapshot); } } return constructSnapshotOptions(client, project, filteredSnap); } private List<AssetOption> getVolumeRPSnapshotOptionsForProject(AssetOptionsContext ctx, URI project) { final ViPRCoreClient client = api(ctx); List<BlockSnapshotRestRep> snapshots = findSnapshotsByProject(client, project); List<BlockSnapshotRestRep> filteredSnap = new ArrayList<>(); for (BlockSnapshotRestRep snapshot: snapshots) { if ( isSnapshotRPBookmark(snapshot) ) { filteredSnap.add(snapshot); } } return constructSnapshotOptions(client, project, filteredSnap); } /** * get single volume snapshot sessions for a project * @param ctx * @param project * @return */ private List<AssetOption> getVolumeSnapshotSessionOptionsForProject(AssetOptionsContext ctx, URI project) { final ViPRCoreClient client = api(ctx); List<BlockSnapshotSessionRestRep> snapshotSessions = client.blockSnapshotSessions().findByProject(project); List<BlockSnapshotSessionRestRep> singleVolumeSnapshotSessions = new ArrayList<BlockSnapshotSessionRestRep>(); for (BlockSnapshotSessionRestRep snapshotSession : snapshotSessions) { if (snapshotSession.getReplicationGroupInstance() == null) { singleVolumeSnapshotSessions.add(snapshotSession); } } return constructSnapshotSessionOptions(client, project, singleVolumeSnapshotSessions); } @Asset("blockSnapshotOrConsistencyGroup") @AssetDependencies({ "project", "blockVolumeOrConsistencyType", "blockSnapshotType", "consistencyGroupByProjectAndType" }) public List<AssetOption> getBlockSnapshotsByVolume(AssetOptionsContext ctx, URI project, String storageType, String snapshotType, URI consistencyGroupId) { if (NONE_TYPE.equals(storageType)) { return new ArrayList<AssetOption>(); } else { if (CG_SNAPSHOT_TYPE_VALUE.equals(snapshotType) || CG_SNAPSHOT_SESSION_TYPE_VALUE.equals(snapshotType)) { if (consistencyGroupId == null) { error("Consistency type invalid : %s", consistencyGroupId); return new ArrayList<AssetOption>(); } if (!BlockProviderUtils.isType(consistencyGroupId, BLOCK_CONSISTENCY_GROUP_TYPE)) { error("Consistency Group field is required for Storage Type [%s, %s]", storageType, consistencyGroupId); return new ArrayList<AssetOption>(); } if (CG_SNAPSHOT_SESSION_TYPE_VALUE.equals(snapshotType)) { return getConsistencyGroupSnapshotSessions(ctx, consistencyGroupId); } else { return getConsistencyGroupSnapshots(ctx, consistencyGroupId); } } else if (SNAPSHOT_SESSION_TYPE_VALUE.equals(snapshotType)) { info("getting blockSnapshotSessions (project=%s)", project); return getVolumeSnapshotSessionOptionsForProject(ctx, project); } else if (RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_VALUE.equals(snapshotType)) { info("getting rpBookmarks (project=%s)", project); return getVolumeRPSnapshotOptionsForProject(ctx, project); } else { info("getting blockSnapshots (project=%s)", project); return getVolumeSnapshotOptionsForProject(ctx, project); } } } @Asset("snapshotAvailableForResynchronize") @AssetDependencies({ "blockVolumeWithSnapshot", "blockVolumeOrConsistencyType" }) public List<AssetOption> getSnapshotSynchronize(AssetOptionsContext ctx, URI volumeId, String volumeOrConsistencyType) { if (!checkTypeConsistency(volumeId, volumeOrConsistencyType)) { warn("Inconsistent types, %s and %s, return empty results", volumeId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().getByVolume(volumeId, new DefaultResourceFilter<BlockSnapshotRestRep>() { @Override public boolean accept(BlockSnapshotRestRep snapshot) { String replicaState = snapshot.getReplicaState(); return replicaState != null && !(replicaState.equals(ReplicationState.DETACHED.name())) && !(replicaState.equals(ReplicationState.INACTIVE.name())); } }); return constructSnapshotOptions(snapshots); } else { return getConsistencyGroupSnapshots(ctx, volumeId); } } @Asset("consistencyGroupByProjectAndType") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getAllConsistencyGroups(final AssetOptionsContext ctx, URI projectId, String type) { if (isConsistencyGroupType(type)) { List<BlockConsistencyGroupRestRep> consistencyGroups = api(ctx).blockConsistencyGroups() .search() .byProject(projectId) .run(); return createBaseResourceOptions(consistencyGroups); } else { return Lists.newArrayList(newAssetOption(NONE_TYPE, "None")); } } @Asset("applicationSnapshotType") public List<AssetOption> getApplicationSnapshotTypes(AssetOptionsContext ctx) { List<AssetOption> options = Lists.newArrayList(); options.add(SNAPSHOT_TARGET_TYPE_OPTION); options.add(SNAPSHOT_SESSION_TYPE_OPTION); return options; } @Asset("applicationSnapshotTargetType") public List<AssetOption> getApplicationSnapshotTargetType(AssetOptionsContext ctx) { List<AssetOption> options = Lists.newArrayList(); options.add(SNAPSHOT_TARGET_TYPE_OPTION); return options; } @Asset("applicationSnapshotSessionCopySets") @AssetDependencies({ "application" }) public List<AssetOption> getApplicationSnapshotSessionCopySets(AssetOptionsContext ctx, URI application) { return createOptions(api(ctx).application().getVolumeGroupSnapsetSessionSets(application).getCopySets().toArray()); } @Asset("applicationSnapshotCopySets") @AssetDependencies({ "application" }) public List<AssetOption> getApplicationSnapshotCopySets(AssetOptionsContext ctx, URI application) { return createOptions(api(ctx).application().getVolumeGroupSnapshotSets(application).getCopySets().toArray()); } private Set<String> getApplicationSnapshotCopySetsForRestore(AssetOptionsContext ctx, URI application) { Set<String> restoreCopySets = new HashSet<String>(); Set<String> copySetNames = api(ctx).application().getVolumeGroupSnapshotSets(application).getCopySets(); boolean isRP = false; NamedVolumesList volsInApp = api(ctx).application().getVolumeByApplication(application); if (volsInApp != null && volsInApp.getVolumes() != null && !volsInApp.getVolumes().isEmpty()) { VolumeRestRep firstVol = api(ctx).blockVolumes().get(volsInApp.getVolumes().get(0).getId()); isRP = BlockStorageUtils.isRPVolume(firstVol); } if (isRP) { for (String copySetName : copySetNames) { VolumeGroupCopySetParam input = new VolumeGroupCopySetParam(); input.setCopySetName(copySetName); SnapshotList snapshots = api(ctx).application().getVolumeGroupSnapshotsForSet(application, input); if (snapshots != null && snapshots.getSnapList() != null && !snapshots.getSnapList().isEmpty()) { BlockSnapshotRestRep snapRep = api(ctx).blockSnapshots().get(snapshots.getSnapList().get(0)); if (snapRep != null) { VolumeRestRep parentVol = api(ctx).blockVolumes().get(snapRep.getParent()); if (BlockStorageUtils.isRPSourceVolume(parentVol)) { restoreCopySets.add(copySetName); } } } } } else { restoreCopySets.addAll(copySetNames); } return restoreCopySets; } private Set<String> getApplicationSnapshotSessionCopySetsForRestore(AssetOptionsContext ctx, URI application) { Set<String> restoreCopySets = new HashSet<String>(); Set<String> copySetNames = api(ctx).application().getVolumeGroupSnapsetSessionSets(application).getCopySets(); boolean isRP = false; NamedVolumesList volsInApp = api(ctx).application().getVolumeByApplication(application); if (volsInApp != null && volsInApp.getVolumes() != null && !volsInApp.getVolumes().isEmpty()) { VolumeRestRep firstVol = api(ctx).blockVolumes().get(volsInApp.getVolumes().get(0).getId()); isRP = BlockStorageUtils.isRPVolume(firstVol); } if (isRP) { List<VolumeRestRep> applicationVolumes = api(ctx).blockVolumes().getByRefs( api(ctx).application().getVolumeByApplication(application).getVolumes()); Set<String> sourceRepGrpNames = new HashSet<String>(); for (VolumeRestRep volume : applicationVolumes) { if (volume.getReplicationGroupInstance() != null && BlockStorageUtils.isRPSourceVolume(volume)) { sourceRepGrpNames.add(volume.getReplicationGroupInstance()); } } for (String copySetName : copySetNames) { VolumeGroupCopySetParam input = new VolumeGroupCopySetParam(); input.setCopySetName(copySetName); BlockSnapshotSessionList sessions = api(ctx).application().getVolumeGroupSnapshotSessionsByCopySet(application, input); if (sessions != null && sessions.getSnapSessionRelatedResourceList() != null && !sessions.getSnapSessionRelatedResourceList().isEmpty()) { BlockSnapshotSessionRestRep sessionRep = api(ctx).blockSnapshotSessions().get(sessions.getSnapSessionRelatedResourceList().get(0)); if (sessionRep != null && sessionRep.getReplicationGroupInstance() != null && sourceRepGrpNames.contains(sessionRep.getReplicationGroupInstance())) { restoreCopySets.add(copySetName); } } } } else { restoreCopySets.addAll(copySetNames); } return restoreCopySets; } @Asset("applicationRestoreCopySets") @AssetDependencies({ "application", "applicationSnapshotType" }) public List<AssetOption> getApplicationRestoreCopySets(AssetOptionsContext ctx, URI application, String snapshotType) { if (snapshotType.equalsIgnoreCase(SNAPSHOT_SESSION_TYPE_VALUE)) { return createOptions(getApplicationSnapshotSessionCopySetsForRestore(ctx, application).toArray()); } else if (snapshotType.equalsIgnoreCase(SNAPSHOT_TARGET_TYPE_VALUE)) { return createOptions(getApplicationSnapshotCopySetsForRestore(ctx, application).toArray()); } return Lists.newArrayList(); } @Asset("applicationCopySets") @AssetDependencies({ "application", "applicationSnapshotType" }) public List<AssetOption> getApplicationCopySets(AssetOptionsContext ctx, URI application, String snapshotType) { if (snapshotType.equalsIgnoreCase(SNAPSHOT_SESSION_TYPE_VALUE)) { return createOptions(api(ctx).application().getVolumeGroupSnapsetSessionSets(application).getCopySets().toArray()); } else if (snapshotType.equalsIgnoreCase(SNAPSHOT_TARGET_TYPE_VALUE)) { return createOptions(api(ctx).application().getVolumeGroupSnapshotSets(application).getCopySets().toArray()); } return Lists.newArrayList(); } protected Set<String> getReplicationGroupsForApplicationFullCopy(ViPRCoreClient client, URI applicationId, String copySet) { Set<String> options = Sets.newHashSet(); VolumeGroupCopySetParam input = new VolumeGroupCopySetParam(); input.setCopySetName(copySet); NamedVolumesList fullCopies = client.application().getVolumeGroupFullCopiesForSet(applicationId, input); for (NamedRelatedResourceRep fullCopy : fullCopies.getVolumes()) { VolumeRestRep fullCopyRep = client.blockVolumes().get(fullCopy); if (fullCopyRep != null && fullCopyRep.getReplicationGroupInstance() != null) { options.add(fullCopyRep.getReplicationGroupInstance()); } } return options; } protected Set<String> getReplicationGroupsForApplicationSnapshotSession(ViPRCoreClient client, URI applicationId, String copySet) { Set<String> options = Sets.newHashSet(); VolumeGroupCopySetParam input = new VolumeGroupCopySetParam(); input.setCopySetName(copySet); BlockSnapshotSessionList sessions = client.application().getVolumeGroupSnapshotSessionsByCopySet(applicationId, input); for (NamedRelatedResourceRep session : sessions.getSnapSessionRelatedResourceList()) { BlockSnapshotSessionRestRep sessionRep = client.blockSnapshotSessions().get(session); if (sessionRep != null && sessionRep.getReplicationGroupInstance() != null) { options.add(sessionRep.getReplicationGroupInstance()); } } return BlockStorageUtils.stripRPTargetFromReplicationGroup(options); } protected Set<String> getReplicationGroupsForApplicationSnapshot(ViPRCoreClient client, URI applicationId, String copySet) { Set<String> options = Sets.newHashSet(); VolumeGroupCopySetParam input = new VolumeGroupCopySetParam(); input.setCopySetName(copySet); SnapshotList sessions = client.application().getVolumeGroupSnapshotsForSet(applicationId, input); for (NamedRelatedResourceRep snap : sessions.getSnapList()) { BlockSnapshotRestRep snapRep = client.blockSnapshots().get(snap); // TODO get replication group from parent. should the snapshot already contain this? VolumeRestRep parentVolume = client.blockVolumes().get(snapRep.getParent()); if (parentVolume != null && parentVolume.getReplicationGroupInstance() != null) { options.add(parentVolume.getReplicationGroupInstance()); } } return BlockStorageUtils.stripRPTargetFromReplicationGroup(options); } @Asset("replicationGroup") @AssetDependencies({ "application", "applicationVirtualArray" }) public List<AssetOption> getApplicationFullCopyReplicationGroups(AssetOptionsContext ctx, URI applicationId, String virtualArrayParameter) { return getApplicationReplicationGroups(ctx, applicationId, virtualArrayParameter); } @Asset("replicationGroup") @AssetDependencies({ "application", "applicationSnapshotVirtualArray" }) public List<AssetOption> getApplicationReplicationGroups(AssetOptionsContext ctx, URI applicationId, String virtualArrayParameter) { ViPRCoreClient client = api(ctx); boolean isTarget = false; URI virtualArray = null; if (virtualArrayParameter != null && StringUtils.split(virtualArrayParameter, ':')[0].equals("tgt")) { virtualArray = URI.create(StringUtils.substringAfter(virtualArrayParameter, ":")); isTarget = true; } else { isTarget = false; } Set<String> subGroups = Sets.newHashSet(); NamedVolumesList applicationVolumes = client.application().getVolumeByApplication(applicationId); for (NamedRelatedResourceRep volumeId : applicationVolumes.getVolumes()) { VolumeRestRep volume = client.blockVolumes().get(volumeId); VolumeRestRep parentVolume = volume; if (volume.getHaVolumes() != null && !volume.getHaVolumes().isEmpty()) { volume = BlockStorageUtils.getVPlexSourceVolume(client, volume); } if (volume != null && volume.getReplicationGroupInstance() != null) { if (isTarget) { if (volume.getVirtualArray().getId().equals(virtualArray)) { subGroups.add(volume.getReplicationGroupInstance()); } } else { if (!BlockStorageUtils.isRPVolume(parentVolume) || BlockStorageUtils.isRPSourceVolume(parentVolume)) { subGroups.add(volume.getReplicationGroupInstance()); } } } } return createStringOptions(BlockStorageUtils.stripRPTargetFromReplicationGroup(subGroups)); } @Asset("replicationGroup") @AssetDependencies({ "application", "fullCopyName" }) public List<AssetOption> getApplicationReplicationGroupsForFullCopy(AssetOptionsContext ctx, URI applicationId, String copySet) { final ViPRCoreClient client = api(ctx); return createStringOptions(getReplicationGroupsForApplicationFullCopy(client, applicationId, copySet)); } @Asset("replicationGroup") @AssetDependencies({ "application", "applicationSnapshotSessionCopySets" }) public List<AssetOption> getApplicationReplicationGroupsForSnapshotSession(AssetOptionsContext ctx, URI applicationId, String copySet) { final ViPRCoreClient client = api(ctx); return createStringOptions(getReplicationGroupsForApplicationSnapshotSession(client, applicationId, copySet)); } @Asset("replicationGroup") @AssetDependencies({ "application", "applicationSnapshotCopySets" }) public List<AssetOption> getApplicationReplicationGroupsForSnapshot(AssetOptionsContext ctx, URI applicationId, String copySet) { final ViPRCoreClient client = api(ctx); return createStringOptions(getReplicationGroupsForApplicationSnapshot(client, applicationId, copySet)); } @Asset("replicationGroup") @AssetDependencies({ "application", "applicationSnapshotType", "applicationCopySets" }) public List<AssetOption> getApplicationReplicationGroups(AssetOptionsContext ctx, URI applicationId, String snapshotType, String copySet) { final ViPRCoreClient client = api(ctx); if (snapshotType.equalsIgnoreCase(SNAPSHOT_SESSION_TYPE_VALUE)) { return createStringOptions(getReplicationGroupsForApplicationSnapshotSession(client, applicationId, copySet)); } else if (snapshotType.equalsIgnoreCase(SNAPSHOT_TARGET_TYPE_VALUE)) { return createStringOptions(getReplicationGroupsForApplicationSnapshot(client, applicationId, copySet)); } return Lists.newArrayList(); } @Asset("replicationGroup") @AssetDependencies({ "application", "applicationSnapshotType", "applicationRestoreCopySets" }) public List<AssetOption> getApplicationRestoreReplicationGroups(AssetOptionsContext ctx, URI applicationId, String snapshotType, String copySet) { final ViPRCoreClient client = api(ctx); if (snapshotType.equalsIgnoreCase(SNAPSHOT_SESSION_TYPE_VALUE)) { return createStringOptions(getReplicationGroupsForApplicationSnapshotSession(client, applicationId, copySet)); } else if (snapshotType.equalsIgnoreCase(SNAPSHOT_TARGET_TYPE_VALUE)) { return createStringOptions(getReplicationGroupsForApplicationSnapshot(client, applicationId, copySet)); } return Lists.newArrayList(); } @Asset("blockSnapshotType") @AssetDependencies({ "blockVolumeOrConsistencyType", "snapshotBlockVolume" }) public List<AssetOption> getBlockSnapshotType(AssetOptionsContext ctx, String storageType, URI blockVolumeOrCG) { // These are hard coded values for now. In the future, this may be available through an API List<AssetOption> options = Lists.newArrayList(); if (isConsistencyGroupType(blockVolumeOrCG)) { options.add(CG_SNAPSHOT_TYPE_OPTION); // Only add cg session option if the CG selected supports it ViPRCoreClient client = api(ctx); BlockConsistencyGroupRestRep cg = client.blockConsistencyGroups().get(blockVolumeOrCG); if (isSnapshotSessionSupportedForCG(cg)) { options.add(CG_SNAPSHOT_SESSION_TYPE_OPTION); } } else { debug("getting blockSnapshotTypes (blockVolume=%s)", blockVolumeOrCG); ViPRCoreClient client = api(ctx); VolumeRestRep volume = client.blockVolumes().get(blockVolumeOrCG); BlockVirtualPoolRestRep virtualPool = client.blockVpools().get(volume.getVirtualPool()); if (isLocalSnapshotSupported(virtualPool)) { options.add(LOCAL_ARRAY_SNAPSHOT_TYPE_OPTION); } if (isRPSourceVolume(volume)) { options.add(RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_OPTION); } if (isSnapshotSessionSupportedForVolume(volume)) { options.add(SNAPSHOT_SESSION_TYPE_OPTION); } } return options; } @Asset("blockSnapshotType") @AssetDependencies("blockVolumeOrConsistencyType") public List<AssetOption> getBlockSnapshotType(AssetOptionsContext ctx, String storageType) { // These are hard coded values for now. In the future, this may be available through an API List<AssetOption> options = Lists.newArrayList(); if (isConsistencyGroupType(storageType)) { options.add(CG_SNAPSHOT_TYPE_OPTION); options.add(CG_SNAPSHOT_SESSION_TYPE_OPTION); } else { options.add(LOCAL_ARRAY_SNAPSHOT_TYPE_OPTION); options.add(RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_OPTION); options.add(SNAPSHOT_SESSION_TYPE_OPTION); } return options; } @Asset("linkedSnapshotsForApplicationSnapshotSessionLinkService") @AssetDependencies({ "application", "applicationSnapshotSessionCopySets" }) public List<AssetOption> getLinkedSnapshotsForApplicationSnapshotSessionVolumeNew(AssetOptionsContext ctx, URI application, String selectedCopySet) { ViPRCoreClient client = api(ctx); List<BlockSnapshotRestRep> snapshots = new ArrayList<BlockSnapshotRestRep>(); Set<String> replicationGroups = getReplicationGroupsForApplicationSnapshotSession(client, application, selectedCopySet); Set<String> copySets = client.application().getVolumeGroupSnapsetSessionSets(application).getCopySets(); List<BlockSnapshotSessionRestRep> snapshotSessions = Lists.newArrayList(); for (String copySet : copySets) { VolumeGroupCopySetParam param = new VolumeGroupCopySetParam(); param.setCopySetName(copySet); BlockSnapshotSessionList snapshotSessionList = client.application().getVolumeGroupSnapshotSessionsByCopySet(application, param); List<BlockSnapshotSessionRestRep> snapshotSessionsTmp = client.blockSnapshotSessions().getByRefs( snapshotSessionList.getSnapSessionRelatedResourceList()); snapshotSessions.addAll(snapshotSessionsTmp); for (BlockSnapshotSessionRestRep session : snapshotSessionsTmp) { if (replicationGroups.contains(BlockStorageUtils.stripRPTargetFromReplicationGroup(session.getReplicationGroupInstance()))) { for (RelatedResourceRep target : session.getLinkedTarget()) { BlockSnapshotRestRep blockSnapshot = client.blockSnapshots().get(target); snapshots.add(blockSnapshot); } } } } return constructSnapshotWithSnapshotSessionOptions(snapshots, snapshotSessions); } @Asset("linkedSnapshotsForApplicationSnapshotSession") @AssetDependencies({ "application", "applicationSnapshotSessionCopySets" }) public List<AssetOption> getLinkedSnapshotsForApplicationSnapshotSessionVolume(AssetOptionsContext ctx, URI application, String copySet) { List<BlockSnapshotRestRep> snapshots = new ArrayList<BlockSnapshotRestRep>(); VolumeGroupCopySetParam param = new VolumeGroupCopySetParam(); param.setCopySetName(copySet); BlockSnapshotSessionList snapshotSessionList = api(ctx).application().getVolumeGroupSnapshotSessionsByCopySet(application, param); List<BlockSnapshotSessionRestRep> snapshotSessions = api(ctx).blockSnapshotSessions().getByRefs( snapshotSessionList.getSnapSessionRelatedResourceList()); for (BlockSnapshotSessionRestRep session : snapshotSessions) { for (RelatedResourceRep target : session.getLinkedTarget()) { BlockSnapshotRestRep blockSnapshot = api(ctx).blockSnapshots().get(target); snapshots.add(blockSnapshot); } } return constructSnapshotWithSnapshotSessionOptions(snapshots, snapshotSessions); } @Asset("linkedSnapshotsForVolume") @AssetDependencies({ "snapshotSessionBlockVolume", "blockVolumeOrConsistencyType" }) public List<AssetOption> getLinkedSnapshotsForSnapshotSessionVolume(AssetOptionsContext ctx, URI volumeOrCGId, String volumeOrConsistencyType) { if (!checkTypeConsistency(volumeOrCGId, volumeOrConsistencyType)) { warn("Inconsistent types, %s and %s, return empty results", volumeOrCGId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } List<BlockSnapshotRestRep> snapshots = new ArrayList<BlockSnapshotRestRep>(); List<BlockSnapshotSessionRestRep> snapshotSessions = new ArrayList<BlockSnapshotSessionRestRep>(); final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { snapshots = client.blockSnapshots().getByVolume(volumeOrCGId, new DefaultResourceFilter<BlockSnapshotRestRep>()); snapshotSessions = client.blockSnapshotSessions().getByVolume(volumeOrCGId, new DefaultResourceFilter<BlockSnapshotSessionRestRep>()); } else { snapshots = client.blockSnapshots().getByConsistencyGroup(volumeOrCGId, new DefaultResourceFilter<BlockSnapshotRestRep>()); snapshotSessions = client.blockSnapshotSessions().getByConsistencyGroup(volumeOrCGId, new DefaultResourceFilter<BlockSnapshotSessionRestRep>()); } return constructSnapshotWithSnapshotSessionOptions(snapshots, snapshotSessions); } @Asset("linkedSnapshotCopyMode") public List<AssetOption> getLinkedSnapshotCopyMode(AssetOptionsContext ctx) { // These are hard coded values for now. In the future, this may be available through an API List<AssetOption> options = Lists.newArrayList(); options.add(LINKED_SNAPSHOT_COPYMODE_OPTION); options.add(LINKED_SNAPSHOT_NOCOPYMODE_OPTION); return options; } @Asset("displayJournals") public List<AssetOption> getDisplayJournals(AssetOptionsContext ctx) { // These are hard coded values for now. In the future, this may be available through an API List<AssetOption> options = Lists.newArrayList(); options.add(DISPLAY_JOURNALS_FALSE_OPTION); options.add(DISPLAY_JOURNALS_TRUE_OPTION); return options; } private List<AssetOption> getBlockVolumesForHost(ViPRCoreClient client, URI tenant, URI host, boolean mounted) { return createVolumeOptions(client, null, host, BlockProviderUtils.getBlockVolumes(client, tenant, host, mounted)); } private List<AssetOption> getBlockVolumesForHost(ViPRCoreClient client, URI tenant, URI host, boolean mounted, ResourceFilter<BlockObjectRestRep> filter) { List<? extends BlockObjectRestRep> resources = BlockProviderUtils.getBlockVolumes(client, tenant, host, mounted); ResourceUtils.applyFilter((List<BlockObjectRestRep>) resources, filter); return createVolumeOptions(client, null, host, resources); } private List<AssetOption> getBlockVolumesForHostDatastore(ViPRCoreClient client, URI tenant, URI host, String datastore) { return createVolumeOptions(client, null, host, BlockProviderUtils.getBlockVolumesForDatastore(client, tenant, host, datastore)); } private List<AssetOption> getProjectBlockVolumesForHost(ViPRCoreClient client, URI project, URI host, boolean mounted) { return getProjectBlockVolumesForHost(client, project, host, mounted, null); } @SuppressWarnings("unchecked") private List<AssetOption> getProjectBlockVolumesForHost(ViPRCoreClient client, URI project, URI host, boolean mounted, ResourceFilter<BlockObjectRestRep> filter) { List<? extends BlockObjectRestRep> resources = getProjectBlockVolumes(client, host, project, mounted); ResourceUtils.applyFilter((List<BlockObjectRestRep>) resources, filter); return createVolumeOptions(client, project, host, resources); } private List<AssetOption> getBlockResourcesForHost(ViPRCoreClient client, URI tenant, URI host, boolean mounted) { return getBlockResourcesForHost(client, tenant, host, mounted, null); } private List<AssetOption> getProjectBlockResourcesForHost(ViPRCoreClient client, URI project, URI host, boolean mounted) { return getProjectBlockResourcesForHost(client, project, host, mounted, null); } @SuppressWarnings("unchecked") private List<AssetOption> getBlockResourcesForHost(ViPRCoreClient client, URI tenant, URI host, boolean mounted, ResourceFilter<BlockObjectRestRep> filter) { List<? extends BlockObjectRestRep> resources = BlockProviderUtils.getBlockResources(client, tenant, host, mounted); ResourceUtils.applyFilter((List<BlockObjectRestRep>) resources, filter); return createVolumeOptions(client, null, host, resources); } @SuppressWarnings("unchecked") private List<AssetOption> getProjectBlockResourcesForHost(ViPRCoreClient client, URI project, URI host, boolean mounted, ResourceFilter<BlockObjectRestRep> filter) { List<? extends BlockObjectRestRep> resources = getProjectBlockResources(client, host, project, mounted); ResourceUtils.applyFilter((List<BlockObjectRestRep>) resources, filter); return createVolumeOptions(client, project, host, resources); } @Asset("mountedBlockVolume") @AssetDependencies("host") public List<AssetOption> getMountedBlockVolumesForHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, true); } @Asset("mountedBlockVolume") @AssetDependencies({ "host", "project" }) public List<AssetOption> getMountedBlockVolumesForHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, true); } @Asset("mountedBlockVolume") @AssetDependencies("linuxHost") public List<AssetOption> getMountedBlockVolumesForLinuxHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockVolume") @AssetDependencies({ "linuxHost", "project" }) public List<AssetOption> getMountedBlockVolumesForLinuxHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockVolume") @AssetDependencies("hpuxHost") public List<AssetOption> getMountedBlockVolumesForHpuxHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockVolume") @AssetDependencies({ "hpuxHost", "project" }) public List<AssetOption> getMountedBlockVolumesForHpuxHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockVolume") @AssetDependencies("windowsHost") public List<AssetOption> getMountedBlockVolumesForWindowsHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockVolume") @AssetDependencies({ "windowsHost", "project" }) public List<AssetOption> getMountedBlockVolumesForWindowsHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("fileSystemType") public List<AssetOption> getWindowsFilesystemTypes(AssetOptionsContext context) { return WINDOWS_FILESYSTEM_TYPES; } @Asset("blockSize") public List<AssetOption> getAllWindowsBlockSize(AssetOptionsContext context) { return ALL_BLOCKSIZE_OPTIONS; } @Asset("blockSize") @AssetDependencies({ "fileSystemType" }) public List<AssetOption> getWindowsBlockSize(AssetOptionsContext context, String fileSystemType) { if ("ntfs".equals(fileSystemType)) { return NTFS_OPTIONS; } else { return FAT32_OPTIONS; } } @Asset("mountedBlockVolume") @AssetDependencies("esxHost") public List<AssetOption> getMountedBlockVolumesForEsxHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, true); } @Asset("mountedBlockVolumeDatastore") @AssetDependencies({ "esxHost", "blockdatastore" }) public List<AssetOption> getMountedBlockVolumesForEsxHostDatastore(AssetOptionsContext context, URI host, String datastore) { return getBlockVolumesForHostDatastore(api(context), context.getTenant(), host, datastore); } @Asset("mountedBlockVolume") @AssetDependencies({ "esxHost", "project" }) public List<AssetOption> getMountedBlockVolumesForEsxHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, true); } @Asset("unmountedBlockVolume") @AssetDependencies("host") public List<AssetOption> getUnmountedBlockVolumesForHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, false); } @Asset("unmountedBlockVolume") @AssetDependencies({ "host", "project" }) public List<AssetOption> getUnmountedBlockVolumesForHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, false); } @Asset("unmountedBlockVolume") @AssetDependencies("linuxHost") public List<AssetOption> getUnmountedBlockVolumesForLinuxHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockVolume") @AssetDependencies({ "linuxHost", "project" }) public List<AssetOption> getUnmountedBlockVolumesForLinuxHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockVolume") @AssetDependencies("windowsHost") public List<AssetOption> getUnmountedBlockVolumesForWindowsHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockVolume") @AssetDependencies({ "windowsHost", "project" }) public List<AssetOption> getUnmountedBlockVolumesForWindowsHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockVolume") @AssetDependencies("esxHost") public List<AssetOption> getUnmountedBlockVolumesForEsxHost(AssetOptionsContext context, URI host) { return getBlockVolumesForHost(api(context), context.getTenant(), host, false); } @Asset("unmountedBlockVolume") @AssetDependencies({ "esxHost", "project" }) public List<AssetOption> getUnmountedBlockVolumesForEsxHost(AssetOptionsContext context, URI host, URI project) { return getProjectBlockVolumesForHost(api(context), project, host, false, new BlockObjectMountPointFilter().not().and(new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not()))); } @Asset("mountedBlockResource") @AssetDependencies("host") public List<AssetOption> getMountedBlockResources(AssetOptionsContext context, URI host) { return getBlockResourcesForHost(api(context), context.getTenant(), host, true); } @Asset("mountedBlockResourceNoTargets") @AssetDependencies("host") public List<AssetOption> getMountedBlockResourcesNoTargets(AssetOptionsContext context, URI host) { return getBlockResourcesForHost(api(context), context.getTenant(), host, true, new BlockObjectSRDFTargetFilter().not()); } @Asset("unmountedBlockResourceNoTargets") @AssetDependencies({ "host" }) public List<AssetOption> getUnmountedBlockResourcesNoTargets(AssetOptionsContext context, URI host) { return getBlockResourcesForHost(api(context), context.getTenant(), host, false, new BlockObjectSRDFTargetFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockResource") @AssetDependencies({ "host" }) public List<AssetOption> getUnmountedBlockResources(AssetOptionsContext context, URI host) { return getBlockResourcesForHost(api(context), context.getTenant(), host, false); } @Asset("unmountedBlockResource") @AssetDependencies({ "host", "project" }) public List<AssetOption> getUnmountedBlockResources(AssetOptionsContext context, URI host, URI project) { return getProjectBlockResourcesForHost(api(context), project, host, false); } @Asset("mountedBlockResource") @AssetDependencies("linuxHost") public List<AssetOption> getLinuxMountedBlockResources(AssetOptionsContext context, URI linuxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), linuxHost, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResourceNoTargets") @AssetDependencies("linuxHost") public List<AssetOption> getLinuxMountedBlockResourcesNoTargets(AssetOptionsContext context, URI linuxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), linuxHost, true, new BlockObjectSRDFTargetFilter().not().and(new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not()))); } @Asset("unmountedBlockResource") @AssetDependencies({ "linuxHost" }) public List<AssetOption> getLinuxUnmountedBlockResources(AssetOptionsContext context, URI linuxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), linuxHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockResource") @AssetDependencies({ "linuxHost", "project" }) public List<AssetOption> getLinuxUnmountedBlockResources(AssetOptionsContext context, URI linuxHost, URI project) { return getProjectBlockResourcesForHost(api(context), project, linuxHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResourcePath") @AssetDependencies("linuxHost") public List<AssetOption> getLinuxMountedBlockResourcePaths(AssetOptionsContext context, URI linuxHost) { List<? extends BlockObjectRestRep> volumes = BlockProviderUtils.getBlockResources(api(context), context.getTenant(), linuxHost, true); return createStringOptions(getTagValues(KnownMachineTags.getHostMountPointTagName(linuxHost), volumes)); } @Asset("unmountedBlockResource") @AssetDependencies({ "aixHost" }) public List<AssetOption> getAixUnmountedBlockResources(AssetOptionsContext context, URI aixHost) { return getBlockResourcesForHost(api(context), context.getTenant(), aixHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockResource") @AssetDependencies({ "aixHost", "project" }) public List<AssetOption> getAixUnmountedBlockResources(AssetOptionsContext context, URI aixHost, URI project) { return getProjectBlockResourcesForHost(api(context), project, aixHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResource") @AssetDependencies("aixHost") public List<AssetOption> getAixMountedBlockResources(AssetOptionsContext context, URI aixHost) { return getBlockResourcesForHost(api(context), context.getTenant(), aixHost, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResourceNoTargets") @AssetDependencies("aixHost") public List<AssetOption> getAixMountedBlockResourcesNoTargets(AssetOptionsContext context, URI aixHost) { return getBlockResourcesForHost(api(context), context.getTenant(), aixHost, true, new BlockObjectSRDFTargetFilter().not().and(new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not()))); } @Asset("unmountedBlockResource") @AssetDependencies({ "hpuxHost" }) public List<AssetOption> getHpuxUnmountedBlockResources(AssetOptionsContext context, URI hpuxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), hpuxHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockResource") @AssetDependencies({ "hpuxHost", "project" }) public List<AssetOption> getHpuxUnmountedBlockResources(AssetOptionsContext context, URI hpuxHost, URI project) { return getProjectBlockResourcesForHost(api(context), project, hpuxHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResource") @AssetDependencies("hpuxHost") public List<AssetOption> getHpuxMountedBlockResources(AssetOptionsContext context, URI hpuxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), hpuxHost, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResourceNoTargets") @AssetDependencies("hpuxHost") public List<AssetOption> getHpuxMountedBlockResourcesNoTargets(AssetOptionsContext context, URI hpuxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), hpuxHost, true, new BlockObjectSRDFTargetFilter().not().and(new BlockObjectVMFSDatastoreFilter().not())); } @Asset("mountedBlockResource") @AssetDependencies("windowsHost") public List<AssetOption> getWindowsMountedBlockResources(AssetOptionsContext context, URI windowsHost) { return getBlockResourcesForHost(api(context), context.getTenant(), windowsHost, true, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResourceNoTargets") @AssetDependencies("windowsHost") public List<AssetOption> getWindowsMountedBlockResourcesNoTargets(AssetOptionsContext context, URI windowsHost) { return getBlockResourcesForHost(api(context), context.getTenant(), windowsHost, true, new BlockObjectSRDFTargetFilter().not().and(new BlockObjectVMFSDatastoreFilter().not()).and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockResource") @AssetDependencies({ "windowsHost" }) public List<AssetOption> getWindowsUnmountedBlockResources(AssetOptionsContext context, URI windowsHost) { return getBlockResourcesForHost(api(context), context.getTenant(), windowsHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("unmountedBlockResource") @AssetDependencies({ "windowsHost", "project" }) public List<AssetOption> getWindowsUnmountedBlockResources(AssetOptionsContext context, URI windowsHost, URI project) { return getProjectBlockResourcesForHost(api(context), project, windowsHost, false, new BlockObjectVMFSDatastoreFilter().not().and(new BlockObjectBootVolumeFilter().not())); } @Asset("mountedBlockResource") @AssetDependencies({ "esxHost" }) public List<AssetOption> getESXMountedBlockResources(AssetOptionsContext context, URI esxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), esxHost, true); } @Asset("unmountedBlockResource") @AssetDependencies({ "esxHost" }) public List<AssetOption> getESXUnmountedBlockResources(AssetOptionsContext context, URI esxHost) { return getBlockResourcesForHost(api(context), context.getTenant(), esxHost, false); } @Asset("unmountedBlockResource") @AssetDependencies({ "esxHost", "project" }) public List<AssetOption> getESXUnmountedBlockResources(AssetOptionsContext context, URI esxHost, URI project) { return getProjectBlockResourcesForHost(api(context), project, esxHost, false); } @Asset("snapshotBlockVolume") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getSnapshotBlockVolumes(AssetOptionsContext context, URI project, String storageType) { final ViPRCoreClient client = api(context); if (isVolumeType(storageType)) { List<VolumeRestRep> volumes = listVolumes(client, project); List<VolumeDetail> volumeDetails = getVolumeDetails(client, volumes); Map<URI, VolumeRestRep> volumeNames = ResourceUtils.mapById(volumes); List<AssetOption> options = Lists.newArrayList(); for (VolumeDetail detail : volumeDetails) { if (detail.vpool == null ) { continue; } boolean localSnapSupported = isLocalSnapshotSupported(detail.vpool); boolean isRPTargetVolume = isRPTargetVolume(detail.volume); boolean isRPSourceVolume = isRPSourceVolume(detail.volume); boolean isInConsistencyGroup = BlockProvider.isInConsistencyGroup(detail.volume); debug("filter[ localSnapSupported=%s, isRPTargetVolume=%s, isRPSourceVolume=%s, isInConsistencyGroup=%s]", localSnapSupported, isRPTargetVolume, isRPSourceVolume, isInConsistencyGroup); if (isRPSourceVolume || (localSnapSupported && (!isInConsistencyGroup || isRPTargetVolume ))) { options.add(createVolumeOption(client, null, detail.volume, volumeNames)); } } return options; } else { List<BlockConsistencyGroupRestRep> consistencyGroups = client.blockConsistencyGroups().search().byProject(project).run(); return createBaseResourceOptions(consistencyGroups); } } @Asset("mobilityGroupMethod") public List<AssetOption> getMobilityGroupMethods(AssetOptionsContext context) { return Lists.newArrayList(MIGRATE_ONLY_OPTION, INGEST_AND_MIGRATE_OPTION); } @Asset("snapshotSessionBlockVolume") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getSnapshotSessionBlockVolumes(AssetOptionsContext context, URI project, String storageType) { final ViPRCoreClient client = api(context); if (isVolumeType(storageType)) { List<VolumeRestRep> volumes = listVolumes(client, project); List<VolumeDetail> volumeDetails = getVolumeDetails(client, volumes); Map<URI, VolumeRestRep> volumeNames = ResourceUtils.mapById(volumes); List<AssetOption> options = Lists.newArrayList(); for (VolumeDetail detail : volumeDetails) { boolean localSnapSupported = isLocalSnapshotSupported(detail.vpool); boolean isRPTargetVolume = isRPTargetVolume(detail.volume); boolean isRPSourceVolume = isRPSourceVolume(detail.volume); boolean isInConsistencyGroup = !StringUtils.isEmpty(detail.volume.getReplicationGroupInstance()); boolean isSnapshotSessionSupported = isSnapshotSessionSupportedForVolume(detail.volume); debug("filter[ localSnapSupported=%s, isRPTargetVolume=%s, isRPSourceVolume=%s, isInConsistencyGroup=%s, isXio3XVolume=%s ]", localSnapSupported, isRPTargetVolume, isRPSourceVolume, isInConsistencyGroup, isSnapshotSessionSupported); if (isSnapshotSessionSupported && localSnapSupported && !isInConsistencyGroup) { options.add(createVolumeOption(client, null, detail.volume, volumeNames)); } } return options; } else { List<BlockConsistencyGroupRestRep> consistencyGroups = client.blockConsistencyGroups().search().byProject(project).run(); return createBaseResourceOptions(consistencyGroups); } } @Asset("snapshotSessionsByVolume") @AssetDependencies({ "project", "blockVolumeOrConsistencyType", "snapshotSessionBlockVolume" }) public List<AssetOption> getSnapshotSessionsByVolume(AssetOptionsContext ctx, URI projectId, String type, URI volumeOrCGId) { if (isVolumeType(type) && BlockProviderUtils.isType(volumeOrCGId, VOLUME_TYPE)) { List<BlockSnapshotSessionRestRep> snapshotSessions = api(ctx).blockSnapshotSessions().getByVolume(volumeOrCGId); return constructSnapshotSessionOptions(api(ctx), projectId, snapshotSessions); } else if (isConsistencyGroupType(type) && BlockProviderUtils.isType(volumeOrCGId, BLOCK_CONSISTENCY_GROUP_TYPE)) { return getConsistencyGroupSnapshotSessions(ctx, volumeOrCGId); } else { return new ArrayList<AssetOption>(); } } @Asset("blockVolumeWithSnapshot") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getBlockVolumesWithSnapshot(AssetOptionsContext context, URI project, String volumeOrConsistencyType) { final ViPRCoreClient client = api(context); if (isVolumeType(volumeOrConsistencyType)) { Set<URI> volIdSet = new HashSet<>(); List<BlockSnapshotRestRep> snapshots = findSnapshotsByProject(client, project); for (BlockSnapshotRestRep snapshot : snapshots) { volIdSet.add(snapshot.getParent().getId()); } // Have to get volumes just as it needs vol's mount point which snapshot doesn't have. List<VolumeRestRep> volumes = getVolumesByIds(client, volIdSet); List<VolumeRestRep> filteredVols = new ArrayList<>(); for (VolumeRestRep vol: volumes) { if (StringUtils.isEmpty(vol.getReplicationGroupInstance())) { filteredVols.add(vol); } } return createVolumeOptions(client, filteredVols); } else { List<BlockConsistencyGroupRestRep> consistencyGroups = client.blockConsistencyGroups() .search() .byProject(project) .run(); return createBaseResourceOptions(consistencyGroups); } } @Asset("localSnapshotBlockVolume") @AssetDependencies({ "project" }) public List<AssetOption> getLocalSnapshotBlockVolumes(AssetOptionsContext context, URI project) { final ViPRCoreClient client = api(context); List<VolumeRestRep> volumes = listVolumes(client, project); List<VolumeDetail> volumeDetails = getVolumeDetails(client, volumes); Map<URI, VolumeRestRep> volumeNames = ResourceUtils.mapById(volumes); List<AssetOption> options = Lists.newArrayList(); for (VolumeDetail detail : volumeDetails) { if (isLocalSnapshotSupported(detail.vpool)) { options.add(createVolumeOption(client, null, detail.volume, volumeNames)); } } return options; } @Asset("remoteSnapshotBlockVolume") @AssetDependencies({ "project" }) public List<AssetOption> getRemoteSnapshotBlockVolumes(AssetOptionsContext context, URI project) { final ViPRCoreClient client = api(context); List<VolumeRestRep> volumes = listVolumes(client, project); List<VolumeDetail> volumeDetails = getVolumeDetails(client, volumes); Map<URI, VolumeRestRep> volumeNames = ResourceUtils.mapById(volumes); List<AssetOption> options = Lists.newArrayList(); for (VolumeDetail detail : volumeDetails) { if (isRemoteSnapshotSupported(detail.volume)) { options.add(createVolumeOption(client, null, detail.volume, volumeNames)); } } return options; } @Asset("localMirrorBlockVolume") @AssetDependencies({ "project" }) public List<AssetOption> getLocalMirrorBlockVolumes(AssetOptionsContext context, URI project) { final ViPRCoreClient client = api(context); List<VolumeRestRep> volumes = listVolumes(client, project); List<VolumeDetail> volumeDetails = getVolumeDetails(client, volumes); Map<URI, VolumeRestRep> volumeNames = getProjectVolumeNames(client, project); List<AssetOption> options = Lists.newArrayList(); for (VolumeDetail detail : volumeDetails) { if (isLocalMirrorSupported(detail.vpool)) { options.add(createVolumeOption(client, null, detail.volume, volumeNames)); } } return options; } @Asset("volumeWithContinuousCopies") @AssetDependencies("project") public List<AssetOption> getVolumesWithContinuousCopies(AssetOptionsContext ctx, URI project) { final ViPRCoreClient client = api(ctx); List<VolumeRestRep> volumes = client.blockVolumes().findByProject(project, new SourceTargetVolumesFilter() { @Override public boolean accept(VolumeRestRep volume) { if (volume.getProtection() == null) { return false; } MirrorRestRep mirrors = volume.getProtection().getMirrorRep(); if (mirrors == null || mirrors.getMirrors() == null || mirrors.getMirrors().isEmpty()) { return false; } return true; } }); return createVolumeOptions(client, volumes); } @Asset("continuousCopies") @AssetDependencies("volumeWithContinuousCopies") public List<AssetOption> getContinuousCopies(AssetOptionsContext ctx, URI volume) { return createVolumeOptions(api(ctx), api(ctx).blockVolumes().getContinuousCopies(volume)); } @Asset("blockJournalSize") @AssetDependencies("rpConsistencyGroupByProject") public List<AssetOption> getBlockJournalSize(AssetOptionsContext ctx, URI consistencyGroup) { String minimumSize = null; BlockConsistencyGroupRestRep cg = api(ctx).blockConsistencyGroups().get(consistencyGroup); for (RelatedResourceRep vol : cg.getVolumes()) { VolumeRestRep volume = api(ctx).blockVolumes().get(vol); if (volume.getProtection() != null && volume.getProtection().getRpRep() != null && volume.getProtection().getRpRep().getProtectionSet() != null) { RelatedResourceRep protectionSetId = volume.getProtection().getRpRep().getProtectionSet(); ProtectionSetRestRep protectionSet = api(ctx).blockVolumes().getProtectionSet(volume.getId(), protectionSetId.getId()); for (RelatedResourceRep protectionVolume : protectionSet.getVolumes()) { VolumeRestRep vol1 = api(ctx).blockVolumes().get(protectionVolume); if (vol1.getProtection().getRpRep().getPersonality().equalsIgnoreCase("METADATA")) { String capacity = api(ctx).blockVolumes().get(protectionVolume).getCapacity(); if (minimumSize == null || Float.parseFloat(capacity) < Float.parseFloat(minimumSize)) { minimumSize = capacity; } } } } } if (minimumSize == null) { return Lists.newArrayList(); } else { return Lists.newArrayList(newAssetOption(minimumSize, minimumSize)); } } @Asset("volumeWithoutConsistencyGroup") @AssetDependencies("project") public List<AssetOption> getVolumesWithoutConsistencyGroup(AssetOptionsContext ctx, URI project) { debug("getting volumes that don't belong to a consistency group (project=%s)", project); ViPRCoreClient client = api(ctx); List<VolumeRestRep> volumes = client.blockVolumes().findByProject(project); Map<URI, VolumeRestRep> volumeNames = getProjectVolumeNames(client, project); List<AssetOption> options = Lists.newArrayList(); for (VolumeRestRep volume : volumes) { if (volume.getConsistencyGroup() == null) { options.add(createVolumeOption(client, null, volume, volumeNames)); } } return options; } @Asset("volumeWithFullCopies") @AssetDependencies({ "project", "blockVolumeOrConsistencyType" }) public List<AssetOption> getVolumesWithFullCopies(AssetOptionsContext ctx, URI project, String volumeOrConsistencyType) { final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { List<VolumeRestRep> volumes = findVolumesByProject(client, project); List<VolumeRestRep> filteredVols = new ArrayList<>(); for (VolumeRestRep vol: volumes) { if ( vol.getProtection() == null || vol.getProtection().getFullCopyRep() == null || vol.getProtection().getFullCopyRep().getFullCopyVolumes() == null || vol.getProtection().getFullCopyRep().getFullCopyVolumes().isEmpty() || ! StringUtils.isEmpty(vol.getReplicationGroupInstance())) { continue; } filteredVols.add(vol); } log.info("Got volumes with full copies: [{}]", filteredVols.size()); return createVolumeOptions(client, filteredVols); } else { List<BlockConsistencyGroupRestRep> consistencyGroups = api(ctx).blockConsistencyGroups() .search() .byProject(project) .run(); return createBaseResourceOptions(consistencyGroups); } } /** * Find all volumes by a project * @param client * @param project * @return a list of volume REST representations. */ private List<VolumeRestRep> findVolumesByProject(ViPRCoreClient client, URI project) { log.info("Finding volumes by project {}", project); List<SearchResultResourceRep> volRefs = client.blockVolumes().performSearchBy(SearchConstants.PROJECT_PARAM, project); List<URI> ids = new ArrayList<>(); for (SearchResultResourceRep volRef: volRefs) { ids.add(volRef.getId()); } List<VolumeRestRep> volumes = client.blockVolumes().getByIds(ids, null); log.info("Got volumes: [{}]", volumes.size()); return volumes; } @Asset("fullCopy") @AssetDependencies({ "volumeWithFullCopies", "blockVolumeOrConsistencyType" }) public List<AssetOption> getFullCopies(AssetOptionsContext ctx, URI volumeId, String volumeOrConsistencyType) { final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { if (!BlockProviderUtils.isType(volumeId, VOLUME_TYPE)) { warn("Inconsistent types, %s and %s, return empty results", volumeId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } return createVolumeOptions(client, client.blockVolumes().getFullCopies(volumeId)); } else { if (!BlockProviderUtils.isType(volumeId, BLOCK_CONSISTENCY_GROUP_TYPE)) { warn("Inconsistent types, %s and %s, return empty results", volumeId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } return getConsistencyGroupFullCopies(ctx, volumeId); } } @Asset("fullCopyAvailableForDetach") @AssetDependencies({ "volumeWithFullCopies", "blockVolumeOrConsistencyType" }) public List<AssetOption> getFullCopiedDetach(AssetOptionsContext ctx, URI volumeId, String volumeOrConsistencyType) { if (!checkTypeConsistency(volumeId, volumeOrConsistencyType)) { warn("Inconsistent types, %s and %s, return empty results", volumeId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { List<VolumeRestRep> volumes = client.blockVolumes().getFullCopies(volumeId, new DefaultResourceFilter<VolumeRestRep>() { @Override public boolean accept(VolumeRestRep volume) { String replicaState = volume.getProtection().getFullCopyRep().getReplicaState(); return replicaState != null && !(replicaState.equals(ReplicationState.DETACHED.name())); } }); return createVolumeOptions(client, volumes); } else { return getConsistencyGroupFullCopies(ctx, volumeId); } } private List<AssetOption> getConsistencyGroupFullCopies(AssetOptionsContext ctx, URI consistencyGroupId) { return createNamedResourceOptions(api(ctx).blockConsistencyGroups().getFullCopies(consistencyGroupId)); } private List<AssetOption> getConsistencyGroupSnapshots(AssetOptionsContext ctx, URI consistencyGroupId) { return createNamedResourceOptions(api(ctx).blockConsistencyGroups().getSnapshots(consistencyGroupId)); } private List<AssetOption> getConsistencyGroupSnapshotSessions(AssetOptionsContext ctx, URI consistencyGroupId) { return createNamedResourceOptions(api(ctx).blockConsistencyGroups().getSnapshotSessions(consistencyGroupId)); } @Asset("fullCopyAvailableForResynchronize") @AssetDependencies({ "volumeWithFullCopies", "blockVolumeOrConsistencyType" }) public List<AssetOption> getFullCopiedSynchronize(AssetOptionsContext ctx, URI volumeId, String volumeOrConsistencyType) { if (!checkTypeConsistency(volumeId, volumeOrConsistencyType)) { warn("Inconsistent types, %s and %s, return empty results", volumeId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { List<VolumeRestRep> volumes = client.blockVolumes().getFullCopies(volumeId, new DefaultResourceFilter<VolumeRestRep>() { @Override public boolean accept(VolumeRestRep volume) { String replicaState = volume.getProtection().getFullCopyRep().getReplicaState(); return replicaState != null && !(replicaState.equals(ReplicationState.DETACHED.name())) && !(replicaState.equals(ReplicationState.INACTIVE.name())); } }); return createVolumeOptions(client, volumes); } else { return getConsistencyGroupFullCopies(ctx, volumeId); } } @Asset("fullCopyAvailableForRestore") @AssetDependencies({ "volumeWithFullCopies", "blockVolumeOrConsistencyType" }) public List<AssetOption> getFullCopiedRestore(AssetOptionsContext ctx, URI volumeId, String volumeOrConsistencyType) { if (!checkTypeConsistency(volumeId, volumeOrConsistencyType)) { warn("Inconsistent types, %s and %s, return empty results", volumeId, volumeOrConsistencyType); return new ArrayList<AssetOption>(); } final ViPRCoreClient client = api(ctx); if (isVolumeType(volumeOrConsistencyType)) { List<VolumeRestRep> volumes = client.blockVolumes().getFullCopies(volumeId, new DefaultResourceFilter<VolumeRestRep>() { @Override public boolean accept(VolumeRestRep volume) { String replicaState = volume.getProtection().getFullCopyRep().getReplicaState(); return replicaState != null && !(replicaState.equals(ReplicationState.RESTORED.name())) && !(replicaState.equals(ReplicationState.INACTIVE.name())) && !(replicaState.equals(ReplicationState.DETACHED.name())); } }); return createVolumeOptions(client, volumes); } else { return getConsistencyGroupFullCopies(ctx, volumeId); } } @Asset("mobilityGroup") public List<AssetOption> getMobilityGroups(AssetOptionsContext ctx) { final ViPRCoreClient client = api(ctx); List<VolumeGroupRestRep> volumeGroups = client.application().getApplications(new DefaultResourceFilter<VolumeGroupRestRep>() { @Override public boolean accept(VolumeGroupRestRep volumeGroup) { if (volumeGroup.getRoles() != null && volumeGroup.getRoles().contains(VolumeGroup.VolumeGroupRole.MOBILITY.name())) { return true; } else { return false; } } }); return createBaseResourceOptions(volumeGroups); } @Asset("addMobilityGroupResource") @AssetDependencies("mobilityGroup") public List<AssetOption> getAddMobilityGroupResources(AssetOptionsContext ctx, final URI mobilityGroupId) { final ViPRCoreClient client = api(ctx); VolumeGroupRestRep mobilityGroup = client.application().get(mobilityGroupId); if (mobilityGroup.getMigrationGroupBy().equals(VolumeGroup.MigrationGroupBy.VOLUMES.name())) { // VPLEX volumes that don't have reference to this mobility group List<URI> volumeIds = client.blockVolumes().listBulkIds(); final ResourceFilter<VolumeRestRep> vplexFilter = new VplexVolumeFilter(); List<VolumeRestRep> volumes = client.blockVolumes().getByIds(volumeIds, new ResourceFilter<VolumeRestRep>() { @Override public boolean acceptId(URI id) { return true; } @Override public boolean accept(VolumeRestRep item) { boolean accept = (item.getVolumeGroups() == null || !contains(item, mobilityGroupId)) && vplexFilter.accept(item); if (accept) { boolean rpProtection = (item.getProtection() != null && item.getProtection().getRpRep() != null && item.getProtection().getRpRep().getPersonality() != null); if (rpProtection) { // If RP+VPLEX protection specified, only allow RP SOURCE volumes to be listed // as candidates for mobility groups. Exclude TARGETs and JOURNALs. String personality = item.getProtection().getRpRep().getPersonality(); if (Volume.PersonalityTypes.TARGET.name().equals(personality) || Volume.PersonalityTypes.METADATA.name().equals(personality)) { accept = false; } } } return accept; } private boolean contains(VolumeRestRep item, URI mobilityGroup) { for (RelatedResourceRep vg : item.getVolumeGroups()) { if (vg.getId().equals(mobilityGroup)) { return true; } } return false; } }); return createBaseResourceOptions(volumes); } else if (mobilityGroup.getMigrationGroupBy().equals(VolumeGroup.MigrationGroupBy.HOSTS.name())) { List<URI> hostIds = client.hosts().listBulkIds(); List<HostRestRep> hosts = client.hosts().getByIds(hostIds, new ResourceFilter<HostRestRep>() { @Override public boolean acceptId(URI id) { return true; } @Override public boolean accept(HostRestRep item) { return item.getVolumeGroups() == null || !contains(item, mobilityGroupId); } private boolean contains(HostRestRep item, URI mobilityGroup) { for (RelatedResourceRep vg : item.getVolumeGroups()) { if (vg.getId().equals(mobilityGroup)) { return true; } } return false; } }); return createBaseResourceOptions(hosts); } else if (mobilityGroup.getMigrationGroupBy().equals(VolumeGroup.MigrationGroupBy.CLUSTERS.name())) { List<URI> clusterIds = client.clusters().listBulkIds(); List<ClusterRestRep> clusters = client.clusters().getByIds(clusterIds, new ResourceFilter<ClusterRestRep>() { @Override public boolean acceptId(URI id) { return true; } @Override public boolean accept(ClusterRestRep item) { return item.getVolumeGroups() == null || !contains(item, mobilityGroupId); } private boolean contains(ClusterRestRep item, URI mobilityGroup) { for (RelatedResourceRep vg : item.getVolumeGroups()) { if (vg.getId().equals(mobilityGroup)) { return true; } } return false; } }); return createBaseResourceOptions(clusters); } else { return Lists.newArrayList(); } } @Asset("removeMobilityGroupResource") @AssetDependencies("mobilityGroup") public List<AssetOption> getRemoveMobilityGroupResources(AssetOptionsContext ctx, URI mobilityGroupId) { final ViPRCoreClient client = api(ctx); VolumeGroupRestRep mobilityGroup = client.application().get(mobilityGroupId); if (mobilityGroup.getMigrationGroupBy().equals(VolumeGroup.MigrationGroupBy.VOLUMES.name())) { return createNamedResourceOptions(client.application().listVolumes(mobilityGroupId)); } else if (mobilityGroup.getMigrationGroupBy().equals(VolumeGroup.MigrationGroupBy.HOSTS.name())) { return createNamedResourceOptions(client.application().getHosts(mobilityGroupId)); } else if (mobilityGroup.getMigrationGroupBy().equals(VolumeGroup.MigrationGroupBy.CLUSTERS.name())) { return createNamedResourceOptions(client.application().getClusters(mobilityGroupId)); } else { return Lists.newArrayList(); } } @Asset("application") public List<AssetOption> getApplications(AssetOptionsContext ctx) { final ViPRCoreClient client = api(ctx); List<VolumeGroupRestRep> volumeGroups = client.application().getApplications(new DefaultResourceFilter<VolumeGroupRestRep>() { @Override public boolean accept(VolumeGroupRestRep volumeGroup) { if (volumeGroup.getRoles() != null && volumeGroup.getRoles().contains(VolumeGroup.VolumeGroupRole.COPY.name())) { return true; } else { return false; } } }); return createBaseResourceOptions(volumeGroups); } @Asset("applicationBlockVolume") @AssetDependencies("application") public List<AssetOption> getApplicationVolumes(AssetOptionsContext ctx, URI application) { final ViPRCoreClient client = api(ctx); List<NamedRelatedResourceRep> volList = client.application().listVolumes(application); List<AssetOption> options = new ArrayList<AssetOption>(); if (volList != null && !volList.isEmpty()) { List<VolumeRestRep> allVols = client.blockVolumes().getByRefs(volList); Map<String, List<VolumeRestRep>> repGrpVolMap = new HashMap<String, List<VolumeRestRep>>(); for (VolumeRestRep vol : allVols) { if (!BlockProviderUtils.isRPTargetReplicationGroup(vol.getReplicationGroupInstance())) { if (repGrpVolMap.get(vol.getReplicationGroupInstance()) == null) { repGrpVolMap.put(vol.getReplicationGroupInstance(), new ArrayList<VolumeRestRep>()); } repGrpVolMap.get(vol.getReplicationGroupInstance()).add(vol); } } for (Entry<String, List<VolumeRestRep>> entry : repGrpVolMap.entrySet()) { for (VolumeRestRep vol : entry.getValue()) { options.add(new AssetOption(vol.getId(), getMessage("application.volumes.replication_group", vol.getName(), vol.getReplicationGroupInstance()))); } } } return options; } @Asset("replicationGroup") @AssetDependencies("application") public List<AssetOption> getApplicationReplicationGroups(AssetOptionsContext ctx, URI applicationId) { return createStringOptions(BlockProviderUtils.getApplicationReplicationGroupNames(api(ctx), applicationId)); } @Asset("copyReplicationGroup") @AssetDependencies({ "application", "restoreFullCopyName" }) public List<AssetOption> getApplicationReplicationGroupsForCopy(AssetOptionsContext ctx, URI applicationId, String copyName) { final ViPRCoreClient client = api(ctx); List<VolumeRestRep> allCopyVols = client.blockVolumes() .getByRefs(client.application().getFullCopiesByApplication(applicationId).getVolumes()); return createStringOptions(BlockStorageUtils.stripRPTargetFromReplicationGroup( groupFullCopyByApplicationSubGroup(ctx, filterByCopyName(allCopyVols, copyName)).keySet())); } @Asset("copyReplicationGroup") @AssetDependencies({ "application", "fullCopyName" }) public List<AssetOption> getApplicationReplicationGroupsForFullCopyName(AssetOptionsContext ctx, URI applicationId, String copyName) { return getApplicationReplicationGroupsForCopy(ctx, applicationId, copyName); } private Map<String, List<VolumeRestRep>> groupFullCopyByApplicationSubGroup(AssetOptionsContext ctx, List<VolumeRestRep> vols) { final ViPRCoreClient client = api(ctx); Map<String, List<VolumeRestRep>> grouped = new HashMap<String, List<VolumeRestRep>>(); Set<RelatedResourceRep> parentVolIds = new HashSet<RelatedResourceRep>(); for (VolumeRestRep vol : vols) { if (vol != null && vol.getProtection() != null && vol.getProtection().getFullCopyRep() != null && vol.getProtection().getFullCopyRep().getAssociatedSourceVolume() != null) { parentVolIds.add(vol.getProtection().getFullCopyRep().getAssociatedSourceVolume()); } } List<VolumeRestRep> parentVolumes = client.blockVolumes().getByRefs(parentVolIds); if (parentVolumes != null && !parentVolumes.isEmpty()) { for (VolumeRestRep vol : parentVolumes) { if (grouped.get(vol.getReplicationGroupInstance()) == null) { grouped.put(vol.getReplicationGroupInstance(), new ArrayList<VolumeRestRep>()); } grouped.get(vol.getReplicationGroupInstance()).add(vol); } } return grouped; } private List<VolumeRestRep> filterByCopyName(List<VolumeRestRep> allCopyVols, String copyName) { List<VolumeRestRep> filtered = new ArrayList<VolumeRestRep>(); if (allCopyVols != null) { for (VolumeRestRep vol : allCopyVols) { if (vol != null && vol.getProtection() != null && vol.getProtection().getFullCopyRep() != null && copyName.equals(vol.getProtection().getFullCopyRep().getFullCopySetName())) { filtered.add(vol); } } } return filtered; } @Asset("fullCopyName") @AssetDependencies("application") public List<AssetOption> getApplicationFullCopyNames(AssetOptionsContext ctx, URI applicationId) { List<VolumeRestRep> fullCopies = getFullCopiesForApplication(ctx, applicationId); Set<String> fullCopyNames = new HashSet<String>(); for (VolumeRestRep vol : fullCopies) { if (vol != null && vol.getProtection() != null && vol.getProtection().getFullCopyRep() != null && vol.getProtection().getFullCopyRep().getFullCopySetName() != null) { fullCopyNames.add(vol.getProtection().getFullCopyRep().getFullCopySetName()); } } return createStringOptions(fullCopyNames); } /** * returns the list of application full copies that can be restored from. For RP, we exclude target copies because the target is read * only * * @param ctx * @param applicationId * @return */ @Asset("restoreFullCopyName") @AssetDependencies("application") public List<AssetOption> getApplicationFullCopyNamesForRestore(AssetOptionsContext ctx, URI applicationId) { List<VolumeRestRep> fullCopies = getFullCopiesForApplication(ctx, applicationId); Set<String> fullCopyNames = new HashSet<String>(); for (VolumeRestRep vol : fullCopies) { if (vol != null && vol.getProtection() != null && vol.getProtection().getFullCopyRep() != null && vol.getProtection().getFullCopyRep().getFullCopySetName() != null && !fullCopyNames.contains(vol.getProtection().getFullCopyRep().getFullCopySetName())) { if (!isFullCopyOfRPTarget(ctx, vol)) { fullCopyNames.add(vol.getProtection().getFullCopyRep().getFullCopySetName()); } } } return createStringOptions(fullCopyNames); } /** * returns true if the passed in volume is a clone of an RP source volume * * @param vol * @return */ private boolean isFullCopyOfRPTarget(AssetOptionsContext ctx, VolumeRestRep vol) { final ViPRCoreClient client = api(ctx); // get the source volume for the full copy if (vol != null && vol.getProtection() != null && vol.getProtection().getFullCopyRep() != null && vol.getProtection().getFullCopyRep().getAssociatedSourceVolume() != null) { if (BlockStorageUtils.isRPTargetVolume(client.blockVolumes().get(vol.getProtection().getFullCopyRep().getAssociatedSourceVolume()))) { return true; } } return false; } @Asset("siteFullCopyName") @AssetDependencies({ "application", "applicationVirtualArray" }) public List<AssetOption> getApplicationFullCopyNamesForSite(AssetOptionsContext ctx, URI applicationId, URI applicationVirtualArray) { List<VolumeRestRep> fullCopies = getFullCopiesForApplication(ctx, applicationId); Set<String> fullCopyNames = new HashSet<String>(); for (VolumeRestRep vol : fullCopies) { if (vol != null && vol.getProtection() != null && vol.getProtection().getFullCopyRep() != null && vol.getProtection().getFullCopyRep().getFullCopySetName() != null && (applicationVirtualArray == null || vol.getVirtualArray().getId().equals(applicationVirtualArray))) { fullCopyNames.add(vol.getProtection().getFullCopyRep().getFullCopySetName()); } } return createStringOptions(fullCopyNames); } private List<VolumeRestRep> getFullCopiesForApplication(AssetOptionsContext ctx, URI applicationId) { List<VolumeRestRep> fullCopies = new ArrayList<VolumeRestRep>(); final ViPRCoreClient client = api(ctx); NamedVolumesList volList = client.application().getFullCopiesByApplication(applicationId); if (volList != null && volList.getVolumes() != null && !volList.getVolumes().isEmpty()) { List<URI> ids = new ArrayList<URI>(); for (NamedRelatedResourceRep volId : volList.getVolumes()) { ids.add(volId.getId()); } fullCopies.addAll(client.blockVolumes().getByIds(ids)); } return fullCopies; } @Asset("applicationSnapshotVirtualArray") @AssetDependencies("application") public List<AssetOption> getApplicationSnapshotVirtualArrays(AssetOptionsContext ctx, URI applicationId) { final ViPRCoreClient client = api(ctx); List<NamedRelatedResourceRep> volList = client.application().listVolumes(applicationId); List<AssetOption> options = new ArrayList<AssetOption>(); boolean isVplex = false; boolean isRP = false; URI sourceVarrayId = null; List<VolumeRestRep> allRPSourceVols = null; if (volList != null && !volList.isEmpty()) { VolumeRestRep vol = client.blockVolumes().get(volList.get(0)); StorageSystemRestRep sys = client.storageSystems().get(vol.getStorageController()); if (sys.getSystemType().equals("vplex")) { isVplex = true; sourceVarrayId = vol.getVirtualArray().getId(); } if (BlockProviderUtils.isVolumeRP(vol)) { isRP = true; allRPSourceVols = client.blockVolumes().getByRefs(volList, RecoverPointPersonalityFilter.SOURCE); if (allRPSourceVols != null && !allRPSourceVols.isEmpty()) { VolumeRestRep rpvol = allRPSourceVols.get(0); sourceVarrayId = rpvol.getVirtualArray().getId(); } } } else { return options; } // if it's neither RP nor vplex, it's just a simple block volume application; site is not needed if (!isVplex && !isRP) { options.add(newAssetOption(URI.create("none"), "None")); } // if the volumes are vplex or RP display source as an option if (isVplex || isRP) { options.add(newAssetOption(sourceVarrayId, "protection.site.type.source")); } // if the volumes are RP (vplex or not) add the RP targets as options if (isRP) { Set<URI> targetVarrayIds = new HashSet<URI>(); List<AssetOption> targetOptions = new ArrayList<AssetOption>(); List<VolumeRestRep> allRPTargetVols = client.blockVolumes().getByRefs(volList, RecoverPointPersonalityFilter.TARGET); for (VolumeRestRep targetVol : allRPTargetVols) { targetVarrayIds.add(targetVol.getVirtualArray().getId()); } List<VirtualArrayRestRep> targetVarrays = client.varrays().getByIds(targetVarrayIds); for (VirtualArrayRestRep targetVarray : targetVarrays) { targetOptions.add(newAssetOption(String.format("tgt:%s", targetVarray.getId().toString()), "protection.site.type.target", targetVarray.getName())); } // sort the targets AssetOptionsUtils.sortOptionsByLabel(targetOptions); options.addAll(targetOptions); } return options; } @Asset("applicationVirtualArray") @AssetDependencies("application") public List<AssetOption> getApplicationVirtualArrays(AssetOptionsContext ctx, URI applicationId) { final ViPRCoreClient client = api(ctx); List<NamedRelatedResourceRep> volList = client.application().listVolumes(applicationId); List<AssetOption> options = new ArrayList<AssetOption>(); boolean isRP = false; URI sourceVarrayId = null; List<VolumeRestRep> allRPSourceVols = null; if (volList != null && !volList.isEmpty()) { VolumeRestRep vol = client.blockVolumes().get(volList.get(0)); if (BlockProviderUtils.isVolumeRP(vol)) { isRP = true; allRPSourceVols = client.blockVolumes().getByRefs(volList, RecoverPointPersonalityFilter.SOURCE); if (allRPSourceVols != null && !allRPSourceVols.isEmpty()) { VolumeRestRep rpvol = allRPSourceVols.get(0); sourceVarrayId = rpvol.getVirtualArray().getId(); } } } else { options.add(newAssetOption(URI.create("none"), "None")); return options; } // if the volumes are RP (vplex or not) add the RP targets as options if (isRP) { options.add(newAssetOption(sourceVarrayId, "protection.site.type.source")); Set<URI> targetVarrayIds = new HashSet<URI>(); List<AssetOption> targetOptions = new ArrayList<AssetOption>(); List<VolumeRestRep> allRPTargetVols = client.blockVolumes().getByRefs(volList, RecoverPointPersonalityFilter.TARGET); for (VolumeRestRep targetVol : allRPTargetVols) { targetVarrayIds.add(targetVol.getVirtualArray().getId()); } List<VirtualArrayRestRep> targetVarrays = client.varrays().getByIds(targetVarrayIds); for (VirtualArrayRestRep targetVarray : targetVarrays) { targetOptions.add(newAssetOption(String.format("tgt:%s", targetVarray.getId().toString()), "protection.site.type.target", targetVarray.getName())); } // sort the targets AssetOptionsUtils.sortOptionsByLabel(targetOptions); options.addAll(targetOptions); } if (options.isEmpty()) { options.add(newAssetOption(URI.create("none"), "None")); } return options; } class VirtualPoolFilter extends DefaultResourceFilter<VolumeRestRep> { private final URI virtualPoolId; public VirtualPoolFilter(URI virtualPoolId) { this.virtualPoolId = virtualPoolId; } @Override public boolean accept(VolumeRestRep item) { return ObjectUtils.equals(ResourceUtils.id(item.getVirtualPool()), virtualPoolId); } } @SafeVarargs public static List<VolumeRestRep> listSourceVolumes(ViPRCoreClient client, URI project, ResourceFilter<VolumeRestRep>... filters) { // Filter volumes that are not SRDF Targets, not RP Targets and not RP Metadata FilterChain<VolumeRestRep> filter = new FilterChain<VolumeRestRep>(new SRDFTargetFilter().not()); filter.and(RecoverPointPersonalityFilter.TARGET.not()); filter.and(RecoverPointPersonalityFilter.METADATA.not()); filter.and(new BlockVolumeBootVolumeFilter().not()); for (ResourceFilter<VolumeRestRep> additionalFilter : filters) { filter.and(additionalFilter); } return client.blockVolumes().findByProject(project, filter); } @SafeVarargs public static List<VolumeRestRep> listJournalVolumes(ViPRCoreClient client, URI project, ResourceFilter<VolumeRestRep>... filters) { // Filter all volumes except Journals FilterChain<VolumeRestRep> filter = new FilterChain<VolumeRestRep>(new SRDFTargetFilter().not()); filter.and(RecoverPointPersonalityFilter.METADATA); for (ResourceFilter<VolumeRestRep> additionalFilter : filters) { filter.and(additionalFilter); } return client.blockVolumes().withInternal(true).findByProject(project, filter); } protected static List<VolumeRestRep> listVolumes(ViPRCoreClient client, URI project) { return client.blockVolumes().findByProject(project); } protected List<VolumeRestRep> listVolumesWithoutConsistencyGroup(ViPRCoreClient client, URI project) { return client.blockVolumes().findByProject(project, new DefaultResourceFilter<VolumeRestRep>() { @Override public boolean accept(VolumeRestRep item) { return !isInConsistencyGroup(item) || isIBMXIVVolume(item); } }); } protected static List<AssetOption> createVolumeWithVarrayOptions(ViPRCoreClient client, Collection<? extends BlockObjectRestRep> blockObjects) { List<URI> varrayIds = getVirtualArrayIds(blockObjects); Map<URI, VirtualArrayRestRep> varrayNames = getVirutalArrayNames(client, varrayIds); List<AssetOption> options = Lists.newArrayList(); for (BlockObjectRestRep blockObject : blockObjects) { options.add(createVolumeWithVarrayOption(blockObject, varrayNames)); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected static AssetOption createVolumeWithVarrayOption(BlockObjectRestRep blockObject, Map<URI, VirtualArrayRestRep> varrayNames) { String label = getBlockObjectLabelWithVarray(blockObject, varrayNames); String name = getBlockObjectName(null, blockObject); if (StringUtils.isNotBlank(name)) { label = String.format("%s: %s", name, label); } return new AssetOption(blockObject.getId(), label); } private static String getBlockObjectLabelWithVarray(BlockObjectRestRep blockObject, Map<URI, VirtualArrayRestRep> varrayNames) { if (blockObject instanceof VolumeRestRep) { VolumeRestRep volume = (VolumeRestRep) blockObject; String varrayName = varrayNames.get(volume.getVirtualArray().getId()).getName(); return getMessage("block.unexport.volume", volume.getName(), volume.getProvisionedCapacity(), varrayName, volume.getWwn()); } return blockObject.getName(); } private static List<URI> getVirtualArrayIds(Collection<? extends BlockObjectRestRep> blockObjects) { List<URI> varrayIds = Lists.newArrayList(); for (BlockObjectRestRep blockObject : blockObjects) { if (blockObject instanceof VolumeRestRep) { VolumeRestRep volume = (VolumeRestRep) blockObject; varrayIds.add(volume.getVirtualArray().getId()); } } return varrayIds; } protected static Map<URI, VirtualArrayRestRep> getVirutalArrayNames(ViPRCoreClient client, List<URI> varrays) { if (varrays == null) { return Collections.emptyMap(); } return ResourceUtils.mapById(client.varrays().getByIds(varrays)); } protected static List<AssetOption> createVolumeOptions(ViPRCoreClient client, Collection<? extends BlockObjectRestRep> blockObjects) { return createVolumeOptions(client, null, null, blockObjects); } protected static List<AssetOption> createVolumeOptions(ViPRCoreClient client, URI project, URI hostId, Collection<? extends BlockObjectRestRep> blockObjects) { Map<URI, VolumeRestRep> volumeNames = getProjectVolumeNames(client, project); List<AssetOption> options = Lists.newArrayList(); for (BlockObjectRestRep blockObject : blockObjects) { options.add(createVolumeOption(client, hostId, blockObject, volumeNames)); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected static AssetOption createVolumeOption(ViPRCoreClient client, URI hostId, BlockObjectRestRep blockObject, Map<URI, VolumeRestRep> volumeNames) { String label = getBlockObjectLabel(client, blockObject, volumeNames); String name = getBlockObjectName(hostId, blockObject); if (StringUtils.isNotBlank(name)) { label = String.format("%s: %s", name, label); } return new AssetOption(blockObject.getId(), label); } protected static Map<URI, VolumeRestRep> getProjectVolumeNames(ViPRCoreClient client, URI project) { if (project == null) { return Collections.emptyMap(); } return ResourceUtils.mapById(client.blockVolumes().findByProject(project)); } protected static String getBlockObjectName(URI hostId, BlockObjectRestRep blockObject) { if (hostId != null) { String mountPoint = KnownMachineTags.getBlockVolumeMountPoint(hostId, blockObject); if (StringUtils.isNotBlank(mountPoint)) { return mountPoint; } } String datastore = KnownMachineTags.getBlockVolumeVMFSDatastore(hostId, blockObject); if (StringUtils.isNotBlank(datastore)) { return datastore; } return null; } protected boolean isMounted(Collection<URI> hostIds, VolumeRestRep volume) { for (URI hostId : hostIds) { if (BlockProviderUtils.isMounted(hostId, volume)) { return true; } } return false; } private static String getBlockObjectLabel(ViPRCoreClient client, BlockObjectRestRep blockObject, Map<URI, VolumeRestRep> volumeNames) { if (blockObject instanceof VolumeRestRep) { if (blockObject instanceof BlockMirrorRestRep) { BlockMirrorRestRep mirror = (BlockMirrorRestRep) blockObject; return getMessage("block.mirror", mirror.getName(), mirror.getWwn()); } else { VolumeRestRep volume = (VolumeRestRep) blockObject; return getMessage("block.volume", volume.getName(), volume.getProvisionedCapacity(), volume.getWwn()); } } else if (blockObject instanceof BlockSnapshotRestRep) { BlockSnapshotRestRep snapshot = (BlockSnapshotRestRep) blockObject; return getMessage("block.snapshot.label", snapshot.getName(), getBlockSnapshotParentVolumeName(volumeNames, snapshot), snapshot.getWwn()); } else if (blockObject instanceof BlockSnapshotSessionRestRep) { BlockSnapshotSessionRestRep snapshotSession = (BlockSnapshotSessionRestRep) blockObject; return getMessage("block.snapshotsession.label", snapshotSession.getName(), getBlockSnapshotSessionParentVolumeName(volumeNames, snapshotSession)); } return blockObject.getName(); } private static String getBlockSnapshotLinkedLabel(BlockSnapshotRestRep snapshot, Map<URI, String> linkedSnapshotToSnapshotSessionMap) { String snapshotSessionName = linkedSnapshotToSnapshotSessionMap.get(snapshot.getId()); if (snapshotSessionName != null && !snapshotSessionName.isEmpty()) { return getMessage("block.snapshot.linked", snapshot.getName(), snapshotSessionName); } return getMessage("block.snapshot.linked.unknown", snapshot.getName()); } protected static String getBlockSnapshotParentVolumeName(Map<URI, VolumeRestRep> volumeNames, BlockSnapshotRestRep snapshot) { if (snapshot.getParent() != null && snapshot.getParent().getId() != null && volumeNames != null && volumeNames.get(snapshot.getParent().getId()) != null) { return ResourceUtils.name(volumeNames.get(snapshot.getParent().getId())); } return getMessage("block.snapshot.unknown.volume"); } protected static String getBlockSnapshotSessionParentVolumeName(Map<URI, VolumeRestRep> volumeNames, BlockSnapshotSessionRestRep snapshotSession) { if (snapshotSession.getParent() != null && snapshotSession.getParent().getId() != null && volumeNames != null && volumeNames.get(snapshotSession.getParent().getId()) != null) { return ResourceUtils.name(volumeNames.get(snapshotSession.getParent().getId())); } return getMessage("block.snapshot.unknown.volume"); } private List<AssetOption> getSnapshotOptionsForProject(AssetOptionsContext ctx, URI project, ResourceFilter<BlockSnapshotRestRep> filter) { ViPRCoreClient client = api(ctx); List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().findByProject(project, filter); return constructSnapshotOptions(client, project, snapshots); } private List<AssetOption> getSnapshotOptionsForProject(AssetOptionsContext ctx, URI project) { ViPRCoreClient client = api(ctx); List<BlockSnapshotRestRep> snapshots = client.blockSnapshots().findByProject(project); return constructSnapshotOptions(client, project, snapshots); } protected List<AssetOption> constructSnapshotOptions(ViPRCoreClient client, URI project, List<BlockSnapshotRestRep> snapshots) { List<AssetOption> options = Lists.newArrayList(); Map<URI, VolumeRestRep> volumeNames = getProjectVolumeNames(client, project); for (BlockSnapshotRestRep snapshot : snapshots) { options.add(new AssetOption(snapshot.getId(), getBlockObjectLabel(client, snapshot, volumeNames))); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected List<AssetOption> constructSnapshotOptions(List<BlockSnapshotRestRep> snapshots) { List<AssetOption> options = Lists.newArrayList(); for (BlockSnapshotRestRep snapshot : snapshots) { options.add(new AssetOption(snapshot.getId(), getMessage("block.snapshot.labelNoVolume", snapshot.getName(), snapshot.getWwn()))); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected List<AssetOption> constructSnapshotWithSnapshotSessionOptions(List<BlockSnapshotRestRep> snapshots, List<BlockSnapshotSessionRestRep> snapshotSessions) { List<AssetOption> options = Lists.newArrayList(); // Create a map of linked target URIs to snapshot session names for convenience when creating // the option labels. Map<URI, String> linkedSnapshotToSnapshotSessionMap = new HashMap<URI, String>(); for (BlockSnapshotSessionRestRep snapshotSession : snapshotSessions) { for (RelatedResourceRep linkedTarget : snapshotSession.getLinkedTarget()) { linkedSnapshotToSnapshotSessionMap.put(linkedTarget.getId(), snapshotSession.getName()); } } for (BlockSnapshotRestRep snapshot : snapshots) { // Ignore RP Bookmarks for snapshot session options boolean isRPSnapshot = (snapshot.getTechnologyType() != null && snapshot.getTechnologyType().equalsIgnoreCase(RECOVERPOINT_BOOKMARK_SNAPSHOT_TYPE_VALUE)); boolean validSnapshotOption = snapshot.getTechnologyType() == null || !isRPSnapshot; if (validSnapshotOption) { options.add(new AssetOption(snapshot.getId(), getBlockSnapshotLinkedLabel(snapshot, linkedSnapshotToSnapshotSessionMap))); } } AssetOptionsUtils.sortOptionsByLabel(options); return options; } protected List<AssetOption> constructSnapshotSessionOptions(ViPRCoreClient client, URI project, List<BlockSnapshotSessionRestRep> snapshotSessions) { List<AssetOption> options = Lists.newArrayList(); Map<URI, VolumeRestRep> volumeNames = getProjectVolumeNames(client, project); for (BlockSnapshotSessionRestRep snapshotSession : snapshotSessions) { options.add(new AssetOption(snapshotSession.getId(), getBlockObjectLabel(client, snapshotSession, volumeNames))); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } private List<AssetOption> getContinuousCopyOptionsForProject(AssetOptionsContext ctx, URI project, URI volumeId, ResourceFilter<BlockMirrorRestRep> filter) { ViPRCoreClient client = api(ctx); List<BlockMirrorRestRep> copies = client.blockVolumes().getContinuousCopies(volumeId, filter); return constructCopiesOptions(client, project, copies); } protected List<AssetOption> constructCopiesOptions(ViPRCoreClient client, URI project, List<BlockMirrorRestRep> copies) { List<AssetOption> options = Lists.newArrayList(); for (BlockMirrorRestRep copy : copies) { options.add(new AssetOption(copy.getId(), getBlockObjectLabel(client, copy, null))); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } /** * Gets the set of volume IDs associated with the given exports. * * @param exports * the export groups. * @return the set of volume IDs. */ protected static Set<URI> getBlockVolumeIdsForExports(List<ExportGroupRestRep> exports) { Set<URI> ids = Sets.newHashSet(); for (ExportGroupRestRep export : exports) { if (export.getVolumes() != null) { for (ExportBlockParam volume : export.getVolumes()) { ids.add(volume.getId()); } } } return ids; } /** * Gets the set of volume IDs for volumes in the given project that are exported to the given host/cluster * * @param client An instance of the ViPRCoreClient * @param projectId The ViPR ID of the project * @param hostOrClusterId The ViPR ID of the host/cluster * * @return The set of Volume IDs */ protected static Set<URI> getExportedVolumes(ViPRCoreClient client, URI projectId, URI hostOrClusterId, URI virtualArrayId) { // determine host and cluster id URI hostId = BlockStorageUtils.isHost(hostOrClusterId) ? hostOrClusterId : null; URI clusterId = BlockStorageUtils.isCluster(hostOrClusterId) ? hostOrClusterId : null; // get a list of all the exports in this project that expose resources to this host/cluster ResourceFilter<ExportGroupRestRep> filter; if (virtualArrayId == null) { filter = new ExportHostOrClusterFilter(hostId, clusterId); } else { filter = new ExportHostOrClusterFilter(hostId, clusterId).and(new ExportVirtualArrayFilter(virtualArrayId)); } List<ExportGroupRestRep> exports = client.blockExports().findByProject(projectId, filter); return getBlockVolumeIdsForExports(exports); } /** * Gets the value of the specified tag from the given volumes. * * @param tagName * the tag name. * @param volumes * the volumes. * @return the tag values. */ public static Set<String> getTagValues(String tagName, Collection<? extends BlockObjectRestRep> volumes) { Set<String> values = Sets.newHashSet(); for (BlockObjectRestRep volume : volumes) { String value = MachineTagUtils.getBlockVolumeTag(volume, tagName); if (value != null) { values.add(value); } } return values; } /** * Returns a list of virtual pools where volume can be moved */ protected List<BlockVirtualPoolRestRep> listTargetVirtualPools(AssetOptionsContext ctx, URI volumeId, ResourceFilter<BlockVirtualPoolRestRep> filter) { ViPRCoreClient client = api(ctx); List<VirtualPoolChangeRep> vpoolChanges = client.blockVolumes().listVirtualPoolChangeCandidates(volumeId); List<URI> vpoolIds = Lists.newArrayList(); for (VirtualPoolChangeRep change : vpoolChanges) { if (change.getAllowed()) { vpoolIds.add(change.getId()); } } return client.blockVpools().getByIds(vpoolIds, filter); } /** * Gets the volume details for a collection of volumes. * * @param client the bourne client. * @param volumes the collection of volumes. * @return the volume details. */ protected static List<VolumeDetail> getVolumeDetails(ViPRCoreClient client, Collection<VolumeRestRep> volumes) { Set<URI> blockVirtualPoolIds = getBlockVirtualPoolIdsForVolumes(volumes); Map<URI, BlockVirtualPoolRestRep> virtualPoolMap = getBlockVirtualPools(client, blockVirtualPoolIds); List<VolumeDetail> details = Lists.newArrayList(); for (VolumeRestRep volume : volumes) { BlockVirtualPoolRestRep virtualPool = virtualPoolMap.get(volume.getVirtualPool().getId()); details.add(new VolumeDetail(volume, virtualPool)); } return details; } /** * Gets the unique set of BlockVirtualPool IDs for the given volumes. * * @param volumes the volumes. * @return the block virtual pool IDs. */ protected static Set<URI> getBlockVirtualPoolIdsForVolumes(Collection<VolumeRestRep> volumes) { Set<URI> ids = Sets.newHashSet(); for (VolumeRestRep volume : volumes) { ids.add(volume.getVirtualPool().getId()); } return ids; } /** * Gets all BlockVirtualPools mapped by ID. * * @param client the ViPR client instance. * @param ids the IDs. * @return the mapping of ID->BlockVirtualPoolRestRep */ public static Map<URI, BlockVirtualPoolRestRep> getBlockVirtualPools(ViPRCoreClient client, Collection<URI> ids) { Map<URI, BlockVirtualPoolRestRep> virtualPools = Maps.newHashMap(); for (BlockVirtualPoolRestRep virtualPool : client.blockVpools().getByIds(ids)) { virtualPools.put(virtualPool.getId(), virtualPool); } return virtualPools; } /** * Gets all BlockVirtualPools mapped by ID. * * @param client the ViPR client instance. * @param volumes the volumes for which we need the VPool information. * @return the mapping of ID->BlockVirtualPoolRestRep */ public static Map<URI, BlockVirtualPoolRestRep> getVpoolsForVolumes(ViPRCoreClient client, List<VolumeRestRep> volumes) { // collect the id of each vpool used by a volume in the given list Set<URI> vpoolIds = Sets.newHashSet(); for (VolumeRestRep volume : volumes) { vpoolIds.add(volume.getVirtualPool().getId()); } // build up a map of URI to VPool return getBlockVirtualPools(client, vpoolIds); } /** * Gets all {@link VolumeRestRep}s that are either in the target VArray or use the target VArray for protection * * @param client the ViPR client instance. * @param targetVArrayId the target VArray ID. * @param volumes the volumes we are concerned with. (These should be VPlex volumes) * @return List of {@link VolumeRestRep}s that are VPlex volumes that are in the target VArray */ public static List<BlockObjectRestRep> getVPlexVolumesInTargetVArray(ViPRCoreClient client, URI targetVArrayId, List<VolumeRestRep> volumes) { // collect vpools used by these volumes Map<URI, BlockVirtualPoolRestRep> vpools = getVpoolsForVolumes(client, volumes); // sift through the volumes to find ones with the correct VArray List<BlockObjectRestRep> acceptedVolumes = Lists.newArrayList(); for (VolumeRestRep volume : volumes) { if (volume.getVirtualArray().getId().equals(targetVArrayId)) { addVolume(acceptedVolumes, volume); } else { // if this volume's HA type is 'distributed' and its distributed VArray matches the target VArray we can accept the volume URI vpoolId = volume.getVirtualPool().getId(); BlockVirtualPoolRestRep volumeVpool = vpools.get(vpoolId); if (volumeVpool != null && isVpoolProtectedByVarray(volumeVpool, targetVArrayId)) { addVolume(acceptedVolumes, volume); } } } return acceptedVolumes; } /** * Class for holding all volume detail information, currently the volume and virtual pool. * * @author jonnymiller */ public static class VolumeDetail { public VolumeRestRep volume; public BlockVirtualPoolRestRep vpool; public VolumeDetail(VolumeRestRep volume) { this.volume = volume; } public VolumeDetail(VolumeRestRep volume, BlockVirtualPoolRestRep vpool) { this.volume = volume; this.vpool = vpool; } } public static List<AssetOption> createVirtualPoolResourceOptions(Collection<? extends VirtualPoolCommonRestRep> virtualPools) { List<AssetOption> options = Lists.newArrayList(); for (VirtualPoolCommonRestRep virtualPool : virtualPools) { options.add(createVirtualPoolResourceOption(virtualPool)); } AssetOptionsUtils.sortOptionsByLabel(options); return options; } public static AssetOption createVirtualPoolResourceOption(VirtualPoolCommonRestRep virtualPool) { boolean hasPools = (virtualPool.getUseMatchedPools() && !CollectionUtils.isEmpty(virtualPool.getMatchedStoragePools()) || (!virtualPool.getUseMatchedPools() && !CollectionUtils.isEmpty(virtualPool.getAssignedStoragePools()))); String label = virtualPool.getName(); if (!hasPools) { label = getMessage("block.virtualPool.noStorage", virtualPool.getName()); } return new AssetOption(virtualPool.getId(), label); } protected List<AssetOption> createVpoolChangeOptions(String vpoolChangeOperation, List<VirtualPoolChangeRep> vpoolChanges) { List<AssetOption> options = Lists.newArrayList(); List<AssetOption> available = Lists.newArrayList(); List<AssetOption> wrongOperation = Lists.newArrayList(); List<AssetOption> notAllowed = Lists.newArrayList(); for (VirtualPoolChangeRep vpoolChange : vpoolChanges) { if (vpoolChange.getAllowed() && vpoolChange.getAllowedChangeOperations() != null) { for (StringHashMapEntry allowedChangeOperation : vpoolChange.getAllowedChangeOperations()) { String operation = allowedChangeOperation.getName(); boolean isCorrectOperation = StringUtils.isNotBlank(operation) && operation.equalsIgnoreCase(vpoolChangeOperation); if (isCorrectOperation) { available.add(new AssetOption(vpoolChange.getId(), vpoolChange.getName())); } else { wrongOperation.add(new AssetOption("", getMessage("block.virtualPool.vpoolChangeOperation", vpoolChange.getName(), getAllowedChangeOperationNames(vpoolChange.getAllowedChangeOperations())))); } } } else { notAllowed.add(new AssetOption("", getMessage("block.virtualPool.vpoolChangeReason", vpoolChange.getName(), vpoolChange.getNotAllowedReason()))); } } options.addAll(available); options.addAll(wrongOperation); options.addAll(notAllowed); return options; } private String getAllowedChangeOperationNames(List<StringHashMapEntry> allowedChangeOperations) { List<String> names = Lists.newArrayList(); for (StringHashMapEntry allowedChangeOperation : allowedChangeOperations) { names.add(getMessage("virtualPoolChange.operation." + allowedChangeOperation.getName())); } return StringUtils.join(names, ','); } protected List<BlockObjectRestRep> getProjectBlockResources(ViPRCoreClient client, URI hostOrClusterId, URI project, boolean onlyMounted) { List<BlockObjectRestRep> blockObjects = Lists.newArrayList(); // the list of host ids that the volume could be mounted to List<URI> hostIds = getHostIds(client, hostOrClusterId, onlyMounted); // get a list of all volumes and snapshots in the project List<VolumeRestRep> projectVolumes = client.blockVolumes().findByProject(project); List<BlockSnapshotRestRep> projectSnapshots = client.blockSnapshots().findByProject(project); // cycle through every volume in the project and add the volume and its snapshots for (VolumeRestRep volume : projectVolumes) { boolean isMounted = isMounted(hostIds, volume); if ((onlyMounted && isMounted) || (!onlyMounted && !isMounted)) { addVolume(blockObjects, volume, projectSnapshots); } } // remaining snapshots can be added now. We don't know their parent volume but we need them in the list anyway blockObjects.addAll(projectSnapshots); return blockObjects; } protected List<VolumeRestRep> getProjectBlockVolumes(ViPRCoreClient client, URI hostOrClusterId, URI project, boolean onlyMounted) { List<VolumeRestRep> volumes = Lists.newArrayList(); // the list of host ids that the volume could be mounted to List<URI> hostIds = getHostIds(client, hostOrClusterId, onlyMounted); // get a list of all volumes and snapshots in the project List<VolumeRestRep> projectVolumes = client.blockVolumes().findByProject(project); // cycle through every volume in the project and add those that match for (VolumeRestRep volume : projectVolumes) { boolean isMounted = isMounted(hostIds, volume); if ((onlyMounted && isMounted) || (!onlyMounted && !isMounted)) { volumes.add(volume); } } return volumes; } protected List<URI> getHostIds(ViPRCoreClient client, URI hostOrClusterId, boolean onlyMounted) { List<URI> hostIds = Lists.newArrayList(); if (onlyMounted) { hostIds.add(hostOrClusterId); } else { hostIds.addAll(HostProvider.getHostIds(client, hostOrClusterId)); // Add Cluster ID to the end of the host ID's if (BlockStorageUtils.isCluster(hostOrClusterId)) { hostIds.add(hostOrClusterId); } else { HostRestRep host = client.hosts().get(hostOrClusterId); if (host.getCluster() != null) { hostIds.add(host.getCluster().getId()); } } } return hostIds; } protected static void addVolume(List<BlockObjectRestRep> blockObjects, VolumeRestRep volume) { addVolume(blockObjects, volume, null); } /** * Add the volume and its snapshots to the 'blockObjects' list. * * When the method completes the snapshots that have been added to the blockObjects list will be removed from the snapshots list. */ protected static void addVolume(List<BlockObjectRestRep> blockObjects, VolumeRestRep volume, List<BlockSnapshotRestRep> snapshots) { blockObjects.add(volume); if (CollectionUtils.isNotEmpty(snapshots)) { // use an iterator so we can do proper removes Iterator<BlockSnapshotRestRep> snapshotIter = snapshots.iterator(); while (snapshotIter.hasNext()) { BlockSnapshotRestRep snap = snapshotIter.next(); if (ResourceUtils.idEquals(snap.getParent(), volume)) { blockObjects.add(snap); snapshotIter.remove(); } } } } /** * SRDF filter for block objects. */ private static class BlockObjectSRDFTargetFilter extends DefaultResourceFilter<BlockObjectRestRep> { private final SRDFTargetFilter filter = new SRDFTargetFilter(); @Override public boolean accept(BlockObjectRestRep item) { if (item instanceof VolumeRestRep) { return filter.accept((VolumeRestRep) item); } return false; } } /** * VMFS Datastore filter for block objects. */ private static class BlockObjectVMFSDatastoreFilter extends DefaultResourceFilter<BlockObjectRestRep> { @Override public boolean accept(BlockObjectRestRep blockObject) { return BlockStorageUtils.isVolumeVMFSDatastore(blockObject); } } /** * VMFS Datastore filter for block volumes. */ private static class BlockVolumeVMFSDatastoreFilter extends DefaultResourceFilter<VolumeRestRep> { @Override public boolean accept(VolumeRestRep volume) { return BlockStorageUtils.isVolumeVMFSDatastore(volume); } } /** * Boot volume filter for block objects. */ private static class BlockObjectBootVolumeFilter extends DefaultResourceFilter<BlockObjectRestRep> { @Override public boolean accept(BlockObjectRestRep blockObject) { return BlockStorageUtils.isVolumeBootVolume(blockObject); } } /** * MountPoint filter for block objects. */ private static class BlockObjectMountPointFilter extends DefaultResourceFilter<BlockObjectRestRep> { @Override public boolean accept(BlockObjectRestRep blockObject) { return BlockStorageUtils.isVolumeMounted(blockObject); } } /** * MountPoint filter for block volumes. */ private static class BlockVolumeMountPointFilter extends DefaultResourceFilter<VolumeRestRep> { @Override public boolean accept(VolumeRestRep volume) { return BlockStorageUtils.isVolumeMounted(volume); } } /** * Check if volume is an IBM XIV volume * * @param vol VolumeRestRep instance to be checked. * @return true if the volume is an IBM XIV volume, false otherwise */ private boolean isIBMXIVVolume(VolumeRestRep vol) { return vol != null && IBMXIV_SYSTEM_TYPE.equals(vol.getSystemType()); } }