Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ProjectQuotaController.cs 10.20 KiB
using Coscine.Api.Project.ParameterObjects;
using Coscine.ApiCommons;
using Coscine.Database.DataModel;
using Coscine.Database.Models;
using Coscine.Database.ReturnObjects;
using Coscine.Database.Util;
using Coscine.Logging;
using Coscine.Metadata;
using Coscine.ResourceTypes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Coscine.Api.Project.Controllers
{
/// <summary>
/// /// This controller represents the actions which can be taken with a project object.
/// </summary>
[Authorize]
public class ProjectQuotaController : Controller
{
private readonly Authenticator _authenticator;
private readonly ProjectModel _projectModel;
private readonly ProjectRoleModel _projectRoleModel;
private readonly ProjectQuotaModel _projectQuotaModel;
private readonly ResourceTypeModel _resourceTypeModel;
private readonly ResourceModel _resourceModel;
private readonly CoscineLogger _coscineLogger;
private readonly RdfStoreConnector _rdfStoreConnector;
/// <summary>
/// ProjectQuotaController constructor
/// </summary>
/// <param name="logger">Logger</param>
public ProjectQuotaController(ILogger<ProjectQuotaController> logger)
{
_authenticator = new Authenticator(this, Program.Configuration);
_projectModel = new ProjectModel();
_projectRoleModel = new ProjectRoleModel();
_resourceTypeModel = new ResourceTypeModel();
_resourceModel = new ResourceModel();
_projectQuotaModel = new ProjectQuotaModel();
_coscineLogger = new CoscineLogger(logger);
_rdfStoreConnector = new RdfStoreConnector(Program.Configuration.GetString("coscine/local/virtuoso/additional/url"));
}
/// <summary>
/// Retrieves all project quotas in GiB grouped by resource type for the selected project.
/// </summary>
/// <param name="id">Id of the project</param>
/// <returns>List of project quotas per resource type</returns>
[HttpGet("[controller]/{id}/-/all")]
public ActionResult<IEnumerable<ProjectQuotaReturnObject>> Quotas(Guid id)
{
var user = _authenticator.GetUser();
var project = _projectModel.GetById(id);
if (project == null)
{
return base.NotFound($"Could not find project with id: {id}");
}
// Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
// - Project: Create Subprojects | Project: View Settings (project, user, quota) ---> conflicts
if (!_projectModel.HasAccess(user, project, UserRoles.Owner, UserRoles.Member))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
var enabledResources = ResourceTypeFactory.Instance.GetResourceTypes();
var resourceTypes = _resourceTypeModel.GetAllWhere(r => enabledResources.Any(e => r.SpecificType.Equals(e)));
return Ok(resourceTypes.Select(x => Helpers.CreateProjectQuotaReturnObject(x, id)));
}
/// <summary>
/// Retrieves the project quota in GiB of a resource type for the selected project together with all individual resources of this resource type.
/// </summary>
/// <param name="id">Id of the project</param>
/// <param name="resourceTypeId">Id of the resource type</param>
/// <returns>The project quota for the resource type together with all individual resources of this resource type.</returns>
[HttpGet("[controller]/{id}/{resourceTypeId}")]
public ActionResult<ProjectQuotaExtendedReturnObject> Quota(Guid id, Guid resourceTypeId)
{
var user = _authenticator.GetUser();
var project = _projectModel.GetById(id);
if (project == null)
{
return NotFound($"Could not find project with id: {id}");
}
// Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
// - Project: View Settings (project, user, quota)
if (!_projectModel.HasAccess(user, project, UserRoles.Owner))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
var resourceType = _resourceTypeModel.GetById(resourceTypeId);
var enabledResources = ResourceTypeFactory.Instance.GetResourceTypes();
if (!enabledResources.Contains(resourceType.SpecificType))
{
return base.NotFound($"Could not find resourceType with id: {resourceTypeId}");
}
return Ok(Helpers.CreateProjectQuotaExtendedReturnObject(resourceType, id));
}
/// <summary>
/// Updates the reserved project quota of a resource type for a selected poject. Quota value in GiB.
/// </summary>
/// <param name="id">Id of the project</param>
/// <param name="resourceTypeId">Id of the resource type</param>
/// <param name="updateProjectQuotaObject">Object containing the update values.</param>
/// <returns>NoContent (204).</returns>
[HttpPost("[controller]/{id}/{resourceTypeId}")]
public IActionResult UpdateQuota(Guid id, Guid resourceTypeId, [FromBody] UpdateProjectQuotaObject updateProjectQuotaObject)
{
var user = _authenticator.GetUser();
var project = _projectModel.GetById(id);
if (project == null)
{
return NotFound($"Could not find project with id: {id}");
}
// Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
// - Project: Change Settings (project, user, quota)
if (!_projectModel.HasAccess(user, project, UserRoles.Owner))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
var resourceType = _resourceTypeModel.GetById(resourceTypeId);
var enabledResources = ResourceTypeFactory.Instance.GetResourceTypes();
if (!enabledResources.Contains(resourceType.SpecificType))
{
return NotFound($"Could not find resourceType with id: {resourceTypeId}");
}
var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resourceType.Type, resourceType.SpecificType);
if (resourceTypeDefinition == null)
{
return BadRequest($"No provider for: \"{resourceType.DisplayName}\".");
}
if (!resourceTypeDefinition.GetResourceTypeInformation().Result.IsQuotaAdjustable)
{
return BadRequest($"Cannot adjust quota for {resourceType.DisplayName}.");
}
if (updateProjectQuotaObject.AllocatedGiB < 0)
{
return BadRequest($"Allocated {updateProjectQuotaObject.AllocatedGiB}. Cannot be less than 0 GB.");
}
var projectQuotaForCurrent = _projectQuotaModel.GetWhere(x => x.ProjectId == id && x.ResourceTypeId == resourceTypeId);
var totalReserved = Helpers.CalculateTotalReservedQuota(resourceType, id);
if (Helpers.ConvertCapacityUnits(totalReserved, QuotaUnit.GibiBYTE) > updateProjectQuotaObject.AllocatedGiB)
{
return BadRequest($"Cannot set quota ({updateProjectQuotaObject.AllocatedGiB} GB) below the total ({Helpers.ConvertCapacityUnits(totalReserved, QuotaUnit.GibiBYTE)} GB) that are currently reserved.");
}
if (updateProjectQuotaObject.AllocatedGiB > projectQuotaForCurrent.MaxQuota)
{
return BadRequest($"Cannot set quota to {updateProjectQuotaObject.AllocatedGiB} GB. It would exceed the maximum of {projectQuotaForCurrent.MaxQuota} GB for {resourceType.SpecificType} resources.");
}
var defaultQuotas = _rdfStoreConnector.GetQuotaDefault(user.Id.ToString());
var defaultQuota = defaultQuotas.FirstOrDefault(q => q.ResourceType == resourceType.DisplayName);
if (projectQuotaForCurrent == null)
{
var projectQuota = new ProjectQuota
{
MaxQuota = (defaultQuota?.DefaultMaxQuota) ?? 0,
Quota = (defaultQuota?.DefaultQuota) ?? 0,
ProjectId = project.Id,
ResourceTypeId = resourceType.Id
};
_projectQuotaModel.Insert(projectQuota);
}
else
{
projectQuotaForCurrent.Quota = updateProjectQuotaObject.AllocatedGiB;
_projectQuotaModel.Update(projectQuotaForCurrent);
}
if (Request.Query != null && Request.Query["noanalyticslog"] != "true")
{
LogAnalyticsOwnerProjectQuotaChange(project, user);
}
return NoContent();
}
private void LogAnalyticsOwnerProjectQuotaChange(Database.DataModel.Project project, User user)
{
var enabledResources = ResourceTypeFactory.Instance.GetResourceTypes();
var resourceTypes = _resourceTypeModel.GetAllWhere(r => enabledResources.Any(e => r.SpecificType.Equals(e)));
var objects = resourceTypes.Select(x => Helpers.CreateProjectQuotaReturnObject(x, project.Id));
_coscineLogger.AnalyticsLog(
new AnalyticsLogObject
{
Type = "Action",
Operation = "Owner Project Quota Change",
RoleId = _projectRoleModel.GetGetUserRoleForProject(project.Id, user.Id).ToString(),
ProjectId = project.Id.ToString(),
QuotaSize = objects.Select(x => $"{x.Name}: {x.Allocated.Value}/{x.Maximum.Value}").ToList()
});
}
}
}