/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.volumecontroller.impl.block; import java.net.URI; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.Controller; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.model.DiscoveredSystemObject; import com.emc.storageos.exceptions.DeviceControllerException; import com.emc.storageos.plugins.common.Constants; import com.emc.storageos.volumecontroller.ControllerException; import com.emc.storageos.volumecontroller.impl.ControllerServiceImpl; import com.emc.storageos.workflow.Workflow; import com.emc.storageos.workflow.WorkflowException; import com.emc.storageos.workflow.WorkflowService; import com.emc.storageos.workflow.WorkflowStepCompleter; public class ExportWorkflowEntryPoints implements Controller { private static volatile String _beanName; private static final Logger _log = LoggerFactory.getLogger(ExportWorkflowEntryPoints.class); private Map<String, MaskingOrchestrator> _orchestratorMap; private DbClient _dbClient; public ExportWorkflowEntryPoints() { } public void setName(String beanName) { _beanName = beanName; } public void setDbClient(DbClient dbc) { _dbClient = dbc; } public void setOrchestratorMap(Map<String, MaskingOrchestrator> orchestratorMap) { _orchestratorMap = orchestratorMap; } public MaskingOrchestrator getOrchestrator(String deviceType) { MaskingOrchestrator orchestrator = _orchestratorMap.get(deviceType); if (orchestrator == null) { // we will use orchestrator for external device orchestrator = _orchestratorMap.get(Constants.EXTERNALDEVICE); if (orchestrator == null) { throw DeviceControllerException.exceptions.invalidSystemType(deviceType); } } return orchestrator; } public static ExportWorkflowEntryPoints getInstance() { return (ExportWorkflowEntryPoints) ControllerServiceImpl.getBean(_beanName); } // ================== Static methods to create Workflow.Method // ====================== public static Workflow.Method exportGroupCreateMethod(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, List<URI> initiatorURIs) { return new Workflow.Method("exportGroupCreate", storageURI, exportGroupURI, volumeMap, initiatorURIs); } public static Workflow.Method exportGroupUpdateMethod(URI storageURI, URI exportGroupURI, Workflow storageWorkflow) { return new Workflow.Method("exportGroupUpdate", storageURI, exportGroupURI, storageWorkflow); } public static Workflow.Method exportGroupDeleteMethod(URI storageURI, URI exportGroupURI) { return new Workflow.Method("exportGroupDelete", storageURI, exportGroupURI); } public static Workflow.Method exportAddVolumesMethod(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap) { return new Workflow.Method("exportAddVolumes", storageURI, exportGroupURI, volumeMap); } public static Workflow.Method exportRemoveVolumesMethod(URI storageURI, URI exportGroupURI, List<URI> volumes) { return new Workflow.Method("exportRemoveVolumes", storageURI, exportGroupURI, volumes); } public static Workflow.Method exportAddInitiatorsMethod(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs) { return new Workflow.Method("exportAddInitiators", storageURI, exportGroupURI, initiatorURIs); } public static Workflow.Method exportRemoveInitiatorsMethod(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs) { return new Workflow.Method("exportRemoveInitiators", storageURI, exportGroupURI, initiatorURIs); } public static Workflow.Method exportGroupChangePathParamsMethod(URI storageURI, URI exportGroupURI, URI volumeURI) { return new Workflow.Method("exportGroupChangePathParams", storageURI, exportGroupURI, volumeURI); } public static Workflow.Method exportChangePolicyAndLimitsMethod(URI storageURI, URI exportMaskURI, URI exportGroupURI, List<URI> volumeURIs, URI newVpoolURI, boolean rollback) { return new Workflow.Method("exportChangePolicyAndLimits", storageURI, exportMaskURI, exportGroupURI, volumeURIs, newVpoolURI, rollback); } public static Workflow.Method changeAutoTieringPolicyMethod(URI storageURI, List<URI> volumeURIs, URI newVpoolURI, boolean rollback) { return new Workflow.Method("changeAutoTieringPolicy", storageURI, volumeURIs, newVpoolURI, rollback); } public static Workflow.Method exportRemovePathsMethod(URI storageURI, URI exportGroup, URI varray, URI exportMask, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>>removedPaths) { return new Workflow.Method("exportRemovePathsStep", storageURI, exportGroup, varray, exportMask, adjustedPaths, removedPaths); } public static Workflow.Method exportAddPathsMethod(URI storageURI, URI exportGroup, URI varray, URI exportMask, Map<URI, List<URI>>adjustedPaths, Map<URI, List<URI>>removedPaths) { return new Workflow.Method("exportAddPathsStep", storageURI, exportGroup, varray, exportMask, adjustedPaths, removedPaths); } // ====================== Methods to call Masking Orchestrator // ====================== public void exportGroupCreate(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, List<URI> initiatorURIs, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); // Check to see if we are re-entering this step after a previous execution already created the export // workflow. // If this is the case, do not create it again. final String workflowKey = "exportGroupCreate"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupCreate(storageURI, exportGroupURI, initiatorURIs, volumeMap, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions.exportGroupCreateFailed(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } /** * This function is called from a main workflow that performs updated to an export * group on may storage arrays. This step performs the updates for one array. It * simply invokes the workflow that was pre-created that will do the needed adds/removes, * * @param storageURI * the storage array of the masks to be updated * @param exportGroupURI * the export group URI * @param storageWorkflow * the pre-created workflow for this storage array. * @param token * the task Id * @throws ControllerException * when an exception is encountered in the workflow execution. */ public void exportGroupUpdate(URI storageURI, URI exportGroupURI, Workflow storageWorkflow, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportGroupUpdate"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupUpdate(storageURI, exportGroupURI, storageWorkflow, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportGroupUpdateFailed(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } public void exportGroupDelete(URI storageURI, URI exportGroupURI, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportGroupDelete"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupDelete(storageURI, exportGroupURI, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportGroupDeleteFailed(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } public void exportAddVolumes(URI storageURI, URI exportGroupURI, Map<URI, Integer> volumeMap, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportAddVolumes"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupAddVolumes(storageURI, exportGroupURI, volumeMap, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportAddVolumes(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } public void exportRemoveVolumes(URI storageURI, URI exportGroupURI, List<URI> volumes, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportRemoveVolumes"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupRemoveVolumes(storageURI, exportGroupURI, volumes, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportRemoveVolumes(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } public void exportAddInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportAddInitiators"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupAddInitiators(storageURI, exportGroupURI, initiatorURIs, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportAddInitiators(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } public void exportRemoveInitiators(URI storageURI, URI exportGroupURI, List<URI> initiatorURIs, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportRemoveInitiators"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupRemoveInitiators(storageURI, exportGroupURI, initiatorURIs, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportRemoveInitiators(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } /** * Changes the PathParams (e.g. maxPaths, pathsPerInitiator) for a volume in all the * ExportMasks containing that volume in an Export Group. * * @param storageURI * -- URI of storage system containing the volume. * @param exportGroupURI * -- URI of Export Group to be processed. * @param volumeURI * -- URI of volume that is chaning VPool parameters for PathParams * @param token * -- String for completers. * @throws ControllerException */ public void exportGroupChangePathParams(URI storageURI, URI exportGroupURI, URI volumeURI, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "exportChangeParams"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.exportGroupChangePathParams(storageURI, exportGroupURI, volumeURI, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportGroupChangePathParams(e); WorkflowStepCompleter.stepFailed(token, exception); } } public void exportChangePolicyAndLimits(URI storageURI, URI exportMaskURI, URI exportGroupURI, List<URI> volumeURIs, URI newVpoolURI, boolean rollback, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); ((AbstractBasicMaskingOrchestrator) orchestrator) .exportGroupChangePolicyAndLimits(storageURI, exportMaskURI, exportGroupURI, volumeURIs, newVpoolURI, rollback, token); } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportChangePolicyAndLimits(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } public void changeAutoTieringPolicy(URI storageURI, List<URI> volumeURIs, URI newVpoolURI, boolean rollback, String token) throws ControllerException { try { WorkflowStepCompleter.stepExecuting(token); DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); ((AbstractBasicMaskingOrchestrator) orchestrator) .changeAutoTieringPolicy(storageURI, volumeURIs, newVpoolURI, rollback, token); } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .changeAutoTieringPolicy(e); WorkflowStepCompleter.stepFailed(token, exception); throw exception; } } /** * No-op workflow step to allow rollback to continue. * * @param stepId The workflow step ID. * @throws WorkflowException */ public void rollbackMethodNull(String stepId) throws WorkflowException { WorkflowStepCompleter.stepSucceded(stepId); } public void exportAddPathsStep(URI storageURI, URI exportGroupURI, URI varray, URI exportMaskURI, Map<URI, List<URI>>adjustedPaths, Map<URI, List<URI>>removePaths, String token) throws ControllerException{ try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "addPaths"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.portRebalance(storageURI, exportGroupURI, varray, exportMaskURI, adjustedPaths, removePaths, true, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } else { _log.info("Sub-workflow for exportAddPathsStep was already created"); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportGroupPortRebalanceError(e); WorkflowStepCompleter.stepFailed(token, exception); } } public void exportRemovePathsStep(URI storageURI, URI exportGroupURI, URI varray, URI exportMaskURI, Map<URI, List<URI>> adjustedPaths, Map<URI, List<URI>>removePaths, String token) throws ControllerException{ try { WorkflowStepCompleter.stepExecuting(token); final String workflowKey = "removePaths"; if (!WorkflowService.getInstance().hasWorkflowBeenCreated(token, workflowKey)) { DiscoveredSystemObject storage = ExportWorkflowUtils.getStorageSystem(_dbClient, storageURI); MaskingOrchestrator orchestrator = getOrchestrator(storage.getSystemType()); orchestrator.portRebalance(storageURI, exportGroupURI, varray, exportMaskURI, adjustedPaths, removePaths, false, token); // Mark this workflow as created/executed so we don't do it again on retry/resume WorkflowService.getInstance().markWorkflowBeenCreated(token, workflowKey); } else { _log.info("Sub-workflow for exportRemovePathsStep was already created"); } } catch (Exception e) { DeviceControllerException exception = DeviceControllerException.exceptions .exportGroupPortRebalanceError(e); WorkflowStepCompleter.stepFailed(token, exception); } } }