/*
* Copyright (c) 2012-2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource;
import static com.emc.storageos.api.mapper.BlockMapper.addAutoTierPolicy;
import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource;
import static com.emc.storageos.api.mapper.DbObjectMapper.toRelatedResource;
import static com.emc.storageos.api.mapper.SystemsMapper.map;
import static com.emc.storageos.api.mapper.TaskMapper.toTask;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.commons.lang.StringUtils;
import org.jsoup.helper.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.emc.storageos.api.mapper.functions.MapStoragePort;
import com.emc.storageos.api.service.impl.resource.utils.AsyncTaskExecutorIntf;
import com.emc.storageos.api.service.impl.resource.utils.DiscoveredObjectTaskScheduler;
import com.emc.storageos.api.service.impl.resource.utils.PropertySetterUtil;
import com.emc.storageos.api.service.impl.resource.utils.PurgeRunnable;
import com.emc.storageos.api.service.impl.resource.utils.VolumeIngestionUtil;
import com.emc.storageos.api.service.impl.response.BulkList;
import com.emc.storageos.cinder.CinderConstants;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.impl.TypeMap;
import com.emc.storageos.db.client.model.AutoTieringPolicy;
import com.emc.storageos.db.client.model.DecommissionedResource;
import com.emc.storageos.db.client.model.DiscoveredDataObject;
import com.emc.storageos.db.client.model.DiscoveredDataObject.CompatibilityStatus;
import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus;
import com.emc.storageos.db.client.model.DiscoveredDataObject.Type;
import com.emc.storageos.db.client.model.FileShare;
import com.emc.storageos.db.client.model.ObjectNamespace;
import com.emc.storageos.db.client.model.ObjectUserSecretKey;
import com.emc.storageos.db.client.model.Operation;
import com.emc.storageos.db.client.model.RemoteDirectorGroup;
import com.emc.storageos.db.client.model.StorageHADomain;
import com.emc.storageos.db.client.model.StoragePool;
import com.emc.storageos.db.client.model.StoragePort;
import com.emc.storageos.db.client.model.StoragePort.OperationalStatus;
import com.emc.storageos.db.client.model.StoragePort.PortType;
import com.emc.storageos.db.client.model.StoragePort.TransportType;
import com.emc.storageos.db.client.model.StorageProvider;
import com.emc.storageos.db.client.model.StorageSystem;
import com.emc.storageos.db.client.model.StorageSystem.Discovery_Namespaces;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObject.ExportType;
import com.emc.storageos.db.client.model.VirtualNAS;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedFileSystem;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedFileSystem.SupportedFileSystemCharacterstics;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeCharacterstics;
import com.emc.storageos.db.client.model.UnManagedDiscoveredObjects.UnManagedVolume.SupportedVolumeInformation;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.model.BulkIdParam;
import com.emc.storageos.model.ResourceOperationTypeEnum;
import com.emc.storageos.model.ResourceTypeEnum;
import com.emc.storageos.model.TaskList;
import com.emc.storageos.model.TaskResourceRep;
import com.emc.storageos.model.block.UnManagedVolumeList;
import com.emc.storageos.model.block.tier.AutoTierPolicyList;
import com.emc.storageos.model.file.UnManagedFileSystemList;
import com.emc.storageos.model.object.ObjectNamespaceList;
import com.emc.storageos.model.object.ObjectNamespaceRestRep;
import com.emc.storageos.model.object.ObjectUserSecretKeyAddRestRep;
import com.emc.storageos.model.object.ObjectUserSecretKeyRequestParam;
import com.emc.storageos.model.pools.StoragePoolList;
import com.emc.storageos.model.pools.StoragePoolRestRep;
import com.emc.storageos.model.ports.StoragePortList;
import com.emc.storageos.model.ports.StoragePortRequestParam;
import com.emc.storageos.model.ports.StoragePortRestRep;
import com.emc.storageos.model.rdfgroup.RDFGroupList;
import com.emc.storageos.model.rdfgroup.RDFGroupRestRep;
import com.emc.storageos.model.systems.StorageSystemBulkRep;
import com.emc.storageos.model.systems.StorageSystemConnectivityList;
import com.emc.storageos.model.systems.StorageSystemList;
import com.emc.storageos.model.systems.StorageSystemRequestParam;
import com.emc.storageos.model.systems.StorageSystemRestRep;
import com.emc.storageos.model.systems.StorageSystemUpdateRequestParam;
import com.emc.storageos.model.vnas.VirtualNASList;
import com.emc.storageos.protectioncontroller.RPController;
import com.emc.storageos.protectioncontroller.impl.recoverpoint.RPHelper;
import com.emc.storageos.security.authorization.CheckPermission;
import com.emc.storageos.security.authorization.DefaultPermissions;
import com.emc.storageos.security.authorization.Role;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.svcs.errorhandling.resources.InternalException;
import com.emc.storageos.util.ConnectivityUtil;
import com.emc.storageos.coordinator.common.Service;
import com.emc.storageos.coordinator.exceptions.CoordinatorException;
import com.emc.storageos.volumecontroller.ArrayAffinityAsyncTask;
import com.emc.storageos.volumecontroller.AsyncTask;
import com.emc.storageos.volumecontroller.BlockController;
import com.emc.storageos.volumecontroller.ControllerException;
import com.emc.storageos.volumecontroller.FileController;
import com.emc.storageos.volumecontroller.ObjectController;
import com.emc.storageos.volumecontroller.StorageController;
import com.emc.storageos.volumecontroller.impl.NativeGUIDGenerator;
import com.emc.storageos.volumecontroller.impl.StoragePortAssociationHelper;
import com.emc.storageos.volumecontroller.impl.cinder.CinderUtils;
import com.emc.storageos.volumecontroller.impl.monitoring.RecordableBourneEvent;
import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager;
import com.emc.storageos.volumecontroller.impl.monitoring.cim.enums.RecordType;
import com.emc.storageos.volumecontroller.impl.plugins.metering.smis.processor.PortMetricsProcessor;
import com.emc.storageos.volumecontroller.impl.utils.DiscoveryUtils;
import com.emc.storageos.volumecontroller.impl.utils.ImplicitPoolMatcher;
import com.google.common.base.Function;
@Path("/vdc/storage-systems")
@DefaultPermissions(readRoles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR },
writeRoles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public class StorageSystemService extends TaskResourceService {
private static final Logger _log = LoggerFactory.getLogger(StorageSystemService.class);
private static final String EVENT_SERVICE_TYPE = "StorageSystem";
protected static final String PORT_EVENT_SERVICE_SOURCE = "StoragePortService";
private static final String PORT_EVENT_SERVICE_TYPE = "storageport";
protected static final String STORAGEPORT_REGISTERED_DESCRIPTION = "Storage Port Registered";
protected static final String POOL_EVENT_SERVICE_SOURCE = "StoragePoolService";
private static final String POOL_EVENT_SERVICE_TYPE = "storagepool";
protected static final String STORAGEPOOL_REGISTERED_DESCRIPTION = "Storage Pool Registered";
private static final String TRUE_STR = "true";
private static final String FALSE_STR = "false";
@Autowired
private RecordableEventManager _evtMgr;
@Autowired
private PortMetricsProcessor portMetricsProcessor;
@Override
public String getServiceType() {
return EVENT_SERVICE_TYPE;
}
// how many times to retry a procedure before returning failure to the user.
// Is used with "system delete" operation.
private int _retry_attempts;
private static class DiscoverJobExec implements AsyncTaskExecutorIntf {
private final StorageController _controller;
DiscoverJobExec(StorageController controller) {
_controller = controller;
}
@Override
public void executeTasks(AsyncTask[] tasks) throws ControllerException {
_controller.discoverStorageSystem(tasks);
}
@Override
public ResourceOperationTypeEnum getOperation() {
return ResourceOperationTypeEnum.DISCOVER_STORAGE_SYSTEM;
}
}
protected static class ArrayAffinityJobExec extends DiscoverJobExec {
ArrayAffinityJobExec(StorageController controller) {
super(controller);
}
@Override
public ResourceOperationTypeEnum getOperation() {
return ResourceOperationTypeEnum.ARRAYAFFINITY_STORAGE_SYSTEM;
}
}
public void setRetryAttempts(int retries) {
_retry_attempts = retries;
}
/**
* {@inheritDoc}
*/
@Override
protected URI getTenantOwner(URI id) {
return null;
}
/**
* Gets the storage system with the passed id from the database.
*
* @param id the URN of a ViPR storage system
*
* @return A reference to StorageSystem.
*
* @throws EntityNotFoundException When the storage system is not
* found.
*/
@Override
protected StorageSystem queryResource(URI id) {
ArgValidator.checkUri(id);
StorageSystem system = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntityNotNull(system, id, isIdEmbeddedInURL(id));
return system;
}
/**
* Gets the storage system with the passed id from the database.
*
* @param id the URN of a ViPR storage system
*
* @return A reference to the registered StorageSystem.
*
* @throws ServiceCodeException When the storage system is not
* registered.
*/
protected StorageSystem queryRegisteredSystem(URI id) {
ArgValidator.checkUri(id);
StorageSystem system = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntityNotNull(system, id, isIdEmbeddedInURL(id));
if (!RegistrationStatus.REGISTERED.toString().equalsIgnoreCase(
system.getRegistrationStatus())) {
throw APIException.badRequests.resourceNotRegistered(StorageSystem.class.getSimpleName(), id);
}
return system;
}
/**
* Manually create a storage system that cannot be discovered using a SMI-S provider. By
* default the storage system will be auto-registered upon its creation.
* For the Block type storage system, the method would add a new system to the SMIS provider.
* The SMIS provider field in the input parameter file is ignored for file type storage systems
* (VNX file and Isilon )
*
* @param param The storage system details.
* @prereq none
* @brief Create storage system
* @return An asynchronous task corresponding to the discovery job scheduled for the new Storage System.
*
* @throws BadRequestException When the system type is not valid or a
* storage system with the same native guid already exists.
* @throws DatabaseException When an error occurs querying the database.
* @throws ControllerException When an error occurs discovering the storage
* system.
*/
@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 createStorageSystem(StorageSystemRequestParam param) throws Exception {
if (!isControllerServiceOnline()) {
_log.error("Controller services are not started yet");
throw APIException.serviceUnavailable.controllerServiceUnavailable();
}
ArgValidator.checkFieldNotEmpty(param.getSystemType(), "system_type");
if (!StorageSystem.Type.isDriverManagedStorageSystem(param.getSystemType())) {
ArgValidator.checkFieldValueFromSystemType(param.getSystemType(), "system_type",
Arrays.asList(StorageSystem.Type.vnxfile, StorageSystem.Type.isilon, StorageSystem.Type.rp,
StorageSystem.Type.netapp, StorageSystem.Type.netappc, StorageSystem.Type.vnxe,
StorageSystem.Type.xtremio, StorageSystem.Type.ecs, StorageSystem.Type.unity, StorageSystem.Type.hp3par));
}
StorageSystem.Type systemType = StorageSystem.Type.valueOf(param.getSystemType());
if (systemType.equals(StorageSystem.Type.vnxfile)) {
validateVNXFileSMISProviderMandatoryDetails(param);
}
ArgValidator.checkFieldNotEmpty(param.getName(), "name");
checkForDuplicateName(param.getName(), StorageSystem.class);
if (systemType.equals(StorageSystem.Type.isilon) || systemType.equals(StorageSystem.Type.unity)
|| systemType.equals(StorageSystem.Type.vnxfile)) {
ArgValidator.checkFieldValidInetAddress(param.getIpAddress(), "ip_address");
} else {
ArgValidator.checkFieldValidIP(param.getIpAddress(), "ip_address");
}
ArgValidator.checkFieldNotNull(param.getPortNumber(), "port_number");
ArgValidator.checkFieldRange(param.getPortNumber(), 1, 65535, "port_number");
validateStorageSystemExists(param.getIpAddress(), param.getPortNumber());
StorageSystem system = prepareStorageSystem(param);
auditOp(OperationTypeEnum.CREATE_STORAGE_SYSTEM, true, null, param.getSerialNumber(),
param.getSystemType(), param.getIpAddress(), param.getPortNumber());
startStorageSystem(system);
// Rather if else everywhere some code duplication with object and file
if (StorageSystem.Type.ecs.toString().equals(system.getSystemType())) {
ObjectController controller = getController(ObjectController.class, param.getSystemType());
ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1);
String taskId = UUID.randomUUID().toString();
tasks.add(new AsyncTask(StorageSystem.class, system.getId(), taskId));
TaskList taskList = discoverStorageSystems(tasks, controller);
return taskList.getTaskList().listIterator().next();
} else {
FileController controller = getController(FileController.class, param.getSystemType());
ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1);
String taskId = UUID.randomUUID().toString();
tasks.add(new AsyncTask(StorageSystem.class, system.getId(), taskId));
/**
* Creates MonitoringJob token on ZooKeeper for vnxfile/isilon device.
* Currently we are handling monitoring for vnxfile/vmax/vnxblock/isilon devices.
* We should not create MonitoringJob token for netapp/rp now.
*/
if (StorageSystem.Type.vnxfile.toString().equals(system.getSystemType()) ||
StorageSystem.Type.isilon.toString().equals(system.getSystemType())) {
controller.startMonitoring(new AsyncTask(StorageSystem.class, system.getId(), taskId),
StorageSystem.Type.valueOf(system.getSystemType()));
}
TaskList taskList = discoverStorageSystems(tasks, controller);
return taskList.getTaskList().listIterator().next();
}
}
private boolean isControllerServiceOnline() {
List<Service> services = null;
try {
services = _coordinator.locateAllServices(CONTROLLER_SVC, CONTROLLER_SVC_VER, null, null);
} catch (CoordinatorException e) {
_log.error("Error happened when querying controller service beacons", e);
}
if (services != null && !services.isEmpty()) {
return true;
}
return false;
}
/**
* Validates SMI-S Provider attributes of the vnxFile as it is a mandatory fields for indications
*
* @param param
*/
private void validateVNXFileSMISProviderMandatoryDetails(StorageSystemRequestParam param) {
ArgValidator.checkFieldValidInetAddress(param.getSmisProviderIP(), "smis_provider_ip");
ArgValidator.checkFieldNotNull(param.getSmisPortNumber(), "smis_port_number");
ArgValidator.checkFieldRange(param.getSmisPortNumber(), 1, 65535, "smis_port_number");
ArgValidator.checkFieldNotEmpty(param.getSmisUserName(), "smis_user_name");
ArgValidator.checkFieldNotEmpty(param.getSmisPassword(), "smis_password");
}
/**
* Validates SMI-S Provider attributes of the vnxFile as it is a mandatory fields for indications
*
* @param param
*/
private void validateVNXFileSMISProviderMandatoryDetails(StorageSystemUpdateRequestParam param) {
/**
* We need to validate only non-null attributes passed by client.
* Because while doing update client can try to update one among all existing mandatory fields.
*/
if (param.getSmisProviderIP() != null) {
ArgValidator.checkFieldValidInetAddress(param.getSmisProviderIP(), "smis_provider_ip");
}
if (param.getSmisUserName() != null) {
ArgValidator.checkFieldNotEmpty(param.getSmisUserName(), "smis_user_name");
}
if (param.getSmisPassword() != null) {
ArgValidator.checkFieldNotEmpty(param.getSmisPassword(), "smis_password");
}
if (param.getSmisPortNumber() != null) {
ArgValidator.checkFieldRange(param.getSmisPortNumber(), 1, 65535, "smis_port_number");
}
}
/**
* Validates a storage system if it already exists for same ipaddress & portNumber
*
* @param ipAddress
* @param portNumber
*/
private void validateStorageSystemExists(String ipAddress, Integer portNumber) {
String systemUniqueKey = ipAddress + "-" + portNumber;
List<StorageSystem> systems = CustomQueryUtility.getActiveStorageSystemByMgmAccessId(_dbClient, systemUniqueKey);
if (systems != null && !systems.isEmpty()) {
throw APIException.badRequests.invalidParameterProviderStorageSystemAlreadyExists("mgmtAccessPoint", systemUniqueKey);
}
}
/**
*
* Remove a storage system. The method would remove the storage system from the
* system control and will remove all resources associated with the storage system from the database.
* Note that resources (pools, ports, volumes, etc.) are not removed from the storage system physically,
* but become unavailable for the user.
*
* @param id the URN of a ViPR storage system
* @prereq none
* @brief Remove a storage system
* @return An asynchronous task.
*
* @throws DatabaseException When an error occurs querying the database.
*/
@POST
@Path("/{id}/deactivate")
@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 deleteStorageSystem(@PathParam("id") URI id) throws DatabaseException
{
StorageSystem system = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntityNotNull(system, id, isIdEmbeddedInURL(id));
if (!RegistrationStatus.UNREGISTERED.toString().equals(system.getRegistrationStatus())) {
throw APIException.badRequests.cannotDeactivateStorageSystem();
}
// Ensure the storage system has no active RecoverPoint volumes under management.
if (RPHelper.containsActiveRpVolumes(id, _dbClient)) {
throw APIException.badRequests.cannotDeactivateStorageSystemActiveRpVolumes();
}
if (DiscoveredDataObject.DataCollectionJobStatus.IN_PROGRESS.toString().equals(system.getDiscoveryStatus())
|| DiscoveredDataObject.DataCollectionJobStatus.SCHEDULED.toString().equals(system.getDiscoveryStatus())) {
throw APIException.serviceUnavailable.cannotDeactivateStorageSystemWhileInDiscover(system.getId());
}
String taskId = UUID.randomUUID().toString();
Operation op = _dbClient.createTaskOpStatus(StorageSystem.class, system.getId(),
taskId, ResourceOperationTypeEnum.DELETE_STORAGE_SYSTEM);
// (COP-22167) Create DecommissionedResource object only if the system is actively managed by a storage provider.
// Otherwise, the created decommissioned object will not be cleared when the provider is removed and added back.
if (StringUtils.isNotBlank(system.getNativeGuid()) && system.isStorageSystemManagedByProvider()
&& !NullColumnValueGetter.isNullURI(system.getActiveProviderURI())) {
DecommissionedResource oldStorage = null;
List<URI> oldResources = _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getDecommissionedResourceIDConstraint(id
.toString()));
if (oldResources != null)
{
List<DecommissionedResource> objects = _dbClient.queryObject(DecommissionedResource.class, oldResources);
for (DecommissionedResource decomObj : objects) {
if (!decomObj.getInactive()) {
oldStorage = decomObj;
break;
}
}
}
if (oldStorage == null) {
oldStorage = new DecommissionedResource();
oldStorage.setNativeGuid(system.getNativeGuid());
oldStorage.setType(TypeMap.getCFName(StorageSystem.class));
oldStorage.setUser(getUserFromContext().getName());
oldStorage.setDecommissionedId(system.getId());
oldStorage.setLabel(system.getLabel());
oldStorage.setId(URIUtil.createId(DecommissionedResource.class));
_dbClient.createObject(oldStorage);
}
StorageProvider provider = _dbClient.queryObject(StorageProvider.class, system.getActiveProviderURI());
if (provider != null) {
StringSet providerDecomSys = provider.getDecommissionedSystems();
if (providerDecomSys == null) {
providerDecomSys = new StringSet();
provider.setDecommissionedSystems(providerDecomSys);
}
providerDecomSys.add(oldStorage.getId().toString());
_dbClient.updateObject(provider);
}
}
PurgeRunnable.executePurging(_dbClient, _dbPurger,
_asynchJobService.getExecutorService(), system,
_retry_attempts, taskId, 60);
return toTask(system, taskId, op);
}
/**
* Allows the user to update credentials for a manually created storage systems.
* Allows the user to update only the name field for vmax and vnx block systems.
*
* @param id the URN of a ViPR storage system
* @param param The storage system details to update.
*
* @brief Update storage system credentials
* @return A StorageSystemRestRep reference specifying the storage system
* data.
*
* @throws BadRequestException When the system is not valid.
* @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 })
@Path("/{id}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public TaskResourceRep updateStorageSystem(@PathParam("id") URI id,
StorageSystemUpdateRequestParam param)
throws ControllerException {
StorageSystem system = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
StorageSystem.Type systemType = StorageSystem.Type.valueOf(system.getSystemType());
if (param.getName() != null && !param.getName().isEmpty() && !param.getName().equalsIgnoreCase(system.getLabel())) {
checkForDuplicateName(param.getName(), StorageSystem.class);
system.setLabel(param.getName());
}
// If unlimited resources is specified and set to true, then no need to look at max resources
// If unlimited resources is set to false, then max resources should also be specified. If not specified, throw error
if (null != param.getIsUnlimitedResourcesSet()) {
if (param.getIsUnlimitedResourcesSet()) {
system.setIsResourceLimitSet(false);
} else {
if (null != param.getMaxResources()) {
system.setIsResourceLimitSet(true);
system.setMaxResources(param.getMaxResources());
} else {
throw APIException.badRequests.parameterMaxResourcesMissing();
}
}
} else if (null != param.getMaxResources()) {
system.setMaxResources(param.getMaxResources());
system.setIsResourceLimitSet(true);
}
// if system type is vmax, vnxblock, hds, openstack, scaleio, xtremio or ceph, update the name or max_resources field alone.
// create Task with ready state and return it. Discovery not needed.
if (systemType.equals(StorageSystem.Type.vmax) || systemType.equals(StorageSystem.Type.vnxblock)
|| systemType.equals(StorageSystem.Type.hds) || systemType.equals(StorageSystem.Type.openstack)
|| systemType.equals(StorageSystem.Type.scaleio) || systemType.equals(StorageSystem.Type.xtremio)
|| systemType.equals(StorageSystem.Type.ceph)) {
// this check is to inform the user that he/she can not update fields other than name and max_resources.
if (param.getIpAddress() != null || param.getPortNumber() != null || param.getUserName() != null ||
param.getPassword() != null || param.getSmisProviderIP() != null || param.getSmisPortNumber() != null ||
param.getSmisUserName() != null || param.getSmisPassword() != null || param.getSmisUseSSL() != null) {
throw APIException.badRequests.onlyNameAndMaxResourceCanBeUpdatedForSystemWithType(systemType.name());
}
_dbClient.persistObject(system);
String taskId = UUID.randomUUID().toString();
TaskList taskList = new TaskList();
Operation op = new Operation();
op.ready("Updated Storage System name");
op.setResourceType(ResourceOperationTypeEnum.UPDATE_STORAGE_SYSTEM);
_dbClient.createTaskOpStatus(StorageSystem.class, system.getId(), taskId, op);
taskList.getTaskList().add(toTask(system, taskId, op));
return taskList.getTaskList().listIterator().next();
}
if (systemType.equals(StorageSystem.Type.vnxfile)) {
validateVNXFileSMISProviderMandatoryDetails(param);
}
String existingIPAddress = system.getIpAddress();
Integer existingPortNumber = system.getPortNumber();
// if the ip or port passed are different from the existing system
// check to ensure a system does not exist with the new ip + port combo
if (((param.getIpAddress() != null && !param.getIpAddress().equals(existingIPAddress)) || (param.getPortNumber() != null && !param
.getPortNumber().equals(existingPortNumber)))) {
String ipAddress = (param.getIpAddress() != null) ? param.getIpAddress() : system.getIpAddress();
Integer portNumber = (param.getPortNumber() != null) ? param.getPortNumber() : system.getPortNumber();
if (systemType.equals(StorageSystem.Type.isilon) || systemType.equals(StorageSystem.Type.unity)
|| systemType.equals(StorageSystem.Type.vnxfile) || systemType.equals(StorageSystem.Type.vnxe)) {
ArgValidator.checkFieldValidInetAddress(ipAddress, "ip_address");
} else {
ArgValidator.checkFieldValidIP(ipAddress, "ip_address");
}
ArgValidator.checkFieldRange(portNumber, 1, 65535, "port_number");
validateStorageSystemExists(ipAddress, portNumber);
system.setMgmtAccessPoint(ipAddress + "-" + portNumber);
}
updateStorageObj(system, param);
auditOp(OperationTypeEnum.UPDATE_STORAGE_SYSTEM, true, null,
id.toString(), param.getIpAddress(), param.getPortNumber());
startStorageSystem(system);
// execute discovery
StorageController controller = getController(FileController.class,
system.getSystemType());
ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1);
String taskId = UUID.randomUUID().toString();
tasks.add(new AsyncTask(StorageSystem.class, system.getId(), taskId));
TaskList taskList = discoverStorageSystems(tasks, controller);
return taskList.getTaskList().listIterator().next();
}
private StorageSystem prepareStorageSystem(StorageSystemRequestParam param) throws DatabaseException {
StorageSystem system = new StorageSystem();
system.setId(URIUtil.createId(StorageSystem.class));
system.setSystemType(param.getSystemType());
system.setAutoDiscovered(false);
system.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
system.setIpAddress(param.getIpAddress());
system.setPortNumber(param.getPortNumber());
system.setMgmtAccessPoint(param.getIpAddress() + "-" + param.getPortNumber());
system.setUsername(param.getUserName());
system.setPassword(param.getPassword());
system.setLabel(param.getName());
system.setSmisProviderIP(param.getSmisProviderIP());
system.setSmisPortNumber(param.getSmisPortNumber());
system.setSmisUserName(param.getSmisUserName());
system.setSmisPassword(param.getSmisPassword());
system.setSmisUseSSL(param.getSmisUseSSL());
_dbClient.createObject(system);
_log.info("Created Storage System with Native Guid:" + system.getNativeGuid());
return system;
}
private void updateStorageObj(StorageSystem system, StorageSystemUpdateRequestParam param) {
if (param.getIpAddress() != null && !param.getIpAddress().equals("")) {
system.setIpAddress(param.getIpAddress());
}
if (param.getPortNumber() != null) {
system.setPortNumber(param.getPortNumber());
}
if (param.getUserName() != null && !param.getUserName().equals("")) {
system.setUsername(param.getUserName());
}
if (param.getPassword() != null && !param.getPassword().equals("")) {
system.setPassword(param.getPassword());
}
if (param.getName() != null && !param.getName().equals("")) {
system.setLabel(param.getName());
}
if (param.getSmisUseSSL() != null) {
system.setSmisUseSSL(param.getSmisUseSSL());
}
system.setSmisProviderIP(param.getSmisProviderIP());
system.setSmisPortNumber(param.getSmisPortNumber());
system.setSmisUserName(param.getSmisUserName());
system.setSmisPassword(param.getSmisPassword());
_dbClient.persistObject(system);
}
/**
* Allows the user to manually discover all storage systems.
*
* @brief Discover all storage systems
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
@Path("/discover")
public TaskList discoverStorageSystemsAll() {
Iterator<URI> storageIter = _dbClient.queryByType(StorageSystem.class, true).iterator();
ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>();
while (storageIter.hasNext()) {
URI storage = storageIter.next();
String taskId = UUID.randomUUID().toString();
tasks.add(new AsyncTask(StorageSystem.class, storage, taskId));
}
BlockController controller = getController(BlockController.class, "vnxblock");
return discoverStorageSystems(tasks, controller);
}
private TaskList discoverStorageSystems(List<AsyncTask> storageTasks,
StorageController controller) {
DiscoveredObjectTaskScheduler scheduler = new DiscoveredObjectTaskScheduler(_dbClient, new DiscoverJobExec(controller));
return scheduler.scheduleAsyncTasks(storageTasks);
}
/**
* Allows the user to manually discover the registered storage system with
* the passed id.
*
* @param id the URN of a ViPR storage system.
* @QueryParam namespace
* StorageSystem Auto Discovery is grouped into multiple namespaces.
* Namespace is used to discover specific parts of Storage System.
*
* Possible Values :
* UNMANAGED_VOLUMES
* UNMANAGED_FIESYSTEMS
* ALL
*
* UNMANAGED_VOLUMES will discover all the Volumes which are present in the Array,
* and only supported on vmax and vnxblock.
* Using UNMANAGED_VOLUMES Namespace in other system types would result in error.
*
* UNMANAGED_FILESYSTEMS will discover all the fileystems which are present in the Array,
* and only supported on netapp.
*
* Using UNMANAGED_FILESYSTEMS Namespace in other system types would result in error.
*
* @brief Discover storage system
* @throws ControllerException When an error occurs discovering the storage
* system.
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
@Path("/{id}/discover")
public TaskResourceRep discoverSystem(@PathParam("id") URI id,
@QueryParam("namespace") String namespace) {
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntity(storageSystem, id, isIdEmbeddedInURL(id), true);
String deviceType = storageSystem.getSystemType();
// If Namespace is empty or null set it to ALL as default
if (namespace == null || namespace.trim().length() < 1) {
namespace = Discovery_Namespaces.ALL.toString();
}
if (!validateNameSpace(namespace, storageSystem)) {
throw APIException.badRequests.invalidParameterStorageSystemNamespace(namespace);
}
// check Storage system's compatibility for unmanaged resource discovery.
// Trigger unmanaged resource discovery only when system is compatible.
if ((Discovery_Namespaces.UNMANAGED_VOLUMES.name().equalsIgnoreCase(namespace) ||
Discovery_Namespaces.BLOCK_SNAPSHOTS.name().equalsIgnoreCase(namespace) ||
Discovery_Namespaces.UNMANAGED_FILESYSTEMS.name().equalsIgnoreCase(namespace)) &&
!CompatibilityStatus.COMPATIBLE.name().equalsIgnoreCase(storageSystem.getCompatibilityStatus())) {
throw APIException.badRequests.cannotDiscoverUnmanagedResourcesForUnsupportedSystem();
}
BlockController controller = getController(BlockController.class, deviceType);
DiscoveredObjectTaskScheduler scheduler = null;
ArrayList<AsyncTask> tasks = new ArrayList<AsyncTask>(1);
String taskId = UUID.randomUUID().toString();
if (Discovery_Namespaces.ARRAY_AFFINITY.name().equalsIgnoreCase(namespace)) {
if (!storageSystem.deviceIsType(Type.vmax) && !storageSystem.deviceIsType(Type.vnxblock) && !storageSystem.deviceIsType(Type.xtremio) &&
!storageSystem.deviceIsType(Type.unity)) {
throw APIException.badRequests.cannotDiscoverArrayAffinityForUnsupportedSystem(storageSystem.getSystemType());
}
scheduler = new DiscoveredObjectTaskScheduler(
_dbClient, new ArrayAffinityJobExec(controller));
URI providerURI = storageSystem.getActiveProviderURI();
List<URI> systemIds = new ArrayList<URI>();
systemIds.add(id);
if (!NullColumnValueGetter.isNullURI(providerURI) &&
(storageSystem.deviceIsType(Type.vmax) || storageSystem.deviceIsType(Type.vnxblock) || storageSystem.deviceIsType(Type.xtremio))) {
List<URI> sysURIs = _dbClient.queryByType(StorageSystem.class, true);
Iterator<StorageSystem> storageSystems = _dbClient.queryIterativeObjects(StorageSystem.class, sysURIs);
while (storageSystems.hasNext()) {
StorageSystem systemObj = storageSystems.next();
if (systemObj == null) {
_log.warn("StorageSystem is no longer in the DB. It could have been deleted or decommissioned");
continue;
}
if (providerURI.equals(systemObj.getActiveProviderURI()) && !id.equals(systemObj.getId())) {
systemIds.add(systemObj.getId());
}
}
}
tasks.add(new ArrayAffinityAsyncTask(StorageSystem.class, systemIds, null, taskId));
} else {
scheduler = new DiscoveredObjectTaskScheduler(
_dbClient, new DiscoverJobExec(controller));
tasks.add(new AsyncTask(StorageSystem.class, storageSystem.getId(), taskId,
namespace));
}
TaskList taskList = scheduler.scheduleAsyncTasks(tasks);
return taskList.getTaskList().listIterator().next();
}
/**
* Gets the id, name, and self link for all registered storage systems.
*
* @brief List storage systems
* @return A reference to a StorageSystemList.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StorageSystemList getStorageSystems() {
StorageSystemList systemsList = new StorageSystemList();
List<URI> ids = _dbClient.queryByType(StorageSystem.class, true);
Iterator<StorageSystem> iter = _dbClient.queryIterativeObjects(StorageSystem.class, ids);
while (iter.hasNext()) {
systemsList.getStorageSystems().add(toNamedRelatedResource(iter.next()));
}
return systemsList;
}
/**
* Get information about the registered storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
*
* @brief Show storage system
* @return A reference to a StorageSystemRestRep
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StorageSystemRestRep getStorageSystem(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
StorageSystemRestRep restRep = map(system);
restRep.setNumResources(getNumResources(system, _dbClient));
return restRep;
}
/**
* Allows the user register the storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
*
* @brief Register storage system
* @return A StorageSystemRestRep reference specifying the data for the
* updated storage system.
* @throws ControllerException
*
*
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/register")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public StorageSystemRestRep registerStorageSystem(@PathParam("id") URI id) throws ControllerException {
// Validate the storage system.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntity(storageSystem, id, isIdEmbeddedInURL(id));
// If not already registered, register it now.
if (RegistrationStatus.UNREGISTERED.toString().equalsIgnoreCase(
storageSystem.getRegistrationStatus())) {
storageSystem.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
_dbClient.persistObject(storageSystem);
startStorageSystem(storageSystem);
auditOp(OperationTypeEnum.REGISTER_STORAGE_SYSTEM, true, null,
storageSystem.getId().toString(), id.toString());
}
// Register all Pools.
URIQueryResultList storagePoolURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePoolConstraint(id),
storagePoolURIs);
Iterator<URI> storagePoolIter = storagePoolURIs.iterator();
List<StoragePool> registeredPools = new ArrayList<StoragePool>();
while (storagePoolIter.hasNext()) {
StoragePool pool = _dbClient.queryObject(StoragePool.class, storagePoolIter.next());
if (pool.getInactive() ||
DiscoveredDataObject.RegistrationStatus.REGISTERED.toString().equals(pool.getRegistrationStatus())) {
continue;
}
registerStoragePool(pool);
registeredPools.add(pool);
}
// Register all Ports.
URIQueryResultList storagePortURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(id),
storagePortURIs);
Iterator<URI> storagePortIter = storagePortURIs.iterator();
while (storagePortIter.hasNext()) {
StoragePort port = _dbClient.queryObject(StoragePort.class, storagePortIter.next());
if (port.getInactive() ||
DiscoveredDataObject.RegistrationStatus.REGISTERED.toString().equals(port.getRegistrationStatus())) {
continue;
}
registerStoragePort(port);
}
StringBuffer errorMessage = new StringBuffer();
// Pool registration also update its varray relationship, so, we should also update vpool to pool relation.
ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(registeredPools, _dbClient, _coordinator, errorMessage);
return map(storageSystem);
}
/**
* Allows the user register the storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
*
* @brief Deregister storage system
* @return A StorageSystemRestRep reference specifying the data for the
* updated storage system.
* @throws ControllerException
*
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/deregister")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public StorageSystemRestRep deregisterStorageSystem(@PathParam("id") URI id) throws ControllerException {
// Validate the storage system.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem storageSystem = _dbClient.queryObject(StorageSystem.class, id);
ArgValidator.checkEntity(storageSystem, id, isIdEmbeddedInURL(id));
if (!RegistrationStatus.UNREGISTERED.toString().equalsIgnoreCase(
storageSystem.getRegistrationStatus())) {
storageSystem.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString());
_dbClient.persistObject(storageSystem);
stopStorageSystem(storageSystem);
}
// Deregister all Pools.
URIQueryResultList storagePoolURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePoolConstraint(id),
storagePoolURIs);
Iterator<URI> storagePoolIter = storagePoolURIs.iterator();
List<StoragePool> modifiedPools = new ArrayList<StoragePool>();
while (storagePoolIter.hasNext()) {
StoragePool pool = _dbClient.queryObject(StoragePool.class, storagePoolIter.next());
modifiedPools.add(pool);
if (pool.getInactive() ||
DiscoveredDataObject.RegistrationStatus.UNREGISTERED.toString().equals(pool.getRegistrationStatus())) {
continue;
}
// Setting status to UNREGISTERED.
pool.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString());
_dbClient.persistObject(pool);
auditOp(OperationTypeEnum.DEREGISTER_STORAGE_POOL, true, null, id.toString());
}
// Deregister all Ports.
URIQueryResultList storagePortURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(id),
storagePortURIs);
Iterator<URI> storagePortIter = storagePortURIs.iterator();
while (storagePortIter.hasNext()) {
StoragePort port = _dbClient.queryObject(StoragePort.class, storagePortIter.next());
if (port.getInactive() ||
DiscoveredDataObject.RegistrationStatus.UNREGISTERED.toString().equals(port.getRegistrationStatus())) {
continue;
}
// Setting status to UNREGISTERED.
port.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString());
_dbClient.persistObject(port);
auditOp(OperationTypeEnum.DEREGISTER_STORAGE_PORT, true, null, port.getLabel(), port.getId().toString());
}
StringBuffer errorMessage = new StringBuffer();
ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(modifiedPools, _dbClient, _coordinator, errorMessage);
auditOp(OperationTypeEnum.DEREGISTER_STORAGE_SYSTEM, true, null,
storageSystem.getId().toString(), id.toString());
return map(storageSystem);
}
/**
* Get information about the connectivity of the registered protection system with the passed id.
*
* @param id the URN of a ViPR protection system.
*
* @brief Show registered protection system connectivity
* @return A StorageSystemConnectivityRestRep object
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/connectivity")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StorageSystemConnectivityList getStorageSystemConnectivity(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
return getConnectivity(queryRegisteredSystem(id));
}
/**
* Return the connectivity rest response for a storage system.
* This method uses the RPSiteArray table in Cassandra to determine which storage systems
* are connected to this storage system via protection. In the future, we may have connectivity
* for other features as well.
*
* @param system protection system
* @return rest response
*/
private StorageSystemConnectivityList getConnectivity(StorageSystem system) {
BlockServiceApi apiImpl =
BlockService.getBlockServiceImpl(system.getSystemType().toString());
if (apiImpl == null) {
apiImpl = BlockService.getBlockServiceImpl(BlockServiceApi.DEFAULT);
}
return apiImpl.getStorageSystemConnectivity(system);
}
/**
* Invoke connect storage. Once system is verified to be registered.
* Statistics, Events will be collected for only registered systems.
*
* @param system Storage system to start Metering & Monitoring.
* @throws ControllerException
*/
private void startStorageSystem(StorageSystem system) throws ControllerException {
if (!DiscoveredDataObject.Type.vplex.name().equals(system.getSystemType())) {
StorageController controller = getStorageController(system.getSystemType());
controller.connectStorage(system.getId());
}
}
/**
* Invoke disconnect storage to stop events and statistics gathering of this
* storage system.
*
* @param storageSystem A reference to the storage system.
* @throws ControllerException When an error occurs disconnecting the
* storage system.
*/
private void stopStorageSystem(StorageSystem storageSystem) throws ControllerException {
if (!DiscoveredDataObject.Type.vplex.name().equals(storageSystem.getSystemType())) {
StorageController controller = getStorageController(storageSystem.getSystemType());
controller.disconnectStorage(storageSystem.getId());
}
}
/**
* Return the storage controller for a given system type.
*
* @param systemType The type of the storage system.
*
* @return A reference to the storage controller
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private StorageController getStorageController(String systemType) {
Class controllerClass = storageSystemClass(systemType);
StorageController controller = (StorageController) getController(controllerClass, systemType);
return controller;
}
/**
* Checks if this system supports FileShare Ops FIX ME -- hook this up into
* the placement logic's supported protocols check
*
* @param systemType
*
* @return The file/block class of storage system
*/
@SuppressWarnings("rawtypes")
public static Class storageSystemClass(String systemType) {
if (systemType.equals(StorageSystem.Type.isilon.toString())
|| systemType.equals(StorageSystem.Type.vnxfile.toString())
|| systemType.equals(StorageSystem.Type.netapp.toString())
|| systemType.equals(StorageSystem.Type.netappc.toString())
|| systemType.equals(StorageSystem.Type.vnxe.toString())
|| systemType.equals(StorageSystem.Type.unity.toString())) {
return FileController.class;
} else if (systemType.equals(StorageSystem.Type.rp.toString())) {
return RPController.class;
} else if (systemType.equals(StorageSystem.Type.ecs.toString())) {
return ObjectController.class;
}
return BlockController.class;
}
/**
* Manually register the discovered storage pool with the passed id on the
* registered storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
* @param poolId The id of the storage pool.
*
* @brief Register storage system storage pool
* @return A reference to a StoragePoolRestRep specifying the data for the
* registered storage pool.
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
@Path("/{id}/storage-pools/{poolId}/register")
public StoragePoolRestRep registerStoragePool(@PathParam("id") URI id,
@PathParam("poolId") URI poolId) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
queryRegisteredSystem(id);
ArgValidator.checkFieldUriType(poolId, StoragePool.class, "poolId");
StoragePool pool = _dbClient.queryObject(StoragePool.class, poolId);
ArgValidator.checkEntity(pool, poolId, isIdEmbeddedInURL(poolId));
if (!id.equals(pool.getStorageDevice())) {
throw APIException.badRequests.poolNotBelongingToSystem(poolId, id);
}
// if not register, registered it. Otherwise, dont do anything
if (RegistrationStatus.UNREGISTERED.toString().equalsIgnoreCase(pool.getRegistrationStatus())) {
registerStoragePool(pool);
StringBuffer errorMessage = new StringBuffer();
// Pool registration also update its varray relationship, so, we should also update vpool to pool relation.
ImplicitPoolMatcher.matchModifiedStoragePoolsWithAllVirtualPool(Arrays.asList(pool), _dbClient, _coordinator, errorMessage);
}
return StoragePoolService.toStoragePoolRep(pool, _dbClient, _coordinator);
}
private void registerStoragePool(StoragePool pool) {
pool.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
_dbClient.updateAndReindexObject(pool);
// record storage port register event.
recordStoragePoolPortEvent(OperationTypeEnum.STORAGE_POOL_REGISTER,
STORAGEPOOL_REGISTERED_DESCRIPTION, pool.getId(), POOL_EVENT_SERVICE_TYPE);
auditOp(OperationTypeEnum.REGISTER_STORAGE_POOL, true,
null, pool.getId().toString(), pool.getStorageDevice().toString());
}
/**
* Gets all virtual NAS for the registered storage system with the passed
* id.
*
* @param id the URN of a ViPR storage system.
*
* @brief List storage system virtual nas servers
* @return A reference to a StoragePooList specifying the id and self link
* for each storage pool.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/vnasservers")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public VirtualNASList getVnasServers(@PathParam("id") URI id) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
VirtualNASList vNasList = new VirtualNASList();
URIQueryResultList vNasURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceVirtualNasConstraint(id),
vNasURIs);
Iterator<URI> vNasIter = vNasURIs.iterator();
while (vNasIter.hasNext()) {
URI vNasURI = vNasIter.next();
VirtualNAS vNas = _dbClient.queryObject(VirtualNAS.class,
vNasURI);
if (vNas != null && !vNas.getInactive()) {
vNasList.getVNASServers().add(toNamedRelatedResource(vNas, vNas.getNativeGuid()));
}
}
return vNasList;
}
/**
* Gets all storage pools for the registered storage system with the passed
* id.
*
* @param id the URN of a ViPR storage system.
*
* @brief List storage system storage pools
* @return A reference to a StoragePooList specifying the id and self link
* for each storage pool.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/storage-pools")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StoragePoolList getAllStoragePools(@PathParam("id") URI id) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
StoragePoolList poolList = new StoragePoolList();
URIQueryResultList storagePoolURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePoolConstraint(id),
storagePoolURIs);
Iterator<URI> storagePoolIter = storagePoolURIs.iterator();
while (storagePoolIter.hasNext()) {
URI storagePoolURI = storagePoolIter.next();
StoragePool storagePool = _dbClient.queryObject(StoragePool.class,
storagePoolURI);
if (storagePool != null && !storagePool.getInactive()) {
poolList.getPools().add(toNamedRelatedResource(storagePool, storagePool.getNativeGuid()));
}
}
return poolList;
}
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/rdf-groups")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public RDFGroupList getAllRAGroups(@PathParam("id") URI id) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
RDFGroupList rdfGroupList = new RDFGroupList();
URIQueryResultList rdfGroupURIs = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getStorageDeviceRemoteGroupsConstraint(id),
rdfGroupURIs);
Iterator<URI> rdfGroupIter = rdfGroupURIs.iterator();
while (rdfGroupIter.hasNext()) {
URI rdfGroupURI = rdfGroupIter.next();
RemoteDirectorGroup rdfGroup = _dbClient.queryObject(RemoteDirectorGroup.class, rdfGroupURI);
if (rdfGroup != null && !rdfGroup.getInactive()) {
rdfGroupList.getRdfGroups().add(toNamedRelatedResource(rdfGroup, rdfGroup.getNativeGuid()));
}
}
return rdfGroupList;
}
/**
* Gets all AutoTier policies associated with registered storage system with the passed
* id. Only policies which satisfy the below will be returned
* 1. AutoTiering should be enabled on StorageSystem
* 2. AutoTierPolicy should be in Enabled State.
*
* @param id the URN of a ViPR storage system.
* @brief List storage system autotier policies
* @return A reference to a AutoTierPolicy List specifying the id and self link
* for each storage pool.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/auto-tier-policies")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public AutoTierPolicyList getAllFastPolicies(@PathParam("id") URI id,
@QueryParam("unique_policy_names") Boolean uniquePolicyNames) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryRegisteredSystem(id);
if (!system.getAutoTieringEnabled()) {
throw APIException.badRequests.autoTieringNotEnabledOnStorageSystem(id);
}
if (uniquePolicyNames == null) {
uniquePolicyNames = false;
}
AutoTierPolicyList policyList = new AutoTierPolicyList();
URIQueryResultList fastPolicyURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceFASTPolicyConstraint(id),
fastPolicyURIs);
Iterator<URI> fastPolicyIterator = fastPolicyURIs.iterator();
while (fastPolicyIterator.hasNext()) {
URI fastPolicyURI = fastPolicyIterator.next();
AutoTieringPolicy fastPolicy = _dbClient.queryObject(AutoTieringPolicy.class,
fastPolicyURI);
if (null != fastPolicy && fastPolicy.getPolicyEnabled()) {
addAutoTierPolicy(fastPolicy, policyList, uniquePolicyNames);
}
}
return policyList;
}
/**
* Gets all object namespaces for the registered storage system with the passed id
*
* @param id the URN of a ViPR storage system.
*
* @brief List object storage namespaces
* @return A reference to a ObjectNamespaceList
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/object-namespaces")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public ObjectNamespaceList getAllObjectNamespaces(@PathParam("id") URI id) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
if (!StorageSystem.Type.ecs.toString().equals(system.getSystemType())) {
throw APIException.badRequests.invalidParameterURIInvalid("id", id);
}
ObjectNamespaceList objNamespaceList = new ObjectNamespaceList();
URIQueryResultList objNamespaceURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceObjectNamespaceConstraint(id),
objNamespaceURIs);
Iterator<URI> ecsNsIter = objNamespaceURIs.iterator();
while (ecsNsIter.hasNext()) {
URI nsURI = ecsNsIter.next();
ObjectNamespace namespace = _dbClient.queryObject(ObjectNamespace.class,
nsURI);
if (namespace != null && !namespace.getInactive()) {
objNamespaceList.getNamespaces().add(toNamedRelatedResource(namespace, namespace.getNativeGuid()));
}
}
return objNamespaceList;
}
/**
* Get information about the storage pool with the passed id on the
* registered storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
* @param poolId The id of the storage pool.
*
* @brief Show storage system storage pool
* @return A StoragePoolRestRep reference specifying the data for the
* requested storage pool.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/storage-pools/{poolId}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StoragePoolRestRep getStoragePool(@PathParam("id") URI id,
@PathParam("poolId") URI poolId) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
ArgValidator.checkFieldUriType(poolId, StoragePool.class, "poolId");
StoragePool storagePool = _dbClient.queryObject(StoragePool.class, poolId);
ArgValidator.checkEntity(storagePool, poolId, isIdEmbeddedInURL(poolId));
return StoragePoolService.toStoragePoolRep(storagePool, _dbClient, _coordinator);
}
/**
* Get details of the object namespace associated with a particular storage system
*
* @param id storage system URN ID
* @param nsId namespace id
* @return details of namespace
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/object-namespaces/{nsId}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public ObjectNamespaceRestRep getObjectNamespace(@PathParam("id") URI id,
@PathParam("nsId") URI nsId) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
if (!StorageSystem.Type.ecs.toString().equals(system.getSystemType())) {
throw APIException.badRequests.invalidParameterURIInvalid("id", id);
}
ArgValidator.checkFieldUriType(nsId, ObjectNamespace.class, "nativeId");
ObjectNamespace ecsNamespace = _dbClient.queryObject(ObjectNamespace.class, nsId);
ArgValidator.checkEntity(ecsNamespace, nsId, isIdEmbeddedInURL(nsId));
return toObjectNamespaceRestRep(ecsNamespace, _dbClient, _coordinator);
}
private ObjectNamespaceRestRep toObjectNamespaceRestRep(ObjectNamespace ecsNamespace, DbClient dbClient,
CoordinatorClient coordinator) {
return map(ecsNamespace);
}
/**
* Create a secret key for an object storage array
*
* @param param secret key
* @param id storage system URN
* @param userId user in array
* @return secret key details
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/object-user/{userId}/secret-keys")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public ObjectUserSecretKeyAddRestRep addUserSecretKey(ObjectUserSecretKeyRequestParam param, @PathParam("id") URI id,
@PathParam("userId") String userId) throws InternalException{
// Make sure storage system is registered and object storage
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
if (!StorageSystem.Type.ecs.toString().equals(system.getSystemType())) {
throw APIException.badRequests.invalidParameterURIInvalid("id", id);
}
ObjectController controller = getController(ObjectController.class, system.getSystemType());
String secretKey = null;
if (param != null && !StringUtil.isBlank( param.getSecretkey() )){
secretKey = param.getSecretkey();
}
ObjectUserSecretKey secretKeyRes = controller.addUserSecretKey(id, userId, secretKey);
//Return key details as this is synchronous call
return map(secretKeyRes, true);
}
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/rdf-groups/{rdfGrpId}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public RDFGroupRestRep getRDFGroup(@PathParam("id") URI id, @PathParam("rdfGrpId") URI rdfGroupId) {
// Make sure storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
ArgValidator.checkFieldUriType(rdfGroupId, RemoteDirectorGroup.class, "rdfGrpId");
RemoteDirectorGroup raGroup = _dbClient.queryObject(RemoteDirectorGroup.class, rdfGroupId);
ArgValidator.checkEntity(raGroup, rdfGroupId, isIdEmbeddedInURL(rdfGroupId));
return toRDFGroupRep(raGroup, _dbClient, _coordinator);
}
private RDFGroupRestRep toRDFGroupRep(RemoteDirectorGroup rdfGroup, DbClient dbClient,
CoordinatorClient coordinator) {
List<URI> volumeList = new ArrayList<URI>();
StringSet volumes = rdfGroup.getVolumes();
if (volumes != null) {
for (String volNativeGuid : volumes) {
try {
Volume vol = DiscoveryUtils.checkStorageVolumeExistsInDB(dbClient, volNativeGuid);
if (vol != null && vol.isSRDFSource()) {
volumeList.add(vol.getId());
}
} catch (IOException e) {
_log.error(e.getMessage(), e);
}
}
}
return map(rdfGroup, volumeList);
}
/**
* Manually register the discovered storage port with the passed id on the
* registered storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
* @param portId The id of the storage port.
*
* @brief Register storage system storage port
* @return A reference to a StoragePortRestRep specifying the data for the
* registered storage port.
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
@Path("/{id}/storage-ports/{portId}/register")
public StoragePortRestRep registerStoragePort(@PathParam("id") URI id,
@PathParam("portId") URI portId) {
// Make sure the storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
queryRegisteredSystem(id);
ArgValidator.checkFieldUriType(portId, StoragePort.class, "portId");
StoragePort port = _dbClient.queryObject(StoragePort.class, portId);
ArgValidator.checkEntity(port, portId, isIdEmbeddedInURL(portId));
if (!id.equals(port.getStorageDevice())) {
throw APIException.badRequests.portNotBelongingToSystem(portId, id);
}
// register port if not registered. Otherwise, do nothing
if (RegistrationStatus.UNREGISTERED.toString().equalsIgnoreCase(port.getRegistrationStatus())) {
registerStoragePort(port);
}
return MapStoragePort.getInstance(_dbClient).toStoragePortRestRep(port);
}
private void registerStoragePort(StoragePort port) {
port.setRegistrationStatus(RegistrationStatus.REGISTERED.toString());
_dbClient.persistObject(port);
// record storage port register event.
recordStoragePoolPortEvent(OperationTypeEnum.STORAGE_PORT_REGISTER,
STORAGEPORT_REGISTERED_DESCRIPTION, port.getId(), PORT_EVENT_SERVICE_TYPE);
auditOp(OperationTypeEnum.REGISTER_STORAGE_PORT,
true, null, port.getId().toString(), port.getStorageDevice().toString());
}
/**
* Record Bourne Event for the completed operations
*
* @param type
* @param type
* @param description
* @param storagePort
*/
private void recordStoragePoolPortEvent(OperationTypeEnum opType, String description,
URI resourcdId, String resType) {
String evType;
evType = opType.getEvType(true);
String service = PORT_EVENT_SERVICE_TYPE;
String eventSource = PORT_EVENT_SERVICE_SOURCE;
if (resType.equalsIgnoreCase("StoragePool")) {
service = POOL_EVENT_SERVICE_TYPE;
eventSource = POOL_EVENT_SERVICE_SOURCE;
}
RecordableBourneEvent event = new RecordableBourneEvent(
/* String */evType,
/* tenant id */null,
/* user id ?? */URI.create("ViPR-User"),
/* project ID */null,
/* VirtualPool */null,
/* service */service,
/* resource id */resourcdId,
/* description */description,
/* timestamp */System.currentTimeMillis(),
/* extensions */"",
/* native guid */null,
/* record type */RecordType.Event.name(),
/* Event Source */eventSource,
/* Operational Status codes */"",
/* Operational Status Descriptions */"");
try {
_evtMgr.recordEvents(event);
} catch (Exception ex) {
_log.error("Failed to record event. Event description: {}. Error: ",
description, ex);
}
}
/**
* Get all storage ports for the registered storage system with the passed
* id.
*
* @param id the URN of a ViPR storage system.
*
* @brief List storage system storage ports
* @return A reference to a StoragePortList specifying the id and self link
* for each port.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/storage-ports")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StoragePortList getAllStoragePorts(@PathParam("id") URI id) {
// Make sure the storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
{ // Update the port metrics calculations. This makes the UI display up-to-date when ports shown.
URIQueryResultList storagePortURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(id),
storagePortURIs);
List<StoragePort> storagePorts = _dbClient.queryObject(StoragePort.class, storagePortURIs);
portMetricsProcessor.computeStoragePortUsage(storagePorts, system, true);
}
StoragePortList portList = new StoragePortList();
URIQueryResultList storagePortURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(id),
storagePortURIs);
Iterator<URI> storagePortsIter = storagePortURIs.iterator();
while (storagePortsIter.hasNext()) {
URI storagePortURI = storagePortsIter.next();
StoragePort storagePort = _dbClient.queryObject(StoragePort.class,
storagePortURI);
if (storagePort != null && !storagePort.getInactive()) {
portList.getPorts().add(toNamedRelatedResource(storagePort, storagePort.getNativeGuid()));
}
}
return portList;
}
/**
* Get information about the storage port with the passed id on the
* registered storage system with the passed id.
*
* @param id the URN of a ViPR storage system.
* @param portId The id of the storage port.
*
* @brief Show storage system storage port
* @return A StoragePortRestRep reference specifying the data for the
* requested port.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/storage-ports/{portId}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public StoragePortRestRep getStoragePort(@PathParam("id") URI id,
@PathParam("portId") URI portId) {
// Make sure the storage system is registered.
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
ArgValidator.checkEntity(system, id, isIdEmbeddedInURL(id));
ArgValidator.checkFieldUriType(portId, StoragePort.class, "portId");
StoragePort port = _dbClient.queryObject(StoragePort.class, portId);
ArgValidator.checkEntity(port, portId, isIdEmbeddedInURL(portId));
return MapStoragePort.getInstance(_dbClient).toStoragePortRestRep(port);
}
/**
* Creates the storage port.
* It is only applicable to cinder storage systems for users to manually create it on ViPR.
* Currently there is no API available to get these information from Cinder.
*
* @param id the storage system id
* @param param the StoragePortRequestParam
* @return A StoragePortRestRep reference specifying the data for the
* created port.
* @throws ControllerException the controller exception
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
@Path("/{id}/storage-ports")
public StoragePortRestRep createStoragePort(@PathParam("id") URI id,
StoragePortRequestParam param) throws ControllerException {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
StorageSystem system = queryResource(id);
// Creating storage ports is supported only for openstack system
if (!Type.openstack.name().equalsIgnoreCase(system.getSystemType())) {
throw APIException.badRequests.cannotCreatePortForSystem(system.getSystemType());
}
ArgValidator.checkFieldNotEmpty(param.getName(), "name");
String portName = param.getName();
// validate transport type
ArgValidator.checkFieldNotEmpty(param.getTransportType(), "transport_type");
ArgValidator.checkFieldValueFromEnum(param.getTransportType(), "transport_type",
EnumSet.of(TransportType.FC, TransportType.IP));
String transportType = param.getTransportType();
// validate port network id
String portNetworkId = param.getPortNetworkId();
ArgValidator.checkFieldNotEmpty(param.getPortNetworkId(), "port_network_id");
StoragePortService.checkValidPortNetworkId(transportType, portNetworkId);
// check for duplicate port name on the same system
checkForDuplicatePortName(portName, id);
// check for duplicate port network id within the system
StoragePortService.checkForDuplicatePortNetworkIdWithinSystem(
_dbClient, portNetworkId, id);
StorageHADomain adapter = CinderUtils.getStorageAdapter(system, _dbClient);
StoragePort port = new StoragePort();
port.setId(URIUtil.createId(StoragePort.class));
port.setStorageDevice(id);
String nativeGuid = NativeGUIDGenerator.generateNativeGuid(system,
portName, NativeGUIDGenerator.PORT);
port.setNativeGuid(nativeGuid);
port.setPortNetworkId(portNetworkId);
port.setRegistrationStatus(DiscoveredDataObject.RegistrationStatus.REGISTERED
.toString());
// always treat it as a frontend port
port.setPortType(PortType.frontend.name());
port.setOperationalStatus(OperationalStatus.OK.toString());
port.setTransportType(transportType);
port.setLabel(portName);
port.setPortName(portName);
port.setStorageHADomain(adapter.getId());
port.setPortGroup(CinderConstants.CINDER_PORT_GROUP);
port.setCompatibilityStatus(CompatibilityStatus.COMPATIBLE.name());
_dbClient.createObject(port);
// runs pool matcher as well
StoragePortAssociationHelper.runUpdatePortAssociationsProcess(
Collections.singleton(port), null, _dbClient,
_coordinator, null);
// Create an audit log entry
auditOp(OperationTypeEnum.CREATE_STORAGE_PORT, true, null,
port.getLabel(), port.getId().toString());
return MapStoragePort.getInstance(_dbClient).toStoragePortRestRep(port);
}
/**
* Check if a storage port with the same name exists for the passed storage system.
*
* @param name Port name
* @param id Storage system id
*/
private void checkForDuplicatePortName(String name, URI systemURI) {
URIQueryResultList storagePortURIs = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getStorageDeviceStoragePortConstraint(systemURI),
storagePortURIs);
Iterator<URI> storagePortIter = storagePortURIs.iterator();
while (storagePortIter.hasNext()) {
StoragePort port = _dbClient.queryObject(StoragePort.class, storagePortIter.next());
if (port != null && !port.getInactive() && port.getLabel().equalsIgnoreCase(name)) {
throw APIException.badRequests.duplicateLabel(name);
}
}
}
/**
*
* List all unmanaged volumes that are available for a storage system.Unmanaged volumes refers to volumes which are available within
* underlying storage systems , but
* still not managed in ViPR.
* As these volumes are not managed in ViPR, there will not be any ViPR specific
* details associated such as, virtual array, virtual pool, or project.
*
* @param id the URN of a ViPR storage system
* @prereq none
* @brief List of all unmanaged volumes available for a storage system
* @return UnManagedVolumeList
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
@Path("/{id}/unmanaged/volumes")
public UnManagedVolumeList getUnManagedVolumes(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
UnManagedVolumeList unManagedVolumeList = new UnManagedVolumeList();
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getStorageDeviceUnManagedVolumeConstraint(id), result);
while (result.iterator().hasNext()) {
URI unManagedVolumeUri = result.iterator().next();
unManagedVolumeList.getUnManagedVolumes()
.add(toRelatedResource(ResourceTypeEnum.UNMANAGED_VOLUMES, unManagedVolumeUri));
}
return unManagedVolumeList;
}
/**
*
* List all unmanaged volumes that are available for a storage system &
* given vpool.
*
* Unmanaged volumes refers to volumes which are available within underlying
* storage systems, but still not managed in ViPR. As these volumes are not
* managed in ViPR, there will not be any ViPR specific details associated
* such as, virtual array, virtual pool, or project.
*
* @param id
* the URN of a ViPR storage system
* @prereq none
* @param vPoolId
* the URN of the Virtual Pool
* @param exportType
* Specifies the type of UnManaged Volume.
* @brief List of all unmanaged volumes available for a storage system & vpool
* @return UnManagedVolumeList
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
@Path("/{id}/unmanaged/{vpoolid}/volumes")
public UnManagedVolumeList getUnManagedVPoolVolumes(@PathParam("id") URI id,
@PathParam("vpoolid") URI vPoolId, @QueryParam("exportType") String exportType) {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
ArgValidator.checkFieldUriType(vPoolId, VirtualPool.class, "id");
if (exportType == null || exportType.trim().length() < 1) {
exportType = ExportType.UNEXPORTED.name();
}
if (ExportType.lookup(exportType) == null) {
throw APIException.badRequests.invalidParameterForUnManagedVolumeQuery(exportType);
}
String isExportedSelected = exportType.equalsIgnoreCase(ExportType.EXPORTED.name()) ? TRUE_STR
: FALSE_STR;
StorageSystem system = _dbClient.queryObject(StorageSystem.class, id);
boolean isVplexSystem = ConnectivityUtil.isAVPlex(system);
Map<String, UnManagedVolume> vplexParentVolumeCache = isVplexSystem ? new HashMap<String, UnManagedVolume>() : null;
UnManagedVolumeList unManagedVolumeList = new UnManagedVolumeList();
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(
AlternateIdConstraint.Factory.getUnManagedVolumeSupportedVPoolConstraint(vPoolId.toString()),
result);
Iterator<UnManagedVolume> unmanagedVolumeItr = _dbClient.queryIterativeObjects(UnManagedVolume.class,
result, true);
while (unmanagedVolumeItr.hasNext()) {
UnManagedVolume umv = unmanagedVolumeItr.next();
String umvExportStatus = umv.getVolumeCharacterstics().get(
SupportedVolumeCharacterstics.IS_NONRP_EXPORTED.toString());
// In some cases, this flag isn't set at all, in which case we need to fall back to
// checking the IS_VOLUME_EXPORTED flag instead.
if (umvExportStatus == null) {
umvExportStatus = umv.getVolumeCharacterstics().get(
SupportedVolumeCharacterstics.IS_VOLUME_EXPORTED.toString());
}
boolean exportStatusMatch = (null != umvExportStatus) && umvExportStatus.equalsIgnoreCase(isExportedSelected);
boolean systemMatch = umv.getStorageSystemUri().equals(id);
// allow backend snapshots for vplex vpool ingestion - must check parent virtual volume for system match
boolean isVplexSnapshot = false;
if (exportStatusMatch && isVplexSystem && VolumeIngestionUtil.isSnapshot(umv)) {
UnManagedVolume vplexParentVolume = VolumeIngestionUtil.findVplexParentVolume(umv, _dbClient, vplexParentVolumeCache);
if (vplexParentVolume != null && vplexParentVolume.getStorageSystemUri().equals(id)) {
isVplexSnapshot = true;
}
}
if (exportStatusMatch && (systemMatch || isVplexSnapshot)) {
String name = (null == umv.getLabel()) ? umv.getNativeGuid() : umv.getLabel();
unManagedVolumeList.getNamedUnManagedVolumes().add(
toNamedRelatedResource(ResourceTypeEnum.UNMANAGED_VOLUMES, umv.getId(), name));
} else {
_log.debug("Ignoring unmanaged volume: {}", umv.getNativeGuid());
}
}
return unManagedVolumeList;
}
/**
*
* List all unmanaged FileSystems that are available for a storage system &
* given vpool.
*
* Unmanaged FileSystems refers to volumes which are available within
* underlying storage systems, but still not managed in ViPR. As these
* FileSystems are not managed in ViPR, there will not be any ViPR specific
* details associated such as, virtual array, virtual pool, or project.
*
* @param id
* the URN of a ViPR storage system
* @prereq none
* @param vPoolId
* the URN of the Virtual Pool
* @param exportType
* Specifies the type of UnManaged FileSystem.
* @brief List of all unmanaged filesystems available for a storage system & vpool
* @return UnManagedFileSystemList
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
@Path("/{id}/unmanaged/{vpoolid}/filesystems")
public UnManagedFileSystemList getUnManagedVPoolFileSystems(@PathParam("id") URI id,
@PathParam("vpoolid") URI vPoolId, @QueryParam("exportType") String exportType) {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
ArgValidator.checkFieldUriType(vPoolId, VirtualPool.class, "id");
if (exportType == null || exportType.trim().length() < 1) {
exportType = ExportType.UNEXPORTED.toString();
}
if (ExportType.lookup(exportType) == null) {
throw APIException.badRequests.invalidParameterForUnManagedVolumeQuery(exportType);
}
String isExportedSelected = exportType.equalsIgnoreCase(ExportType.EXPORTED.name()) ? TRUE_STR
: FALSE_STR;
UnManagedFileSystemList unManagedFileSystemList = new UnManagedFileSystemList();
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getUnManagedFileSystemSupportedVPoolConstraint(vPoolId.toString()), result);
Iterator<UnManagedFileSystem> unmanagedFileSystemItr = _dbClient.queryIterativeObjects(
UnManagedFileSystem.class, result, true);
while (unmanagedFileSystemItr.hasNext()) {
UnManagedFileSystem umfs = unmanagedFileSystemItr.next();
String umfsExportStatus = umfs.getFileSystemCharacterstics().get(
SupportedFileSystemCharacterstics.IS_FILESYSTEM_EXPORTED.toString());
if (umfs.getStorageSystemUri().equals(id) && null != umfsExportStatus
&& isExportedSelected.equalsIgnoreCase(umfsExportStatus)) {
String name = (null == umfs.getLabel()) ? umfs.getNativeGuid() : umfs.getLabel();
unManagedFileSystemList.getNamedUnManagedFileSystem().add(
toNamedRelatedResource(ResourceTypeEnum.UNMANAGED_FILESYSTEMS, umfs.getId(), name));
} else {
_log.info("Ignoring unmanaged filesystem: {}", umfs.getNativeGuid());
}
}
return unManagedFileSystemList;
}
/**
*
* List all unmanaged file systems which are available for a storage system.Unmanaged file systems refers to file systems which are
* available within underlying storage systems , but
* still not managed in ViPR.
* As these file systems are not managed in ViPR, there will not be any ViPR specific
* details associated such as, virtual array, virtual pool, or project.
*
* @param id the URN of a ViPR storage system
*
* @prereq none
* @brief List of all unmanaged file systems available for a storage system
* @return UnManagedFileSystemList
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
@Path("/{id}/unmanaged/filesystems")
public UnManagedFileSystemList getUnManagedFileSystems(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, StorageSystem.class, "id");
UnManagedFileSystemList unManagedFileSystemList = new UnManagedFileSystemList();
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getStorageDeviceUnManagedFileSystemConstraint(id), result);
Iterator<UnManagedFileSystem> unmanagedFileSystemItr = _dbClient.queryIterativeObjects(
UnManagedFileSystem.class, result, true);
while(unmanagedFileSystemItr.hasNext()){
UnManagedFileSystem umfs = unmanagedFileSystemItr.next();
unManagedFileSystemList.getUnManagedFileSystem()
.add(toRelatedResource(ResourceTypeEnum.UNMANAGED_FILESYSTEMS, umfs.getId()));
}
return unManagedFileSystemList;
}
/**
* Retrieve resource representations based on input ids.
*
* @param param POST data containing the id list.
* @brief List data of storage system resources
* @return list of representations.
*
* @throws DatabaseException When an error occurs querying the database.
*/
@POST
@Path("/bulk")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public StorageSystemBulkRep getBulkResources(BulkIdParam param) {
return (StorageSystemBulkRep) super.getBulkResources(param);
}
@SuppressWarnings("unchecked")
@Override
public Class<StorageSystem> getResourceClass() {
return StorageSystem.class;
}
private class mapStorageSystemWithResources implements Function<StorageSystem, StorageSystemRestRep> {
@Override
public StorageSystemRestRep apply(StorageSystem system) {
StorageSystemRestRep restRep = map(system);
restRep.setNumResources(getNumResources(system, _dbClient));
return restRep;
}
}
@Override
public StorageSystemBulkRep queryBulkResourceReps(List<URI> ids) {
Iterator<StorageSystem> _dbIterator = _dbClient.queryIterativeObjects(
StorageSystem.class, ids);
return new StorageSystemBulkRep(BulkList.wrapping(_dbIterator, new mapStorageSystemWithResources()));
}
@Override
public StorageSystemBulkRep queryFilteredBulkResourceReps(List<URI> ids) {
verifySystemAdmin();
return queryBulkResourceReps(ids);
}
@Override
protected ResourceTypeEnum getResourceType() {
return ResourceTypeEnum.STORAGE_SYSTEM;
}
// Counts and returns the number of resources in a storage system
public static Integer getNumResources(StorageSystem system, DbClient dbClient) {
if (StorageSystem.Type.isFileStorageSystem(system.getSystemType())) {
return dbClient.countObjects(FileShare.class, "storageDevice", system.getId());
}
else {
return dbClient.countObjects(Volume.class, "storageDevice", system.getId());
}
}
/*
* Checks for valid Name space for discovery
* Valid Name space for Block ALL & UNMANAGED_VOLUMES
* Valid Name space for File ALL & UNMANAGED_FILESYSTEMS
*/
private boolean validateNameSpace(String nameSpace, StorageSystem storageSystem) {
boolean validNameSpace = false;
if (Discovery_Namespaces.BLOCK_SNAPSHOTS.name().equalsIgnoreCase(nameSpace)) {
if (Type.vmax.name().equalsIgnoreCase(storageSystem.getSystemType()) ||
Type.vnxblock.name().equalsIgnoreCase(storageSystem.getSystemType())) {
return true;
}
return false;
}
if (Discovery_Namespaces.ARRAY_AFFINITY.name().equalsIgnoreCase(nameSpace)) {
if (Type.vmax.name().equalsIgnoreCase(storageSystem.getSystemType()) ||
Type.vnxblock.name().equalsIgnoreCase(storageSystem.getSystemType()) ||
Type.xtremio.name().equalsIgnoreCase(storageSystem.getSystemType()) ||
Type.unity.name().equalsIgnoreCase(storageSystem.getSystemType())) {
return true;
}
return false;
}
// VNXe and Unity storage system supports both block and file type unmanaged objects discovery
if (Type.vnxe.toString().equalsIgnoreCase(storageSystem.getSystemType()) ||
Type.unity.toString().equalsIgnoreCase(storageSystem.getSystemType())) {
if (nameSpace.equalsIgnoreCase(Discovery_Namespaces.UNMANAGED_FILESYSTEMS.toString()) ||
nameSpace.equalsIgnoreCase(Discovery_Namespaces.UNMANAGED_VOLUMES.toString()) ||
nameSpace.equalsIgnoreCase(Discovery_Namespaces.ALL.toString())) {
return true;
}
}
boolean isFileStorageSystem = storageSystem.storageSystemIsFile();
if (isFileStorageSystem) {
if (nameSpace.equalsIgnoreCase(Discovery_Namespaces.UNMANAGED_FILESYSTEMS.toString()) ||
nameSpace.equalsIgnoreCase(Discovery_Namespaces.ALL.toString())) {
validNameSpace = true;
}
} else {
if (nameSpace.equalsIgnoreCase(Discovery_Namespaces.UNMANAGED_VOLUMES.toString()) ||
nameSpace.equalsIgnoreCase(Discovery_Namespaces.ALL.toString())) {
validNameSpace = true;
}
}
return validNameSpace;
}
public PortMetricsProcessor getPortMetricsProcessor() {
return portMetricsProcessor;
}
public void setPortMetricsProcessor(PortMetricsProcessor portMetricsProcessor) {
this.portMetricsProcessor = portMetricsProcessor;
}
}