/*
* Copyright (c) 2008-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.BlockMapper.toVirtualPoolResource;
import static com.emc.storageos.api.mapper.DbObjectMapper.toNamedRelatedResource;
import static com.emc.storageos.api.mapper.VirtualArrayMapper.map;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
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 javax.ws.rs.core.Response;
import com.emc.storageos.db.client.model.*;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.emc.storageos.api.mapper.functions.MapVirtualArray;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.api.service.impl.resource.utils.GeoVisibilityHelper;
import com.emc.storageos.api.service.impl.response.BulkList;
import com.emc.storageos.api.service.impl.response.ResRepFilter;
import com.emc.storageos.api.service.impl.response.RestLinkFactory;
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.NamedElementQueryResultList;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.DiscoveredDataObject.CompatibilityStatus;
import com.emc.storageos.db.client.model.DiscoveredDataObject.DiscoveryStatus;
import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.EndpointUtility;
import com.emc.storageos.db.common.VdcUtil;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.model.BulkIdParam;
import com.emc.storageos.model.NamedRelatedResourceRep;
import com.emc.storageos.model.RelatedResourceRep;
import com.emc.storageos.model.ResourceTypeEnum;
import com.emc.storageos.model.RestLinkRep;
import com.emc.storageos.model.auth.ACLAssignmentChanges;
import com.emc.storageos.model.auth.ACLAssignments;
import com.emc.storageos.model.block.tier.AutoTierPolicyList;
import com.emc.storageos.model.compute.ComputeSystemBulkRep;
import com.emc.storageos.model.compute.ComputeSystemRestRep;
import com.emc.storageos.model.pools.StoragePoolList;
import com.emc.storageos.model.ports.StoragePortList;
import com.emc.storageos.model.search.SearchResultResourceRep;
import com.emc.storageos.model.search.SearchResults;
import com.emc.storageos.model.valid.Endpoint.EndpointType;
import com.emc.storageos.model.varray.AttributeList;
import com.emc.storageos.model.varray.NetworkCreate;
import com.emc.storageos.model.varray.NetworkList;
import com.emc.storageos.model.varray.NetworkRestRep;
import com.emc.storageos.model.varray.VArrayAttributeList;
import com.emc.storageos.model.varray.VirtualArrayBulkRep;
import com.emc.storageos.model.varray.VirtualArrayConnectivityList;
import com.emc.storageos.model.varray.VirtualArrayConnectivityRestRep;
import com.emc.storageos.model.varray.VirtualArrayCreateParam;
import com.emc.storageos.model.varray.VirtualArrayList;
import com.emc.storageos.model.varray.VirtualArrayRestRep;
import com.emc.storageos.model.varray.VirtualArrayUpdateParam;
import com.emc.storageos.model.vpool.VirtualPoolAvailableAttributesResourceRep;
import com.emc.storageos.model.vpool.VirtualPoolList;
import com.emc.storageos.security.authentication.StorageOSUser;
import com.emc.storageos.security.authorization.ACL;
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.security.geo.GeoServiceClient;
import com.emc.storageos.services.OperationTypeEnum;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.emc.storageos.util.ConnectivityUtil;
import com.emc.storageos.volumecontroller.AttributeMatcher;
import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager;
import com.emc.storageos.volumecontroller.impl.utils.AttributeMatcherFramework;
import com.emc.storageos.volumecontroller.impl.utils.ObjectLocalCache;
import com.google.common.collect.Lists;
/**
* VirtualArray service - create/list VirtualArrays, create/list transport zones in
* a VirtualArray.
*/
@Path("/vdc/varrays")
@DefaultPermissions(readRoles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR },
readAcls = { ACL.USE },
writeRoles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public class VirtualArrayService extends TaggedResource {
private static Logger _log = LoggerFactory.getLogger(VirtualArrayService.class);
private static final String EVENT_SERVICE_TYPE = "VirtualArray";
private static final String EVENT_SERVICE_SOURCE = "VirtualArrayService";
private static final String SEARCH_INITIATOR_PORT = "initiator_port";
private static final String SEARCH_HOST = "host";
private static final String SEARCH_CLUSTER = "cluster";
@Autowired
private NetworkService _networkService;
@Autowired
private ComputeSystemService computeSystemService;
@Autowired
protected GeoVisibilityHelper _geoHelper;
@Override
public String getServiceType() {
return EVENT_SERVICE_TYPE;
}
private RecordableEventManager eventManager;
public void setEventManager(RecordableEventManager eventManager) {
this.eventManager = eventManager;
}
private AttributeMatcherFramework _matcherFramework;
/**
* List VirtualArrays in zone the user is authorized to see
*
* @brief List VirtualArrays in zone
* @return List of VirtualArrays
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public VirtualArrayList getVirtualArrayList(
@DefaultValue("") @QueryParam(VDC_ID_QUERY_PARAM) String shortVdcId,
@DefaultValue("") @QueryParam(TENANT_ID_QUERY_PARAM) String tenantId ) {
_geoHelper.verifyVdcId(shortVdcId);
VirtualArrayList list = new VirtualArrayList();
TenantOrg tenant_input = null;
// if input tenant is not empty, but user have no access to it, return empty list.
if (!StringUtils.isEmpty(tenantId)) {
tenant_input = getTenantIfHaveAccess(tenantId);
if (tenant_input == null) {
return list;
}
}
List<VirtualArray> nhObjList = Collections.emptyList();
if (_geoHelper.isLocalVdcId(shortVdcId)) {
_log.debug("retrieving virtual arrays via dbclient");
final List<URI> ids = _dbClient.queryByType(VirtualArray.class, true);
nhObjList = _dbClient.queryObject(VirtualArray.class, ids);
} else {
_log.debug("retrieving virtual arrays via geoclient");
try {
GeoServiceClient geoClient = _geoHelper.getClient(shortVdcId);
final List<URI> ids = Lists.newArrayList(geoClient.queryByType(VirtualArray.class, true));
nhObjList = Lists.newArrayList(geoClient.queryObjects(VirtualArray.class, ids));
} catch (Exception ex) {
// TODO: revisit this exception
_log.error("error retrieving virtual arrays", ex);
throw APIException.internalServerErrors.genericApisvcError("error retrieving virtual arrays", ex);
}
}
StorageOSUser user = getUserFromContext();
// full list if role is {Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR} AND no tenant restriction from input
// else only return the list, which input tenant has access.
if (_permissionsHelper.userHasGivenRole(user,
null, Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR)) {
for (VirtualArray nh : nhObjList) {
if (tenant_input == null || _permissionsHelper.tenantHasUsageACL(tenant_input.getId(), nh)) {
list.getVirtualArrays().add(toNamedRelatedResource(ResourceTypeEnum.VARRAY,
nh.getId(), nh.getLabel()));
}
}
} else {
// otherwise, filter by only authorized to use
URI tenant = null;
if (tenant_input == null) {
tenant = URI.create(user.getTenantId());
} else {
tenant = tenant_input.getId();
}
Set<VirtualArray> varraySet = new HashSet<VirtualArray>();
for (VirtualArray virtualArray : nhObjList) {
if (_permissionsHelper.tenantHasUsageACL(tenant, virtualArray)) {
varraySet.add(virtualArray);
}
}
// if no tenant specified in request, also adding varrays which sub-tenants of the user have access to.
if (tenant_input == null) {
List<URI> subtenants = _permissionsHelper.getSubtenantsWithRoles(user);
for (VirtualArray virtualArray : nhObjList) {
if (_permissionsHelper.tenantHasUsageACL(subtenants, virtualArray)) {
varraySet.add(virtualArray);
}
}
}
for (VirtualArray virtualArray : varraySet) {
list.getVirtualArrays().add(toNamedRelatedResource(ResourceTypeEnum.VARRAY,
virtualArray.getId(), virtualArray.getLabel()));
}
}
return list;
}
/**
* Get all Auto Tier policies associated with given VirtualArray which satisfies
* poolType.
* If provisionType is thick, then only TierPolicies which belongs to Thick Provisioning
* will be returned.
* If provisionType is thin, then only TierPolicies which belongs to
* Thin Provisioning will be returned.
* If provisionType is not specified, then all TierPolicies will be returned.
* In addition to the above constraints, only policies which satisfy the following conditions gets returned
* 1. AutoTiering should be enabled on top level StorageSystem, which these policies belong to
* 2. Policy should be in enabled State.
*
* ProvisionType Values :
* {
* Thin
* Thick
* }
*
* @params QueryParam , which includes provisionType
* provisionType- Thin or Thick
* @brief List VirtualArray auto tier policies for provision type
* @return A reference to a AutoTierPolicy List specifying the id and self link
* for each policy
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/auto-tier-policies")
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN })
public AutoTierPolicyList getAutoTierPolicies(@PathParam("id") URI id,
@QueryParam("provisioning_type") String provisionType,
@QueryParam("unique_auto_tier_policy_names") Boolean uniquePolicyNames) {
if (null == uniquePolicyNames) {
uniquePolicyNames = false;
}
URIQueryResultList poolsInVirtualArray = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getVirtualArrayStoragePoolsConstraint(id.toString()), poolsInVirtualArray);
Iterator<StoragePool> poolIter = _dbClient.queryIterativeObjectField(StoragePool.class, "storageDevice", poolsInVirtualArray);
Set<URI> systems = new HashSet<>();
while (poolIter.hasNext()) {
systems.add(poolIter.next().getStorageDevice());
}
Set<URI> autoTierPolicyURIs = new HashSet<URI>();
for (URI systemId : systems) {
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory
.getStorageDeviceFASTPolicyConstraint(systemId), result);
while (result.iterator().hasNext()) {
URI policyURI = result.iterator().next();
autoTierPolicyURIs.add(policyURI);
}
}
return getAutoTierPolicies(provisionType, autoTierPolicyURIs, uniquePolicyNames);
}
/**
* Get all Auto Tier policies for all VArrays for a given provisioning type.
* If provisionType is thick, then only TierPolicies which belongs to Thick Provisioning
* will be returned.
* If provisionType is thin, then only TierPolicies which belongs to
* Thin Provisioning will be returned.
* If provisionType is not specified, then all TierPolicies will be returned.
* In addition to the above constraints, only policies which satisfy the following conditions gets returned
* 1. AutoTiering should be enabled on top level StorageSystem, which these policies belong to
* 2. Policy should be in enabled State.
*
* ProvisionType Values :
* {
* Thin
* Thick
* }
*
* @params QueryParam , which includes provisionType
* provisionType- Thin or Thick
* @brief List VirtualArray auto tier policies for provision type
* @return A reference to a AutoTierPolicy List specifying the id and self link
* for each policy
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/auto-tier-policies")
@CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN })
public AutoTierPolicyList getAutoTierPolicies(@QueryParam("provisioning_type") String provisionType,
@QueryParam("unique_auto_tier_policy_names") Boolean uniquePolicyNames,
BulkIdParam param) {
if (null == uniquePolicyNames) {
uniquePolicyNames = false;
}
Set<URI> systems = new HashSet<>();
for (URI id : param.getIds()) {
URIQueryResultList poolsInVirtualArray = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getVirtualArrayStoragePoolsConstraint(id.toString()), poolsInVirtualArray);
Iterator<StoragePool> poolIter = _dbClient.queryIterativeObjectField(StoragePool.class, "storageDevice", poolsInVirtualArray);
while (poolIter.hasNext()) {
systems.add(poolIter.next().getStorageDevice());
}
}
Set<URI> autoTierPolicyURIs = new HashSet<>();
for (URI systemId : systems) {
URIQueryResultList result = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory
.getStorageDeviceFASTPolicyConstraint(systemId), result);
while (result.iterator().hasNext()) {
URI policyURI = result.iterator().next();
autoTierPolicyURIs.add(policyURI);
}
}
return getAutoTierPolicies(provisionType, autoTierPolicyURIs, uniquePolicyNames);
}
/**
* get Policies which satisfy the below
* 1. if policy is enabled
* 2. if is enabled on associated Storage System.
* 3. Policy's provisioning Type equals given provisioningType
*/
private AutoTierPolicyList getAutoTierPolicies(String provisionType,
Set<URI> autoTierPolicyUris, boolean uniquePolicyNames) {
AutoTierPolicyList result = new AutoTierPolicyList();
List<URI> autoTierPolicyUriList = new ArrayList<>(autoTierPolicyUris);
Iterator<AutoTieringPolicy> autoTierPolicies = _dbClient.queryIterativeObjects(AutoTieringPolicy.class,
autoTierPolicyUriList, true);
Map<URI, StorageSystem> systemCache = new HashMap<>();
while (autoTierPolicies.hasNext()) {
AutoTieringPolicy policy = autoTierPolicies.next();
// If policy is disabled, skip it
if (!policy.getPolicyEnabled()) {
continue;
}
if (!doesGivenProvisionTypeMatchAutoTierPolicy(provisionType, policy)) {
continue;
}
StorageSystem system = systemCache.get(policy.getStorageSystem());
if (system == null) {
system = _dbClient.queryObject(StorageSystem.class, policy.getStorageSystem());
systemCache.put(policy.getStorageSystem(), system);
}
// if is disabled then skip it too.
if (null != system && system.getAutoTieringEnabled()) {
addAutoTierPolicy(policy, result, uniquePolicyNames);
}
}
return result;
}
/**
* Conditions to find out whether given Provision Type matches
* discovered Policy's provisionType
*
* @param provisioningType
* @param policy
* @return
*/
private boolean doesGivenProvisionTypeMatchAutoTierPolicy(
String provisioningType, AutoTieringPolicy policy) {
if (null == provisioningType || provisioningType.isEmpty()) {
return true;
}
// for vnx case, all Policies will be set to ALL
if (AutoTieringPolicy.ProvisioningType.All.toString().equalsIgnoreCase(
policy.getProvisioningType())) {
return true;
}
if (provisioningType.equalsIgnoreCase(VirtualPool.ProvisioningType.Thick.toString())
&& AutoTieringPolicy.ProvisioningType.ThicklyProvisioned.toString()
.equalsIgnoreCase(policy.getProvisioningType())) {
return true;
}
if (provisioningType.equalsIgnoreCase(VirtualPool.ProvisioningType.Thin.toString())
&& AutoTieringPolicy.ProvisioningType.ThinlyProvisioned.toString()
.equalsIgnoreCase(policy.getProvisioningType())) {
return true;
}
return false;
}
/**
* Create VirtualArray
*
* @param param VirtualArray parameters
* @brief Create VirtualArray
* @return VirtualArray details
*/
@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 VirtualArrayRestRep createVirtualArray(VirtualArrayCreateParam param) {
// check for active nh with same name
checkDuplicateLabel(VirtualArray.class, param.getLabel());
VirtualArray varray = new VirtualArray();
varray.setId(URIUtil.createId(VirtualArray.class));
varray.setLabel(param.getLabel());
if (param.getBlockSettings().getAutoSanZoning() != null) {
varray.setAutoSanZoning(param.getBlockSettings().getAutoSanZoning());
} else {
varray.setAutoSanZoning(true);
}
if (param.getObjectSettings().getProtectionType() != null) {
varray.setProtectionType(param.getObjectSettings().getProtectionType());
}
_dbClient.createObject(varray);
auditOp(OperationTypeEnum.CREATE_VARRAY, true, null,
param.getLabel(), varray.getAutoSanZoning().toString(), varray.getId().toString());
return map(varray);
}
/**
* @brief Update VirtualArray
*
*/
@PUT
@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}")
public VirtualArrayRestRep updateVirtualArray(@PathParam("id") URI id,
VirtualArrayUpdateParam param) {
VirtualArray varray = queryResource(id);
if (param.getLabel() != null && !param.getLabel().isEmpty()) {
if (!varray.getLabel().equalsIgnoreCase(param.getLabel())) {
// check for active VirtualArray with same name
checkDuplicateLabel(VirtualArray.class, param.getLabel());
}
varray.setLabel(param.getLabel());
}
if (param.getBlockSettings().getAutoSanZoning() != null) {
varray.setAutoSanZoning(param.getBlockSettings().getAutoSanZoning());
}
if (param.getObjectSettings().getProtectionType() != null) {
varray.setProtectionType(param.getObjectSettings().getProtectionType());
}
_dbClient.persistObject(varray);
auditOp(OperationTypeEnum.UPDATE_VARRAY, true, null,
id.toString(), param.getLabel(), varray.getAutoSanZoning().toString());
return map(varray);
}
/**
* Get info for VirtualArray
*
* @param id the URN of a ViPR VirtualArray
* @brief Show VirtualArray
* @return VirtualArray details
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public VirtualArrayRestRep getVirtualArray(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = null;
if (_geoHelper.isLocalURI(id)) {
_log.debug("retrieving varray via dbclient");
varray = getVirtualArrayById(id, false);
} else {
_log.debug("retrieving varray via geoclient");
String shortVdcId = VdcUtil.getVdcId(VirtualArray.class, id).toString();
// TODO: do we want to leverage caching like the native lookup
GeoServiceClient geoClient = _geoHelper.getClient(shortVdcId);
try {
varray = geoClient.queryObject(VirtualArray.class, id);
} catch (Exception ex) {
// TODO: revisit this exception
_log.error("error retrieving virtual array from vdc " + shortVdcId, ex);
throw APIException.internalServerErrors.genericApisvcError("error retrieving remote array", ex);
}
}
return map(varray);
}
@Override
protected VirtualArray queryResource(URI id) {
VirtualArray vArray = getVirtualArrayById(id, false);
ArgValidator.checkEntityNotNull(vArray, id, isIdEmbeddedInURL(id));
return vArray;
}
@Override
protected URI getTenantOwner(URI id) {
return null;
}
/**
* Deactivate the VirtualArray.
* When a VirtualArray is deactivated it will move to a "marked for deletion" state.
* Once in this state, new resources may no longer be created in the VirtualArray.
* The VirtualArray will be permanently deleted once all references to this VirtualArray
* of type VirtualPool, BlockSnapshot, FileSystem, Volume, HostingDeviceInfo, StorageSystem,
* Network are deleted
*
* @param id the URN of a ViPR VirtualArray
* @brief Delete VirtualArray
* @return No data returned in response body
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/deactivate")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public Response deleteVirtualArray(@PathParam("id") URI id) {
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntityNotNull(varray, id, isIdEmbeddedInURL(id));
ArgValidator.checkReference(VirtualArray.class, id, checkForDelete(varray));
if (varray.getDeviceRegistered()) {
// registered varray can not be deleted
throw APIException.badRequests.resourceCannotBeDeleted("Varray is already registered.");
}
_dbClient.markForDeletion(varray);
auditOp(OperationTypeEnum.DELETE_VARRAY, true, null,
id.toString(), varray.getLabel());
return Response.ok().build();
}
/**
*
* Returns the storage pools for the VirtualArray with the passed id. When
* the VirtualArray has been explicitly assigned to one or more storage
* pools, this API will return the ids of those storage pools. VirtualArrays
* can be explicitly assigned to storage pools when a storage pool is
* created or later by modifying the storage pool after it has been created.
* <p>
* Whether or not a VirtualArray has been explicitly assigned to any storage pools the VirtualArray may still have implicit associations
* with one or more storage pools due to the VirtualArray's network connectivity. That is, a network resides in a VirtualArray and may
* contain storage ports. This implies that these storage ports reside in the VirtualArray, which further implies that the storage
* system and any storage pools on that storage system also reside in the VirtualArray. If the VirtualArray has no explicit assignments,
* but does have implicit associations, the API will instead return those storage pools implicitly associated.
* <p>
* The API provides the ability to force the return of the list of storage pools implicitly associated with the VirtualArray using the
* request parameter "network_connectivity". Passing this parameter with a value of "true" will return the ids of the storage pools
* implicitly associated with the VirtualArray as described.
*
* @param id the URN of a ViPR VirtualArray.
* @param useNetworkConnectivity true to use the network connectivity to
* get the list of storage pools implicitly connected to the
* VirtualArray.
*
* @brief List VirtualArray storage pools
* @return The ids of the storage pools associated with the VirtualArray.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/storage-pools")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public StoragePoolList getVirtualArrayStoragePools(@PathParam("id") URI id,
@QueryParam("network_connectivity") boolean useNetworkConnectivity) {
// Get and validate the varray with the passed id.
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntity(varray, id, isIdEmbeddedInURL(id));
// Query the database for the storage pools associated with the
// VirtualArray. If the request is for storage pools whose
// association with the VirtualArray is implicit through network
// connectivity, then return only these storage pools.
// Otherwise, the result is for storage pools explicitly assigned
// to the VirtualArray.
URIQueryResultList storagePoolURIs = new URIQueryResultList();
if (useNetworkConnectivity) {
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getImplicitVirtualArrayStoragePoolsConstraint(id.toString()),
storagePoolURIs);
} else {
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getVirtualArrayStoragePoolsConstraint(id.toString()), storagePoolURIs);
}
// Create and return the result.
StoragePoolList storagePools = new StoragePoolList();
for (URI uri : storagePoolURIs) {
StoragePool storagePool = _dbClient.queryObject(StoragePool.class, uri);
if ((storagePool != null)
&& (CompatibilityStatus.COMPATIBLE.toString().equals(storagePool
.getCompatibilityStatus()))
&& (RegistrationStatus.REGISTERED.toString().equals(storagePool
.getRegistrationStatus()))
&& DiscoveryStatus.VISIBLE.toString().equals(storagePool.getDiscoveryStatus())) {
storagePools.getPools().add(toNamedRelatedResource(storagePool, storagePool.getNativeGuid()));
}
}
return storagePools;
}
/**
*
* Returns the storage ports for the VirtualArray with the passed id. When
* the VirtualArray has been explicitly assigned to one or more storage
* ports, this API will return the ids of those storage ports. VirtualArrays
* can be explicitly assigned to storage ports when a storage port is
* created or later by modifying the storage port after it has been created.
* <p>
* Whether or not a VirtualArray has been explicitly assigned to any storage ports the VirtualArray may still have implicit associations
* with one or more storage port due to the VirtualArray's network connectivity. That is, a network resides in a VirtualArray and may
* contain storage ports. This implies that these storage ports reside in the VirtualArray. If the VirtualArray has no explicit storage
* port assignments, but does have implicit associations, the API will instead return those storage ports implicitly associated.
* <p>
* The API provides the ability to force the return of the list of storage ports implicitly associated with the VirtualArray using the
* request parameter "network_connectivity". Passing this parameter with a value of "true" will return the ids of the storage ports
* implicitly associated with the VirtualArray as described.
*
* @param id the URN of a ViPR VirtualArray.
* @param useNetworkConnectivity true to use the network connectivity to
* get the list of storage ports implicitly connected to the
* VirtualArray.
*
* @brief List VirtualArray storage ports
* @return The ids of the storage ports associated with the VirtualArray.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/storage-ports")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public StoragePortList getVirtualArrayStoragePorts(@PathParam("id") URI id,
@QueryParam("network_connectivity") boolean useNetworkConnectivity) {
// Get and validate the varray with the passed id.
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntity(varray, id, isIdEmbeddedInURL(id));
// Query the database for the storage ports associated with the
// VirtualArray. If the request is for storage ports whose
// association with the VirtualArray is implicit through network
// connectivity, then return only these storage ports. Otherwise,
// the result is for storage ports explicitly assigned to the
// VirtualArray.
URIQueryResultList storagePortURIs = new URIQueryResultList();
if (useNetworkConnectivity) {
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getImplicitVirtualArrayStoragePortsConstraint(id.toString()),
storagePortURIs);
} else {
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getVirtualArrayStoragePortsConstraint(id.toString()), storagePortURIs);
}
// Create and return the result.
StoragePortList storagePorts = new StoragePortList();
for (URI uri : storagePortURIs) {
StoragePort storagePort = _dbClient.queryObject(StoragePort.class, uri);
if ((storagePort != null)
&& (RegistrationStatus.REGISTERED.toString().equals(storagePort
.getRegistrationStatus()))
&& DiscoveryStatus.VISIBLE.toString().equals(storagePort.getDiscoveryStatus())) {
storagePorts.getPorts().add(toNamedRelatedResource(storagePort, storagePort.getNativeGuid()));
}
}
return storagePorts;
}
/**
* Returns the id and self link for all VirtualPool associated
* with the VirtualArray.
*
* @param id the URN of a ViPR VirtualArray.
*
* @brief List VirtualArray VirtualPools
* @return A reference to a VirtualPoolList specifying the id and self link for the
* VirtualPool for the VirtualArray.
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/vpools")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public VirtualPoolList getVirtualArrayVirtualPool(
@PathParam("id") URI id,
@DefaultValue("") @QueryParam(TENANT_ID_QUERY_PARAM) String tenantId) {
TenantOrg tenant_input = getTenantIfHaveAccess(tenantId);
VirtualPoolList cosList = new VirtualPoolList();
URIQueryResultList resultList = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getVirtualArrayVirtualPoolConstraint(id),
resultList);
Iterator<URI> cosIterator = resultList.iterator();
while (cosIterator.hasNext()) {
URI cosId = cosIterator.next();
VirtualPool cos = _dbClient.queryObject(VirtualPool.class, cosId);
if (cosList.containsVirtualPoolResource(cosId.toString())) { // already added, ignore
continue;
}
/*
* when input tenant parameter is null, An user can see the vpool if:
* 1. be sysadmin or sysmonitor or restricted sysadmin
* 2. mapped to that tenant.
* 3. tenant admin but not mapping to the tenant cannot see it
*
* when input tenant parameter is not null, in addition to above conditions need be met,
* the specified tenant also need have access to the vpool.
*/
StorageOSUser user = getUserFromContext();
if (_permissionsHelper.userHasGivenRole(user, null,
Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR, Role.RESTRICTED_SYSTEM_ADMIN) ||
userTenantHasPermissionForVirtualPool(cosId.toString())) {
if (tenant_input == null || _permissionsHelper.tenantHasUsageACL(tenant_input.getId(), cos)) {
_log.debug("Adding VirtualPool");
cosList.getVirtualPool().add(toVirtualPoolResource(cos));
}
}
}
return cosList;
}
/**
* Determines if the VirtualPool with the passed id is accessible to
* the user's tenant (includes the subtenants user has TenantAdmin role) .
*
* @param vpoolId The VirtualPool id.
*
* @return true if the VirtualPool is accessible to the user's tenant, false otherwise.
*/
private boolean userTenantHasPermissionForVirtualPool(String vpoolId) {
VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, URI.create(vpoolId));
if (vpool == null) {
_log.error("VirtualPool {} could not be found in the database", vpoolId);
return false;
}
StorageOSUser user = getUserFromContext();
URI tenantURI = URI.create(user.getTenantId());
// check user's home tenant
if (_permissionsHelper.tenantHasUsageACL(tenantURI, vpool)) {
_log.debug("Home tenant {} has usage ACL for VirtualPool {}", tenantURI, vpoolId);
return true;
}
// check user's subtenant
for (String subtenantId : _permissionsHelper.getSubtenantsForUser(user)) {
if (_permissionsHelper.tenantHasUsageACL(URI.create(subtenantId), vpool)) {
_log.debug("Subtenant {} has usage ACL for VirtualPool {}", tenantURI, vpoolId);
return true;
}
}
return false;
}
/**
* Create a network and assign it to the virtual array.
*
* @param param Network parameters
* @param id the URN of a ViPR VirtualArray
* @see NetworkService#createNetwork(NetworkCreate)
* @deprecated used {@link NetworkService#createNetwork(NetworkCreate)}
* @brief Create Network
* @return Network details
*/
@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/networks")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN })
public NetworkRestRep createNetwork(@PathParam("id") URI id,
NetworkCreate param) {
_log.debug("createNetwork: started for varray {}", id);
// check VirtualArray
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntity(varray, id, isIdEmbeddedInURL(id));
if (param.getVarrays() != null && !param.getVarrays().isEmpty()) {
throw APIException.badRequests.invalidParameterForVarrayNetwork(id.toString());
}
// set the varray in the param
param.setVarrays(Collections.singletonList(id));
// delegate to network service the actual work
return _networkService.createNetwork(param);
}
/**
* List transport zones in VirtualArray
*
* @param id the URN of a ViPR VirtualArray
* @brief List VirtualArray Networks
* @return List of Networks
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/networks")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public NetworkList getNetworkList(@PathParam("id") URI id) {
NetworkList networkList = new NetworkList();
// Verify the passed virtual array id.
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntity(varray, id, isIdEmbeddedInURL(id));
// Get the networks assigned to the virtual array.
List<Network> networks = CustomQueryUtility.queryActiveResourcesByRelation(
_dbClient, id, Network.class, "connectedVirtualArrays");
for (Network network : networks) {
if (network == null || network.getInactive() == true) {
continue;
}
networkList.getNetworks().add(
toNamedRelatedResource(ResourceTypeEnum.NETWORK, network.getId(),
network.getLabel()));
}
return networkList;
}
/**
* Get VirtualArray ACL. There is only one privilege, "use", and it is used to determine who can create resources in the VirtualArray.
*
* @param id the URN of a ViPR VirtualArray
* @brief Show VirtualArray ACL
* @return ACL Assignment details
*/
@GET
@Path("/{id}/acl")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public ACLAssignments getAcls(@PathParam("id") URI id) {
return getAclsResponse(id);
}
/**
* Add or remove individual ACL entry(s). Request body must include at least one add or remove operation
*
* @param changes ACL assignment changes
* @param id the URN of a ViPR VirtualArray
* @brief Add or remove ACL for VirtualArray
* @return No data returned in response body
*/
@PUT
@Path("/{id}/acl")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@CheckPermission(roles = { Role.SECURITY_ADMIN, Role.SYSTEM_ADMIN, Role.RESTRICTED_SYSTEM_ADMIN }, blockProxies = true)
public ACLAssignments updateAcls(@PathParam("id") URI id,
ACLAssignmentChanges changes) {
VirtualArray varray = getVirtualArrayById(id, true);
_permissionsHelper.updateACLs(varray, changes, new PermissionsHelper.UsageACLFilter(_permissionsHelper));
_dbClient.persistObject(varray);
auditOp(OperationTypeEnum.MODIFY_VARRAY_ACL, true, null,
id.toString(), varray.getLabel());
return getAclsResponse(id);
}
private ACLAssignments getAclsResponse(URI id) {
VirtualArray varray = getVirtualArrayById(id, false);
ACLAssignments response = new ACLAssignments();
response.setAssignments(_permissionsHelper.convertToACLEntries(varray.getAcls()));
return response;
}
/**
* Get information about the connectivity of the registered VirtualArray
* with the passed id.
*
* @param id the URN of a ViPR VirtualArray
* @brief List VirtualArray connectivity
* @return NeighbourhoodConnectivityRestRep object
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/connectivity")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public VirtualArrayConnectivityList getVirtualArrayConnectivity(@PathParam("id") URI id) {
return getConnectivity(queryResource(id));
}
/**
* Gets information about VirtualArrays that are connected to the passed in VirtualArray that support some kind of protection
*
* @param varray
* @return rest response
*/
private VirtualArrayConnectivityList getConnectivity(VirtualArray varray) {
Set<VirtualArrayConnectivityRestRep> connections = AbstractBlockServiceApiImpl.getVirtualArrayConnectivity(_dbClient,
varray.getId());
VirtualArrayConnectivityList connectivityList = new VirtualArrayConnectivityList();
connectivityList.setConnections(new ArrayList<VirtualArrayConnectivityRestRep>());
connectivityList.getConnections().addAll(connections);
return connectivityList;
}
/**
* Get tenant object from id
*
* @param id the URN of a ViPR tenant object
* @return
*/
private VirtualArray getVirtualArrayById(URI id, boolean checkInactive) {
if (id == null) {
return null;
}
VirtualArray n = _permissionsHelper.getObjectById(id, VirtualArray.class);
ArgValidator.checkEntity(n, id, isIdEmbeddedInURL(id), checkInactive);
return n;
}
/**
* Finds the available attributes & its values in a varray. Ex: In a
* varray, if a system supports raid_levels such as RAID1, RAID2 then
* this API call provides the supported information.
*
* @param id the URN of a ViPR VirtualArray.
* @brief List available attributes for VirutalArray
* @return List available attributes for VirutalArray
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/available-attributes")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public AttributeList getAvailableAttributes(@PathParam("id") URI id) {
// Get and validate the varray with the passed id.
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntityNotNull(varray, id, isIdEmbeddedInURL(id));
_log.info("Finding the available attributes for varray: {}", id);
AttributeList list = new AttributeList();
list.setVArrayId(id);
ObjectLocalCache cache = new ObjectLocalCache(_dbClient);
List<StoragePool> pools = getVirtualArrayPools(Arrays.asList(id), cache).get(id);
Map<String, Set<String>> availableAttrs = _matcherFramework.getAvailableAttributes(id, pools, cache,
AttributeMatcher.VPOOL_MATCHERS);
cache.clearCache();
for (Map.Entry<String, Set<String>> entry : availableAttrs.entrySet()) {
list.getAttributes().add(new VirtualPoolAvailableAttributesResourceRep(entry.getKey(), entry.getValue()));
}
return list;
}
/**
* Finds the available attributes & its values in a varray. Ex: In a
* varray, if a system supports raid_levels such as RAID1, RAID2 then
* this API call provides the supported information.
*
* @brief List available attributes for all VirutalArrays
* @return List available attributes for all VirutalArrays
*/
@POST
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/available-attributes")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR })
public VArrayAttributeList getAvailableAttributes(BulkIdParam param) {
_log.info("Finding the available attributes for all varray: {}");
VArrayAttributeList vArrayAttributes = new VArrayAttributeList();
ObjectLocalCache cache = new ObjectLocalCache(_dbClient);
Map<URI, List<StoragePool>> allPools = getVirtualArrayPools(param.getIds(), cache);
for (Map.Entry<URI, List<StoragePool>> varrEntry : allPools.entrySet()) {
Map<String, Set<String>> availableAttrs = _matcherFramework.
getAvailableAttributes(varrEntry.getKey(), varrEntry.getValue(),
cache, AttributeMatcher.VPOOL_MATCHERS);
AttributeList list = new AttributeList();
list.setVArrayId(varrEntry.getKey());
for (Map.Entry<String, Set<String>> entry : availableAttrs.entrySet()) {
list.getAttributes().add(new VirtualPoolAvailableAttributesResourceRep(entry.getKey(), entry.getValue()));
}
if (!list.getAttributes().isEmpty()) {
vArrayAttributes.getAttributes().add(list);
}
}
cache.clearCache();
return vArrayAttributes;
}
/**
* Retrieve resource representations based on input ids.
*
* @param param POST data containing the id list.
* @brief List data of varray resources
* @return list of representations.
*/
@POST
@Path("/bulk")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Override
public VirtualArrayBulkRep getBulkResources(BulkIdParam param) {
return (VirtualArrayBulkRep) super.getBulkResources(param);
}
private Map<URI, List<StoragePool>> getVirtualArrayPools(List<URI> varrayIds, ObjectLocalCache cache) {
Map<URI, List<StoragePool>> poolMap = new HashMap<>();
for (URI varr : varrayIds) {
List<StoragePool> poolList = poolMap.get(varr);
if (poolList == null) {
poolList = new ArrayList<>();
poolMap.put(varr, poolList);
}
URIQueryResultList poolsQueryResult = new URIQueryResultList();
_dbClient.queryByConstraint(AlternateIdConstraint.Factory
.getVirtualArrayStoragePoolsConstraint(varr.toString()), poolsQueryResult);
Iterator<URI> poolItr = poolsQueryResult.iterator();
while (poolItr.hasNext()) {
StoragePool pool = cache.queryObject(StoragePool.class, poolItr.next());
poolList.add(pool);
}
}
return poolMap;
}
public void setMatcherFramework(AttributeMatcherFramework matcherFramework) {
_matcherFramework = matcherFramework;
}
@SuppressWarnings("unchecked")
@Override
public Class<VirtualArray> getResourceClass() {
return VirtualArray.class;
}
@Override
public VirtualArrayBulkRep queryBulkResourceReps(List<URI> ids) {
if (!ids.iterator().hasNext()) {
return new VirtualArrayBulkRep();
}
// get vdc id from the first id; assume all id's are from the same vdc
String shortVdcId = VdcUtil.getVdcId(getResourceClass(), ids.iterator().next()).toString();
Iterator<VirtualArray> dbIterator;
if (shortVdcId.equals(VdcUtil.getLocalShortVdcId())) {
dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids);
} else {
GeoServiceClient geoClient = _geoHelper.getClient(shortVdcId);
try {
dbIterator = geoClient.queryObjects(getResourceClass(), ids);
} catch (Exception ex) {
// TODO: revisit this exception
_log.error("error retrieving bulk virtual arrays from vdc " + shortVdcId, ex);
throw APIException.internalServerErrors.genericApisvcError("error retrieving remote array", ex);
}
}
return new VirtualArrayBulkRep(BulkList.wrapping(dbIterator, MapVirtualArray.getInstance()));
}
/**
* Fetches all Compute Systems that are visible in the vArray
*
* First determine physical connectivity to any switches in the vArrray.
* 1. From the vArray, determine the networks. (Call this Network Set)
* 2. From the networks, get the physical switches that are attached.
* 3. For each physical switch, iterate through the networks and get the FC endpoints.
* 4. Look for any of the FIC ports in any of the FC endpoints on any of the
* networks on the physical switch. When a FIC port matches, call this FIC
* Port.
* 5. If found, then there is physical connectivity.
*
* With physical connectivity Established:
* 1. Given the FIC Port from step (4), pull the VSAN or VSANs assigned to
* it on UCS.
* 2. If the set contains one of the networks from the Network
* Set in (1), we have connectivity to that vArray.
*
* @param id
* the URN of a ViPR VirtualArray.
* @brief List all Compute Systems that are visible in the vArray
* @return List of Compute Systems
*/
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/{id}/compute-systems")
@CheckPermission(roles = { Role.SYSTEM_ADMIN, Role.SYSTEM_MONITOR }, acls = { ACL.USE })
public ComputeSystemBulkRep getComputeSystems(@PathParam("id") URI id) {
_log.info("get connected CS for vArray: {}", id);
// Get and validate the varray with the passed id.
ArgValidator.checkFieldUriType(id, VirtualArray.class, "id");
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, id);
ArgValidator.checkEntityNotNull(varray, id, isIdEmbeddedInURL(id));
BulkIdParam matchingCsIds = new BulkIdParam();
// get varray networks
List<Network> networks = CustomQueryUtility.queryActiveResourcesByRelation(_dbClient, id, Network.class,
"connectedVirtualArrays");
// collect network vsanIds and switch ids
Set<String> networkVsanIds = new HashSet<>();
Set<String> nsIds = new HashSet<>();
for (Network network : networks) {
if (StorageProtocol.Transport.FC.name().equalsIgnoreCase(network.getTransportType())
&& DiscoveredSystemObject.RegistrationStatus.REGISTERED.name().equals(network.getRegistrationStatus())) {
networkVsanIds.add(network.getNativeId());
if (network.getNetworkSystems() != null) {
nsIds.addAll(network.getNetworkSystems());
}
}
}
_log.info("vArray has these networks: {}", networkVsanIds);
// use only registered network systems
Set<URI> nsUris = new HashSet<>();
for (String nsUri : nsIds) {
nsUris.add(URI.create(nsUri));
}
List<NetworkSystem> nsList = _dbClient.queryObject(NetworkSystem.class, nsUris);
for (NetworkSystem ns : nsList) {
if (!DiscoveredSystemObject.RegistrationStatus.REGISTERED.name().equals(ns.getRegistrationStatus())) {
nsIds.remove(ns.getId().toString());
}
}
_log.info("the networks run on these network systems: {}", nsIds);
if (networkVsanIds.isEmpty() || nsIds.isEmpty()) {
// no networks in the array - exit early
return new ComputeSystemBulkRep();
}
// for every switch get FCEndpoint.remotePortName(s)
Set<String> connectedEndpoints = new HashSet<String>();
for (String nsId : nsIds) {
URIQueryResultList uriList = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getNetworkSystemFCPortConnectionConstraint(URI.create(nsId)),
uriList);
List<URI> epIds = new ArrayList<URI>();
Iterator<URI> iter = uriList.iterator();
while (iter.hasNext()) {
epIds.add(iter.next());
}
List<FCEndpoint> eps = _dbClient.queryObjectField(FCEndpoint.class, "remotePortName", epIds);
for (FCEndpoint ep : eps) {
connectedEndpoints.add(ep.getRemotePortName());
}
}
_log.debug("all connected endpoints: {}", connectedEndpoints);
// get all CS
List<URI> csIds = _dbClient.queryByType(ComputeSystem.class, true);
List<ComputeSystem> csList = _dbClient.queryObject(ComputeSystem.class, csIds);
for (ComputeSystem cs : csList) {
if (!DiscoveredSystemObject.RegistrationStatus.REGISTERED.name().equals(cs.getRegistrationStatus())) {
// skip not registered CS
continue;
}
boolean connected = false;
_log.info("evaluating uplinks of cs: {}", cs.getLabel());
// loop thru UplinkPorts to find matches
URIQueryResultList uris = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getComputeSystemComputeFabricUplinkPortConstraint(cs.getId()), uris);
List<ComputeFabricUplinkPort> uplinkPorts = _dbClient
.queryObject(ComputeFabricUplinkPort.class, uris, true);
for (ComputeFabricUplinkPort port : uplinkPorts) {
if (connectedEndpoints.contains(port.getWwpn())) {
_log.info("found matching endpoint: {}", port.getWwpn());
if (!Collections.disjoint(port.getVsans(), networkVsanIds)) {
_log.info("and networks overlap: {}", port.getVsans());
matchingCsIds.getIds().add(cs.getId());
connected = true;
break;
}
}
}
if (connected) {
continue; // skip uplink port channel matching as we are already connected
}
// now loop thru UplinkPortChannels to find matches
uris = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getComputeSystemComputeUplinkPortChannelConstraint(cs.getId()), uris);
List<ComputeFabricUplinkPortChannel> uplinkPortChannels = _dbClient
.queryObject(ComputeFabricUplinkPortChannel.class, uris, true);
for (ComputeFabricUplinkPortChannel port : uplinkPortChannels) {
if (connectedEndpoints.contains(port.getWwpn())) {
_log.info("found matching endpoint: {}", port.getWwpn());
if (!Collections.disjoint(port.getVsans(), networkVsanIds)) {
_log.info("and networks overlap: {}", port.getVsans());
matchingCsIds.getIds().add(cs.getId());
connected = true;
break;
}
}
}
}
_log.info("these CS are connected to the vArray: {}", matchingCsIds.getIds());
if (matchingCsIds.getIds().isEmpty()) {
return new ComputeSystemBulkRep();
}
ComputeSystemBulkRep computeSystemReps = computeSystemService.getBulkResources(matchingCsIds);
return mapValidServiceProfileTemplatesToComputeSystem(computeSystemReps, varray.getId());
}
private ComputeSystemBulkRep mapValidServiceProfileTemplatesToComputeSystem(ComputeSystemBulkRep bulkRep, URI varrayId) {
_log.debug("mapping Service Profile Templates valid for varray to the Compute Systems");
ComputeSystemBulkRep rep = new ComputeSystemBulkRep();
List<ComputeSystemRestRep> computeSystemList = new ArrayList<ComputeSystemRestRep>();
for (ComputeSystemRestRep computeSystem : bulkRep.getComputeSystems()) {
computeSystem.setServiceProfileTemplates(getServiceProfileTemplatesForComputeSystem(computeSystem.getId(), varrayId));
computeSystemList.add(computeSystem);
}
rep.setComputeSystems(computeSystemList);
return rep;
}
private List<NamedRelatedResourceRep> getServiceProfileTemplatesForComputeSystem(URI computeSystemId, URI varrayId) {
List<NamedRelatedResourceRep> templates = new ArrayList<NamedRelatedResourceRep>();
ComputeSystem computeSystem = _dbClient.queryObject(ComputeSystem.class, computeSystemId);
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, varrayId);
_log.debug("Finding SPTs from Compute System:" + computeSystem.getLabel() + " valid for varray:" + varray.getLabel());
List<NamedRelatedResourceRep> spts = computeSystemService.getServiceProfileTemplatesForComputeSystem(computeSystem, _dbClient);
StringSet varrays = new StringSet();
varrays.add(varrayId.toString());
// Filter SPTs that are not valid for the varrays for the UCS in this vcp
for (NamedRelatedResourceRep spt : spts) {
if (computeSystemService.isServiceProfileTemplateValidForVarrays(varrays, spt.getId())) {
templates.add(spt);
_log.debug("SPT " + spt.getName() + " is valid for the varray:" + varray.getLabel());
} else {
_log.debug("SPT " + spt.getName() + " is not valid for the varray:" + varray.getLabel());
}
}
return templates;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
protected VirtualArrayBulkRep queryFilteredBulkResourceReps(
List<URI> ids) {
if (isSystemOrRestrictedSystemAdmin()) {
return queryBulkResourceReps(ids);
}
if (!ids.iterator().hasNext()) {
return new VirtualArrayBulkRep();
}
// get vdc id from the first id; assume all id's are from the same vdc
String shortVdcId = VdcUtil.getVdcId(getResourceClass(), ids.iterator().next()).toString();
Iterator<VirtualArray> dbIterator;
if (shortVdcId.equals(VdcUtil.getLocalShortVdcId())) {
dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids);
} else {
GeoServiceClient geoClient = _geoHelper.getClient(shortVdcId);
try {
dbIterator = geoClient.queryObjects(getResourceClass(), ids);
} catch (Exception ex) {
// TODO: revisit this exception
_log.error("error retrieving bulk virtual arrays from vdc " + shortVdcId, ex);
throw APIException.internalServerErrors.genericApisvcError("error retrieving remote array", ex);
}
}
BulkList.ResourceFilter filter = new BulkList.VirtualArrayACLFilter(getUserFromContext(), _permissionsHelper);
return new VirtualArrayBulkRep(BulkList.wrapping(dbIterator, MapVirtualArray.getInstance(), filter));
}
@Override
protected ResourceTypeEnum getResourceType() {
return ResourceTypeEnum.VARRAY;
}
public static class VirtualArrayResRepFilter extends
ResRepFilter<SearchResultResourceRep> {
boolean _authorized = false;
public VirtualArrayResRepFilter(StorageOSUser user,
PermissionsHelper permissionsHelper, boolean authorized) {
super(user, permissionsHelper);
_authorized = authorized;
}
@Override
public boolean isAccessible(SearchResultResourceRep resrep) {
URI id = resrep.getId();
// check permission on varray
VirtualArray varray = _permissionsHelper
.getObjectById(id, VirtualArray.class);
if (varray == null || varray.getInactive()) {
_log.error("Could not find varray {} in the database or"
+ "the varray is inactive", id);
return false;
}
if (!_authorized) {
if (!isVirtualArrayAccessible(varray)) {
_log.error("varray {} is not accessible.", id);
return false;
}
}
return true;
}
}
/**
* Finds the virtual arrays for the initiator port with the passed
* identifier and returns the id, name, and self link for those virtual
* arrays. This API only supports fiber channel and iSCSI initiator ports,
* and the passed port identifier must be the WWN or IQN of the port.
*
* Note that in order for an initiator to be associated with any virtual,
* arrays it must be in an active network. The virtual arrays for the passed
* initiator are those active virtual arrays associated with the storage
* ports in the initiator's active network. If the initiator is not in a
* network, an empty list is returned.
*
* parameter: 'initiator_port' The identifier of the initiator port.
*
*
* @param parameters The search parameters.
* @param authorized Whether or not the caller is authorized.
*
* @return The search results specifying the virtual arrays for the
* initiator identified in the passed search parameters.
*/
@Override
protected SearchResults getOtherSearchResults(Map<String, List<String>> parameters,
boolean authorized) {
SearchResults result = new SearchResults();
String[] searchCriteria = { SEARCH_INITIATOR_PORT, SEARCH_HOST, SEARCH_CLUSTER };
validateSearchParameters(parameters, searchCriteria);
Set<String> varrayIds = new HashSet<String>();
for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
if (entry.getKey().equals(SEARCH_INITIATOR_PORT)) {
String initiatorId = parameters.get(SEARCH_INITIATOR_PORT).get(0);
// Validate the user passed a value for the initiator port.
ArgValidator.checkFieldNotEmpty(initiatorId, SEARCH_INITIATOR_PORT);
// Validate the format of the passed initiator port.
if (!EndpointUtility.isValidEndpoint(initiatorId, EndpointType.ANY)) {
throw APIException.badRequests.initiatorPortNotValid();
}
_log.info("Searching for virtual arrays for initiator {}", initiatorId);
varrayIds.addAll(ConnectivityUtil.getInitiatorVarrays(initiatorId, _dbClient));
break;
} else if (entry.getKey().equals(SEARCH_HOST)) {
// find and validate host
String hostId = parameters.get(SEARCH_HOST).get(0);
URI hostUri = URI.create(hostId);
ArgValidator.checkFieldNotEmpty(hostId, SEARCH_HOST);
Host host = queryObject(Host.class, hostUri, false);
verifyAuthorizedInTenantOrg(host.getTenant(), getUserFromContext());
_log.info("looking for virtual arrays connected to host " + host.getHostName());
varrayIds.addAll(getVarraysForHost(hostUri));
break;
} else if (entry.getKey().equals(SEARCH_CLUSTER)) {
// find and validate cluster
String clusterId = parameters.get(SEARCH_CLUSTER).get(0);
URI clusterUri = URI.create(clusterId);
ArgValidator.checkFieldNotEmpty(clusterId, SEARCH_CLUSTER);
Cluster cluster = queryObject(Cluster.class, clusterUri, false);
verifyAuthorizedInTenantOrg(cluster.getTenant(), getUserFromContext());
_log.info("looking for virtual arrays connected to cluster " + cluster.getLabel());
List<Set<String>> hostVarraySets = new ArrayList<Set<String>>();
List<NamedElementQueryResultList.NamedElement> dataObjects =
listChildren(clusterUri, Host.class, "label", "cluster");
for (NamedElementQueryResultList.NamedElement dataObject : dataObjects) {
Set<String> hostVarrays = getVarraysForHost(dataObject.getId());
hostVarraySets.add(hostVarrays);
}
boolean first = true;
for (Set<String> varrays : hostVarraySets) {
if (first) {
varrayIds.addAll(varrays);
first = false;
} else {
varrayIds.retainAll(varrays);
}
}
break;
}
}
// For each virtual array in the set create a search result
// and add it to the search results list.
List<SearchResultResourceRep> searchResultList = new ArrayList<SearchResultResourceRep>();
if (!varrayIds.isEmpty()) {
for (String varrayId : varrayIds) {
URI varrayURI = URI.create(varrayId);
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, varrayURI);
// Filter out those that are inactive or not accessible to the user.
if (varray == null || varray.getInactive()) {
_log.info("Could not find virtual array {} in the database, or "
+ "the virtual array is inactive", varrayURI);
continue;
}
if (!authorized) {
if (!_permissionsHelper.tenantHasUsageACL(
URI.create(getUserFromContext().getTenantId()), varray)) {
_log.info("Virtual array {} is not accessible.", varrayURI);
continue;
}
}
RestLinkRep selfLink = new RestLinkRep("self", RestLinkFactory.newLink(getResourceType(), varrayURI));
SearchResultResourceRep searchResult = new SearchResultResourceRep(varrayURI, selfLink, varray.getLabel());
searchResultList.add(searchResult);
}
}
result.setResource(searchResultList);
return result;
}
/**
* Return the Virtual Arrays connected to a given Host
* by checking the connectivity of the Host's Initiators.
*
* @param hostUri URI of a Host
* @return a set of Virtual Array URI strings
*/
private Set<String> getVarraysForHost(URI hostUri) {
_log.info("looking for initiators for host URI: " + hostUri);
Set<String> varrayIds = new HashSet<String>();
Set<String> initiatorList = new HashSet<String>();
List<NamedElementQueryResultList.NamedElement> dataObjects =
listChildren(hostUri, Initiator.class, "iniport", "host");
for (NamedElementQueryResultList.NamedElement dataObject : dataObjects) {
initiatorList.add(dataObject.getId().toString());
}
for (String initUri : initiatorList) {
Initiator init = _dbClient.queryObject(Initiator.class, URI.create(initUri));
if (null != init) {
_log.info(" found initiator " + init.getInitiatorPort());
varrayIds.addAll(ConnectivityUtil.getInitiatorVarrays(
init.getInitiatorPort(), _dbClient));
_log.info(" connected to varrays: " + varrayIds.toString());
}
}
return varrayIds;
}
/**
* Validate if one param passed is valid.
*
* @param params to evaluate
* @param criterias that can be searched for
* @return true of false
*/
private boolean isValidSearch(Map<String, List<String>> params, String[] criterias) {
for (String search : criterias) {
if (params.containsKey(search)) {
return true;
}
}
return false;
}
/**
* Validate search params.
*
* @param params to evaluate
* @param criterias that can be searched for
*/
private void validateSearchParameters(Map<String, List<String>> params, String[] criterias) {
if (!isValidSearch(params, criterias)) {
throw APIException.badRequests.invalidParameterSearchMissingParameter(
getResourceClass().getName(),
Arrays.toString(criterias));
}
// Make sure all parameters are our parameters, otherwise throw an
// exception because we don't support other search criteria than our own.
// Also, make sure only ONE of the acceptable parameters has been given
List<String> unacceptableKeys = new ArrayList<String>();
List<String> acceptableKeys = new ArrayList<String>();
boolean found = false;
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
found = false;
for (String search : criterias) {
if (entry.getKey().equals(search)) {
found = true;
acceptableKeys.add(entry.getKey());
}
}
if (!found) {
unacceptableKeys.add(entry.getKey());
}
}
// {1} parameter for {0} search could not be combined with any other parameter but found {2}
if (acceptableKeys.size() > 1) {
throw APIException.badRequests.parameterForSearchCouldNotBeCombinedWithAnyOtherParameter(
getResourceClass().getName(),
Arrays.toString(criterias),
acceptableKeys.toString());
}
if (!unacceptableKeys.isEmpty()) {
throw APIException.badRequests.parameterForSearchCouldNotBeCombinedWithAnyOtherParameter(
getResourceClass().getName(),
Arrays.toString(criterias),
unacceptableKeys.toString());
}
}
/**
* Get object specific permissions filter
*/
@Override
public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user,
PermissionsHelper permissionsHelper) {
return new VirtualArrayResRepFilter(user, permissionsHelper, false);
}
/**
* Validates that each of the passed virtual array ids reference an existing
* virtual array in the database and throws a bad request exception when
* an invalid id is found.
*
* @param virtualArrayIds The set of virtual array ids to validate
* @param dbClient A reference to a DB client.
*/
public static void checkVirtualArrayURIs(Set<String> virtualArrayIds,
DbClient dbClient) {
Set<String> invalidIds = new HashSet<String>();
if ((virtualArrayIds != null) && (!virtualArrayIds.isEmpty())) {
Iterator<String> virtualArrayIdsIter = virtualArrayIds.iterator();
while (virtualArrayIdsIter.hasNext()) {
URI virtualArrayURI = null;
try {
virtualArrayURI = URI.create(virtualArrayIdsIter.next());
VirtualArray virtualArray = dbClient.queryObject(VirtualArray.class,
virtualArrayURI);
if (virtualArray == null) {
invalidIds.add(virtualArrayURI.toString());
}
} catch (DatabaseException e) {
if (virtualArrayURI != null) {
invalidIds.add(virtualArrayURI.toString());
}
}
}
}
if (!invalidIds.isEmpty()) {
throw APIException.badRequests.theURIsOfParametersAreNotValid("virtual arrays", invalidIds);
}
}
}