package org.ovirt.engine.core.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Named;
import javax.inject.Singleton;
import org.ovirt.engine.core.common.businessentities.Quota;
import org.ovirt.engine.core.common.businessentities.QuotaCluster;
import org.ovirt.engine.core.common.businessentities.QuotaEnforcementTypeEnum;
import org.ovirt.engine.core.common.businessentities.QuotaStorage;
import org.ovirt.engine.core.compat.Guid;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
/**
* {@code QuotaDaoImpl} implements the calling to quota stored procedures ({@link QuotaDao}).
*/
@Named
@Singleton
public class QuotaDaoImpl extends BaseDao implements QuotaDao {
/**
* Save {@code Quota} entity with specific {@code Quota} storage and {@code Quota} cluster limitation list.
*/
@Override
public void save(Quota quota) {
saveGlobalQuota(quota);
saveStorageSpecificQuotas(quota);
saveClusterSpecificQuotas(quota);
}
/**
* Get {@code Quota} by name.
*
* @param quotaName
* - The quota name to find.
* @param storagePoolId
* - Id of the storage pool to which the quota belongs
* @return The quota entity that was found.
*/
@Override
public Quota getQuotaByQuotaName(String quotaName, Guid storagePoolId) {
MapSqlParameterSource quotaParameterSource = getCustomMapSqlParameterSource();
quotaParameterSource.addValue("quota_name", quotaName);
quotaParameterSource.addValue("storage_pool_id", storagePoolId);
return getCallsHandler().executeRead("GetQuotaByQuotaName", getQuotaFromResultSet(), quotaParameterSource);
}
/**
* Get list of {@code Quota}s which are consumed by ad element id in storage pool (if not storage pool id not
* null).
*
* @param adElementId
* - The user ID or group ID.
* @param storagePoolId
* - The storage pool Id to search the quotas in (If null search all over the setup).
* @param recursive
* - Find by
* @return All quotas for user.
*/
@Override
public List<Quota> getQuotaByAdElementId(Guid adElementId, Guid storagePoolId, boolean recursive) {
MapSqlParameterSource quotaParameterSource = getCustomMapSqlParameterSource();
quotaParameterSource.addValue("ad_element_id", adElementId);
quotaParameterSource.addValue("storage_pool_id", storagePoolId);
quotaParameterSource.addValue("recursive", recursive);
return getCallsHandler().executeReadList("GetQuotaByAdElementId",
getQuotaMetaDataFromResultSet(),
quotaParameterSource);
}
/**
* Get specific limitation for {@code Cluster}.
*
* @param clusterId
* - The vds group id, if null returns all the vds group limitations in the storage pool.
* @param quotaId
* - The {@code Quota} id
* @return List of QuotaStorage
*/
@Override
public List<QuotaCluster> getQuotaClusterByClusterGuid(Guid clusterId, Guid quotaId) {
return getQuotaClusterByClusterGuid(clusterId, quotaId, true);
}
/**
* Get specific limitation for {@code Cluster}.
*
* @param clusterId
* - The vds group id, if null returns all the vds group limitations in the storage pool.
* @param quotaId
* - The {@code Quota} id
* @param allowEmpty
* - Whether to return empty quotas or not
* @return List of QuotaStorage
*/
@Override
public List<QuotaCluster> getQuotaClusterByClusterGuid(Guid clusterId, Guid quotaId, boolean allowEmpty) {
MapSqlParameterSource parameterSource =
createQuotaIdParameterMapper(quotaId)
.addValue("cluster_id", clusterId)
.addValue("allow_empty", allowEmpty);
return getCallsHandler().executeReadList("GetQuotaClusterByClusterGuid",
getClusterQuotaResultSet(),
parameterSource);
}
/**
* Get specific limitation for storage domain.
*
* @param storageId
* - The storage id, if null returns all the storages limitation in the storage pool.
* @param quotaId
* - The quota id
* @return List of QuotaStorage
*/
@Override
public List<QuotaStorage> getQuotaStorageByStorageGuid(Guid storageId, Guid quotaId) {
return getQuotaStorageByStorageGuid(storageId, quotaId, true);
}
/**
* Get specific limitation for storage domain.
*
* @param storageId
* - The storage id, if null returns all the storages limitation in the storage pool.
* @param quotaId
* - The quota id
* @param allowEmpty
* - Whether to return empty quotas or not
* @return List of QuotaStorage
*/
@Override
public List<QuotaStorage> getQuotaStorageByStorageGuid(Guid storageId, Guid quotaId, boolean allowEmpty) {
MapSqlParameterSource parameterSource =
createQuotaIdParameterMapper(quotaId).addValue("storage_id", storageId).addValue("allow_empty",
allowEmpty);
return getCallsHandler().executeReadList("GetQuotaStorageByStorageGuid",
getQuotaStorageResultSet(),
parameterSource);
}
@Override
public List<QuotaStorage> getAllQuotaStorageIncludingConsumption() {
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
return getCallsHandler().executeReadList("calculateAllStorageUsage",
getQuotaStorageResultSet(),
parameterSource);
}
/**
* Returns all the Quota storages in the storage pool if v_storage_id is null, if v_storage_id is not null then a
* specific quota storage will be returned.
*/
@Override
public List<Quota> getQuotaByStoragePoolGuid(Guid storagePoolId) {
MapSqlParameterSource parameterSource =
getCustomMapSqlParameterSource().addValue("storage_pool_id", storagePoolId);
return getCallsHandler().executeReadList("GetQuotaByStoragePoolGuid",
getQuotaFromResultSet(),
parameterSource);
}
@Override
public Quota getDefaultQuotaForStoragePool(Guid storagePoolId) {
MapSqlParameterSource parameterSource =
getCustomMapSqlParameterSource().addValue("storage_pool_id", storagePoolId);
return getCallsHandler().executeRead("GetDefaultQuotaForStoragePool",
getQuotaFromResultSet(),
parameterSource);
}
/**
* Get full {@code Quota} entity.
*/
@Override
public Quota getById(Guid quotaId) {
MapSqlParameterSource parameterSource = createQuotaIdParameterMapper(quotaId);
Quota quotaEntity =
getCallsHandler().executeRead("GetQuotaByQuotaGuid", getQuotaFromResultSet(), parameterSource);
if (quotaEntity != null) {
quotaEntity.setQuotaClusters(getQuotaClusterByQuotaGuid(quotaId));
quotaEntity.setQuotaStorages(getQuotaStorageByQuotaGuid(quotaId));
}
return quotaEntity;
}
@Override
public int getQuotaCount() {
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
return getCallsHandler().executeRead
("getQuotaCount", SingleColumnRowMapper.newInstance(Long.class), parameterSource).intValue();
}
/**
* Get all the full quotas. Including consumption data. This call is very heavy and should be used really and with
* caution. It was created to support cache initialization
*
* @return all quota in DB (including consumption calculation)
*/
@Override
public List<Quota> getAllQuotaIncludingConsumption() {
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
// get thin quota (only basic quota meta data)
List<Quota> allThinQuota = getCallsHandler().executeReadList("getAllThinQuota", getQuotaMetaDataFromResultSet(), parameterSource);
if (allThinQuota != null && !allThinQuota.isEmpty()){
Map<Guid, Quota> allQuotaMap = new HashMap<>();
for (Quota quota : allThinQuota) {
allQuotaMap.put(quota.getId(), quota);
}
List<QuotaStorage> quotaStorageList = getAllQuotaStorageIncludingConsumption();
List<QuotaCluster> quotaClusterList = getAllQuotaClusterIncludingConsumption();
if (quotaStorageList != null) {
for (QuotaStorage quotaStorage : quotaStorageList) {
Quota quota = allQuotaMap.get(quotaStorage.getQuotaId());
if (quota != null) {
if (quotaStorage.getStorageId() == null || quotaStorage.getStorageId().equals(Guid.Empty)) {
quota.setGlobalQuotaStorage(quotaStorage);
} else {
if (quota.getQuotaStorages() == null) {
quota.setQuotaStorages(new ArrayList<>());
}
quota.getQuotaStorages().add(quotaStorage);
}
}
}
}
if (quotaClusterList != null) {
for (QuotaCluster quotaCluster : quotaClusterList) {
Quota quota = allQuotaMap.get(quotaCluster.getQuotaId());
if (quota != null) {
if (quotaCluster.getClusterId() == null || quotaCluster.getClusterId().equals(Guid.Empty)) {
quota.setGlobalQuotaCluster(quotaCluster);
} else {
if (quota.getQuotaClusters() == null) {
quota.setQuotaClusters(new ArrayList<>());
}
quota.getQuotaClusters().add(quotaCluster);
}
}
}
}
}
// The thin quota were all filled
return allThinQuota;
}
/**
* Get all quota storages which belong to quota with quotaId.
*/
@Override
public List<QuotaStorage> getQuotaStorageByQuotaGuid(Guid quotaId) {
MapSqlParameterSource parameterSource = createQuotaIdParameterMapper(quotaId);
return getCallsHandler().executeReadList("GetQuotaStorageByQuotaGuid",
getQuotaStorageResultSet(),
parameterSource);
}
/**
* Get all quota storages which belong to quota with quotaId.
*/
@Override
public List<QuotaStorage> getQuotaStorageByQuotaGuidWithGeneralDefault(Guid quotaId) {
return getQuotaStorageByStorageGuid(null, quotaId, false);
}
/**
* Get all quota Vds groups, which belong to quota with quotaId.
*/
@Override
public List<QuotaCluster> getQuotaClusterByQuotaGuid(Guid quotaId) {
MapSqlParameterSource parameterSource = createQuotaIdParameterMapper(quotaId);
return getCallsHandler().executeReadList("GetQuotaClusterByQuotaGuid",
getClusterQuotaResultSet(),
parameterSource);
}
@Override
public List<QuotaCluster> getAllQuotaClusterIncludingConsumption() {
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
return getCallsHandler().executeReadList("calculateAllClusterUsage",
getClusterQuotaResultSet(),
parameterSource);
}
/**
* Get all quota Vds groups, which belong to quota with quotaId.
* In case no quota Vds Groups are returned, a fictitious QuotaCluster is returned,
* with an {@link Guid#Empty} Vds Id and a {@code null} name.
*/
@Override
public List<QuotaCluster> getQuotaClusterByQuotaGuidWithGeneralDefault(Guid quotaId) {
return getQuotaClusterByClusterGuid(null, quotaId, false);
}
@Override
public List<Quota> getAllRelevantQuotasForStorage(Guid storageId, long engineSessionSeqId, boolean isFiltered) {
MapSqlParameterSource quotaParameterSource = getCustomMapSqlParameterSource();
quotaParameterSource.addValue("storage_id", storageId)
.addValue("engine_session_seq_id", engineSessionSeqId)
.addValue("is_filtered", isFiltered);
return getCallsHandler().executeReadList("getAllThinQuotasByStorageId",
getQuotaMetaDataFromResultSet(),
quotaParameterSource);
}
@Override
public List<Quota> getAllRelevantQuotasForCluster(Guid clusterId, long engineSessionSeqId, boolean isFiltered) {
MapSqlParameterSource quotaParameterSource = getCustomMapSqlParameterSource();
quotaParameterSource.addValue("cluster_id", clusterId)
.addValue("engine_session_seq_id", engineSessionSeqId)
.addValue("is_filtered", isFiltered);
return getCallsHandler().executeReadList("getAllThinQuotasByClusterId",
getQuotaMetaDataFromResultSet(),
quotaParameterSource);
}
/**
* Remove quota with quota id.
*/
@Override
public void remove(Guid id) {
getCallsHandler().executeModification("DeleteQuotaByQuotaGuid",
createQuotaIdParameterMapper(id));
}
/**
* Update {@code Quota}, by updating the quota meta data and remove all its limitations and add the limitations
* from the quota parameter.
*/
@Override
public void update(Quota quota) {
getCallsHandler().executeModification("UpdateQuotaMetaData",
createQuotaMetaDataParameterMapper(quota));
getCallsHandler().executeModification("DeleteQuotaLimitationByQuotaGuid",
createQuotaIdParameterMapper(quota.getId()));
getCallsHandler().executeModification("InsertQuotaLimitation", getFullQuotaParameterMap(quota));
saveStorageSpecificQuotas(quota);
saveClusterSpecificQuotas(quota);
}
/**
* Return initialized entity with quota Vds group result set.
*/
private RowMapper<QuotaCluster> getClusterQuotaResultSet() {
return (rs, rowNum) -> {
QuotaCluster entity = new QuotaCluster();
entity.setQuotaId(getGuidDefaultEmpty(rs, "quota_id"));
entity.setQuotaClusterId(getGuidDefaultEmpty(rs, "quota_cluster_id"));
entity.setClusterId(getGuidDefaultEmpty(rs, "cluster_id"));
entity.setClusterName(rs.getString("cluster_name"));
entity.setMemSizeMB((Long) rs.getObject("mem_size_mb"));
entity.setMemSizeMBUsage((Long) rs.getObject("mem_size_mb_usage"));
entity.setVirtualCpu((Integer) rs.getObject("virtual_cpu"));
entity.setVirtualCpuUsage((Integer) rs.getObject("virtual_cpu_usage"));
return entity;
};
}
/**
* Returns initialized entity with quota Storage result set.
*/
private RowMapper<QuotaStorage> getQuotaStorageResultSet() {
return (rs, rowNum) -> {
QuotaStorage entity = new QuotaStorage();
entity.setQuotaId(getGuidDefaultEmpty(rs, "quota_id"));
entity.setQuotaStorageId(getGuidDefaultEmpty(rs, "quota_storage_id"));
entity.setStorageId(getGuidDefaultEmpty(rs, "storage_id"));
entity.setStorageName(rs.getString("storage_name"));
entity.setStorageSizeGB((Long) rs.getObject("storage_size_gb"));
entity.setStorageSizeGBUsage((Double) rs.getObject("storage_size_gb_usage"));
return entity;
};
}
/**
* Returns initialized entity with quota result set.
*/
private RowMapper<Quota> getQuotaFromResultSet() {
return (rs, rowNum) -> {
Quota entity = getQuotaMetaDataFromResultSet(rs);
// Check if memory size is not null, this is an indication if global limitation for vds group exists or
// not, since global limitation must be for all the quota vds group parameters.
if (rs.getObject("mem_size_mb") != null) {
// Set global vds group quota.
QuotaCluster clusterEntity = new QuotaCluster();
clusterEntity.setMemSizeMB((Long) rs.getObject("mem_size_mb"));
clusterEntity.setMemSizeMBUsage((Long) rs.getObject("mem_size_mb_usage"));
clusterEntity.setVirtualCpu((Integer) rs.getObject("virtual_cpu"));
clusterEntity.setVirtualCpuUsage((Integer) rs.getObject("virtual_cpu_usage"));
entity.setGlobalQuotaCluster(clusterEntity);
}
// Check if storage limit size is not null, this is an indication if global limitation for storage
// exists or
// not.
if (rs.getObject("storage_size_gb") != null) {
// Set global storage quota.
QuotaStorage storageEntity = new QuotaStorage();
storageEntity.setStorageSizeGB((Long) rs.getObject("storage_size_gb"));
storageEntity.setStorageSizeGBUsage((Double) rs.getObject("storage_size_gb_usage"));
entity.setGlobalQuotaStorage(storageEntity);
}
return entity;
};
}
/**
* Returns initialized entity with quota meta data result set.
*/
private RowMapper<Quota> getQuotaMetaDataFromResultSet() {
return (rs, rowNum) -> getQuotaMetaDataFromResultSet(rs);
}
private Quota getQuotaMetaDataFromResultSet(ResultSet rs) throws SQLException {
Quota entity = new Quota();
entity.setId(getGuidDefaultEmpty(rs, "quota_id"));
entity.setStoragePoolId(getGuidDefaultEmpty(rs, "storage_pool_id"));
entity.setStoragePoolName(rs.getString("storage_pool_name"));
entity.setQuotaName((String) rs.getObject("quota_name"));
entity.setDescription((String) rs.getObject("description"));
entity.setThresholdClusterPercentage((Integer) rs.getObject("threshold_cluster_percentage"));
entity.setThresholdStoragePercentage((Integer) rs.getObject("threshold_storage_percentage"));
entity.setGraceClusterPercentage((Integer) rs.getObject("grace_cluster_percentage"));
entity.setGraceStoragePercentage((Integer) rs.getObject("grace_storage_percentage"));
entity.setQuotaEnforcementType(QuotaEnforcementTypeEnum.forValue(rs.getInt("quota_enforcement_type")));
entity.setDefault(rs.getBoolean("is_default"));
return entity;
}
private MapSqlParameterSource createQuotaIdParameterMapper(Guid quotaId) {
return getCustomMapSqlParameterSource().addValue("id", quotaId);
}
/**
* Build quota storage parameter map, for quota limitation table, to indicate specific limitation on storage domain.
*
* @param quotaId
* - The global quota id which the storage is referencing to
* @param quotaStorage
* - The business entity which reflects the limitation on the specific storage.
* @return - Parameter Map
*/
private MapSqlParameterSource getQuotaStorageParameterMap(Guid quotaId, QuotaStorage quotaStorage) {
return createQuotaIdParameterMapper(quotaStorage.getQuotaStorageId()).addValue("quota_id",
quotaId)
.addValue("storage_id", quotaStorage.getStorageId())
.addValue("cluster_id", null)
.addValue("storage_size_gb", quotaStorage.getStorageSizeGB())
.addValue("virtual_cpu", null)
.addValue("mem_size_mb", null);
}
/**
* Build quota vds group parameter map, for quota limitation table, to indicate specific limitation on specific
* {@code Cluster}.
*
* @param quotaId
* - The global quota id which the {@code Cluster} is referencing to
* @param quotaCluster
* - The business entity which reflects the limitation on the specific cluster.
* @return - {@code Cluster} Parameter Map
*/
private MapSqlParameterSource getQuotaClusterParameterMap(Guid quotaId, QuotaCluster quotaCluster) {
return createQuotaIdParameterMapper(quotaCluster.getQuotaClusterId()).addValue("quota_id", quotaId)
.addValue("cluster_id", quotaCluster.getClusterId())
.addValue("storage_id", null)
.addValue("storage_size_gb", null)
.addValue("virtual_cpu", quotaCluster.getVirtualCpu())
.addValue("mem_size_mb", quotaCluster.getMemSizeMB());
}
/**
* Build parameter map, for quota limitation table, to indicate global limitation on {@code StoragePool}.
*
* @param quota
* - The global quota.
* @return - Global quota Parameter Map.
*/
private MapSqlParameterSource getFullQuotaParameterMap(Quota quota) {
return getCustomMapSqlParameterSource()
.addValue("id", quota.getId())
.addValue("quota_id", quota.getId())
.addValue("cluster_id", null)
.addValue("storage_id", null)
.addValue("storage_size_gb",
quota.getGlobalQuotaStorage() != null ? quota.getGlobalQuotaStorage()
.getStorageSizeGB() : null)
.addValue("virtual_cpu",
quota.getGlobalQuotaCluster() != null ? quota.getGlobalQuotaCluster().getVirtualCpu()
: null)
.addValue("mem_size_mb",
quota.getGlobalQuotaCluster() != null ? quota.getGlobalQuotaCluster().getMemSizeMB()
: null);
}
private MapSqlParameterSource createQuotaMetaDataParameterMapper(Quota quota) {
return createQuotaIdParameterMapper(quota.getId()).addValue("storage_pool_id", quota.getStoragePoolId())
.addValue("quota_name", quota.getQuotaName())
.addValue("description", quota.getDescription())
.addValue("threshold_cluster_percentage", quota.getThresholdClusterPercentage())
.addValue("threshold_storage_percentage", quota.getThresholdStoragePercentage())
.addValue("grace_cluster_percentage", quota.getGraceClusterPercentage())
.addValue("grace_storage_percentage", quota.getGraceStoragePercentage())
.addValue("is_default", quota.isDefault());
}
private void saveGlobalQuota(Quota quota) {
getCallsHandler().executeModification("InsertQuota", createQuotaMetaDataParameterMapper(quota));
getCallsHandler().executeModification("InsertQuotaLimitation", getFullQuotaParameterMap(quota));
}
private void saveClusterSpecificQuotas(Quota quota) {
// Add quota specific vds group limitations.
for (QuotaCluster quotaCluster : quota.getQuotaClusters()) {
getCallsHandler().executeModification("InsertQuotaLimitation",
getQuotaClusterParameterMap(quota.getId(), quotaCluster));
}
}
private void saveStorageSpecificQuotas(Quota quota) {
// Add quota specific storage domains limitations.
for (QuotaStorage quotaStorage : quota.getQuotaStorages()) {
getCallsHandler().executeModification("InsertQuotaLimitation",
getQuotaStorageParameterMap(quota.getId(), quotaStorage));
}
}
@Override
public List<Quota> getAllWithQuery(String query) {
return getJdbcTemplate().query(query, getQuotaMetaDataFromResultSet());
}
@Override
public boolean isQuotaInUse(Quota quota){
MapSqlParameterSource parameterSource = getCustomMapSqlParameterSource()
.addValue("quota_id", quota.getId());
Map<String, Object> dbResults =
new SimpleJdbcCall(getJdbcTemplate()).withFunctionName("IsQuotaInUse").execute(
parameterSource);
String resultKey = getDialect().getFunctionReturnKey();
return dbResults.get(resultKey) != null && (Boolean) dbResults.get(resultKey);
}
@Override
public List<Integer> getNonCountableQutoaVmStatuses() {
return getCallsHandler().executeReadList
("getNonCountableQutoaVmStatuses", SingleColumnRowMapper.newInstance(Integer.class), null);
}
}