Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ResourceQuotaController.cs 8.58 KiB
using Coscine.Api.Resources.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.ResourceTypes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
namespace Coscine.Api.Resources.Controllers
{
/// <summary>
/// This controller represents the actions which can be taken with a resource object.
/// </summary>
[Authorize]
public class ResourceQuotaController : Controller
{
private readonly Authenticator _authenticator;
private readonly CoscineLogger _coscineLogger;
private readonly ResourceModel _resourceModel;
private readonly ProjectModel _projectModel;
private readonly ProjectRoleModel _projectRoleModel;
private readonly ProjectQuotaModel _projectQuotaModel;
private readonly ProjectResourceModel _projectResourceModel;
private readonly ResourceTypeModel _resourceTypeModel;
private readonly float _oneGiB = 1024 * 1024 * 1024; // 1 GiB = 1024 Bytes
/// <summary>
/// ResourceQuotaController constructor specifying a ResourceModel.
/// </summary>
public ResourceQuotaController(ILogger<ResourceQuotaController> logger)
{
_authenticator = new Authenticator(this, Program.Configuration);
_coscineLogger = new CoscineLogger(logger);
_resourceModel = new ResourceModel();
_projectModel = new ProjectModel();
_projectRoleModel = new ProjectRoleModel();
_projectQuotaModel = new ProjectQuotaModel();
_projectResourceModel = new ProjectResourceModel();
_resourceTypeModel = new ResourceTypeModel();
}
/// <summary>
/// Retrieves the resource used and reserved quota for an individual resource.
/// </summary>
/// <param name="id">Id of the resource.</param>
/// <returns>The quota of the resource.</returns>
[HttpGet("[controller]/{id}")]
public ActionResult<ResourceQuotaReturnObject> GetResourceQuota(Guid id)
{
var resource = _resourceModel.GetById(id);
if (resource == null)
{
return base.NotFound($"Could not find resource with id: {id}");
}
var projectId = _projectResourceModel.GetWhere(x => x.ResourceId == id).ProjectId;
// Rights Matrix (https://git.rwth-aachen.de/coscine/docs/private/internal-wiki/-/blob/master/coscine/Definition%20of%20rights%20Matrix.md)
// - Resource: View Resource (RCV, Metadatamanager)
if (!_projectModel.HasAccess(_authenticator.GetUser(), projectId, UserRoles.Owner, UserRoles.Member, UserRoles.Guest))
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
var displayName = _resourceTypeModel.GetById(resource.TypeId).DisplayName;
var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resource);
if (resourceTypeDefinition == null)
{
return BadRequest($"No provider for: \"{displayName}\".");
}
return Json(Helpers.CreateResourceQuotaReturnObject(resource, resourceTypeDefinition));
}
/// <summary>
/// Updates the resource quota for an individual resource.
/// </summary>
/// <param name="id">Id of the resource.</param>
/// <param name="updateResourceObject">Contains the resource id and the new quota.</param>
/// <returns>204 if successful.</returns>
[HttpPost("[controller]/{id}")]
public IActionResult UpdateResourceQuota(Guid id, [FromBody] UpdateResourceObject updateResourceObject)
{
var resource = _resourceModel.GetById(id);
if (resource == null)
{
return NotFound($"Could not find resource with id: {id}");
}
var projectId = _projectResourceModel.GetWhere(x => x.ResourceId == id).ProjectId;
var user = _authenticator.GetUser();
// 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, projectId, UserRoles.Owner) && resource.Creator != _authenticator.GetUser().Id)
{
return Unauthorized("The user is not authorized to perform a get on the selected project!");
}
var resourceType = _resourceTypeModel.GetById(resource.TypeId);
if (resourceType == null)
{
return NotFound($"Could not find resourceType with id: {resource.TypeId}");
}
var resourceTypeDefinition = ResourceTypeFactory.Instance.GetResourceType(resource);
if (resourceTypeDefinition == null)
{
return BadRequest($"No provider for: \"{resource.Type.DisplayName}\".");
}
if (updateResourceObject.ReservedGiB < 1)
{
return BadRequest($"Allocated {updateResourceObject.ReservedGiB}. Cannot be less than 1.");
}
var projectQuota =
_projectQuotaModel.GetWhere((x) =>
x.ProjectId == projectId &&
x.ResourceTypeId == resource.TypeId);
var totalReserved = Helpers.CalculateTotalReservedQuota(resourceType, projectId);
var reservedForCurrent = resourceTypeDefinition.GetResourceQuotaAvailable(resource.Id.ToString()).Result;
var maximum = projectQuota.Quota - (totalReserved.Value - reservedForCurrent);
if (totalReserved.Value - reservedForCurrent + updateResourceObject.ReservedGiB > projectQuota.Quota)
{
return BadRequest($"Cannot set quota to {updateResourceObject.ReservedGiB} GB. Current resource quota cannot reserve more than {maximum} GB. To increase that number, allocate more {resourceType.SpecificType} quota to the project.");
}
var used = (int)Math.Ceiling(resourceTypeDefinition.GetResourceQuotaUsed(resource.Id.ToString()).Result / _oneGiB);
if (updateResourceObject.ReservedGiB < used)
{
return BadRequest($"Cannot set quota to {updateResourceObject.ReservedGiB} GB. Currently {used} GB are in use. You are not allowed to reserve less than what is currently in use.");
}
resourceTypeDefinition.SetResourceQuota(resource.Id.ToString(), updateResourceObject.ReservedGiB).Wait();
if (resourceType.Type == "rds")
{
var rdsResourceTypeModel = new RDSResourceTypeModel();
var rdsResourceType = rdsResourceTypeModel.GetById(resource.ResourceTypeOptionId.Value);
rdsResourceTypeModel.Update(rdsResourceType);
}
else if (resourceType.Type == "rdss3")
{
var rdsS3ResourceTypeModel = new RdsS3ResourceTypeModel();
var rdsS3ResourceType = rdsS3ResourceTypeModel.GetById(resource.ResourceTypeOptionId.Value);
rdsS3ResourceTypeModel.Update(rdsS3ResourceType);
}
if (Request.Query != null && Request.Query["noanalyticslog"] != "true")
{
LogAnalyticsOwnerResourceQuotaChange(resource, user, updateResourceObject.ReservedGiB, (int)maximum);
}
return NoContent();
}
private void LogAnalyticsOwnerResourceQuotaChange(Resource resource, User user, int reserved, int maximum)
{
var resourceTypeDisplayName = _resourceTypeModel.GetById(resource.TypeId).DisplayName;
var projectId = _projectResourceModel.GetProjectForResource(resource.Id).Value;
_coscineLogger.AnalyticsLog(
new AnalyticsLogObject
{
Type = "Action",
Operation = "Owner Resource Quota Change",
RoleId = _projectRoleModel.GetGetUserRoleForProject(projectId, user.Id).ToString(),
ProjectId = projectId.ToString(),
QuotaSize = new List<string> { $"{resourceTypeDisplayName}: {reserved}/{maximum}" },
ResourceId = resource.Id.ToString(),
ApplicationsProfile = resource.ApplicationProfile
});
}
}
}