/* * (non-Javadoc) * * @see * com.emc.storageos.volumecontroller.BlockStorageDevice#doWaitForSynchronized * (java.lang.Class, com.emc.storageos.db.client.model.StorageSystem, * java.net.URI, com.emc.storageos.volumecontroller.TaskCompleter) */ @Override public void doWaitForSynchronized( Class<? extends BlockObject> clazz, StorageSystem storageObj, URI target, TaskCompleter completer) { log.info("START waitForSynchronized for {}", target); try { Volume targetObj = dbClient.queryObject(Volume.class, target); // Source could be either Volume or BlockSnapshot BlockObject sourceObj = BlockObject.fetch(dbClient, targetObj.getAssociatedSourceVolume()); // We split the pair which causes the data to be synchronized. // When the split is complete that data is synchronized. HDSApiClient hdsApiClient = hdsApiFactory.getClient( HDSUtils.getHDSServerManagementServerInfo(storageObj), storageObj.getSmisUserName(), storageObj.getSmisPassword()); HDSApiProtectionManager hdsApiProtectionManager = hdsApiClient.getHdsApiProtectionManager(); String replicationGroupObjectID = hdsApiProtectionManager.getReplicationGroupObjectId(); ReplicationInfo replicationInfo = hdsApiProtectionManager.getReplicationInfoFromSystem( sourceObj.getNativeId(), targetObj.getNativeId()) .first; hdsApiProtectionManager.modifyShadowImagePair( replicationGroupObjectID, replicationInfo.getObjectID(), HDSApiProtectionManager.ShadowImageOperationType.split); // Update state in case we are waiting for synchronization // after creation of a new full copy that was not created // inactive. String state = targetObj.getReplicaState(); if (!ReplicationState.SYNCHRONIZED.name().equals(state)) { targetObj.setSyncActive(true); targetObj.setReplicaState(ReplicationState.SYNCHRONIZED.name()); dbClient.persistObject(targetObj); } // Queue job to wait for replication status to move to split. ControllerServiceImpl.enqueueJob( new QueueJob( new HDSReplicationSyncJob( storageObj.getId(), sourceObj.getNativeId(), targetObj.getNativeId(), ReplicationStatus.SPLIT, completer))); } catch (Exception e) { log.error("Exception occurred while waiting for synchronization", e); ServiceError serviceError = DeviceControllerException.errors.jobFailed(e); completer.error(dbClient, serviceError); } log.info("completed doWaitForSynchronized"); }
/** * Gets the VPlex cluster Id for a given VPlex virtual volume. * * @param virtualVolume * @return */ private String getVPlexClusterFromVolume(Volume virtualVolume) { String clusterId = null; if (virtualVolume != null && virtualVolume.getNativeId() != null) { String[] nativeIdSplit = virtualVolume.getNativeId().split("/"); clusterId = nativeIdSplit[2]; } return clusterId; }
private void handleBlockVolumeErrors(DbClient dbClient) { for (VolumeDescriptor volumeDescriptor : VolumeDescriptor.getDescriptors(_volumeDescriptors, VolumeDescriptor.Type.BLOCK_DATA)) { Volume volume = dbClient.queryObject(Volume.class, volumeDescriptor.getVolumeURI()); if (volume != null && (volume.getNativeId() == null || volume.getNativeId().equals(""))) { _log.info("No native id was present on volume {}, marking inactive", volume.getLabel()); dbClient.markForDeletion(volume); } } }
/* * (non-Javadoc) * * @see com.emc.storageos.volumecontroller.BlockStorageDevice#doExpandVolume(com.emc.storageos.db.client.model.StorageSystem, * com.emc.storageos.db.client.model.StoragePool, com.emc.storageos.db.client.model.Volume, java.lang.Long, * com.emc.storageos.volumecontroller.TaskCompleter) */ @Override public void doExpandVolume( StorageSystem storageSystem, StoragePool storagePool, Volume volume, Long size, TaskCompleter taskCompleter) throws DeviceControllerException { log.info( String.format( "Expand Volume Start - Array: %s, Pool: %s, Volume: %s, New size: %d", storageSystem.getSerialNumber(), storagePool.getNativeGuid(), volume.getLabel(), size)); try { HDSApiClient hdsApiClient = hdsApiFactory.getClient( HDSUtils.getHDSServerManagementServerInfo(storageSystem), storageSystem.getSmisUserName(), storageSystem.getSmisPassword()); String systemObjectID = HDSUtils.getSystemObjectID(storageSystem); String asyncTaskMessageId = null; if (volume.getThinlyProvisioned()) { asyncTaskMessageId = hdsApiClient.modifyThinVolume( systemObjectID, HDSUtils.getLogicalUnitObjectId(volume.getNativeId(), storageSystem), size); } if (null != asyncTaskMessageId) { HDSJob expandVolumeJob = new HDSVolumeExpandJob( asyncTaskMessageId, storageSystem.getId(), storagePool.getId(), taskCompleter, "ExpandVolume"); ControllerServiceImpl.enqueueJob(new QueueJob(expandVolumeJob)); } } catch (final InternalException e) { log.error("Problem in doExpandVolume: ", e); taskCompleter.error(dbClient, e); } catch (final Exception e) { log.error("Problem in doExpandVolume: ", e); ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doExpandVolume", e.getMessage()); taskCompleter.error(dbClient, serviceError); } log.info( String.format( "Expand Volume End - Array: %s, Pool: %s, Volume: %s", storageSystem.getSerialNumber(), storagePool.getNativeGuid(), volume.getLabel())); }
/** * Detaches volumes from initiators. * * @param storage the storage * @param volumes the volumes * @param initiators the initiators * @throws Exception the exception */ private void detachVolumesFromInitiators( StorageSystem storage, List<Volume> volumes, List<Initiator> initiators) throws Exception { CinderEndPointInfo ep = CinderUtils.getCinderEndPoint(storage.getActiveProviderURI(), dbClient); log.debug("Getting the cinder APi for the provider with id {}", storage.getActiveProviderURI()); CinderApi cinderApi = cinderApiFactory.getApi(storage.getActiveProviderURI(), ep); List<Initiator> iSCSIInitiators = new ArrayList<Initiator>(); List<Initiator> fcInitiators = new ArrayList<Initiator>(); splitInitiatorsByProtocol(initiators, iSCSIInitiators, fcInitiators); String host = getHostNameFromInitiators(initiators); Map<String, String[]> mapSettingVsValues = getFCInitiatorsArray(fcInitiators); String[] fcInitiatorsWwpns = mapSettingVsValues.get(WWPNS); String[] fcInitiatorsWwnns = mapSettingVsValues.get(WWNNS); for (Volume volume : volumes) { // cinder generated volume ID String volumeId = volume.getNativeId(); // for iSCSI for (Initiator initiator : iSCSIInitiators) { String initiatorPort = initiator.getInitiatorPort(); log.debug( String.format( "Detaching volume %s ( %s ) from initiator %s on Openstack cinder node", volumeId, volume.getId(), initiatorPort)); cinderApi.detachVolume(volumeId, initiatorPort, null, null, host); // TODO : Do not use Job to poll status till we figure out how // to get detach status. /* * CinderJob detachJob = new CinderDetachVolumeJob(volumeId, * volume.getLabel(), storage.getId(), * CinderConstants.ComponentType.volume.name(), ep, * taskCompleter); ControllerServiceImpl.enqueueJob(new * QueueJob(detachJob)); */ } // for FC if (fcInitiatorsWwpns.length > 0) { log.debug( String.format( "Detaching volume %s ( %s ) from initiator %s on Openstack cinder node", volumeId, volume.getId(), fcInitiatorsWwpns)); cinderApi.detachVolume(volumeId, null, fcInitiatorsWwpns, fcInitiatorsWwnns, host); } // If ITLs are added, remove them removeITLsFromVolume(volume); } }
@Override public void createSingleVolumeSnapshot( StorageSystem storage, URI snapshot, Boolean createInactive, Boolean readOnly, TaskCompleter taskCompleter) throws DeviceControllerException { try { BlockSnapshot snapshotObj = _dbClient.queryObject(BlockSnapshot.class, snapshot); Volume volume = _dbClient.queryObject(Volume.class, snapshotObj.getParent()); TenantOrg tenant = _dbClient.queryObject(TenantOrg.class, volume.getTenant().getURI()); String tenantName = tenant.getLabel(); String snapLabelToUse = _nameGenerator.generate( tenantName, snapshotObj.getLabel(), snapshot.toString(), '-', SmisConstants.MAX_SNAPSHOT_NAME_LENGTH); VNXeApiClient apiClient = getVnxeClient(storage); VNXeCommandJob job = apiClient.createLunSnap(volume.getNativeId(), snapLabelToUse); if (job != null) { ControllerServiceImpl.enqueueJob( new QueueJob( new VNXeBlockSnapshotCreateJob( job.getId(), storage.getId(), !createInactive, taskCompleter))); } } catch (VNXeException e) { _log.error("Create volume snapshot got the exception", e); taskCompleter.error(_dbClient, e); } catch (Exception ex) { _log.error("Create volume snapshot got the exception", ex); ServiceError error = DeviceControllerErrors.vnxe.jobFailed("CreateVolumeSnapshot", ex.getMessage()); taskCompleter.error(_dbClient, error); } }
/* * (non-Javadoc) * * @see com.emc.storageos.volumecontroller.BlockStorageDevice#doDeleteVolumes(com.emc.storageos.db.client.model.StorageSystem, * java.lang.String, java.util.List, com.emc.storageos.volumecontroller.TaskCompleter) */ @Override public void doDeleteVolumes( StorageSystem storageSystem, String opId, List<Volume> volumes, TaskCompleter taskCompleter) throws DeviceControllerException { try { StringBuilder logMsgBuilder = new StringBuilder( String.format("Delete Volume Start - Array:%s", storageSystem.getSerialNumber())); MultiVolumeTaskCompleter multiVolumeTaskCompleter = (MultiVolumeTaskCompleter) taskCompleter; Set<String> thickLogicalUnitIdList = new HashSet<String>(); Set<String> thinLogicalUnitIdList = new HashSet<String>(); HDSApiClient hdsApiClient = hdsApiFactory.getClient( HDSUtils.getHDSServerManagementServerInfo(storageSystem), storageSystem.getSmisUserName(), storageSystem.getSmisPassword()); String systemObjectId = HDSUtils.getSystemObjectID(storageSystem); log.info("volumes size: {}", volumes.size()); for (Volume volume : volumes) { logMsgBuilder.append(String.format("%nVolume:%s", volume.getLabel())); String logicalUnitObjectId = HDSUtils.getLogicalUnitObjectId(volume.getNativeId(), storageSystem); LogicalUnit logicalUnit = hdsApiClient.getLogicalUnitInfo(systemObjectId, logicalUnitObjectId); if (logicalUnit == null) { // related volume state (if any) has been deleted. skip // processing, if already deleted from array. log.info(String.format("Volume %s already deleted: ", volume.getNativeId())); volume.setInactive(true); dbClient.persistObject(volume); VolumeTaskCompleter deleteTaskCompleter = multiVolumeTaskCompleter.skipTaskCompleter(volume.getId()); deleteTaskCompleter.ready(dbClient); continue; } if (volume.getThinlyProvisioned()) { thinLogicalUnitIdList.add(logicalUnitObjectId); } else { thickLogicalUnitIdList.add(logicalUnitObjectId); } } log.info(logMsgBuilder.toString()); if (!multiVolumeTaskCompleter.isVolumeTaskCompletersEmpty()) { if (null != thickLogicalUnitIdList && !thickLogicalUnitIdList.isEmpty()) { String asyncThickLUsJobId = hdsApiClient.deleteThickLogicalUnits(systemObjectId, thickLogicalUnitIdList); if (null != asyncThickLUsJobId) { ControllerServiceImpl.enqueueJob( new QueueJob( new HDSDeleteVolumeJob( asyncThickLUsJobId, volumes.get(0).getStorageController(), taskCompleter))); } } if (null != thinLogicalUnitIdList && !thinLogicalUnitIdList.isEmpty()) { String asyncThinHDSJobId = hdsApiClient.deleteThinLogicalUnits(systemObjectId, thinLogicalUnitIdList); // Not sure whether this really works as tracking two jobs // in single operation. if (null != asyncThinHDSJobId) { ControllerServiceImpl.enqueueJob( new QueueJob( new HDSDeleteVolumeJob( asyncThinHDSJobId, volumes.get(0).getStorageController(), taskCompleter))); } } } else { // If we are here, there are no volumes to delete, we have // invoked ready() for the VolumeDeleteCompleter, and told // the multiVolumeTaskCompleter to skip these completers. // In this case, the multiVolumeTaskCompleter complete() // method will not be invoked and the result is that the // workflow that initiated this delete request will never // be updated. So, here we just call complete() on the // multiVolumeTaskCompleter to ensure the workflow status is // updated. multiVolumeTaskCompleter.ready(dbClient); } } catch (Exception e) { log.error("Problem in doDeleteVolume: ", e); ServiceError error = DeviceControllerErrors.hds.methodFailed("doDeleteVolume", e.getMessage()); taskCompleter.error(dbClient, error); } StringBuilder logMsgBuilder = new StringBuilder( String.format("Delete Volume End - Array: %s", storageSystem.getSerialNumber())); for (Volume volume : volumes) { logMsgBuilder.append(String.format("%nVolume:%s", volume.getLabel())); } log.info(logMsgBuilder.toString()); }
@Override public void doModifyVolumes( StorageSystem storage, StoragePool storagePool, String opId, List<Volume> volumes, TaskCompleter taskCompleter) throws DeviceControllerException { StringBuilder logMsgBuilder = new StringBuilder( String.format( "Modify Volume Start - Array:%s, Pool:%s", storage.getSerialNumber(), storagePool.getNativeGuid())); String systemObjectID = HDSUtils.getSystemObjectID(storage); for (Volume volume : volumes) { try { HDSApiClient hdsApiClient = hdsApiFactory.getClient( HDSUtils.getHDSServerManagementServerInfo(storage), storage.getSmisUserName(), storage.getSmisPassword()); logMsgBuilder.append( String.format( "%nVolume:%s , IsThinlyProvisioned: %s, tieringPolicy: %s", volume.getLabel(), volume.getThinlyProvisioned(), volume.getAutoTieringPolicyUri())); LogicalUnit logicalUnit = hdsApiClient.getLogicalUnitInfo( systemObjectID, HDSUtils.getLogicalUnitObjectId(volume.getNativeId(), storage)); String policyName = ControllerUtils.getAutoTieringPolicyName(volume.getId(), dbClient); String autoTierPolicyName = null; if (policyName.equals(Constants.NONE)) { autoTierPolicyName = null; } else { autoTierPolicyName = HitachiTieringPolicy.getPolicy( policyName.replaceAll( HDSConstants.SLASH_OPERATOR, HDSConstants.UNDERSCORE_OPERATOR)) .getKey(); } if (null != logicalUnit && null != logicalUnit.getLdevList() && !logicalUnit.getLdevList().isEmpty()) { Iterator<LDEV> ldevItr = logicalUnit.getLdevList().iterator(); if (ldevItr.hasNext()) { LDEV ldev = ldevItr.next(); String asyncMessageId = hdsApiClient.modifyThinVolumeTieringPolicy( systemObjectID, logicalUnit.getObjectID(), ldev.getObjectID(), autoTierPolicyName); if (null != asyncMessageId) { HDSJob modifyHDSJob = new HDSModifyVolumeJob( asyncMessageId, volume.getStorageController(), taskCompleter, HDSModifyVolumeJob.VOLUME_MODIFY_JOB); ControllerServiceImpl.enqueueJob(new QueueJob(modifyHDSJob)); } } } else { String errorMsg = String.format("No LDEV's found for volume: %s", volume.getId()); log.info(errorMsg); ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doModifyVolumes", errorMsg); taskCompleter.error(dbClient, serviceError); } } catch (final InternalException e) { log.error("Problem in doModifyVolumes: ", e); taskCompleter.error(dbClient, e); } catch (final Exception e) { log.error("Problem in doModifyVolumes: ", e); ServiceError serviceError = DeviceControllerErrors.hds.methodFailed("doModifyVolumes", e.getMessage()); taskCompleter.error(dbClient, serviceError); } } }
/** * Attaches volumes to initiators. * * @param storage the storage * @param volumes the volumes * @param initiators the initiators * @param volumeToTargetLunMap the volume to target lun map * @throws Exception the exception */ private void attachVolumesToInitiators( StorageSystem storage, List<Volume> volumes, List<Initiator> initiators, Map<URI, Integer> volumeToTargetLunMap, Map<Volume, Map<String, List<String>>> volumeToInitiatorTargetMap, ExportMask exportMask) throws Exception { CinderEndPointInfo ep = CinderUtils.getCinderEndPoint(storage.getActiveProviderURI(), dbClient); log.debug( "Getting the cinder APi for the provider with id {}", storage.getActiveProviderURI()); CinderApi cinderApi = cinderApiFactory.getApi(storage.getActiveProviderURI(), ep); List<Initiator> iSCSIInitiators = new ArrayList<Initiator>(); List<Initiator> fcInitiators = new ArrayList<Initiator>(); splitInitiatorsByProtocol(initiators, iSCSIInitiators, fcInitiators); String host = getHostNameFromInitiators(initiators); Map<String, String[]> mapSettingVsValues = getFCInitiatorsArray(fcInitiators); String[] fcInitiatorsWwpns = mapSettingVsValues.get(WWPNS); String[] fcInitiatorsWwnns = mapSettingVsValues.get(WWNNS); for (Volume volume : volumes) { // cinder generated volume ID String volumeId = volume.getNativeId(); int targetLunId = -1; VolumeAttachResponse attachResponse = null; // for iSCSI for (Initiator initiator : iSCSIInitiators) { String initiatorPort = initiator.getInitiatorPort(); log.debug( String.format( "Attaching volume %s ( %s ) to initiator %s on Openstack cinder node", volumeId, volume.getId(), initiatorPort)); attachResponse = cinderApi.attachVolume(volumeId, initiatorPort, null, null, host); log.info("Got response : {}", attachResponse.connection_info.toString()); targetLunId = attachResponse.connection_info.data.target_lun; } // for FC if (fcInitiatorsWwpns.length > 0) { log.debug( String.format( "Attaching volume %s ( %s ) to initiators %s on Openstack cinder node", volumeId, volume.getId(), fcInitiatorsWwpns)); attachResponse = cinderApi.attachVolume(volumeId, null, fcInitiatorsWwpns, fcInitiatorsWwnns, host); log.info("Got response : {}", attachResponse.connection_info.toString()); targetLunId = attachResponse.connection_info.data.target_lun; Map<String, List<String>> initTargetMap = attachResponse.connection_info.data.initiator_target_map; if (null != initTargetMap && !initTargetMap.isEmpty()) { volumeToInitiatorTargetMap.put( volume, attachResponse.connection_info.data.initiator_target_map); } } volumeToTargetLunMap.put(volume.getId(), targetLunId); // After the successful export, create or modify the storage ports CinderStoragePortOperations storagePortOperationsInstance = CinderStoragePortOperations.getInstance(storage, dbClient); storagePortOperationsInstance.invoke(attachResponse); } // Add ITLs to volume objects storeITLMappingInVolume(volumeToTargetLunMap, exportMask); }