// Copyright Epic Games, Inc. All Rights Reserved. using HordeServer.Api; using HordeServer.Models; using HordeServer.Services; using HordeServer.Utilities; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using MongoDB.Bson; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Reflection; using System.Security.Claims; using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Logging; namespace HordeServer.Controllers { using LeaseId = ObjectId; using PoolId = StringId; using AgentSoftwareChannelName = StringId; /// /// Controller for the /api/v1/leases endpoint /// [ApiController] [Authorize] [Route("[controller]")] public class LeasesController : ControllerBase { /// /// Singleton instance of the ACL service /// AclService AclService; /// /// Singleton instance of the agent service /// AgentService AgentService; /// /// Logger instance /// private ILogger Logger; /// /// Constructor /// /// The ACL service singleton /// The agent service /// The controller logger public LeasesController(AclService AclService, AgentService AgentService, ILogger Logger) { this.AclService = AclService; this.AgentService = AgentService; this.Logger = Logger; } /// /// Find all the leases for a particular agent /// /// Unique id of the agent to find /// The session to query /// Start of the time window to consider /// End of the time window to consider /// Index of the first result to return /// Number of results to return /// Sessions [HttpGet] [Route("/api/v1/leases")] public async Task>> FindLeasesAsync([FromQuery] string? AgentId, [FromQuery] string? SessionId, [FromQuery] DateTimeOffset? StartTime, [FromQuery] DateTimeOffset? FinishTime, [FromQuery] int Index = 0, [FromQuery] int Count = 1000) { AgentId? AgentIdValue = null; if (AgentId == null) { if (!await AclService.AuthorizeAsync(AclAction.ViewLeases, User)) { return Forbid(); } } else { AgentIdValue = new AgentId(AgentId); IAgent? Agent = await AgentService.GetAgentAsync(AgentIdValue.Value); if (Agent == null) { return NotFound(); } if (!await AgentService.AuthorizeAsync(Agent, AclAction.ViewLeases, User, null)) { return Forbid(); } } List Leases = await AgentService.FindLeasesAsync(AgentIdValue, SessionId?.ToObjectId(), StartTime?.UtcDateTime, FinishTime?.UtcDateTime, Index, Count); return Leases.ConvertAll(x => new GetAgentLeaseResponse(x)); } /// /// Get info about a particular lease /// /// Unique id of the particular lease /// Lease matching the given id [HttpGet] [Route("/api/v1/leases/{LeaseId}")] public async Task> GetLeaseAsync(LeaseId LeaseId) { ILease? Lease = await AgentService.GetLeaseAsync(LeaseId); if (Lease == null) { return NotFound(); } IAgent? Agent = await AgentService.GetAgentAsync(Lease.AgentId); if (Agent == null) { return NotFound(); } if (!await AgentService.AuthorizeAsync(Agent, AclAction.ViewLeases, User, null)) { return Forbid(); } return new GetAgentLeaseResponse(Lease); } /// /// Update a particular lease /// /// Unique id of the particular lease /// /// Lease matching the given id [HttpPut] [Route("/api/v1/leases/{LeaseId}")] public async Task UpdateLeaseAsync(LeaseId LeaseId, [FromBody] UpdateLeaseRequest Request) { // only update supported right now is abort if (!Request.Aborted.HasValue || !Request.Aborted.Value) { return Ok(); } ILease? Lease = await AgentService.GetLeaseAsync(LeaseId); if (Lease == null) { return NotFound(); } IAgent? Agent = await AgentService.GetAgentAsync(Lease.AgentId); if (Agent == null) { return NotFound(); } if (!await AgentService.AuthorizeAsync(Agent, AclAction.AdminWrite, User, null)) { return Forbid(); } AgentLease? AgentLease = Agent.Leases.FirstOrDefault(x => x.Id == LeaseId); if (AgentLease == null) { return NotFound(); } if (!AgentLease.IsConformLease()) { Logger.LogError("Lease abort only supported on conform leases for now, {LeaseId}", LeaseId); return Ok(); } await AgentService.CancelLeaseAsync(Agent, LeaseId); return Ok(); } } }