@Override public void deleteOrRemoveVolumesFromExportMask( URI arrayURI, URI exportGroupURI, URI exportMaskURI, List<URI> volumes, List<URI> initiatorURIs, TaskCompleter completer, String stepId) { try { StorageSystem array = _dbClient.queryObject(StorageSystem.class, arrayURI); BlockStorageDevice device = _blockController.getDevice(array.getSystemType()); ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); WorkflowStepCompleter.stepExecuting(stepId); // If the exportMask isn't found, or has been deleted, nothing to do. if (exportMask == null || exportMask.getInactive()) { _log.info(String.format("ExportMask %s inactive, returning success", exportMaskURI)); WorkflowStepCompleter.stepSucceded(stepId); return; } // Protect concurrent operations by locking {host, array} dupple. // Lock will be released when workflow step completes. List<String> lockKeys = ControllerLockingUtil.getHostStorageLockKeys( _dbClient, ExportGroupType.Host, StringSetUtil.stringSetToUriList(exportMask.getInitiators()), arrayURI); getWorkflowService() .acquireWorkflowStepLocks( stepId, lockKeys, LockTimeoutValue.get(LockType.VPLEX_BACKEND_EXPORT)); // Make sure the completer will complete the workflow. This happens on rollback case. if (!completer.getOpId().equals(stepId)) { completer.setOpId(stepId); } // Refresh the ExportMask exportMask = refreshExportMask(array, device, exportMask); // Determine if we're deleting the last volume in the mask. StringMap maskVolumesMap = exportMask.getVolumes(); Set<String> remainingVolumes = new HashSet<String>(); List<URI> passedVolumesInMask = new ArrayList<>(volumes); if (maskVolumesMap != null) { remainingVolumes.addAll(maskVolumesMap.keySet()); } for (URI volume : volumes) { remainingVolumes.remove(volume.toString()); // Remove any volumes from the volume list that are no longer // in the export mask. When a failure occurs removing a backend // volume from a mask, the rollback method will try and remove it // again. However, in the case of a distributed volume, one side // may have succeeded, so we will try and remove it again. Previously, // this was not a problem. However, new validation exists at the // block level that checks to make sure the volume to remove is // actually in the mask, which now causes a failure when you remove // it a second time. So, we check here and remove any volumes that // are not in the mask to handle this condition. if ((maskVolumesMap != null) && (!maskVolumesMap.keySet().contains(volume.toString()))) { passedVolumesInMask.remove(volume); } } // None of the volumes is in the export mask, so we are done. if (passedVolumesInMask.isEmpty()) { _log.info( "None of these volumes {} are in export mask {}", volumes, exportMask.forDisplay()); WorkflowStepCompleter.stepSucceded(stepId); return; } // If it is last volume and there are no existing volumes, delete the ExportMask. if (remainingVolumes.isEmpty() && !exportMask.hasAnyExistingVolumes()) { device.doExportDelete(array, exportMask, passedVolumesInMask, initiatorURIs, completer); } else { List<Initiator> initiators = null; if (initiatorURIs != null && !initiatorURIs.isEmpty()) { initiators = _dbClient.queryObject(Initiator.class, initiatorURIs); } device.doExportRemoveVolumes(array, exportMask, passedVolumesInMask, initiators, completer); } } catch (Exception ex) { _log.error("Failed to delete or remove volumes to export mask for vnx: ", ex); VPlexApiException vplexex = DeviceControllerExceptions.vplex.addStepsForCreateVolumesFailed(ex); WorkflowStepCompleter.stepFailed(stepId, vplexex); } }
@Override public void deleteOrRemoveVolumesFromExportMask( URI arrayURI, URI exportGroupURI, URI exportMaskURI, List<URI> volumes, TaskCompleter completer, String stepId) { try { WorkflowStepCompleter.stepExecuting(stepId); StorageSystem array = _dbClient.queryObject(StorageSystem.class, arrayURI); BlockStorageDevice device = _blockController.getDevice(array.getSystemType()); ExportMask exportMask = _dbClient.queryObject(ExportMask.class, exportMaskURI); // If the exportMask isn't found, or has been deleted, nothing to do. if (exportMask == null || exportMask.getInactive()) { _log.info(String.format("ExportMask %s inactive, returning success", exportMaskURI)); WorkflowStepCompleter.stepSucceded(stepId); return; } // Protect concurrent operations by locking {host, array} dupple. // Lock will be released when work flow step completes. List<String> lockKeys = ControllerLockingUtil.getHostStorageLockKeys( _dbClient, ExportGroupType.Host, StringSetUtil.stringSetToUriList(exportMask.getInitiators()), arrayURI); getWorkflowService() .acquireWorkflowStepLocks( stepId, lockKeys, LockTimeoutValue.get(LockType.VPLEX_BACKEND_EXPORT)); // Make sure the completer will complete the work flow. This happens on roll back case. if (!completer.getOpId().equals(stepId)) { completer.setOpId(stepId); } // Refresh the ExportMask exportMask = refreshExportMask(array, device, exportMask); // Determine if we're deleting the last volume. Set<String> remainingVolumes = new HashSet<String>(); if (exportMask.getVolumes() != null) { remainingVolumes.addAll(exportMask.getVolumes().keySet()); } for (URI volume : volumes) { remainingVolumes.remove(volume.toString()); } // If it is last volume, delete the ExportMask. if (remainingVolumes.isEmpty() && (exportMask.getExistingVolumes() == null || exportMask.getExistingVolumes().isEmpty())) { _log.debug( String.format( "Calling doExportGroupDelete on the device %s", array.getId().toString())); device.doExportGroupDelete(array, exportMask, completer); } else { _log.debug( String.format( "Calling doExportRemoveVolumes on the device %s", array.getId().toString())); device.doExportRemoveVolumes(array, exportMask, volumes, completer); } } catch (Exception ex) { _log.error("Failed to delete or remove volumes to export mask for cinder: ", ex); VPlexApiException vplexex = DeviceControllerExceptions.vplex.addStepsForDeleteVolumesFailed(ex); WorkflowStepCompleter.stepFailed(stepId, vplexex); } }