/* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*
*/
package com.emc.storageos.api.service.impl.resource.cinder;
import static com.emc.storageos.db.client.constraint.ContainmentConstraint.Factory.getBlockSnapshotByConsistencyGroup;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.api.service.authorization.PermissionsHelper;
import com.emc.storageos.cinder.model.CinderAvailabiltyZone;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.PrefixConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.BlockConsistencyGroup;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.Project;
import com.emc.storageos.db.client.model.VirtualArray;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.security.authentication.StorageOSUser;
import com.emc.storageos.security.authorization.ACL;
import com.emc.storageos.security.authorization.Role;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
public class CinderHelpers {
private DbClient _dbClient;
private PermissionsHelper _permissionsHelper;
private static final Logger _log = LoggerFactory.getLogger(CinderHelpers.class);
private static final long GB = 1024 * 1024 * 1024;
private static CinderHelpers instCinderHelpers = null;
private static Object mutex = new Object();
private CinderHelpers(DbClient dbClient, PermissionsHelper permissionsHelper) {
_dbClient = dbClient;
_permissionsHelper = permissionsHelper;
}
public CinderHelpers() {
}
public static CinderHelpers getInstance(DbClient dbClient, PermissionsHelper permissionsHelper) {
if (instCinderHelpers == null) {
synchronized (mutex) {
if (instCinderHelpers == null) {
instCinderHelpers = new CinderHelpers(dbClient, permissionsHelper);
}
}
}
return instCinderHelpers;
}
/**
* Get project from the OpenStack Tenant ID parameter
*
*
* @prereq none
*
* @param openstackTenantId
* @param user - with user credential details
*
* @brief get project fro given tenant_id
* @return Project
*/
protected Project getProject(String openstackTenantId, StorageOSUser user) {
URI vipr_tenantId = URI.create(user.getTenantId());
URIQueryResultList uris = new URIQueryResultList();
_dbClient.queryByConstraint(
PrefixConstraint.Factory.getTagsPrefixConstraint(
Project.class, openstackTenantId, vipr_tenantId),
uris);
for (URI projectUri : uris) {
Project project = _dbClient.queryObject(Project.class, projectUri);
if (project != null && isAuthorized(projectUri, user))
return project;
else if (!isAuthorized(projectUri, user)) {
throw APIException.badRequests.accessDenied();
}
}
return null; // no project found
}
// Helper function to check if the user has authorization to access the project
// This is used by all search functions
private boolean isAuthorized(URI projectUri, StorageOSUser user) {
if (_permissionsHelper == null)
return false;
Project project = _permissionsHelper.getObjectById(projectUri, Project.class);
if (project == null)
return false;
if ((_permissionsHelper.userHasGivenRole(user, project.getTenantOrg().getURI(),
Role.SYSTEM_MONITOR, Role.TENANT_ADMIN) || _permissionsHelper.userHasGivenACL(user,
projectUri, ACL.ANY))) {
return true;
}
else
return false;
}
/**
* Get vpool from the given label
*
*
* @prereq none
*
* @param vpool_name
*
* @brief get vpool
* @return vpool
*/
public VirtualPool getVpool(String vpoolName) {
if (vpoolName == null)
return null;
URIQueryResultList uris = new URIQueryResultList();
_dbClient.queryByConstraint(
PrefixConstraint.Factory.getLabelPrefixConstraint(
VirtualPool.class, vpoolName),
uris);
for (URI vpoolUri : uris) {
VirtualPool vpool = _dbClient.queryObject(VirtualPool.class, vpoolUri);
if (vpool != null && vpool.getType().equals(VirtualPool.Type.block.name()))
return vpool;
}
return null; // no matching vpool found
}
/**
* Get varray from the given label
*
*
* @prereq none
*
* @param varray_name
* @param user
*
* @brief get varray
* @return varray
*/
public VirtualArray getVarray(String varrayName, StorageOSUser user) {
if ((varrayName == null) || (varrayName.equals(""))) {
ArrayList<CinderAvailabiltyZone> azList = new ArrayList<CinderAvailabiltyZone>();
getAvailabilityZones(azList, user);
if (!azList.isEmpty()) {
varrayName = ((CinderAvailabiltyZone) azList.get(0)).zoneName;
}
else {
throw APIException.internalServerErrors.genericApisvcError("Get Varray failed", new Throwable("VArray not configured."));
}
}
URIQueryResultList uris = new URIQueryResultList();
_dbClient.queryByConstraint(
PrefixConstraint.Factory.getLabelPrefixConstraint(
VirtualArray.class, varrayName),
uris);
if (uris != null) {
while (uris.iterator().hasNext()) {
URI varrayUri = uris.iterator().next();
VirtualArray varray = _dbClient.queryObject(VirtualArray.class, varrayUri);
if (varray != null && !varray.getInactive())
return varray;
}
}
return null; // no matching varray found
}
public String trimId(String id) {
String[] splits = id.split(":");
if (splits.length >= 4) {
String uriId = splits[3];
return uriId;
}
else {
return null;
}
}
/**
* Get list of availability zones
*
*
* @prereq none
*
* @param az_list
* @param user
*
* @brief get availablityzones
* @return availablityZoneList
*/
public List getAvailabilityZones(List azList, StorageOSUser user) {
_log.debug("retrieving virtual arrays via dbclient");
List<VirtualArray> nhObjList = Collections.emptyList();
final List<URI> ids = _dbClient.queryByType(VirtualArray.class, true);
nhObjList = _dbClient.queryObject(VirtualArray.class, ids);
// filter by only authorized to use
URI tenant = URI.create(user.getTenantId());
for (VirtualArray nh : nhObjList) {
if (_permissionsHelper.tenantHasUsageACL(tenant, nh)) {
CinderAvailabiltyZone objAz = new CinderAvailabiltyZone();
objAz.zoneName = nh.getLabel();
objAz.zoneState.available = !nh.getInactive();
azList.add(objAz);
}
}
return azList;
}
/**
* Get Volume for passed project and Id
*
* @prereq none
*
* @brief query and return Volume for provided Project and Id
* @param Project, searchId
* @return Volume
*/
public Volume queryVolumeById(Project proj, String searchId) {
URIQueryResultList uris = new URIQueryResultList();
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getProjectVolumeConstraint(proj.getId()),
uris);
for (URI volumeUri : uris) {
Volume volume = _dbClient.queryObject(Volume.class, volumeUri);
String trimmedId = trimId(volume.getId().toString());
if (volume != null && !volume.getInactive() && (trimmedId.equalsIgnoreCase(searchId))) {
return volume;
}
}
return null;
}
/**
* Get DataObject for passed tenant id and class type
*
* @prereq none
*
* @brief query and return blockObject for provided openstackId and
* class type like volume/snapshot/consistencygroup
* @param openstackTenantId
* @return Dataobject
*/
public DataObject queryByTag(URI openstackId, StorageOSUser user, Class<? extends DataObject> block) {
URI vipr_tenantId = URI.create(user.getTenantId());
URIQueryResultList uris = new URIQueryResultList();
_dbClient.queryByConstraint(
PrefixConstraint.Factory.getTagsPrefixConstraint(
block, openstackId.toString(), vipr_tenantId), uris);
if (uris != null) {
while (uris.iterator().hasNext()) {
URI blockUri = uris.iterator().next();
DataObject blockObject = _dbClient.queryObject(block, blockUri);
if (blockObject != null) {
return blockObject;
}
}
}
return null;
}
/**
* Get all consistency group based on tenant id
*
* @prereq none
*
* @brief get consistency group Uris
* @param openstackTenantId
* @return URIQueryResultList
*/
protected URIQueryResultList getConsistencyGroupsUris(
String openstackTenantId, StorageOSUser user) {
URIQueryResultList uris = new URIQueryResultList();
Project project = getProject(openstackTenantId,
user);
if (project == null) // return empty list
return null;
_dbClient.queryByConstraint(ContainmentConstraint.Factory
.getProjectBlockConsistencyGroupConstraint(project.getId()),
uris);
return uris;
}
/**
* Get Consistency Group Snapshot Uris
*
*
* @prereq none
*
* @param consistencyGroupsUris
* @brief get consistency group snapshot URIS
* @return URI list
*
*/
public URIQueryResultList getConsistencyGroupSnapshotUris(URI consistencyGroupsUri) {
URIQueryResultList snapshotUris = new URIQueryResultList();
if (consistencyGroupsUri != null) {
BlockConsistencyGroup blockCG = _dbClient.queryObject(
BlockConsistencyGroup.class, consistencyGroupsUri);
if (null != blockCG && !(blockCG.getInactive())) {
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getBlockSnapshotByConsistencyGroup(blockCG.getId()),
snapshotUris);
}
}
return snapshotUris;
}
/**
* If the Consistency Group has Snapshot(s), then Volume can not be created.
*
* @param blockConsistencyGroup Block Consistency Grp Instance
* @return
*/
public boolean verifyConsistencyGroupHasSnapshot(BlockConsistencyGroup consistencyGroup) {
final URIQueryResultList cgSnapshotsResults = new URIQueryResultList();
_dbClient.queryByConstraint(getBlockSnapshotByConsistencyGroup(consistencyGroup.getId()),
cgSnapshotsResults);
Iterator<BlockSnapshot> blockSnapshotIterator = _dbClient.queryIterativeObjects(BlockSnapshot.class, cgSnapshotsResults);
if (blockSnapshotIterator.hasNext()) {
return true;
}
return false;
}
}