@Override protected Tasks<TaskResourceRep> doExecute() throws Exception { VolumeGroupUpdateParam input = new VolumeGroupUpdateParam(); VolumeGroupVolumeList removeVolumesList = new VolumeGroupVolumeList(); removeVolumesList.setVolumes(volumeIds); input.setRemoveVolumesList(removeVolumesList); TaskList taskList = getClient().application().updateApplication(applicationId, input); return new Tasks<TaskResourceRep>( getClient().auth().getClient(), taskList.getTaskList(), TaskResourceRep.class); }
/** * Allows the user to remove a storage system from the list of decommisioned resources After that * corresponding provider should be able to be rescanned and add this system back to the list of * managed systems. * * @param id id the URN of a ViPR Storage provider * @param param The storage system details. * @brief removes the storage system from the list of decommissioned systems and rescans the * provider. * @return An asynchronous task corresponding to the scan job scheduled for the provider. * @throws BadRequestException When the system type is not valid or a storage system with the same * native guid already exists. * @throws com.emc.storageos.db.exceptions.DatabaseException When an error occurs querying the * database. * @throws ControllerException When an error occurs discovering the storage system. */ @PUT @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @CheckPermission(roles = {Role.SYSTEM_ADMIN}) @Path("/{id}/storage-systems") public TaskResourceRep addStorageSystem( @PathParam("id") URI id, StorageSystemProviderRequestParam param) throws ControllerException { TaskResourceRep taskRep; URIQueryResultList list = new URIQueryResultList(); ArgValidator.checkFieldNotEmpty(param.getSystemType(), "system_type"); if (!StorageSystem.Type.isProviderStorageSystem( DiscoveredDataObject.Type.valueOf(param.getSystemType()))) { throw APIException.badRequests.cannotAddStorageSystemTypeToStorageProvider( param.getSystemType()); } StorageProvider provider = _dbClient.queryObject(StorageProvider.class, id); ArgValidator.checkEntityNotNull(provider, id, isIdEmbeddedInURL(id)); ArgValidator.checkFieldNotEmpty(param.getSerialNumber(), "serialNumber"); String nativeGuid = NativeGUIDGenerator.generateNativeGuid(param.getSystemType(), param.getSerialNumber()); // check for duplicate StorageSystem. List<StorageSystem> systems = CustomQueryUtility.getActiveStorageSystemByNativeGuid(_dbClient, nativeGuid); if (systems != null && !systems.isEmpty()) { throw APIException.badRequests.invalidParameterProviderStorageSystemAlreadyExists( "nativeGuid", nativeGuid); } int cleared = DecommissionedResource.removeDecommissionedFlag(_dbClient, nativeGuid, StorageSystem.class); if (cleared == 0) { log.info("Cleared {} decommissioned systems", cleared); } else { log.info("Did not find any decommissioned systems to clear. Continue to scan."); } ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1); String taskId = UUID.randomUUID().toString(); tasks.add(new AsyncTask(StorageProvider.class, provider.getId(), taskId)); BlockController controller = getController(BlockController.class, provider.getInterfaceType()); DiscoveredObjectTaskScheduler scheduler = new DiscoveredObjectTaskScheduler(_dbClient, new ScanJobExec(controller)); TaskList taskList = scheduler.scheduleAsyncTasks(tasks); return taskList.getTaskList().listIterator().next(); }
/** * Vcenter Discovery * * @param vcenter the Vcenter to be discovered. provided, a new taskId is generated. * @return the task used to track the discovery job */ protected TaskResourceRep doDiscoverVcenter(Vcenter vcenter) { ComputeSystemController controller = getController(ComputeSystemController.class, "vcenter"); DiscoveredObjectTaskScheduler scheduler = new DiscoveredObjectTaskScheduler(_dbClient, new DiscoverJobExec(controller)); String taskId = UUID.randomUUID().toString(); ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1); tasks.add(new AsyncTask(Vcenter.class, vcenter.getId(), taskId)); TaskList taskList = scheduler.scheduleAsyncTasks(tasks); TaskResourceRep taskResourceRep = taskList.getTaskList().iterator().next(); updateTaskTenant(taskResourceRep); return taskResourceRep; }
@POST @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) @CheckPermission(roles = {Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN}) public TaskResourceRep registerStorageProvider(StorageProviderCreateParam param) throws ControllerException { ArgValidator.checkFieldNotEmpty(param.getName(), "name"); checkForDuplicateName(param.getName(), StorageProvider.class); ArgValidator.checkFieldNotEmpty(param.getIpAddress(), "ip_address"); ArgValidator.checkFieldNotNull(param.getPortNumber(), "port_number"); ArgValidator.checkFieldNotEmpty(param.getUserName(), "user_name"); ArgValidator.checkFieldNotEmpty(param.getPassword(), "password"); ArgValidator.checkFieldRange(param.getPortNumber(), 1, 65535, "port_number"); ArgValidator.checkFieldValueFromEnum( param.getInterfaceType(), "interface_type", StorageProvider.InterfaceType.class); String providerKey = param.getIpAddress() + "-" + param.getPortNumber(); List<StorageProvider> providers = CustomQueryUtility.getActiveStorageProvidersByProviderId(_dbClient, providerKey); if (providers != null && !providers.isEmpty()) { throw APIException.badRequests.invalidParameterStorageProviderAlreadyRegistered(providerKey); } // Set the SSL parameter Boolean useSSL = param.getUseSSL(); if (useSSL == null) { useSSL = StorageProviderCreateParam.USE_SSL_DEFAULT; } StorageProvider provider = new StorageProvider(); provider.setId(URIUtil.createId(StorageProvider.class)); provider.setLabel(param.getName()); provider.setIPAddress(param.getIpAddress()); provider.setPortNumber(param.getPortNumber()); provider.setUserName(param.getUserName()); provider.setPassword(param.getPassword()); provider.setUseSSL(useSSL); provider.setInterfaceType(param.getInterfaceType()); provider.setRegistrationStatus(RegistrationStatus.REGISTERED.toString()); provider.setConnectionStatus(ConnectionStatus.INITIALIZING.name()); provider.setSecondaryUsername(param.getSecondaryUsername()); provider.setSecondaryPassword(param.getSecondaryPassword()); provider.setElementManagerURL(param.getElementManagerURL()); if (param.getSioCLI() != null) { // TODO: Validate the input? provider.addKey(StorageProvider.GlobalKeys.SIO_CLI.name(), param.getSioCLI()); } if (StorageProvider.InterfaceType.ibmxiv.name().equalsIgnoreCase(provider.getInterfaceType())) { provider.setManufacturer("IBM"); } _dbClient.createObject(provider); auditOp( OperationTypeEnum.REGISTER_STORAGEPROVIDER, true, null, provider.getLabel(), provider.getId().toString(), provider.getIPAddress(), provider.getPortNumber(), provider.getUserName(), provider.getInterfaceType()); ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1); String taskId = UUID.randomUUID().toString(); tasks.add(new AsyncTask(StorageProvider.class, provider.getId(), taskId)); BlockController controller = getController(BlockController.class, provider.getInterfaceType()); log.debug("controller.getClass().getName() :{}", controller.getClass().getName()); log.debug("controller.getClass().getSimpleName() :{}", controller.getClass().getSimpleName()); /** * Creates MonitoringJob token for vnxblock/vmax, hds, cinder and IBM XIV device on zooKeeper * queue */ // TODO : If all interface types have monitoring impl class added (scaleIO is missing), // this check can be removed. String interfaceType = provider.getInterfaceType(); if (StorageProvider.InterfaceType.hicommand.name().equalsIgnoreCase(interfaceType) || StorageProvider.InterfaceType.smis.name().equalsIgnoreCase(interfaceType) || StorageProvider.InterfaceType.cinder.name().equalsIgnoreCase(interfaceType) || StorageProvider.InterfaceType.ibmxiv.name().equalsIgnoreCase(interfaceType)) { controller.startMonitoring( new AsyncTask(StorageProvider.class, provider.getId(), taskId), getSystemTypeByInterface(interfaceType)); } DiscoveredObjectTaskScheduler scheduler = new DiscoveredObjectTaskScheduler(_dbClient, new ScanJobExec(controller)); TaskList taskList = scheduler.scheduleAsyncTasks(tasks); return taskList.getTaskList().listIterator().next(); }
/** {@inheritDoc} */ @Override public TaskList resynchronizeCopy(Volume sourceVolume, Volume fullCopyVolume) { // Create the task list. TaskList taskList = new TaskList(); // Create a unique task id. String taskId = UUID.randomUUID().toString(); // If the source is in a CG, then we will resynchronize the corresponding // full copies for all the volumes in the CG. Since we did not allow // full copies for volumes or snaps in CGs prior to Jedi, there should // be a full copy for all volumes in the CG. Map<URI, Volume> fullCopyMap = getFullCopySetMap(sourceVolume, fullCopyVolume); Set<URI> fullCopyURIs = fullCopyMap.keySet(); // Get the storage system for the source volume. StorageSystem sourceSystem = _dbClient.queryObject(StorageSystem.class, sourceVolume.getStorageController()); URI sourceSystemURI = sourceSystem.getId(); // Create the resynchronize task on the full copy volumes. for (URI fullCopyURI : fullCopyURIs) { Operation op = _dbClient.createTaskOpStatus( Volume.class, fullCopyURI, taskId, ResourceOperationTypeEnum.RESYNCHRONIZE_VOLUME_FULL_COPY); fullCopyMap.get(fullCopyURI).getOpStatus().put(taskId, op); TaskResourceRep fullCopyVolumeTask = TaskMapper.toTask(fullCopyMap.get(fullCopyURI), taskId, op); taskList.getTaskList().add(fullCopyVolumeTask); } // Invoke the controller. try { VPlexController controller = getController(VPlexController.class, DiscoveredDataObject.Type.vplex.toString()); controller.resyncFullCopy(sourceSystemURI, new ArrayList<URI>(fullCopyURIs), taskId); } catch (InternalException ie) { s_logger.error("Controller error", ie); // Update the status for the VPLEX volume copies and their // corresponding tasks. for (Volume vplexFullCopy : fullCopyMap.values()) { Operation op = vplexFullCopy.getOpStatus().get(taskId); if (op != null) { op.error(ie); vplexFullCopy.getOpStatus().updateTaskStatus(taskId, op); _dbClient.persistObject(vplexFullCopy); for (TaskResourceRep task : taskList.getTaskList()) { if (task.getResource().getId().equals(vplexFullCopy.getId())) { task.setState(op.getStatus()); task.setMessage(op.getMessage()); break; } } } } } return taskList; }
/** {@inheritDoc} */ @Override public TaskList detach(BlockObject fcSourceObj, Volume fullCopyVolume) { // If full copy volume is already detached or was never // activated, return detach action is completed successfully // as done in base class. Otherwise, send detach full copy // request to controller. TaskList taskList = new TaskList(); String taskId = UUID.randomUUID().toString(); if ((BlockFullCopyUtils.isFullCopyDetached(fullCopyVolume, _dbClient)) || (BlockFullCopyUtils.isFullCopyInactive(fullCopyVolume, _dbClient))) { super.detach(fcSourceObj, fullCopyVolume); } else { // You cannot create a full copy of a VPLEX snapshot, so // the source will be a volume. Volume sourceVolume = (Volume) fcSourceObj; // If the source is in a CG, then we will detach the corresponding // full copies for all the volumes in the CG. Since we did not allow // full copies for volumes or snaps in CGs prior to Jedi, there should // be a full copy for all volumes in the CG. Map<URI, Volume> fullCopyMap = getFullCopySetMap(sourceVolume, fullCopyVolume); Set<URI> fullCopyURIs = fullCopyMap.keySet(); // Get the storage system for the source volume. StorageSystem sourceSystem = _dbClient.queryObject(StorageSystem.class, sourceVolume.getStorageController()); URI sourceSystemURI = sourceSystem.getId(); // Create the detach task on the full copy volumes. for (URI fullCopyURI : fullCopyURIs) { Operation op = _dbClient.createTaskOpStatus( Volume.class, fullCopyURI, taskId, ResourceOperationTypeEnum.DETACH_VOLUME_FULL_COPY); fullCopyMap.get(fullCopyURI).getOpStatus().put(taskId, op); TaskResourceRep fullCopyVolumeTask = TaskMapper.toTask(fullCopyMap.get(fullCopyURI), taskId, op); taskList.getTaskList().add(fullCopyVolumeTask); } // Invoke the controller. try { VPlexController controller = getController(VPlexController.class, DiscoveredDataObject.Type.vplex.toString()); controller.detachFullCopy(sourceSystemURI, new ArrayList<URI>(fullCopyURIs), taskId); } catch (InternalException ie) { s_logger.error("Controller error", ie); // Update the status for the VPLEX volume copies and their // corresponding tasks. for (Volume vplexFullCopy : fullCopyMap.values()) { Operation op = vplexFullCopy.getOpStatus().get(taskId); if (op != null) { op.error(ie); vplexFullCopy.getOpStatus().updateTaskStatus(taskId, op); _dbClient.persistObject(vplexFullCopy); for (TaskResourceRep task : taskList.getTaskList()) { if (task.getResource().getId().equals(vplexFullCopy.getId())) { task.setState(op.getStatus()); task.setMessage(op.getMessage()); break; } } } } } } return taskList; }
/** {@inheritDoc} */ @Override public TaskList create( List<BlockObject> fcSourceObjList, VirtualArray varray, String name, boolean createInactive, int count, String taskId) { // Populate the descriptors list with all volumes required // to create the VPLEX volume copies. int sourceCounter = 0; URI vplexSrcSystemId = null; TaskList taskList = new TaskList(); List<Volume> vplexCopyVolumes = new ArrayList<Volume>(); List<VolumeDescriptor> volumeDescriptors = new ArrayList<VolumeDescriptor>(); List<BlockObject> sortedSourceObjectList = sortFullCopySourceList(fcSourceObjList); for (BlockObject fcSourceObj : sortedSourceObjectList) { URI fcSourceURI = fcSourceObj.getId(); if (URIUtil.isType(fcSourceURI, BlockSnapshot.class)) { // Full copy of snapshots is not supported for VPLEX. return super.create(sortedSourceObjectList, varray, name, createInactive, count, taskId); } Volume vplexSrcVolume = (Volume) fcSourceObj; String copyName = name + (sortedSourceObjectList.size() > 1 ? "-" + ++sourceCounter : ""); // Create a volume descriptor for the source VPLEX volume being copied. // and add it to the descriptors list. Be sure to identify this VPLEX // volume as the source volume being copied. vplexSrcSystemId = fcSourceObj.getStorageController(); VolumeDescriptor vplexSrcVolumeDescr = new VolumeDescriptor( VolumeDescriptor.Type.VPLEX_VIRT_VOLUME, vplexSrcSystemId, fcSourceURI, null, null); Map<String, Object> descrParams = new HashMap<String, Object>(); descrParams.put(VolumeDescriptor.PARAM_IS_COPY_SOURCE_ID, Boolean.TRUE); vplexSrcVolumeDescr.setParameters(descrParams); volumeDescriptors.add(vplexSrcVolumeDescr); // Get some info about the VPLEX volume being copied and its storage // system. Project vplexSrcProject = BlockFullCopyUtils.queryFullCopySourceProject(fcSourceObj, _dbClient); StorageSystem vplexSrcSystem = _dbClient.queryObject(StorageSystem.class, vplexSrcSystemId); Project vplexSystemProject = VPlexBlockServiceApiImpl.getVplexProject(vplexSrcSystem, _dbClient, _tenantsService); // For the VPLEX volume being copied, determine which of the associated // backend volumes is the primary and, for distributed volumes, which // is the HA volume. The primary volume will be natively copied and we // we need to place and prepare a volume to hold the copy. This copy // will be the primary backend volume for the VPLEX volume copy. For // a distributed virtual volume, we will need to place and prepare // a volume to hold the HA volume of the VPLEX volume copy. Volume vplexSrcPrimaryVolume = null; Volume vplexSrcHAVolume = null; StringSet assocVolumeURIs = vplexSrcVolume.getAssociatedVolumes(); Iterator<String> assocVolumeURIsIter = assocVolumeURIs.iterator(); while (assocVolumeURIsIter.hasNext()) { URI assocVolumeURI = URI.create(assocVolumeURIsIter.next()); Volume assocVolume = _dbClient.queryObject(Volume.class, assocVolumeURI); if (assocVolume.getVirtualArray().toString().equals(varray.getId().toString())) { vplexSrcPrimaryVolume = assocVolume; } else { vplexSrcHAVolume = assocVolume; } } // Get the capabilities VirtualPool vpool = BlockFullCopyUtils.queryFullCopySourceVPool(fcSourceObj, _dbClient); VirtualPoolCapabilityValuesWrapper capabilities = getCapabilitiesForFullCopyCreate(fcSourceObj, vpool, count); // Get the number of copies to create and the size of the volumes. // Note that for the size, we must use the actual provisioned size // of the source side backend volume. The size passed in the // capabilities will be the size of the VPLEX volume. When the // source side backend volume for the copy is provisioned, you // might not get that actual size. On VMAX, the size will be slightly // larger while for VNX the size will be exactly what is requested. // So, if the source side is a VMAX, the source side for the copy // will be slightly larger than the size in the capabilities. If the HA // side is VNX and we use the size in the capabilities, then you will // get exactly that size for the HA backend volume. As a result, source // side backend volume for the copy will be slightly larger than the // HA side. Now the way a VPLEX copy is made is it uses native full // copy to create a native full copy of the source side backend // volume. It then provisions the HA side volume. The new source side // backend copy is then imported into VPLEX in the same way as is done // for a vpool change that imports a volume to VPLEX. This code in the // VPLEX controller creates a local VPLEX volume using the source side // copy and for a distributed volume it then attaches as a remote // mirror the HA backend volume that is provisioned. If the HA volume // is slightly smaller, then this will fail on the VPLEX. So, we must // ensure that HA side volume is big enough by using the provisioned // capacity of the source side backend volume of the VPLEX volume being // copied. long size = vplexSrcPrimaryVolume.getProvisionedCapacity(); // Place and prepare a volume for each copy to serve as a native // copy of a VPLEX backend volume. The VPLEX backend volume that // is copied is the backend volume in the same virtual array as the // VPLEX volume i.e, the primary backend volume. Create // descriptors for these prepared volumes and add them to the list. List<Volume> vplexCopyPrimaryVolumes = prepareFullCopyPrimaryVolumes( copyName, count, vplexSrcPrimaryVolume, capabilities, volumeDescriptors); // If the VPLEX volume being copied is distributed, then the VPLEX // HA volume should be non-null. We use the VPLEX scheduler to place // and then prepare volumes for the HA volumes of the VPLEX volume // copies. This should be done in the same manner as is done for the // import volume routine. This is because to form the VPLEX volume // copy we import the copy of the primary backend volume. List<Volume> vplexCopyHAVolumes = new ArrayList<Volume>(); if (vplexSrcHAVolume != null) { vplexCopyHAVolumes.addAll( prepareFullCopyHAVolumes( copyName, count, size, vplexSrcSystem, vplexSystemProject, varray, vplexSrcHAVolume, taskId, volumeDescriptors)); } // For each copy to be created, place and prepare a volume for the // primary backend volume copy. When copying a distributed VPLEX // volume, we also must place and prepare a volume for the HA // backend volume copy. Lastly, we must prepare a volume for the // VPLEX volume copy. Create descriptors for these prepared volumes // and add them to the volume descriptors list. for (int i = 0; i < count; i++) { // Prepare a new VPLEX volume for each copy. Volume vplexCopyPrimaryVolume = vplexCopyPrimaryVolumes.get(i); Volume vplexCopyHAVolume = null; if (vplexCopyHAVolumes.size() != 0) { vplexCopyHAVolume = vplexCopyHAVolumes.get(i); } Volume vplexCopyVolume = prepareFullCopyVPlexVolume( copyName, count, i, size, vplexSrcVolume, vplexSrcProject, varray, vpool, vplexSrcSystemId, vplexCopyPrimaryVolume, vplexCopyHAVolume, taskId, volumeDescriptors); vplexCopyVolumes.add(vplexCopyVolume); // Create task for each copy. Operation op = vplexCopyVolume.getOpStatus().get(taskId); TaskResourceRep task = toTask(vplexCopyVolume, taskId, op); taskList.getTaskList().add(task); } } // Invoke the VPLEX controller to create the copies. try { s_logger.info("Getting VPlex controller {}.", taskId); VPlexController controller = getController(VPlexController.class, DiscoveredDataObject.Type.vplex.toString()); // TBD controller needs to be updated to handle CGs. controller.createFullCopy(vplexSrcSystemId, volumeDescriptors, taskId); s_logger.info("Successfully invoked controller."); } catch (InternalException e) { s_logger.error("Controller error", e); // Update the status for the VPLEX volume copies and their // corresponding tasks. for (Volume vplexCopyVolume : vplexCopyVolumes) { Operation op = vplexCopyVolume.getOpStatus().get(taskId); if (op != null) { op.error(e); vplexCopyVolume.getOpStatus().updateTaskStatus(taskId, op); _dbClient.persistObject(vplexCopyVolume); for (TaskResourceRep task : taskList.getTaskList()) { if (task.getResource().getId().equals(vplexCopyVolume.getId())) { task.setState(op.getStatus()); task.setMessage(op.getMessage()); break; } } } } // Mark all volumes inactive, except for the VPLEX volume // we were trying to copy. for (VolumeDescriptor descriptor : volumeDescriptors) { if (descriptor.getParameters().get(VolumeDescriptor.PARAM_IS_COPY_SOURCE_ID) == null) { Volume volume = _dbClient.queryObject(Volume.class, descriptor.getVolumeURI()); volume.setInactive(true); _dbClient.persistObject(volume); } } } return taskList; }