Skip to content
Snippets Groups Projects
Select Git revision
  • master
1 result

pci.c

Blame
  • 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
                    });
            }
        }
    }