/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.protectioncontroller.impl.recoverpoint; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.BlockObject; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.protectioncontroller.ProtectionExportController; import com.emc.storageos.volumecontroller.impl.block.ExportWorkflowUtils; import com.emc.storageos.workflow.Workflow; public class RPDeviceExportController implements ProtectionExportController { private final DbClient dbClient; private final ExportWorkflowUtils wfUtils; private static final Logger log = LoggerFactory.getLogger(RPDeviceExportController.class); public RPDeviceExportController(DbClient dbClient, ExportWorkflowUtils wfUtils) { this.dbClient = dbClient; this.wfUtils = wfUtils; } @Override public String addStepsForExportGroupCreate(Workflow workflow, String wfGroupId, String waitFor, URI export, Map<URI, Integer> objectsToAdd, URI storageUri, List<URI> initiatorURIs) { // Extract all BlockSnapshots with a protection system from the list of objects to export and // sort them by protection system. If we have objects with a protection system set, the // export needs to be handled by the associated protection controller, and NOT the block // controller. Map<URI, Map<URI, Integer>> protectionMap = sortSnapshotsByProtectionSystem(objectsToAdd); if (!protectionMap.isEmpty()) { for (URI protectionSystemUri : protectionMap.keySet()) { // Obtain subset of objects to export that reference the current protection controller Map<URI, Integer> objectsToExportWithProtection = protectionMap.get(protectionSystemUri); log.info(String .format( "Generating exportGroupCreate steps for objects %s associated with protection system [%s] and storage system [%s]", objectsToExportWithProtection.keySet(), protectionSystemUri, storageUri)); waitFor = wfUtils. generateExportGroupCreateWorkflow(workflow, null, waitFor, protectionSystemUri, export, objectsToExportWithProtection, initiatorURIs); // Reconcile the list of objects being added by removing those that have been exported for (URI blockObjectUri : objectsToExportWithProtection.keySet()) { objectsToAdd.remove(blockObjectUri); } } } return waitFor; } @Override public String addStepsForExportGroupRemoveVolumes(Workflow workflow, String wfGroupId, String waitFor, URI export, Map<URI, Integer> objectsToRemove, URI storageUri) { // Obtain a Map of BlockSnapshots that are associated to a protection system. Map<URI, Map<URI, Integer>> removeBlockObjectsByProtectionSystem = sortSnapshotsByProtectionSystem(objectsToRemove); if (!removeBlockObjectsByProtectionSystem.isEmpty()) { // For each protection system, create the export group remove volume steps for the associated BlockSnapshot objects. for (URI protectionSystemUri : removeBlockObjectsByProtectionSystem.keySet()) { List<URI> objectsToRemoveWithProtection = new ArrayList<URI>(removeBlockObjectsByProtectionSystem.get( protectionSystemUri).keySet()); log.info(String .format( "Generating exportGroupRemoveVolumes step for objects %s associated with protection system [%s] and storage system [%s]", objectsToRemoveWithProtection, protectionSystemUri, storageUri)); waitFor = wfUtils.generateExportGroupRemoveVolumes(workflow, wfGroupId, waitFor, protectionSystemUri, export, objectsToRemoveWithProtection); // Reconcile the primary list of unexport objects by removing all BlockSnapshots associated with the current // protection system. for (URI blockObjectUri : objectsToRemoveWithProtection) { objectsToRemove.remove(blockObjectUri); } } } return waitFor; } @Override public String addStepsForExportGroupAddVolumes(Workflow workflow, String wfGroupId, String waitFor, URI export, Map<URI, Integer> objectsToAdd, URI storageUri) { // Obtain a Map of BlockSnapshots that are associated to a protection system. Map<URI, Map<URI, Integer>> addedBlockObjectsByProtectionSystem = sortSnapshotsByProtectionSystem(objectsToAdd); if (!addedBlockObjectsByProtectionSystem.isEmpty()) { // For each protection system, create the export group add volume steps for the associated BlockSnapshot objects. for (URI protectionSystemUri : addedBlockObjectsByProtectionSystem.keySet()) { Map<URI, Integer> objectsToAddWithProtection = addedBlockObjectsByProtectionSystem.get(protectionSystemUri); log.info(String .format( "Generating exportGroupAddVolumes step for objects %s associated with protection system [%s] and storage system [%s]", objectsToAddWithProtection.keySet(), protectionSystemUri, storageUri)); waitFor = wfUtils.generateExportGroupAddVolumes(workflow, wfGroupId, waitFor, protectionSystemUri, export, objectsToAddWithProtection); // Reconcile the primary list of objects to export by removing all BlockSnapshots associated with the current // protection system. for (URI blockObjectUri : objectsToAddWithProtection.keySet()) { objectsToAdd.remove(blockObjectUri); } } } return waitFor; } /** * Extracts RP BlockSnapshot objects from a list of BlockObjects and sort them by protection system. If the * protection system is not set, the object is omitted from the sorted Map. * * @param blockObjectsMap * @return a Map of BlockSnapshot objects sorted by protection system */ private Map<URI, Map<URI, Integer>> sortSnapshotsByProtectionSystem(Map<URI, Integer> blockObjectsMap) { Map<URI, Map<URI, Integer>> protectionMap = new HashMap<URI, Map<URI, Integer>>(); if (blockObjectsMap != null) { for (URI blockObjectUri : blockObjectsMap.keySet()) { BlockObject bo = BlockObject.fetch(dbClient, blockObjectUri); // Only grab the RP BlockSnapshots if (bo != null && bo instanceof BlockSnapshot && !NullColumnValueGetter.isNullURI(bo.getProtectionController())) { if (protectionMap.get(bo.getProtectionController()) == null) { protectionMap.put(bo.getProtectionController(), new HashMap<URI, Integer>()); } protectionMap.get(bo.getProtectionController()).put(blockObjectUri, blockObjectsMap.get(blockObjectUri)); } } } return protectionMap; } }