/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package controllers.arrays; import com.emc.storageos.model.RelatedResourceRep; import com.emc.storageos.model.systems.StorageSystemRestRep; import static com.emc.vipr.client.core.util.ResourceUtils.id; import static com.emc.vipr.client.core.util.ResourceUtils.uris; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import static controllers.Common.angularRenderArgs; import static controllers.Common.copyRenderArgsToAngular; import static controllers.Common.flashException; import static controllers.Common.getReferrer; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import jobs.vipr.AutoTierPolicyNamesCall; import jobs.vipr.ConnectedBlockVirtualPoolsCall; import jobs.vipr.TenantsCall; import jobs.vipr.VirtualArraysCall; import models.BlockProtocols; import models.DriveTypes; import models.HighAvailability; import models.PoolAssignmentTypes; import models.ProtectionSystemTypes; import models.ProvisioningTypes; import models.RaidLevel; import models.RemoteCopyMode; import models.RpoType; import models.SRDFCopyMode; import models.SizeUnit; import models.StorageSystemTypes; import models.VirtualPoolPlacementPolicy; import models.datatable.StoragePoolDataTable; import models.datatable.StoragePoolDataTable.StoragePoolInfo; import models.datatable.VirtualPoolDataTable; import models.datatable.VirtualPoolDataTable.VirtualPoolInfo; import models.virtualpool.BlockVirtualPoolForm; import models.virtualpool.RPCopyForm; import models.virtualpool.SrdfCopyForm; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang.StringUtils; import play.Logger; import play.data.binding.As; import play.data.validation.Validation; import play.exceptions.UnexpectedException; import play.i18n.Messages; import play.libs.F.Promise; import play.mvc.Catch; import play.mvc.Http; import play.mvc.With; import util.EnumOption; import util.MessagesUtils; import util.StoragePoolUtils; import util.StorageSystemTypeUtils; import util.StorageSystemUtils; import util.StringOption; import util.TenantUtils; import util.ValidationResponse; import util.VirtualArrayUtils; import util.VirtualPoolUtils; import util.datatable.DataTablesSupport; import com.emc.storageos.model.pools.StoragePoolRestRep; import com.emc.storageos.model.storagesystem.type.StorageSystemTypeList; import com.emc.storageos.model.storagesystem.type.StorageSystemTypeRestRep; import com.emc.storageos.model.varray.VirtualArrayRestRep; import com.emc.storageos.model.vpool.BlockVirtualPoolRestRep; import com.emc.storageos.model.vpool.FileVirtualPoolRestRep; import com.emc.storageos.model.vpool.VirtualPoolCommonRestRep; import com.emc.vipr.client.exceptions.ViPRException; import com.emc.vipr.client.exceptions.ViPRHttpException; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import controllers.Common; import controllers.deadbolt.Restrict; import controllers.deadbolt.Restrictions; import controllers.util.ViprResourceController; @With(Common.class) @Restrictions({ @Restrict("SYSTEM_ADMIN"), @Restrict("RESTRICTED_SYSTEM_ADMIN") }) public class BlockVirtualPools extends ViprResourceController { protected static final String SAVED_SUCCESS = "VirtualPools.save.success"; protected static final String SAVED_ERROR = "VirtualPools.save.error"; protected static final String DELETED_SUCCESS = "VirtualPools.delete.success"; protected static final String DELETED_ERROR = "VirtualPools.delete.error"; protected static final String UNKNOWN = "VirtualPools.unknown"; private static final String GUIDE_DATA = "GUIDE_DATA"; private static final String STORAGE_SYSTEMS = "storage_systems"; private static final String VARRAYS = "varrays"; private static final String VPOOL_COOKIES = "vpools"; private static final String ATTRIBUTE_SYSTEM_TYPES = "system_type"; private static final String UNITY = "unity"; private static final String VMAX = "vmax"; private static final String XTREMIO = "xtremio"; private static final String VP_ALL_FLASH = "all-flash-diamond"; private static final String VP_VMAX_DIAMOND = "vmax-diamond"; private static final String VP_VMAX_DIAMOND_COMPRESSED = "vmax-diamond-compressed"; private static final String VP_XIO_DIAMOND = "xio-diamond"; private static final String VP_UNITY_DIAMOND = "unity-diamond"; private static final String DEFAULT_AUTO_TIER = "Diamond SLO (0.8ms)"; private static List<String> getSupportAutoTierTypes() { List<String> result = new ArrayList<String>(); StorageSystemTypeList types = StorageSystemTypeUtils.getAllStorageSystemTypes(StorageSystemTypeUtils.ALL_TYPE); for (StorageSystemTypeRestRep type : types.getStorageSystemTypes()) { if (type.isNative() || type.getIsSmiProvider() || !type.isSupportAutoTierPolicy()) { continue; } result.add(type.getStorageTypeName()); } return result; } public static void list() { VirtualPoolDataTable dataTable = createVirtualPoolDataTable(); render(dataTable); } private static VirtualPoolDataTable createVirtualPoolDataTable() { VirtualPoolDataTable dataTable = new VirtualPoolDataTable(); dataTable.alterColumn("provisionedAs").hidden(); dataTable.alterColumn("provisioningType").setVisible(true); return dataTable; } public static void listJson() { List<VirtualPoolInfo> items = Lists.newArrayList(); for (BlockVirtualPoolRestRep virtualPool : VirtualPoolUtils.getBlockVirtualPools()) { items.add(new VirtualPoolInfo(virtualPool)); } renderJSON(DataTablesSupport.createJSON(items, params)); } public static void checkDisconnectedStoragePools(@As(",") String[] ids) { List<BlockVirtualPoolRestRep> virtualpools = VirtualPoolUtils.getBlockVirtualPools(); Set<String> connectedstoragepools = new HashSet<String>(); List<String> failedArrays = new ArrayList<String>(); for (BlockVirtualPoolRestRep virtualpool:virtualpools) { if(virtualpool.getUseMatchedPools()) { for (RelatedResourceRep pool : virtualpool.getMatchedStoragePools()) { connectedstoragepools.add(pool.getId().toString()); } } else { for (RelatedResourceRep pool : virtualpool.getAssignedStoragePools()) { connectedstoragepools.add(pool.getId().toString()); } } } for (String id:ids) { StorageSystemRestRep storageSystem =StorageSystemUtils.getStorageSystem(id); if (storageSystem != null && !storageSystem.getRegistrationStatus().equals("UNREGISTERED")) { boolean found = false; List<StoragePoolRestRep> storagepools = StoragePoolUtils.getStoragePools(id); for (StoragePoolRestRep storagepool : storagepools) { if (connectedstoragepools.contains(storagepool.getId().toString())) { found = true; break; } } if (!found) { failedArrays.add(storageSystem.getName()); } } } renderJSON(failedArrays); } public static void duplicate(String ids) { BlockVirtualPoolRestRep targetVPool = VirtualPoolUtils.getBlockVirtualPool(ids); if (targetVPool == null) { flash.error(MessagesUtils.get(UNKNOWN, ids)); backToReferrer(); } BlockVirtualPoolForm copy = new BlockVirtualPoolForm(); copy.load(targetVPool); copy.id = null; copy.name = Messages.get("virtualPools.duplicate.name", copy.name); // Target VPool could have resources, set resources to 0 on the new Copy VPool so user can modify form copy.numResources = 0; edit(copy); } public static void create() { BlockVirtualPoolForm vpool = new BlockVirtualPoolForm(); vpool.provisioningType = ProvisioningTypes.THIN; vpool.protocols = Sets.newHashSet(BlockProtocols.FC); vpool.placementPolicy = VirtualPoolPlacementPolicy.DEFAULT; vpool.minPaths = 1; vpool.maxPaths = 2; vpool.initiatorPaths = 1; vpool.expandable = true; vpool.rpJournalSizeUnit = SizeUnit.x; vpool.rpJournalSize = RPCopyForm.JOURNAL_DEFAULT_MULTIPLIER; vpool.rpRpoValue = Long.valueOf(25); vpool.rpRpoType = RpoType.SECONDS; vpool.protectSourceSite = true; vpool.enableAutoCrossConnExport = true; edit(vpool); } public static void createAllFlash() { // This method should only list available storage type discovered Set<String> typesList = new HashSet<String>(); JsonObject dataObject = getCookieAsJson(GUIDE_DATA); JsonArray storage_systems = dataObject.getAsJsonArray(STORAGE_SYSTEMS); if(storage_systems != null ) { for(Object storageobject : storage_systems) { JsonObject storage = (JsonObject) storageobject; String storageid = storage.get("id").getAsString(); StorageSystemRestRep storagesys = StorageSystemUtils.getStorageSystem(storageid); if(storagesys != null && !storagesys.getRegistrationStatus().equals("UNREGISTERED")) { typesList.add(storagesys.getSystemType()); } } } renderArgs.put("types", typesList); render(); } /** * This method create virtual pool according to storage system types * @param types : List of storage system types discovered */ public static void createAllFlashAuto(List<String> types) { List<String> vaIds4allflash = new ArrayList<String>(); List<String> vaIds4vmax = new ArrayList<String>(); List<String> vaIds4xio = new ArrayList<String>(); List<String> vaIds4unity = new ArrayList<String>(); JsonArray vpools = new JsonArray(); // Read cookies for storage systems and virtual pools JsonObject dataObject = getCookieAsJson(GUIDE_DATA); if(dataObject != null) { JsonArray varrays = dataObject.getAsJsonArray(VARRAYS); if (varrays != null) { for (Object varray : varrays) { JsonObject jsonvarray = (JsonObject) varray; String varrayid = jsonvarray.get("id").getAsString(); // Check virtual array first VirtualArrayRestRep varrayRest = VirtualArrayUtils.getVirtualArray(varrayid); if (varrayRest != null) { // Get virtual array attributes Map<String, Set<String>> attributes = VirtualArrayUtils.getAvailableAttributes(uris(varrayid)); Set<String> system_type = attributes.get(ATTRIBUTE_SYSTEM_TYPES); if (system_type != null && !system_type.isEmpty()) { if (system_type.size() > 1) { vaIds4allflash.add(varrayid); } else { // It has one system type for (String vasystemtype : system_type) { if (StringUtils.equals(UNITY, vasystemtype)) { vaIds4unity.add(varrayid); } if (StringUtils.equals(VMAX, vasystemtype)) { vaIds4vmax.add(varrayid); } if (StringUtils.equals(XTREMIO, vasystemtype)) { vaIds4xio.add(varrayid); } } } } else { //Control should not reach here but let add in all flash vaIds4allflash.add(varrayid); } } } } } if(!vaIds4allflash.isEmpty()){ Map<String, String> virtualpoolAllFlashMap = allFlashVirtualPool(); String vpid = virtualpoolAllFlashMap.get(VP_ALL_FLASH); if(vpid != null) { BlockVirtualPoolRestRep blockvpool = VirtualPoolUtils.getBlockVirtualPool(vpid); List<RelatedResourceRep> virtualarrays = blockvpool.getVirtualArrays(); for(String vaid:vaIds4allflash) { RelatedResourceRep newVaId = new RelatedResourceRep(); newVaId.setId(URI.create(vaid)); virtualarrays.add(newVaId); } blockvpool.setVirtualArrays(virtualarrays); updateAutoVirtualPool(vpid, blockvpool,vpools); } else { createBaseVPool(VP_ALL_FLASH, StorageSystemTypes.NONE, vaIds4allflash, Messages.get("gettingStarted.vpool.allflash.desc"), vpools); } } if(!vaIds4vmax.isEmpty()) { Map<String, String> virtualpoolAllFlashMap = allFlashVirtualPool(); // Check if we should add in existing compressed vpool boolean isCompression = isCompressionEnable(vaIds4vmax); String vpid = virtualpoolAllFlashMap.get(VP_VMAX_DIAMOND); if(vpid != null && !isCompression) { BlockVirtualPoolRestRep blockvpool = VirtualPoolUtils.getBlockVirtualPool(vpid); List<RelatedResourceRep> virtualarrays = blockvpool.getVirtualArrays(); for(String vaid:vaIds4vmax) { RelatedResourceRep newVaId = new RelatedResourceRep(); newVaId.setId(URI.create(vaid)); virtualarrays.add(newVaId); } blockvpool.setVirtualArrays(virtualarrays); updateAutoVirtualPool(vpid, blockvpool,vpools); } else { //Check compressed vpool vpid = virtualpoolAllFlashMap.get(VP_VMAX_DIAMOND_COMPRESSED); if(vpid != null && isCompression) { BlockVirtualPoolRestRep blockvpool = VirtualPoolUtils.getBlockVirtualPool(vpid); List<RelatedResourceRep> virtualarrays = blockvpool.getVirtualArrays(); for(String vaid:vaIds4vmax) { RelatedResourceRep newVaId = new RelatedResourceRep(); newVaId.setId(URI.create(vaid)); virtualarrays.add(newVaId); } blockvpool.setVirtualArrays(virtualarrays); updateAutoVirtualPool(vpid, blockvpool,vpools); } else { createBaseVPool(VP_VMAX_DIAMOND, StorageSystemTypes.VMAX, vaIds4vmax, Messages.get("gettingStarted.vpool.vmax.desc"), vpools); } } } if(!vaIds4xio.isEmpty()) { Map<String, String> virtualpoolAllFlashMap = allFlashVirtualPool(); String vpid = virtualpoolAllFlashMap.get(VP_XIO_DIAMOND); if(vpid != null) { BlockVirtualPoolRestRep blockvpool = VirtualPoolUtils.getBlockVirtualPool(vpid); List<RelatedResourceRep> virtualarrays = blockvpool.getVirtualArrays(); for(String vaid:vaIds4xio) { RelatedResourceRep newVaId = new RelatedResourceRep(); newVaId.setId(URI.create(vaid)); virtualarrays.add(newVaId); } blockvpool.setVirtualArrays(virtualarrays); updateAutoVirtualPool(vpid, blockvpool,vpools); } else { createBaseVPool(VP_XIO_DIAMOND, StorageSystemTypes.XTREMIO, vaIds4xio, Messages.get("gettingStarted.vpool.xio.desc"), vpools); } } if(!vaIds4unity.isEmpty()) { Map<String, String> virtualpoolAllFlashMap = allFlashVirtualPool(); String vpid = virtualpoolAllFlashMap.get(VP_UNITY_DIAMOND); if(vpid != null) { BlockVirtualPoolRestRep blockvpool = VirtualPoolUtils.getBlockVirtualPool(vpid); List<RelatedResourceRep> virtualarrays = blockvpool.getVirtualArrays(); for(String vaid:vaIds4unity) { RelatedResourceRep newVaId = new RelatedResourceRep(); newVaId.setId(URI.create(vaid)); virtualarrays.add(newVaId); } blockvpool.setVirtualArrays(virtualarrays); updateAutoVirtualPool(vpid, blockvpool,vpools); } else { createBaseVPool(VP_UNITY_DIAMOND, StorageSystemTypes.UNITY, vaIds4unity, Messages.get("gettingStarted.vpool.unity.desc"), vpools); } } dataObject.add(VPOOL_COOKIES, vpools); saveJsonAsCookie(GUIDE_DATA, dataObject); list(); } public static void edit(String id) { BlockVirtualPoolRestRep virtualPool = VirtualPoolUtils.getBlockVirtualPool(id); if (virtualPool == null) { flash.error(MessagesUtils.get(UNKNOWN, id)); backToReferrer(); } BlockVirtualPoolForm vpool = new BlockVirtualPoolForm(); vpool.load(virtualPool); edit(vpool); } private static void edit(BlockVirtualPoolForm vpool) { List<String> autoTierTypes = getSupportAutoTierTypes(); applyFlashParam(vpool, "vpool", "autoTierPolicy", "systemType", "provisioningType", "haVirtualArray", "haVirtualPool", "highAvailability", "remoteProtection"); List<String> varrays = getFlashList("vpool", "virtualArrays"); if (varrays != null) { vpool.virtualArrays = varrays; } Boolean uniqueNamesBool = getFlashBoolean("vpool", "uniqueAutoTierPolicyNames"); if (uniqueNamesBool != null) { vpool.uniqueAutoTierPolicyNames = uniqueNamesBool; } addStaticOptions(); addDynamicOptions(vpool); renderArgs.put("storagePoolsDataTable", createStoragePoolDataTable()); copyRenderArgsToAngular(); angularRenderArgs().put("vpool", vpool); render("@edit", vpool, autoTierTypes); } private static StoragePoolDataTable createStoragePoolDataTable() { StoragePoolDataTable dataTable = new StoragePoolDataTable(); dataTable.alterColumn("registrationStatus").hidden(); return dataTable; } private static Boolean getFlashBoolean(String beanName, String name) { String bool = flash.get(beanName + "." + name); if (bool != null) { return Boolean.valueOf(bool); } else { return null; } } private static List<String> getFlashList(String beanName, String name) { String value = flash.get(beanName + "." + name); if (value != null) { return Lists.newArrayList(value.split(",")); } return null; } private static void applyFlashParam(BlockVirtualPoolForm bean, String beanName, String... names) { for (String name : names) { String value = flash.get(beanName + "." + name); if (value != null) { try { BeanUtils.setProperty(bean, name, value); } catch (IllegalAccessException e) { Logger.warn(e, "Could not set property %s from flash", name); } catch (InvocationTargetException e) { Logger.warn(e, "Could not set property %s from flash", name); } } } } /** * Handles errors that might arise during JSON requests and returns the error message. * * @param e */ @Catch({ UnexpectedException.class, ViPRException.class }) public static void handleJsonError(Exception e) { if (request.isAjax() || StringUtils.endsWithIgnoreCase(request.action, "json")) { Throwable cause = Common.unwrap(e); String message = Common.getUserMessage(cause); Logger.error(e, "AJAX request failed: %s.%s [%s]", request.controller, request.action, message); error(message); } } public static void listVirtualArrayAttributesJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } renderJSON(vpool.getVirtualPoolAttributes()); } public static void listContinuousCopyVirtualPoolsJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(vpool.connectedVirtualPools().asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listRecoverPointVirtualArraysJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<VirtualArrayRestRep> virtualArrays = await(vpool.recoverPointVirtualArrays().asPromise()); renderJSON(dataObjectOptions(virtualArrays)); } public static void listRecoverPointVirtualPoolsJson(RPCopyForm rpCopy) { if (rpCopy == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(rpCopy.recoverPointVirtualPools().asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listRecoverPointJournalVPoolsJson(RPCopyForm rpCopy) { if (rpCopy == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(rpCopy.recoverPointJournalVirtualPools().asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listSourceRpJournalVPoolsJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(vpool.sourceRpJournalVirtualPools().asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listHaRpJournalVPoolsJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(vpool.haRpJournalVirtualPools().asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listSrdfVirtualArraysJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } vpool.deserialize(); List<StringOption> actualOptions = Lists.newArrayList(); List<VirtualArrayRestRep> virtualArrays = await(vpool.srdfVirtualArrays().asPromise()); for (StringOption option : dataObjectOptions(virtualArrays)) { if (!varrayAlreadyInSRDFCopies(option.id, vpool.srdfCopies)) { actualOptions.add(option); } } renderJSON(actualOptions); } public static void listSrdfVirtualPoolsJson(String virtualArray) { if (virtualArray == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(new ConnectedBlockVirtualPoolsCall(uris(virtualArray)).asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listHighAvailabilityVirtualArraysJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<VirtualArrayRestRep> virtualArrays = await(vpool.highAvailabilityVirtualArrays().asPromise()); renderJSON(dataObjectOptions(virtualArrays)); } public static void listHighAvailabilityVirtualPoolsJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<BlockVirtualPoolRestRep> pools = await(vpool.highAvailabilityVirtualPools().asPromise()); renderJSON(dataObjectOptions(pools)); } public static void listAutoTierPoliciesJson(BlockVirtualPoolForm vpool) { if (vpool == null) { renderJSON(Collections.emptyList()); } List<String> policyNames = await(vpool.autoTierPolicyNames().asPromise()); renderJSON(StringOption.options(policyNames)); } public static void listStoragePoolsJson(BlockVirtualPoolForm vpool) { List<StoragePoolInfo> items = Lists.newArrayList(); if (vpool != null && vpool.protocols != null && !vpool.protocols.isEmpty()) { vpool.deserialize(); Map<URI, String> storageSystemNames = StorageSystemUtils.getStorageSystemNames(); List<StoragePoolRestRep> pools = getMatchingStoragePools(vpool); for (StoragePoolRestRep pool : pools) { String storageSystemName = storageSystemNames.get(id(pool.getStorageSystem())); items.add(new StoragePoolInfo(pool, storageSystemName)); } } renderJSON(DataTablesSupport.createJSON(items, params)); } public static void listStoragePoolsbyIdJson(String id) { BlockVirtualPoolRestRep virtualPool = VirtualPoolUtils.getBlockVirtualPool(id); if (virtualPool == null) { flash.error(MessagesUtils.get(UNKNOWN, id)); backToReferrer(); } BlockVirtualPoolForm vpool = new BlockVirtualPoolForm(); vpool.load(virtualPool); List<StoragePoolInfo> items = Lists.newArrayList(); if (vpool != null && vpool.protocols != null && !vpool.protocols.isEmpty()) { vpool.deserialize(); Map<URI, String> storageSystemNames = StorageSystemUtils.getStorageSystemNames(); List<StoragePoolRestRep> pools = getMatchingStoragePools(vpool); for (StoragePoolRestRep pool : pools) { String storageSystemName = storageSystemNames.get(id(pool.getStorageSystem())); items.add(new StoragePoolInfo(pool, storageSystemName)); } } renderJSON(DataTablesSupport.createJSON(items, params)); } private static List<StoragePoolRestRep> getMatchingStoragePools(BlockVirtualPoolForm vpool) { try { return await(vpool.matchingStoragePools().asPromise()); } catch (UnexpectedException e) { Throwable cause = Common.unwrap(e); if (cause instanceof ViPRHttpException) { int httpCode = ((ViPRHttpException) cause).getHttpCode(); // Bad request is usually a result of partially completing the form if (httpCode == Http.StatusCode.BAD_REQUEST) { Logger.warn(cause, "Bad Request when querying matching storage pools, returning no matches"); return Lists.newArrayList(); } } throw e; } } public static void validateRecoverPointCopy(RPCopyForm rpCopy) { if (rpCopy == null) { renderJSON(ValidationResponse.invalid()); } rpCopy.validate("rpCopy"); if (Validation.hasErrors()) { renderJSON(ValidationResponse.collectErrors()); } else { renderJSON(ValidationResponse.valid()); } } public static void validateSrdfCopy(SrdfCopyForm srdfCopy) { if (srdfCopy == null) { renderJSON(ValidationResponse.invalid()); } srdfCopy.validate("srdfCopy"); if (Validation.hasErrors()) { renderJSON(ValidationResponse.collectErrors()); } else { renderJSON(ValidationResponse.valid()); } } public static void save(BlockVirtualPoolForm vpool) { if (vpool == null) { list(); } vpool.deserialize(); vpool.validate("vpool"); if (Validation.hasErrors()) { error(vpool); } try { BlockVirtualPoolRestRep virtualPool = vpool.save(); flash.success(MessagesUtils.get(SAVED_SUCCESS, virtualPool.getName())); list(); } catch (ViPRException e) { exception(vpool, e); } } private static boolean varrayAlreadyInSRDFCopies(String varrayId, SrdfCopyForm[] copies) { for (SrdfCopyForm copy : copies) { if (copy.virtualArray.equals(varrayId)) { return true; } } return false; } private static void backToReferrer() { String referrer = getReferrer(); if (StringUtils.isNotBlank(referrer)) { redirect(referrer); } else { list(); } } private static void exception(BlockVirtualPoolForm vpool, ViPRException e) { flashException(e); error(vpool); } private static void error(BlockVirtualPoolForm vpool) { // Only flash vpool parameters to reduce amount stored in flash scope for (String param : params.all().keySet()) { if (param.startsWith("vpool.") && !StringUtils.equalsIgnoreCase(param, "vpool.rpCopiesJson")) { params.flash(param); } } Validation.keep(); if (vpool.isNew()) { create(); } else { edit(vpool.id); } } public static void delete(@As(",") String[] ids) { delete(uris(ids)); } private static void delete(List<URI> ids) { performSuccessFail(ids, new DeactivateOperation(), DELETED_SUCCESS, DELETED_ERROR); backToReferrer(); } private static void addStaticOptions() { renderArgs.put("provisioningTypeOptions", ProvisioningTypes.options( ProvisioningTypes.THICK, ProvisioningTypes.THIN )); renderArgs.put("protocolsOptions", BlockProtocols.options( BlockProtocols.FC, BlockProtocols.iSCSI, BlockProtocols.ScaleIO, BlockProtocols.RBD )); renderArgs.put("placementPolicyOptions", VirtualPoolPlacementPolicy.options( VirtualPoolPlacementPolicy.DEFAULT, VirtualPoolPlacementPolicy.ARRAY_AFFINITY )); renderArgs.put("systemTypeOptions", StorageSystemTypes.getBlockStorageOptions()); renderArgs.put("driveTypeOptions", DriveTypes.options( DriveTypes.NONE, DriveTypes.FC, DriveTypes.SAS, DriveTypes.NL_SAS, DriveTypes.SATA, DriveTypes.SSD )); renderArgs.put("raidLevelsOptions", RaidLevel.options( RaidLevel.RAID0, RaidLevel.RAID1, RaidLevel.RAID2, RaidLevel.RAID3, RaidLevel.RAID4, RaidLevel.RAID5, RaidLevel.RAID6, RaidLevel.RAID10 )); renderArgs.put("poolAssignmentOptions", PoolAssignmentTypes.options( PoolAssignmentTypes.AUTOMATIC, PoolAssignmentTypes.MANUAL )); renderArgs.put("highAvailabilityOptions", Lists.newArrayList( HighAvailability.option(HighAvailability.VPLEX_LOCAL), HighAvailability.option(HighAvailability.VPLEX_DISTRIBUTED) )); renderArgs.put("vplexActiveSiteOptions", Lists.newArrayList( HighAvailability.option(HighAvailability.VPLEX_SOURCE), HighAvailability.option(HighAvailability.VPLEX_HA) )); renderArgs.put("remoteProtectionOptions", Lists.newArrayList( ProtectionSystemTypes.option(ProtectionSystemTypes.RECOVERPOINT), ProtectionSystemTypes.option(ProtectionSystemTypes.SRDF) )); renderArgs.put("rpRemoteCopyModeOptions", RemoteCopyMode.OPTIONS); renderArgs.put("rpRpoTypeOptions", RpoType.OPTIONS); renderArgs.put("srdfCopyModeOptions", SRDFCopyMode.OPTIONS); renderArgs.put( "numPathsOptions", StringOption.options(new String[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32" }, false)); renderArgs.put("rpJournalSizeUnitOptions", EnumOption.options(SizeUnit.values(), false)); renderArgs.put("varrayAttributeNames", VirtualArrayUtils.ATTRIBUTES); } private static void addDynamicOptions(BlockVirtualPoolForm vpool) { // Runs all queries in jobs Promise<List<VirtualArrayRestRep>> virtualArrays = new VirtualArraysCall().asPromise(); Promise<List<String>> autoTierPolicies = vpool.autoTierPolicyNames().asPromise(); Promise<List<BlockVirtualPoolRestRep>> connectedVirtualPools = vpool.connectedVirtualPools().asPromise(); Promise<List<VirtualArrayRestRep>> haVirtualArrays = vpool.highAvailabilityVirtualArrays().asPromise(); Promise<List<BlockVirtualPoolRestRep>> haVirtualPools = vpool.highAvailabilityVirtualPools().asPromise(); Promise<List<VirtualArrayRestRep>> rpVirtualArrays = vpool.recoverPointVirtualArrays().asPromise(); Promise<List<VirtualArrayRestRep>> rpJournalVirtualArrays = vpool.recoverPointVirtualArrays().asPromise(); Promise<List<VirtualArrayRestRep>> sourceJournalVirtualArrays = vpool.sourceJournalVirtualArrays().asPromise(); Promise<List<VirtualArrayRestRep>> haJournalVirtualArrays = vpool.haRpJournalVirtualArrays().asPromise(); Promise<List<BlockVirtualPoolRestRep>> sourceJournalVirtualPools = vpool.sourceRpJournalVirtualPools().asPromise(); Promise<List<BlockVirtualPoolRestRep>> haJournalVirtualPools = vpool.haRpJournalVirtualPools().asPromise(); Promise<List<VirtualArrayRestRep>> srdfVirtualArrays = vpool.srdfVirtualArrays().asPromise(); if (TenantUtils.canReadAllTenants() && VirtualPoolUtils.canUpdateACLs()) { addDataObjectOptions("tenantOptions", new TenantsCall().asPromise()); } addDataObjectOptions("virtualArrayOptions", virtualArrays); addStringOptions("autoTierPolicyOptions", autoTierPolicies); addDataObjectOptions("continuousCopyVirtualPoolOptions", connectedVirtualPools); addDataObjectOptions("haVirtualArrayOptions", haVirtualArrays); addDataObjectOptions("haVirtualPoolOptions", haVirtualPools); addDataObjectOptions("rpVirtualArrayOptions", rpVirtualArrays); addDataObjectOptions("rpJournalVirtualArrayOptions", rpJournalVirtualArrays); addDataObjectOptions("vpoolSourceJournalVirtualArrayOptions", sourceJournalVirtualArrays); addDataObjectOptions("vpoolSourceJournalVirtualPoolOptions", sourceJournalVirtualPools); addDataObjectOptions("vpoolHAJournalVirtualArrayOptions", haJournalVirtualArrays); addDataObjectOptions("vpoolHAJournalVirtualPoolOptions", haJournalVirtualPools); addDataObjectOptions("srdfVirtualArrayOptions", srdfVirtualArrays); addDataObjectOptions("srdfVirtualPoolOptions", connectedVirtualPools); } private static Map<String, String> allFlashVirtualPool() { // Build virtual pool map name:id only for all-flash virtualpool. Map<String, String> virtualpoolAllFlashMap = new HashMap <String, String> (); List<BlockVirtualPoolRestRep> allblockvps = VirtualPoolUtils.getBlockVirtualPools(); for(BlockVirtualPoolRestRep blockvp: allblockvps) { if(StringUtils.equalsIgnoreCase(VP_VMAX_DIAMOND, blockvp.getName())) { virtualpoolAllFlashMap.put(VP_VMAX_DIAMOND, blockvp.getId().toString()); } if(StringUtils.equalsIgnoreCase(VP_VMAX_DIAMOND_COMPRESSED, blockvp.getName())) { virtualpoolAllFlashMap.put(VP_VMAX_DIAMOND_COMPRESSED, blockvp.getId().toString()); } if(StringUtils.equalsIgnoreCase(VP_XIO_DIAMOND, blockvp.getName())) { virtualpoolAllFlashMap.put(VP_XIO_DIAMOND, blockvp.getId().toString()); } if(StringUtils.equalsIgnoreCase(VP_UNITY_DIAMOND, blockvp.getName())) { virtualpoolAllFlashMap.put(VP_UNITY_DIAMOND, blockvp.getId().toString()); } if(StringUtils.equalsIgnoreCase(VP_ALL_FLASH, blockvp.getName())) { virtualpoolAllFlashMap.put(VP_ALL_FLASH, blockvp.getId().toString()); } } return virtualpoolAllFlashMap; } private static void buildVpoolCookies( String vpoolid, String vpoolname, JsonArray vpools) { JsonObject jsonvarray = new JsonObject(); jsonvarray.addProperty("id", vpoolid); jsonvarray.addProperty("name", vpoolname); vpools.add(jsonvarray); } private static void createBaseVPool(String vpoolName, String storageType, List<String> virtualarrayIds, String vpdesc,JsonArray vpools) { BlockVirtualPoolForm vpool = new BlockVirtualPoolForm(); // defaults vpool.provisioningType = ProvisioningTypes.THIN; vpool.protocols = Sets.newHashSet(BlockProtocols.FC); vpool.minPaths = 1; vpool.maxPaths = 1; vpool.initiatorPaths = 1; vpool.expandable = true; vpool.rpJournalSizeUnit = SizeUnit.x; vpool.rpJournalSize = RPCopyForm.JOURNAL_DEFAULT_MULTIPLIER; vpool.rpRpoValue = Long.valueOf(25); vpool.rpRpoType = RpoType.SECONDS; vpool.protectSourceSite = true; vpool.enableAutoCrossConnExport = true; vpool.poolAssignment = PoolAssignmentTypes.AUTOMATIC; vpool.maxSnapshots = 10; vpool.name = vpoolName; vpool.systemType = storageType; vpool.virtualArrays = virtualarrayIds; vpool.description = vpdesc; vpool.enableCompression = false; // Check if creating a vmax AFA virtual pool, need to set auto-tiering if(StringUtils.equals(VMAX, storageType)) { vpool.uniqueAutoTierPolicyNames = true; boolean isAutoTier = false; AutoTierPolicyNamesCall auto_tiering = vpool.autoTierPolicyNames(); List<String> autoPolicyList = auto_tiering.call(); for(String policy: autoPolicyList) { if(StringUtils.equals(DEFAULT_AUTO_TIER, policy)) { vpool.autoTierPolicy = policy; isAutoTier = true; break; } } if(!isAutoTier) { //This means we did not find the pattern, set random for(String policy: autoPolicyList) { vpool.autoTierPolicy = policy; break; } } for(String virtualArrayId: virtualarrayIds) { List<StoragePoolRestRep> spList = StoragePoolUtils.getStoragePoolsAssignedToVirtualArray(virtualArrayId); for(StoragePoolRestRep sp: spList) { if(sp.getCompressionEnabled() != null && sp.getCompressionEnabled()) { vpool.enableCompression = true; //rename with compression enable vpool.name = VP_VMAX_DIAMOND_COMPRESSED; break; } } if(vpool.enableCompression) { break; } } } BlockVirtualPoolRestRep vpoolTask = vpool.save(); if (vpoolTask != null) { buildVpoolCookies(vpoolTask.getId().toString(), vpool.name,vpools); } } private static boolean isCompressionEnable(List<String> virtualarrayIds) { boolean enableCompression = false; for(String virtualArrayId: virtualarrayIds) { List<StoragePoolRestRep> spList = StoragePoolUtils.getStoragePoolsAssignedToVirtualArray(virtualArrayId); for(StoragePoolRestRep sp: spList) { if(sp.getCompressionEnabled() != null && sp.getCompressionEnabled()) { enableCompression = true; break; } } if(enableCompression) { break; } } return enableCompression; } private static void updateAutoVirtualPool(String vpid, BlockVirtualPoolRestRep blockvpool,JsonArray vpools) { BlockVirtualPoolForm vpool = new BlockVirtualPoolForm(); vpool.load(blockvpool); blockvpool = vpool.save(); if (blockvpool != null) { buildVpoolCookies(vpid, vpool.name,vpools); } } protected static class DeactivateOperation implements ResourceIdOperation<Void> { @Override public Void performOperation(URI id) throws Exception { VirtualPoolCommonRestRep virtualPool = VirtualPoolUtils.getVirtualPool(id.toString()); if (virtualPool instanceof BlockVirtualPoolRestRep) { VirtualPoolUtils.deactivateBlock(id); } else if (virtualPool instanceof FileVirtualPoolRestRep) { VirtualPoolUtils.deactivateFile(id); } return null; } } }