Skip to content
Snippets Groups Projects

Product/588 quota management

Merged Marcel Nellesen requested to merge Product/588-quotaManagement into Sprint/2021-01
6 files
+ 305
42
Compare changes
  • Side-by-side
  • Inline
Files
6
using Coscine.Action;
using Coscine.Action.EventArgs;
using Coscine.Api.Project.ParameterObjects;
using Coscine.Api.Project.ReturnObjects;
using Coscine.ApiCommons;
using Coscine.ApiCommons.Factories;
using Coscine.Configuration;
@@ -32,8 +34,12 @@ namespace Coscine.Api.Project.Controllers
private readonly Emitter _emitter;
private readonly ActivatedFeaturesModel _activatedFeaturesModel;
private readonly ProjectRoleModel _projectRoleModel;
private readonly ProjectQuotaModel _projectQuotaModel;
private readonly ResourceTypeModel _resourceTypeModel;
private readonly ResourceModel _resourceModel;
private readonly CoscineLogger _coscineLogger;
private readonly AnalyticsLogObject _analyticsLogObject;
private readonly int _maxAvailable = 100;
/// <summary>
/// ProjectController constructor
@@ -47,6 +53,9 @@ namespace Coscine.Api.Project.Controllers
_emitter = new Emitter(_configuration);
_activatedFeaturesModel = new ActivatedFeaturesModel();
_projectRoleModel = new ProjectRoleModel();
_resourceTypeModel = new ResourceTypeModel();
_resourceModel = new ResourceModel();
_projectQuotaModel = new ProjectQuotaModel();
_coscineLogger = new CoscineLogger(logger);
_analyticsLogObject = new AnalyticsLogObject();
}
@@ -155,56 +164,231 @@ namespace Coscine.Api.Project.Controllers
}
/// <summary>
/// Retrieves the quota for the selected project
/// Retrieves the quota for the selected project.
/// </summary>
/// <param name="id">Id of the resource</param>
/// <returns>Json object or Statuscode 401</returns>
[HttpGet("[controller]/{id}/quotas")]
public ActionResult<IEnumerable<ProjectQuota>> Quotas(string id)
/// <param name="projectId">Id of the project.</param>
/// <returns>List of project quotas</returns>
[HttpGet("[controller]/{projectId}/quota/-/all")]
public ActionResult<IEnumerable<ProjectQuota>> Quotas(string projectId)
{
var user = _authenticator.GetUser();
var projectObject = ObjectFactory<ProjectObject>.DeserializeFromStream(Request.Body);
var guidId = Guid.Parse(id);
var project = _projectModel.GetById(guidId);
if (_projectModel.HasAccess(user, project, UserRoles.Owner))
if (!Guid.TryParse(projectId, out Guid projectGuid))
{
return BadRequest($"{projectId} is not a guid.");
}
var project = _projectModel.GetById(projectGuid);
if (project == null)
{
ProjectQuotaModel projectQuotaModel = new ProjectQuotaModel();
var projectQuotas =
projectQuotaModel.GetAllWhere((projectQuota) =>
projectQuota.ProjectId == guidId
&& projectQuota.ResourceType.Enabled == true)
.Select((projectQuota) => projectQuotaModel.CreateReturnObjectFromDatabaseObject(projectQuota));
return NotFound($"Could not find project with id: {projectId}");
}
if (!_projectModel.HasAccess(user, project, UserRoles.Owner))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
var projectQuotas =
_projectQuotaModel.GetAllWhere((projectQuota) =>
projectQuota.ProjectId == projectGuid
&& projectQuota.ResourceType.Enabled == true);
ResourceModel resourceModel = new ResourceModel();
RDSResourceTypeModel rdsResourceTypeModel = new RDSResourceTypeModel();
var returnList = new List<dynamic>();
foreach (var projectQuota in projectQuotas)
var resourceTypes = _resourceTypeModel.GetAllWhere(x => x.Enabled);
return Json(resourceTypes.Select(x =>
{
var projectQuota = _projectQuotaModel.GetWhere((y) =>
y.ProjectId == projectGuid &&
y.ResourceTypeId == x.Id);
return new ProjectQuotaReturnObject
{
// TODO: Cleanup quota and give it to every resource, this hard coded solution seems not scalable
if (projectQuota.ResourceType.DisplayName == "rds")
{
var resources = resourceModel.GetAllWhere((resource) =>
resource.TypeId == projectQuota.ResourceType.Id
&& (from connection in resource.ProjectResourceResourceIdIds
where connection.ProjectId == guidId
select connection).Any());
var size = resources.Sum((resource) =>
rdsResourceTypeModel.GetById(resource.ResourceTypeOptionId.Value).Size);
returnList.Add(new {
type = projectQuota.ResourceType.DisplayName,
available = projectQuota.Quotas,
allocated = size
});
}
}
return Json(returnList);
Id = x.Id,
Name = x.DisplayName,
Used = CalculateUsed(x, projectGuid),
Allocated = projectQuota == null ? 0 : projectQuota.Quota
};
}));
}
private int CalculateUsed(ResourceType resourceType, Guid projectId)
{
var resourceTypeDefinition = ResourceTypeFactory.CreateResourceTypeObject(resourceType.DisplayName, _configuration);
var resources = _resourceModel.GetAllWhere((resource) =>
(from projectResource in resource.ProjectResourceResourceIdIds
where projectResource.ProjectId == projectId
select projectResource).Any() &&
resource.TypeId == resourceType.Id);
var used = resources.Sum(y => resourceTypeDefinition.GetResourceQuotaAvailable(y.Id.ToString(), _resourceModel.GetResourceTypeOptions(y.Id)).Result);
return (int)used;
}
/// <summary>
/// Retrieves the quota for the selected project and resource Type.
/// </summary>
/// <param name="projectId">Id of the project</param>
/// <param name="resourceTypeId">Id of the resource type</param>
/// <returns>The project quota for the resource type.</returns>
[HttpGet("[controller]/{projectId}/quota/{resourceTypeId}")]
public ActionResult<ProjectQuotaReturnObject> Quota(string projectId, string resourceTypeId)
{
var user = _authenticator.GetUser();
if (!Guid.TryParse(projectId, out Guid projectGuid))
{
return BadRequest($"{projectId} is not a guid.");
}
else
var project = _projectModel.GetById(projectGuid);
if (project == null)
{
return NotFound($"Could not find project with id: {projectId}");
}
if (!_projectModel.HasAccess(user, project, UserRoles.Owner))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
if (!Guid.TryParse(resourceTypeId, out Guid resourceTypeGuid))
{
return BadRequest($"{resourceTypeId} is not a guid.");
}
var resourceType = _resourceTypeModel.GetById(resourceTypeGuid);
if (resourceType == null || !resourceType.Enabled)
{
return NotFound($"Could not find resourceType with id: {resourceTypeId}");
}
var projectQuota =
_projectQuotaModel.GetWhere((x) =>
x.ProjectId == projectGuid &&
x.ResourceTypeId == resourceTypeGuid);
var projectQuotaReturnObject = new ProjectQuotaReturnObject
{
Id = resourceTypeGuid,
Name = resourceType.DisplayName,
Used = CalculateUsed(resourceType, projectGuid),
Allocated = projectQuota.Quota};
return Json(projectQuotaReturnObject);
}
/// <summary>
/// Get the max quota for a resource type.
/// </summary>
/// <param name="projectId">Id of the project.</param>
/// <param name="resourceTypeId">Id of the resource</param>
/// <returns>The maximum value for the quota.</returns>
[HttpGet("[controller]/{projectId}/quota/{resourceTypeId}/max")]
public ActionResult<MaxProjectQuota> GetQuotaMax(string projectId, string resourceTypeId)
{
var user = _authenticator.GetUser();
if (!Guid.TryParse(projectId, out Guid projectGuid))
{
return BadRequest($"{projectId} is not a guid.");
}
var project = _projectModel.GetById(projectGuid);
if (project == null)
{
return NotFound($"Could not find project with id: {projectId}");
}
if (!_projectModel.HasAccess(user, project, UserRoles.Owner))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
if (!Guid.TryParse(resourceTypeId, out Guid resourceTypeGuid))
{
return BadRequest($"{resourceTypeId} is not a guid.");
}
var resourceType = _resourceTypeModel.GetById(resourceTypeGuid);
if (resourceType == null || !resourceType.Enabled)
{
return NotFound($"Could not find resourceType with id: {resourceTypeId}");
}
return Json(new MaxProjectQuota { Id = resourceTypeGuid, Available = _maxAvailable });
}
/// <summary>
/// Update the project quota.
/// </summary>
/// <param name="projectId">Id of the project.</param>
/// <param name="resourceTypeId">Id of the resource.</param>
/// <param name="updateProjectQuotaObject">Object containing the update values.</param>
/// <returns>NoContent (204).</returns>
[HttpPost("[controller]/{projectId}/quota/{resourceTypeId}")]
public IActionResult UpdateQuota(string projectId, string resourceTypeId, [FromBody]UpdateProjectQuotaObject updateProjectQuotaObject)
{
var user = _authenticator.GetUser();
if (!Guid.TryParse(projectId, out Guid projectGuid))
{
return BadRequest($"{projectId} is not a guid.");
}
var project = _projectModel.GetById(projectGuid);
if (project == null)
{
return NotFound($"Could not find project with id: {projectId}");
}
if (!_projectModel.HasAccess(user, project, UserRoles.Owner))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
if (!Guid.TryParse(resourceTypeId, out Guid resourceTypeGuid))
{
return BadRequest($"{resourceTypeId} is not a guid.");
}
var resourceType = _resourceTypeModel.GetById(resourceTypeGuid);
if (resourceType == null || !resourceType.Enabled)
{
return NotFound($"Could not find resourceType with id: {resourceTypeId}");
}
if (updateProjectQuotaObject.Allocated < 0)
{
return BadRequest($"Allocated {updateProjectQuotaObject.Allocated}. Cannot be less than 0.");
}
var projectQuotaForCurrent = _projectQuotaModel.GetWhere(x => x.ProjectId == projectGuid && x.ResourceTypeId == resourceTypeGuid);
var used = CalculateUsed(resourceType, projectGuid);
if(used > updateProjectQuotaObject.Allocated)
{
return BadRequest($"Cannot set quota ({updateProjectQuotaObject.Allocated}) below the used value ({used}).");
}
var projectQuotaForAll = _projectQuotaModel.GetAllWhere(x => x.ProjectId == projectGuid).Sum(x => x.Quota);
if(projectQuotaForAll - projectQuotaForCurrent.Quota + updateProjectQuotaObject.Allocated > _maxAvailable)
{
return BadRequest($"Cannot set quota to {updateProjectQuotaObject.Allocated}. In combination with the other quotas ({projectQuotaForAll - projectQuotaForCurrent.Quota}), it would exceed the limit of {_maxAvailable}");
}
projectQuotaForCurrent.Quota = updateProjectQuotaObject.Allocated;
_projectQuotaModel.Update(projectQuotaForCurrent);
return NoContent();
}
/// <summary>
@@ -319,10 +503,9 @@ namespace Coscine.Api.Project.Controllers
projectInstituteModel.Delete(projectInstitute);
}
var projectQuotaModel = new ProjectQuotaModel();
foreach (var projectQuota in projectQuotaModel.GetAllWhere((Quota) => Quota.ProjectId == project.Id))
foreach (var projectQuota in _projectQuotaModel.GetAllWhere((Quota) => Quota.ProjectId == project.Id))
{
projectQuotaModel.Delete(projectQuota);
_projectQuotaModel.Delete(projectQuota);
}
_activatedFeaturesModel.DeactivateAllFeatures(project);
Loading